@import 'tailwindcss'; @import 'tw-animate-css'; @import '@xterm/xterm/css/xterm.css'; @import 'katex/dist/katex.min.css'; @import './rich-markdown-editor.css'; @import './markdown-preview.css'; @import './terminal.css'; @import './mobile-page.css'; @font-face { font-family: 'Geist'; src: url('./fonts/Geist-Variable.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; } @font-face { font-family: 'Orca Nerd Font Symbols'; src: url('./fonts/SymbolsNerdFontMono-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; unicode-range: U+E000-F8FF, U+F0000-FFFFD, U+100000-10FFFD; } @custom-variant dark (&:is(.dark *)); /* Why: hover-reveal controls (sidebar/row action buttons) hide with `opacity-0` and fade in via `group-hover`. Touch devices have no hover, so those controls stay invisible. Gate the hide behind `can-hover:` so touch (hover: none) keeps them visible while pointer devices preserve the reveal-on-hover behavior. */ @custom-variant can-hover (@media (hover: hover)); .theme-transition-disabled *, .theme-transition-disabled *::before, .theme-transition-disabled *::after { /* Why: theme swaps flip many CSS variables at once; transitions make parts of the UI fade at different speeds. Animations stay enabled for spinners. */ transition: none !important; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-destructive-foreground: var(--destructive-foreground); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-worktree-sidebar: var(--worktree-sidebar); --color-worktree-sidebar-foreground: var(--worktree-sidebar-foreground); --color-worktree-sidebar-accent: var(--worktree-sidebar-accent); --color-worktree-sidebar-accent-foreground: var(--worktree-sidebar-accent-foreground); --color-worktree-sidebar-border: var(--worktree-sidebar-border); --color-worktree-sidebar-ring: var(--worktree-sidebar-ring); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); --color-terminal-pane-title-on-dark-fg: var(--terminal-pane-title-on-dark-fg); --color-terminal-pane-title-on-dark-input-fg: var(--terminal-pane-title-on-dark-input-fg); --color-terminal-pane-title-on-dark-placeholder: var(--terminal-pane-title-on-dark-placeholder); --color-terminal-pane-title-on-dark-button-fg: var(--terminal-pane-title-on-dark-button-fg); --color-terminal-pane-title-on-dark-button-hover-fg: var( --terminal-pane-title-on-dark-button-hover-fg ); --color-terminal-pane-title-on-dark-input-bg: var(--terminal-pane-title-on-dark-input-bg); --color-terminal-pane-title-on-dark-separator: var(--terminal-pane-title-on-dark-separator); --color-terminal-pane-title-on-light-fg: var(--terminal-pane-title-on-light-fg); --color-terminal-pane-title-on-light-input-fg: var(--terminal-pane-title-on-light-input-fg); --color-terminal-pane-title-on-light-placeholder: var(--terminal-pane-title-on-light-placeholder); --color-terminal-pane-title-on-light-button-fg: var(--terminal-pane-title-on-light-button-fg); --color-terminal-pane-title-on-light-button-hover-fg: var( --terminal-pane-title-on-light-button-hover-fg ); --color-terminal-pane-title-on-light-input-bg: var(--terminal-pane-title-on-light-input-bg); --color-terminal-pane-title-on-light-separator: var(--terminal-pane-title-on-light-separator); --color-ai-action-accent: var(--ai-action-accent); --color-status-success: var(--status-success); --color-status-success-background: var(--status-success-background); --color-status-success-border: var(--status-success-border); --color-tab-group-split-divider: var(--tab-group-split-divider); --color-tab-group-split-divider-strong: var(--tab-group-split-divider-strong); --color-git-graph-ref: var(--git-graph-ref); --color-git-graph-remote-ref: var(--git-graph-remote-ref); --color-git-graph-base-ref: var(--git-graph-base-ref); --color-git-graph-lane-1: var(--git-graph-lane-1); --color-git-graph-lane-2: var(--git-graph-lane-2); --color-git-graph-lane-3: var(--git-graph-lane-3); --color-git-graph-lane-4: var(--git-graph-lane-4); --color-git-graph-lane-5: var(--git-graph-lane-5); --color-annotation-highlight: var(--annotation-highlight); --radius-sm: calc(var(--radius) * 0.6); --radius-md: calc(var(--radius) * 0.8); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) * 1.4); --radius-2xl: calc(var(--radius) * 1.8); --radius-3xl: calc(var(--radius) * 2.2); --radius-4xl: calc(var(--radius) * 2.6); } /* ── Light Mode ──────────────────────────────────────── */ :root { --app-font-family: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --font-sans: var(--app-font-family); --font-mono: 'SF Mono', SFMono-Regular, ui-monospace, 'Cascadia Code', Menlo, Consolas, 'Liberation Mono', monospace; --radius: 0.625rem; --orca-security-background: #fff; --orca-security-foreground: #0a0a0a; --orca-security-card: #fff; --orca-security-card-foreground: #0a0a0a; --orca-security-popover: #fff; --orca-security-popover-foreground: #0a0a0a; --orca-security-primary: #171717; --orca-security-primary-foreground: #fafafa; --orca-security-secondary: #f5f5f5; --orca-security-secondary-foreground: #171717; --orca-security-muted: #f5f5f5; --orca-security-muted-foreground: #737373; --orca-security-accent: #f5f5f5; --orca-security-accent-foreground: #171717; --orca-security-border: #e5e5e5; --orca-security-input: #e5e5e5; --orca-security-ring: #a1a1a1; --background: #fff; --editor-surface: #ffffff; --foreground: #0a0a0a; --card: #fff; --card-foreground: #0a0a0a; --popover: #fff; --popover-foreground: #0a0a0a; --primary: #171717; --primary-foreground: #fafafa; --secondary: #f5f5f5; --secondary-foreground: #171717; --muted: #f5f5f5; --muted-foreground: #737373; --accent: #f5f5f5; --accent-foreground: #171717; --destructive: #e40014; --destructive-foreground: #fcf3f3; --border: #e5e5e5; --input: #e5e5e5; --ring: #a1a1a1; --terminal-pane-locate: var(--color-blue-600); --ai-action-accent: var(--color-violet-500); --status-success: #15803d; --status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent); --status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent); --chart-1: var(--color-blue-300); --chart-2: var(--color-blue-500); --chart-3: var(--color-blue-600); --chart-4: var(--color-blue-700); --chart-5: var(--color-blue-800); --worktree-sidebar: #f5f5f5; --worktree-sidebar-foreground: #0a0a0a; --worktree-sidebar-accent: #eaeaea; --worktree-sidebar-accent-foreground: #171717; --worktree-sidebar-border: #e5e5e5; --worktree-sidebar-ring: #a1a1a1; --sidebar: #fafafa; --sidebar-foreground: #0a0a0a; --sidebar-primary: #171717; --sidebar-primary-foreground: #fafafa; --sidebar-accent: #f5f5f5; --sidebar-accent-foreground: #171717; --sidebar-border: #e5e5e5; --sidebar-ring: #a1a1a1; --terminal-pane-title-on-dark-fg: rgb(255 255 255 / 0.52); --terminal-pane-title-on-dark-input-fg: rgb(255 255 255 / 0.7); --terminal-pane-title-on-dark-placeholder: rgb(255 255 255 / 0.38); --terminal-pane-title-on-dark-button-fg: rgb(255 255 255); --terminal-pane-title-on-dark-button-hover-fg: rgb(255 255 255); --terminal-pane-title-on-dark-input-bg: rgb(255 255 255 / 0.04); --terminal-pane-title-on-dark-separator: rgb(255 255 255 / 0.06); --terminal-pane-title-on-light-fg: rgb(24 24 27 / 0.64); --terminal-pane-title-on-light-input-fg: rgb(24 24 27 / 0.82); --terminal-pane-title-on-light-placeholder: rgb(24 24 27 / 0.48); --terminal-pane-title-on-light-button-fg: rgb(24 24 27); --terminal-pane-title-on-light-button-hover-fg: rgb(24 24 27); --terminal-pane-title-on-light-input-bg: rgb(24 24 27 / 0.05); --terminal-pane-title-on-light-separator: rgb(24 24 27 / 0.1); --git-decoration-added: #587c0c; --git-decoration-modified: #895503; --git-decoration-deleted: #ad0707; --git-decoration-renamed: #007acc; --git-decoration-untracked: #007100; --git-decoration-copied: #007acc; --git-decoration-ignored: #8c8c8c; --git-graph-ref: #007acc; --git-graph-remote-ref: #b66dff; --git-graph-base-ref: #ea5c00; --git-graph-lane-1: #ffb000; --git-graph-lane-2: #dc267f; --git-graph-lane-3: #994f00; --git-graph-lane-4: #40b0a6; --git-graph-lane-5: #b66dff; --annotation-highlight: #f59e0b; --markdown-search-match: #facc15; --markdown-search-match-active: #fb923c; /* Why: tab-group splits use a dedicated divider — `--border` is too faint on card/editor surfaces when panes are side-by-side or stacked. Default must meet >=3:1 against `--card`, not only the hover/drag strong state. */ --tab-group-split-divider: #868690; --tab-group-split-divider-strong: #71717a; } /* ── Dark Mode ───────────────────────────────────────── */ .dark { --orca-security-background: #0a0a0a; --orca-security-foreground: #fafafa; --orca-security-card: #171717; --orca-security-card-foreground: #fafafa; --orca-security-popover: #171717; --orca-security-popover-foreground: #fafafa; --orca-security-primary: #e5e5e5; --orca-security-primary-foreground: #171717; --orca-security-secondary: #262626; --orca-security-secondary-foreground: #fafafa; --orca-security-muted: #262626; --orca-security-muted-foreground: #a1a1a1; --orca-security-accent: #404040; --orca-security-accent-foreground: #fafafa; --orca-security-border: rgb(255 255 255 / 0.07); --orca-security-input: rgb(255 255 255 / 0.15); --orca-security-ring: #737373; --background: #0a0a0a; --editor-surface: #1e1e1e; --foreground: #fafafa; --card: #171717; --card-foreground: #fafafa; --popover: #171717; --popover-foreground: #fafafa; --primary: #e5e5e5; --primary-foreground: #171717; --secondary: #262626; --secondary-foreground: #fafafa; --muted: #262626; --muted-foreground: #a1a1a1; --accent: #404040; --accent-foreground: #fafafa; --destructive: #ff6568; --destructive-foreground: #df2225; --border: rgb(255 255 255 / 0.07); --input: rgb(255 255 255 / 0.15); --ring: #737373; --terminal-pane-locate: var(--color-blue-400); --ai-action-accent: var(--color-violet-400); --status-success: #86efac; --status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent); --status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent); --chart-1: var(--color-blue-300); --chart-2: var(--color-blue-500); --chart-3: var(--color-blue-600); --chart-4: var(--color-blue-700); --chart-5: var(--color-blue-800); /* Why: light mode sets worktree-sidebar to secondary (#f5f5f5); mirror that lift in dark mode so the panel reads clearly above #0a0a0a canvas. */ --worktree-sidebar: #2a2a2a; --worktree-sidebar-foreground: #fafafa; --worktree-sidebar-accent: #353535; --worktree-sidebar-accent-foreground: #fafafa; /* Match --border / --sidebar-border (7%) so the left sidebar's divider lines aren't brighter than the rest of the UI in dark mode (#5906). */ --worktree-sidebar-border: rgb(255 255 255 / 0.07); --worktree-sidebar-ring: #737373; --sidebar: #171717; --sidebar-foreground: #fafafa; --sidebar-primary: #1447e6; --sidebar-primary-foreground: #fafafa; --sidebar-accent: #262626; --sidebar-accent-foreground: #fafafa; --sidebar-border: rgb(255 255 255 / 0.07); --sidebar-ring: #525252; --terminal-pane-title-on-dark-fg: rgb(255 255 255 / 0.52); --terminal-pane-title-on-dark-input-fg: rgb(255 255 255 / 0.7); --terminal-pane-title-on-dark-placeholder: rgb(255 255 255 / 0.38); --terminal-pane-title-on-dark-button-fg: rgb(255 255 255); --terminal-pane-title-on-dark-button-hover-fg: rgb(255 255 255); --terminal-pane-title-on-dark-input-bg: rgb(255 255 255 / 0.04); --terminal-pane-title-on-dark-separator: rgb(255 255 255 / 0.06); --terminal-pane-title-on-light-fg: rgb(24 24 27 / 0.64); --terminal-pane-title-on-light-input-fg: rgb(24 24 27 / 0.82); --terminal-pane-title-on-light-placeholder: rgb(24 24 27 / 0.48); --terminal-pane-title-on-light-button-fg: rgb(24 24 27); --terminal-pane-title-on-light-button-hover-fg: rgb(24 24 27); --terminal-pane-title-on-light-input-bg: rgb(24 24 27 / 0.05); --terminal-pane-title-on-light-separator: rgb(24 24 27 / 0.1); --git-decoration-added: #81b88b; --git-decoration-modified: #e2c08d; --git-decoration-deleted: #c74e39; --git-decoration-renamed: #73c991; --git-decoration-untracked: #73c991; --git-decoration-copied: #73c991; --git-decoration-ignored: #6e6e6e; --git-graph-ref: #3794ff; --git-graph-remote-ref: #b66dff; --git-graph-base-ref: #ea5c00; --git-graph-lane-1: #ffb000; --git-graph-lane-2: #dc267f; --git-graph-lane-3: #ce9178; --git-graph-lane-4: #40b0a6; --git-graph-lane-5: #b66dff; --annotation-highlight: #fbbf24; --markdown-search-match: #facc15; --markdown-search-match-active: #fb923c; /* Brighter than terminal defaults so the always-visible line clears 3:1 on `--card`. */ --tab-group-split-divider: #71717a; --tab-group-split-divider-strong: #a1a1aa; } .plugin-security-chrome { /* Why: plugin themes may style the app, but provenance and consent must retain host-owned contrast so a pack cannot disguise a trust decision. */ --background: var(--orca-security-background); --foreground: var(--orca-security-foreground); --card: var(--orca-security-card); --card-foreground: var(--orca-security-card-foreground); --popover: var(--orca-security-popover); --popover-foreground: var(--orca-security-popover-foreground); --primary: var(--orca-security-primary); --primary-foreground: var(--orca-security-primary-foreground); --secondary: var(--orca-security-secondary); --secondary-foreground: var(--orca-security-secondary-foreground); --muted: var(--orca-security-muted); --muted-foreground: var(--orca-security-muted-foreground); --accent: var(--orca-security-accent); --accent-foreground: var(--orca-security-accent-foreground); --border: var(--orca-security-border); --input: var(--orca-security-input); --ring: var(--orca-security-ring); } .linear-priority-bars { --linear-priority-bar-inactive-fill: color-mix(in srgb, lch(39.576 1.25 282) 34%, transparent); } .dark .linear-priority-bars { --linear-priority-bar-inactive-fill: color-mix(in srgb, lch(39.576 1.25 282) 62%, transparent); } [data-sonner-toaster] { font-family: var(--font-sans); } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] { align-items: flex-start; flex-wrap: wrap; gap: 10px; padding: 14px 16px; box-shadow: 0 10px 24px rgb(0 0 0 / 0.18); } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-icon] { margin-top: 2px; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-content] { min-width: 0; flex: 1 1 calc(100% - 30px); gap: 6px; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-button] { /* Why: Sonner's native action slots otherwise share the copy row and squeeze long notices; indent the wrapped footer to align with text after the icon. */ margin-top: 2px; margin-left: 26px; margin-right: 0; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-button] ~ [data-button] { margin-left: 0; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-title] { line-height: 1.35; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-description] { /* Why: match the 80% body-copy opacity used by the custom-React toast bodies (delete-worktree-failure, local-base-ref-suggestion) so string and JSX descriptions read at the same weight. */ color: color-mix(in srgb, var(--popover-foreground) 80%, transparent); line-height: 1.45; } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-close-button] { /* Why: Sonner's dark-theme defaults can resolve the close icon and button background to the same color; keep the X readable on both Orca themes. */ color: var(--popover-foreground); background: var(--popover); border-color: rgb(0 0 0 / 0.14); } [data-sonner-toaster][data-sonner-theme='dark'] [data-sonner-toast][data-styled='true'] [data-close-button] { color: var(--popover-foreground); background: var(--popover); border-color: rgb(255 255 255 / 0.14); } .dark [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-close-button] { border-color: rgb(255 255 255 / 0.14); } [data-sonner-toaster] [data-sonner-toast][data-styled='true'] [data-close-button]:hover { color: var(--accent-foreground); background: var(--accent); } /* ── Base Layer ──────────────────────────────────────── */ @layer base { *, *::before, *::after { @apply border-border outline-ring/50; } body { @apply bg-background text-foreground; margin: 0; padding: 0; overflow: hidden; /* Why: mobile browser chrome changes the visible viewport while open. */ height: 100dvh; font-family: var( --app-font-family, 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif ); letter-spacing: 0.01em; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ul { list-style: none; } :where(button:not(:disabled)) { cursor: pointer; } :where(button:disabled) { cursor: default; } } /* ── Sleek scrollbar (VS Code-like) ─────────────────── */ .scrollbar-sleek { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--muted-foreground, #737373) 34%, transparent) transparent; } .scrollbar-sleek::-webkit-scrollbar { width: 12px; height: 12px; } .scrollbar-sleek::-webkit-scrollbar-track { background: transparent; } .scrollbar-sleek::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--muted-foreground, #737373) 28%, transparent); border: 3px solid transparent; border-radius: 0; background-clip: padding-box; min-height: 28px; } /* Thicker variant for dense data tables where the default 6px-thumb is hard to grab. */ .scrollbar-sleek-lg { scrollbar-width: auto; } .scrollbar-sleek-lg::-webkit-scrollbar { width: 16px; height: 16px; } .scrollbar-sleek-lg::-webkit-scrollbar-thumb { border-width: 3px; min-height: 36px; } .scrollbar-sleek::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--muted-foreground, #737373) 48%, transparent); } .scrollbar-sleek::-webkit-scrollbar-thumb:active { background-color: color-mix(in srgb, var(--foreground, #171717) 36%, transparent); } .scrollbar-sleek-parent:hover .scrollbar-sleek, .scrollbar-sleek:hover { scrollbar-color: color-mix(in srgb, var(--muted-foreground, #737373) 48%, transparent) transparent; } /* Why: no reserved `scrollbar-gutter` — paired with `overflow-y: auto`, a list that fits shows no scrollbar (and no Windows scrollbar arrow buttons), so its rows stay flush with the fixed header controls, matching macOS. The gutter is only taken while actually scrolling. Thumb still fades in on hover. */ .worktree-sidebar-scrollbar { padding-right: 4px; scrollbar-color: transparent transparent; } .worktree-sidebar-scrollbar::-webkit-scrollbar { width: 8px; } .worktree-sidebar-scrollbar::-webkit-scrollbar-thumb { background-color: transparent; /* Why: no right inset — a 3px transparent right border left a visible strip beside the sidebar resize seam that read like a gap in the drag handle. */ border-width: 3px 0 3px 0; } .scrollbar-sleek-parent:hover .worktree-sidebar-scrollbar, .worktree-sidebar-scrollbar:hover { scrollbar-color: color-mix(in srgb, var(--muted-foreground, #737373) 48%, transparent) transparent; } .scrollbar-sleek-parent:hover .worktree-sidebar-scrollbar::-webkit-scrollbar-thumb, .worktree-sidebar-scrollbar:hover::-webkit-scrollbar-thumb { background-color: color-mix(in srgb, var(--muted-foreground, #737373) 28%, transparent); } .scrollbar-sleek-parent:hover .worktree-sidebar-scrollbar::-webkit-scrollbar-thumb:hover, .worktree-sidebar-scrollbar:hover::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--muted-foreground, #737373) 48%, transparent); } .scrollbar-sleek-parent:hover .worktree-sidebar-scrollbar::-webkit-scrollbar-thumb:active, .worktree-sidebar-scrollbar:hover::-webkit-scrollbar-thumb:active { background-color: color-mix(in srgb, var(--foreground, #171717) 36%, transparent); } [data-slot='popover-content'] { max-height: var(--radix-popover-content-available-height); } /* Radix owns the available-height variable on PopoverContent. Make that same node scrollable so Chromium scrollbar hit-testing stays inside the layer. */ .popover-scroll-content { color-scheme: dark; max-height: min(15rem, var(--radix-popover-content-available-height, 15rem)); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; } /* ── Editor-style scrollbar (matches Monaco) ────────── */ .scrollbar-editor, .xterm .xterm-viewport { scrollbar-width: thin; scrollbar-color: rgba(121, 121, 121, 0.4) transparent; } .scrollbar-editor::-webkit-scrollbar, .xterm .xterm-viewport::-webkit-scrollbar { width: 14px; } .scrollbar-editor::-webkit-scrollbar-track, .xterm .xterm-viewport::-webkit-scrollbar-track { background: transparent; } .scrollbar-editor::-webkit-scrollbar-thumb, .xterm .xterm-viewport::-webkit-scrollbar-thumb { background: rgba(121, 121, 121, 0.4); border: 3px solid transparent; border-radius: 7px; background-clip: padding-box; } .scrollbar-editor::-webkit-scrollbar-thumb:hover, .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { background: rgba(121, 121, 121, 0.7); border: 3px solid transparent; background-clip: padding-box; } .combined-diff-scroll-container { -ms-overflow-style: none; scrollbar-width: none; } .combined-diff-scroll-container::-webkit-scrollbar { width: 0; height: 0; } /* Why: horizontal tab strips scroll via chevrons, wheel, and trackpad; a native scrollbar thumb overlays tab labels and looks broken. */ .terminal-tab-strip, .project-view-tab-strip { -ms-overflow-style: none; scrollbar-width: none; } .terminal-tab-strip::-webkit-scrollbar, .project-view-tab-strip::-webkit-scrollbar { width: 0; height: 0; } /* Why: mask fades avoid painting card-colored overlays that mismatch active tabs. */ .terminal-tab-strip--fade-start.terminal-tab-strip--fade-end { -webkit-mask-image: linear-gradient( to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent ); mask-image: linear-gradient( to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent ); } .terminal-tab-strip--fade-start:not(.terminal-tab-strip--fade-end) { -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 100%); mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 100%); } .terminal-tab-strip--fade-end:not(.terminal-tab-strip--fade-start) { -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 1.5rem), transparent); mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 1.5rem), transparent); } /* Tab activity affordance (amber wash) is rendered as a React DOM child in SortableTab.tsx rather than via ::after here, so the drop-indicator ::before/::after pseudo-elements stay free for drag-and-drop feedback. See drop-indicator.ts and SortableTab.tsx for the implementation. */ /* ── Layout ──────────────────────────────────────────── */ #root { height: 100dvh; width: 100vw; overflow: hidden; } .app-layout { display: flex; flex-direction: column; height: 100dvh; width: 100vw; overflow: hidden; } /* Why: native windows have a stable content box and need no wake-time viewport reflow. */ html.native-shell, html.native-shell body, html.native-shell #root, html.native-shell .app-layout { height: 100%; } /* Tab-group split resize handle — wide hit area, visible center line. */ .tab-group-split-resize-handle { flex-shrink: 0; position: relative; background: transparent; } .tab-group-split-resize-handle.is-vertical { width: 6px; cursor: col-resize; } .tab-group-split-resize-handle.is-horizontal { height: 6px; cursor: row-resize; } .tab-group-split-resize-handle::after { content: ''; position: absolute; border-radius: 1px; background: var(--tab-group-split-divider); transition: background 100ms ease; } .tab-group-split-resize-handle.is-vertical::after { top: 0; bottom: 0; left: 50%; width: 3px; transform: translateX(-50%); } .tab-group-split-resize-handle.is-horizontal::after { left: 0; right: 0; top: 50%; height: 3px; transform: translateY(-50%); } .tab-group-split-resize-handle:hover::after, .tab-group-split-resize-handle.is-dragging::after { background: var(--tab-group-split-divider-strong); } /* ── Titlebar ────────────────────────────────────────── */ /* Why: Radix portals (dropdowns, popovers, dialogs, sheets) render at the document root. Electron's OS-level drag hit-test ignores z-index — portaled content that visually overlaps a -webkit-app-region: drag element is unclickable without an explicit no-drag. These rules cover every Radix portal variant: popper wrappers (dropdowns, popovers), dialog/sheet overlays, and their content panels. */ [data-radix-popper-content-wrapper], [data-slot='sheet-overlay'], [data-slot='sheet-content'], [data-slot='dialog-overlay'], [data-slot='dialog-content'] { -webkit-app-region: no-drag; } .titlebar { height: 36px; min-height: 36px; display: flex; flex-direction: row; align-items: center; background: var(--bg-titlebar, var(--card)); border-bottom: 1px solid var(--border); -webkit-app-region: drag; user-select: none; } /* Why: workspace view still needs a full titlebar-height strip above the sidebar so the native macOS traffic lights and sidebar chrome sit in the same vertical band they use in settings/landing. The center and right workspace columns are offset separately to align with this 36px baseline (4px drag strip + 32px tab row). */ .titlebar-left { height: 36px; min-height: 36px; display: flex; flex-direction: row; align-items: center; overflow: hidden; flex-shrink: 0; /* Why: in workspace view this strip sits directly above the worktree sidebar — match its surface so the left column reads as one panel. */ background: var(--worktree-sidebar); /* Why: draw the divider via inset shadow instead of border-bottom so the flex content area spans the full 36px. With border-bottom + border-box, the content area shrinks to 35px and flex-centered controls land at y=17.5, a half-pixel below the native traffic-light center at y=18 (set via setWindowButtonPosition in createMainWindow.ts). The shadow paints the same 1px seam without stealing layout space, so the sidebar toggle, agent badge, and back/forward arrows align pixel-perfectly with the traffic lights. */ box-shadow: inset 0 -1px 0 var(--border); -webkit-app-region: drag; user-select: none; } /* Why: when the sidebar is collapsed this header floats over the tab strip, so keep the standard titlebar surface instead of the sidebar tint. */ .titlebar-left-floating { background: var(--bg-titlebar, var(--card)); } .titlebar-traffic-light-pad { width: calc(80px / var(--ui-zoom-factor, 1)); flex-shrink: 0; } /* Why: small identity anchor on desktop custom titlebars where native window chrome is hidden. Sized to sit comfortably in the 36px titlebar with a little horizontal breathing room. The SVG fill is white; light mode inverts it to black so it reads on the light titlebar background. */ .titlebar-logo { height: 16px; flex-shrink: 0; margin: 0 4px 0 10px; opacity: 0.75; } /* Why: .dark is toggled on (the :root), so :not(.dark) on a descendant always matches. Scope to :root:not(.dark) to correctly target light mode only. */ :root:not(.dark) .titlebar-logo { filter: invert(1); } /* Why: desktop custom title bar buttons replace hidden native OS chrome. Anchored to the top-right corner of the viewport so they overlay any layout mode (full titlebar, workspace split, etc.) and stay accessible at all times. */ .window-controls { position: fixed; top: 0; right: 0; z-index: 9999; display: flex; flex-direction: row; height: 36px; -webkit-app-region: no-drag; } .window-controls-btn { display: flex; align-items: center; justify-content: center; width: 46px; height: 36px; background: transparent; border: none; color: var(--muted-foreground); cursor: pointer; transition: background 100ms, color 100ms; } .window-controls-btn:hover { background: var(--accent); color: var(--foreground); } .window-controls-close:hover { background: #c42b1c; color: #fff; } /* Why: flex spacer that reserves the width occupied by the three window-control buttons (3 × 46px) so that the preceding titlebar content is not obscured by the fixed-position overlay when custom desktop chrome is active. */ .window-controls-titlebar-spacer { flex-shrink: 0; width: var(--window-controls-width, 0px); } .right-sidebar-header-drag { -webkit-app-region: drag; user-select: none; } [data-terminal-focus-release-surface='true'] { -webkit-app-region: drag; } /* Why: Electron drag regions swallow renderer pointer events. While regular xterm owns focus, make the next top-chrome click observable so it can release terminal zoom ownership; after release these surfaces become draggable again. */ :root[data-regular-terminal-input-focused] .titlebar, :root[data-regular-terminal-input-focused] .titlebar-left, :root[data-regular-terminal-input-focused] .window-controls-titlebar-spacer, :root[data-regular-terminal-input-focused] .right-sidebar-header-drag, :root[data-regular-terminal-input-focused] [data-terminal-focus-release-surface='true'] { -webkit-app-region: no-drag; } .right-sidebar-header-no-drag { -webkit-app-region: no-drag; } /* Why: the right sidebar header extends to the window's right edge. When custom desktop chrome is active, the fixed-position window-controls overlay sits on top of that edge, so we add matching padding-right so the header's close button (pr-1) isn't hidden behind the overlay. */ .right-sidebar-header-inset { padding-right: var(--window-controls-width, 0px); } /* Why: in side-bar activity-bar mode the icon strip sits flush against the right window edge. The fixed-position window-controls overlay (height 36px, width 138px) covers the top-right corner when custom desktop chrome is active, so the topmost sidebar icons are unreachable without this offset. */ .side-activity-bar-windows-inset { padding-top: var(--window-controls-height, 0px); } /* Why: in side activity-bar mode the panel header does NOT extend to the window edge — the 40px icon strip sits to its right. But the window-controls overlay is 138px wide when custom desktop chrome is active, so it still overlaps the panel by (138 - 40) = 98px. Apply exactly that remainder as padding-right so the close button clears the minimize button. max(0px, ...) keeps this a no-op when the var is 0px and the subtraction would otherwise go negative. */ .right-sidebar-header-side-inset { padding-right: max(0px, calc(var(--window-controls-width, 0px) - 40px)); } .sidebar-toggle { -webkit-app-region: no-drag; background: none; border: none; color: var(--muted-foreground); cursor: pointer; padding: 4px 8px; display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: background 150ms; } .sidebar-toggle:hover { background: var(--accent); color: var(--foreground); } /* Why: tighter padding for the back/forward pair so the arrows sit close together as a single navigation group, while the standard .sidebar-toggle spacing stays unchanged for other titlebar icons. */ .sidebar-toggle-compact { padding: 4px 5px; color: var(--foreground); } .sidebar-toggle-compact:disabled { color: var(--muted-foreground); } .sidebar-toggle:disabled { cursor: default; opacity: 0.45; } .sidebar-toggle:disabled:hover { background: none; color: var(--muted-foreground); } .titlebar-app-name { -webkit-app-region: no-drag; display: inline-flex; align-items: center; gap: 4px; height: 24px; max-width: min(280px, 32vw); margin-left: 2px; margin-right: 4px; padding: 0 6px; border-radius: 4px; color: var(--muted-foreground); font-size: 12px; font-weight: 600; line-height: 24px; white-space: nowrap; overflow: hidden; cursor: pointer; } /* Why: when the app name sits inside the worktree sidebar header, it should inherit that panel's contrast instead of the generic titlebar text color. */ .titlebar-left:not(.titlebar-left-floating) .titlebar-app-name { color: var(--worktree-sidebar-foreground); } .titlebar-app-name-main { flex: 0 0 auto; } .titlebar-icon-button { -webkit-app-region: no-drag; background: none; border: none; color: var(--muted-foreground); cursor: pointer; padding: 4px; margin-right: 8px; display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: background 150ms; } .titlebar-icon-button:hover { background: var(--accent); color: var(--foreground); } .titlebar-icon-button:disabled { cursor: default; opacity: 0.5; } .titlebar-icon-button:disabled:hover { background: none; color: var(--muted-foreground); } .titlebar-profile-switcher { -webkit-app-region: no-drag; flex-shrink: 0; } .editor-header { display: flex; align-items: center; /* Keep adjacent actions aligned with the app's compact toolbar spacing. */ gap: 4px; min-height: 36px; padding: 6px 14px; background: var(--editor-surface); border-bottom: 1px solid color-mix(in srgb, var(--border) 72%, transparent); flex-shrink: 0; } .editor-header-text { min-width: 0; flex: 1; } .editor-header-path { display: block; min-width: 0; flex: 0 1 auto; padding: 0; max-width: 100%; border: none; background: transparent; color: var(--muted-foreground); cursor: pointer; font-size: 12px; line-height: 1.2; font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left; } .editor-header-path:hover, .editor-header-path:focus-visible { color: var(--foreground); } .editor-header-path--static { cursor: default; } .editor-header-path--static:hover, .editor-header-path--static:focus-visible { color: var(--muted-foreground); } .editor-header-path-row { display: flex; align-items: center; gap: 8px; min-width: 0; } .editor-header-copy-toast { opacity: 0; transform: translateY(2px); transition: opacity 120ms ease, transform 120ms ease; pointer-events: none; flex-shrink: 0; padding: 2px 6px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 72%, transparent); color: var(--foreground); font-size: 11px; line-height: 1.2; white-space: nowrap; } .editor-header-copy-toast.is-visible { opacity: 1; transform: translateY(0); } /* ── Content ─────────────────────────────────────────── */ .content-area { display: flex; flex-direction: row; flex: 1; overflow: hidden; } /* ── Sidebar ─────────────────────────────────────────── */ [data-file-explorer-row][data-selected='true'] { /* Why: flat bg-accent ≈ panel background in light mode, so selection mixes foreground into accent and adds an inset ring to stay legible in both themes. */ background: color-mix(in srgb, var(--foreground) 8%, var(--accent)); box-shadow: inset 0 0 0 1px var(--border); color: var(--accent-foreground); } [data-file-explorer-row][data-selected='true']:hover { background: color-mix(in srgb, var(--foreground) 10%, var(--accent)); } .dark [data-file-explorer-row][data-selected='true'] { background: color-mix(in srgb, var(--accent) 70%, transparent); } .dark [data-file-explorer-row][data-selected='true']:hover { background: color-mix(in srgb, var(--accent) 80%, transparent); } .sidebar { width: 240px; flex-shrink: 0; background: var(--sidebar); border-right: 1px solid var(--sidebar-border, var(--border)); overflow-y: auto; overflow-x: hidden; transition: width 200ms ease; } /* Why: light-mode sidebar-accent/40 is nearly invisible on the sidebar, while agent rows stack on top of the card hover. Keep nested rows quieter than the workspace card without changing the established dark-mode balance. */ .worktree-sidebar-card-hover:hover { background: color-mix(in srgb, var(--sidebar-foreground) 4%, transparent); } .dark .worktree-sidebar-card-hover:hover { background: color-mix(in srgb, var(--sidebar-accent) 40%, transparent); } /* Why: the brighter border carries the selected state; a translucent wash keeps card text legible instead of lifting the surface toward the foreground color. */ [data-worktree-card-surface][data-worktree-card-active='primary'] { border-color: color-mix(in srgb, var(--worktree-sidebar-border) 40%, transparent); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 8%, transparent); box-shadow: 0 1px 2px color-mix(in srgb, var(--worktree-sidebar-foreground) 4%, transparent); } .dark [data-worktree-card-surface][data-worktree-card-active='primary'] { border-color: color-mix( in srgb, var(--worktree-sidebar-foreground) 18%, var(--worktree-sidebar-border) ); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 10%, transparent); box-shadow: 0 1px 2px color-mix(in srgb, var(--worktree-sidebar-foreground) 3%, transparent); } [data-worktree-card-surface][data-worktree-card-active='secondary'] { border-color: color-mix(in srgb, var(--sidebar-ring) 25%, transparent); background: color-mix(in srgb, var(--sidebar-accent) 45%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--sidebar-ring) 15%, transparent); } .dark [data-worktree-card-surface][data-worktree-card-active='secondary'] { border-color: color-mix(in srgb, var(--sidebar-ring) 28%, transparent); background: color-mix(in srgb, var(--sidebar-accent) 34%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--sidebar-ring) 18%, transparent); } .worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--sidebar-foreground) 1.25%, transparent); } .worktree-agent-row-hover[data-focused-agent-pane='true'] { /* Why: a borderless fill. --sidebar-accent ≈ --sidebar in light mode, so the selection wash mixes sidebar-foreground into the accent to stay legible without going so dark that muted text (timestamp) drops out. */ background: color-mix(in srgb, var(--sidebar-foreground) 12%, var(--sidebar-accent)); } .dark .worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); } .dark .worktree-agent-row-hover[data-focused-agent-pane='true'] { background: color-mix(in srgb, var(--accent) 70%, transparent); } /* Why: sidebar-accent sits too close to sidebar for this persistent prompt; a foreground mix creates the requested light/dark separation without a new token. */ .setup-script-prompt-card { background: color-mix(in srgb, var(--sidebar-foreground) 5%, var(--sidebar)); } .dark .setup-script-prompt-card { background: color-mix(in srgb, var(--sidebar-foreground) 12%, var(--sidebar)); } /* Why: one-shot sidebar education cards need stronger separation than worktree-sidebar-accent, which sits almost on top of the sidebar fill. */ .worktree-sidebar-notice-card { position: relative; border: 1px solid color-mix(in srgb, var(--worktree-sidebar-foreground) 24%, var(--worktree-sidebar-border)); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 9%, var(--worktree-sidebar)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--worktree-sidebar-foreground) 8%, transparent), 0 1px 2px color-mix(in srgb, var(--worktree-sidebar-foreground) 10%, transparent); } .dark .worktree-sidebar-notice-card { border-color: color-mix( in srgb, var(--worktree-sidebar-foreground) 32%, var(--worktree-sidebar-border) ); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 14%, var(--worktree-sidebar)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--worktree-sidebar-foreground) 12%, transparent), 0 1px 4px rgb(0 0 0 / 0.28); } /* Why: the project-order notice sits directly under the Projects header; a caret aligned to that label reads as a callout instead of a random card. */ .worktree-sidebar-notice-card--to-section-title::before { content: ''; position: absolute; top: -5px; left: 1.75rem; width: 10px; height: 10px; transform: rotate(45deg); border-left: 1px solid color-mix(in srgb, var(--worktree-sidebar-foreground) 24%, var(--worktree-sidebar-border)); border-top: 1px solid color-mix(in srgb, var(--worktree-sidebar-foreground) 24%, var(--worktree-sidebar-border)); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 9%, var(--worktree-sidebar)); } .dark .worktree-sidebar-notice-card--to-section-title::before { border-left-color: color-mix( in srgb, var(--worktree-sidebar-foreground) 32%, var(--worktree-sidebar-border) ); border-top-color: color-mix( in srgb, var(--worktree-sidebar-foreground) 32%, var(--worktree-sidebar-border) ); background: color-mix(in srgb, var(--worktree-sidebar-foreground) 14%, var(--worktree-sidebar)); } /* Why: one-shot status-bar callout is portaled fixed above the meters. Opaque popover surface (not glass) so titlebar/terminal chrome cannot bleed through; use design tokens + the documented floating elevation. */ .status-bar-change-notice-card { border: 1px solid var(--border); background: var(--popover); color: var(--popover-foreground); /* STYLEGUIDE: floating elevation for popovers that escape the editor surface. */ box-shadow: 0 10px 24px rgb(0 0 0 / 0.18); } /* Why: caret points down at the usage meters this notice explains. */ .status-bar-change-notice-card::after { content: ''; position: absolute; left: 1.25rem; bottom: -6px; width: 12px; height: 12px; transform: rotate(45deg); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--popover); } /* Why: the first-run Mobile Emulator intro sits directly under that menu row; an upward caret aligned to the phone icon reads as a callout, not a footer. */ .mobile-emulator-tab-intro-callout--menu { position: relative; } .mobile-emulator-tab-intro-callout--menu::before { content: ''; position: absolute; top: -7px; left: 0.8125rem; border-style: solid; border-width: 0 7px 7px; /* Why: use foreground + border to create a subtle shadow that adapts to theme */ border-color: transparent transparent color-mix(in srgb, var(--foreground) 10%, var(--border)) transparent; } .mobile-emulator-tab-intro-callout--menu::after { content: ''; position: absolute; top: -6px; left: 0.8125rem; border-style: solid; border-width: 0 6px 6px; border-color: transparent transparent var(--muted) transparent; } .dark .mobile-emulator-tab-intro-callout--menu::before { /* Why: use foreground + border to create a subtle shadow that adapts to theme */ border-bottom-color: color-mix(in srgb, var(--foreground) 12%, var(--border)); } .dark .mobile-emulator-tab-intro-callout--menu::after { border-bottom-color: color-mix(in srgb, var(--accent) 80%, transparent); } /* Why: anchor the optional setup card over the emulator without blurring the device preview, which read as a rendering glitch. */ .mobile-emulator-agent-setup-guide-scrim { background: linear-gradient( to top, color-mix(in srgb, var(--background) 92%, transparent), transparent ); pointer-events: none; } /* Why: the detected command is editable, but a pure app-background fill reads like a black box in dark mode and overpowers the prompt card. */ .setup-script-prompt-command { background: color-mix(in srgb, var(--sidebar-foreground) 2%, var(--sidebar)); } .dark .setup-script-prompt-command { background: color-mix(in srgb, var(--sidebar-foreground) 8%, var(--sidebar)); } .worktree-agent-lineage-parent-row { /* Why: inline orchestration trees have two chevron levels; the manager row needs a structural cue that is quieter than the workspace card chrome. */ background: color-mix(in srgb, var(--sidebar-foreground) 3%, var(--sidebar)); box-shadow: inset 2px 0 0 color-mix(in srgb, var(--sidebar-foreground) 38%, transparent), inset 0 0 0 1px color-mix(in srgb, var(--sidebar-foreground) 10%, transparent); } .worktree-agent-lineage-parent-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--sidebar-foreground) 6%, var(--sidebar)); } .dark .worktree-agent-lineage-parent-row { background: color-mix(in srgb, var(--accent) 22%, var(--sidebar)); box-shadow: inset 2px 0 0 color-mix(in srgb, var(--accent) 58%, transparent), inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent); } .dark .worktree-agent-lineage-parent-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--accent) 30%, var(--sidebar)); } .worktree-agent-lineage-child-row { position: relative; background: color-mix(in srgb, var(--sidebar) 74%, var(--background)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sidebar-foreground) 7%, transparent); } .worktree-agent-lineage-child-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--sidebar-foreground) 4%, var(--sidebar)); } .worktree-agent-lineage-child-row::before { content: ''; position: absolute; left: 0.15rem; top: 50%; width: 0.35rem; border-top: 1px solid color-mix(in srgb, var(--sidebar-foreground) 20%, transparent); } .dark .worktree-agent-lineage-child-row { background: color-mix(in srgb, var(--accent) 10%, var(--sidebar)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 16%, transparent); } .dark .worktree-agent-lineage-child-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--accent) 18%, var(--sidebar)); } .dark .worktree-agent-lineage-child-row::before { border-top-color: color-mix(in srgb, var(--accent) 42%, transparent); } .worktree-agent-lineage-children { margin-left: 0.75rem; padding-left: 0.25rem; border-left: 1px solid color-mix(in srgb, var(--sidebar-foreground) 22%, transparent); } .dark .worktree-agent-lineage-children { border-left-color: color-mix(in srgb, var(--accent) 28%, transparent); } .worktree-agent-send-target-button { /* Why: the row remains an ordinary agent row during send-target mode; the action itself carries the AI target outline so the clickable affordance is explicit without boxing the whole session. */ border-color: color-mix(in srgb, var(--ai-action-accent) 72%, transparent); background: color-mix(in srgb, var(--ai-action-accent) 12%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ai-action-accent) 22%, transparent); color: var(--foreground); } .worktree-agent-send-target-button:hover { border-color: color-mix(in srgb, var(--ai-action-accent) 88%, transparent); background: color-mix(in srgb, var(--ai-action-accent) 18%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ai-action-accent) 34%, transparent); } .worktree-agent-send-target-button:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 50%, transparent); } /* Why: the virtualized card row is height-measured; animate the grid track instead of explicit height so the reveal stays CSS-owned and interruptible. */ .compact-agent-expansion-grid { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 180ms cubic-bezier(0.16, 1, 0.3, 1); } .compact-agent-expansion-grid-expanded { grid-template-rows: 1fr; } /* Why: keyframes run when the content mounts already in its final state. */ @keyframes compact-agent-expansion-reveal { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: translateY(0); } } .compact-agent-expansion-grid-expanded .compact-agent-expansion-content { animation: compact-agent-expansion-reveal 180ms cubic-bezier(0.16, 1, 0.3, 1) both; } /* Why: the collapsed summary still uses pill spacing, while expanded compact agents read as a quiet tree inside the existing worktree card. */ .compact-agent-summary-panel { padding: 2px; border-radius: var(--radius-sm, 0.25rem); background: transparent; box-shadow: inset 0 0 0 1px transparent; transition: background 180ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 180ms cubic-bezier(0.16, 1, 0.3, 1); } .compact-agent-summary-panel-expanded { background: transparent; box-shadow: inset 0 0 0 1px transparent; } [data-compact-agent-list='true'] { margin-inline-start: -0.5rem; width: calc(100% + 0.5rem); } /* Why: compact expanded agents live inside an already-framed worktree card. Keep the tree legible with indentation and interaction states instead of stacking row cards and shaded panels. */ [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-parent-row, [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-child-row { background: transparent; box-shadow: none; } [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-child-row::before { content: none; } [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-parent-row.worktree-agent-row-hover:hover, [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-child-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--sidebar-foreground) 1.25%, transparent); } .dark [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-parent-row.worktree-agent-row-hover:hover, .dark [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-lineage-child-row.worktree-agent-row-hover:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); } [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-row-hover[data-focused-agent-pane='true'] { background: color-mix(in srgb, var(--sidebar-foreground) 12%, var(--sidebar-accent)); } .dark [data-compact-agent-list='true'] .compact-agent-row.worktree-agent-row-hover[data-focused-agent-pane='true'] { background: color-mix(in srgb, var(--accent) 70%, transparent); } [data-compact-agent-list='true'] .worktree-agent-lineage-children { border-left-color: color-mix(in srgb, var(--sidebar-foreground) 16%, transparent); } .dark [data-compact-agent-list='true'] .worktree-agent-lineage-children { border-left-color: color-mix(in srgb, var(--accent) 20%, transparent); } @media (prefers-reduced-motion: reduce) { .compact-agent-expansion-grid { transition-duration: 0ms; } .compact-agent-expansion-grid-expanded .compact-agent-expansion-content { animation-duration: 0ms; } .compact-agent-summary-panel { transition-duration: 0ms; } } .scroll-to-current-workspace-reveal-highlight { position: relative; isolation: isolate; overflow: visible; } .scroll-to-current-workspace-reveal-highlight::before { content: ''; position: absolute; inset: 0; z-index: 30; pointer-events: none; border: 1.5px solid color-mix(in srgb, var(--terminal-pane-locate) 68%, transparent); border-radius: inherit; box-shadow: 0 0 0 1px color-mix(in srgb, var(--terminal-pane-locate) 34%, transparent), 0 0 14px color-mix(in srgb, var(--terminal-pane-locate) 36%, transparent); animation: scroll-to-current-workspace-reveal-glow 1.5s ease-out forwards; } .scroll-to-current-workspace-reveal-highlight--ai::before { border-color: color-mix(in srgb, var(--ai-action-accent) 68%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ai-action-accent) 34%, transparent), 0 0 14px color-mix(in srgb, var(--ai-action-accent) 36%, transparent); } @keyframes scroll-to-current-workspace-reveal-glow { 0% { opacity: 1; transform: scale(0.992); } 24% { opacity: 0.72; transform: scale(1); } 60% { opacity: 0.28; transform: scale(1.006); } 100% { opacity: 0; transform: scale(1.006); } } @media (prefers-reduced-motion: reduce) { .scroll-to-current-workspace-reveal-highlight::before { animation: none; opacity: 1; transform: none; } } @keyframes settings-shell-enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .settings-view-shell { animation: settings-shell-enter 180ms ease-out; } .collapsible-height-content { overflow: hidden; } .collapsible-height-content[data-state='open'] { animation: collapsible-down 200ms ease-out; } .collapsible-height-content[data-state='closed'] { animation: collapsible-up 180ms ease-out; } @keyframes collapsible-down { from { height: 0; opacity: 0; } to { height: var(--radix-collapsible-content-height); opacity: 1; } } @keyframes collapsible-up { from { height: var(--radix-collapsible-content-height); opacity: 1; } to { height: 0; opacity: 0; } } .sidebar.collapsed { width: 0; border-right: none; overflow: hidden; } /* Why: the workspace board is offset to the sidebar edge. The generic left sheet translates by its full width, which makes an offset board fly in from far offscreen; this reveals it from the sidebar boundary instead. */ .workspace-kanban-sheet-content[data-state='open'] { animation-name: workspace-kanban-sheet-in; animation-duration: 300ms; animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); } .workspace-kanban-sheet-content[data-state='closed'] { animation-name: workspace-kanban-sheet-out; animation-duration: 200ms; animation-timing-function: cubic-bezier(0.7, 0, 0.84, 0); } /* Why: this board is attached to the worktree sidebar, not floating above it; the generic Sheet elevation casts a haze over the sidebar when left open. */ .workspace-kanban-sheet-content { box-shadow: inset 1px 0 0 color-mix(in srgb, var(--worktree-sidebar-border) 80%, transparent); backdrop-filter: none; } /* Why: a sidebar-card drag should advertise the board as a possible drop surface without fully committing the companion panel until the pointer enters it. */ .workspace-kanban-sheet-content[data-workspace-board-drag-preview='true'] { background: color-mix(in srgb, var(--worktree-sidebar) 88%, var(--background)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sidebar-ring) 58%, transparent), 0 10px 24px color-mix(in srgb, var(--foreground) 12%, transparent); } .workspace-kanban-sheet-content[data-workspace-board-drag-preview='true'] > * { opacity: 0.42; } /* Why: while a card drag previews the board, pulse the toolbar trigger with the same ring the drawer uses so it reads as another way to open the board. */ @keyframes workspace-board-trigger-preview-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sidebar-ring) 55%, transparent); } 70%, 100% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--sidebar-ring) 0%, transparent); } } [data-workspace-board-trigger][data-workspace-board-preview='true'] { animation: workspace-board-trigger-preview-pulse 1.4s ease-out infinite; } @media (prefers-reduced-motion: reduce) { [data-workspace-board-trigger][data-workspace-board-preview='true'] { animation: none; } } @keyframes workspace-kanban-sheet-in { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } } @keyframes workspace-kanban-sheet-out { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 100% 0 0); } } /* Why: board-origin cards use pointer drag so Shift+scroll can keep firing; these replace the native drag cursor and ghost affordance. */ [data-workspace-board-pointer-draggable='true'] { cursor: grab; } [data-workspace-board-card-pointer-dragging='true'] { outline: 1px solid var(--sidebar-ring); outline-offset: 1px; box-shadow: 0 0 0 1px color-mix(in srgb, var(--sidebar-ring) 36%, transparent); } [data-workspace-board-card-pointer-dragging='true'], [data-workspace-board-card-pointer-dragging='true'] *, :root[data-workspace-board-pointer-dragging] * { cursor: grabbing !important; } [data-workspace-board-card-drag-preview='true'] { z-index: 2147483647; overflow: visible; border-radius: var(--radius); outline: 1px solid var(--sidebar-ring); outline-offset: 1px; box-shadow: 0 10px 24px color-mix(in srgb, var(--foreground) 16%, transparent); opacity: 0.96; will-change: transform; } [data-workspace-board-card-drag-preview='true'][data-workspace-board-card-drag-stack='true'] { isolation: isolate; } [data-workspace-board-card-drag-card='true'] { width: 100%; height: 100%; } [data-workspace-board-card-drag-preview='true'][data-workspace-board-card-drag-stack='true']::before, [data-workspace-board-card-drag-preview='true'][data-workspace-board-card-drag-stack='true']::after { content: ''; position: absolute; inset: 0; z-index: -1; border-radius: var(--radius); border: 1px solid color-mix(in srgb, var(--sidebar-ring) 44%, transparent); background: var(--sidebar); } [data-workspace-board-card-drag-preview='true'][data-workspace-board-card-drag-stack='true']::before { transform: translate(4px, 4px); opacity: 0.72; } [data-workspace-board-card-drag-preview='true'][data-workspace-board-card-drag-stack='true']::after { transform: translate(8px, 8px); opacity: 0.44; } [data-workspace-board-card-drag-preview='true'] * { cursor: grabbing !important; } [data-worktree-sidebar-drag-preview='true'] { z-index: 2147483000; overflow: visible; border-radius: var(--radius); opacity: 0.96; filter: drop-shadow(0 10px 24px color-mix(in srgb, var(--foreground) 18%, transparent)); will-change: transform; } [data-worktree-sidebar-drag-preview='true'] * { cursor: grabbing !important; } [data-worktree-sidebar-drag-count='true'] { position: absolute; top: -6px; right: 8px; display: inline-flex; min-width: 18px; height: 18px; align-items: center; justify-content: center; border-radius: 9999px; background: var(--sidebar-ring); color: var(--sidebar); font-size: 10px; font-weight: 700; box-shadow: 0 0 0 2px var(--sidebar); } [data-workspace-board-card-drop-indicator='true'] { z-index: 2147483646; height: 3px; border-radius: 9999px; background: var(--sidebar-ring); box-shadow: 0 0 0 1px color-mix(in srgb, var(--sidebar-ring) 24%, transparent), 0 8px 20px color-mix(in srgb, var(--sidebar-ring) 36%, transparent); opacity: 0; transition: transform 120ms cubic-bezier(0.2, 0.8, 0.2, 1), width 120ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 80ms ease-out; will-change: transform, width, opacity; } [data-workspace-board-card-drop-indicator='true']::before, [data-workspace-board-card-drop-indicator='true']::after { content: ''; position: absolute; top: 50%; width: 7px; height: 7px; border-radius: 9999px; background: var(--sidebar-ring); transform: translateY(-50%); } [data-workspace-board-card-drop-indicator='true']::before { left: -1px; } [data-workspace-board-card-drop-indicator='true']::after { right: -1px; } [data-workspace-board-card-drag-count='true'] { position: absolute; top: -8px; right: -8px; z-index: 2; display: flex; min-width: 18px; height: 18px; align-items: center; justify-content: center; border-radius: 9999px; border: 1px solid var(--sidebar-border); background: var(--foreground); color: var(--background); font-size: 10px; font-weight: 600; line-height: 1; } .sidebar-header { padding: 12px 16px 8px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted-foreground); } .worktree-list { padding: 0 4px; } .worktree-item { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; border-radius: 6px; cursor: pointer; transition: background 120ms; } .worktree-item:hover { background: var(--accent); } .worktree-item.active { background: var(--accent); } .worktree-branch { font-size: 13px; font-family: inherit; color: var(--foreground); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .worktree-path { font-size: 11px; color: var(--muted-foreground); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ── Misc ────────────────────────────────────────────── */ .number-input-clean { appearance: textfield; } .number-input-clean::-webkit-outer-spin-button, .number-input-clean::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } /* ── Landing ─────────────────────────────────────────── */ .landing { flex: 1; display: flex; align-items: center; justify-content: center; background: var(--background); } .landing-content { display: flex; flex-direction: column; align-items: center; gap: 16px; } .landing-title { font-size: 48px; font-weight: 700; color: var(--muted-foreground); letter-spacing: -0.02em; } .landing-action { background: var(--secondary); border: 1px solid var(--border); color: var(--foreground); font-family: inherit; font-size: 14px; padding: 8px 24px; border-radius: 6px; cursor: pointer; transition: background 150ms; } .landing-action:hover { background: var(--accent); } .landing-hint { font-size: 12px; color: var(--muted-foreground); } /* ── fix: ensure Monaco find widget layout is not reversed ── */ .monaco-editor .find-widget, .monaco-editor .find-widget .monaco-inputbox, .monaco-editor .find-widget .matchesCount { direction: ltr !important; flex-direction: row !important; } .monaco-editor .find-widget .button, .monaco-editor .find-widget .monaco-button, .monaco-editor .find-widget .monaco-find-input .controls .button { display: inline-flex !important; align-items: center !important; justify-content: center !important; padding: 0 !important; width: 20px !important; height: 20px !important; line-height: normal !important; box-sizing: border-box !important; vertical-align: middle !important; border: none !important; box-shadow: none !important; transition: none !important; } /* Why: the expand/collapse toggle (the chevron on the far left) is positioned absolutely and relies on Monaco's default height:100% to vertically center its icon over the find row. The generic .button override above forces a fixed 20px height, which pins the chevron to the top. Restore Monaco's full-height 18px toggle so the chevron centers like the stock find widget. */ .monaco-editor .find-widget .button.toggle { width: 18px !important; height: 100% !important; top: 0 !important; } .monaco-editor .find-widget .button > .codicon, .monaco-editor .find-widget .button > i { display: flex !important; align-items: center !important; justify-content: center !important; width: 100% !important; height: 100% !important; } .monaco-editor .monaco-search-result-highlight { background: color-mix(in srgb, var(--warning, #f59e0b) 34%, transparent); border-radius: 3px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warning, #f59e0b) 52%, transparent); } .monaco-editor .monaco-markdown-doc-link { color: #58a6ff !important; text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); text-underline-offset: 2px; } /* Why: Monaco's faded scrollbar uses the class `invisible`, which collides with Tailwind's `.invisible` utility (visibility: hidden) — so also restore visibility. */ .monaco-editor .reference-zone-widget .monaco-scrollable-element > .scrollbar.vertical.invisible.fade { opacity: 1; visibility: visible; pointer-events: auto; } /* Why: Monaco leaves the peek preview container `inline-block` and only sizes the editor child, so the container shrink-wraps the child in BOTH axes while the inherited automaticLayout ResizeObserver measures the container — a feedback loop that ratchets the preview to blank at fractional zoom/DPI (issue #7405). Pinning both dimensions to the splitview slot severs the loop. */ .monaco-editor .reference-zone-widget .preview.inline { height: 100%; width: 100%; } /* ── Git conflict decorations ───────────────────────────────────── */ .monaco-editor .orca-conflict-marker-line { background: color-mix(in srgb, var(--destructive) 12%, transparent); } .monaco-editor .orca-conflict-section-line { border-left: 3px solid transparent; } .monaco-editor .orca-conflict-current-line { background: color-mix(in srgb, var(--git-decoration-modified) 12%, transparent); border-left-color: color-mix(in srgb, var(--git-decoration-modified) 72%, transparent); } .monaco-editor .orca-conflict-base-line { background: color-mix(in srgb, var(--muted-foreground) 7%, transparent); border-left-color: color-mix(in srgb, var(--muted-foreground) 36%, transparent); } .monaco-editor .orca-conflict-incoming-line { background: color-mix(in srgb, var(--git-decoration-renamed) 11%, transparent); border-left-color: color-mix(in srgb, var(--git-decoration-renamed) 68%, transparent); } .monaco-editor .orca-conflict-line-decoration { width: 4px !important; margin-left: 3px; background: var(--destructive); border-radius: 999px; } .monaco-editor .orca-conflict-margin { background: color-mix(in srgb, var(--destructive) 8%, transparent); } .monaco-editor .orca-conflict-marker-label { color: var(--destructive); font-family: var(--font-sans, system-ui, sans-serif); font-size: 11px; font-weight: 600; font-style: normal; opacity: 0.92; } /* Why: Monaco's find-widget button tooltips (Close, Find in Selection, etc.) render inside a `.context-view` wrapper → `.workbench-hover-container` → `.workbench-hover.compact`, positioned above the target button. The wrapper's bounding box (z-index 2576, `pointer-events: auto`) overlaps the button hit area, so as the tooltip appears it fires `mouseleave` on the button → 200ms debounce → hover disposes → mouse is again "over" the button → `mouseover` re-fires a new tooltip → loop. The visible effect is an infinitely flashing tooltip that also blocks clicks on the button beneath it. The overlap is only reliably reproducible when the right sidebar is open, because the find widget's x-position shifts the wrapper onto the button rect; with the sidebar closed the wrapper often lands slightly offset and doesn't intercept. These are compact tooltips (`HoverStyle.Pointer` → `.workbench-hover.compact`) configured with `hideOnHover: true`, so the CompositeMouseTracker only tracks the target element — not the wrapper. Making the entire wrapper chain non-interactive breaks the overlap feedback loop without affecting tracker logic, keyboard focus traps, or interactive markdown hovers (which are never `.compact`). The `:has()` selector ensures we only disable pointer events on context-views that actually contain a compact hover, leaving menus, dropdown popups and other context-view consumers untouched. */ .context-view:has(> .workbench-hover-container > .workbench-hover.compact), .workbench-hover-container:has(> .workbench-hover.compact) { pointer-events: none; } /* Why: compact hovers for simple label strings (e.g. "Find in Selection (⌥⌘L)") get `white-space: pre-wrap` inline-set by Monaco, so when the tooltip lands near the viewport edge its max-width clamps and the label wraps to 2–3 lines, pushing the tooltip down over the find-widget buttons. These labels are single-line by design; forcing nowrap keeps the tooltip on one line and lets the positioning logic flip/shift as needed to fit. Only applies to compact hovers — markdown hovers still wrap normally. */ .workbench-hover.compact .hover-contents { white-space: nowrap !important; } /* ── Update card animations ───────────────────────────────────────── */ @keyframes update-card-enter { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes update-card-exit { from { opacity: 1; } to { opacity: 0; } } .animate-update-card-enter { animation: update-card-enter 200ms ease-out both; } /* Why: `skills update` reports no parseable progress, so the skill-update bar is deliberately indeterminate rather than a faked percentage. */ @keyframes skill-update-slide { from { transform: translateX(-100%); } to { transform: translateX(365%); } } .animate-update-card-exit { animation: update-card-exit 150ms ease-in both; } /* Waveform bars in the FeatureTipsModal voice tip — purely decorative. */ @keyframes waveform { 0%, 100% { transform: scaleY(0.4); opacity: 0.6; } 50% { transform: scaleY(1); opacity: 1; } } .animate-waveform { animation: waveform 1.4s ease-in-out infinite; transform-origin: center; } /* CLI feature tip — terminal cursor inside the agent-control command. */ @keyframes cli-tip-caret { 0%, 45% { opacity: 1; } 46%, 100% { opacity: 0; } } .animate-cli-tip-caret { animation: cli-tip-caret 0.9s steps(1, end) infinite; } @keyframes cli-tip-command-line { 0% { opacity: 0; transform: translateY(2px); } 100% { opacity: 1; transform: translateY(0); } } .animate-cli-tip-command-line { animation: cli-tip-command-line 160ms ease-out both; } @media (prefers-reduced-motion: reduce) { .animate-cli-tip-caret { animation: none; opacity: 1; transform: none; } .animate-cli-tip-command-line { animation: none; } } .cli-tip-orchestration-frame .feature-wall-orch-stage { --feature-wall-workspace-title-size: 11.5px; --feature-wall-agent-message-size: 10.5px; --feature-wall-agent-row-gap: 5px; --feature-wall-agent-status-col: 10px; --feature-wall-agent-icon-col: 12px; --feature-wall-agent-status-box: 10px; --feature-wall-agent-status-icon: 9px; --feature-wall-agent-icon-box: 12px; --feature-wall-child-indent: 22px; align-content: start !important; padding-top: 10px !important; padding-left: 12px !important; padding-right: 52px !important; } .cli-tip-orchestration-frame .feature-wall-agent-icon svg { height: 11px; width: 11px; } .cli-tip-orchestration-frame .feature-wall-agent-status [aria-label] { height: 10px; width: 10px; } .cli-tip-orchestration-frame .feature-wall-agent-status [aria-label] > span { height: 6px; width: 6px; border-width: 1.5px; } /* Cmd+J feature tip — JS-driven sequence (keypress → palette → typing → results). The keypress press-down and palette entrance are handled inline by React state transitions; this file only defines the caret blink and the results fade-in. */ /* Blinking caret for the simulated command-palette input while "typing". */ @keyframes cmd-j-tip-caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } .animate-cmd-j-tip-caret { animation: cmd-j-tip-caret 1s step-end infinite; } /* Worktree rows fade in when the palette opens — mirrors the real palette, which shows recent worktrees on empty query and filters synchronously. */ @keyframes cmd-j-tip-result-in { 0% { opacity: 0; transform: translateY(2px); } 100% { opacity: 1; transform: translateY(0); } } .animate-cmd-j-tip-result-in { animation: cmd-j-tip-result-in 120ms ease-out both; } @media (prefers-reduced-motion: reduce) { .animate-cmd-j-tip-caret { animation: none; opacity: 1; } .animate-cmd-j-tip-result-in { animation: none; opacity: 1; transform: none; } } /* ── Feature wall: agents-orchestration animations ───────────────── */ /* Why: drives the supported-agents marquee on page 1 of the agents tile. Track is duplicated in the DOM so a -50% translate loops seamlessly. */ @keyframes feature-wall-marquee-flow { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } } .feature-wall-marquee-track { animation: feature-wall-marquee-flow 36s linear infinite; } /* Shared click pulse for feature-wall fake cursors. Matches the Editor tour ring so every animated mouse click reads as the same interaction. */ .feature-wall-click-ring { animation: feature-wall-click-ring 460ms ease-out forwards; } @keyframes feature-wall-click-ring { 0% { transform: scale(0.4); opacity: 0.9; } 100% { transform: scale(1.4); opacity: 0; } } /* Why: smooth reveal for the Tasks-tile workspace card so it eases in once the workspace flips from "Creating" to "Ready" instead of popping in. */ @keyframes tasks-workspace-in { 0% { opacity: 0; transform: translateY(4px); } 100% { opacity: 1; transform: translateY(0); } } /* Why: orchestrator → child connector arrows. Faint dashed strokes drawn in JS so endpoints follow the real card geometry as cards animate between phase 1 (parent + nested child) and phase 2 (parent + spawned peer). */ .feature-wall-orch-arrows { position: absolute; inset: 0; pointer-events: none; z-index: 1; transition: opacity 280ms ease; } .feature-wall-orch-arrows[data-fading='true'] { opacity: 0; } .feature-wall-orch-arrows path { fill: none; stroke: color-mix(in srgb, var(--foreground) 32%, transparent); stroke-width: 1.5; stroke-dasharray: 4 4; } /* Message envelope that travels along the dashed connector. Position is driven by `offset-path` so the bubble visibly follows the same shape the connector drew. */ .feature-wall-bubble { position: absolute; top: 0; left: 0; z-index: 3; width: 24px; height: 24px; border-radius: 999px; background: var(--foreground); color: var(--background); display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 6px 16px rgba(24, 24, 27, 0.22), 0 1px 2px rgba(24, 24, 27, 0.12); opacity: 0; offset-rotate: 0deg; offset-distance: 0%; pointer-events: none; will-change: offset-distance, opacity, transform; transform: translate(-12px, -12px) scale(0.7); } .feature-wall-bubble svg { width: 13px; height: 13px; } .feature-wall-bubble.in-flight { opacity: 1; offset-distance: 100%; transform: translate(-12px, -12px) scale(1); transition: offset-distance 1600ms cubic-bezier(0.25, 0.6, 0.25, 1), transform 280ms ease, opacity 280ms ease; } .feature-wall-bubble.landed { opacity: 0; offset-distance: 100%; transform: translate(-12px, -12px) scale(0.85); transition: opacity 320ms ease 80ms; } /* When a message just lands, briefly tint the recipient line so the new text reads as a fresh inbound message rather than ambient text. */ @keyframes feature-wall-msg-pop { 0% { color: rgb(180 83 9); } 70% { color: rgb(180 83 9); } 100% { color: var(--foreground); } } .feature-wall-msg-received { animation: feature-wall-msg-pop 1100ms ease-out; } /* Children container fades in once the orchestrator finishes creating. */ .feature-wall-children-wrapper { opacity: 0; transform: translateY(6px); transition: opacity 320ms ease, transform 320ms ease; } .feature-wall-children-wrapper[data-visible='true'] { opacity: 1; transform: none; } @keyframes feature-wall-child-card-in { 0% { opacity: 0; transform: translateY(4px); } 100% { opacity: 1; transform: translateY(0); } } .feature-wall-child-card-shell { animation: feature-wall-child-card-in 260ms ease-out both; } /* Each child agent row stays collapsed until *its* dispatch bubble lands on it, so the child workspace visibly gains an agent as work arrives. */ .feature-wall-spawn-row { overflow: hidden; opacity: 1; max-height: 60px; transform: none; transition: opacity 320ms ease 80ms, transform 320ms ease 80ms, max-height 320ms cubic-bezier(0.4, 0, 0.2, 1) 80ms, margin 320ms cubic-bezier(0.4, 0, 0.2, 1) 80ms, padding 320ms cubic-bezier(0.4, 0, 0.2, 1) 80ms; } .feature-wall-spawn-row[data-pending='true'] { opacity: 0; transform: translateY(2px); pointer-events: none; max-height: 0; margin-top: 0; margin-bottom: 0; padding-top: 0; padding-bottom: 0; transition: opacity 220ms ease, transform 220ms ease, max-height 320ms cubic-bezier(0.4, 0, 0.2, 1), margin 320ms cubic-bezier(0.4, 0, 0.2, 1), padding 320ms cubic-bezier(0.4, 0, 0.2, 1); } /* Brief one-shot pulse when the Codex limits popover swaps accounts and the "0% used" label flashes from red to green. */ @keyframes feature-wall-meta-pulse { 0% { color: rgb(220 38 38); transform: scale(1); } 20% { color: rgb(22 163 74); transform: scale(1.08); } 100% { color: rgb(22 163 74); transform: scale(1); } } .feature-wall-meta-pulse { color: rgb(22 163 74); font-weight: 600; animation: feature-wall-meta-pulse 1100ms ease-out 1; } /* Onboarding step 5: the compact "Take the tour" intro expands into the full tour shell, so animate the browser snapshots to avoid a hard jump. */ html.onboarding-tour-start-transition::view-transition-old(root), html.onboarding-tour-start-transition::view-transition-new(root) { animation-duration: 760ms; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); animation-fill-mode: both; mix-blend-mode: normal; } html.onboarding-tour-start-transition::view-transition-old(root) { animation-name: onboarding-tour-start-old; } html.onboarding-tour-start-transition::view-transition-new(root) { animation-name: onboarding-tour-start-new; } @keyframes onboarding-tour-start-old { 0% { opacity: 1; transform: translateY(0) scale(1); } 28% { opacity: 0.9; transform: translateY(-2px) scale(0.998); } 42% { opacity: 0; transform: translateY(-12px) scale(0.99); } 100% { opacity: 0; transform: translateY(-12px) scale(0.99); } } @keyframes onboarding-tour-start-new { 0% { opacity: 0; transform: translateY(18px) scale(0.992); } 34% { opacity: 0; transform: translateY(18px) scale(0.992); } 100% { opacity: 1; transform: translateY(0) scale(1); } } /* ── Feature tour nudge: cycling preview ─────────────────────────── */ /* Why: the bottom-right nudge cycles through 4 silhouette frames (Workspace → Orchestration → Tasks → Terminal). Each frame is visible for 1/4 of the cycle. Holding fade-out late (24%–25%) gives the user dwell time on the resolved state before swapping. Uses CSS-driven timing rather than React state so we stay cheap when the popup is mounted but idle. */ :root { --feature-tour-cycle: 16s; } .feature-tour-frame { position: absolute; inset: 0; opacity: 0; animation: feature-tour-frame-fade var(--feature-tour-cycle) linear infinite both; } .feature-tour-frame[data-frame='1'] { animation-delay: 0s; } .feature-tour-frame[data-frame='2'] { animation-delay: 4s; } .feature-tour-frame[data-frame='3'] { animation-delay: 8s; } .feature-tour-frame[data-frame='4'] { animation-delay: 12s; } @keyframes feature-tour-frame-fade { 0% { opacity: 0; } 1.5% { opacity: 1; } 24% { opacity: 1; } 25% { opacity: 0; } 100% { opacity: 0; } } .orca-contextual-tour-target-rings { border-radius: 9999px; pointer-events: none; } .orca-contextual-tour-target-rings::before { content: ''; position: absolute; inset: -2px; border: 1px solid color-mix(in srgb, var(--ring) 72%, transparent); border-radius: inherit; box-shadow: 0 0 0 1px color-mix(in srgb, var(--ring) 18%, transparent); opacity: 0; transform-origin: center; animation: contextual-tour-target-ring 1.8s ease-out infinite; } @keyframes contextual-tour-target-ring { 0% { opacity: 0.72; transform: scale(0.68); } 72%, 100% { opacity: 0; transform: scale(2.4); } } @media (prefers-reduced-motion: reduce) { .orca-contextual-tour-target-rings::before { animation: none; opacity: 0.72; transform: scale(1.28); } } .feature-tour-copy-slide { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 4px; opacity: 0; animation: feature-tour-frame-fade var(--feature-tour-cycle) linear infinite both; } .feature-tour-copy-slide[data-frame='1'] { animation-delay: 0s; } .feature-tour-copy-slide[data-frame='2'] { animation-delay: 4s; } .feature-tour-copy-slide[data-frame='3'] { animation-delay: 8s; } .feature-tour-copy-slide[data-frame='4'] { animation-delay: 12s; } .feature-tour-dot { width: 5px; height: 5px; border-radius: 9999px; background: color-mix(in srgb, var(--foreground) 18%, transparent); animation: feature-tour-dot-pulse var(--feature-tour-cycle) linear infinite; } .feature-tour-dot[data-frame='1'] { animation-delay: 0s; } .feature-tour-dot[data-frame='2'] { animation-delay: 4s; } .feature-tour-dot[data-frame='3'] { animation-delay: 8s; } .feature-tour-dot[data-frame='4'] { animation-delay: 12s; } @keyframes feature-tour-dot-pulse { 0%, 24% { background: var(--primary); transform: scale(1.05); } 25%, 100% { background: color-mix(in srgb, var(--foreground) 18%, transparent); transform: scale(1); } } /* Frame 1 — Workspace: agent-state dot pulses while a "fix login race" workspace shows two agent rows working in parallel. */ .feature-tour-ws-status { animation: feature-tour-status-pulse 1.6s ease-in-out infinite; } @keyframes feature-tour-status-pulse { 0%, 100% { opacity: 0.95; transform: scale(1); } 50% { opacity: 0.55; transform: scale(0.85); } } /* Frame 2 — Orchestration: child cards flash as bubbles land along the dashed paths fanning down from the coordinator. */ /* Why: bubbles use percent-based left/top so they always travel from the root card's right edge (34%) to the child card's left edge (64%), regardless of preview width. The previous offset-path used hardcoded pixels and drifted off the dashed lines once the preview resized. */ .feature-tour-orch-bubble { position: absolute; left: 34%; top: 50%; width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; border-radius: 3px; background: var(--primary); color: var(--primary-foreground); display: inline-flex; align-items: center; justify-content: center; opacity: 0; z-index: 4; } .feature-tour-orch-bubble.top { animation: feature-tour-orch-travel-top var(--feature-tour-cycle) cubic-bezier(0.4, 0, 0.2, 1) infinite; animation-delay: 4s; } .feature-tour-orch-bubble.mid { animation: feature-tour-orch-travel-mid var(--feature-tour-cycle) cubic-bezier(0.4, 0, 0.2, 1) infinite; animation-delay: calc(4s + 0.2s); } .feature-tour-orch-bubble.bot { animation: feature-tour-orch-travel-bot var(--feature-tour-cycle) cubic-bezier(0.4, 0, 0.2, 1) infinite; animation-delay: calc(4s + 0.4s); } @keyframes feature-tour-orch-travel-top { 0% { left: 34%; top: 50%; opacity: 0; } 2% { opacity: 1; } 3.5% { left: 49%; top: 50%; opacity: 1; } 6.5% { left: 64%; top: 18%; opacity: 1; } 7.5% { left: 64%; top: 18%; opacity: 0; } 25%, 100% { left: 64%; top: 18%; opacity: 0; } } @keyframes feature-tour-orch-travel-mid { 0% { left: 34%; top: 50%; opacity: 0; } 2% { opacity: 1; } 6.5% { left: 64%; top: 50%; opacity: 1; } 7.5% { left: 64%; top: 50%; opacity: 0; } 25%, 100% { left: 64%; top: 50%; opacity: 0; } } @keyframes feature-tour-orch-travel-bot { 0% { left: 34%; top: 50%; opacity: 0; } 2% { opacity: 1; } 3.5% { left: 49%; top: 50%; opacity: 1; } 6.5% { left: 64%; top: 82%; opacity: 1; } 7.5% { left: 64%; top: 82%; opacity: 0; } 25%, 100% { left: 64%; top: 82%; opacity: 0; } } .feature-tour-orch-child { animation: feature-tour-orch-child-flash var(--feature-tour-cycle) linear infinite; } .feature-tour-orch-child.top { animation-delay: 4s; } .feature-tour-orch-child.mid { animation-delay: calc(4s + 0.2s); } .feature-tour-orch-child.bot { animation-delay: calc(4s + 0.4s); } @keyframes feature-tour-orch-child-flash { 0%, 6% { box-shadow: 0 0 0 0 transparent; border-color: var(--border); } 7% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--foreground) 12%, transparent); border-color: color-mix(in srgb, var(--foreground) 38%, transparent); } 9% { box-shadow: 0 0 0 0 transparent; border-color: var(--border); } 25%, 100% { box-shadow: 0 0 0 0 transparent; border-color: var(--border); } } /* Frame 3 — Tasks: cursor lands on the second row, the "Open" pill morphs to a dark "Start workspace →" pill, then a workspace card slides in. */ .feature-tour-tasks-cursor { /* Why: anchored from the row's right edge so the cursor sits just past the pill's right edge (12px row padding + ~6px past pill end) instead of covering the label text. The arrow tip (top-left of the SVG) lands on the dark pill's trailing edge with the body of the cursor extending right. */ position: absolute; top: 50%; right: 14px; width: 14px; height: 14px; pointer-events: none; z-index: 8; transform: translate(120px, -30%); opacity: 0; animation: feature-tour-tasks-cursor var(--feature-tour-cycle) cubic-bezier(0.45, 0.05, 0.2, 1) infinite; animation-delay: 8s; } .feature-tour-tasks-cursor svg { width: 14px; height: 14px; display: block; } @keyframes feature-tour-tasks-cursor { 0% { transform: translate(160px, -10%); opacity: 0; } 2% { opacity: 1; } 5% { transform: translate(60px, -30%); opacity: 1; } 8% { transform: translate(0px, -30%); opacity: 1; } 9% { transform: translate(0px, -10%); opacity: 1; } 10.5% { transform: translate(0px, -30%); opacity: 1; } 23.5% { transform: translate(0px, -30%); opacity: 1; } 24.5% { opacity: 0; } 25%, 100% { transform: translate(0px, -30%); opacity: 0; } } .feature-tour-tasks-row { animation: feature-tour-tasks-row-hover var(--feature-tour-cycle) linear infinite; animation-delay: 8s; } @keyframes feature-tour-tasks-row-hover { 0%, 4% { background: transparent; box-shadow: none; } 6% { background: color-mix(in srgb, var(--foreground) 5%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 6%, transparent); } 23.5% { background: color-mix(in srgb, var(--foreground) 5%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 6%, transparent); } 25%, 100% { background: transparent; box-shadow: none; } } .feature-tour-tasks-pill { animation: feature-tour-tasks-pill-morph var(--feature-tour-cycle) linear infinite; animation-delay: 8s; } @keyframes feature-tour-tasks-pill-morph { 0%, 6% { width: 28px; background: rgb(34 197 94 / 0.14); border-color: rgb(34 197 94 / 0.3); box-shadow: none; } 8% { width: 78px; background: var(--primary); border-color: var(--primary); box-shadow: 0 1px 2px rgb(0 0 0 / 0.18); } 23.5% { width: 78px; background: var(--primary); border-color: var(--primary); box-shadow: 0 1px 2px rgb(0 0 0 / 0.18); } 25%, 100% { width: 28px; background: rgb(34 197 94 / 0.14); border-color: rgb(34 197 94 / 0.3); box-shadow: none; } } .feature-tour-tasks-pill-label { opacity: 0; animation: feature-tour-tasks-pill-label var(--feature-tour-cycle) linear infinite; animation-delay: 8s; } @keyframes feature-tour-tasks-pill-label { 0%, 7% { opacity: 0; } 9% { opacity: 1; } 23.5% { opacity: 1; } 24.5% { opacity: 0; } 25%, 100% { opacity: 0; } } /* Click ring fires when the cursor "clicks" the morphed pill on the tasks row. Positioned to overlay the right-side pill of the second task. */ .feature-tour-tasks-click-ring { /* Why: ring is centered on the cursor tip (right=28 from row's right edge) so the click feedback lands where the cursor is, on the arrow icon — not centered on the pill, which would visually disconnect from the cursor. */ position: absolute; top: 50%; right: 14px; width: 28px; height: 28px; margin-top: -14px; border-radius: 9999px; border: 1.5px solid color-mix(in srgb, var(--foreground) 55%, transparent); opacity: 0; z-index: 7; pointer-events: none; animation: feature-tour-tasks-click-ring var(--feature-tour-cycle) linear infinite; animation-delay: 8s; } @keyframes feature-tour-tasks-click-ring { 0%, 7% { opacity: 0; transform: scale(0.4); } 8% { opacity: 0.85; transform: scale(0.6); } 10% { opacity: 0; transform: scale(1.4); } 25%, 100% { opacity: 0; transform: scale(1.4); } } /* Newly-created workspace card slides in beneath the task row once the user clicks "Start workspace" — sells the "task → workspace" jump. */ .feature-tour-tasks-workspace { opacity: 0; transform: translateY(-6px); animation: feature-tour-tasks-workspace var(--feature-tour-cycle) linear infinite; animation-delay: 8s; } @keyframes feature-tour-tasks-workspace { 0%, 10% { opacity: 0; transform: translateY(-6px); } 12% { opacity: 1; transform: translateY(0); } 23.5% { opacity: 1; transform: translateY(0); } 25%, 100% { opacity: 0; transform: translateY(-6px); } } /* Frame 4 — Terminal: command stays anchored while the split panes stream Playwright and Claude activity. */ .feature-tour-terminal-line { width: 23ch; } .feature-tour-terminal-output { opacity: 0; transform: translateY(2px); animation: feature-tour-terminal-output var(--feature-tour-cycle) linear infinite; animation-delay: 12s; } .feature-tour-terminal-output[data-line='1'] { animation-delay: calc(12s + 0.05s); } .feature-tour-terminal-output[data-line='2'] { animation-delay: calc(12s + 0.25s); } .feature-tour-terminal-output[data-line='3'] { animation-delay: calc(12s + 0.45s); } @keyframes feature-tour-terminal-output { 0%, 10% { opacity: 0; transform: translateY(2px); } 12% { opacity: 1; transform: translateY(0); } 23.5% { opacity: 1; transform: translateY(0); } 25%, 100% { opacity: 0; transform: translateY(2px); } } @media (prefers-reduced-motion: reduce) { .feature-tour-frame, .feature-tour-copy-slide, .feature-tour-dot, .feature-tour-ws-status, .feature-tour-orch-bubble, .feature-tour-orch-child, .feature-tour-tasks-cursor, .feature-tour-tasks-row, .feature-tour-tasks-pill, .feature-tour-tasks-pill-label, .feature-tour-tasks-click-ring, .feature-tour-tasks-workspace, .feature-tour-terminal-output { animation: none !important; } .feature-tour-frame[data-frame='1'], .feature-tour-copy-slide[data-frame='1'] { opacity: 1; } .feature-tour-dot[data-frame='1'] { background: var(--primary); } } /* ── Diff comment decorations ────────────────────────────────────── */ /* Why: the "+" button is appended into Monaco's editor DOM node by useDiffCommentDecorator. Keep it visually subtle until hovered so it does not distract from the diff itself. Left position overlaps the glyph margin so the affordance reads as "add comment on this line". */ .orca-diff-comment-add-btn { position: absolute; left: 4px; width: 18px; height: 18px; display: none; align-items: center; justify-content: center; padding: 0; border: 1px solid color-mix(in srgb, var(--foreground) 22%, var(--border)); border-radius: 4px; background: color-mix(in srgb, var(--foreground) 5%, var(--editor-surface)); color: color-mix(in srgb, var(--foreground) 78%, var(--muted-foreground)); cursor: pointer; z-index: 5; opacity: 1; box-shadow: 0 1px 2px color-mix(in srgb, var(--foreground) 12%, transparent); transition: color 100ms ease, background-color 100ms ease, border-color 100ms ease, box-shadow 100ms ease; } .orca-diff-comment-add-btn:hover { color: var(--primary); border-color: color-mix(in srgb, var(--primary) 52%, var(--border)); background: color-mix(in srgb, var(--primary) 12%, var(--background)); box-shadow: 0 1px 4px color-mix(in srgb, var(--foreground) 16%, transparent); } .orca-diff-comment-add-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; } .orca-diff-comment-range-highlight { background: rgba(59, 130, 246, 0.14); } .dark .orca-diff-comment-range-highlight { background: rgba(96, 165, 250, 0.18); } .orca-diff-comment-inline { width: 100%; /* Why: Monaco's view-zone node already starts after the diff gutter. Avoid adding a second left inset so saved notes sit flush with the code column. */ padding: 4px 24px 6px 0; box-sizing: border-box; } .orca-diff-comment-inline > .orca-diff-comment-card { max-width: 420px; } /* Why: the saved note used to blend into the editor background because it reused the same muted/background mix the editor itself uses. Stay grayscale to match the rest of the UI, but lift the card off the editor with a foreground-tinted fill, a solid left accent bar, a soft shadow, and a bolded uppercase meta label. Dark mode uses 6% (vs light's 5%) to produce roughly the same absolute luminance delta above its editor surface — the foreground color is different (white vs black) so equal percentages would not give equal contrast. Override lives in `.dark`. */ .orca-diff-comment-card { position: relative; /* Why: Monaco's view-lines overlay (data-mprt=8) is positioned absolutely on top of view-zone DOM. Without an explicit z-index here, clicks on interior controls (Cancel/Save in edit mode, the textarea, etc.) hit the overlay first and never reach our buttons. Lifting the whole card creates a stacking context that keeps every nested control clickable. */ z-index: 1; display: flex; gap: 12px; border: 1px solid color-mix(in srgb, var(--foreground) 10%, var(--border)); border-radius: 8px; background: var(--background); padding: 12px 14px; font-family: var(--font-sans, system-ui, -apple-system, sans-serif); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(0, 0, 0, 0.03); transition: border-color 150ms ease, box-shadow 150ms ease, background-color 150ms ease; } .dark .orca-diff-comment-card { border-color: color-mix(in srgb, var(--foreground) 12%, var(--border)); background: color-mix(in srgb, var(--foreground) 2%, var(--editor-surface)); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.15); } /* Content Column */ .orca-diff-comment-content-col { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; } /* Header Row */ .orca-diff-comment-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-width: 0; } /* Meta Group (Name, line, timestamp) */ .orca-diff-comment-meta-group { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; font-size: 13px; line-height: 1.4; font-weight: 600; color: var(--foreground); } /* Action button pill: segmented control like Notion's Resolve / ... */ .orca-diff-comment-actions-pill { display: inline-flex; align-items: center; gap: 2px; padding: 0 2px; border: 1px solid color-mix(in srgb, var(--foreground) 10%, var(--border)); border-radius: 6px; background: var(--background); overflow: hidden; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02); } .dark .orca-diff-comment-actions-pill { border-color: color-mix(in srgb, var(--foreground) 14%, var(--border)); background: color-mix(in srgb, var(--foreground) 4%, var(--editor-surface)); } .orca-diff-comment-pill-btn { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; padding: 4px 7px; font-size: 11px; font-weight: 500; color: var(--muted-foreground); border: none; background: transparent; cursor: pointer; height: 24px; transition: background-color 100ms ease, color 100ms ease; } .orca-diff-comment-edit { min-width: 28px; height: 24px; padding: 4px 7px; border-radius: 4px; } .orca-diff-comment-pill-btn:hover { background: color-mix(in srgb, var(--foreground) 6%, transparent); color: var(--foreground); } .orca-diff-comment-pill-btn-danger:hover { background: color-mix(in srgb, var(--destructive) 10%, transparent); color: var(--destructive); } .orca-diff-comment-pill-divider { width: 1px; height: 12px; background: color-mix(in srgb, var(--foreground) 12%, var(--border)); flex-shrink: 0; } /* Quote/Reference block: Warm, gorgeous Notion-like callout */ .orca-diff-comment-quote { display: flex; align-items: flex-start; gap: 8px; margin: 2px 0 4px 0; padding-left: 8px; border-left: 2px solid color-mix(in srgb, #e7b10a 35%, transparent); color: var(--muted-foreground); font-size: 12.5px; line-height: 1.35; } .orca-diff-comment-quote-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Comment Body */ .orca-diff-comment-body { font-size: 13.5px; line-height: 1.5; color: var(--foreground); white-space: pre-wrap; word-break: break-word; margin-top: 2px; } /* Popover for adding new comment */ .orca-diff-comment-popover { position: absolute; left: 56px; right: 24px; max-width: 420px; z-index: 1000; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--foreground) 10%, var(--border)); border-radius: 8px; background: var(--background); color: var(--foreground); box-shadow: 0 10px 32px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08); } .dark .orca-diff-comment-popover { border-color: color-mix(in srgb, var(--foreground) 14%, var(--border)); background: color-mix(in srgb, var(--foreground) 2%, var(--editor-surface)); box-shadow: 0 10px 32px rgba(0, 0, 0, 0.3), 0 4px 16px rgba(0, 0, 0, 0.2); } .orca-diff-comment-popover-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted-foreground); margin-bottom: 2px; } .orca-diff-comment-popover-textarea { width: 100%; min-height: 56px; max-height: 240px; overflow-y: auto; resize: none; padding: 8px 12px; border: 1px solid color-mix(in srgb, var(--foreground) 12%, var(--border)); border-radius: 6px; background: var(--background); color: var(--foreground); font-family: inherit; font-size: 13px; line-height: 1.45; outline: none; transition: border-color 150ms ease, box-shadow 150ms ease; } .dark .orca-diff-comment-popover-textarea { border-color: color-mix(in srgb, var(--foreground) 10%, var(--border)); background: color-mix(in srgb, var(--foreground) 3%, var(--editor-surface)); } .orca-diff-comment-popover-textarea:focus { border-color: color-mix(in srgb, var(--ring) 70%, var(--border)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 18%, transparent); } .dark .orca-diff-comment-popover-textarea:focus { border-color: color-mix(in srgb, var(--ring) 70%, var(--border)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 12%, transparent); } .orca-diff-comment-popover-textarea::-webkit-scrollbar { width: 12px; } .orca-diff-comment-popover-textarea::-webkit-scrollbar-track { background: transparent; } .orca-diff-comment-popover-textarea::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--muted-foreground, #737373) 28%, transparent); border: 3px solid transparent; background-clip: padding-box; } .orca-diff-comment-popover-footer { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 4px; } /* Why: tours need a distinct item surface without highlighting the underlying target. */ .orca-contextual-tour-panel { --contextual-tour-panel-surface: color-mix(in srgb, var(--foreground) 7%, var(--popover)); --contextual-tour-panel-border: color-mix(in srgb, var(--foreground) 14%, var(--border)); background: var(--contextual-tour-panel-surface); border-color: var(--contextual-tour-panel-border); box-shadow: inset 0 1px 0 0 color-mix(in srgb, var(--foreground) 10%, transparent), 0 10px 24px rgba(0, 0, 0, 0.18); } .dark .orca-contextual-tour-panel { --contextual-tour-panel-surface: color-mix(in srgb, var(--foreground) 10%, var(--popover)); --contextual-tour-panel-border: color-mix(in srgb, var(--foreground) 16%, var(--border)); box-shadow: inset 0 1px 0 0 color-mix(in srgb, var(--foreground) 5%, transparent), 0 10px 24px rgba(0, 0, 0, 0.18); }