Files
lib-theme-vermilion/theme.css
jules b44532665f lib-theme-vermilion: initial import (bold/identity-forward set, 2026-07)
One of four divergent candidates for the bold consumer theme family
(committed saturated color at 30-60% surface coverage, strong display
type). Includes the post-diverge fixes: heading color:inherit so brand
slabs keep their foreground pairing, plus per-theme refinements.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 23:20:55 +10:00

430 lines
16 KiB
CSS
Raw 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.

/*
* Vermilion — poster chrome.
*
* A bold, identity-forward consumer theme. One hot vermilion red-orange is THE
* brand, and it is carried by the CHROME — the primary action, hero panels,
* the entire sidebar, selection — in big committed slabs, editorial-poster
* style. Roughly 3040% of a typical screen is drenched vermilion. The content
* well stays out of the fight: warm paper with near-black warm ink, so the
* poster color reads as identity, not noise. Massive condensed display type
* (Anton) is the second half of the voice; the vermilion and the type do the
* pointing together.
*
* Destructive is deliberately NOT a sibling of the brand: pulled to a deeper
* crimson (hue ~15, L≈0.48, light label) so a destructive button and a primary
* button never read as the same family.
*
* Dark mode is the poster at night: near-black warm charcoal with the same
* vermilion glowing slightly brighter, carrying dark ink on top
* (bright-swatch/dark-ink) — the chrome stays vermilion.
*
* Type: Anton (single weight 400 — condensed poster caps, it IS the voice) for
* headings, Archivo for body, JetBrains Mono for code. Consumer register with
* a tall display end of the ramp (hero 4rem — Anton is condensed, big sizes
* stay narrow). Radius is a modest 0.5rem — poster edges, not toys. Motion is
* snappy (120/240/360/500ms); springs alias to the standard eases.
*
* Token contract matches lib-theme-caffe-florian/theme.css (Crema v1).
*/
/*
* Fonts: consuming apps load Anton + Archivo + 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: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-heading: "Anton", "Archivo", -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: "Anton", "Archivo", -apple-system, BlinkMacSystemFont, sans-serif;
--body-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
/* ── Colors ── warm paper content well, near-black warm ink, and the hot
* vermilion drenching the chrome. The paper carries a faint vermilion
* tint (chroma 0.012, hue pulled toward the brand) so the brand reaches
* the content well without gambling its legibility. */
--background: oklch(0.97 0.012 45);
--foreground: oklch(0.21 0.012 40);
--card: oklch(0.995 0.004 60);
--card-foreground: oklch(0.21 0.012 40);
--popover: oklch(0.99 0.005 60);
--popover-foreground: oklch(0.21 0.012 40);
/* Primary — the poster vermilion, deepened from the nominal 0.60 to L0.55
* so near-white ink clears the 4.5:1 floor with room to spare. This is the
* same slab the sidebar is drenched in — one color, big commitments. */
--primary: oklch(0.55 0.21 30);
--primary-foreground: oklch(0.985 0.006 40);
--secondary: oklch(0.93 0.014 48);
--secondary-foreground: oklch(0.3 0.014 40);
--muted: oklch(0.93 0.014 48);
--muted-foreground: oklch(0.45 0.014 40);
/* Accent — a pale vermilion wash with deep vermilion ink: the hover /
* selection tint that echoes the brand without adding a second fill. */
--accent: oklch(0.94 0.035 40);
--accent-foreground: oklch(0.42 0.16 31);
/* ── Status ── destructive must never look like the brand's sibling:
* crimson hue ~15 AND visibly deeper (L0.48) with a light label, vs the
* brighter orange-leaning primary (hue 30, L0.55). Success/warning carry
* dark ink on bright swatches; warning sits at amber 70 — far from the
* vermilion — so alerts never blend into the chrome. */
--destructive: oklch(0.48 0.19 15);
--destructive-foreground: oklch(0.98 0.01 15);
--success: oklch(0.62 0.14 150);
--success-foreground: oklch(0.16 0.03 150);
--warning: oklch(0.72 0.15 70);
--warning-foreground: oklch(0.22 0.05 60);
--info: oklch(0.52 0.13 250);
--info-foreground: oklch(0.98 0.01 250);
--border: oklch(0.21 0.012 40 / 0.12);
--input: oklch(0.21 0.012 40 / 0.14);
--ring: oklch(0.55 0.21 30 / 0.55);
/* Chart palette — vermilion leads, then a spaced spectrum (blue / teal /
* violet / gold), hues ≥60° apart, adjacent lightness varied. */
--chart-1: oklch(0.58 0.2 32);
--chart-2: oklch(0.5 0.13 250);
--chart-3: oklch(0.68 0.11 185);
--chart-4: oklch(0.55 0.15 305);
--chart-5: oklch(0.72 0.13 95);
/* ── Sidebar ── DRENCHED. The whole rail is the poster slab: vermilion
* field, near-white ink, white-alpha hairlines. The active item is a paper
* chip punched out of the slab (deep vermilion ink on near-white). */
--sidebar: oklch(0.52 0.2 31);
--sidebar-foreground: oklch(0.985 0.006 40);
--sidebar-primary: oklch(0.985 0.008 60);
--sidebar-primary-foreground: oklch(0.42 0.17 31);
--sidebar-accent: oklch(0.46 0.185 31);
--sidebar-accent-foreground: oklch(0.985 0.006 40);
--sidebar-border: oklch(1 0 0 / 0.22);
--sidebar-ring: oklch(0.985 0.008 60 / 0.6);
/* Syntax — warm-ink base; the vermilion takes the function seat. */
--syntax-keyword: oklch(0.48 0.15 305);
--syntax-string: oklch(0.5 0.12 150);
--syntax-number: oklch(0.52 0.14 55);
--syntax-comment: oklch(0.52 0.012 40);
--syntax-function: oklch(0.5 0.18 30);
--syntax-type: oklch(0.5 0.1 200);
/* ── Chat surfaces ──
* Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. The user
* bubble is a vermilion slab with near-white ink — the poster color owns
* the human's voice; the assistant answers from clean paper. */
--chat-user-bg: oklch(0.55 0.21 30);
--chat-user-fg: oklch(0.985 0.006 40);
--chat-assistant-bg: oklch(0.995 0.004 60);
--chat-assistant-fg: oklch(0.21 0.012 40);
--chat-assistant-border: oklch(0.21 0.012 40 / 0.1);
/* Poster edges, not toys. */
--radius: 0.5rem;
/* ── Motion ── snappy poster energy. Springs alias to the standard eases —
* the personality is speed and commitment, not bounce. */
--duration-fast: 120ms;
--duration-base: 240ms;
--duration-slow: 360ms;
--duration-slower: 500ms;
--duration-spring: 240ms;
--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);
/* One real spring — a bold consumer theme earns a snappy press. */
--ease-spring-snappy: cubic-bezier(0.2, 1.4, 0.3, 1);
--ease-spring-bouncy: var(--ease-standard);
/* ── Typography ── consumer register with a big condensed display end.
* Anton is condensed, so the tall sizes stay narrow on screen; line
* heights tighten hard at the poster end of the ramp. */
--text-hero-size: 4rem;
--text-hero-lh: 1.02;
--text-display-size: 3rem;
--text-display-lh: 1.05;
--text-headline-size: 2rem;
--text-headline-lh: 1.12;
--text-title-size: 1.375rem;
--text-title-lh: 1.25;
--text-subtitle-size: 1.125rem;
--text-subtitle-lh: 1.4;
--text-body-size: 1rem;
--text-body-lh: 1.55;
--text-label-size: 0.875rem;
--text-label-lh: 1.25rem;
--text-caption-size: 0.75rem;
--text-caption-lh: 1.0625rem;
/* ── Elevation ── low, warm-black shadows — print-flat until something
* genuinely lifts. */
--elevation-0: none;
--elevation-1: 0 1px 2px oklch(0.18 0.02 40 / 0.07);
--elevation-2: 0 1px 3px oklch(0.18 0.02 40 / 0.09), 0 1px 2px oklch(0.18 0.02 40 / 0.05);
--elevation-3: 0 4px 8px -2px oklch(0.18 0.02 40 / 0.1), 0 2px 4px -2px oklch(0.18 0.02 40 / 0.05);
--elevation-4: 0 12px 24px -6px oklch(0.18 0.02 40 / 0.12), 0 4px 8px -4px oklch(0.18 0.02 40 / 0.06);
--elevation-5: 0 20px 40px -8px oklch(0.18 0.02 40 / 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 poster at night. Near-black warm charcoal (low chroma, hue
* ~40, never blue-slate), cards stepping clearly lighter, and the vermilion
* glowing slightly brighter with dark ink on top (bright-swatch/dark-ink).
* The chrome stays vermilion — the sidebar does not go grey at night.
*/
.dark {
--background: oklch(0.18 0.01 40);
--foreground: oklch(0.95 0.008 55);
--card: oklch(0.23 0.012 40);
--card-foreground: oklch(0.95 0.008 55);
--popover: oklch(0.25 0.012 40);
--popover-foreground: oklch(0.95 0.008 55);
--primary: oklch(0.64 0.2 33);
--primary-foreground: oklch(0.13 0.018 35);
--secondary: oklch(0.27 0.012 40);
--secondary-foreground: oklch(0.92 0.01 55);
--muted: oklch(0.27 0.012 40);
--muted-foreground: oklch(0.73 0.014 50);
--accent: oklch(0.32 0.075 33);
--accent-foreground: oklch(0.89 0.08 40);
--destructive: oklch(0.52 0.2 15);
--destructive-foreground: oklch(0.98 0.01 15);
--success: oklch(0.7 0.15 150);
--success-foreground: oklch(0.16 0.03 150);
--warning: oklch(0.76 0.15 70);
--warning-foreground: oklch(0.22 0.05 60);
--info: oklch(0.66 0.13 250);
--info-foreground: oklch(0.15 0.03 250);
--border: oklch(0.95 0.008 55 / 0.13);
--input: oklch(0.95 0.008 55 / 0.15);
--ring: oklch(0.64 0.2 33 / 0.55);
--chart-1: oklch(0.66 0.19 33);
--chart-2: oklch(0.62 0.13 250);
--chart-3: oklch(0.74 0.11 185);
--chart-4: oklch(0.66 0.15 305);
--chart-5: oklch(0.8 0.13 95);
/* Sidebar — still drenched, tuned a step deeper so near-white ink glows. */
--sidebar: oklch(0.48 0.185 30);
--sidebar-foreground: oklch(0.985 0.006 40);
--sidebar-primary: oklch(0.97 0.01 55);
--sidebar-primary-foreground: oklch(0.4 0.165 31);
--sidebar-accent: oklch(0.4 0.16 30);
--sidebar-accent-foreground: oklch(0.985 0.006 40);
--sidebar-border: oklch(1 0 0 / 0.2);
--sidebar-ring: oklch(0.97 0.01 55 / 0.6);
--syntax-keyword: oklch(0.72 0.13 305);
--syntax-string: oklch(0.74 0.12 150);
--syntax-number: oklch(0.78 0.13 60);
--syntax-comment: oklch(0.62 0.012 45);
--syntax-function: oklch(0.72 0.16 33);
--syntax-type: oklch(0.72 0.1 200);
/* ── Chat surfaces (dark) ── user bubble a step deeper than the glowing
* primary so near-white ink stays comfortably legible. */
--chat-user-bg: oklch(0.5 0.19 30);
--chat-user-fg: oklch(0.985 0.006 40);
--chat-assistant-bg: oklch(0.23 0.012 40);
--chat-assistant-fg: oklch(0.95 0.008 55);
--chat-assistant-border: oklch(0.95 0.008 55 / 0.13);
--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 8px -2px oklch(0 0 0 / 0.4), 0 2px 4px -2px oklch(0 0 0 / 0.25);
--elevation-4: 0 12px 24px -6px oklch(0 0 0 / 0.45), 0 4px 8px -4px oklch(0 0 0 / 0.25);
--elevation-5: 0 20px 40px -8px oklch(0 0 0 / 0.55);
}
/*
* @layer base — Vermilion's poster philosophy.
*
* Condensed display type in committed sizes, warm paper for reading, and the
* one hot color spent in slabs — chrome, primary, selection — never scattered.
* Everything that isn't the poster stays quiet ink-on-paper.
*/
@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 — Anton, the single-weight poster voice. It ships at 400 only;
* it is already black-condensed, so weight stays 400 and tracking opens a
* hair (condensed faces need air, not squeeze). Case is the author's call —
* the face carries the register without forced uppercase. */
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: 400;
text-transform: none;
letter-spacing: 0.01em;
/* 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 ink chip, no brand color spent here. */
: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;
}
/* Selection — the poster color claims what you grab. */
::selection {
background: color-mix(in oklch, var(--primary) 30%, transparent);
color: var(--foreground);
}
/* Links — vermilion, underline-on-hover. */
a {
color: color-mix(in oklch, var(--primary) 75%, 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 — the vermilion 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 — a touch of poster weight; opacity absorb on press, snappy. */
[data-slot="button"] {
font-weight: 600;
letter-spacing: 0;
}
/* Card titles — pinned to the subtitle role so the scale is the theme's
* decision, not the card primitive's default. (Anton at title sizes inside a
* card would shout; the subtitle size keeps the poster voice measured.) */
[data-slot="card-title"] {
font-size: var(--text-subtitle-size);
line-height: var(--text-subtitle-lh);
}
/* Touch targets — desktop keeps the crisp 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.9;
}
[data-slot="button"]:active:not(:disabled) {
opacity: 0.82;
transform: scale(0.99);
}
/* Inputs — clean paper surface, hairline border, vermilion 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) 22%, 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;
}