@import "tailwindcss"; @custom-variant dark (&:is(.dark, .dark *)); @custom-variant light (&:not(.dark, .dark *)); /* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */ @custom-variant wco (&:is(.wco, .wco *)); /* On mobile, morph the expanded hero composer into the compact docked composer while it moves; the rest of the app remains visually stationary. */ html[data-mobile-composer-route-transition="true"]::view-transition-old(root), html[data-mobile-composer-route-transition="true"]::view-transition-new(root) { animation: none; } html[data-mobile-composer-route-transition="true"]::view-transition-group(t3-mobile-composer) { animation-duration: 180ms; animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } html[data-mobile-composer-route-transition="true"]::view-transition-image-pair(t3-mobile-composer) { isolation: isolate; } html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobile-composer) { animation: t3-mobile-composer-old 180ms linear both; mix-blend-mode: normal; } html[data-mobile-composer-route-transition="true"]::view-transition-new(t3-mobile-composer) { animation: t3-mobile-composer-new 180ms linear both; mix-blend-mode: normal; } /* The expanded and compact composers have different internal layouts. Use a brief crossfade while their shared wrapper moves so the layout change does not read as a single-frame cut. */ @keyframes t3-mobile-composer-old { 0%, 35% { opacity: 1; } 65%, 100% { opacity: 0; } } @keyframes t3-mobile-composer-new { 0%, 35% { opacity: 0; } 65%, 100% { opacity: 1; } } html[data-mobile-composer-route-transition="true"]::view-transition-group(t3-mobile-draft-headline) { animation-duration: 130ms; } html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobile-draft-headline) { animation: t3-mobile-draft-headline-exit 130ms cubic-bezier(0.4, 0, 1, 1) both; mix-blend-mode: normal; } @keyframes t3-mobile-draft-headline-exit { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-6px); } } :root { --app-scrollbar-width: 6px; --appearance-contrast-base: 100%; --appearance-contrast-boost: 0%; --appearance-contrast-border-boost: 0%; --appearance-contrast-target: black; --app-scrollbar-thumb: rgb(217 217 217); --app-scrollbar-thumb-hover: rgb(191 191 191); /* * Compact UI geometry. Keep these values semantic so sidebar, palette, * tooltip, and toolbar controls cannot quietly drift apart. */ --control-radius: 0.5rem; --sidebar-content-inset: 0.5rem; --sidebar-control-gap: 0.5rem; --sidebar-icon-color: color-mix( in srgb, var(--contrast-sidebar-muted-foreground) 60%, var(--sidebar) ); --sidebar-row-content-inset: 0.625rem; --command-shell-inset: 0.5rem; --command-content-inset: 1rem; --floating-content-inset: 0.75rem; --glass-blur: 12px; --glass-opacity: 80%; --glass-saturation: 1.14; --desktop-window-right-resize-inset: 0px; --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; @variant dark { --appearance-contrast-target: white; --app-scrollbar-thumb: rgb(255 255 255 / 8%); --app-scrollbar-thumb-hover: rgb(255 255 255 / 12%); --glass-blur: 16px; --glass-saturation: 1.08; } } .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 ); } /* The font tokens are declared outside the inline theme so utilities reference the variables and Settings -> Appearance can override them at runtime. The default stacks are mirrored in `appearanceFonts.ts`. */ @theme { --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace; } @theme inline { --color-zinc-25: oklch(99.2% 0 0); --animate-skeleton: skeleton 2s infinite linear; /* Duty-cycled indicator animations: long holds with stepped ramps, so the compositor updates discrete frames instead of every vsync. */ --animate-status-pulse: status-pulse 2s infinite; --animate-ghost-pulse: ghost-pulse 2.4s infinite; --animate-status-ping: status-ping 2s infinite; --color-warning-foreground: var(--warning-foreground); --color-warning: var(--warning); --color-warning-surface: var(--warning-surface); --color-error-foreground: var(--error-foreground); --color-error: var(--error); --color-error-surface: var(--error-surface); --color-update-foreground: var(--update-foreground); --color-update: var(--update); --color-update-surface: var(--update-surface); --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(--contrast-input); --color-border: var(--contrast-border); --color-destructive: var(--destructive); --color-accent-foreground: var(--contrast-accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--contrast-muted-foreground); --color-muted: var(--muted); --color-placeholder: var(--contrast-placeholder); --color-secondary-label: var(--contrast-secondary-label); --color-icon-muted: var(--contrast-icon-muted); --color-secondary-foreground: var(--contrast-secondary-foreground); --color-secondary: var(--secondary); --color-primary-foreground: var(--primary-foreground); --color-primary: var(--primary); --color-popover-foreground: var(--contrast-popover-foreground); --color-popover: var(--popover); --color-card-foreground: var(--contrast-card-foreground); --color-card: var(--card); --color-foreground: var(--contrast-foreground); --color-background: var(--background); --color-surface-raised: var(--surface-raised); --color-message: var(--message-surface); --color-message-foreground: var(--contrast-message-foreground); --color-message-action: var(--message-action); --color-message-action-foreground: var(--message-action-foreground); --color-message-action-hover: var(--message-action-hover); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--contrast-sidebar-foreground); --color-sidebar-muted-foreground: var(--contrast-sidebar-muted-foreground); --color-sidebar-control-surface: var(--sidebar-control-surface); --color-sidebar-row-hover: var(--sidebar-row-hover); --color-sidebar-row-active: var(--sidebar-row-active); --color-sidebar-row-selected: var(--sidebar-row-selected); --color-sidebar-border: var(--contrast-sidebar-border); --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 { /* Transform-only so the highlight sweep stays on the compositor, then a long hold with the band parked off-screen instead of a constant shimmer. */ 0% { transform: translateX(-100%); } 60%, 100% { transform: translateX(100%); } } @keyframes ghost-pulse { /* The loading ghosts' breath. Stepped like the status indicators, so however many bars a ghost holds, the compositor draws a handful of discrete frames per cycle rather than one per vsync — which on a 120Hz display is the difference between ~14 and ~288 updates. */ 0%, 42% { opacity: 1; animation-timing-function: steps(4); } 50%, 92% { opacity: 0.55; animation-timing-function: steps(4); } 100% { opacity: 1; } } @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; } } } @utility surface-glass { background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--background) !important; } } @utility alert-glass { --alert-glass-tint: transparent; background: linear-gradient( color-mix(in srgb, var(--alert-glass-tint) 4%, transparent), color-mix(in srgb, var(--alert-glass-tint) 4%, transparent) ), color-mix(in srgb, var(--background) var(--glass-opacity), transparent) !important; -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); &[data-variant="error"] { --alert-glass-tint: var(--destructive); } &[data-variant="info"] { --alert-glass-tint: var(--info); } &[data-variant="success"] { --alert-glass-tint: var(--success); } &[data-variant="warning"] { --alert-glass-tint: var(--warning); } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--background) !important; } } @utility dialog-glass { background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); border-color: color-mix(in srgb, var(--contrast-foreground) 10%, transparent); box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%); @variant dark { border-color: color-mix(in srgb, var(--color-white) 8%, transparent); box-shadow: inset 0 1px rgb(255 255 255 / 4%), 0 24px 72px -20px rgb(0 0 0 / 90%); } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--popover) !important; } } @utility dialog-backdrop { background: color-mix(in srgb, var(--background) 60%, transparent); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); @variant dark { background: color-mix(in srgb, var(--background) 64%, transparent); } } @utility dropdown-glass { background: color-mix( in srgb, var(--popover) 18%, color-mix(in srgb, var(--popover) var(--glass-opacity), transparent) ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); border: 1px solid color-mix(in srgb, var(--contrast-foreground) 10%, transparent); @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--popover) !important; } } @utility topbar-scroll-fade { --topbar-scroll-fade-height: 2.5rem; -webkit-mask-image: linear-gradient( to bottom, transparent 0%, rgb(0 0 0 / 10%) 10%, rgb(0 0 0 / 30%) 24%, rgb(0 0 0 / 58%) 42%, rgb(0 0 0 / 82%) 62%, rgb(0 0 0 / 96%) 82%, black 100% ), linear-gradient(black, black), linear-gradient(black, black); -webkit-mask-position: top, bottom, right; -webkit-mask-repeat: no-repeat; -webkit-mask-size: 100% var(--topbar-scroll-fade-height), 100% calc(100% - var(--topbar-scroll-fade-height)), var(--app-scrollbar-width) 100%; mask-image: linear-gradient( to bottom, transparent 0%, rgb(0 0 0 / 10%) 10%, rgb(0 0 0 / 30%) 24%, rgb(0 0 0 / 58%) 42%, rgb(0 0 0 / 82%) 62%, rgb(0 0 0 / 96%) 82%, black 100% ), linear-gradient(black, black), linear-gradient(black, black); mask-position: top, bottom, right; mask-repeat: no-repeat; mask-size: 100% var(--topbar-scroll-fade-height), 100% calc(100% - var(--topbar-scroll-fade-height)), var(--app-scrollbar-width) 100%; @variant sm { --topbar-scroll-fade-height: 3rem; } } /* Virtualizers own their native scroll element, so they cannot use ScrollArea's viewport fade. Keep the scrollbar lane opaque while sharing the same fade contract across those lists. */ @utility virtualized-scroll-fade { -webkit-mask-image: var(--virtualized-scroll-fade-mask), linear-gradient(black, black); mask-image: var(--virtualized-scroll-fade-mask), linear-gradient(black, black); -webkit-mask-position: left, right; mask-position: left, right; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-size: calc(100% - var(--app-scrollbar-width)) 100%, var(--app-scrollbar-width) 100%; mask-size: calc(100% - var(--app-scrollbar-width)) 100%, var(--app-scrollbar-width) 100%; } /* Stage-channel art needs a mask and pseudo-element gradient, so keep the behavior composable without tying it to the global components layer. */ @utility sidebar-stage-backdrop { --stage-fade: var(--sidebar-stage-fade, var(--app-chrome-background)); mask-image: linear-gradient(to bottom, black 0%, black 55%, transparent 92%); -webkit-mask-image: linear-gradient(to bottom, black 0%, black 55%, transparent 92%); &::after { content: ""; position: absolute; inset: 0; background: linear-gradient( to bottom, transparent 0%, transparent 28%, color-mix(in srgb, var(--stage-fade) 10%, transparent) 40%, color-mix(in srgb, var(--stage-fade) 30%, transparent) 52%, color-mix(in srgb, var(--stage-fade) 58%, transparent) 64%, color-mix(in srgb, var(--stage-fade) 82%, transparent) 75%, color-mix(in srgb, var(--stage-fade) 96%, transparent) 85%, var(--stage-fade) 93% ); } } @keyframes live-activity-focus { 0% { transform: translateX(0); } 100% { transform: translateX(100%); } } @keyframes live-activity-focus-counter { 0% { transform: translateX(0); } 100% { transform: translateX(-100%); } } @utility live-activity-focus { --live-activity-focus-width: 4.5rem; right: auto; left: calc(-1 * var(--live-activity-focus-width)); width: calc(100% + var(--live-activity-focus-width) + var(--live-activity-focus-width)); -webkit-mask-image: linear-gradient( to right, transparent 0, rgb(0 0 0 / 12%) 0.675rem, rgb(0 0 0 / 55%) 1.575rem, black 2.25rem, rgb(0 0 0 / 55%) 2.925rem, rgb(0 0 0 / 12%) 3.825rem, transparent var(--live-activity-focus-width), transparent 100% ); -webkit-mask-repeat: no-repeat; mask-image: linear-gradient( to right, transparent 0, rgb(0 0 0 / 12%) 0.675rem, rgb(0 0 0 / 55%) 1.575rem, black 2.25rem, rgb(0 0 0 / 55%) 2.925rem, rgb(0 0 0 / 12%) 3.825rem, transparent var(--live-activity-focus-width), transparent 100% ); mask-repeat: no-repeat; animation: live-activity-focus 2.2s linear infinite; will-change: transform; @media (prefers-reduced-motion: reduce) { animation: none; opacity: 0; will-change: auto; } } @utility live-activity-focus-counter { width: 100%; animation: live-activity-focus-counter 2.2s linear infinite; will-change: transform; @media (prefers-reduced-motion: reduce) { animation: none; will-change: auto; } } @utility live-activity-focus-aligned { width: calc(100% - var(--live-activity-focus-width) - var(--live-activity-focus-width)); margin-left: var(--live-activity-focus-width); } @layer base { :root { /* Keep the original T3 Code artwork palettes as the defaults. Built-in themes override them with their own pigments in the components layer. */ --stage-art-top: oklch(0.782169 0.123386 240.226); --stage-art-mid: oklch(0.616111 0.195824 259.735); --stage-art-bottom: oklch(0.441553 0.232394 265.474); --stage-art-highlight: oklch(0.951597 0.037289 215.482); --stage-art-secondary: oklch(0.794668 0.12136 235.46); --stage-art-tertiary: oklch(0.678991 0.170261 275.365); --stage-art-line: oklch(0.959666 0.029238 218.179); --stage-art-celeste-highlight: oklch(0.968763 0.045822 196.42); --stage-art-celeste-secondary: oklch(0.827395 0.126071 211.26); --stage-art-violet-highlight: oklch(0.895381 0.053248 286.447); --stage-art-grid-line: oklch(0.966822 0.01757 239.99); --stage-night-base-top: oklch(0.283792 0.117327 297.201); --stage-night-base-mid: oklch(0.227147 0.086086 277.99); --stage-night-base-bottom: oklch(0.200528 0.055699 261.216); --stage-night-top: var(--stage-night-base-top); --stage-night-mid: var(--stage-night-base-mid); --stage-night-bottom: var(--stage-night-base-bottom); --stage-night-highlight: oklch(0.707246 0.157418 252.091); --stage-night-secondary: oklch(0.600473 0.182225 277.296); --stage-night-tertiary: oklch(0.62583 0.210886 305.994); --stage-night-line: oklch(0.938794 0.029114 273.103); --stage-night-glow-highlight: oklch(0.553749 0.176543 271.958); --stage-night-glow-secondary: oklch(0.345571 0.117466 273.568); --stage-night-sparkle: oklch(0.880867 0.057747 269.011); @variant dark { --stage-art-top: oklch(0.581473 0.149124 256.9); --stage-art-mid: oklch(0.456509 0.159377 261.945); --stage-art-bottom: oklch(0.291327 0.136578 267.649); } } * { @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, body { background-color: var(--app-chrome-background); } body { @apply text-foreground relative; } } @layer components { /* Each maintainer palette gives the same line art its own material: rose vellum, forest drafting paper, marine cyanotype, copper, and violet ink. These colors stay deliberately deep at the top edge so the white stage wordmark and controls retain contrast in both appearance modes. */ html[data-theme-id="t3-chat"] { --stage-art-top: oklch(0.760675 0.141361 348.019); --stage-art-mid: oklch(0.588093 0.188832 353.138); --stage-art-bottom: oklch(0.383959 0.135096 348.656); --stage-art-highlight: oklch(0.949689 0.034241 339.171); --stage-art-secondary: oklch(0.763402 0.163836 352.525); --stage-art-tertiary: oklch(0.70819 0.180285 311.949); --stage-art-line: oklch(0.952158 0.034194 336.179); @variant dark { --stage-art-top: oklch(0.540689 0.143665 347.587); --stage-art-mid: oklch(0.396586 0.126592 347.6); --stage-art-bottom: oklch(0.249959 0.079694 340.523); --stage-art-highlight: oklch(0.921297 0.051708 343.229); --stage-art-secondary: oklch(0.667398 0.165674 352.549); --stage-art-tertiary: oklch(0.609315 0.163722 306.315); --stage-art-line: oklch(0.945349 0.036045 341.433); } } html[data-theme-id="grove"] { --stage-art-top: oklch(0.751465 0.112731 157.313); --stage-art-mid: oklch(0.567105 0.11099 158.859); --stage-art-bottom: oklch(0.367918 0.067635 160.558); --stage-art-highlight: oklch(0.976387 0.034353 161.456); --stage-art-secondary: oklch(0.80968 0.117071 158.817); --stage-art-tertiary: oklch(0.784102 0.108047 88.516); --stage-art-line: oklch(0.981098 0.027812 158.718); --stage-night-top: oklch(0.45805 0.079616 160.092); --stage-night-mid: oklch(0.368483 0.065631 162.719); --stage-night-bottom: oklch(0.264797 0.044397 168.088); --stage-night-highlight: oklch(0.912563 0.055173 158.974); --stage-night-secondary: oklch(0.665652 0.109731 156.599); --stage-night-tertiary: oklch(0.698651 0.103024 89.828); --stage-night-line: oklch(0.945336 0.041923 157.222); @variant dark { --stage-art-top: oklch(0.58719 0.09869 157.426); --stage-art-mid: oklch(0.454979 0.079031 159.756); --stage-art-bottom: oklch(0.297856 0.050355 161.167); --stage-art-highlight: oklch(0.952407 0.053872 158.44); --stage-art-secondary: oklch(0.732591 0.120606 155.853); --stage-art-tertiary: oklch(0.716282 0.116547 80.563); --stage-art-line: oklch(0.961577 0.035285 157.03); --stage-night-top: oklch(0.398632 0.065534 158.601); --stage-night-mid: oklch(0.290561 0.049694 160.456); --stage-night-bottom: oklch(0.210147 0.03173 169.818); --stage-night-highlight: oklch(0.866303 0.057526 156.796); --stage-night-secondary: oklch(0.586553 0.093722 157.365); --stage-night-tertiary: oklch(0.6364 0.101769 82.985); --stage-night-line: oklch(0.913292 0.035718 156.976); } } html[data-theme-id="ocean"] { --stage-art-top: oklch(0.792993 0.088072 220.421); --stage-art-mid: oklch(0.590296 0.116841 243.184); --stage-art-bottom: oklch(0.409123 0.093718 247.98); --stage-art-highlight: oklch(0.971217 0.023008 213.615); --stage-art-secondary: oklch(0.788391 0.090856 215.684); --stage-art-tertiary: oklch(0.76441 0.099607 187.893); --stage-art-line: oklch(0.976025 0.019647 212.543); @variant dark { --stage-art-top: oklch(0.59663 0.089167 233.427); --stage-art-mid: oklch(0.461094 0.084904 243.478); --stage-art-bottom: oklch(0.294818 0.05947 250.526); --stage-art-highlight: oklch(0.952907 0.032224 221.27); --stage-art-secondary: oklch(0.732079 0.09296 224.414); --stage-art-tertiary: oklch(0.720885 0.095495 190.903); --stage-art-line: oklch(0.961039 0.027355 219.756); } } html[data-theme-id="ember"] { --stage-art-top: oklch(0.782439 0.118806 52.569); --stage-art-mid: oklch(0.62863 0.15922 39.401); --stage-art-bottom: oklch(0.404251 0.117664 30.424); --stage-art-highlight: oklch(0.962469 0.02774 70.95); --stage-art-secondary: oklch(0.815735 0.11904 53.659); --stage-art-tertiary: oklch(0.69361 0.159346 24.787); --stage-art-line: oklch(0.970313 0.02052 67.583); --stage-night-top: oklch(0.470236 0.102322 39.355); --stage-night-mid: oklch(0.345367 0.080697 33.217); --stage-night-bottom: oklch(0.227386 0.056077 27.437); --stage-night-highlight: oklch(0.903891 0.059281 56.181); --stage-night-secondary: oklch(0.641705 0.126508 44.376); --stage-night-tertiary: oklch(0.538694 0.129931 25.865); --stage-night-line: oklch(0.926348 0.046029 58.73); @variant dark { --stage-art-top: oklch(0.597533 0.120694 43.455); --stage-art-mid: oklch(0.437763 0.101287 34.86); --stage-art-bottom: oklch(0.264269 0.055858 26.548); --stage-art-highlight: oklch(0.929214 0.042638 55.801); --stage-art-secondary: oklch(0.705592 0.137369 43.176); --stage-art-tertiary: oklch(0.629583 0.158322 24.088); --stage-art-line: oklch(0.945058 0.033906 58.824); --stage-night-top: oklch(0.392352 0.081287 36.444); --stage-night-mid: oklch(0.271305 0.056352 31.135); --stage-night-bottom: oklch(0.182126 0.028154 27.774); --stage-night-highlight: oklch(0.851007 0.061294 53.805); --stage-night-secondary: oklch(0.560789 0.10645 42.953); --stage-night-tertiary: oklch(0.476228 0.106656 24.165); --stage-night-line: oklch(0.884931 0.046607 56.556); } } html[data-theme-id="iris"] { --stage-art-top: oklch(0.738305 0.113454 298.926); --stage-art-mid: oklch(0.551826 0.159189 294.531); --stage-art-bottom: oklch(0.37147 0.133317 289.999); --stage-art-highlight: oklch(0.949472 0.029204 303.081); --stage-art-secondary: oklch(0.745085 0.125892 298.647); --stage-art-tertiary: oklch(0.73066 0.167815 340.964); --stage-art-line: oklch(0.960278 0.024064 306.969); @variant dark { --stage-art-top: oklch(0.57297 0.145973 295.185); --stage-art-mid: oklch(0.419499 0.13752 292.131); --stage-art-bottom: oklch(0.274235 0.095798 286.608); --stage-art-highlight: oklch(0.916698 0.047206 300.224); --stage-art-secondary: oklch(0.670994 0.13095 296.689); --stage-art-tertiary: oklch(0.679357 0.165376 340.439); --stage-art-line: oklch(0.940582 0.032921 299.076); } } :is(html[data-theme-id="t3-chat"], html[data-theme-id="ocean"], html[data-theme-id="iris"]) { --stage-night-top: color-mix(in oklch, var(--stage-art-top) 38%, var(--stage-night-base-top)); --stage-night-mid: color-mix(in oklch, var(--stage-art-mid) 38%, var(--stage-night-base-mid)); --stage-night-bottom: color-mix( in oklch, var(--stage-art-bottom) 38%, var(--stage-night-base-bottom) ); --stage-night-highlight: var(--stage-art-highlight); --stage-night-secondary: color-mix( in oklch, var(--stage-art-secondary) 55%, var(--stage-night-mid) ); --stage-night-tertiary: color-mix( in oklch, var(--stage-art-tertiary) 60%, var(--stage-night-top) ); --stage-night-line: color-mix(in oklch, var(--stage-art-line) 82%, oklch(1 0 0)); } :is( html[data-theme-id="t3-chat"], html[data-theme-id="grove"], html[data-theme-id="ocean"], html[data-theme-id="ember"], html[data-theme-id="iris"] ) { --stage-art-celeste-highlight: var(--stage-art-highlight); --stage-art-celeste-secondary: var(--stage-art-secondary); --stage-art-violet-highlight: var(--stage-art-highlight); --stage-art-grid-line: var(--stage-art-line); --stage-night-glow-highlight: var(--stage-night-highlight); --stage-night-glow-secondary: var(--stage-night-secondary); --stage-night-sparkle: var(--stage-night-line); } @keyframes settings-search-target-pulse { 0%, 100% { box-shadow: 0 0 0 0 transparent; } 50% { box-shadow: 0 0 0 2px color-mix(in oklab, var(--color-primary) 70%, transparent); } } [data-settings-page-scroll] div.settings-search-target-pulse, [data-settings-page-scroll] section.settings-search-target-pulse > div:first-child { animation: settings-search-target-pulse 650ms ease-in-out 2; border-radius: 0.75rem; } /* The pulse is the destination indicator; without it (reduced motion), the focus outline takes over, so exactly one indicator shows at a time. */ [data-settings-page-scroll] .settings-search-target-pulse:focus { outline: none; } .chat-composer-shoulder-tab { border-color: var( --chat-composer-outline, color-mix(in srgb, var(--contrast-foreground) 8%, transparent) ); background: color-mix( in srgb, var(--chat-composer-glass-surface, var(--card)) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); box-shadow: 0 -8px 24px -18px rgb(0 0 0 / 45%); @variant dark { box-shadow: 0 -10px 28px -18px rgb(0 0 0 / 80%); } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--chat-composer-glass-surface, var(--card)); } } .chat-composer-banner-stack-cap { --chat-composer-attached-surface: var(--chat-composer-glass-surface, var(--card)); --chat-composer-attached-outline: var( --chat-composer-outline, color-mix(in srgb, var(--contrast-foreground) 8%, transparent) ); background: color-mix( in srgb, var(--chat-composer-attached-surface) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); @variant dark { --chat-composer-attached-surface: var( --chat-composer-glass-surface, color-mix(in srgb, var(--background) 96%, var(--color-white)) ); --chat-composer-attached-outline: var( --chat-composer-outline, color-mix(in srgb, var(--color-white) 5%, transparent) ); } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--chat-composer-attached-surface); } } /* Mirror the run-context strip above the composer. These surfaces deliberately own no card fill or border themselves: a masked pseudo-element draws the same inset glass, 16px outer corners, quiet outline, and open attachment seam as the strip below. */ .chat-composer-drawer-surface, .chat-composer-top-drawer { --chat-composer-attachment-overlap: calc(1rem + 1px); --chat-composer-attached-surface: var(--chat-composer-glass-surface, var(--card)); --chat-composer-attached-outline: var( --chat-composer-outline, color-mix(in srgb, var(--contrast-foreground) 8%, transparent) ); --chat-composer-attached-tint: transparent; position: relative; isolation: isolate; border: 0 !important; background: transparent !important; box-shadow: none; @variant dark { --chat-composer-attached-surface: var( --chat-composer-glass-surface, color-mix(in srgb, var(--background) 96%, var(--color-white)) ); --chat-composer-attached-outline: var( --chat-composer-outline, color-mix(in srgb, var(--color-white) 5%, transparent) ); &::before { background: linear-gradient(var(--chat-composer-attached-tint), var(--chat-composer-attached-tint)), linear-gradient( to top, transparent 0 var(--chat-composer-attachment-overlap), rgb(0 0 0 / 18%) var(--chat-composer-attachment-overlap), transparent calc(var(--chat-composer-attachment-overlap) + 10px) ), color-mix( in srgb, var(--chat-composer-attached-surface) var(--glass-opacity), transparent ); box-shadow: 0 14px 32px -18px rgb(0 0 0 / 75%); } } } .chat-composer-drawer-attached, .chat-composer-top-drawer { padding-bottom: var(--chat-composer-attachment-overlap); } [data-chat-composer-form="true"], .chat-composer-drawer-slot, .chat-composer-top-drawer { --chat-composer-drawer-inset: 1.375rem; } .chat-composer-drawer-slot, .chat-composer-top-drawer { --chat-composer-attachment-overlap: calc(1rem + 1px); width: calc(100% - var(--chat-composer-drawer-inset) - var(--chat-composer-drawer-inset)); max-width: calc(48rem - var(--chat-composer-drawer-inset) - var(--chat-composer-drawer-inset)); margin-inline: auto; margin-bottom: calc(-1 * var(--chat-composer-attachment-overlap)); } :is(.chat-composer-drawer-surface, .chat-composer-top-drawer)::before { pointer-events: none; position: absolute; z-index: -1; inset: 0; border: 1px solid var(--chat-composer-attached-outline); border-radius: 16px 16px 0 0; background: linear-gradient(var(--chat-composer-attached-tint), var(--chat-composer-attached-tint)), color-mix(in srgb, var(--chat-composer-attached-surface) var(--glass-opacity), transparent); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); -webkit-mask-image: linear-gradient( to top, transparent 0 var(--chat-composer-attachment-overlap), black var(--chat-composer-attachment-overlap) ); mask-image: linear-gradient( to top, transparent 0 var(--chat-composer-attachment-overlap), black var(--chat-composer-attachment-overlap) ); box-shadow: 0 12px 28px -18px rgb(0 0 0 / 40%); content: ""; @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: linear-gradient(var(--chat-composer-attached-tint), var(--chat-composer-attached-tint)), var(--chat-composer-attached-surface) !important; } } .chat-composer-drawer-slot + .chat-composer-drawer-slot::before, .chat-composer-drawer-slot + :has(.chat-composer-top-drawer) .chat-composer-top-drawer::before { border-top: 0; border-radius: 0; } .chat-composer-top-drawer { z-index: 0; } :is(.chat-composer-drawer-surface, .chat-composer-top-drawer)[data-variant="error"] { --chat-composer-attached-outline: color-mix(in srgb, var(--error) 32%, transparent); --chat-composer-attached-tint: color-mix(in srgb, var(--error) 8%, transparent); } :is(.chat-composer-drawer-surface, .chat-composer-top-drawer)[data-variant="info"] { --chat-composer-attached-outline: color-mix(in srgb, var(--info) 32%, transparent); --chat-composer-attached-tint: color-mix(in srgb, var(--info) 4%, transparent); } :is(.chat-composer-drawer-surface, .chat-composer-top-drawer)[data-variant="success"] { --chat-composer-attached-outline: color-mix(in srgb, var(--success) 32%, transparent); --chat-composer-attached-tint: color-mix(in srgb, var(--success) 4%, transparent); } :is(.chat-composer-drawer-surface, .chat-composer-top-drawer)[data-variant="warning"] { --chat-composer-attached-outline: color-mix(in srgb, var(--warning) 28%, transparent); --chat-composer-attached-tint: color-mix(in srgb, var(--warning) 8%, transparent); } .chat-composer-glass-shell { --chat-composer-attachment-overlap: calc(1rem + 1px); --chat-composer-glass-surface: var(--card); --chat-composer-outline: rgb(0 0 0 / 8%); isolation: isolate; @variant dark { --chat-composer-glass-surface: color-mix(in srgb, var(--background) 96%, var(--color-white)); --chat-composer-outline: color-mix(in srgb, var(--color-white) 5%, transparent); --chat-composer-highlight: rgb(255 255 255 / 3%); } } .chat-composer-glass-shell::before { pointer-events: none; position: absolute; z-index: 0; inset: 0; border-radius: 22px; background: color-mix( in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); content: ""; } .chat-composer-glass-shell-with-context { --chat-composer-context-extension: 2.25rem; } .chat-composer-glass-shell-with-context::before { border-radius: 0; /* * One continuous glass layer: a 22px composer joined to a 16px strip. The * strip is inset 1.375rem per side, so the step-in positions and their * curve controls stay in rem to keep tracking it at non-default interface * font sizes; the composer's 22px top radius and the strip's 16px bottom * radius are px by design. */ clip-path: shape( from 0 22px, curve to 22px 0 with 0 9.85px / 9.85px 0, line to calc(100% - 22px) 0, curve to 100% 22px with calc(100% - 9.85px) 0 / 100% 9.85px, line to 100% calc(100% - var(--chat-composer-context-extension) - 1.375rem), curve to calc(100% - 1.375rem) calc(100% - var(--chat-composer-context-extension)) with 100% calc(100% - var(--chat-composer-context-extension) - 0.6156rem) / calc(100% - 0.6156rem) calc(100% - var(--chat-composer-context-extension)), line to calc(100% - 1.375rem) calc(100% - 16px), curve to calc(100% - 1.375rem - 16px) 100% with calc(100% - 1.375rem) calc(100% - 7.16px) / calc(100% - 1.375rem - 7.16px) 100%, line to calc(1.375rem + 16px) 100%, curve to 1.375rem calc(100% - 16px) with calc(1.375rem + 7.16px) 100% / 1.375rem calc(100% - 7.16px), line to 1.375rem calc(100% - var(--chat-composer-context-extension)), curve to 0 calc(100% - var(--chat-composer-context-extension) - 1.375rem) with 0.6156rem calc(100% - var(--chat-composer-context-extension)) / 0 calc(100% - var(--chat-composer-context-extension) - 0.6156rem), line to 0 22px, close ); } @media (min-width: 40rem) { .chat-composer-glass-shell-with-context { /* The xs toolbar controls shrink by 4px at Tailwind's sm breakpoint. */ --chat-composer-context-extension: 2rem; } } .chat-composer-glass-host { box-shadow: 0 12px 28px -18px rgb(0 0 0 / 40%); @variant dark { box-shadow: none; &::after { box-shadow: inset 0 1px var(--chat-composer-highlight); } } } .chat-composer-glass-host::after { pointer-events: none; position: absolute; z-index: 1; inset: 0; border: 1px solid var(--chat-composer-outline); border-radius: inherit; content: ""; } /* A top attachment cannot share the shell's single clipped backdrop: it needs the composer surface and outline to paint in front of its overlap. Split the glass into exact surfaces while a drawer or tab is present; the default composer keeps the cheaper continuous layer. */ .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) )::before, .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) ) .chat-composer-glass-host::after { display: none; } .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) ) .chat-composer-glass-host { box-shadow: none; } .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) ) .chat-composer-glass-host [data-chat-composer-main-surface="true"] { background: color-mix( in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); box-shadow: 0 12px 28px -18px rgb(0 0 0 / 40%); &::after { pointer-events: none; position: absolute; z-index: 20; inset: 0; border: 1px solid var(--chat-composer-outline); border-radius: inherit; content: ""; } @variant dark { box-shadow: none; &::after { box-shadow: inset 0 1px var(--chat-composer-highlight); } } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { background: var(--chat-composer-glass-surface); } } .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(.chat-composer-top-drawer) ) .chat-composer-glass-host [data-chat-composer-mobile-collapsed="true"] { min-height: var(--chat-composer-attachment-overlap); } .chat-composer-glass-shell-with-context .chat-composer-glass-host::after, .chat-composer-glass-shell-with-context:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) ) [data-chat-composer-main-surface="true"]::after { /* Keep the attachment seam open; the strip continues the outer outline below. */ clip-path: polygon( 0 0, 100% 0, 100% 100%, calc(100% - 22px) 100%, calc(100% - 22px) calc(100% - 2px), 22px calc(100% - 2px), 22px 100%, 0 100% ); } .chat-composer-context-strip { position: relative; isolation: isolate; @variant dark { &::before { border-color: rgb(255 255 255 / 7%); background: linear-gradient( to bottom, transparent 0 1rem, rgb(0 0 0 / 18%) 1rem, transparent calc(1rem + 10px) ), rgb(255 255 255 / 2%); box-shadow: 0 14px 32px -18px rgb(0 0 0 / 75%); } } } .chat-composer-context-strip::before { position: absolute; z-index: -1; inset: 0; border: 1px solid var(--chat-composer-outline); border-radius: 0 0 16px 16px; /* Start the strip outline exactly where the composer's 22px curve reaches its tangent. */ -webkit-mask-image: linear-gradient(to bottom, transparent 0 1rem, black 1rem); mask-image: linear-gradient(to bottom, transparent 0 1rem, black 1rem); box-shadow: 0 12px 28px -18px rgb(0 0 0 / 40%); content: ""; } .chat-composer-glass-shell:is( .chat-composer-glass-shell-attached, :has(:is(.chat-composer-top-drawer, .chat-composer-shoulder-tab)) ) .chat-composer-context-strip { &::before { background: color-mix( in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); } @variant dark { &::before { background: linear-gradient( to bottom, transparent 0 1rem, rgb(0 0 0 / 18%) 1rem, transparent calc(1rem + 10px) ), linear-gradient(rgb(255 255 255 / 2%), rgb(255 255 255 / 2%)), color-mix(in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent); } } } @supports not (clip-path: shape(from 0 0, line to 1px 1px)) { .chat-composer-glass-shell-with-context::before { inset-block-end: var(--chat-composer-context-extension); border-radius: 22px; clip-path: none; } .chat-composer-context-strip::before { background: color-mix( in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent ); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); } .chat-composer-context-strip { @variant dark { &::before { background: linear-gradient( to bottom, transparent 0 1rem, rgb(0 0 0 / 18%) 1rem, transparent calc(1rem + 10px) ), linear-gradient(rgb(255 255 255 / 2%), rgb(255 255 255 / 2%)), color-mix(in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent); } } } } .settings-slider { --settings-slider-progress: 0%; --settings-slider-fill-offset: 0.5rem; --settings-slider-fill-position: calc( var(--settings-slider-progress) + var(--settings-slider-fill-offset) ); appearance: none; height: 1.5rem; background: transparent; cursor: pointer; } .settings-slider::-webkit-slider-runnable-track { height: 0.375rem; border-radius: 9999px; background: linear-gradient( to right, var(--primary) 0 var(--settings-slider-fill-position), color-mix(in srgb, var(--contrast-muted-foreground) 22%, transparent) var(--settings-slider-fill-position) 100% ); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--contrast-border) 55%, transparent); } .settings-slider::-moz-range-track { height: 0.375rem; border-radius: 9999px; background: color-mix(in srgb, var(--contrast-muted-foreground) 22%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--contrast-border) 55%, transparent); } .settings-slider::-moz-range-progress { height: 0.375rem; border-radius: 9999px; background: var(--primary); } .settings-slider::-webkit-slider-thumb { appearance: none; width: 1rem; height: 1rem; margin-top: -0.3125rem; border: 2px solid var(--primary); border-radius: 9999px; background: var(--background); box-shadow: 0 1px 2px color-mix(in srgb, var(--contrast-foreground) 12%, transparent); transition: transform 120ms ease, box-shadow 120ms ease; } .settings-slider::-moz-range-thumb { width: 1rem; height: 1rem; border: 2px solid var(--primary); border-radius: 9999px; background: var(--background); box-shadow: 0 1px 2px color-mix(in srgb, var(--contrast-foreground) 12%, transparent); transition: transform 120ms ease, box-shadow 120ms ease; } .settings-slider:hover::-webkit-slider-thumb { transform: scale(1.08); box-shadow: 0 1px 3px color-mix(in srgb, var(--contrast-foreground) 20%, transparent); } .settings-slider:hover::-moz-range-thumb { transform: scale(1.08); box-shadow: 0 1px 3px color-mix(in srgb, var(--contrast-foreground) 20%, transparent); } .settings-slider:active::-webkit-slider-thumb { transform: scale(0.94); } .settings-slider:active::-moz-range-thumb { transform: scale(0.94); } .settings-slider:focus-visible { outline: none; } .settings-slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px var(--background), 0 0 0 5px var(--ring); } .settings-slider:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 3px var(--background), 0 0 0 5px var(--ring); } @media (forced-colors: active) { .settings-slider { appearance: auto; accent-color: Highlight; } .settings-slider::-webkit-slider-runnable-track, .settings-slider::-webkit-slider-thumb { all: revert; } .settings-slider::-moz-range-track, .settings-slider::-moz-range-progress, .settings-slider::-moz-range-thumb { all: revert; } } @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { .chat-composer-glass-shell::before { background: var(--chat-composer-glass-surface); } } } /* 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: var(--surface-grain-size); } /* 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-zinc-25); --app-chrome-background: var(--background); --toolbar-background: var(--app-chrome-background); --toolbar-foreground: var(--foreground); --toolbar-border: var(--border); --toolbar-control: var(--popover); --toolbar-control-foreground: var(--foreground); --toolbar-control-hover: var(--accent); --surface-raised: color-mix(in srgb, var(--card) 20%, transparent); --foreground: var(--color-zinc-800); --card: var(--color-white); --card-foreground: var(--color-zinc-800); --popover: var(--color-white); --popover-foreground: var(--color-zinc-800); --primary: oklch(0.488 0.217 264); --primary-foreground: var(--color-white); --secondary: var(--color-zinc-50); --secondary-foreground: var(--color-zinc-800); --muted: var(--color-zinc-50); --muted-foreground: var(--color-zinc-500); --placeholder: var(--muted-foreground); --secondary-label: var(--muted-foreground); --icon-muted: var(--muted-foreground); --message-surface: var(--accent); --message-foreground: var(--foreground); --message-action: var(--primary); --message-action-foreground: var(--primary-foreground); --message-action-hover: color-mix(in srgb, var(--primary) 90%, var(--background)); --accent: var(--color-zinc-100); --accent-foreground: var(--color-zinc-900); --error: var(--color-red-500); --error-foreground: var(--color-red-700); --error-surface: color-mix(in srgb, var(--error) 8%, transparent); --destructive: var(--error); --border: var(--color-zinc-200); --input: var(--color-zinc-300); --ring: var(--primary); --destructive-foreground: var(--error-foreground); --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); --warning-surface: color-mix(in srgb, var(--warning) 8%, transparent); --update: var(--primary); --update-foreground: var(--primary); --update-surface: color-mix(in srgb, var(--update) 12%, transparent); /* Keep every sidebar primitive on the same light surface hierarchy, including portaled mobile sheets and settings navigation outside the app sidebar. */ --sidebar: var(--color-zinc-50); --sidebar-foreground: var(--foreground); --sidebar-muted-foreground: var(--muted-foreground); --sidebar-control-surface: var(--color-zinc-100); --sidebar-row-hover: var(--color-zinc-25); --sidebar-row-active: var(--color-white); --sidebar-row-selected: var(--color-white); --sidebar-border: var(--border); --sidebar-stage-fade: var(--sidebar); --code-background: color-mix(in srgb, var(--card) 90%, var(--background)); --code-foreground: var(--foreground); --terminal-background: var(--background); --terminal-foreground: var(--foreground); --terminal-cursor: rgb(38 56 78); --terminal-selection-background: rgb(37 63 99 / 20%); @variant dark { color-scheme: dark; /* Keep the workspace in the same neutral-black family as sidebar v2. Surfaces lift from this base instead of starting from a milky gray. */ --background: var(--color-neutral-950); --surface-raised: var(--secondary); --foreground: var(--color-neutral-100); --card: color-mix(in srgb, var(--background) 97%, var(--color-white)); --card-foreground: var(--color-neutral-100); --popover: color-mix(in srgb, var(--background) 94%, var(--color-white)); --popover-foreground: var(--color-neutral-100); --primary: oklch(0.571 0.21 264); --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); --error: color-mix(in srgb, var(--color-red-500) 90%, var(--color-white)); --error-foreground: var(--color-red-400); --error-surface: color-mix(in srgb, var(--error) 16%, transparent); --border: --alpha(var(--color-white) / 6%); --input: --alpha(var(--color-white) / 8%); --info-foreground: var(--color-blue-400); --success-foreground: var(--color-emerald-400); --warning-foreground: var(--color-amber-400); --warning-surface: color-mix(in srgb, var(--warning) 16%, transparent); --update-foreground: var(--color-blue-400); --update-surface: color-mix(in srgb, var(--update) 18%, transparent); --sidebar: var(--card); --sidebar-control-surface: var(--muted); --sidebar-row-hover: var(--accent); --sidebar-row-active: var(--accent); --sidebar-row-selected: var(--muted); --sidebar-stage-fade: var(--card); --terminal-cursor: rgb(180 203 255); --terminal-selection-background: rgb(180 203 255 / 25%); } } /* Keep both sidebar implementations (default and legacy) on the same quiet zinc hierarchy: zinc-50 navigation, zinc-25 hover, and white selected/raised surfaces. */ [data-app-sidebar] { --background: var(--color-zinc-25); --foreground: var(--color-zinc-800); --card: var(--color-white); --card-foreground: var(--color-zinc-800); --accent: var(--color-zinc-100); --accent-foreground: var(--color-zinc-900); --muted: var(--color-zinc-50); --muted-foreground: var(--color-zinc-500); --border: var(--color-zinc-200); --input: var(--color-zinc-300); --sidebar: var(--color-zinc-50); --sidebar-foreground: var(--color-zinc-800); --sidebar-muted-foreground: var(--color-zinc-500); --sidebar-control-surface: var(--color-zinc-100); --sidebar-row-hover: var(--color-zinc-25); --sidebar-row-active: var(--color-white); --sidebar-row-selected: var(--color-white); --sidebar-border: var(--color-zinc-200); --sidebar-stage-fade: var(--sidebar); @variant dark { --background: #000; --foreground: #f1f3f7; --card: #000; --card-foreground: var(--foreground); --accent: #191a1d; --accent-foreground: #f7f9ff; --muted: #0a0a0a; --muted-foreground: #a3a3a3; --border: rgb(255 255 255 / 8%); --input: rgb(255 255 255 / 18%); --sidebar: var(--card); --sidebar-foreground: var(--foreground); --sidebar-muted-foreground: var(--muted-foreground); --sidebar-control-surface: var(--muted); --sidebar-row-hover: color-mix(in srgb, var(--contrast-foreground) 8%, transparent); --sidebar-row-active: color-mix(in srgb, var(--contrast-foreground) 11%, transparent); --sidebar-row-selected: color-mix(in srgb, var(--contrast-foreground) 7%, transparent); --sidebar-border: var(--border); --sidebar-stage-fade: var(--card); } } /* Theme files are expressed in app color roles and mapped to the existing semantic surface tokens here. Keep this block after the sidebar-version compatibility overrides so both navigation implementations receive the same palette. Success, info, provider, and channel identity colors remain independent; error, warning, and update roles are themeable below. */ /* The non-empty marker adds enough specificity to outrank the generated root dark variant without reintroducing raw `.dark` selectors. */ html[data-theme-id]:not([data-theme-id=""]) { --background: var(--app-theme-canvas); --app-chrome-background: var(--app-theme-chrome); --toolbar-background: var(--app-theme-toolbar); --toolbar-foreground: var(--app-theme-toolbar-foreground); --toolbar-border: var(--app-theme-toolbar-border); --toolbar-control: var(--app-theme-toolbar-control); --toolbar-control-foreground: var(--app-theme-toolbar-control-foreground); --toolbar-control-hover: var(--app-theme-toolbar-control-hover); --surface-raised: var(--app-theme-surface-raised); --foreground: var(--app-theme-text); --card: var(--app-theme-surface); --card-foreground: var(--app-theme-text); --popover: var(--app-theme-surface-overlay); --popover-foreground: var(--app-theme-text); /* Solid controls (CTAs, switches, sliders, the send button) all share the theme's action color so every "act now" affordance reads consistently; the accent keeps driving surfaces, selection, and focus. Palettes without a distinct action color make these identical. */ --primary: var(--app-theme-message-action); --primary-foreground: var(--app-theme-message-action-foreground); --secondary: var(--app-theme-secondary); --secondary-foreground: var(--app-theme-secondary-foreground); --muted: var(--app-theme-muted); --muted-foreground: var(--app-theme-muted-foreground); --placeholder: var(--app-theme-placeholder); --secondary-label: var(--app-theme-secondary-label); --icon-muted: var(--app-theme-icon-muted); --accent: var(--app-theme-accent-surface); --accent-foreground: var(--app-theme-accent-surface-foreground); --message-surface: var(--app-theme-message-surface); --message-foreground: var(--app-theme-message-foreground); --message-action: var(--app-theme-message-action); --message-action-foreground: var(--app-theme-message-action-foreground); --message-action-hover: var(--app-theme-message-action-hover); --error: var(--app-theme-error); --error-foreground: var(--app-theme-error-foreground); --error-surface: var(--app-theme-error-surface); --destructive: var(--error); --destructive-foreground: var(--error-foreground); --warning: var(--app-theme-warning); --warning-foreground: var(--app-theme-warning-foreground); --warning-surface: var(--app-theme-warning-surface); --update: var(--app-theme-update); --update-foreground: var(--app-theme-update-foreground); --update-surface: var(--app-theme-update-surface); --border: var(--app-theme-border); --input: var(--app-theme-input); --ring: var(--app-theme-focus); --sidebar: var(--app-theme-sidebar); --sidebar-foreground: var(--app-theme-sidebar-foreground); --sidebar-muted-foreground: var(--app-theme-sidebar-muted-foreground); --sidebar-control-surface: var(--app-theme-sidebar-control-surface); --sidebar-row-hover: var(--app-theme-sidebar-row-hover); --sidebar-row-active: var(--app-theme-sidebar-row-active); --sidebar-row-selected: var(--app-theme-sidebar-row-selected); --sidebar-border: var(--app-theme-sidebar-border); --sidebar-stage-fade: var(--app-theme-sidebar); --code-background: var(--app-theme-code-background); --code-foreground: var(--app-theme-code-foreground); --terminal-background: var(--app-theme-terminal-background); --terminal-foreground: var(--app-theme-terminal-foreground); --terminal-cursor: var(--app-theme-terminal-cursor); --terminal-selection-background: var(--app-theme-terminal-selection-background); } /* T3 Chat's composer is a translucent lift over --chat-background. Route its measured flattened color through the raised-surface role instead of deriving another tint from the canvas, which made the dark composer too red. */ html[data-theme-id] .chat-composer-glass-shell { --chat-composer-glass-surface: var(--app-theme-surface-raised); --chat-composer-outline: var(--app-theme-toolbar-border); @variant dark { --chat-composer-outline: color-mix(in srgb, var(--app-theme-input) 30%, var(--background)); --chat-composer-highlight: color-mix(in srgb, var(--app-theme-input) 12%, transparent); } } html[data-theme-id] :is(.chat-composer-banner-stack-cap, .chat-composer-drawer-surface, .chat-composer-top-drawer) { --chat-composer-attached-surface: var(--app-theme-surface-raised); } html[data-theme-id] :is(.chat-composer-banner-stack-cap, .chat-composer-drawer-surface, .chat-composer-top-drawer):is( :not([data-variant]), [data-variant="default"] ) { --chat-composer-attached-outline: var(--chat-composer-outline, var(--app-theme-toolbar-border)); @variant dark { --chat-composer-attached-outline: var( --chat-composer-outline, color-mix(in srgb, var(--app-theme-input) 30%, var(--background)) ); } } html[data-theme-id="t3-chat"] .chat-composer-glass-shell { /* T3 Chat's visible composer edge is a dark plum, not the stock translucent white outline. Its highlight is derived from --chat-input-gradient. */ @variant dark { --chat-composer-outline: #241e28; --chat-composer-highlight: color-mix(in srgb, #432d48 12%, transparent); } } html[data-theme-id="t3-chat"] :is(.chat-composer-banner-stack-cap, .chat-composer-drawer-surface, .chat-composer-top-drawer):is( :not([data-variant]), [data-variant="default"] ) { @variant dark { --chat-composer-attached-outline: #241e28; } } /* Theme-token dependency probes are restored synchronously, before paint. Keep transitions from observing the temporary sentinel color in between. */ html[data-theme-token-probe], html[data-theme-token-probe] *, html[data-theme-token-probe] *::before, html[data-theme-token-probe] *::after { transition: none !important; } #theme-inspector-spotlight { position: fixed; z-index: 100; inset: 0; width: 100vw; height: 100dvh; overflow: visible; pointer-events: none; } [data-slot="popover-positioner"]:has([data-theme-editor-panel]), [data-slot="tooltip-positioner"]:has([data-theme-editor-panel]) { z-index: 120; } .theme-inspector-spotlight-dimmer { fill: rgb(2 3 8 / 54%); } .theme-inspector-spotlight-glow { fill: color-mix(in oklab, var(--ring) 9%, transparent); stroke: color-mix(in oklab, var(--ring) 72%, white); stroke-width: 2px; opacity: 0.92; vector-effect: non-scaling-stroke; } #theme-inspector-hover { position: fixed; z-index: 101; pointer-events: none; background: color-mix(in oklab, var(--ring) 7%, transparent); border: 1px solid color-mix(in oklab, var(--ring) 70%, white); box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 16%, transparent), 0 0 18px color-mix(in oklab, var(--ring) 38%, transparent); } #theme-inspector-hover [data-theme-inspector-hover-label] { position: absolute; left: 0; max-width: 12rem; overflow: hidden; padding: 0.2rem 0.45rem; border: 1px solid color-mix(in oklab, var(--ring) 48%, var(--contrast-border)); border-radius: 0.4rem; background: var(--popover); box-shadow: 0 4px 16px rgb(0 0 0 / 24%); color: var(--contrast-popover-foreground); font-size: 0.6875rem; font-weight: 600; line-height: 1rem; text-overflow: ellipsis; white-space: nowrap; } #theme-inspector-hover[data-placement="above"] [data-theme-inspector-hover-label] { bottom: calc(100% + 0.35rem); } #theme-inspector-hover[data-placement="below"] [data-theme-inspector-hover-label] { top: calc(100% + 0.35rem); } /* Workspace actions use a small, separate chrome hierarchy. Keeping these roles explicit prevents the thread toolbar from falling back to the default dark-mode whites while preserving the same theme file across clients. */ html[data-theme-id] [data-chat-header] { background-color: var(--toolbar-background); color: var(--contrast-toolbar-foreground); } html[data-theme-id] [data-chat-header] [data-slot="button"], html[data-theme-id] [data-chat-header] [data-slot="menu-trigger"], html[data-theme-id] [data-chat-header] [data-toolbar-control] { --control-icon-color: var(--contrast-toolbar-control-foreground); background-color: var(--toolbar-control); border-color: var(--contrast-toolbar-border); color: var(--contrast-toolbar-control-foreground); } /* The panel layout toggles stay ghost: they render both inside the header and in the titlebar strip, so filling them would make them change appearance as the panel opens. They only take the themed foreground; hover and pressed keep the base ghost accent. The tooltip trigger's data-slot wins over the toggle's when the trigger renders the toggle, so match both. */ html[data-theme-id] [data-panel-layout-controls] [data-slot="toggle"], html[data-theme-id] [data-panel-layout-controls] [data-slot="tooltip-trigger"], html[data-theme-id] [data-workspace-titlebar-controls] [data-slot="toggle"], html[data-theme-id] [data-workspace-titlebar-controls] [data-slot="tooltip-trigger"] { --control-icon-color: var(--contrast-toolbar-foreground); color: var(--contrast-toolbar-foreground); } html[data-theme-id] [data-chat-header] [data-slot="button"]:hover, html[data-theme-id] [data-chat-header] [data-slot="button"][data-pressed], html[data-theme-id] [data-chat-header] [data-slot="menu-trigger"]:hover, html[data-theme-id] [data-chat-header] [data-slot="menu-trigger"][data-pressed], html[data-theme-id] [data-chat-header] [data-toolbar-control]:hover, html[data-theme-id] [data-chat-header] [data-toolbar-control][data-pressed] { background-color: var(--toolbar-control-hover); } html[data-theme-id] [data-chat-header] [data-slot="separator"] { background-color: var(--contrast-toolbar-border); } /* Chat code blocks join the other code surfaces on the code tokens. The default look keeps its secondary/input tints; themed palettes tint those surfaces with the accent, which fights syntax highlighting. */ html[data-theme-id] .chat-markdown .chat-markdown-codeblock { background-color: var(--code-background); border-color: var(--contrast-border); color: var(--code-foreground); } html[data-theme-id] .chat-markdown pre { background-color: var(--code-background); color: var(--code-foreground); } html[data-theme-id] .chat-markdown .chat-markdown-codeblock pre { background-color: transparent; } html[data-theme-id] .chat-markdown .chat-markdown-codeblock-header, html[data-theme-id] .chat-markdown .chat-markdown-chrome-action { color: color-mix(in srgb, var(--code-foreground) 72%, transparent); } /* T3 Chat renders inline code and compact chat artifacts with its translucent secondary surface flattened over the light chat canvas. The raw muted and secondary tokens are substantially darker than those visible pixels. */ html[data-theme-id="t3-chat"] { @variant light { & .chat-markdown :not(pre) > code, & [data-changed-files-state], & [data-changed-files-header] { background-color: var(--message-surface); } & .chat-markdown :not(pre) > code, & [data-changed-files-state] { border-color: transparent; } & .chat-markdown :not(pre) > code { color: var(--contrast-message-foreground); } } } html[data-theme-id] .chat-markdown .chat-markdown-chrome-action:hover, html[data-theme-id] .chat-markdown .chat-markdown-chrome-action[aria-pressed="true"] { color: var(--code-foreground); } html[data-theme-id] [data-app-sidebar] { --background: var(--app-theme-canvas); --foreground: var(--app-theme-text); --card: var(--app-theme-surface); --card-foreground: var(--app-theme-text); --accent: var(--app-theme-accent-surface); --accent-foreground: var(--app-theme-accent-surface-foreground); --muted: var(--app-theme-muted); --muted-foreground: var(--app-theme-muted-foreground); --border: var(--app-theme-border); --input: var(--app-theme-input); --sidebar: var(--app-theme-sidebar); --sidebar-foreground: var(--app-theme-sidebar-foreground); --sidebar-muted-foreground: var(--app-theme-sidebar-muted-foreground); --sidebar-control-surface: var(--app-theme-sidebar-control-surface); --sidebar-row-hover: var(--app-theme-sidebar-row-hover); --sidebar-row-active: var(--app-theme-sidebar-row-active); --sidebar-row-selected: var(--app-theme-sidebar-row-selected); --sidebar-border: var(--app-theme-sidebar-border); --sidebar-stage-fade: var(--app-theme-sidebar); border-color: color-mix(in srgb, var(--contrast-sidebar-foreground) 10%, transparent); @variant dark { border-color: color-mix(in srgb, var(--contrast-sidebar-foreground) 8%, transparent); } } /* T3 Chat's panel divider is deliberately pink, and its resize affordance keeps that color while hovered. Do not neutralize this branded edge. */ html[data-theme-id="t3-chat"] [data-app-sidebar] { @variant dark { border-color: var(--contrast-sidebar-border); } } /* Contrast stays in ordinary custom properties so both Tailwind utilities and global/imperative chrome styles resolve the same adjusted role. Redeclare on the sidebar because it owns a local semantic palette. */ :root, [data-app-sidebar] { --contrast-toolbar-foreground: color-mix( in oklab, color-mix( in oklab, var(--toolbar-foreground) var(--appearance-contrast-base), var(--toolbar-background) ), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-toolbar-border: color-mix( in srgb, color-mix(in srgb, var(--toolbar-border) var(--appearance-contrast-base), transparent), var(--toolbar-foreground) var(--appearance-contrast-border-boost) ); --contrast-toolbar-control-foreground: color-mix( in oklab, color-mix( in oklab, var(--toolbar-control-foreground) var(--appearance-contrast-base), var(--toolbar-control) ), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-input: color-mix( in srgb, color-mix(in srgb, var(--input) var(--appearance-contrast-base), transparent), var(--foreground) var(--appearance-contrast-border-boost) ); --contrast-border: color-mix( in srgb, color-mix(in srgb, var(--border) var(--appearance-contrast-base), transparent), var(--foreground) var(--appearance-contrast-border-boost) ); --contrast-foreground: color-mix( in oklab, color-mix(in oklab, var(--foreground) var(--appearance-contrast-base), var(--background)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-muted-foreground: color-mix( in oklab, color-mix(in oklab, var(--muted-foreground) var(--appearance-contrast-base), var(--background)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-placeholder: color-mix( in oklab, color-mix(in oklab, var(--placeholder) var(--appearance-contrast-base), var(--background)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-secondary-label: color-mix( in oklab, color-mix(in oklab, var(--secondary-label) var(--appearance-contrast-base), var(--background)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-icon-muted: color-mix( in oklab, color-mix(in oklab, var(--icon-muted) var(--appearance-contrast-base), var(--background)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-card-foreground: color-mix( in oklab, color-mix(in oklab, var(--card-foreground) var(--appearance-contrast-base), var(--card)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-popover-foreground: color-mix( in oklab, color-mix(in oklab, var(--popover-foreground) var(--appearance-contrast-base), var(--popover)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-accent-foreground: color-mix( in oklab, color-mix(in oklab, var(--accent-foreground) var(--appearance-contrast-base), var(--accent)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-secondary-foreground: color-mix( in oklab, color-mix( in oklab, var(--secondary-foreground) var(--appearance-contrast-base), var(--secondary) ), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-message-foreground: color-mix( in oklab, color-mix( in oklab, var(--message-foreground) var(--appearance-contrast-base), var(--message-surface) ), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-sidebar-foreground: color-mix( in oklab, color-mix(in oklab, var(--sidebar-foreground) var(--appearance-contrast-base), var(--sidebar)), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-sidebar-muted-foreground: color-mix( in oklab, color-mix( in oklab, var(--sidebar-muted-foreground) var(--appearance-contrast-base), var(--sidebar) ), var(--appearance-contrast-target) var(--appearance-contrast-boost) ); --contrast-sidebar-border: color-mix( in srgb, color-mix(in srgb, var(--sidebar-border) var(--appearance-contrast-base), transparent), var(--sidebar-foreground) var(--appearance-contrast-border-boost) ); } body { /* Reference the theme token (not a literal stack) so the Settings -> Appearance runtime override of --font-sans reaches all interface text. */ font-family: var(--font-sans); 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); padding-right: var(--desktop-window-right-resize-inset); } .electron-windows { --desktop-window-right-resize-inset: 6px; } /* 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"); --surface-grain-size: 256px 256px; } /* The live T3 Chat texture is a 128px grayscale tile with a constant 7/255 alpha. Keep our procedural texture cheap while matching that scale and strength for the branded preset. */ html[data-theme-id="t3-chat"] { --surface-grain: url("data:image/svg+xml,%3Csvg viewBox='0 0 128 128' 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.02745'/%3E%3C/svg%3E"); --surface-grain-size: 128px 128px; } body { background-image: var(--surface-grain); background-repeat: repeat; background-size: var(--surface-grain-size); } pre, code { font-family: var(--font-mono); } /* Code blocks in chat carry the size preference. Scoped to chat markdown rather than every pre: a global rule would beat text-size utilities and inherited sizes on unrelated pre surfaces (terminal previews, approvals). Inline code stays relative to its sentence so it never towers over prose; diffs and file previews take the size through --diffs-font-size. */ .chat-markdown .chat-markdown-shiki .shiki, .chat-markdown pre code { font-size: var(--font-size-code, inherit); } /* @pierre/diffs surfaces (diffs, file previews, annotatable code, search lines) render inside shadow roots but consult these hooks with their own literal stacks as fallback. Custom properties inherit across the shadow boundary, so defining them once here routes every code surface through the appearance font tokens. */ :root { --diffs-font-family: var(--font-mono); --diffs-header-font-family: var(--font-sans); } /* 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: var(--app-scrollbar-thumb); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: var(--app-scrollbar-thumb-hover); } /* Chat markdown rendering */ .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(--contrast-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(--contrast-muted-foreground); } .chat-markdown ul { /* Reset for nested uls under a widened ol — --list-gutter is an inherited custom property, so without this a task-list under a 3+ digit ordered list would inherit the outer gutter instead of its own default. */ --list-gutter: 1.25rem; padding-left: 1.25rem; list-style-type: disc; } /* --list-gutter defaults to the same 1.25rem as .chat-markdown ul, but ChatMarkdown's `ol` renderer widens it (via inline style) for lists whose widest marker is 3+ characters, so item 100+ isn't clipped by list-style-position: outside painting the marker past the padding box. Reset it here too so a nested ol without its own widened marker doesn't inherit the outer one. */ .chat-markdown ol { --list-gutter: 1.25rem; padding-left: var(--list-gutter, 1.25rem); list-style-type: decimal; } .chat-markdown ol > li::marker { font-variant-numeric: tabular-nums; } .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 calc(-1 * var(--list-gutter, 1.25rem)); vertical-align: middle; } /* Markdown assumes inline images — GitHub comments lay button images out in a row — and the Tailwind preflight's block-level img would stack them one per line. */ .chat-markdown img { display: inline-block; } .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 blockquote { border-left: 2px solid var(--contrast-border); padding-left: 0.8rem; color: var(--contrast-muted-foreground); } .chat-markdown section[data-footnotes] { margin-top: 1.25rem; border-top: 1px solid var(--contrast-border); padding-top: 0.75rem; color: var(--contrast-muted-foreground); font-size: 0.75rem; } .chat-markdown section[data-footnotes] ol { margin: 0; } .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(--contrast-border); border-radius: 0.375rem; background: var(--muted); padding: 0.1rem 0.35rem; color: var(--contrast-foreground); font-size: 0.75rem; } .chat-markdown .chat-markdown-file-link, .chat-markdown .chat-markdown-file-link:hover { color: var(--contrast-foreground); text-decoration: none; } .chat-markdown .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(--contrast-border); border-radius: 0.75rem; background: var(--muted); padding: 0.8rem 0.9rem; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--contrast-border) 78%, transparent) transparent; } .chat-markdown pre code { border: none; background: transparent; padding: 0; } .chat-markdown pre::-webkit-scrollbar { height: 7px; } .chat-markdown pre::-webkit-scrollbar-thumb { border-radius: 999px; background: color-mix(in srgb, var(--contrast-border) 78%, transparent); } .chat-markdown .chat-markdown-codeblock-header, .chat-markdown .chat-markdown-chrome-action { color: color-mix(in srgb, var(--contrast-foreground) 72%, transparent); } .chat-markdown .chat-markdown-chrome-action:hover { color: var(--contrast-foreground); } .chat-markdown .chat-markdown-chrome-action[aria-pressed="true"] { color: var(--contrast-foreground); background: color-mix(in srgb, var(--contrast-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(--contrast-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(--contrast-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; } /* Prompt-stash save acknowledgement: the new count fades up from just below its resting position, once, then stops. One-shot and event-driven (React remounts the element by key on each stash) — no continuous animation. */ @keyframes prompt-stash-count-enter { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } @keyframes provider-update-pill-countdown { from { transform: scaleX(1); } to { transform: scaleX(0); } } .diff-render-surface diffs-container { border: 0; border-radius: 0; overflow: clip; background: var(--code-background); color: var(--code-foreground); } /* Pierre's file renderer owns its own surface tokens. Keep the root of a file preview on the same themeable code surface as the diff panel. */ .diff-render-surface diffs-container, .file-preview-virtualizer diffs-container { --diffs-bg: var(--code-background) !important; --diffs-light-bg: var(--code-background) !important; --diffs-dark-bg: var(--code-background) !important; background-color: var(--code-background) !important; color: var(--code-foreground) !important; } @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; } .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; } @keyframes preview-loading-progress { from { transform: scaleX(0.04); } to { transform: scaleX(0.9); } } .preview-loading-progress { opacity: 0; transform: scaleX(1); transition: transform 150ms ease-out, opacity 150ms ease-out 220ms; } .preview-loading-progress[data-loading="true"] { opacity: 1; animation: preview-loading-progress 5.3s cubic-bezier(0.1, 0.5, 0.2, 1) forwards; } @media (prefers-reduced-motion: reduce) { .preview-loading-progress, .preview-loading-progress[data-loading="true"] { transition: none; animation: none; } .preview-loading-progress[data-loading="true"] { transform: scaleX(0.9); } }