@import "react-grid-layout/css/styles.css" layer(base); @import "react-resizable/css/styles.css" layer(base); @import "tailwindcss"; @import "tw-animate-css"; @import "tailwind-scrollbar-hide/v4"; @plugin "@tailwindcss/forms"; @plugin "@tailwindcss/typography"; @plugin "tailwind-scrollbar"; /* Streamdown ships prebuilt Tailwind classes - scan it for used utilities */ @source "../node_modules/streamdown/dist"; /* Raw palettes and static tokens - theme-independent, never override per theme */ @theme { --font-sans: "Geist Variable", "Helvetica Neue", Helvetica, Arial, sans-serif; --font-mono: "Geist Mono Variable", monaco, Consolas, "Lucida Console", monospace; --text-xxs: 0.65rem; --text-xxs--line-height: 0.75rem; --text-xxs--letter-spacing: -0.01em; --text-xxs--font-weight: 500; --text-2sm: 0.8125rem; --text-2sm--line-height: 0.875rem; --text-2sm--letter-spacing: -0.01em; --text-2sm--font-weight: 500; --color-charcoal-100: #e8e9ec; --color-charcoal-200: #d7d9dd; --color-charcoal-300: #b5b8c0; --color-charcoal-400: #878c99; --color-charcoal-500: #5f6570; --color-charcoal-550: #4d525b; --color-charcoal-600: #3b3e45; --color-charcoal-650: #2c3034; --color-charcoal-700: #272a2e; --color-charcoal-750: #212327; --color-charcoal-775: #1c1e21; --color-charcoal-800: #1a1b1f; --color-charcoal-850: #15171a; --color-charcoal-900: #121317; --color-charcoal-950: #0d0e12; --color-charcoal-1000: #0b0c0f; --color-apple-100: #e4ffc9; --color-apple-200: #cfffa0; --color-apple-300: #bfff81; --color-apple-400: #afff62; --color-apple-500: #a8ff53; --color-apple-600: #82d134; --color-apple-700: #6fb12f; --color-apple-750: #5e932a; --color-apple-800: #45711a; --color-apple-850: #2e4e10; --color-apple-900: #20370a; --color-apple-950: #152506; --color-mint-50: #f0fdf4; --color-mint-100: #ddfbe6; --color-mint-200: #bdf5d0; --color-mint-300: #87eba9; --color-mint-400: #4fd97e; --color-mint-500: #28bf5c; --color-mint-600: #1b9e48; --color-mint-700: #197c3c; --color-mint-800: #196233; --color-mint-900: #16512c; --color-mint-950: #062d15; --color-sun-50: #fdfee8; --color-sun-100: #fdffc2; --color-sun-200: #ffff89; --color-sun-300: #fff852; --color-sun-400: #fdea12; --color-sun-500: #eccf06; --color-sun-600: #cca302; --color-sun-700: #a37505; --color-sun-800: #865b0d; --color-sun-900: #724b11; --color-sun-950: #432705; --color-lavender-50: #f4f2ff; --color-lavender-100: #eae8ff; --color-lavender-200: #d7d4ff; --color-lavender-300: #bab2ff; --color-lavender-400: #826dff; --color-lavender-500: #7655fd; --color-lavender-600: #6532f5; --color-lavender-700: #5620e1; --color-lavender-800: #481abd; --color-lavender-900: #3d189a; --color-lavender-950: #230c69; --text-shadow-custom: 1px 1px 1px rgba(0, 0, 0, 0.5); --animate-accordion-down: accordion-down 0.2s ease-out; --animate-accordion-up: accordion-up 0.2s ease-out; --animate-tile-scroll: tile-move 0.5s infinite linear; --animate-tile-scroll-offset: tile-move-offset 0.5s infinite linear; @keyframes accordion-down { from { height: 0; } to { height: var(--radix-accordion-content-height); } } @keyframes accordion-up { from { height: var(--radix-accordion-content-height); } to { height: 0; } } @keyframes tile-move { 0% { background-position: 0px; } 100% { background-position: 8px; } } @keyframes tile-move-offset { 0% { background-position: -1px; } 100% { background-position: 7px; } } } /* Semantic tokens - the themable layer. Utilities compile to var(--color-*), so a theme overrides these vars in a scoped selector, e.g. [data-theme="light"] { --color-text-bright: #1a1b1f; } Defaults below are the original dark theme. */ @theme { /* Text colors */ --color-primary: var(--color-apple-500); --color-secondary: var(--color-charcoal-650); --color-tertiary: var(--color-charcoal-700); --color-text-link: var(--color-lavender-400); --color-text-faint: var(--color-charcoal-500); --color-text-dimmed: var(--color-charcoal-400); --color-text-bright: var(--color-charcoal-200); /* Surfaces, from deepest to most raised */ --color-background-deep: var(--color-charcoal-900); --color-background-dimmed: var(--color-charcoal-850); --color-background-bright: var(--color-charcoal-800); --color-background-hover: var(--color-charcoal-750); --color-surface-hover-subtle: var(--color-charcoal-750); --color-background-raised: var(--color-charcoal-700); --color-surface-selected: var(--color-charcoal-650); --color-surface-selected-hover: var(--color-charcoal-600); --color-surface-control: var(--color-charcoal-600); --color-surface-control-hover: var(--color-charcoal-550); --color-surface-control-active: var(--color-charcoal-500); --color-input-bg: var(--color-charcoal-750); /* Borders, from subtlest to most visible */ --color-grid-dimmed: var(--color-charcoal-750); --color-grid-bright: var(--color-charcoal-700); /* Blend of border-bright over the selected card, so it tracks whatever ramp border-bright is on - the dark themes need no contrast entry of their own */ --color-border-selected: color-mix(in srgb, var(--color-border-bright) 50%, var(--color-surface-selected)); --color-border-bright: var(--color-charcoal-600); --color-border-brighter: var(--color-charcoal-550); --color-border-brightest: var(--color-charcoal-500); --color-success: var(--color-mint-500); --color-pending: var(--color-blue-500); --color-warning: var(--color-amber-500); --color-error: var(--color-rose-600); /* Environment colors */ --color-dev: var(--color-pink-500); --color-staging: var(--color-orange-400); --color-prod: var(--color-mint-500); --color-preview: var(--color-yellow-400); /* Icon colors */ --color-tasks: var(--color-blue-500); --color-runs: var(--color-indigo-500); --color-batches: var(--color-pink-500); --color-schedules: var(--color-yellow-500); --color-queues: var(--color-purple-500); --color-query: var(--color-blue-500); --color-metrics: var(--color-green-500); --color-customDashboards: var(--color-charcoal-400); --color-deployments: var(--color-blue-500); --color-concurrency: var(--color-amber-500); --color-limits: var(--color-purple-500); --color-regions: var(--color-green-500); --color-logs: var(--color-pink-500); --color-tests: var(--color-pink-500); --color-apiKeys: var(--color-amber-500); --color-environmentVariables: var(--color-pink-500); --color-alerts: var(--color-red-500); --color-projectSettings: var(--color-blue-500); --color-orgSettings: var(--color-blue-500); --color-docs: var(--color-blue-500); --color-bulkActions: var(--color-emerald-500); --color-aiPrompts: var(--color-blue-500); --color-aiMetrics: var(--color-green-500); --color-errors: var(--color-amber-500); --color-agents: var(--color-purple-500); --color-webhooks: var(--color-teal-500); --color-sessions: var(--color-pink-500); --color-playgrounds: var(--color-fuchsia-500); --color-models: var(--color-violet-500); --color-previewBranches: var(--color-yellow-500); } /* Callout variant accents (see components/primitives/Callout.tsx) */ @theme { --color-callout-warning-text: var(--color-yellow-200); --color-callout-error-text: var(--color-rose-200); --color-callout-success-text: var(--color-green-200); --color-callout-docs: var(--color-blue-400); --color-callout-docs-text: var(--color-blue-200); --color-callout-pending: var(--color-blue-400); --color-callout-pending-bg: var(--color-blue-800); --color-callout-pending-text: var(--color-blue-300); --color-callout-pricing: var(--color-indigo-400); --color-callout-pricing-bg: var(--color-indigo-800); --color-callout-pricing-text: var(--color-indigo-300); } /* Theme overrides. A theme re-maps ONLY the semantic tokens above, never the raw palette values. That invariant is what lets a future [data-contrast] overlay re-map semantic tokens on top of whichever theme is active. */ /* System preference unified accents (dark+light); Classic keeps the original set. One shared value per accent token, >=3:1 against both dark cards and white. Accents whose Classic default already clears both modes (blue-500, indigo-500, pink-500, purple-500, red-500, violet-500, fuchsia-500, rose-600) are not repeated here. Text-sized tokens (text-link, callout text) stay per-mode: no color reaches 4.5:1 on both #1a1b1f and #ffffff. Dark derives everything else (monochrome surfaces etc.) from Classic. */ :is([data-theme="dark"], [data-theme="light"]) { /* Status */ --color-success: var(--color-mint-600); --color-warning: var(--color-amber-600); /* Env set: pink dev and green prod as in Classic, preview moves to blue (yellow's unified mid-tone reads muddy brown). Staging stays warm orange and is the one per-mode env color - see the light block. */ --color-prod: var(--color-mint-600); --color-preview: var(--color-blue-500); /* Icons */ --color-schedules: var(--color-yellow-700); /* Matches the preview env color */ --color-previewBranches: var(--color-blue-500); --color-metrics: var(--color-green-600); --color-regions: var(--color-green-600); --color-aiMetrics: var(--color-green-600); --color-bulkActions: var(--color-emerald-600); --color-concurrency: var(--color-amber-600); --color-errors: var(--color-amber-600); --color-apiKeys: var(--color-amber-600); /* Queue charts read blue here; Classic keeps the queues purple */ --color-queues-chart: var(--color-blue-500); --color-queues-chart-ref: var(--color-charcoal-500); /* Callout accents (callout text/bg tints stay per-mode) */ --color-callout-docs: var(--color-blue-500); --color-callout-pending: var(--color-blue-500); --color-callout-pricing: var(--color-indigo-500); /* Amber run statuses: three distinct steps, Classic's dark-to-light order kept (waiting-for-deploy < pending-version < paused) */ --color-run-waiting-for-deploy: var(--color-amber-700); --color-run-pending-version: #c76508; --color-run-paused: var(--color-amber-600); /* Nudged under 3:1's ceiling on white; stays lighter than system-failure */ --color-run-timed-out: #ed5f74; } /* System themes drop decorative icon accents to monochrome; Classic keeps the colored icons. side-menu-active-icon is set in SideMenuItem for the active nav item; system-mono-icon marks section-header icons (e.g. the limits page). */ :is([data-theme="dark"], [data-theme="light"]) :is(.side-menu-active-icon, .system-mono-icon) { color: var(--color-text-bright); } /* System themes: status/env labels follow the surrounding text color, only the icon keeps its tint. Classic colors both. Set in EnvironmentLabel and the status combo components. */ :is([data-theme="dark"], [data-theme="light"]) .system-mono-label { color: inherit; } /* Tinted status chips respond to the contrast control: a ring in the chip's own text color fades in as contrast rises, so the soft tint keeps its footprint but the chip gains definition. Transparent at contrast 0; Classic never sets the variable. Marker set by the chip components. */ :is([data-theme="dark"], [data-theme="light"]) .contrast-chip { box-shadow: inset 0 0 0 1px color-mix(in srgb, currentcolor calc(var(--theme-contrast, 0) * 70%), transparent); } /* Code syntax palette - the trigger-dark highlight theme, shared by the shiki theme (streamdown) and the prism theme (CodeBlock). Consumed from JS via var(), so declared static to always be emitted. */ @theme static { --color-code-background: #212327; --color-code-foreground: #878c99; --color-code-line-number: #484c54; --color-code-plain: #d4d4d4; --color-code-muted: #5f6570; --color-code-comment: #6f736d; --color-code-keyword: #e888f8; --color-code-storage: #8271ed; --color-code-type: #f770c6; --color-code-function: #d9f07c; --color-code-variable: #cccbff; --color-code-constant: #9c9af2; --color-code-language: #9b99ff; --color-code-object-key: #8b89ff; --color-code-string: #afec73; --color-code-template-punctuation: #7a78ea; --color-code-number: #b5cea8; --color-code-builtin: #e5c07b; --color-code-attribute: #c39eff; --color-code-escape: #d7ba7d; --color-code-regexp: #d16969; --color-code-regexp-constant: #646695; --color-code-invalid: #f44747; --color-code-deleted: #f85149; --color-code-jsx-text: #d7d9dd; } /* CodeMirror editor palette (see components/code/codeMirrorTheme.ts). Consumed from JS via var(), so declared static to always be emitted. */ @theme static { --color-editor-background: var(--color-background-deep); --color-editor-foreground: #abb2bf; --color-editor-keyword: #c678dd; --color-editor-name: #9b99ff; --color-editor-function: #61afef; --color-editor-constant: #d19a66; --color-editor-type: #e5c07b; --color-editor-operator: #56b6c2; --color-editor-comment: #7d8799; --color-editor-heading: #e06c75; --color-editor-string: #afec73; --color-editor-invalid: #ffffff; --color-editor-panel-background: #21252b; --color-editor-highlight-background: rgba(71, 85, 105, 0.2); --color-editor-tooltip-background: #353a42; --color-editor-selection: rgb(71 85 105); --color-editor-cursor: #528bff; --color-editor-search-match: #72a1ff59; --color-editor-search-match-outline: #457dff; --color-editor-search-match-selected: #6199ff2f; --color-editor-selection-match: #aafe661a; --color-editor-matching-bracket: rgba(18, 19, 23, 0.9); --color-editor-matching-bracket-outline: rgba(81, 90, 107, 0.5); --color-editor-fold-placeholder: #dddddd; --color-editor-scrollbar-track-active: #131b2b; --color-editor-scrollbar-thumb: #293649; --color-editor-scrollbar-thumb-active: #3c4b62; } /* Queue chart series colors - queues purple in Classic, overridden to blue in the System themes; the grey reference series lightens per mode there. Consumed from JS via var(), so declared static. */ @theme static { --color-queues-chart: var(--color-queues); --color-queues-chart-ref: #4d525b; } /* Run-status chart colors. In-between shades are intentional - statuses within a family (blues, roses, charcoals) are evenly spaced so chart series stay distinguishable. Referenced from JS via var(--color-run-*), so declared static to always be emitted. */ @theme static { --color-run-pending: var(--color-charcoal-500); --color-run-delayed: #6b7580; --color-run-pending-version: var(--color-warning); --color-run-waiting-for-deploy: #d97706; --color-run-executing: var(--color-pending); --color-run-retrying-after-failure: #2f6fec; --color-run-dequeued: #4d8ef5; --color-run-waiting-to-resume: #555d67; --color-run-paused: #fbbf24; --color-run-canceled: #78828c; --color-run-expired: #848d96; --color-run-interrupted: #d52c4d; --color-run-completed-successfully: var(--color-success); --color-run-completed-with-errors: #de405c; --color-run-system-failure: #e7536c; --color-run-crashed: #cc193d; --color-run-timed-out: #f0667b; } /* shadcn/ui tokens used by streamdown's internals. Inline so the vars resolve where the utility is used - .streamdown-container redefines them locally. */ @theme inline { --color-background: var(--background, #121317); --color-foreground: var(--foreground, #d7d9dd); --color-muted: var(--muted, #1c1e21); --color-muted-foreground: var(--muted-foreground, #878c99); --color-border: var(--border, #2c3034); --color-sidebar: var(--sidebar, #15171a); --color-primary-foreground: var(--primary-foreground, #121317); } @custom-variant lg-height (@media (max-height: 750px)); @custom-variant md-height (@media (max-height: 600px)); /* dark: follows the app theme (data-theme on ), not the OS preference. Classic and Dark are both dark-mode themes, so the variant matches both. */ @custom-variant dark (&:where([data-theme="dark"], [data-theme="classic"], [data-theme="dark"] *, [data-theme="classic"] *)); /* system: matches the System preference themes (Dark and Light) but never Classic - for restyles that must leave Classic untouched. */ @custom-variant system (&:where([data-theme="dark"], [data-theme="light"], [data-theme="dark"] *, [data-theme="light"] *)); /* light: the Light theme only - for values that are fine on every dark theme but illegible on white. Classic is never matched. */ @custom-variant light (&:where([data-theme="light"], [data-theme="light"] *)); @utility focus-custom { &:focus-visible { outline: 1px solid var(--color-text-link); /* Inset the ring inside the box; at offset 0 the outline sits outside the border edge and gets clipped by ancestors with overflow hidden/auto (scroll areas, the side menu grid). */ outline-offset: -1px; border-radius: 5px; } } @utility scrollbar-gutter-stable { scrollbar-gutter: stable; } /* Fade the thumb in only while the pointer is in the scroll area. Uses ::-webkit-scrollbar (no scrollbar-width) so Chrome keeps a classic always-present bar to reveal, not the auto-hiding overlay; Firefox falls back to standard props. Thumb color is a registered @property so it can transition. */ @property --sm-sb-thumb { syntax: ""; initial-value: transparent; inherits: true; } @utility scrollbar-thumb-on-hover { transition: --sm-sb-thumb 200ms ease; &::-webkit-scrollbar { width: 8px; height: 8px; } &::-webkit-scrollbar-track { background: transparent; } &::-webkit-scrollbar-thumb { background-color: var(--sm-sb-thumb); /* transparent border + padding-box clip = thinner thumb, inset from the channel edges */ border: 2px solid transparent; border-radius: 9999px; background-clip: padding-box; } @supports (-moz-appearance: none) { scrollbar-width: thin; scrollbar-color: var(--sm-sb-thumb) transparent; } &:hover { --sm-sb-thumb: var(--color-surface-control); } } /* Shared stop list for the animated glow utilities below. The gradient itself is assembled per-element so the animated --gradient-angle resolves there. */ :root { --glow-gradient-stops: rgb(99 102 241), rgb(245 158 11), rgb(236 72 153), rgb(245 158 11), rgb(99 102 241); } @utility animated-gradient-glow { position: relative; overflow: visible; &::before { content: ""; position: absolute; inset: -8px; z-index: -1; background: conic-gradient(from var(--gradient-angle), var(--glow-gradient-stops)); border-radius: inherit; animation: gradient-rotation 3s linear infinite; pointer-events: none; filter: blur(0.5rem); opacity: 0.1; } } @utility animated-gradient-glow-small { position: relative; overflow: visible; &::before { content: ""; position: absolute; inset: -1px; z-index: -1; background: conic-gradient(from var(--gradient-angle), var(--glow-gradient-stops)); border-radius: inherit; animation: gradient-rotation 3s linear infinite; pointer-events: none; filter: blur(0.2rem); opacity: 0.3; } } @property --gradient-angle { syntax: ""; initial-value: 0deg; inherits: false; } @keyframes gradient-rotation { 0% { --gradient-angle: 0deg; } 100% { --gradient-angle: 360deg; } } @layer base { /* v4 defaults border color to currentcolor - keep the app-wide default from v3 */ *, ::after, ::before, ::backdrop, ::file-selector-button { border-color: var(--color-grid-bright); } body { @apply bg-background-dimmed text-text-dimmed; font-feature-settings: "rlig" 1, "calt" 1; } /* Text selection styles */ ::selection { @apply bg-text-bright/30 text-text-bright; } /* Kept separate from ::selection on purpose: grouping them makes older Firefox drop the whole rule. */ /* stylelint-disable-next-line selector-no-vendor-prefix */ ::-moz-selection { @apply bg-text-bright/30 text-text-bright; } /* Native form controls, scrollbars etc. follow the app theme */ :root { color-scheme: dark; } [data-theme="light"] { color-scheme: light; } /* shadcn charts: https://ui.shadcn.com/docs/components/chart#add-a-grid */ :root { --chart-1: 12 76% 61%; --chart-2: 173 58% 39%; --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; } /* Classic and Dark share these HSL chart vars - they were the app-wide dark values. */ :is([data-theme="dark"], [data-theme="classic"]) { --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; } /* System preference unified chart set (dark+light): Classic's hues, with chart-2/3 darkened to clear 3:1 on white. Classic keeps the set above. */ :is([data-theme="dark"], [data-theme="light"]) { --chart-1: 220 70% 50%; --chart-2: 160 60% 40%; --chart-3: 30 80% 47%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; } /* Override react-grid-layout placeholder color (default is red) */ .react-grid-item.react-grid-placeholder { background: rgb(99 102 241) !important; /* indigo-500 */ border-radius: 0.375rem !important; /* rounded-md */ } /* Sidebar reorder grid: subtle placeholder */ .sidebar-reorder-grid .react-grid-item.react-grid-placeholder { background: var(--color-background-raised) !important; border-radius: 0.25rem; opacity: 1 !important; } /* Sidebar reorder grid: only animate transform (vertical position), not width/height */ .sidebar-reorder-grid .react-grid-item { transition: transform 200ms ease !important; } /* Override resize handle icon to white */ .react-resizable-handle { background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiNmZmZmZmYiLz48L2c+PC9zdmc+') !important; } .react-resizable-handle::after { border-bottom-color: rgba(255, 255, 255, 0.4) !important; border-right-color: rgba(255, 255, 255, 0.4) !important; border-top-color: rgba(255, 255, 255, 0.4) !important; border-left-color: rgba(255, 255, 255, 0.4) !important; } } @layer components { @supports (-webkit-hyphens: none) { .safari-only { @apply border-b border-grid-dimmed; } } } /* Streamdown markdown styling */ .streamdown-container { /* Streamdown uses shadcn/ui CSS variables - derive them from our semantic tokens so they follow the theme. They map Tailwind utility classes like bg-background, bg-primary, etc. that streamdown uses internally for its link safety modal, code blocks, and other interactive elements. */ --background: var(--color-background-deep); --foreground: var(--color-text-bright); --muted: var(--color-charcoal-775); --muted-foreground: var(--color-text-dimmed); --border: var(--color-border-bright); --primary: var(--color-primary); --primary-foreground: var(--color-background-deep); --sidebar: var(--color-background-dimmed); /* Code block styling */ & [data-streamdown="code-block"] { @apply rounded-sm my-2 border-charcoal-700; } & p { @apply my-1; } & h1, & h2, & h3, & h4, & h5, & h6 { @apply font-semibold text-text-bright mt-2 mb-1; } & h1 { @apply text-base; } & h2 { @apply text-sm; } & h3, & h4, & h5, & h6 { @apply text-xs; } & ul, & ol { @apply ml-4 my-1; } & ul { @apply list-disc; } & ol { @apply list-decimal; } & li { @apply my-0.5; } /* Theme-mapped, not raw charcoal: fenced blocks stay dark via shiki. */ & code:not(pre code) { @apply px-1 py-0.5 rounded-sm text-text-bright font-mono; background-color: var(--muted); } & blockquote { @apply border-l-2 border-charcoal-600 pl-3 my-2 italic; } & a { @apply text-text-link hover:underline; } & strong { @apply font-semibold text-text-bright; } & em { @apply italic; } & hr { @apply my-2 border-charcoal-600; } & table { @apply w-full my-2 border-collapse; } & th, & td { @apply border border-grid-bright px-2 py-1 text-left; } & th { @apply font-semibold; background-color: var(--muted); } /* The body scrolls and sizes the code; streamdown ships it at text-sm. */ & [data-streamdown="code-block-body"] { @apply text-xs leading-relaxed scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600; } } /* Light theme. Overrides the themable variables only; raw palettes stay put. Code/editor values come from the trigger.light VS Code theme. */ [data-theme="light"] { --color-secondary: #ffffff; --color-input-bg: #ffffff; /* shadcn vars consumed by charts/streamdown (tooltip cursor fill etc.) */ --background: #ffffff; --foreground: #1a1b1f; --muted: #eceef1; --muted-foreground: #5f6570; --border: #e2e4e9; --sidebar: #f6f7f8; --primary-foreground: #ffffff; /* Text */ --color-primary: var(--color-apple-600); --color-tertiary: #eef0f3; --color-text-link: var(--color-lavender-600); --color-text-faint: var(--color-charcoal-400); --color-text-dimmed: var(--color-charcoal-500); --color-text-bright: var(--color-charcoal-800); /* Surfaces */ --color-background-deep: #f1f2f4; --color-background-dimmed: #fbfbfc; --color-background-bright: #ffffff; --color-background-hover: #f2f3f5; /* Cards on white need a gentler hover than the app-wide surfaces */ --color-surface-hover-subtle: #f7f8f9; --color-background-raised: #e9eaee; --color-surface-control: #dcdee3; --color-surface-control-hover: #cfd2d9; --color-surface-control-active: #b8bcc6; /* Selection sits lighter than the controls here - on white a soft grey is already enough to read as selected */ --color-surface-selected: #eff0f2; --color-surface-selected-hover: #e7e9ec; /* Borders */ --color-grid-dimmed: #eceef1; --color-grid-bright: #e2e4e9; --color-border-selected: #e0e2e6; --color-border-bright: #d2d5db; --color-border-brighter: #b9bdc7; --color-border-brightest: #9ba1ad; /* Status/env/icon accents live in the unified dark+light block above; dev keeps its Classic pink-500, which passes on white too. */ /* Staging is the one per-mode env color: warm orange has no clean unified mid-tone, so dark keeps Classic's bright orange-400 and light deepens it */ --color-staging: var(--color-orange-600); /* Grey chart reference series, light enough not to dominate on white */ --color-queues-chart-ref: #c3c7cf; /* Neutral run statuses: soft light grays for sparkbars and charts */ --color-run-pending: #ccd0d6; --color-run-delayed: #d3d6db; --color-run-waiting-to-resume: #c5c9d0; --color-run-canceled: #d8dbdf; --color-run-expired: #dee0e4; /* Monochrome icon gray - per-mode, not part of the unified accent set */ --color-customDashboards: var(--color-charcoal-500); /* Callout text/bg - deep tints instead of the dark theme's pastels; text can't unify across modes (see the unified accents block) */ --color-callout-warning-text: var(--color-yellow-800); --color-callout-error-text: var(--color-rose-700); --color-callout-success-text: var(--color-green-800); --color-callout-docs-text: var(--color-blue-800); --color-callout-pending-bg: var(--color-blue-100); --color-callout-pending-text: var(--color-blue-800); --color-callout-pricing-bg: var(--color-indigo-100); --color-callout-pricing-text: var(--color-indigo-800); /* Code syntax - trigger.light */ --color-code-background: #ffffff; --color-code-foreground: #333333; --color-code-line-number: #a8a8ad; --color-code-plain: #2e2e4b; --color-code-muted: #333333; --color-code-comment: #767a81; --color-code-keyword: #b114d3; --color-code-storage: #b114d3; --color-code-type: #b114d3; --color-code-function: #6532f5; --color-code-variable: #404040; --color-code-constant: #1e1e1e; --color-code-language: #b114d3; --color-code-object-key: #222222; --color-code-string: #262626; --color-code-template-punctuation: #0879e2; --color-code-number: #262626; --color-code-builtin: #3080e0; --color-code-attribute: #222222; --color-code-escape: #222222; --color-code-regexp: #dc3545; --color-code-regexp-constant: #5f6570; --color-code-invalid: #dc3545; --color-code-deleted: #dc3545; --color-code-jsx-text: #2e2e4b; /* CodeMirror - trigger.light */ --color-editor-background: #ffffff; --color-editor-foreground: #2e2e4b; --color-editor-keyword: #b114d3; --color-editor-name: #197c3c; --color-editor-function: #6532f5; --color-editor-constant: #3080e0; --color-editor-type: #2980b9; --color-editor-operator: #333333; --color-editor-comment: #767a81; --color-editor-heading: #2c3e50; --color-editor-string: #262626; --color-editor-invalid: #dc3545; --color-editor-panel-background: #f4f4f6; --color-editor-highlight-background: #f8f8fa; --color-editor-tooltip-background: #ffffff; --color-editor-selection: #d9dce3; --color-editor-cursor: #2e2e4b; --color-editor-search-match: #0879e226; --color-editor-search-match-outline: #0879e2; --color-editor-search-match-selected: #0879e240; --color-editor-selection-match: #e8e8ed; --color-editor-matching-bracket: rgba(240, 241, 244, 0.9); --color-editor-matching-bracket-outline: rgba(160, 166, 180, 0.5); --color-editor-fold-placeholder: #555555; --color-editor-scrollbar-track-active: #e8e9ec; --color-editor-scrollbar-thumb: #c9ccd4; --color-editor-scrollbar-thumb-active: #aeb3be; } /* Streamdown's muted surface has no semantic token (charcoal-775); theme it here */ [data-theme="light"] .streamdown-container { --muted: #eceef1; } /* The timeline label shadow is a Classic legibility aid; the System themes drop it entirely */ :is([data-theme="dark"], [data-theme="light"]) .text-shadow-custom { text-shadow: none; } /* Neutral timeline points: invert to a light dot with a gray ring */ [data-theme="light"] .timeline-point.bg-surface-control-active { border-color: var(--color-surface-control-active); background-color: var(--color-background-bright); } /* Run timeline bars: no fade gradient on light */ [data-theme="light"] .timeline-span { background-image: none; } /* On saturated bars the duration label keeps the dark-theme treatment, but only when the bar is wide enough to contain the label — on narrow bars the sticky label overflows onto the page background, where the default dark-on-light text is correct. */ [data-theme="light"] .timeline-span.bg-success, [data-theme="light"] .timeline-span.bg-error, [data-theme="light"] .timeline-span.bg-blue-500 { container-type: inline-size; } @container (min-width: 3.5rem) { [data-theme="light"] .timeline-span.bg-success .text-shadow-custom, [data-theme="light"] .timeline-span.bg-error .text-shadow-custom, [data-theme="light"] .timeline-span.bg-blue-500 .text-shadow-custom { color: #ffffff; } } /* The table row-hover menu wraps the always-visible "Suggest a region" button in a ring container; on light that ring doubles up with the button's own border, so drop it here. */ [data-theme="light"] .suggest-region-cell > div > div { box-shadow: none; } /* Interface contrast (System themes only). --theme-contrast is 0..1, set on from the dashboard preference. It pulls the whole monochrome scale apart: text mixes toward the mode's foreground, backgrounds toward its depth, borders step up. Accents are untouched. srgb mixing keeps contrast 0 byte-identical to the base values, and Classic never reads the variable. These blocks must stay below the [data-theme="light"] theme block so they win the cascade. */ [data-theme="dark"] { /* Text brightens toward white */ --color-text-bright: color-mix(in srgb, var(--color-charcoal-200), #fff calc(var(--theme-contrast, 0) * 100%)); --color-text-dimmed: color-mix(in srgb, var(--color-charcoal-400), #fff calc(var(--theme-contrast, 0) * 60%)); --color-text-faint: color-mix(in srgb, var(--color-charcoal-500), #fff calc(var(--theme-contrast, 0) * 45%)); /* Backgrounds deepen toward black, keeping their relative order */ --color-background-deep: color-mix(in srgb, var(--color-charcoal-900), #000 calc(var(--theme-contrast, 0) * 60%)); --color-background-dimmed: color-mix(in srgb, var(--color-charcoal-850), #000 calc(var(--theme-contrast, 0) * 55%)); --color-background-bright: color-mix(in srgb, var(--color-charcoal-800), #000 calc(var(--theme-contrast, 0) * 45%)); --color-background-hover: color-mix(in srgb, var(--color-charcoal-750), #000 calc(var(--theme-contrast, 0) * 35%)); --color-surface-hover-subtle: color-mix(in srgb, var(--color-charcoal-750), #000 calc(var(--theme-contrast, 0) * 35%)); --color-background-raised: color-mix(in srgb, var(--color-charcoal-700), #000 calc(var(--theme-contrast, 0) * 25%)); --color-input-bg: color-mix(in srgb, var(--color-charcoal-750), #000 calc(var(--theme-contrast, 0) * 35%)); /* Controls and borders step up toward white */ --color-surface-control: color-mix(in srgb, var(--color-charcoal-600), #fff calc(var(--theme-contrast, 0) * 12%)); --color-surface-control-hover: color-mix(in srgb, var(--color-charcoal-550), #fff calc(var(--theme-contrast, 0) * 14%)); --color-surface-control-active: color-mix(in srgb, var(--color-charcoal-500), #fff calc(var(--theme-contrast, 0) * 16%)); --color-grid-dimmed: color-mix(in srgb, var(--color-charcoal-750), #fff calc(var(--theme-contrast, 0) * 18%)); --color-grid-bright: color-mix(in srgb, var(--color-charcoal-700), #fff calc(var(--theme-contrast, 0) * 20%)); --color-border-bright: color-mix(in srgb, var(--color-charcoal-600), #fff calc(var(--theme-contrast, 0) * 24%)); --color-border-brighter: color-mix(in srgb, var(--color-charcoal-550), #fff calc(var(--theme-contrast, 0) * 27%)); --color-border-brightest: color-mix(in srgb, var(--color-charcoal-500), #fff calc(var(--theme-contrast, 0) * 30%)); } [data-theme="light"] { /* Text deepens toward black */ --color-text-bright: color-mix(in srgb, #1a1b1f, #000 calc(var(--theme-contrast, 0) * 100%)); --color-text-dimmed: color-mix(in srgb, var(--color-charcoal-500), #000 calc(var(--theme-contrast, 0) * 85%)); --color-text-faint: color-mix(in srgb, var(--color-charcoal-400), #000 calc(var(--theme-contrast, 0) * 70%)); /* On white the foregrounds carry the contrast: cards stay white while the page-behind surfaces darken a touch so panels separate */ --color-background-deep: color-mix(in srgb, #f1f2f4, #000 calc(var(--theme-contrast, 0) * 10%)); --color-background-hover: color-mix(in srgb, #f2f3f5, #000 calc(var(--theme-contrast, 0) * 8%)); /* Radio card surfaces take no ramp at all on white - their contrast is carried by border-selected below. Deliberately absent: surface-hover-subtle, surface-selected, surface-selected-hover. */ --color-background-raised: color-mix(in srgb, #e9eaee, #000 calc(var(--theme-contrast, 0) * 10%)); /* Controls and borders push hard toward black - this is where light-mode contrast is actually visible */ --color-surface-control: color-mix(in srgb, #dcdee3, #000 calc(var(--theme-contrast, 0) * 25%)); --color-surface-control-hover: color-mix(in srgb, #cfd2d9, #000 calc(var(--theme-contrast, 0) * 28%)); --color-surface-control-active: color-mix(in srgb, #b8bcc6, #000 calc(var(--theme-contrast, 0) * 32%)); --color-grid-dimmed: color-mix(in srgb, #eceef1, #000 calc(var(--theme-contrast, 0) * 28%)); --color-grid-bright: color-mix(in srgb, #e2e4e9, #000 calc(var(--theme-contrast, 0) * 32%)); /* Steeper than border-bright so the selected card stays the loudest edge */ --color-border-selected: color-mix(in srgb, #e0e2e6, #000 calc(var(--theme-contrast, 0) * 45%)); --color-border-bright: color-mix(in srgb, #d2d5db, #000 calc(var(--theme-contrast, 0) * 38%)); --color-border-brighter: color-mix(in srgb, #b9bdc7, #000 calc(var(--theme-contrast, 0) * 42%)); --color-border-brightest: color-mix(in srgb, #9ba1ad, #000 calc(var(--theme-contrast, 0) * 46%)); } form:has(.unlock-hint-staging-env:hover) [data-unlock-target="staging-env"], form:has(.unlock-hint-pull-prod:hover) [data-unlock-target="pull-prod"], form:has(.unlock-hint-pull-stg:hover) [data-unlock-target="pull-stg"], form:has(.unlock-hint-pull-preview:hover) [data-unlock-target="pull-preview"], form:has(.unlock-hint-pull-dev:hover) [data-unlock-target="pull-dev"] { border-radius: 0.25rem; outline: 2px dashed var(--color-warning); outline-offset: 2px; }