@import "tailwindcss"; @custom-variant dark (&:is(.dark, .dark *)); /* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */ @custom-variant wco (&:is(.wco, .wco *)); :root { --app-scrollbar-width: 6px; --workspace-topbar-height: 52px; --workspace-controls-top: 0px; --workspace-controls-left: calc(env(safe-area-inset-left) + 0.75rem); --workspace-controls-right: calc(env(safe-area-inset-right) + 0.75rem); --workspace-native-controls-inset: 0px; --workspace-titlebar-control-size: 1.75rem; --workspace-titlebar-control-gap: 0.75rem; } [data-slot="sidebar-wrapper"] { --workspace-titlebar-content-left: calc( var(--workspace-controls-left) + var(--workspace-titlebar-control-size) + var(--workspace-titlebar-control-gap) ); } .wco { --workspace-topbar-height: env(titlebar-area-height, 52px); --workspace-controls-top: env(titlebar-area-y, 0px); --workspace-controls-left: calc(env(titlebar-area-x, 0px) + 0.75rem); --workspace-controls-right: calc( 100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px) + 0.75rem ); --workspace-native-controls-inset: calc( 100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px) + 0.75rem ); } @theme inline { --animate-skeleton: skeleton 2s -1s infinite linear; /* Duty-cycled indicator animations: long opacity holds with short stepped ramps, so the compositor only produces frames while the value changes (~20% of the cycle) instead of every vsync. Keep flat holds dominant. */ --animate-status-pulse: status-pulse 2s infinite; --animate-status-ping: status-ping 2s infinite; --font-sans: "DM Sans Variable", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; --font-mono: "SF Mono", "SFMono-Regular", "JetBrains Mono", Consolas, "Liberation Mono", Menlo, monospace; --color-warning-foreground: var(--warning-foreground); --color-warning: var(--warning); --color-success-foreground: var(--success-foreground); --color-success: var(--success); --color-info-foreground: var(--info-foreground); --color-info: var(--info); --color-destructive-foreground: var(--destructive-foreground); --color-ring: var(--ring); --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); --color-muted: var(--muted); --color-secondary-foreground: var(--secondary-foreground); --color-secondary: var(--secondary); --color-primary-foreground: var(--primary-foreground); --color-primary: var(--primary); --color-popover-foreground: var(--popover-foreground); --color-popover: var(--popover); --color-card-foreground: var(--card-foreground); --color-card: var(--card); --color-foreground: var(--foreground); --color-background: var(--background); --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --radius-2xl: calc(var(--radius) + 8px); --radius-3xl: calc(var(--radius) + 12px); --radius-4xl: calc(var(--radius) + 16px); @keyframes skeleton { to { background-position: -200% 0; } } @keyframes status-pulse { 0%, 40% { opacity: 1; animation-timing-function: steps(6); } 50%, 90% { opacity: 0.5; animation-timing-function: steps(6); } 100% { opacity: 1; } } @keyframes status-ping { /* Burst first (immediate feedback for click ripples), then hold invisible for the rest of the cycle. Mirrors animate-ping's 75%-scale start. */ 0% { opacity: 0.9; scale: 0.75; animation-timing-function: steps(8); } 40%, 100% { opacity: 0; scale: 2; } } } @layer base { * { @apply border-border outline-ring/50; } :where([data-slot="menu-popup"], [data-slot="select-popup"], [data-slot="popover-popup"]):focus, :where( [data-slot="menu-popup"], [data-slot="select-popup"], [data-slot="popover-popup"] ):focus-visible { @apply outline-none ring-0; } html { background-color: var(--app-chrome-background); } body { @apply text-foreground relative; background-color: var(--app-chrome-background); } } @layer components { .sidebar-brand { display: none; } .sidebar-brand-stage { display: none; } @media (min-width: 48rem) { @container sidebar-header (min-width: 13.5rem) { .sidebar-brand { display: flex; } } @container sidebar-header (min-width: 15.75rem) { .sidebar-brand-stage { display: inline-flex; } } } .workspace-topbar { display: flex; height: var(--workspace-topbar-height); min-height: var(--workspace-topbar-height); flex-shrink: 0; align-items: center; } .workspace-titlebar-controls { position: absolute; top: var(--workspace-controls-top); right: var(--workspace-controls-right); display: flex; height: var(--workspace-topbar-height); align-items: center; -webkit-app-region: no-drag; } .surface-subheader { @apply flex h-10 min-h-10 shrink-0 items-center border-b border-border/60 bg-background; } .chat-composer-horizontal-inset { padding-inline-start: calc(env(safe-area-inset-left) + 0.75rem); padding-inline-end: calc(env(safe-area-inset-right) + 0.75rem); } .chat-composer-glass { background: color-mix(in srgb, var(--card) 20%, transparent); } /* Mix from --background (not --card): the lower chrome is a full-width strip over the main view, and a card-tinted wash reads as a lighter seam against it when no content is scrolled underneath. The backdrop blur, not the tint, carries the frosted effect. */ .chat-composer-lower-chrome { background: color-mix(in srgb, var(--background) 20%, transparent); } .chat-composer-glass { box-shadow: 0 18px 48px -20px rgb(0 0 0 / 28%), 0 4px 14px -7px rgb(0 0 0 / 22%); } .chat-composer-shared-blur { -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); } .dark .chat-composer-glass { background: color-mix(in srgb, var(--card) 45%, transparent); } .dark .chat-composer-lower-chrome { background: color-mix(in srgb, var(--background) 45%, transparent); } .dark .chat-composer-glass { box-shadow: 0 18px 48px -20px rgb(0 0 0 / 60%), 0 4px 14px -7px rgb(0 0 0 / 40%); } .chat-composer-lower-chrome { margin-top: -1px; margin-inline-end: var(--app-scrollbar-width); padding-top: 1px; } @media (min-width: 40rem) { .chat-composer-horizontal-inset { padding-inline-start: calc(env(safe-area-inset-left) + 1.25rem); padding-inline-end: calc(env(safe-area-inset-right) + 1.25rem); } } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { .chat-composer-glass { background: var(--card); } .chat-composer-lower-chrome { background: var(--background); } } } /* Safe-area inset utilities for surfaces that opt into edge-to-edge rendering. Insets resolve to 0 when the browser already constrains the layout viewport to the safe area. */ @utility pt-safe { padding-top: max(env(safe-area-inset-top), 0px); } @utility pb-safe { padding-bottom: max(env(safe-area-inset-bottom), 0px); } @utility pl-safe { padding-left: max(env(safe-area-inset-left), 0px); } @utility pr-safe { padding-right: max(env(safe-area-inset-right), 0px); } /* Grain texture for chrome surfaces that float above the body (see the --surface-grain note). Layered over the element's background-color, so it composes with bg-* utilities. */ @utility surface-grain { background-image: var(--surface-grain); background-repeat: repeat; background-size: 256px 256px; } /* Suppress all transitions during theme changes */ .no-transitions, .no-transitions *, .no-transitions *::before, .no-transitions *::after { transition-duration: 0s !important; animation-duration: 0s !important; } :root { color-scheme: light; --radius: 0.625rem; --background: var(--color-white); --app-chrome-background: var(--background); --foreground: var(--color-neutral-800); --card: var(--color-white); --card-foreground: var(--color-neutral-800); --popover: var(--color-white); --popover-foreground: var(--color-neutral-800); --primary: oklch(0.488 0.217 264); --primary-foreground: var(--color-white); --secondary: --alpha(var(--color-black) / 4%); --secondary-foreground: var(--color-neutral-800); --muted: --alpha(var(--color-black) / 4%); --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-black)); --accent: --alpha(var(--color-black) / 4%); --accent-foreground: var(--color-neutral-800); --destructive: var(--color-red-500); --border: --alpha(var(--color-black) / 8%); --input: --alpha(var(--color-black) / 10%); --ring: oklch(0.488 0.217 264); --destructive-foreground: var(--color-red-700); --info: var(--color-blue-500); --info-foreground: var(--color-blue-700); --success: var(--color-emerald-500); --success-foreground: var(--color-emerald-700); --warning: var(--color-amber-500); --warning-foreground: var(--color-amber-700); @variant dark { color-scheme: dark; --background: color-mix(in srgb, var(--color-neutral-950) 95%, var(--color-white)); --app-chrome-background: var(--background); --foreground: var(--color-neutral-100); --card: color-mix(in srgb, var(--background) 98%, var(--color-white)); --card-foreground: var(--color-neutral-100); --popover: color-mix(in srgb, var(--background) 98%, var(--color-white)); --popover-foreground: var(--color-neutral-100); --primary: oklch(0.588 0.217 264); --primary-foreground: var(--color-white); --secondary: --alpha(var(--color-white) / 4%); --secondary-foreground: var(--color-neutral-100); --muted: --alpha(var(--color-white) / 4%); --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-white)); --accent: --alpha(var(--color-white) / 4%); --accent-foreground: var(--color-neutral-100); --destructive: color-mix(in srgb, var(--color-red-500) 90%, var(--color-white)); --border: --alpha(var(--color-white) / 6%); --input: --alpha(var(--color-white) / 8%); --ring: oklch(0.588 0.217 264); --destructive-foreground: var(--color-red-400); --info: var(--color-blue-500); --info-foreground: var(--color-blue-400); --success: var(--color-emerald-500); --success-foreground: var(--color-emerald-400); --warning: var(--color-amber-500); --warning-foreground: var(--color-amber-400); } } body { font-family: "DM Sans Variable", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; margin: 0; padding: 0; } html, body { min-height: calc(100svh + env(safe-area-inset-top)); overscroll-behavior: none; } body { height: 100%; overflow: hidden; } #root { height: 100%; width: 100%; max-width: 100%; overflow-x: hidden; overflow-x: clip; overflow-y: hidden; overscroll-behavior-y: none; padding-top: max(env(safe-area-inset-top), 0px); } /* App-chrome grain. Baked into each surface's own background (behind content) rather than a fixed overlay on top: a full-viewport overlay forces the compositor to re-blend every frame any animation produces, which multiplied idle GPU cost. The overlay's 0.035 opacity lives in the SVG rect instead. Surfaces that float over the body (e.g. the inset main card) must opt in via the surface-grain utility, or they lose the grain's subtle brightening and stand out against the body. */ :root { --surface-grain: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E"); } body { background-image: var(--surface-grain); background-repeat: repeat; background-size: 256px 256px; } pre, code { font-family: "SF Mono", "SFMono-Regular", "JetBrains Mono", Consolas, "Liberation Mono", Menlo, monospace; } /* Window drag region (frameless titlebar) */ .drag-region { -webkit-app-region: drag; } .drag-region button, .drag-region input, .drag-region textarea, .drag-region select, .drag-region a { -webkit-app-region: no-drag; } /* Scrollbar styling */ ::-webkit-scrollbar { width: var(--app-scrollbar-width); } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.15); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.25); } .dark ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); } .dark ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.18); } .turn-chip-strip { scrollbar-width: none; -ms-overflow-style: none; overscroll-behavior-x: contain; } .turn-chip-strip::-webkit-scrollbar { display: none; } /* Terminal drawer scrollbar parity with chat */ .thread-terminal-drawer .xterm .xterm-scrollable-element > .scrollbar.vertical { width: 6px !important; } .thread-terminal-drawer .xterm .xterm-scrollable-element > .scrollbar > .slider { border-radius: 3px; } .thread-terminal-drawer .xterm .xterm-scrollable-element > .scrollbar.vertical > .slider { width: 6px !important; left: 0 !important; } /* Reasoning select -- clickable label surface */ label:has(> select#reasoning-effort) { position: relative; } label:has(> select#reasoning-effort) select { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; } /* Chat markdown rendering */ .chat-markdown { min-width: 0; overflow-wrap: anywhere; word-break: break-word; } .chat-markdown > :first-child { margin-top: 0; } .chat-markdown > :last-child { margin-bottom: 0; } .chat-markdown p, .chat-markdown ul, .chat-markdown ol, .chat-markdown blockquote, .chat-markdown pre, .chat-markdown .chat-markdown-table-container { margin: 0.65rem 0; } .chat-markdown h1, .chat-markdown h2, .chat-markdown h3, .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 { margin: 1.25rem 0 0.5rem; font-weight: 600; line-height: 1.3; color: var(--foreground); } .chat-markdown h1 { font-size: 1.25rem; } .chat-markdown h2 { font-size: 1.125rem; } .chat-markdown h3 { font-size: 1rem; } .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 { font-size: 0.875rem; } .chat-markdown h6 { color: var(--muted-foreground); } .chat-markdown ul { padding-left: 1.25rem; list-style-type: disc; } .chat-markdown ol { padding-left: 1.25rem; list-style-type: decimal; } .chat-markdown ul ul { list-style-type: circle; } .chat-markdown ul ul ul { list-style-type: square; } .chat-markdown ol ol { list-style-type: lower-alpha; } .chat-markdown ol ol ol { list-style-type: lower-roman; } .chat-markdown li + li { margin-top: 0.25rem; } /* GitHub-style task lists: the checkbox replaces the list marker. */ .chat-markdown li.task-list-item { list-style-type: none; } .chat-markdown li.task-list-item input[type="checkbox"] { margin: 0 0.35em 0.15em -1.25rem; vertical-align: middle; } .chat-markdown a { color: var(--info-foreground); text-decoration: none; } .chat-markdown a:not(.chat-markdown-file-link):hover, .chat-markdown a:not(.chat-markdown-file-link):focus-visible { background-image: radial-gradient(circle, currentcolor 0.75px, transparent 1px); background-position: left bottom; background-repeat: repeat-x; background-size: 4px 2px; } .chat-markdown .chat-markdown-link-favicon { @apply inline-flex; width: 14px; height: 14px; margin-inline: 0.25em 0.2em; vertical-align: -0.125em; } .chat-markdown .chat-markdown-link-leading { white-space: nowrap; } .chat-markdown blockquote { border-left: 2px solid var(--border); padding-left: 0.8rem; color: var(--muted-foreground); } .chat-markdown section[data-footnotes] { margin-top: 1.25rem; border-top: 1px solid var(--border); padding-top: 0.75rem; color: var(--muted-foreground); font-size: 0.75rem; } .chat-markdown section[data-footnotes] ol { margin: 0; padding-left: 1.25rem; } .chat-markdown section[data-footnotes] li + li { margin-top: 0.35rem; } .chat-markdown a[data-footnote-ref], .chat-markdown a[data-footnote-backref] { display: inline-flex; min-width: 1rem; align-items: center; justify-content: center; border-radius: 0.25rem; text-decoration: none; font-size: 0.6875rem; font-weight: 600; } .chat-markdown :not(pre) > code { border: 1px solid var(--border); border-radius: 0.375rem; background: var(--muted); padding: 0.1rem 0.35rem; color: var(--foreground); font-size: 0.75rem; } .chat-markdown a.chat-markdown-file-link { color: var(--foreground); text-decoration: none; } .chat-markdown a.chat-markdown-file-link:hover { color: var(--foreground); text-decoration: none; } .chat-markdown a.chat-markdown-file-link:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 70%, transparent); } .chat-markdown pre { max-width: 100%; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.75rem; background: var(--muted); padding: 0.8rem 0.9rem; } .chat-markdown pre code { border: none; background: transparent; padding: 0; font-size: 0.75rem; } .chat-markdown pre { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--border) 78%, transparent) transparent; } .chat-markdown pre::-webkit-scrollbar { height: 7px; } .chat-markdown pre::-webkit-scrollbar-track { background: transparent; } .chat-markdown pre::-webkit-scrollbar-thumb { border-radius: 999px; background: color-mix(in srgb, var(--border) 78%, transparent); } .markdown-file-link-tooltip-scroll { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--border) 78%, transparent) transparent; } .markdown-file-link-tooltip-scroll::-webkit-scrollbar { height: 6px; } .markdown-file-link-tooltip-scroll::-webkit-scrollbar-track { background: transparent; } .markdown-file-link-tooltip-scroll::-webkit-scrollbar-thumb { border-radius: 999px; background: color-mix(in srgb, var(--border) 78%, transparent); } .chat-markdown .chat-markdown-codeblock { margin: 0.65rem 0; overflow: hidden; border: 1px solid var(--border); border-radius: 0.75rem; background: color-mix(in srgb, var(--muted) 78%, var(--background)); } .chat-markdown .chat-markdown-codeblock-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; border-bottom: 1px solid var(--border); background: var(--muted); padding: 0.25rem 0.375rem 0.25rem 0.7rem; color: var(--muted-foreground); } .chat-markdown .chat-markdown-codeblock-title { display: inline-flex; min-width: 0; align-items: center; gap: 0.4rem; font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace); font-size: 0.6875rem; } .chat-markdown .chat-markdown-chrome-action { color: var(--muted-foreground); } .chat-markdown .chat-markdown-chrome-action:hover { color: var(--foreground); } .chat-markdown .chat-markdown-chrome-action[aria-pressed="true"] { color: var(--foreground); background: color-mix(in srgb, var(--foreground) 8%, transparent); } .chat-markdown .chat-markdown-codeblock pre { margin: 0; border: none; border-radius: 0; background: transparent; } .chat-markdown .chat-markdown-codeblock[data-wrap="true"] pre { white-space: pre-wrap; overflow-wrap: anywhere; } .chat-markdown .chat-markdown-shiki .shiki { background: transparent !important; } /* Diagnostics-style tables: row separators only, uppercase headers, and a scroll-fade container for horizontal overflow. The root chat-markdown wrapping rules (overflow-wrap: anywhere) would let columns shrink to single characters and defeat the overflow — restore word-boundary wrapping so the min column width is the longest word. */ .chat-markdown table { width: 100%; min-width: max-content; border-collapse: collapse; overflow-wrap: normal; word-break: normal; font-size: 0.75rem; } .chat-markdown th, .chat-markdown td { padding: 0.45rem 0.75rem; text-align: left; } .chat-markdown thead th { border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent); padding-block: 0.55rem; font-weight: 600; white-space: nowrap; } .chat-markdown tbody td { border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent); } /* Collapsed (default): single-line cells truncate so arbitrary chat content cannot blow the column out; the footer toggle expands cells to wrap. */ .chat-markdown .chat-markdown-table-container[data-expanded="false"] th, .chat-markdown .chat-markdown-table-container[data-expanded="false"] td { overflow: hidden; max-width: 24rem; text-overflow: ellipsis; white-space: nowrap; } .chat-markdown .chat-markdown-table-container[data-expanded="true"] td { max-width: 24rem; overflow-wrap: anywhere; } .chat-markdown .chat-markdown-table-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 0.125rem; } @keyframes provider-update-pill-countdown { from { transform: scaleX(1); } to { transform: scaleX(0); } } .provider-update-pill-progress { animation: provider-update-pill-countdown var(--provider-update-pill-dismiss-ms) linear forwards; } /* Diffs theme bridge (match diff surfaces to app palette) */ .diff-panel-viewport { background: color-mix(in srgb, var(--background) 94%, var(--card)); } .diff-render-file, .diff-render-surface > diffs-container { border: 1px solid var(--border); border-radius: 0.5rem; overflow: clip; background: color-mix(in srgb, var(--card) 92%, var(--background)); } @keyframes ultrathink-rainbow { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } } @keyframes ultrathink-chroma-shift { 0% { filter: hue-rotate(0deg) saturate(1.2); } 100% { filter: hue-rotate(360deg) saturate(1.2); } } .ultrathink-frame { --ultrathink-spectrum: linear-gradient( 120deg, #ff6b6b 0%, #f59e0b 18%, #22c55e 36%, #14b8a6 54%, #3b82f6 72%, #ec4899 90%, #ff6b6b 100% ); position: relative; background: transparent; } .ultrathink-frame::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background-image: var(--ultrathink-spectrum); background-size: 220% 220%; pointer-events: none; filter: saturate(0.82) brightness(0.92); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude; animation: ultrathink-rainbow 10s linear infinite; } .ultrathink-frame > * { position: relative; } .ultrathink-chroma { animation: ultrathink-chroma-shift 10s linear infinite; } .ultrathink-pill { background: linear-gradient(var(--card), var(--card)) padding-box, var(--ultrathink-spectrum) border-box; background-size: 100% 100%, 220% 220%; background-position: 0 0, 0% 50%; animation: ultrathink-rainbow 10s linear infinite; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--card) 82%, transparent); } .ultrathink-word { display: inline-block; color: transparent; background-image: var(--ultrathink-spectrum); background-size: 220% 220%; background-position: 0% 50%; background-clip: text; -webkit-background-clip: text; animation: ultrathink-rainbow 10s linear infinite; } /* Thin scrollbar for model picker */ .model-picker-list::-webkit-scrollbar { width: 4px; } .model-picker-list::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.1); border-radius: 2px; } .model-picker-list::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.2); } .dark .model-picker-list::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.08); } .dark .model-picker-list::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.15); }