dark-mode-tokens

dark mode tokens: why inverting your palette doesn’t work

Flip every hex value for dark mode and the depth disappears — a card that read as “elevated” in light mode goes flat, because that depth was never really in the color.

The instinct to treat dark mode as an inversion makes sense on the surface: light backgrounds become dark, dark text becomes light, done. But contrast ratios don't survive a blind flip, and neither does hierarchy. 

A subtle shadow that separated a card from its background in light mode has nothing to push against once the background is already dark — the elevation cue depended on the direction of light and shadow, not just the presence of two different values.

The actual fix is to stop tokening colors and start tokening roles. Instead of `--card-bg: #ffffff`, the token becomes `--surface-1`, and that token gets a different real value per theme — not a computed inversion of the light value, but a value chosen specifically to do the same job in a dark context.

Same pattern for `--text-primary`, `--border-subtle`, and every other role a component actually needs. Once every component references the role instead of a raw color, switching themes stops being a redesign and becomes exactly what it should be: swapping which value set a name points to, with the component never touched at all.

https://www.march4orthdesign.com/m4d-projects/download.html