Colors
Semantic colour tokens on Radix Gray, with red and green for status, switched by a .dark class.
The palette
Almost everything is Radix Colors' Gray scale, used the way Radix's own guide describes: steps 1 to 2 for backgrounds, 3 to 5 for component surfaces, 6 to 8 for borders, 11 to 12 for text. Because gray.css and gray-dark.css already scope their variables under :root and .dark, a token like --foreground: var(--gray-12) resolves correctly in both modes with a single declaration.
--background
Page surface.
--foreground
Default text on the page.
- Aa
--card
Raised panels; brighter than the page in both modes.
- Aa
--popover
Menus, selects and other floating surfaces.
- Aa
--primary
The strongest fill, used by the default button.
- Aa
--secondary
Quiet filled controls.
- Aa
--muted
Subdued backgrounds for secondary content.
- Aa
--accent
Hover and highlighted states in menus and ghost buttons.
- Aa
--marker
Highlighter yellow for emphasised text.
- Aa
--destructive
Errors and dangerous actions.
- Aa
--success
Confirmation and success states.
--border
Default borders and dividers.
--input
Borders on form controls.
--ring
Focus rings.
Where it isn't automatic
A few tokens use a different step per mode, so they need an explicit .dark override:
- Card and popover are pure white in light mode and
gray-2in dark. In both cases that is a step brighter than the page, which is the elevation convention I follow. - Destructive and success don't use Radix step 9. Step 9 is tuned for vividness rather than contrast, and against white text red and green fall below 4.5:1. Step 11 in light and step 8 in dark both clear AA, at roughly 4.7 to 5.4:1.
- Marker is a hex yellow,
#ffd34din light and#6b5200in dark. It is not a Radix step; no yellow scale is imported.
What's missing
There is no brand colour in the theme. The site's blue lives in styles/globals.css as a site token, so components stay neutral. Opacity modifiers like bg-destructive/10 are used for tinted states; they are not separate tokens.
Rules
The same rules ship in DESIGN.md and the MCP server, for the agents building with this.
- must
When you use a filled token as a background, set text with its
-foregroundpair, for examplebg-destructive text-destructive-foreground.pair-fill-with-foreground
- must
Use
destructiveandsuccessonly to mean error or danger and success; do not use them as decoration.status-colours-for-status
- must
If you change
--destructiveor--success, keep white text on them at WCAG AA (4.5:1) in both modes.That is why they use Radix step 11 in light and step 8 in dark instead of step 9.
keep-status-contrast
- should
Reserve
bg-markerwithtext-marker-foregroundfor highlighter-style emphasis, not for fills or status.marker-is-highlight
- should
Use
bg-cardorbg-popoverfor anything that sits above the page, andbg-backgroundfor the page itself.surfaces-for-elevation