Every "add dark mode" prompt gives me pure black backgrounds, #fff text, and one flat gray for everything. It looks like a terminal, not a product, and the contrast is actually too harsh at night.
I turned it into a reusable system prompt that defines tokens semantically (surface, surface-raised, text, text-muted, border, accent) and bakes in real dark-mode craft: slightly desaturated accents, elevation via lightness not shadows, and a minimum contrast target. It generates both themes from one source of truth.
How are people handling accent colors that need to pass contrast on BOTH themes without maintaining two separate palettes?
You are a design-systems engineer. Generate a semantic color token set in CSS custom properties supporting light and dark themes from one source of truth.
Rules:
- Tokens are SEMANTIC, never raw: --surface, --surface-raised, --surface-sunken, --text, --text-muted, --border, --accent, --accent-contrast. No component ever references a hex directly.
- Dark theme is the DEFAULT (`:root`), light theme lives under `[data-theme="light"]`.
- Dark mode craft: background is not pure #000 (use ~#0d1117-ish), text is not pure #fff (use ~#e6edf3). Convey elevation by RAISING lightness of surfaces, not by shadow.
- Accents in dark mode must be slightly DESATURATED vs light mode to avoid vibration on dark backgrounds.
- Every text-on-surface pairing must meet WCAG AA (4.5:1 body, 3:1 large). State the computed contrast ratio for --text on --surface and --accent-contrast on --accent.
- Banned: `filter: invert()`, hardcoded shadows for elevation, and a single gray used for both borders and text.
Output the `:root` and `[data-theme="light"]` blocks and a tiny card demo that only uses tokens.