Files
lib-theme-oat/theme.css
jules 3cd3c0ea13 lib-theme-oat: initial import (warm-consumer set, 2026-07)
Includes the 2026-07-07 UX sweep: neutral inline-code chips (accent
reserved for actions/links/focus), dark-mode card/popover lightness
lift for visible surface separation, 44px touch-target floor on
coarse pointers, card-title pinned to a named ramp role.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:35:56 +10:00

471 lines
17 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Oat — warm greige, cozy-neutral theme. Oat, driftwood, mushroom, raw linen.
*
* The thesis: a genuinely NEUTRAL, calm consumer surface that still has warmth
* and material character. The neutral is a real GREIGE mid-tone (grey-warm),
* not a pale near-white and not a drenched color field. Built for an everyday
* personal-cloud utility that should feel grounded and tactile, never loud.
*
* Escape from the "AI cream" band (L 0.840.97, warm chroma, hue 40100) is by
* DEPTH + restraint, not by picking a different hue: the body background sits at
* a noticeably lower lightness (L≈0.91) with very low warm chroma (≈0.009, hue
* ~78), so it reads as a soft grey-warm "oat" surface rather than a bright cream.
* Cards step UP to a warm near-white (L≈0.975) so the card-on-field separation
* is clearly visible and does real hierarchy work — that visible step is the
* theme's premium tell. Ink is a warm charcoal-taupe. The accent is a soft,
* muted clay-rose coral (hue ~35), spent surgically on the primary action,
* selection and focus; a muted slate-blue is the single cool counterpoint (info).
*
* Dark mode is "oats at night": a warm dark taupe-charcoal (low chroma, warm
* hue ~70, deep but not pure black and never blue-gray), cards stepping lighter
* like firelight on material, the coral brightened, dark-ink-on-bright per the
* contract's contrast pattern.
*
* Token contract: Crema v1 (create-crema-app/TOKEN_CONTRACT.md).
*/
/*
* Fonts: consuming apps load Hanken Grotesk + Fraunces + 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 when the theme is imported after other statements, so neither
* is done in this file.
*/
:root {
--font-sans: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-heading: "Fraunces", "Hanken Grotesk", Georgia, serif;
--font-mono: "JetBrains Mono", ui-monospace, 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: "Fraunces", "Hanken Grotesk", Georgia, serif;
--body-family: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
/* ── Colors ── greige mid-tone field, warm near-white cards, warm
* charcoal-taupe ink, muted clay-rose coral accent. */
/* Body field: a genuine grey-warm "oat", noticeably below cream lightness. */
--background: oklch(0.91 0.009 78);
--foreground: oklch(0.24 0.012 55);
/* Cards step UP toward warm near-white — the visible card-on-field step. */
--card: oklch(0.975 0.006 82);
--card-foreground: oklch(0.24 0.012 55);
--popover: oklch(0.98 0.005 82);
--popover-foreground: oklch(0.24 0.012 55);
/* Primary: muted clay-rose coral. Deep enough that warm-white text clears
* the 4.5:1 floor (white-on-mid-coral usually misses; this is L≈0.55). */
--primary: oklch(0.55 0.15 35);
--primary-foreground: oklch(0.99 0.01 60);
/* Secondary / muted: a soft greige a step below the field. */
--secondary: oklch(0.86 0.014 75);
--secondary-foreground: oklch(0.3 0.012 55);
--muted: oklch(0.86 0.012 78);
--muted-foreground: oklch(0.44 0.012 60);
/* Accent: a pale coral wash carrying deep-coral ink. */
--accent: oklch(0.88 0.03 32);
--accent-foreground: oklch(0.4 0.12 32);
/* Status quartet — kept clearly distinct from the muted coral primary:
* destructive is a hotter, higher-chroma true red; success sage-green;
* warning amber; info the cool slate-blue counterpoint. */
--destructive: oklch(0.55 0.21 25);
--destructive-foreground: oklch(0.99 0.01 60);
--success: oklch(0.57 0.12 150);
--success-foreground: oklch(0.14 0.04 150);
--warning: oklch(0.76 0.13 75);
--warning-foreground: oklch(0.24 0.04 75);
--info: oklch(0.52 0.12 245);
--info-foreground: oklch(0.99 0.01 60);
--border: oklch(0.24 0.012 55 / 0.14);
--input: oklch(0.24 0.012 55 / 0.14);
--ring: oklch(0.55 0.15 35 / 0.5);
/* Chart palette — cozy-neutral swatches: clay coral / sage / slate-blue /
* amber / mauve. Hues ≥60° apart, adjacent-index lightness alternated. */
--chart-1: oklch(0.62 0.13 35);
--chart-2: oklch(0.68 0.09 150);
--chart-3: oklch(0.6 0.1 245);
--chart-4: oklch(0.78 0.1 75);
--chart-5: oklch(0.7 0.07 320);
--sidebar: oklch(0.89 0.011 78);
--sidebar-foreground: oklch(0.24 0.012 55);
--sidebar-primary: oklch(0.55 0.15 35);
--sidebar-primary-foreground: oklch(0.99 0.01 60);
--sidebar-accent: oklch(0.88 0.03 32);
--sidebar-accent-foreground: oklch(0.4 0.12 32);
--sidebar-border: oklch(0.24 0.012 55 / 0.1);
--sidebar-ring: oklch(0.55 0.15 35 / 0.5);
/* Syntax (Tier 2) — warm-neutral code palette. */
--syntax-keyword: oklch(0.5 0.14 35);
--syntax-string: oklch(0.5 0.1 150);
--syntax-number: oklch(0.54 0.12 75);
--syntax-comment: oklch(0.55 0.008 78);
--syntax-function: oklch(0.5 0.12 245);
--syntax-type: oklch(0.52 0.08 200);
/* ── Chat surfaces ──
* Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is a
* filled deep-coral panel with warm-white text; assistant bubble is a
* card-like warm-white surface with a hairline border. */
--chat-user-bg: oklch(0.5 0.14 35);
--chat-user-fg: oklch(0.99 0.01 60);
--chat-assistant-bg: oklch(0.975 0.006 82);
--chat-assistant-fg: oklch(0.24 0.012 55);
--chat-assistant-border: oklch(0.24 0.012 55 / 0.12);
/* Soft-friendly radius. */
--radius: 1rem;
/* ── Motion ── calm-buoyant, base ~300ms. Springs are real, gently damped. */
--duration-fast: 160ms;
--duration-base: 300ms;
--duration-slow: 450ms;
--duration-slower: 600ms;
--duration-spring: 500ms;
--ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1);
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
--ease-spring-gentle: linear(0, 0.04 8%, 0.12 15%, 0.23 22%, 0.37 30%, 0.51 38%, 0.63 46%, 0.74 54%, 0.83 62%, 0.89 70%, 0.94 78%, 0.97 86%, 0.99 94%, 1);
--ease-spring-snappy: linear(0, 0.06 6%, 0.18 12%, 0.33 18%, 0.5 25%, 0.65 32%, 0.8 40%, 0.9 48%, 0.98 56%, 1.015 64%, 1.02 72%, 1.015 80%, 1.005 88%, 1);
--ease-spring-bouncy: linear(0, 0.08 8%, 0.22 16%, 0.4 24%, 0.58 32%, 0.75 40%, 0.88 48%, 0.98 56%, 1.04 64%, 1.06 72%, 1.04 80%, 1.01 86%, 0.995 92%, 1);
/* Emphasized moments settle with the gentle spring. */
--ease-emphasized: var(--ease-spring-gentle);
/* ── Typography ── product register, fixed rem, full role ramp.
* Warm-humanist and cozy but crisp: Fraunces headings, Hanken Grotesk body. */
--text-hero-size: 3.5rem;
--text-hero-lh: 1.05;
--text-display-size: 3rem;
--text-display-lh: 1.1;
--text-headline-size: 2rem;
--text-headline-lh: 1.2;
--text-title-size: 1.5rem;
--text-title-lh: 1.3;
--text-subtitle-size: 1.25rem;
--text-subtitle-lh: 1.5;
--text-body-size: 1.0625rem;
--text-body-lh: 1.65;
--text-label-size: 0.9375rem;
--text-label-lh: 1.25rem;
--text-caption-size: 0.8125rem;
--text-caption-lh: 1.125rem;
/* ── Elevation ── soft warm-grey diffuse shadows, derived from the warm
* ink at low alpha. Gentle, tactile, never a hard drop. */
--elevation-0: none;
--elevation-1: 0 1px 2px oklch(0.24 0.012 55 / 0.05);
--elevation-2: 0 1px 3px oklch(0.24 0.012 55 / 0.07), 0 1px 2px oklch(0.24 0.012 55 / 0.04);
--elevation-3: 0 4px 12px -3px oklch(0.24 0.012 55 / 0.08), 0 2px 6px -3px oklch(0.24 0.012 55 / 0.05);
--elevation-4: 0 12px 28px -6px oklch(0.24 0.012 55 / 0.1), 0 6px 12px -6px oklch(0.24 0.012 55 / 0.05);
--elevation-5: 0 24px 48px -10px oklch(0.24 0.012 55 / 0.16);
--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 — "oats at night". Warm dark taupe-charcoal (L≈0.20, hue ~70), deep
* but not pure black and not blue-gray. Cards step LIGHTER (firelight on
* material). Coral brightens; status foregrounds go dark-ink-on-bright.
*/
.dark {
--background: oklch(0.2 0.008 70);
--foreground: oklch(0.92 0.01 82);
--card: oklch(0.26 0.009 70);
--card-foreground: oklch(0.92 0.01 82);
--popover: oklch(0.275 0.009 70);
--popover-foreground: oklch(0.92 0.01 82);
--primary: oklch(0.68 0.14 38);
--primary-foreground: oklch(0.2 0.03 38);
--secondary: oklch(0.28 0.008 70);
--secondary-foreground: oklch(0.9 0.01 82);
--muted: oklch(0.28 0.008 70);
--muted-foreground: oklch(0.71 0.011 80);
--accent: oklch(0.32 0.05 35);
--accent-foreground: oklch(0.85 0.08 38);
--destructive: oklch(0.65 0.2 28);
--destructive-foreground: oklch(0.18 0.03 28);
--success: oklch(0.68 0.14 150);
--success-foreground: oklch(0.18 0.03 150);
--warning: oklch(0.8 0.13 75);
--warning-foreground: oklch(0.22 0.04 75);
--info: oklch(0.7 0.12 245);
--info-foreground: oklch(0.16 0.03 245);
--border: oklch(0.92 0.01 82 / 0.12);
--input: oklch(0.92 0.01 82 / 0.12);
--ring: oklch(0.68 0.14 38 / 0.5);
--chart-1: oklch(0.72 0.13 38);
--chart-2: oklch(0.74 0.09 150);
--chart-3: oklch(0.7 0.1 245);
--chart-4: oklch(0.82 0.1 75);
--chart-5: oklch(0.76 0.07 320);
--sidebar: oklch(0.22 0.008 70);
--sidebar-foreground: oklch(0.92 0.01 82);
--sidebar-primary: oklch(0.68 0.14 38);
--sidebar-primary-foreground: oklch(0.2 0.03 38);
--sidebar-accent: oklch(0.32 0.05 35);
--sidebar-accent-foreground: oklch(0.85 0.08 38);
--sidebar-border: oklch(0.92 0.01 82 / 0.08);
--sidebar-ring: oklch(0.68 0.14 38 / 0.5);
--syntax-keyword: oklch(0.75 0.13 38);
--syntax-string: oklch(0.74 0.12 150);
--syntax-number: oklch(0.8 0.12 75);
--syntax-comment: oklch(0.55 0.008 78);
--syntax-function: oklch(0.72 0.12 245);
--syntax-type: oklch(0.72 0.08 200);
/* ── Chat surfaces (dark) ── */
--chat-user-bg: oklch(0.55 0.15 38);
--chat-user-fg: oklch(0.99 0.01 60);
--chat-assistant-bg: oklch(0.26 0.009 70);
--chat-assistant-fg: oklch(0.92 0.01 82);
--chat-assistant-border: oklch(0.92 0.01 82 / 0.12);
/* Deep warm shadows for the night palette. */
--elevation-1: 0 1px 2px oklch(0 0 0 / 0.3);
--elevation-2: 0 1px 3px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.25);
--elevation-3: 0 4px 12px -3px oklch(0 0 0 / 0.4), 0 2px 6px -3px oklch(0 0 0 / 0.28);
--elevation-4: 0 12px 28px -6px oklch(0 0 0 / 0.45), 0 6px 12px -6px oklch(0 0 0 / 0.3);
--elevation-5: 0 24px 48px -10px oklch(0 0 0 / 0.55);
}
/*
* @layer base — Oat's cozy-neutral philosophy.
*
* No glass, no brutalist offsets. Warm-humanist type, soft-round corners,
* gentle diffuse shadows. Cards sit on the greige field with a hairline border
* AND a visible lightness step so hierarchy reads even before the shadow does.
*/
@layer base {
body {
min-height: 100vh;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
letter-spacing: -0.006em;
font-family: var(--font-sans);
font-size: var(--text-body-size);
line-height: var(--text-body-lh);
}
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.012em;
color: var(--foreground);
}
code, kbd, samp, pre,
[data-slot="code"],
[data-slot="code-block"] {
font-family: var(--font-mono);
}
/* Inline code — neutral ink on a warm tinted chip. Coral stays reserved
* for actions, links and focus so the accent keeps pointing at one thing. */
:not(pre) > code {
padding: 0.1em 0.35em;
border-radius: calc(var(--radius) * 0.4);
background: color-mix(in oklch, var(--foreground) 7%, transparent);
color: var(--foreground);
font-size: 0.9em;
}
/* Selection — soft coral wash. */
::selection {
background: color-mix(in oklch, var(--primary) 20%, transparent);
color: var(--foreground);
}
/* Anchor links — coral, underline warms on hover. */
a {
color: var(--primary);
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);
}
/* Card & overlay surfaces — soft warm-grey diffuse shadow so surfaces feel
* lifted off the oat field, tactile rather than hard-edged. */
[data-slot="card"],
[data-slot="popover-content"],
[data-slot="dropdown-menu-content"],
[data-slot="context-menu-content"],
[data-slot="menubar-content"],
[data-slot="hover-card-content"],
[data-slot="select-content"],
[data-slot="combobox-content"],
[data-slot="command"],
[data-slot="tooltip-content"],
[data-slot="sheet-content"],
[data-slot="dialog-content"],
[data-slot="alert-dialog-content"],
[data-slot="drawer-content"] {
border: var(--border-width-base) solid var(--border);
box-shadow: var(--elevation-3);
}
.dark [data-slot="card"],
.dark [data-slot="popover-content"],
.dark [data-slot="dropdown-menu-content"],
.dark [data-slot="context-menu-content"],
.dark [data-slot="menubar-content"],
.dark [data-slot="hover-card-content"],
.dark [data-slot="select-content"],
.dark [data-slot="combobox-content"],
.dark [data-slot="command"],
.dark [data-slot="tooltip-content"],
.dark [data-slot="sheet-content"],
.dark [data-slot="dialog-content"],
.dark [data-slot="alert-dialog-content"],
.dark [data-slot="drawer-content"] {
box-shadow: var(--elevation-4);
}
[data-slot="button"] {
font-weight: 500;
}
[data-slot="sidebar"] {
background: var(--sidebar);
border-right: var(--border-width-base) solid var(--sidebar-border);
}
}
/*
* Unlayered control tuning — placed outside @layer base so it beats Tailwind's
* default utility classes shipped with shadcn primitives. Oat's controls are
* comfortable with soft-round corners and a flush coral focus ring rather than
* Tailwind's 3px halo. Inputs are ≥44px everywhere; buttons keep their density
* ladder under a mouse and clear the 44px touch floor on coarse pointers.
*/
@media (pointer: coarse) {
[data-slot="button"] {
min-height: 2.75rem;
min-width: 2.75rem;
}
}
[data-slot="button"]:hover:not(:disabled) {
opacity: 0.9;
}
[data-slot="button"]:active:not(:disabled) {
opacity: 0.82;
transform: scale(0.99);
}
[data-slot="button"]:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
box-shadow: none;
}
[data-slot="input"],
[data-slot="textarea"],
[data-slot="select-trigger"] {
min-height: 2.75rem;
padding-inline: 1rem;
font-size: 0.9375rem;
background: var(--card);
border: 1px 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="textarea"] {
min-height: 6.25rem;
padding-block: 0.75rem;
line-height: 1.55;
resize: vertical;
}
[data-slot="input"]::placeholder,
[data-slot="textarea"]::placeholder {
color: var(--muted-foreground);
opacity: 0.7;
}
[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) 25%, transparent);
}
[data-slot="input"]:focus,
[data-slot="input"]:focus-visible,
[data-slot="textarea"]:focus,
[data-slot="textarea"]:focus-visible,
[data-slot="select-trigger"]:focus,
[data-slot="select-trigger"]:focus-visible {
border-color: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
outline: none;
}
/* ─── Cards ───
* Warm near-white surface a clear step above the oat field, soft-round 1rem
* corners, hairline border, gentle lift on hover. */
[data-slot="card"] {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
transition:
border-color var(--duration-base) var(--ease-standard),
box-shadow var(--duration-base) var(--ease-standard);
}
[data-slot="card"]:hover {
box-shadow: var(--elevation-4);
}
[data-slot="card-title"] {
font-family: var(--font-heading);
font-weight: 600;
letter-spacing: -0.012em;
font-size: var(--text-title-size);
line-height: var(--text-title-lh);
}
[data-slot="card-description"] {
color: var(--muted-foreground);
font-size: 0.9375rem;
}