How to: re-skin via tokens
Never edit a component's CSS to change how it looks app-wide. GRAIN's atoms and the AI-mode mechanism (styles/grain.css) read semantic token slots; a consumer re-skins by overriding those slots in its own sheet, linked after GRAIN's.
The slots
- fonts:
--type-font(the grade switch atoms inherit),--font-grain,--font-smooth,--font-accent - ink/paper:
--ink,--paper,--color-fg,--color-muted,--line-soft - scale:
--space-1…--space-8,--text-sm,--border,--radius-sm,--radius-md - AI spotlight:
--ai-veil(the "AI is acting" backdrop) and--ai-focus-move(how slowly the
spotlight glides between surfaces) — set once in the theme so every page behaves identically.
Do this
/* your-theme.css — linked AFTER grain/styles/variables.css in <head> */
:root {
--ink: #1a1a2e;
--paper: #f4f1ea;
--radius-md: 12px;
}No component file changes. If a component's look still doesn't move, that component is reading a hardcoded value instead of a token — that's a bug in the component (CONVENTIONS §4 forbids it), not something to route around in your override sheet.
Don't do this
Don't fork a component's .css to change its color, spacing, or radius — that's exactly the per-component edit tokens exist to avoid, and it'll drift the next time the component updates upstream. If the token slots genuinely don't cover what you need, that's a gap in the token set worth raising, not a reason to bypass it.
Verify
bun run dev
# toggle the theme cycler in the window bar, or set data-theme on <html> —
# a real token override should be visible everywhere the slot is used, immediately