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 <noreply@anthropic.com>
86 lines
3.9 KiB
Markdown
86 lines
3.9 KiB
Markdown
# 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`).
|