import InfoBox from '../components/InfoBox.astro';
import PullQuote from '../components/PullQuote.astro';

A complete visual redesign replaced the game's typography and color palette across 18 catalogued surfaces, from buttons and game board tiles to tooltips and brand assets. Rather than landing dozens of isolated style edits directly on `main`, the work was structured around a dedicated token-migration decision record and sequenced through a single base branch umbrella.

## Token replacement without parallel generations

The first structural decision in the migration plan was to replace existing `--color-*` and `--font-*` custom properties directly in `src/app.css` as each phase landed. The repo did not introduce a parallel `--color-v3-*` token set to let old and new themes coexist, continuing the in-place custom property pattern set during [design-system-v2-first-attempt](/posts/design-system-v2-first-attempt#values-change-names-dont). The codebase is a single CSS file with one running instance, so parallel token generations between phases would only ever sit as dead code. Between phases, the live app on the base branch temporarily mixed old and new surfaces, which was accepted as a normal transient state rather than gated behind feature flags.

```css
--font-display: 'Baloo 2', display, system-ui, sans-serif;
--font-ui: 'Nunito', system-ui, sans-serif;
--font-weight-extrabold: 800;
```

Space Grotesk was retired in favor of Baloo 2 for headings and Nunito for body copy and buttons, while Space Mono was retained for score and game-log data. Both new fonts carry the SIL Open Font License 1.1, matching the existing font licenses and requiring no new firewall rules.

## Contrast math over raw hex

The mockup provided flat hex values, but those values were treated as a reference palette rather than raw colors to copy into CSS. Checking the mockup's raw hex against documented WCAG contrast requirements revealed four real contrast failures before any code was committed. In particular, the raw hex for banana fruit text against the light grid background produced a 2.74:1 contrast ratio, failing the 3:1 WCAG 1.4.11 threshold and repeating an exact bug previously fixed in [premature-norwegian](/posts/premature-norwegian#norwegian-in-one-evening).

<InfoBox variant="note" title="WCAG contrast verification">
Re-tuning the mockup's flat hex values into `oklch()` with lightness targets preserved the intended visual tone while guaranteeing required contrast floors across both themes.
</InfoBox>

```
dark text-muted #8f93a8 vs surface-raised #2b2c3a: 4.53:1 (needs >=4.8:1)
light text-muted #6b7280 vs surface #ffffff: 4.83:1 (needs >=5.3:1)
dark accent #e2456a vs white text: 3.97:1 (needs >=4.5:1)
banana/golden #a98a2e vs light grid #E8EAF0: 2.74:1 (needs >=3:1)
```

Re-expressing colors in `oklch()` allowed tuning lightness values specifically for perceptual uniformity while satisfying every contrast floor documented in `src/app.css`.

## Seven phases, one base branch

The implementation proceeded across seven grouped phase tickets: foundations, board tiles, notifications, duel flow, result panels, home menu, and brand assets. Each phase landed as its own focused PR targeting the base branch `docs/design-system-redesign-1067` rather than `main`, following the same umbrella pattern previously used in [norwegian-done-properly](/posts/norwegian-done-properly).

<PullQuote attribution="Token migration architecture">
main only sees this work once, when the base PR merges.
</PullQuote>

When all seven phases were complete on the base branch, the umbrella merged to `main` in a single merge commit (`a6cf9d0c`), closing all seven phase issues at once without exposing `main` to intermediate breakage.

## Catching contrast on press

A ten-minute follow-up pass addressed backspace visual treatment and replaced remaining literal `color: white` declarations with `--color-text-on-accent`. Audit testing during that follow-up surfaced a second-order bug: pressed keys hardcoded white text against a light-theme active background (94% lightness), yielding a 1.23:1 contrast ratio where pressed key labels became invisible. Removing the hardcoded color allowed pressed keys to inherit proper theme text tokens while keeping submit-key overrides intact.