lib-theme-flint: initial import (calm-pro/dense-utility set, 2026-07)
One of four divergent candidates for the operator/console theme family (successor to Skyrise for developer-product screens). Dense/pro type register, keyboard-first focus treatment, tabular numerals, coarse-pointer 44px touch floor, neutral code chips, dark card separation per house sweep. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
423
theme.css
Normal file
423
theme.css
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Flint — instrument panel.
|
||||
*
|
||||
* Braun-era workshop calm with one signal spark. The whole light surface is a
|
||||
* warm-stone gray (hue ~80, chroma 0.004 — clearly warmer than graphite's
|
||||
* chroma-0, far quieter than any cream), with clean white cards and a deep
|
||||
* graphite-umber ink (hue ~60). ONE accent: signal orange (hue ~48) — the
|
||||
* machine's indicator lamp — spent only on the primary action, selection,
|
||||
* focus, and the live/recording dot. It carries dark umber ink on top
|
||||
* (bright-swatch/dark-ink) so it lands high above the contrast floor.
|
||||
*
|
||||
* Status hues are held clearly apart from the lamp: destructive red is
|
||||
* DEEPENED at hue 25 so it never blurs into the orange at 48; warning sits at
|
||||
* ochre hue 85, a distinct earthy yellow, never a second orange; success green
|
||||
* 150, info blue 248.
|
||||
*
|
||||
* Dark mode is the panel at night: dark warm graphite (hue ~60, low chroma,
|
||||
* never blue), cards a full lightness step above the field (≥0.05 L), and the
|
||||
* same signal orange glowing luminous with dark ink.
|
||||
*
|
||||
* Type: Archivo for headings (grotesk with DIN-instrument character, weight
|
||||
* 600), Inter for body, JetBrains Mono for code. Dense/pro register — body
|
||||
* 0.9375rem, fixed rem, full role ramp. Radius is a machined, softly
|
||||
* chamfered 0.625rem. Shadows are crisp, low, and tight. Motion is mechanical
|
||||
* and quick (120/220/320/450ms); springs alias to the standard eases — a good
|
||||
* tool clicks, it doesn't bounce.
|
||||
*
|
||||
* Token contract matches lib-theme-caffe-florian/theme.css (Crema v1).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fonts: consuming apps load Archivo + 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: "Archivo", "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: "Archivo", "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
--body-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
|
||||
/* ── Colors ── warm-stone gray field, white cards, graphite-umber ink,
|
||||
* one signal-orange indicator lamp. */
|
||||
--background: oklch(0.945 0.004 80);
|
||||
--foreground: oklch(0.22 0.008 60);
|
||||
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.22 0.008 60);
|
||||
|
||||
--popover: oklch(0.99 0.002 80);
|
||||
--popover-foreground: oklch(0.22 0.008 60);
|
||||
|
||||
/* Primary — the indicator lamp. Signal orange at hue 48 (pushed off the
|
||||
* destructive red at 25), bright enough to glow, with near-black umber ink
|
||||
* on top (bright-swatch/dark-ink) — crisp, never orange-on-orange. */
|
||||
--primary: oklch(0.66 0.18 48);
|
||||
--primary-foreground: oklch(0.15 0.025 48);
|
||||
|
||||
--secondary: oklch(0.915 0.005 75);
|
||||
--secondary-foreground: oklch(0.3 0.008 60);
|
||||
|
||||
--muted: oklch(0.915 0.005 75);
|
||||
--muted-foreground: oklch(0.45 0.01 60);
|
||||
|
||||
/* Accent — the lamp as a hover/selection tint: a faint warm-orange wash
|
||||
* with deep burnt-orange ink, not a second competing fill. */
|
||||
--accent: oklch(0.92 0.035 55);
|
||||
--accent-foreground: oklch(0.42 0.11 45);
|
||||
|
||||
/* ── Status ── held clearly apart from the signal orange (48). Destructive
|
||||
* red is deepened at hue 25 with a light label; warning is ochre at hue 85
|
||||
* (earthy yellow, never a second orange) with dark ink; success/info follow
|
||||
* the bright-swatch/dark-ink pattern where legible. */
|
||||
--destructive: oklch(0.52 0.2 25);
|
||||
--destructive-foreground: oklch(0.98 0.01 25);
|
||||
--success: oklch(0.62 0.14 150);
|
||||
--success-foreground: oklch(0.17 0.03 150);
|
||||
--warning: oklch(0.72 0.14 85);
|
||||
--warning-foreground: oklch(0.24 0.05 85);
|
||||
--info: oklch(0.54 0.13 248);
|
||||
--info-foreground: oklch(0.98 0.01 248);
|
||||
|
||||
--border: oklch(0.22 0.008 60 / 0.12);
|
||||
--input: oklch(0.22 0.008 60 / 0.14);
|
||||
--ring: oklch(0.66 0.18 48 / 0.6);
|
||||
|
||||
/* Chart palette — signal-orange lead, then restrained spaced hues:
|
||||
* blue / teal / violet / green. Adjacent hues ≥60° apart, adjacent
|
||||
* lightness varied. */
|
||||
--chart-1: oklch(0.68 0.17 48);
|
||||
--chart-2: oklch(0.56 0.13 248);
|
||||
--chart-3: oklch(0.66 0.1 180);
|
||||
--chart-4: oklch(0.54 0.14 300);
|
||||
--chart-5: oklch(0.68 0.13 130);
|
||||
|
||||
--sidebar: oklch(0.925 0.005 78);
|
||||
--sidebar-foreground: oklch(0.22 0.008 60);
|
||||
--sidebar-primary: oklch(0.66 0.18 48);
|
||||
--sidebar-primary-foreground: oklch(0.15 0.025 48);
|
||||
--sidebar-accent: oklch(0.9 0.035 55);
|
||||
--sidebar-accent-foreground: oklch(0.42 0.11 45);
|
||||
--sidebar-border: oklch(0.22 0.008 60 / 0.1);
|
||||
--sidebar-ring: oklch(0.66 0.18 48 / 0.6);
|
||||
|
||||
/* Syntax — muted-precise warm-neutral base; the number readout gets the
|
||||
* deep signal hue, everything else stays restrained. */
|
||||
--syntax-keyword: oklch(0.5 0.12 300);
|
||||
--syntax-string: oklch(0.5 0.11 150);
|
||||
--syntax-number: oklch(0.55 0.14 48);
|
||||
--syntax-comment: oklch(0.55 0.008 60);
|
||||
--syntax-function: oklch(0.5 0.13 248);
|
||||
--syntax-type: oklch(0.52 0.09 190);
|
||||
|
||||
/* ── Chat surfaces ──
|
||||
* Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. User bubble
|
||||
* is a deep warm-graphite panel with light text (neutral, so the orange
|
||||
* stays scarce); assistant bubble is a clean card with a hairline border. */
|
||||
--chat-user-bg: oklch(0.28 0.01 60);
|
||||
--chat-user-fg: oklch(0.96 0.004 80);
|
||||
--chat-assistant-bg: oklch(1 0 0);
|
||||
--chat-assistant-fg: oklch(0.22 0.008 60);
|
||||
--chat-assistant-border: oklch(0.22 0.008 60 / 0.12);
|
||||
|
||||
/* Machined, softly chamfered. */
|
||||
--radius: 0.625rem;
|
||||
|
||||
/* ── Motion ── mechanical and quick; a good tool clicks, it doesn't
|
||||
* bounce. Springs alias to the standard eases. */
|
||||
--duration-fast: 120ms;
|
||||
--duration-base: 220ms;
|
||||
--duration-slow: 320ms;
|
||||
--duration-slower: 450ms;
|
||||
--duration-spring: 220ms;
|
||||
|
||||
--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, full role ramp. */
|
||||
--text-hero-size: 3rem;
|
||||
--text-hero-lh: 1.05;
|
||||
--text-display-size: 2.25rem;
|
||||
--text-display-lh: 1.1;
|
||||
--text-headline-size: 1.625rem;
|
||||
--text-headline-lh: 1.25;
|
||||
--text-title-size: 1.25rem;
|
||||
--text-title-lh: 1.3;
|
||||
--text-subtitle-size: 1.0625rem;
|
||||
--text-subtitle-lh: 1.4;
|
||||
--text-body-size: 0.9375rem;
|
||||
--text-body-lh: 1.5;
|
||||
--text-label-size: 0.8125rem;
|
||||
--text-label-lh: 1.125rem;
|
||||
--text-caption-size: 0.75rem;
|
||||
--text-caption-lh: 1rem;
|
||||
|
||||
/* ── Elevation ── crisp, low, machined: small offsets, tight blur. */
|
||||
--elevation-0: none;
|
||||
--elevation-1: 0 1px 1px oklch(0.22 0.008 60 / 0.07);
|
||||
--elevation-2: 0 1px 2px oklch(0.22 0.008 60 / 0.08), 0 1px 1px oklch(0.22 0.008 60 / 0.05);
|
||||
--elevation-3: 0 2px 6px -1px oklch(0.22 0.008 60 / 0.1), 0 1px 2px -1px oklch(0.22 0.008 60 / 0.06);
|
||||
--elevation-4: 0 8px 16px -4px oklch(0.22 0.008 60 / 0.12), 0 2px 4px -2px oklch(0.22 0.008 60 / 0.06);
|
||||
--elevation-5: 0 14px 28px -6px oklch(0.22 0.008 60 / 0.18);
|
||||
|
||||
--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 panel at night. Dark warm graphite (hue ~60, low chroma,
|
||||
* never blue), cards a full step above the field, popover a step above card
|
||||
* and capped below --muted; the signal orange glows luminous with dark ink.
|
||||
*/
|
||||
.dark {
|
||||
--background: oklch(0.2 0.006 60);
|
||||
--foreground: oklch(0.93 0.005 75);
|
||||
|
||||
--card: oklch(0.26 0.007 60);
|
||||
--card-foreground: oklch(0.93 0.005 75);
|
||||
|
||||
--popover: oklch(0.28 0.007 60);
|
||||
--popover-foreground: oklch(0.93 0.005 75);
|
||||
|
||||
--primary: oklch(0.72 0.185 48);
|
||||
--primary-foreground: oklch(0.15 0.025 48);
|
||||
|
||||
--secondary: oklch(0.29 0.007 60);
|
||||
--secondary-foreground: oklch(0.9 0.005 75);
|
||||
|
||||
--muted: oklch(0.3 0.007 60);
|
||||
--muted-foreground: oklch(0.72 0.01 70);
|
||||
|
||||
--accent: oklch(0.32 0.05 48);
|
||||
--accent-foreground: oklch(0.85 0.11 55);
|
||||
|
||||
--destructive: oklch(0.56 0.2 25);
|
||||
--destructive-foreground: oklch(0.98 0.01 25);
|
||||
--success: oklch(0.7 0.14 150);
|
||||
--success-foreground: oklch(0.17 0.03 150);
|
||||
--warning: oklch(0.78 0.13 85);
|
||||
--warning-foreground: oklch(0.24 0.05 85);
|
||||
--info: oklch(0.68 0.13 248);
|
||||
--info-foreground: oklch(0.16 0.03 248);
|
||||
|
||||
--border: oklch(0.93 0.005 75 / 0.12);
|
||||
--input: oklch(0.93 0.005 75 / 0.14);
|
||||
--ring: oklch(0.72 0.185 48 / 0.6);
|
||||
|
||||
--chart-1: oklch(0.74 0.17 48);
|
||||
--chart-2: oklch(0.66 0.13 248);
|
||||
--chart-3: oklch(0.72 0.1 180);
|
||||
--chart-4: oklch(0.64 0.14 300);
|
||||
--chart-5: oklch(0.74 0.13 130);
|
||||
|
||||
--sidebar: oklch(0.22 0.007 60);
|
||||
--sidebar-foreground: oklch(0.93 0.005 75);
|
||||
--sidebar-primary: oklch(0.72 0.185 48);
|
||||
--sidebar-primary-foreground: oklch(0.15 0.025 48);
|
||||
--sidebar-accent: oklch(0.32 0.05 48);
|
||||
--sidebar-accent-foreground: oklch(0.85 0.11 55);
|
||||
--sidebar-border: oklch(0.93 0.005 75 / 0.09);
|
||||
--sidebar-ring: oklch(0.72 0.185 48 / 0.6);
|
||||
|
||||
--syntax-keyword: oklch(0.72 0.12 300);
|
||||
--syntax-string: oklch(0.74 0.12 150);
|
||||
--syntax-number: oklch(0.76 0.15 48);
|
||||
--syntax-comment: oklch(0.6 0.008 65);
|
||||
--syntax-function: oklch(0.72 0.13 248);
|
||||
--syntax-type: oklch(0.72 0.09 190);
|
||||
|
||||
/* ── Chat surfaces (dark) ── */
|
||||
--chat-user-bg: oklch(0.34 0.008 60);
|
||||
--chat-user-fg: oklch(0.96 0.004 80);
|
||||
--chat-assistant-bg: oklch(0.26 0.007 60);
|
||||
--chat-assistant-fg: oklch(0.93 0.005 75);
|
||||
--chat-assistant-border: oklch(0.93 0.005 75 / 0.12);
|
||||
|
||||
--elevation-1: 0 1px 1px oklch(0 0 0 / 0.32);
|
||||
--elevation-2: 0 1px 2px oklch(0 0 0 / 0.4), 0 1px 1px oklch(0 0 0 / 0.25);
|
||||
--elevation-3: 0 2px 6px -1px oklch(0 0 0 / 0.42), 0 1px 2px -1px oklch(0 0 0 / 0.25);
|
||||
--elevation-4: 0 8px 16px -4px oklch(0 0 0 / 0.46), 0 2px 4px -2px oklch(0 0 0 / 0.25);
|
||||
--elevation-5: 0 14px 28px -6px oklch(0 0 0 / 0.55);
|
||||
}
|
||||
|
||||
/*
|
||||
* @layer base — Flint's instrument-panel philosophy.
|
||||
*
|
||||
* No glass, no flourish. DIN-flavored grotesk headings, calm warm-neutral
|
||||
* surfaces hairline-separated, aligned digits everywhere numbers live, and the
|
||||
* signal-orange lamp reserved for focus, selection, and the primary action.
|
||||
* Everything else stays quiet and out of the way.
|
||||
*/
|
||||
@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 — Archivo, machined and firm. */
|
||||
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);
|
||||
}
|
||||
|
||||
code, kbd, samp, pre,
|
||||
[data-slot="code"],
|
||||
[data-slot="code-block"] {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* Inline code — warm-neutral chip. */
|
||||
: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;
|
||||
}
|
||||
|
||||
/* Instrument readouts — aligned digits wherever numbers stack. */
|
||||
[data-slot="table"],
|
||||
.num {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Selection — the signal lamp. */
|
||||
::selection {
|
||||
background: color-mix(in oklch, var(--primary) 30%, transparent);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Links — signal-tinted ink, underline-on-hover. */
|
||||
a {
|
||||
color: color-mix(in oklch, var(--primary) 65%, 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 Flint signature. Buttons get a crisp,
|
||||
* always-visible 2px signal-orange outline with 2px offset; inputs get a flush
|
||||
* 1px ring + border-color change (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, mechanical-fast. */
|
||||
[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 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 — clean card surface, hairline border, signal 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(--border);
|
||||
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) 24%, 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;
|
||||
}
|
||||
Reference in New Issue
Block a user