Lumen
Foundations

Design tokens

One semantic contract; themes swap underneath.

Lumen exposes one semantic contract. Themes swap the values underneath without touching component code.

Selector layering

The shipped contract is :root (Day) and .dark (Night) — exactly what lumen/theme.css defines and what shadcn/Tailwind apps expect, so Lumen drops straight into an existing app. (The standalone labs under /labs/ predate the package and still use a legacy html[data-mode]/data-mood selector internally; that is a lab convenience, not the contract.)

The token set

GroupTokens
Typography--font-sans / --font-serif / --font-display / --font-mono
Surfaces--background / --foreground, --card / --popover
Brand--primary / -foreground, --secondary, --accent / -foreground, --glow, --gradient-primary
Neutrals--muted / -foreground, --border / --input / --ring
Status--success, --warning, --destructive, --info
Health status--status-in-range / -borderline / -out-of-range (+ -text) — aliases of the status hues
Data--data-1--data-6
On-light text*-text variants (e.g. --primary-text, --data-2-text)
Charts--chart-grid / -axis / -track / -band / -band-line
Space--spacing — the 4px base every gap/pad derives from
Size--size-control-sm/md/lg (32/36/44), --size-tap-min (24 — the pressable floor)
Layers--layer-raised--layer-tooltip — one stacking vocabulary
Icons--icon-sm/md/lg (16/20/24), --icon-stroke
Strokes & opacity--stroke-hairline / --stroke-emphasis, --opacity-disabled
Motion--duration-quick / --duration-gentle, --ease-lumen
Shape & depth--radius, --radius-sm--radius-2xl, --shadow-sm / --shadow-lg, --overlay

Why -text variants exist

Saturated fills are too light to use as small text on the pinkish-white ground. Each hue therefore ships a paired -text step that clears WCAG AA. The rule is on the author: fills, dots, and bars use the bright token; small colored text uses the -text step (as the Badge component does).

The semantic tokens are chosen steps from the tonal scales — so contrast is structural, not lucky.

On this page