/* * Phosphor — terminal heritage, dark-first. * * The dark mode IS the theme: a deep charcoal with a barely-there green * undertone (hue ~150, chroma 0.006 — never blue-gray, never pure black), * the way a switched-off CRT still remembers its phosphor coat. Cards step * LIGHTER off the background by a full 0.06 L, and hairline light-alpha * borders do all the separation work — the elevation ladder exists but is * whisper-quiet, because on a terminal, borders beat shadows. The single * accent is phosphor green (~oklch(0.75 0.16 148)) carrying DARK ink on the * bright fill (the ivrea dark-ink-on-bright pattern), spent on the primary * action, focus, and selection only. * * Light mode is the "paper terminal": warm-white paper (hue ~120, faint) with * deep green-charcoal ink, and the same green deepened to ~L0.45 so white * labels clear the floor. Success is pulled to TEAL (hue 178, 30° from the * primary's 148) so state-green never collides with action-green. * * Type is the signature: IBM Plex Mono for HEADINGS (500/600, slightly tight), * IBM Plex Sans for body, Plex Mono for code. Dense/pro register — body * 0.9375rem, modest display sizes (mono runs wide). Radius is a tight * 0.375rem; motion is instant-feeling (100/180/280/400ms), springs aliased. * Syntax colors are a muted-precise terminal scheme — no neon soup. * * Token contract matches lib-theme-caffe-florian/theme.css (Crema v1). */ /* * Fonts: consuming apps load IBM Plex Sans + IBM Plex Mono at the top of * their entry CSS (where @import statements are allowed), via the Google * Fonts URL documented in this theme's README. Embedding the @import here — * or smuggling the URL in a comment for a build script to lift — breaks * PostCSS's ordering rules, so neither is done in this file. */ :root { --font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; /* Tailwind utility families. Distinct names so a consuming app's * `@theme inline` can indirect to these (--font-heading/--font-sans collide * with Tailwind's own font-* namespace). Mirror --font-heading/--font-sans. */ --heading-family: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; --body-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* ── Colors ── paper terminal: warm-white paper, deep green-charcoal ink, * one deepened phosphor-green accent carrying white labels. */ --background: oklch(0.975 0.004 120); --foreground: oklch(0.22 0.015 150); --card: oklch(0.99 0.002 120); --card-foreground: oklch(0.22 0.015 150); --popover: oklch(0.995 0.002 120); --popover-foreground: oklch(0.22 0.015 150); /* Primary — phosphor green deepened for paper (L0.45) so near-white * labels sit well above the floor. The bright terminal green returns * in dark mode, where it belongs. */ --primary: oklch(0.45 0.12 150); --primary-foreground: oklch(0.98 0.008 140); --secondary: oklch(0.93 0.008 140); --secondary-foreground: oklch(0.3 0.015 150); --muted: oklch(0.935 0.007 135); --muted-foreground: oklch(0.44 0.018 150); /* Accent — hover/selection wash: a faint green tint with deep green ink, * not a second competing fill. */ --accent: oklch(0.93 0.028 148); --accent-foreground: oklch(0.33 0.09 150); /* ── Status ── success is TEAL (hue 178, 30° off the green primary) so * "ok" never impersonates "act". Destructive/info carry light labels on * deep fills; warning carries dark amber ink on a mid amber. */ --destructive: oklch(0.55 0.21 27); --destructive-foreground: oklch(0.98 0.01 27); --success: oklch(0.5 0.11 178); --success-foreground: oklch(0.98 0.01 178); --warning: oklch(0.66 0.15 80); --warning-foreground: oklch(0.21 0.05 80); --info: oklch(0.5 0.13 235); --info-foreground: oklch(0.98 0.01 235); /* Borders do the separation work — a touch stronger than house norm. */ --border: oklch(0.22 0.015 150 / 0.14); --input: oklch(0.22 0.015 150 / 0.16); --ring: oklch(0.45 0.12 150 / 0.6); /* Chart palette — phosphor green lead, then blue / amber / violet / red. * Hues spaced, adjacent-index lightness varied. */ --chart-1: oklch(0.52 0.13 150); --chart-2: oklch(0.58 0.13 235); --chart-3: oklch(0.68 0.14 80); --chart-4: oklch(0.55 0.15 310); --chart-5: oklch(0.6 0.17 25); --sidebar: oklch(0.955 0.006 130); --sidebar-foreground: oklch(0.22 0.015 150); --sidebar-primary: oklch(0.45 0.12 150); --sidebar-primary-foreground: oklch(0.98 0.008 140); --sidebar-accent: oklch(0.92 0.028 148); --sidebar-accent-foreground: oklch(0.33 0.09 150); --sidebar-border: oklch(0.22 0.015 150 / 0.1); --sidebar-ring: oklch(0.45 0.12 150 / 0.6); /* Syntax — paper-terminal ink: precise, low-chroma, green-led. */ --syntax-keyword: oklch(0.45 0.11 150); --syntax-string: oklch(0.5 0.09 80); --syntax-number: oklch(0.48 0.09 178); --syntax-comment: oklch(0.55 0.015 150); --syntax-function: oklch(0.48 0.11 235); --syntax-type: oklch(0.5 0.09 310); /* ── Chat surfaces ── * Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. User bubble * is the deep green-charcoal ink as a panel with paper text; assistant is * a clean card behind a hairline border. */ --chat-user-bg: oklch(0.27 0.018 150); --chat-user-fg: oklch(0.97 0.005 120); --chat-assistant-bg: oklch(0.99 0.002 120); --chat-assistant-fg: oklch(0.22 0.015 150); --chat-assistant-border: oklch(0.22 0.015 150 / 0.14); /* Tight console radius. */ --radius: 0.375rem; /* ── Motion ── instant-feeling. Springs alias to the standard eases — * a console does not bounce; personality lives in the speed. */ --duration-fast: 100ms; --duration-base: 180ms; --duration-slow: 280ms; --duration-slower: 400ms; --duration-spring: 180ms; --ease-standard: cubic-bezier(0.2, 0, 0, 1); --ease-decelerate: cubic-bezier(0, 0, 0, 1); --ease-accelerate: cubic-bezier(0.3, 0, 1, 1); --ease-emphasized: cubic-bezier(0.2, 0, 0, 1); --ease-spring-gentle: var(--ease-standard); --ease-spring-snappy: var(--ease-decelerate); --ease-spring-bouncy: var(--ease-standard); /* ── Typography ── dense/pro register, fixed rem. Display sizes run * modest because mono headings run wide. */ --text-hero-size: 2.75rem; --text-hero-lh: 1.1; --text-display-size: 2rem; --text-display-lh: 1.15; --text-headline-size: 1.5rem; --text-headline-lh: 1.25; --text-title-size: 1.1875rem; --text-title-lh: 1.35; --text-subtitle-size: 1.0625rem; --text-subtitle-lh: 1.45; --text-body-size: 0.9375rem; --text-body-lh: 1.5; --text-label-size: 0.8125rem; --text-label-lh: 1.25rem; --text-caption-size: 0.75rem; --text-caption-lh: 1.0625rem; /* ── Elevation ── whisper-quiet: borders separate, shadows only hint. * The ladder is present but nearly flat. */ --elevation-0: none; --elevation-1: 0 1px 1px oklch(0.22 0.015 150 / 0.04); --elevation-2: 0 1px 2px oklch(0.22 0.015 150 / 0.05); --elevation-3: 0 2px 4px -1px oklch(0.22 0.015 150 / 0.06); --elevation-4: 0 4px 10px -3px oklch(0.22 0.015 150 / 0.08); --elevation-5: 0 8px 20px -6px oklch(0.22 0.015 150 / 0.1); --spacing: 0.25rem; --border-width-thin: 0.5px; --border-width-base: 1px; --border-width-thick: 2px; --border-width-heavy: 4px; /* No glass — inert values so consuming apps referencing these get no-ops. */ --glass-blur: 0px; --glass-saturate: 100%; --glass-brightness: 1; --glass-contrast: 1; } /* * Dark mode — the native identity. Deep charcoal with the faint phosphor * undertone (hue 150, chroma 0.006 — not blue-gray, not black). Cards step * a full 0.06 L LIGHTER; popover sits one step above card, below muted. * Hairline light-alpha borders carry the structure; the bright phosphor * green takes dark ink on top. */ .dark { --background: oklch(0.17 0.006 150); --foreground: oklch(0.93 0.008 150); --card: oklch(0.23 0.007 150); --card-foreground: oklch(0.93 0.008 150); --popover: oklch(0.25 0.007 150); --popover-foreground: oklch(0.93 0.008 150); --primary: oklch(0.75 0.16 148); --primary-foreground: oklch(0.18 0.045 148); --secondary: oklch(0.27 0.008 150); --secondary-foreground: oklch(0.9 0.008 150); --muted: oklch(0.27 0.008 150); --muted-foreground: oklch(0.71 0.012 150); --accent: oklch(0.29 0.04 148); --accent-foreground: oklch(0.86 0.12 148); --destructive: oklch(0.68 0.19 25); --destructive-foreground: oklch(0.16 0.045 25); --success: oklch(0.78 0.13 178); --success-foreground: oklch(0.18 0.04 178); --warning: oklch(0.8 0.15 80); --warning-foreground: oklch(0.2 0.05 80); --info: oklch(0.72 0.12 235); --info-foreground: oklch(0.16 0.04 235); /* Light-alpha hairlines — a touch stronger than house norm; borders are * the separation mechanism here, not shadows. */ --border: oklch(0.95 0.01 150 / 0.14); --input: oklch(0.95 0.01 150 / 0.17); --ring: oklch(0.75 0.16 148 / 0.6); --chart-1: oklch(0.75 0.16 148); --chart-2: oklch(0.66 0.13 235); --chart-3: oklch(0.79 0.14 80); --chart-4: oklch(0.64 0.14 310); --chart-5: oklch(0.68 0.17 25); /* Sidebar drops BELOW the background — the darkest rail on screen, a * terminal gutter. */ --sidebar: oklch(0.15 0.006 150); --sidebar-foreground: oklch(0.93 0.008 150); --sidebar-primary: oklch(0.75 0.16 148); --sidebar-primary-foreground: oklch(0.18 0.045 148); --sidebar-accent: oklch(0.27 0.04 148); --sidebar-accent-foreground: oklch(0.86 0.12 148); --sidebar-border: oklch(0.95 0.01 150 / 0.1); --sidebar-ring: oklch(0.75 0.16 148 / 0.6); /* Syntax — a great terminal colorscheme: green keywords, warm strings, * teal numbers, dim comments. Chroma capped ~0.12; muted-precise. */ --syntax-keyword: oklch(0.78 0.11 148); --syntax-string: oklch(0.79 0.09 80); --syntax-number: oklch(0.76 0.09 178); --syntax-comment: oklch(0.58 0.015 150); --syntax-function: oklch(0.77 0.08 235); --syntax-type: oklch(0.74 0.08 310); /* ── Chat surfaces (dark) ── user panel steps above muted; assistant sits * on the card step behind a hairline. */ --chat-user-bg: oklch(0.31 0.015 150); --chat-user-fg: oklch(0.96 0.006 150); --chat-assistant-bg: oklch(0.23 0.007 150); --chat-assistant-fg: oklch(0.93 0.008 150); --chat-assistant-border: oklch(0.95 0.01 150 / 0.14); --elevation-1: 0 1px 1px oklch(0 0 0 / 0.16); --elevation-2: 0 1px 2px oklch(0 0 0 / 0.2); --elevation-3: 0 2px 4px -1px oklch(0 0 0 / 0.24); --elevation-4: 0 4px 10px -3px oklch(0 0 0 / 0.28); --elevation-5: 0 8px 20px -6px oklch(0 0 0 / 0.34); } /* * @layer base — Phosphor's dense, keyboard-first console philosophy. * * Mono headings, hairline-separated calm surfaces, tabular numerals in data * contexts, and the phosphor green reserved for focus, selection, and the * primary action. Everything else stays quiet. */ @layer base { body { min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: -0.004em; font-family: var(--font-sans); font-size: var(--text-body-size); line-height: var(--text-body-lh); } /* Headings — IBM Plex Mono, the signature. 600, slightly tight; mono * already runs wide, so no extra tracking. */ h1, h2, h3, h4, [data-slot="card-title"], [data-slot="dialog-title"], [data-slot="sheet-title"], [data-slot="alert-dialog-title"] { font-family: var(--font-heading); font-weight: 600; letter-spacing: -0.015em; color: var(--foreground); } h4, [data-slot="card-title"] { font-weight: 500; } code, kbd, samp, pre, [data-slot="code"], [data-slot="code-block"] { font-family: var(--font-mono); } /* Inline code — neutral chip: faint foreground tint, foreground ink. * Never accent-colored. */ :not(pre) > code { padding: 0.1em 0.35em; border-radius: calc(var(--radius) * 0.5); background: color-mix(in oklch, var(--foreground) 6%, transparent); color: var(--foreground); font-size: 0.9em; } /* Dense utility — data reads in columns. Tabular numerals for tables and * an opt-in .num class for stat tiles, IDs, and metric rows. */ [data-slot="table"] { font-variant-numeric: tabular-nums; } .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; } /* Selection — the phosphor spark. */ ::selection { background: color-mix(in oklch, var(--primary) 30%, transparent); color: var(--foreground); } /* Links — green-leaning ink, underline-on-hover. */ a { color: color-mix(in oklch, var(--primary) 70%, var(--foreground)); text-decoration-color: color-mix(in oklch, var(--primary) 40%, transparent); text-underline-offset: 0.2em; transition: text-decoration-color var(--duration-fast) var(--ease-standard); } a:hover { text-decoration-color: var(--primary); } [data-slot="sidebar"] { background: var(--sidebar); border-right: var(--border-width-base) solid var(--sidebar-border); } } /* * Focus-visible — keyboard-first is a signature. Buttons get a crisp 2px * phosphor outline, offset; inputs get a flush 1px ring plus a border-color * change (see the input block below). Placed outside @layer base so it beats * Tailwind's default ring utilities. */ [data-slot="button"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: none; } [data-slot="input"]:focus-visible, [data-slot="textarea"]:focus-visible, [data-slot="select-trigger"]:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); } /* Buttons — quiet weight; opacity absorb on press, instant. */ [data-slot="button"] { font-weight: 500; letter-spacing: -0.004em; } /* Card titles — pinned to the subtitle role so the scale is the theme's * decision, not the card primitive's default. */ [data-slot="card-title"] { font-size: var(--text-subtitle-size); line-height: var(--text-subtitle-lh); } /* Touch targets — desktop keeps the dense console ladder; coarse pointers * get the 44px floor on every control. */ @media (pointer: coarse) { [data-slot="button"] { min-height: 2.75rem; min-width: 2.75rem; } [data-slot="input"], [data-slot="select-trigger"] { min-height: 2.75rem; } } [data-slot="button"]:hover:not(:disabled) { opacity: 0.9; } [data-slot="button"]:active:not(:disabled) { opacity: 0.82; transform: scale(0.99); } /* Inputs — card surface, hairline border, phosphor focus as a flush ring. */ [data-slot="input"], [data-slot="textarea"], [data-slot="select-trigger"] { background: var(--card); border: var(--border-width-base) solid var(--input); border-radius: var(--radius); color: var(--foreground); transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); } [data-slot="input"]::placeholder, [data-slot="textarea"]::placeholder { color: var(--muted-foreground); opacity: 0.8; } [data-slot="input"]:hover:not(:disabled), [data-slot="textarea"]:hover:not(:disabled), [data-slot="select-trigger"]:hover:not(:disabled) { border-color: color-mix(in oklch, var(--foreground) 26%, transparent); } [data-slot="input"]:focus, [data-slot="textarea"]:focus, [data-slot="select-trigger"]:focus { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); outline: none; }