/* * Klein — ultramarine drench. * * Yves Klein blue as the identity. The background field ITSELF is a committed, * saturated deep ultramarine — not a tint, not an accent, the world you stand * in — carrying near-white ink. Cards are clean near-white panels floating on * the blue, with dark ink on top. This inverts the usual light-theme logic: * :root (light mode) IS the drenched blue world; the blue carries 30–60% of * every surface by construction. * * The counterpoint is a warm amber-orange (hue ~60) spent on the primary * action, focus, selection, and the user chat bubble — the one hot signal that * pops off the ultramarine. Secondary and muted stay inside the blue family * (deeper stripes of the same hue); the sidebar is a deeper band of * ultramarine. Borders are dark hairlines because borders live on the white * cards and inputs; the sidebar gets its own white-alpha hairline token. * * Dark mode is ultramarine at midnight: the field deepens, cards become deep * blue panels stepping LIGHTER off the field, ink stays near-white — the theme * is unmistakably blue in both modes. * * Type is the art-poster voice: Syne (700+) for headings, Inter for body, * JetBrains Mono for code. Consumer register — generous 1rem radius, confident * motion (150/300/450/600ms) with real gentle springs, deep blue-black shadows * (a drenched field casts blue shadow, never gray). * * Token contract matches lib-theme-caffe-florian/theme.css (Crema v1). */ /* * Fonts: consuming apps load Syne + Inter + JetBrains 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: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "Syne", "Inter", -apple-system, BlinkMacSystemFont, sans-serif; --font-mono: "JetBrains 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: "Syne", "Inter", -apple-system, BlinkMacSystemFont, sans-serif; --body-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* ── Colors ── the drench: deep saturated ultramarine field, near-white * ink on the blue, clean near-white cards carrying dark blue-black ink. */ --background: oklch(0.44 0.2 265); --foreground: oklch(0.985 0.008 265); --card: oklch(0.99 0.005 265); --card-foreground: oklch(0.21 0.045 265); --popover: oklch(1 0 0); --popover-foreground: oklch(0.21 0.045 265); /* Primary — the warm counterpoint. Vivid amber-orange with near-black warm * ink on top (bright-swatch/dark-ink pairing); the one hot signal that * pops off the blue field. */ --primary: oklch(0.72 0.17 60); --primary-foreground: oklch(0.2 0.05 60); /* Secondary — a deeper stripe of the same ultramarine, white ink. */ --secondary: oklch(0.38 0.18 265); --secondary-foreground: oklch(0.975 0.008 265); /* Muted — the family's quiet register: deeper blue surface; the muted ink * is a pale desaturated ultramarine that still clears 4.5:1 on the field. */ --muted: oklch(0.39 0.18 265); --muted-foreground: oklch(0.87 0.05 265); /* Accent — hover/selection tint for menus and popovers (which are white * panels here): a pale ultramarine wash with deep blue ink. */ --accent: oklch(0.93 0.035 265); --accent-foreground: oklch(0.3 0.13 265); /* ── Status ── tuned for the CARD surface (chips sit on white panels). * Dark ink on bright swatches for success/warning/info; destructive keeps * a light label on a deep alarm red. Warning sits at yellow ~90 so it * never reads as the amber-orange primary (hue 60). Info is a cyan-sky * (~220) clearly apart from the ultramarine field (265). */ --destructive: oklch(0.55 0.21 27); --destructive-foreground: oklch(0.98 0.01 27); --success: oklch(0.62 0.14 150); --success-foreground: oklch(0.17 0.03 150); --warning: oklch(0.8 0.15 90); --warning-foreground: oklch(0.23 0.05 90); --info: oklch(0.7 0.12 220); --info-foreground: oklch(0.16 0.03 220); /* Borders live where hairlines are drawn: on white cards and inputs — so * --border is a dark blue-ink hairline. The blue field's own hairlines are * carried by --sidebar-border (white-alpha) below. */ --border: oklch(0.21 0.045 265 / 0.14); --input: oklch(0.21 0.045 265 / 0.18); --ring: oklch(0.72 0.17 60 / 0.6); /* Chart palette — amber counterpoint leads, then the identity ultramarine, * teal, magenta, green. Hues spaced ≥60°, adjacent lightness varied. * Tuned for the white card surface where charts render. */ --chart-1: oklch(0.72 0.17 60); --chart-2: oklch(0.48 0.2 265); --chart-3: oklch(0.65 0.12 190); --chart-4: oklch(0.56 0.2 340); --chart-5: oklch(0.62 0.15 150); /* Sidebar — a deeper stripe of ultramarine; hairlines on the blue are * white-alpha; the amber signal marks the active item. */ --sidebar: oklch(0.36 0.17 265); --sidebar-foreground: oklch(0.975 0.008 265); --sidebar-primary: oklch(0.72 0.17 60); --sidebar-primary-foreground: oklch(0.2 0.05 60); --sidebar-accent: oklch(0.47 0.2 265); --sidebar-accent-foreground: oklch(0.985 0.008 265); --sidebar-border: oklch(1 0 0 / 0.18); --sidebar-ring: oklch(0.72 0.17 60 / 0.6); /* Syntax — code blocks render on light card surfaces: deep inks with the * theme's blue and amber in the leading roles. */ --syntax-keyword: oklch(0.45 0.2 265); --syntax-string: oklch(0.48 0.12 150); --syntax-number: oklch(0.55 0.14 60); --syntax-comment: oklch(0.55 0.03 265); --syntax-function: oklch(0.5 0.16 300); --syntax-type: oklch(0.48 0.1 190); /* ── Chat surfaces ── * Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. The user * bubble is the amber counterpoint (dark ink) glowing against the blue * field; the assistant answers on a clean white card with a hairline. */ --chat-user-bg: oklch(0.72 0.17 60); --chat-user-fg: oklch(0.2 0.05 60); --chat-assistant-bg: oklch(0.99 0.005 265); --chat-assistant-fg: oklch(0.21 0.045 265); --chat-assistant-border: oklch(0.21 0.045 265 / 0.12); /* Generous consumer radius. */ --radius: 1rem; /* ── Motion ── confident consumer pacing with real gentle springs — the * bold identity is allowed a physical settle. */ --duration-fast: 150ms; --duration-base: 300ms; --duration-slow: 450ms; --duration-slower: 600ms; --duration-spring: 450ms; --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.3, 0, 0, 1); --ease-spring-gentle: cubic-bezier(0.34, 1.16, 0.64, 1); --ease-spring-snappy: cubic-bezier(0.42, 1.28, 0.56, 1); --ease-spring-bouncy: cubic-bezier(0.36, 1.44, 0.44, 1); /* ── Typography ── consumer register, fixed rem, full role ramp. */ --text-hero-size: 3.25rem; --text-hero-lh: 1.05; --text-display-size: 2.5rem; --text-display-lh: 1.1; --text-headline-size: 1.75rem; --text-headline-lh: 1.2; --text-title-size: 1.375rem; --text-title-lh: 1.3; --text-subtitle-size: 1.125rem; --text-subtitle-lh: 1.45; --text-body-size: 1rem; --text-body-lh: 1.6; --text-label-size: 0.875rem; --text-label-lh: 1.25rem; --text-caption-size: 0.75rem; --text-caption-lh: 1.125rem; /* ── Elevation ── shadows cast on a drenched field are deep blue-black, * never gray — white cards lift off the ultramarine on blue shadow. */ --elevation-0: none; --elevation-1: 0 1px 2px oklch(0.12 0.08 265 / 0.2); --elevation-2: 0 2px 4px oklch(0.12 0.08 265 / 0.24), 0 1px 2px oklch(0.12 0.08 265 / 0.16); --elevation-3: 0 6px 12px -2px oklch(0.12 0.08 265 / 0.28), 0 2px 4px -2px oklch(0.12 0.08 265 / 0.18); --elevation-4: 0 14px 28px -6px oklch(0.12 0.08 265 / 0.34), 0 4px 10px -4px oklch(0.12 0.08 265 / 0.2); --elevation-5: 0 24px 48px -8px oklch(0.12 0.08 265 / 0.44); --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 — ultramarine at midnight. The field deepens (still unmistakably * blue, never charcoal); cards become deep blue panels stepping LIGHTER off * the field (bg 0.30 → card 0.36 → popover 0.385 → muted 0.40); ink stays * near-white; the amber signal brightens a touch against the night. */ .dark { --background: oklch(0.3 0.13 265); --foreground: oklch(0.965 0.01 265); --card: oklch(0.36 0.14 265); --card-foreground: oklch(0.965 0.01 265); --popover: oklch(0.385 0.14 265); --popover-foreground: oklch(0.965 0.01 265); --primary: oklch(0.75 0.16 60); --primary-foreground: oklch(0.2 0.05 60); --secondary: oklch(0.4 0.15 265); --secondary-foreground: oklch(0.95 0.012 265); --muted: oklch(0.4 0.15 265); --muted-foreground: oklch(0.85 0.045 265); --accent: oklch(0.45 0.16 265); --accent-foreground: oklch(0.97 0.01 265); --destructive: oklch(0.56 0.21 27); --destructive-foreground: oklch(0.98 0.01 27); --success: oklch(0.7 0.15 150); --success-foreground: oklch(0.17 0.03 150); --warning: oklch(0.83 0.15 90); --warning-foreground: oklch(0.23 0.05 90); --info: oklch(0.74 0.12 220); --info-foreground: oklch(0.16 0.03 220); /* At midnight every surface is blue, so hairlines are white-ink alpha. */ --border: oklch(0.97 0.01 265 / 0.16); --input: oklch(0.97 0.01 265 / 0.2); --ring: oklch(0.75 0.16 60 / 0.6); --chart-1: oklch(0.78 0.16 60); --chart-2: oklch(0.68 0.15 265); --chart-3: oklch(0.74 0.12 190); --chart-4: oklch(0.7 0.17 340); --chart-5: oklch(0.74 0.15 150); --sidebar: oklch(0.26 0.12 265); --sidebar-foreground: oklch(0.965 0.01 265); --sidebar-primary: oklch(0.75 0.16 60); --sidebar-primary-foreground: oklch(0.2 0.05 60); --sidebar-accent: oklch(0.37 0.15 265); --sidebar-accent-foreground: oklch(0.97 0.01 265); --sidebar-border: oklch(1 0 0 / 0.14); --sidebar-ring: oklch(0.75 0.16 60 / 0.6); --syntax-keyword: oklch(0.82 0.1 265); --syntax-string: oklch(0.82 0.12 150); --syntax-number: oklch(0.84 0.13 60); --syntax-comment: oklch(0.72 0.03 265); --syntax-function: oklch(0.8 0.12 300); --syntax-type: oklch(0.8 0.1 190); /* ── Chat surfaces (dark) ── the amber user bubble glows against the * midnight field; the assistant answers on a deep blue card panel. */ --chat-user-bg: oklch(0.75 0.16 60); --chat-user-fg: oklch(0.2 0.05 60); --chat-assistant-bg: oklch(0.36 0.14 265); --chat-assistant-fg: oklch(0.965 0.01 265); --chat-assistant-border: oklch(0.97 0.01 265 / 0.14); --elevation-1: 0 1px 2px oklch(0.08 0.05 265 / 0.4); --elevation-2: 0 2px 4px oklch(0.08 0.05 265 / 0.45), 0 1px 2px oklch(0.08 0.05 265 / 0.3); --elevation-3: 0 6px 12px -2px oklch(0.08 0.05 265 / 0.5), 0 2px 4px -2px oklch(0.08 0.05 265 / 0.3); --elevation-4: 0 14px 28px -6px oklch(0.08 0.05 265 / 0.55), 0 4px 10px -4px oklch(0.08 0.05 265 / 0.3); --elevation-5: 0 24px 48px -8px oklch(0.08 0.05 265 / 0.65); } /* * @layer base — Klein's poster philosophy. * * The field is the identity: content floats on committed ultramarine. Syne * headings at 700 give the art-poster voice; Inter keeps the body legible and * modern; the amber counterpoint does all the pointing — selection, focus, * links' underlines, the CTA. */ @layer base { body { min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: -0.005em; font-family: var(--font-sans); font-size: var(--text-body-size); line-height: var(--text-body-lh); } /* Headings — Syne at 700, the poster voice. Syne runs wide; a touch of * negative tracking keeps it confident rather than sprawling. */ 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: 700; letter-spacing: -0.015em; /* inherit, not var(--foreground): identity themes put headings on * colored slabs (bg-primary heroes) — forcing the field ink there * breaks the slab's own foreground pairing. */ color: inherit; } code, kbd, samp, pre, [data-slot="code"], [data-slot="code-block"] { font-family: var(--font-mono); } /* Inline code — neutral chip: foreground-tint wash with foreground ink, * so it reads correctly on both the blue field and the white cards. */ :not(pre) > code { padding: 0.1em 0.35em; border-radius: calc(var(--radius) * 0.5); background: color-mix(in oklch, var(--foreground) 8%, transparent); color: var(--foreground); font-size: 0.9em; } /* Selection — the amber counterpoint, everywhere. */ ::selection { background: color-mix(in oklch, var(--primary) 45%, transparent); color: var(--foreground); } /* Links — ink follows the surface (white on the field, dark on cards); * the amber underline is the constant link signal on both. */ a { color: inherit; font-weight: 600; text-decoration-color: color-mix(in oklch, var(--primary) 70%, transparent); text-decoration-thickness: 2px; 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 — the amber ring, offset (not inset), for keyboard users. * Placed outside @layer base so it beats Tailwind's default ring utilities. */ [data-slot="button"]:focus-visible, [data-slot="input"]:focus-visible, [data-slot="textarea"]:focus-visible, [data-slot="select-trigger"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: none; } /* Buttons — confident weight; a springy press absorb suits the identity. */ [data-slot="button"] { font-weight: 600; letter-spacing: -0.005em; } /* 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 consumer density 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.92; } [data-slot="button"]:active:not(:disabled) { opacity: 0.84; transform: scale(0.98); transition: transform var(--duration-fast) var(--ease-spring-gentle), opacity var(--duration-fast) var(--ease-standard); } /* Inputs — white card panels with dark hairlines floating on the blue; * the amber focus ring is the constant. */ [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(--card-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: color-mix(in oklch, var(--card-foreground) 55%, transparent); } [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(--card-foreground) 32%, 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; }