lib-theme-acid: 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>
This commit is contained in:
61
README.md
Normal file
61
README.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# lib-theme-acid
|
||||||
|
|
||||||
|
**Chartreuse on black.** Festival/Wrapped energy for consumer surfaces that
|
||||||
|
want an unmistakable identity — the committed color carries 30–60% of the
|
||||||
|
surface, the opposite of a calm settings app.
|
||||||
|
|
||||||
|
## Thesis
|
||||||
|
|
||||||
|
Dark mode is the native identity: a near-black green-cast field
|
||||||
|
(`oklch(0.16 0.01 130)`) with electric acid chartreuse
|
||||||
|
(`oklch(0.87 0.21 128)`) carrying the type accents, the panels, and the
|
||||||
|
fills. The signature pair is **black ink on acid** (~13:1) — the primary
|
||||||
|
button, the user chat bubble, and the sidebar accents all run black-on-acid,
|
||||||
|
never white-on-green. Cards step a clear ≥0.05 lighter than the field; the
|
||||||
|
sidebar drops to a pure-black stripe so the acid accents hit hardest there.
|
||||||
|
|
||||||
|
`:root` is the brand's **paper mode** — an honest light mode on a committed
|
||||||
|
chartreuse-washed paper (`oklch(0.96 0.05 120)`, visibly acid, not cream)
|
||||||
|
with near-black green ink. The primary inverts the signature: a deep
|
||||||
|
green-black fill (`oklch(0.3 0.09 130)`) carrying acid-bright labels.
|
||||||
|
|
||||||
|
Status never borrows the brand's lane: destructive is hot red (hue 25,
|
||||||
|
light label); warning is amber 85, held clearly apart from the chartreuse in
|
||||||
|
both hue and chroma; **success is pushed to teal (hue 175, dark ink)** so no
|
||||||
|
second green ever fights the brand; info is cool blue 240. Charts are
|
||||||
|
acid-led with a cool spectrum behind (128 / 240 / 330 / 190 / 40).
|
||||||
|
|
||||||
|
Radius is a chunky-sharp `0.75rem`. Motion is punchy and fast
|
||||||
|
(100/200/320/450ms) with **one real snappy spring**
|
||||||
|
(`--ease-spring-snappy: cubic-bezier(0.2, 1.4, 0.3, 1)` — actual overshoot)
|
||||||
|
reserved for affordances; gentle/bouncy alias to the standard ease.
|
||||||
|
Selection is acid at 40% alpha. Elevation in dark mode is pure-black
|
||||||
|
shadows; no glass (inert stubs).
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
Load in the **consuming app's** entry CSS, at the very top (never `@import`
|
||||||
|
inside `theme.css` — it breaks PostCSS ordering):
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap");
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Archivo Black** — headings. A single-weight display black: it only ships
|
||||||
|
weight 400, so the theme's heading rule pins `font-weight: 400` and lets
|
||||||
|
the blackness of the cut do the work. Tracking is tight (`-0.02em`).
|
||||||
|
Don't ask for bold — faux-bolding this face ruins it.
|
||||||
|
- **Space Grotesk** (400/500/600/700) — body, labels, buttons. Consumer
|
||||||
|
register: body 1rem/1.55, label 0.875rem, caption 0.75rem, title
|
||||||
|
1.375rem, subtitle 1.125rem, headline 1.875rem, display 2.75rem,
|
||||||
|
hero 3.5rem.
|
||||||
|
- **JetBrains Mono** (400/500/600) — code. Dark-mode syntax is a rave
|
||||||
|
terminal with discipline: acid keyword, cool companions (teal strings,
|
||||||
|
magenta numbers, blue functions, orange types).
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node create-crema-app/scripts/validate-theme.mjs lib-theme-acid/theme.css
|
||||||
|
# ✓ PASS — all mandatory tokens present, contrast floors met, no ban violations.
|
||||||
|
```
|
||||||
426
theme.css
Normal file
426
theme.css
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
/*
|
||||||
|
* Acid — chartreuse on black.
|
||||||
|
*
|
||||||
|
* Festival/Wrapped energy. The native identity is dark mode: a near-black
|
||||||
|
* green-cast field with electric acid chartreuse (oklch 0.87 0.21 128)
|
||||||
|
* carrying the type, the panels, and the fills. Black ink on acid is the
|
||||||
|
* signature pair (~13:1) — the primary button, the user bubble, the sidebar
|
||||||
|
* accents all run black-on-acid, never white-on-green.
|
||||||
|
*
|
||||||
|
* :root is the brand's paper mode — honest light mode on a committed
|
||||||
|
* chartreuse-washed paper (oklch 0.96 0.05 120; visibly acid, not cream)
|
||||||
|
* with near-black green ink and a DEEP green-black primary (0.3 0.09 130)
|
||||||
|
* whose labels are acid-bright. The saturated color carries 30–60% of the
|
||||||
|
* surface in both modes; this is the opposite of a calm settings app.
|
||||||
|
*
|
||||||
|
* Status stays out of the brand's lane: destructive is hot red (hue 25,
|
||||||
|
* light label), warning is amber 85 pulled clearly apart from the
|
||||||
|
* chartreuse in both hue and chroma, success is pushed to TEAL (hue 175,
|
||||||
|
* dark ink) so no second green ever fights the brand, info is cool blue 240.
|
||||||
|
*
|
||||||
|
* Type: Archivo Black (single-weight display black, weight 400, tight
|
||||||
|
* -0.02em) for headings, Space Grotesk for body, JetBrains Mono for code.
|
||||||
|
* Radius is a chunky-sharp 0.75rem. Motion is punchy and fast
|
||||||
|
* (100/200/320/450ms) with one real snappy spring for affordances.
|
||||||
|
*
|
||||||
|
* Token contract matches lib-theme-caffe-florian/theme.css (Crema v1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fonts: consuming apps load Archivo Black + Space Grotesk + 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: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
--font-heading: "Archivo Black", "Space Grotesk", -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 Black", "Space Grotesk", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
--body-family: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
|
||||||
|
/* ── Colors ── bright acid-tinted paper (committed chartreuse wash, not
|
||||||
|
* cream), near-white cards a step above it, near-black green ink, and a
|
||||||
|
* deep green-black primary carrying acid-bright labels. */
|
||||||
|
--background: oklch(0.96 0.05 120);
|
||||||
|
--foreground: oklch(0.18 0.02 130);
|
||||||
|
|
||||||
|
--card: oklch(0.985 0.02 120);
|
||||||
|
--card-foreground: oklch(0.18 0.02 130);
|
||||||
|
|
||||||
|
--popover: oklch(0.99 0.015 120);
|
||||||
|
--popover-foreground: oklch(0.18 0.02 130);
|
||||||
|
|
||||||
|
/* Primary — deep green-black fill with the acid chartreuse as its label:
|
||||||
|
* the paper-mode inversion of the dark-mode black-on-acid signature. */
|
||||||
|
--primary: oklch(0.3 0.09 130);
|
||||||
|
--primary-foreground: oklch(0.9 0.21 126);
|
||||||
|
|
||||||
|
--secondary: oklch(0.9 0.06 120);
|
||||||
|
--secondary-foreground: oklch(0.28 0.05 130);
|
||||||
|
|
||||||
|
--muted: oklch(0.915 0.045 120);
|
||||||
|
--muted-foreground: oklch(0.42 0.05 130);
|
||||||
|
|
||||||
|
/* Accent — an acid wash for hover/selection tints, with deep green ink. */
|
||||||
|
--accent: oklch(0.9 0.1 122);
|
||||||
|
--accent-foreground: oklch(0.3 0.09 130);
|
||||||
|
|
||||||
|
/* ── Status ── kept out of the chartreuse lane. Destructive = hot red
|
||||||
|
* (hue 25) with a light label; warning = amber 85, clearly apart from the
|
||||||
|
* brand in hue AND chroma; success = TEAL 175 with dark ink so no second
|
||||||
|
* green fights the chartreuse; info = cool blue 240. */
|
||||||
|
--destructive: oklch(0.54 0.21 25);
|
||||||
|
--destructive-foreground: oklch(0.98 0.01 25);
|
||||||
|
--success: oklch(0.72 0.13 175);
|
||||||
|
--success-foreground: oklch(0.16 0.03 175);
|
||||||
|
--warning: oklch(0.8 0.16 85);
|
||||||
|
--warning-foreground: oklch(0.22 0.05 85);
|
||||||
|
--info: oklch(0.54 0.15 240);
|
||||||
|
--info-foreground: oklch(0.98 0.01 240);
|
||||||
|
|
||||||
|
--border: oklch(0.18 0.02 130 / 0.14);
|
||||||
|
--input: oklch(0.18 0.02 130 / 0.16);
|
||||||
|
--ring: oklch(0.55 0.16 130 / 0.6);
|
||||||
|
|
||||||
|
/* Chart palette — acid-led: deep chartreuse first, then cool blue /
|
||||||
|
* magenta / teal / hot orange. Hues ≥60° apart, adjacent lightness varied. */
|
||||||
|
--chart-1: oklch(0.68 0.17 128);
|
||||||
|
--chart-2: oklch(0.55 0.15 240);
|
||||||
|
--chart-3: oklch(0.6 0.18 330);
|
||||||
|
--chart-4: oklch(0.7 0.12 190);
|
||||||
|
--chart-5: oklch(0.62 0.17 40);
|
||||||
|
|
||||||
|
/* Sidebar — a deeper acid-paper stripe: more committed chartreuse than
|
||||||
|
* the field, with the deep-green primary and acid washes on it. */
|
||||||
|
--sidebar: oklch(0.93 0.07 120);
|
||||||
|
--sidebar-foreground: oklch(0.18 0.02 130);
|
||||||
|
--sidebar-primary: oklch(0.3 0.09 130);
|
||||||
|
--sidebar-primary-foreground: oklch(0.9 0.21 126);
|
||||||
|
--sidebar-accent: oklch(0.88 0.11 122);
|
||||||
|
--sidebar-accent-foreground: oklch(0.3 0.09 130);
|
||||||
|
--sidebar-border: oklch(0.18 0.02 130 / 0.12);
|
||||||
|
--sidebar-ring: oklch(0.55 0.16 130 / 0.6);
|
||||||
|
|
||||||
|
/* Syntax — deep chartreuse keyword leads; the rest stays cool. */
|
||||||
|
--syntax-keyword: oklch(0.45 0.13 130);
|
||||||
|
--syntax-string: oklch(0.48 0.1 175);
|
||||||
|
--syntax-number: oklch(0.55 0.16 330);
|
||||||
|
--syntax-comment: oklch(0.52 0.03 130);
|
||||||
|
--syntax-function: oklch(0.48 0.14 240);
|
||||||
|
--syntax-type: oklch(0.5 0.13 40);
|
||||||
|
|
||||||
|
/* ── Chat surfaces ──
|
||||||
|
* Contract for lib-chat-ui / lib-agent-ui / lib-agent-dock-ui. In paper
|
||||||
|
* mode the user bubble is the deep green-black panel with light text;
|
||||||
|
* the assistant bubble is a clean card with a hairline border. */
|
||||||
|
--chat-user-bg: oklch(0.3 0.09 130);
|
||||||
|
--chat-user-fg: oklch(0.97 0.03 120);
|
||||||
|
--chat-assistant-bg: oklch(0.985 0.02 120);
|
||||||
|
--chat-assistant-fg: oklch(0.18 0.02 130);
|
||||||
|
--chat-assistant-border: oklch(0.18 0.02 130 / 0.14);
|
||||||
|
|
||||||
|
/* Chunky-sharp radius. */
|
||||||
|
--radius: 0.75rem;
|
||||||
|
|
||||||
|
/* ── Motion ── punchy and fast. One REAL snappy spring (actual overshoot)
|
||||||
|
* for affordances; gentle/bouncy alias to the standard ease so the
|
||||||
|
* personality stays a single sharp gesture, not a bounce-house. */
|
||||||
|
--duration-fast: 100ms;
|
||||||
|
--duration-base: 200ms;
|
||||||
|
--duration-slow: 320ms;
|
||||||
|
--duration-slower: 450ms;
|
||||||
|
--duration-spring: 380ms;
|
||||||
|
|
||||||
|
--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: var(--ease-standard);
|
||||||
|
--ease-spring-snappy: cubic-bezier(0.2, 1.4, 0.3, 1);
|
||||||
|
--ease-spring-bouncy: var(--ease-standard);
|
||||||
|
|
||||||
|
/* ── Typography ── consumer register, fixed rem, full role ramp. */
|
||||||
|
--text-hero-size: 3.5rem;
|
||||||
|
--text-hero-lh: 1.02;
|
||||||
|
--text-display-size: 2.75rem;
|
||||||
|
--text-display-lh: 1.05;
|
||||||
|
--text-headline-size: 1.875rem;
|
||||||
|
--text-headline-lh: 1.15;
|
||||||
|
--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: 1rem;
|
||||||
|
|
||||||
|
/* ── Elevation ── crisp green-black shadows on the paper. */
|
||||||
|
--elevation-0: none;
|
||||||
|
--elevation-1: 0 1px 2px oklch(0.18 0.03 130 / 0.08);
|
||||||
|
--elevation-2: 0 1px 3px oklch(0.18 0.03 130 / 0.1), 0 1px 2px oklch(0.18 0.03 130 / 0.06);
|
||||||
|
--elevation-3: 0 4px 8px -2px oklch(0.18 0.03 130 / 0.1), 0 2px 4px -2px oklch(0.18 0.03 130 / 0.06);
|
||||||
|
--elevation-4: 0 12px 24px -6px oklch(0.18 0.03 130 / 0.13), 0 4px 8px -4px oklch(0.18 0.03 130 / 0.06);
|
||||||
|
--elevation-5: 0 20px 40px -8px oklch(0.18 0.03 130 / 0.2);
|
||||||
|
|
||||||
|
--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 native identity. Near-black green-cast field, cards
|
||||||
|
* stepping clearly lighter, and the full acid chartreuse as primary with
|
||||||
|
* BLACK ink on it (the signature pair, ~13:1). The acid carries the type
|
||||||
|
* accents, the panels, and the fills — a rave terminal with discipline.
|
||||||
|
*/
|
||||||
|
.dark {
|
||||||
|
--background: oklch(0.16 0.01 130);
|
||||||
|
--foreground: oklch(0.95 0.03 120);
|
||||||
|
|
||||||
|
--card: oklch(0.21 0.012 130);
|
||||||
|
--card-foreground: oklch(0.95 0.03 120);
|
||||||
|
|
||||||
|
--popover: oklch(0.23 0.014 130);
|
||||||
|
--popover-foreground: oklch(0.95 0.03 120);
|
||||||
|
|
||||||
|
/* Black-on-acid — the signature. */
|
||||||
|
--primary: oklch(0.87 0.21 128);
|
||||||
|
--primary-foreground: oklch(0.15 0.02 130);
|
||||||
|
|
||||||
|
--secondary: oklch(0.26 0.02 130);
|
||||||
|
--secondary-foreground: oklch(0.93 0.03 120);
|
||||||
|
|
||||||
|
--muted: oklch(0.25 0.015 130);
|
||||||
|
--muted-foreground: oklch(0.75 0.05 125);
|
||||||
|
|
||||||
|
/* Accent — a dark acid wash with acid-bright ink. */
|
||||||
|
--accent: oklch(0.28 0.06 128);
|
||||||
|
--accent-foreground: oklch(0.88 0.18 126);
|
||||||
|
|
||||||
|
--destructive: oklch(0.56 0.21 25);
|
||||||
|
--destructive-foreground: oklch(0.98 0.01 25);
|
||||||
|
--success: oklch(0.76 0.13 175);
|
||||||
|
--success-foreground: oklch(0.16 0.03 175);
|
||||||
|
--warning: oklch(0.82 0.16 85);
|
||||||
|
--warning-foreground: oklch(0.22 0.05 85);
|
||||||
|
--info: oklch(0.68 0.14 240);
|
||||||
|
--info-foreground: oklch(0.16 0.03 240);
|
||||||
|
|
||||||
|
--border: oklch(0.95 0.03 120 / 0.12);
|
||||||
|
--input: oklch(0.95 0.03 120 / 0.14);
|
||||||
|
--ring: oklch(0.87 0.21 128 / 0.6);
|
||||||
|
|
||||||
|
/* Chart palette — acid leads at full charge; cool spectrum follows. */
|
||||||
|
--chart-1: oklch(0.87 0.21 128);
|
||||||
|
--chart-2: oklch(0.68 0.14 240);
|
||||||
|
--chart-3: oklch(0.74 0.17 330);
|
||||||
|
--chart-4: oklch(0.8 0.12 190);
|
||||||
|
--chart-5: oklch(0.72 0.16 40);
|
||||||
|
|
||||||
|
/* Sidebar — a pure-black stripe with acid accents. */
|
||||||
|
--sidebar: oklch(0.13 0.008 130);
|
||||||
|
--sidebar-foreground: oklch(0.95 0.03 120);
|
||||||
|
--sidebar-primary: oklch(0.87 0.21 128);
|
||||||
|
--sidebar-primary-foreground: oklch(0.15 0.02 130);
|
||||||
|
--sidebar-accent: oklch(0.26 0.06 128);
|
||||||
|
--sidebar-accent-foreground: oklch(0.88 0.18 126);
|
||||||
|
--sidebar-border: oklch(0.95 0.03 120 / 0.09);
|
||||||
|
--sidebar-ring: oklch(0.87 0.21 128 / 0.6);
|
||||||
|
|
||||||
|
/* Syntax — rave terminal, disciplined: acid keyword against cool
|
||||||
|
* companions, nothing else allowed near the chartreuse lane. */
|
||||||
|
--syntax-keyword: oklch(0.85 0.2 128);
|
||||||
|
--syntax-string: oklch(0.78 0.11 175);
|
||||||
|
--syntax-number: oklch(0.76 0.16 330);
|
||||||
|
--syntax-comment: oklch(0.6 0.03 130);
|
||||||
|
--syntax-function: oklch(0.72 0.13 240);
|
||||||
|
--syntax-type: oklch(0.76 0.14 40);
|
||||||
|
|
||||||
|
/* ── Chat surfaces (dark) ──
|
||||||
|
* User bubble IS the signature: acid chartreuse with black ink. */
|
||||||
|
--chat-user-bg: oklch(0.87 0.21 128);
|
||||||
|
--chat-user-fg: oklch(0.15 0.02 130);
|
||||||
|
--chat-assistant-bg: oklch(0.21 0.012 130);
|
||||||
|
--chat-assistant-fg: oklch(0.95 0.03 120);
|
||||||
|
--chat-assistant-border: oklch(0.95 0.03 120 / 0.12);
|
||||||
|
|
||||||
|
/* ── Elevation (dark) ── pure-black shadows. */
|
||||||
|
--elevation-1: 0 1px 2px oklch(0 0 0 / 0.35);
|
||||||
|
--elevation-2: 0 1px 3px oklch(0 0 0 / 0.45), 0 1px 2px oklch(0 0 0 / 0.28);
|
||||||
|
--elevation-3: 0 4px 8px -2px oklch(0 0 0 / 0.45), 0 2px 4px -2px oklch(0 0 0 / 0.28);
|
||||||
|
--elevation-4: 0 12px 24px -6px oklch(0 0 0 / 0.5), 0 4px 8px -4px oklch(0 0 0 / 0.28);
|
||||||
|
--elevation-5: 0 20px 40px -8px oklch(0 0 0 / 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @layer base — Acid's festival philosophy, disciplined.
|
||||||
|
*
|
||||||
|
* Archivo Black headings hit like posters; Space Grotesk keeps the body
|
||||||
|
* legible; the chartreuse is committed (it carries panels and fills, not
|
||||||
|
* just a ring) but status meaning never borrows it. Selection is acid at
|
||||||
|
* 40% alpha — even highlighting text is on-brand.
|
||||||
|
*/
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
letter-spacing: -0.008em;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: var(--text-body-size);
|
||||||
|
line-height: var(--text-body-lh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings — Archivo Black: single-weight display black. The face only
|
||||||
|
* ships 400, so the rule pins weight 400 and lets the blackness of the
|
||||||
|
* cut do the shouting; tracking pulled tight. */
|
||||||
|
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;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
/* 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. */
|
||||||
|
: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 — acid at 40% alpha. */
|
||||||
|
::selection {
|
||||||
|
background: color-mix(in oklch, var(--primary) 40%, transparent);
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links — brand-inked, underline-on-hover. */
|
||||||
|
a {
|
||||||
|
color: color-mix(in oklch, var(--primary) 75%, var(--foreground));
|
||||||
|
text-decoration-color: color-mix(in oklch, var(--primary) 45%, 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 acid 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; snappy spring press, festival-fast. */
|
||||||
|
[data-slot="button"] {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: -0.008em;
|
||||||
|
transition:
|
||||||
|
opacity var(--duration-fast) var(--ease-standard),
|
||||||
|
transform var(--duration-spring) var(--ease-spring-snappy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 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.92;
|
||||||
|
}
|
||||||
|
[data-slot="button"]:active:not(:disabled) {
|
||||||
|
opacity: 0.85;
|
||||||
|
transform: scale(0.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inputs — card surface, hairline border, acid 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) 25%, 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