root-colors.css — Color palette (oklch)root-typography.css — Font sizes, weights, line heightsroot-layout.css — Spacing, radius, borders, sizingA 3-layer token system built on CSS custom properties. Colors, typography, spacing, and layout — with automatic light/dark mode support.
Each layer adds meaning. Primitives hold raw values, semantics assign purpose, and the bridge maps to shadcn/Tailwind utilities.
Primitives (root-*.css)
--root-color-brand-500, --root-space-4, --root-font-size-md
↓
Semantics (semantic-*.css)
--background-brand-strong-default, --text-base-strong
↓
Bridge (shadcn-bridge.css)
--primary, --foreground, --ringRaw values with no semantic meaning. Five color scales (brand, danger, neutral, success, warning) with 50–950 steps, plus typography and layout values.
root-colors.css — Color palette (oklch)root-typography.css — Font sizes, weights, line heightsroot-layout.css — Spacing, radius, borders, sizing--root-color-brand-500: oklch(61.87% 0.2067 259.23);
--root-color-neutral-950: oklch(16.84% 0.0000 none);
--root-font-size-md: 1rem;
--root-space-4: 0.5rem;
--root-radius-4: 0.5rem;Named by purpose, not value. Semantic tokens reference primitives and remap automatically between light and dark mode. Components consume these in their .css files.
semantic-colors.css — Background, text, border, icon tokenssemantic-global.css — Mode-independent layout aliasestypography.css — Composite classes (.text-content-body, .text-heading-small)/* Light (:root) */
--background-base: var(--root-color-neutral-050);
--text-base-strong: var(--root-color-neutral-950);
--border-default: var(--root-opacity-neutral-300);
/* Dark (.dark) */
--background-base: var(--root-color-neutral-950);
--text-base-strong: var(--root-color-neutral-050);
--border-default: var(--root-opacity-inverse-300);Maps Lyse semantic tokens to shadcn variable names. This makes components compatible with the shadcn ecosystem and Tailwind utilities like bg-primary or text-foreground.
--background: var(--background-base);
--foreground: var(--text-base-strong);
--primary: var(--background-brand-strong-default);
--destructive: var(--background-danger-strong-default);
--ring: var(--border-selected);Component CSS files use Layer 2 tokens for theming (colors, borders, shadows). Layout properties use dedicated layout tokens.
/* button.css — theming via Layer 2 tokens */
.button-primary {
background: var(--background-brand-strong-default);
color: var(--text-inverse);
}
.button-primary:hover {
background: var(--background-brand-strong-hover);
}/* Structure via layout tokens */
padding: var(--layout-padding-md);
gap: var(--layout-gap-sm);
border-radius: var(--layout-radius-lg);Add the dark class to any ancestor. Semantic tokens remap automatically — no component changes needed.
:root {
--text-base-strong: var(--root-color-neutral-950);
}
.dark {
--text-base-strong: var(--root-color-neutral-050);
}