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--brand (Solar, which means Halo: the mark, the Halo button, a cover's light), --primary / -foreground (the action, in ink), --secondary, --accent / -foreground, --glow, --gradient-primary
Neutrals--muted / -foreground, --border (dividers only), --border-strong = --input (the 3:1 control edge), --ring. The soft lines and fills are the ink at a low alpha
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-standard / --duration-gentle, --ease-standard / --ease-exit, --ease-lumen (the Vital rhythms)
Type--type-display … --type-unit (font shorthands) plus --type-*-tracking; use the type-* utilities
Shape & depth--radius, --radius-sm … --radius-xl, --shadow-sm / --shadow-lg / --shadow-xl, --surface-raised, --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