From 0c31a343e2ae61bc83b8ada10a0fe8469b2885bd Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 8 Jul 2026 07:20:58 +1000 Subject: [PATCH] lib-theme-lantern: initial import (access-first set, 2026-07) One of three candidates for the access-first / maximum-legibility theme family (WCAG AAA as identity): 7:1+ contrast on every pair (passes validate-theme.mjs --aaa), 1.125rem body floor with nothing under 14px, 44px controls for everyone, 3px focus rings, links underlined at rest, reduced-motion built in. Built for IGH/NDIS-facing surfaces first. Co-Authored-By: Claude Fable 5 --- README.md | 85 ++++++++++ theme.css | 454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100644 README.md create mode 100644 theme.css diff --git a/README.md b/README.md new file mode 100644 index 0000000..993005a --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# lib-theme-lantern + +**Warm paper, kitchen table not clinic.** + +Lantern is one of three divergent candidates for Crema's access-first theme +family: WCAG AAA as identity, not compliance. Its thesis is that maximum +legibility can feel warm and human — a document you read at the kitchen table +with someone you trust, not a form handed across a clinic counter. Built for +NDIS participants, their families, and older support coordinators (the +IGH/IveGotHome portals): dignity, clarity, zero squinting. The discipline IS +the personality. + +## The idea + +- **Light mode** — warm ivory paper (`oklch(0.97 0.012 85)`), warm-white cards, + near-black warm umber ink at **17.8:1**. The surface is deliberately high in + lightness so 7:1 ink is easy everywhere and nothing has to shout. +- **Primary** — a deep amber-brown gold (`oklch(0.4 0.11 70)`): a lantern's + brass, not a yellow hazard. Warm-white label at **9.0:1**. Links share the + same gold and are **underlined by default** (thicker on hover). +- **Dark mode** — the lantern lit: warm dark umber (`oklch(0.17 0.012 60)`), + warm-white ink at **16.5:1**, and the gold turned luminous + (`oklch(0.78 0.13 80)`) with a black-umber label at **9.7:1**. +- **Type** — Lexend for body AND headings (weight 600 headings). Lexend was + designed to improve reading proficiency; here it earns its keep. JetBrains + Mono for code. + +## Access-family contract (shared DNA) + +- Type ramp starts larger: body 1.125rem/1.65, label 1rem/1.5, caption + 0.875rem/1.4 (never below 14px). Generous line-heights throughout. +- Body ink and `muted-foreground` ≥ 7:1 on background AND card, both modes. + Primary label ≥ 7:1 on primary. Status label pairs all ≥ 7:1. +- Focus: 3px solid outline + 2px offset on buttons; inputs get a border-color + change plus a 2px ring. Always visible. +- Touch targets: buttons and inputs min-height 2.75rem **globally**, not just + behind a coarse-pointer media query. +- Borders strong — ink at 0.25–0.32 alpha. Boundaries, not hairlines + (`--border-width-base` is 1.5px; no sub-pixel widths). +- Radius soft but modest (0.625rem). Elevation low; borders do the separating. +- Motion minimal and quick (120/200/300/400ms); all springs alias the standard + ease; `prefers-reduced-motion: reduce` zeroes transitions on interactive + slots. Nothing essential is motion-only. + +## Verified contrast (WCAG 2.1 relative luminance, exact oklch→sRGB) + +| Pair | Light | Dark | +|---|---|---| +| foreground / background | 17.81:1 | 16.54:1 | +| foreground / card | 19.14:1 | 14.98:1 | +| muted-foreground / background | 9.99:1 | 9.55:1 | +| muted-foreground / card | 10.73:1 | 8.65:1 | +| muted-foreground / muted | 8.86:1 | 7.54:1 | +| primary-foreground / primary | 9.00:1 | 9.73:1 | +| status labels / fills (worst) | 8.09:1 | 7.40:1 | + +## Fonts + +Consuming apps load fonts at the very top of their entry CSS (never inside +`theme.css` — see the token contract): + +```css +@import url("https://fonts.googleapis.com/css2?family=Lexend:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"); +``` + +## Validation + +```bash +node create-crema-app/scripts/validate-theme.mjs lib-theme-lantern/theme.css +# ✓ PASS — all mandatory tokens present, contrast floors met, no ban violations. +``` + +## Notes + +- Warning is a deep amber-**orange** (hue 55, L 0.42) in light mode — well + separated from the hue-70/80 brass so the two never read as one swatch, and + dark enough that it never becomes a pale hazard stripe. +- Dark-mode surface ladder: background 0.17 → sidebar 0.20 → card 0.22 → + popover 0.245 → muted/secondary 0.27 (popover above card, below muted). +- Chart hues 80/150/220/290/20 (≥60° apart), adjacent lightness varied. +- Chat: user bubble is a deep warm-umber panel (13:1 light / 11:1 dark); + assistant bubble is a card with the strong border. +- Headings use `color: inherit` so titles inside primary buttons, status + banners, and chat bubbles keep their surface's ink. +- No glass — inert stubs (`0px / 100% / 1 / 1`). diff --git a/theme.css b/theme.css new file mode 100644 index 0000000..effd6a0 --- /dev/null +++ b/theme.css @@ -0,0 +1,454 @@ +/* + * Lantern — warm paper, kitchen table not clinic. + * + * An access-first theme: WCAG AAA as identity, not compliance. Lantern is the + * proof that AAA can feel warm and human. The surface is warm ivory paper — + * high lightness on purpose, so 7:1 ink is easy and nothing has to shout. + * Ink is a near-black warm umber (~15:1 on paper). The single accent is a deep + * amber-brown gold — a lantern's brass, not a yellow hazard — carrying a + * warm-white label well above 7:1. Links share the same deep gold and are + * underlined by default. Built for people who deserve dignity, clarity, and + * zero squinting: NDIS participants, their families, older support + * coordinators. The discipline IS the personality. + * + * Dark mode is the lantern lit: warm dark umber, warm-white ink, and the gold + * turned luminous with a black-umber label on top (bright-swatch/dark-ink, the + * high-contrast direction). + * + * Family DNA (shared across the access candidates): + * - Type ramp starts larger (body 1.125rem/1.65); captions never below 14px. + * - Body ink AND muted-foreground >= 7:1 on background AND card, both modes. + * - Primary label >= 7:1 on primary; status labels >= 7:1 where feasible. + * - Focus: 3px solid outline + 2px offset; inputs get border change + ring. + * - Links underlined by default; underline thickens on hover. + * - Touch targets: 2.75rem min-height on buttons/inputs GLOBALLY. + * - Borders strong (ink at ~0.25-0.3 alpha) — boundaries, not decoration. + * - Motion minimal and quick; springs alias standard; reduced-motion honored. + * + * Computed contrast (exact WCAG 2.1 relative-luminance math, oklch -> sRGB; + * sketched first with Y ~ L^3, then verified with the validator's converter): + * LIGHT + * foreground L0.16 on background L0.97 ..... 17.81:1 + * foreground L0.16 on card L0.995 .......... 19.14:1 + * muted-foreground L0.36 on background ..... 9.99:1 + * muted-foreground L0.36 on card ........... 10.73:1 + * muted-foreground L0.36 on muted L0.93 .... 8.86:1 + * primary-foreground L0.985 on primary L0.40 9.00:1 + * status labels L0.985 on L0.40-0.42 fills . 8.09-8.77:1 + * DARK + * foreground L0.95 on background L0.17 ..... 16.54:1 + * foreground L0.95 on card L0.22 ........... 14.98:1 + * muted-foreground L0.78 on background ..... 9.55:1 + * muted-foreground L0.78 on card ........... 8.65:1 + * muted-foreground L0.78 on muted L0.27 .... 7.54:1 + * primary-foreground L0.15 on primary L0.78 9.73:1 + * status inks L0.16 on L0.72-0.80 fills .... 7.40-10.22:1 + * + * Token contract: Crema v1 (create-crema-app/TOKEN_CONTRACT.md). + */ + +/* + * Fonts: consuming apps load Lexend (400/500/600/700) + JetBrains Mono + * (400/500/600) at the top of their entry CSS via the URL documented in this + * theme's README. Lexend is chosen deliberately — it was designed to improve + * reading proficiency — and serves body AND headings. No @import here (PostCSS + * ordering) and no URL smuggled in comments. + */ + +:root { + --font-sans: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-heading: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; + + /* Tailwind utility families — mirror --font-heading/--font-sans. */ + --heading-family: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --body-family: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + + /* ── Colors ── warm ivory paper, warm-white cards, near-black warm ink. + * High-lightness surface keeps every 7:1 pair easy. */ + --background: oklch(0.97 0.012 85); + --foreground: oklch(0.16 0.01 60); /* ~17.8:1 on background */ + + --card: oklch(0.995 0.006 85); + --card-foreground: oklch(0.16 0.01 60); /* ~19.1:1 on card */ + + --popover: oklch(0.99 0.007 85); + --popover-foreground: oklch(0.16 0.01 60); + + /* Primary — the lantern's brass: deep amber-brown gold with a warm-white + * label. L0.40 fill vs L0.985 label ~8.8:1 (>= 7:1 AAA). */ + --primary: oklch(0.4 0.11 70); + --primary-foreground: oklch(0.985 0.008 85); + + --secondary: oklch(0.91 0.025 80); + --secondary-foreground: oklch(0.25 0.03 65); /* ~12.2:1 on secondary */ + + /* Muted stays light so muted-foreground can hold 7:1 on it too. */ + --muted: oklch(0.93 0.015 83); + --muted-foreground: oklch(0.36 0.015 65); /* ~9.96:1 bg / ~10.7:1 card / ~8.8:1 muted */ + + /* Accent — warm gold wash for hover/selection with deep gold-brown ink. */ + --accent: oklch(0.9 0.055 85); + --accent-foreground: oklch(0.33 0.09 70); /* ~9.1:1 on accent */ + + /* ── Status ── deep fills carrying warm-white labels, all >= 7:1. + * Warning is pulled to deep amber-ORANGE (hue 55) and darker than any + * yellow so it never reads as a pale hazard stripe. */ + --destructive: oklch(0.42 0.16 27); + --destructive-foreground: oklch(0.985 0.008 27); /* ~8.1:1 */ + --success: oklch(0.4 0.1 150); + --success-foreground: oklch(0.985 0.008 150); /* ~8.8:1 */ + --warning: oklch(0.42 0.12 55); + --warning-foreground: oklch(0.985 0.008 55); /* ~8.1:1 */ + --info: oklch(0.42 0.1 250); + --info-foreground: oklch(0.985 0.008 250); /* ~8.1:1 */ + + /* Borders STRONG — ink at 0.25-0.3 alpha. Visible boundaries. */ + --border: oklch(0.16 0.01 60 / 0.27); + --input: oklch(0.16 0.01 60 / 0.32); + --ring: oklch(0.4 0.11 70); + + /* Charts — hues >= 60 degrees apart (80/150/220/290/20), adjacent + * lightness varied, all deep enough to sit legibly on paper. */ + --chart-1: oklch(0.55 0.12 80); + --chart-2: oklch(0.45 0.1 150); + --chart-3: oklch(0.6 0.1 220); + --chart-4: oklch(0.45 0.12 290); + --chart-5: oklch(0.52 0.14 20); + + /* Sidebar — slightly deeper paper, same ink, same brass. */ + --sidebar: oklch(0.945 0.014 84); + --sidebar-foreground: oklch(0.16 0.01 60); + --sidebar-primary: oklch(0.4 0.11 70); + --sidebar-primary-foreground: oklch(0.985 0.008 85); + --sidebar-accent: oklch(0.9 0.055 85); + --sidebar-accent-foreground: oklch(0.33 0.09 70); + --sidebar-border: oklch(0.16 0.01 60 / 0.22); + --sidebar-ring: oklch(0.4 0.11 70); + + /* Syntax — deep, calm hues on the paper; comments stay >= 7:1 too. */ + --syntax-keyword: oklch(0.42 0.12 290); + --syntax-string: oklch(0.42 0.1 150); + --syntax-number: oklch(0.44 0.12 55); + --syntax-comment: oklch(0.44 0.015 65); + --syntax-function: oklch(0.42 0.1 250); + --syntax-type: oklch(0.42 0.08 200); + + /* ── Chat surfaces ── + * User bubble is a deep warm-umber panel with warm-white text (~13:1); + * assistant bubble is a warm-white card with a strong border. */ + --chat-user-bg: oklch(0.3 0.05 65); + --chat-user-fg: oklch(0.985 0.008 85); + --chat-assistant-bg: oklch(0.995 0.006 85); + --chat-assistant-fg: oklch(0.16 0.01 60); + --chat-assistant-border: oklch(0.16 0.01 60 / 0.27); + + /* Soft but modest. */ + --radius: 0.625rem; + + /* ── Motion ── minimal and quick; nothing essential is motion-only. + * Springs alias to standard — calm by construction. */ + --duration-fast: 120ms; + --duration-base: 200ms; + --duration-slow: 300ms; + --duration-slower: 400ms; + --duration-spring: 200ms; + + --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-standard); + --ease-spring-bouncy: var(--ease-standard); + + /* ── Typography ── access ramp: starts larger, generous line-heights, + * caption never below 14px. Fixed rem, product register. */ + --text-hero-size: 3rem; + --text-hero-lh: 1.1; + --text-display-size: 2.5rem; + --text-display-lh: 1.15; + --text-headline-size: 1.875rem; + --text-headline-lh: 1.25; + --text-title-size: 1.5rem; + --text-title-lh: 1.35; + --text-subtitle-size: 1.25rem; + --text-subtitle-lh: 1.5; + --text-body-size: 1.125rem; + --text-body-lh: 1.65; + --text-label-size: 1rem; + --text-label-lh: 1.5; + --text-caption-size: 0.875rem; + --text-caption-lh: 1.4; + + /* ── Elevation ── low and warm; separation is the borders' job. */ + --elevation-0: none; + --elevation-1: 0 1px 2px oklch(0.16 0.01 60 / 0.05); + --elevation-2: 0 1px 3px oklch(0.16 0.01 60 / 0.07), 0 1px 2px oklch(0.16 0.01 60 / 0.04); + --elevation-3: 0 4px 8px -2px oklch(0.16 0.01 60 / 0.08), 0 2px 4px -2px oklch(0.16 0.01 60 / 0.04); + --elevation-4: 0 10px 20px -6px oklch(0.16 0.01 60 / 0.1), 0 4px 8px -4px oklch(0.16 0.01 60 / 0.05); + --elevation-5: 0 18px 36px -8px oklch(0.16 0.01 60 / 0.14); + + --spacing: 0.25rem; + + /* Border widths — no sub-pixel hairlines in an access theme. */ + --border-width-thin: 1px; + --border-width-base: 1.5px; + --border-width-thick: 3px; + --border-width-heavy: 5px; + + /* 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 lantern lit. Warm dark umber, warm-white ink, cards a full + * +0.05 L above the background, popover above card and below muted so the + * altitude ladder stays readable. The gold turns luminous and carries a + * black-umber label (bright-swatch/dark-ink), as do all dark status fills. + */ +.dark { + --background: oklch(0.17 0.012 60); + --foreground: oklch(0.95 0.01 80); /* ~16.5:1 on background */ + + --card: oklch(0.22 0.012 60); + --card-foreground: oklch(0.95 0.01 80); /* ~15.0:1 on card */ + + --popover: oklch(0.245 0.012 60); + --popover-foreground: oklch(0.95 0.01 80); + + /* Luminous warm gold, black-umber ink — ~9.8:1. */ + --primary: oklch(0.78 0.13 80); + --primary-foreground: oklch(0.15 0.03 70); + + --secondary: oklch(0.27 0.02 65); + --secondary-foreground: oklch(0.93 0.01 80); + + --muted: oklch(0.27 0.015 62); + --muted-foreground: oklch(0.78 0.015 75); /* ~9.6:1 bg / ~8.7:1 card / ~7.5:1 muted */ + + --accent: oklch(0.3 0.05 75); + --accent-foreground: oklch(0.85 0.11 82); /* ~8.6:1 on accent */ + + /* Status — bright fills, dark umber inks, all >= 7:1. */ + --destructive: oklch(0.72 0.14 25); + --destructive-foreground: oklch(0.16 0.03 25); /* ~7.8:1 */ + --success: oklch(0.78 0.15 150); + --success-foreground: oklch(0.16 0.03 150); /* ~9.7:1 */ + --warning: oklch(0.8 0.14 60); + --warning-foreground: oklch(0.16 0.03 60); /* ~10.4:1 */ + --info: oklch(0.75 0.1 250); + --info-foreground: oklch(0.16 0.03 250); /* ~8.7:1 */ + + --border: oklch(0.95 0.01 80 / 0.25); + --input: oklch(0.95 0.01 80 / 0.3); + --ring: oklch(0.78 0.13 80); + + --chart-1: oklch(0.8 0.13 80); + --chart-2: oklch(0.7 0.13 150); + --chart-3: oklch(0.75 0.1 220); + --chart-4: oklch(0.68 0.12 290); + --chart-5: oklch(0.72 0.14 20); + + --sidebar: oklch(0.2 0.012 60); + --sidebar-foreground: oklch(0.95 0.01 80); + --sidebar-primary: oklch(0.78 0.13 80); + --sidebar-primary-foreground: oklch(0.15 0.03 70); + --sidebar-accent: oklch(0.3 0.05 75); + --sidebar-accent-foreground: oklch(0.85 0.11 82); + --sidebar-border: oklch(0.95 0.01 80 / 0.2); + --sidebar-ring: oklch(0.78 0.13 80); + + --syntax-keyword: oklch(0.78 0.1 290); + --syntax-string: oklch(0.78 0.12 150); + --syntax-number: oklch(0.82 0.12 70); + --syntax-comment: oklch(0.72 0.015 70); + --syntax-function: oklch(0.75 0.1 250); + --syntax-type: oklch(0.78 0.08 200); + + /* ── Chat surfaces (dark) ── */ + --chat-user-bg: oklch(0.32 0.04 70); + --chat-user-fg: oklch(0.96 0.01 80); + --chat-assistant-bg: oklch(0.22 0.012 60); + --chat-assistant-fg: oklch(0.95 0.01 80); + --chat-assistant-border: oklch(0.95 0.01 80 / 0.25); + + --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 10px 20px -6px oklch(0 0 0 / 0.45), 0 4px 8px -4px oklch(0 0 0 / 0.25); + --elevation-5: 0 18px 36px -8px oklch(0 0 0 / 0.55); +} + +/* + * @layer base — Lantern's warm, legible philosophy. + * + * Lexend for everything (it earns its keep at reading time), strong visible + * boundaries, one brass accent, links that look like links, and focus you can + * find from across the kitchen table. + */ +@layer base { + body { + min-height: 100vh; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-family: var(--font-sans); + font-size: var(--text-body-size); + line-height: var(--text-body-lh); + } + + /* Headings — Lexend 600. `color: inherit` so headings inside colored + * surfaces (primary buttons, status banners, chat bubbles) stay legible. */ + 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: inherit; + } + + code, kbd, samp, pre, + [data-slot="code"], + [data-slot="code-block"] { + font-family: var(--font-mono); + } + + /* Inline code — foreground-tint chip, foreground ink. */ + :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.92em; + } + + /* Selection — the brass, as a wash. */ + ::selection { + background: color-mix(in oklch, var(--primary) 30%, transparent); + color: var(--foreground); + } + + /* Links — deep gold, UNDERLINED BY DEFAULT (a link must look like a link + * without color vision); underline thickens on hover. */ + a { + color: var(--primary); + text-decoration-line: underline; + text-decoration-thickness: 0.07em; + text-underline-offset: 0.18em; + transition: text-decoration-thickness var(--duration-fast) var(--ease-standard); + } + a:hover { + text-decoration-thickness: 0.14em; + } + + [data-slot="sidebar"] { + background: var(--sidebar); + border-right: var(--border-width-base) solid var(--sidebar-border); + } +} + +/* + * Focus-visible — 3px solid brass outline, 2px offset. Always visible, + * findable at arm's length. Placed outside @layer base so it beats Tailwind's + * default ring utilities. + */ +[data-slot="button"]:focus-visible, +[data-slot="select-trigger"]:focus-visible { + outline: 3px solid var(--ring); + outline-offset: 2px; + box-shadow: none; +} + +/* Buttons — medium weight, generous letterforms, no shrinking targets. */ +[data-slot="button"] { + font-weight: 500; +} + +/* 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 — 44px floor GLOBALLY, not just for coarse pointers. Tremor, + * arthritis, and a hurried mouse all deserve the same landing pad. + */ +[data-slot="button"] { + min-height: 2.75rem; + min-width: 2.75rem; +} +[data-slot="input"], +[data-slot="select-trigger"] { + min-height: 2.75rem; +} +/* Coarse pointers keep their explicit guarantee too. */ +@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.84; +} + +/* Inputs — warm-white field, STRONG border, brass focus: border-color change + * plus a 2px ring so focus survives low vision and bright rooms. */ +[data-slot="input"], +[data-slot="textarea"], +[data-slot="select-trigger"] { + background: var(--card); + border: var(--border-width-base) solid var(--input); + 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); +} +[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) 45%, transparent); +} +[data-slot="input"]:focus, +[data-slot="input"]:focus-visible, +[data-slot="textarea"]:focus, +[data-slot="textarea"]:focus-visible, +[data-slot="select-trigger"]:focus { + border-color: var(--primary); + box-shadow: 0 0 0 2px var(--ring); + outline: none; +} + +/* Reduced motion — zero transitions on the interactive slots; nothing in + * Lantern depends on movement to be understood. */ +@media (prefers-reduced-motion: reduce) { + [data-slot="button"], + [data-slot="input"], + [data-slot="textarea"], + [data-slot="select-trigger"], + a { + transition: none; + } +}