iter0
Back to Blog
Agentic Web Design·

DESIGN.md for dark mode: give agents paired colour tokens

Use the same token names in light and dark mode, with explicit text and background pairs. This complete fixture uses the system colour preference and no theme switch.

John McKeown
John McKeown

6 min read

Specify the text and background together

Give an agent a rule for each colour’s job in both themes. A panel needs a background and readable text; the main action needs its own background and label colour. Asking for a darker page without naming those pairs leaves the agent to decide which text, borders and controls should change.

This example uses one set of semantic names, including --surface and --ink. The stylesheet changes their values when the browser reports a dark preference. MDN documents prefers-color-scheme as the CSS media feature for that preference. The example follows the system setting and deliberately has no manual theme control.

Copy the complete theme note

The file below tells a reviewer which pairs to check. It keeps the values in styles.css, so the note describes usage without duplicating a palette. Wrenboard is a fictional product; these theme values are a proposed example rather than a measured brand system.

Read the note through AGENTS.md when using the Codex fixture. For Claude Code or Cursor, use the corresponding loading guide. Loading the rule and producing the intended colours remain separate things to verify.

# Wrenboard light and dark themes

## Ownership
styles.css owns the light and dark token values.
Use the same --page, --surface, --ink, --muted, --action,
--on-action and --focus names in both themes.
Use the system colour preference; do not add a manual switch.

## Components
A panel uses --surface and --ink.
Supporting text uses --muted on --surface.
The main action uses --action and --on-action.
Keep its focus-visible outline in both themes.
Do not invert screenshots or add per-component colour literals.

## Review
Start a theme review with: Theme check:
Report body, panel, text and action colours in both themes.
Check normal text pairs at 4.5:1 or better.
Check hover and focus as well as the initial screen.
Do not claim a whole-site accessibility pass from this fixture.

Keep both palettes in one stylesheet

Save this complete stylesheet beside the downloadable HTML. The panel, supporting text and action all consume the same token names in either theme. The hover state changes underline thickness, leaving the action’s text and background pair intact. The focus outline has its own value in each theme.

If you already have a theme system, use its existing owner and selector instead of adding a second one. The existing CSS-conflict guide covers tracing a value back to its owning file; this example addresses the separate problem of checking both themes.

:root {
  color-scheme: light dark;
  --page: #ffffff;
  --surface: #f5f5f5;
  --ink: #171717;
  --muted: #525252;
  --action: #202020;
  --on-action: #ffffff;
  --focus: #1d4ed8;
}
@media (prefers-color-scheme: dark) {
  :root {
    --page: #171717;
    --surface: #262626;
    --ink: #fafafa;
    --muted: #d4d4d4;
    --action: #fafafa;
    --on-action: #171717;
    --focus: #93c5fd;
  }
}
* { box-sizing: border-box; }
body { margin: 0; padding: 1.5rem; background: var(--page);
  color: var(--ink); font: 1rem/1.6 system-ui, sans-serif; }
main { max-width: 50rem; margin: auto; }
.panel { padding: 1.5rem; background: var(--surface); color: var(--ink); }
.supporting { color: var(--muted); }
.button-primary { display: inline-flex; padding: .65rem 1rem;
  min-height: 44px; background: var(--action); color: var(--on-action); }
.button-primary:hover { text-decoration-thickness: 3px; }
.button-primary:focus-visible { outline: 3px solid var(--focus);
  outline-offset: 3px; }

Inspect the rendered pairs in both themes

Open the supplied HTML and use your browser’s rendering tools to emulate light and dark preferences. Inspect the computed background and text colours on body, the panel, the supporting paragraph and the main action. A token declaration alone does not tell you which later CSS rule wins.

For normal text, WCAG 2.2’s minimum contrast criterion is 4.5:1; qualifying large text has a 3:1 threshold and the criterion has other exceptions. This fixture chooses 4.5:1 as its check for all its text pairs. That is a proposed test for this sample, not a statement that contrast alone establishes accessibility. Tab to the link and inspect its outline in both modes.

On 3 November 2026, we calculated contrast from the exact hex values in the downloadable stylesheet. All eight declared text pairs exceeded 4.5:1; the lowest was supporting text in the light theme at 7.167:1. These are source-palette calculations using the WCAG contrast formula, not measurements of computed browser styles. A later overriding style could change the rendered pair.

Calculated text contrast from the declared light and dark palettes
Text roleLight contrastDark contrast
Body17.928:117.176:1
Panel16.444:114.499:1
Supporting7.167:110.210:1
Action label16.293:117.176:1

Use the complete page and a bounded review request

The page contains a panel, supporting text and a link to an access note. There is no form service. Save index.html and styles.css together, then compare the same page in both themes at 390 and 1440 pixels. Keep the content identical so the comparison concerns theme behaviour.

Ask an agent to report each computed text and background pair, then check those numbers in the browser. If it cannot run a browser, its source review should say so. The downloadable AGENTS.md points to the design note; it does not supply a browser tool or guarantee an accurate review.

<!doctype html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Wrenboard theme fixture</title><link rel="stylesheet" href="styles.css">
</head><body><main><h1>Keep interview notes together</h1>
<section class="panel"><h2>Beta access</h2>
<p class="supporting">Ask the product owner for an invitation.</p>
<a class="button-primary" href="#access">Request access</a></section>
<p id="access">This local sample does not collect submissions.</p>
</main></body></html>

What this example has and has not proved

On 3 November 2026, Codex CLI 0.162.1 reviewed the supplied fixture with codex exec -s read-only and the exact prompt below. It read AGENTS.md, DESIGN.md, styles.css and index.html. Its reply began: “Theme check: No concrete mismatches found in `index.html` and its linked `styles.css`.” It quoted the theme rules and calculated all eight text contrast ratios from the stylesheet, each above 4.5:1. The command exited 0 without changing files.

The run loaded the user’s global configuration too. This is one source review of a compliant fixture; the calculated ratios are not computed browser measurements or a whole-site accessibility result. Separate source checks parsed the CSS, resolved its tokens and confirmed the access target. MDN and W3C documentation was checked on 3 November 2026. A separate native Chrome check at 390 by 844 showed both themes, keyboard focus and a link reaching #access.

Before adding the example to a real site, test its longest text, actual media and form states in both themes. A product image may already have the right colours; do not invert it merely because the surrounding page changes.

Review index.html against the project instructions in this folder. Read files only; do not edit. List each concrete mismatch between the page and the instructions, quoting the instruction you rely on.

Put the brief into practice

A launch page should make the buyer, promise, proof, and next action obvious. iter0 uses this same standard when it turns a brief or reference site into a builder-ready page.

Start your launch build

Common questions

Does this example need a dark-mode button?

No. It follows the system colour preference through CSS. Add a manual control only if that is a separate requirement for your site.

Why use the same token names in both themes?

The component keeps referring to its role, such as surface or text, while the stylesheet supplies each theme’s values. Check the actual computed pair in both modes.

Do these checks prove the whole website is accessible?

No. Text contrast and visible focus cover only part of a review. Check the actual page content, keyboard behaviour, forms and other applicable requirements.