lib-theme-siena: 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>
This commit is contained in:
jules
2026-07-07 22:35:56 +10:00
commit 8f6afab89e
2 changed files with 439 additions and 0 deletions

392
theme.css Normal file
View File

@@ -0,0 +1,392 @@
/*
* Siena — drenched Mediterranean courtyard. A Sienese piazza at five in the
* afternoon: the background is a real terracotta wall, not a tinted white;
* cards are sun-bleached plaster panels resting ON that wall; the ink is a
* deep warm olive-brown that never goes black. Warmth lives in the surface
* itself — hierarchy is done by material (plaster on clay), not by shadow
* theatrics or balloon corners.
*
* Palette rationale: burnt sienna carries the primary action (deep enough for
* plaster-white labels at 6.9:1); worn-stone secondaries and an ochre warning
* stay inside the courtyard's heat; one cool note — a Mediterranean blue — is
* spent on accent and info so the warmth has something to push against. Dark
* mode is the same courtyard at dusk: umber-brown surfaces (never blue-gray)
* with the terracotta turned into glow.
*
* Token contract matches lib-theme-pristine/theme.css.
*/
/*
* Fonts: consuming apps load Fraunces + Albert Sans + JetBrains Mono at the
* top of their entry CSS via the Google Fonts URL documented in this theme's
* README. No @import here — PostCSS ordering forbids it — and no URL smuggled
* in comments for build scripts to lift.
*/
:root {
--font-sans: "Albert Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-heading: "Fraunces", 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. Mirror --font-heading/--font-sans. */
--heading-family: "Fraunces", Georgia, serif;
--body-family: "Albert Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
/* ── Colors ── terracotta field, plaster cards, olive-brown ink.
* The background commits: L 0.84, chroma 0.055 at hue 55 — a painted
* wall, not the pale cream band. */
--background: oklch(0.84 0.055 55);
--foreground: oklch(0.24 0.03 60);
--card: oklch(0.96 0.018 75);
--card-foreground: oklch(0.24 0.03 60);
--popover: oklch(0.97 0.015 75);
--popover-foreground: oklch(0.24 0.03 60);
/* Burnt sienna — deep enough to carry plaster-white labels (6.9:1). */
--primary: oklch(0.46 0.13 38);
--primary-foreground: oklch(0.97 0.02 75);
/* Worn stone — a step off the wall, still warm. */
--secondary: oklch(0.9 0.03 68);
--secondary-foreground: oklch(0.28 0.035 55);
--muted: oklch(0.89 0.035 65);
--muted-foreground: oklch(0.38 0.045 55);
/* The one cool note — washed Mediterranean blue. */
--accent: oklch(0.88 0.04 230);
--accent-foreground: oklch(0.3 0.08 240);
--destructive: oklch(0.48 0.18 28);
--destructive-foreground: oklch(0.97 0.02 75);
/* Olive success — courtyard green, dark olive ink on top. */
--success: oklch(0.62 0.11 130);
--success-foreground: oklch(0.18 0.05 135);
/* Ochre warning — sun pigment, umber ink label. */
--warning: oklch(0.76 0.13 80);
--warning-foreground: oklch(0.24 0.06 80);
/* Info shares the accent's Mediterranean blue, deepened for plaster text. */
--info: oklch(0.46 0.09 245);
--info-foreground: oklch(0.97 0.02 75);
/* Hairlines are ink washes — on a colored wall they need a little more
* presence than they would on white. */
--border: oklch(0.24 0.03 60 / 0.2);
--input: oklch(0.24 0.03 60 / 0.2);
--ring: oklch(0.46 0.13 38 / 0.5);
/* Chart palette — terracotta / olive / sea blue / ochre / plum.
* Hues ≥60° apart, adjacent lightness varied. */
--chart-1: oklch(0.58 0.13 40);
--chart-2: oklch(0.68 0.1 125);
--chart-3: oklch(0.55 0.1 240);
--chart-4: oklch(0.75 0.12 85);
--chart-5: oklch(0.62 0.09 320);
/* Sidebar — a deeper stripe of the same wall, in shadow. */
--sidebar: oklch(0.8 0.065 50);
--sidebar-foreground: oklch(0.24 0.03 60);
--sidebar-primary: oklch(0.46 0.13 38);
--sidebar-primary-foreground: oklch(0.97 0.02 75);
--sidebar-accent: oklch(0.86 0.05 55);
--sidebar-accent-foreground: oklch(0.38 0.12 38);
--sidebar-border: oklch(0.24 0.03 60 / 0.16);
--sidebar-ring: oklch(0.46 0.13 38 / 0.5);
--syntax-keyword: oklch(0.44 0.13 38);
--syntax-string: oklch(0.46 0.09 135);
--syntax-number: oklch(0.5 0.12 60);
--syntax-comment: oklch(0.5 0.03 60);
--syntax-function: oklch(0.44 0.1 245);
--syntax-type: oklch(0.46 0.07 195);
/* ── Chat surfaces ──
* Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. User
* bubble is filled burnt sienna with plaster text; assistant bubble is
* a plaster card with an ink hairline. */
--chat-user-bg: oklch(0.44 0.13 38);
--chat-user-fg: oklch(0.97 0.02 75);
--chat-assistant-bg: oklch(0.96 0.018 75);
--chat-assistant-fg: oklch(0.24 0.03 60);
--chat-assistant-border: oklch(0.24 0.03 60 / 0.16);
/* Modest, honest corners — softness comes from color, not radius. */
--radius: 0.75rem;
/* ── Motion ── settled and unhurried, still product-fast. */
--duration-fast: 130ms;
--duration-base: 300ms;
--duration-slow: 420ms;
--duration-slower: 560ms;
--duration-spring: 340ms;
--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-emphasized: cubic-bezier(0.3, 0, 0.15, 1);
/* Calm theme — springs alias to standard easings rather than bounce.
* Personality lives in the values, never in absence. */
--ease-spring-gentle: var(--ease-standard);
--ease-spring-snappy: var(--ease-decelerate);
--ease-spring-bouncy: var(--ease-emphasized);
/* ── Typography ── product register: fixed rem sizes, full ramp.
* Fraunces carries the display voice; Albert Sans does the work. */
--text-hero-size: 3.5rem;
--text-hero-lh: 3.75rem;
--text-display-size: 3rem;
--text-display-lh: 3.25rem;
--text-headline-size: 2rem;
--text-headline-lh: 2.375rem;
--text-title-size: 1.5rem;
--text-title-lh: 1.875rem;
--text-subtitle-size: 1.1875rem;
--text-subtitle-lh: 1.75rem;
--text-body-size: 1.0625rem;
--text-body-lh: 1.625rem;
--text-label-size: 0.9375rem;
--text-label-lh: 1.25rem;
--text-caption-size: 0.8125rem;
--text-caption-lh: 1.125rem;
/* ── Elevation ── warm umber shadows, low-key: things rest on the wall,
* they don't float. Never pure black. */
--elevation-0: none;
--elevation-1: 0 1px 2px oklch(0.24 0.03 60 / 0.1);
--elevation-2: 0 1px 3px oklch(0.24 0.03 60 / 0.12), 0 1px 2px oklch(0.24 0.03 60 / 0.08);
--elevation-3: 0 4px 10px -2px oklch(0.24 0.03 60 / 0.14), 0 2px 4px -2px oklch(0.24 0.03 60 / 0.08);
--elevation-4: 0 12px 28px -6px oklch(0.24 0.03 60 / 0.18), 0 4px 10px -4px oklch(0.24 0.03 60 / 0.1);
--elevation-5: 0 24px 48px -12px oklch(0.24 0.03 60 / 0.26);
--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 — dusk in the same courtyard. Deep umber-brown surfaces (never
* blue-gray); the terracotta becomes glow and takes dark umber labels, since
* dark-ink-on-bright beats white-on-mid-tone.
*/
.dark {
--background: oklch(0.22 0.02 55);
--foreground: oklch(0.93 0.02 75);
--card: oklch(0.28 0.022 55);
--card-foreground: oklch(0.93 0.02 75);
--popover: oklch(0.295 0.024 55);
--popover-foreground: oklch(0.93 0.02 75);
--primary: oklch(0.7 0.14 45);
--primary-foreground: oklch(0.16 0.03 45);
--secondary: oklch(0.31 0.025 55);
--secondary-foreground: oklch(0.9 0.02 75);
--muted: oklch(0.3 0.025 55);
--muted-foreground: oklch(0.72 0.03 70);
--accent: oklch(0.3 0.05 240);
--accent-foreground: oklch(0.85 0.06 235);
--destructive: oklch(0.64 0.19 30);
--destructive-foreground: oklch(0.14 0.03 28);
--success: oklch(0.7 0.12 130);
--success-foreground: oklch(0.14 0.04 135);
--warning: oklch(0.78 0.13 80);
--warning-foreground: oklch(0.2 0.05 80);
--info: oklch(0.7 0.1 240);
--info-foreground: oklch(0.14 0.03 245);
--border: oklch(0.93 0.02 75 / 0.12);
--input: oklch(0.93 0.02 75 / 0.12);
--ring: oklch(0.7 0.14 45 / 0.5);
--chart-1: oklch(0.68 0.13 40);
--chart-2: oklch(0.75 0.1 125);
--chart-3: oklch(0.68 0.1 240);
--chart-4: oklch(0.8 0.12 85);
--chart-5: oklch(0.72 0.09 320);
--sidebar: oklch(0.2 0.02 55);
--sidebar-foreground: oklch(0.93 0.02 75);
--sidebar-primary: oklch(0.7 0.14 45);
--sidebar-primary-foreground: oklch(0.16 0.03 45);
--sidebar-accent: oklch(0.32 0.04 45);
--sidebar-accent-foreground: oklch(0.88 0.07 50);
--sidebar-border: oklch(0.93 0.02 75 / 0.1);
--sidebar-ring: oklch(0.7 0.14 45 / 0.5);
--syntax-keyword: oklch(0.75 0.13 45);
--syntax-string: oklch(0.76 0.11 135);
--syntax-number: oklch(0.8 0.12 65);
--syntax-comment: oklch(0.6 0.03 65);
--syntax-function: oklch(0.74 0.1 240);
--syntax-type: oklch(0.75 0.07 195);
/* ── Chat surfaces (dark) ── */
--chat-user-bg: oklch(0.48 0.13 40);
--chat-user-fg: oklch(0.97 0.02 75);
--chat-assistant-bg: oklch(0.29 0.023 55);
--chat-assistant-fg: oklch(0.93 0.02 75);
--chat-assistant-border: oklch(0.93 0.02 75 / 0.12);
/* Dusk shadows — deeper umber, never blue-black. */
--elevation-1: 0 1px 2px oklch(0.1 0.012 55 / 0.4);
--elevation-2: 0 1px 3px oklch(0.1 0.012 55 / 0.45), 0 1px 2px oklch(0.1 0.012 55 / 0.3);
--elevation-3: 0 4px 10px -2px oklch(0.1 0.012 55 / 0.45), 0 2px 4px -2px oklch(0.1 0.012 55 / 0.3);
--elevation-4: 0 12px 28px -6px oklch(0.1 0.012 55 / 0.5), 0 4px 10px -4px oklch(0.1 0.012 55 / 0.3);
--elevation-5: 0 24px 48px -12px oklch(0.1 0.012 55 / 0.6);
}
/*
* @layer base — Siena's material philosophy.
*
* Plaster panels on a painted wall: cards get a hairline ink border and a
* low warm shadow (they rest, they don't float). Fraunces carries headings;
* everything else is quiet Albert Sans on olive-brown ink.
*/
@layer base {
body {
min-height: 100vh;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
letter-spacing: -0.011em;
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.01em;
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 chip; sienna 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.5);
background: color-mix(in oklch, var(--foreground) 7%, transparent);
color: var(--foreground);
font-size: 0.9em;
}
/* Selection — sun-warmed sienna wash. */
::selection {
background: color-mix(in oklch, var(--primary) 24%, transparent);
color: var(--foreground);
}
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);
}
/* Plaster panels — hairline ink border + resting warm shadow. Border
* AND shadow both stay light so surfaces read as material, not chrome. */
[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-2);
}
[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="tooltip-content"] {
box-shadow: var(--elevation-3);
}
[data-slot="sheet-content"],
[data-slot="dialog-content"],
[data-slot="alert-dialog-content"],
[data-slot="drawer-content"] {
box-shadow: var(--elevation-4);
}
[data-slot="button"] {
font-weight: 500;
}
[data-slot="button"]:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
[data-slot="sidebar"] {
background: var(--sidebar);
border-right: var(--border-width-base) solid var(--sidebar-border);
}
}
/*
* Unlayered control tuning — outside @layer base so it beats Tailwind's
* utility defaults shipped with shadcn primitives.
*/
/* 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 its density; 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;
}
}