// The light theme rests on four things that are all easy to break without noticing, // because breaking any of them still looks correct in whichever theme you happen to be // developing in: // // - The boot script decides the theme before first paint. If it stops being blocking, // or stops being reachable under the page's CSP, the site paints dark and corrects // itself a moment later — the flash that a theme switch exists to avoid. // - Every colour token is declared in both palettes. One missing from the light block // silently falls back to the dark value, which is how you get white text on white. // - No component re-introduces a literal colour. One hard-coded hex is invisible in // dark and unreadable in light. // - "System" is stored as a mode, not as the colour it resolved to. Storing 'dark' // when the user asked to follow the system means the page stops following it. import assert from 'node:assert/strict'; import { readFileSync, readdirSync } from 'node:fs'; import { JSDOM } from 'jsdom'; const read = (rel) => readFileSync(new URL(`../${rel}`, import.meta.url), 'utf8'); const themeCss = read('src/styles/theme.css'); const bootJs = read('src/scripts/theme-boot.js'); const switcher = read('src/components/ui/ThemeSwitcher.jsx'); const header = read('src/components/ui/Header.jsx'); const template = read('templates/index.template.html'); // ── The boot script has to win the race against first paint ────────────────────────── { const tag = template.match(/