Modules
Module: a dark-only (or light-only) product
The template's site and app both follow the reader's system appearance. The site's skins must be the app's skins: a marketing page readable in a skin the software has never worn is a page showing a product that does not exist. If your app forces one appearance, force the same one on the site.
The app
On every window the app creates (AppDelegate.makeWindow,
makeSettingsWindow):
window.appearance = NSAppearance(named: .darkAqua)
Palette colours resolve against the drawing appearance, so they follow
automatically. Previews only approximate this with .preferredColorScheme —
AppKit controls take their look from the window, which a preview does not have.
The site
site/app/globals.css: replace everylight-dark(a, b)pair with its dark half, keep the plain:rootfallback block equal to those dark values, and changecolor-scheme: light dark;tocolor-scheme: dark;.site/lib/palette.ts: makePALETTE.lightequal toPALETTE.dark, or deletelightand updatesite/lib/palette.test.tsto compare onlydark.site/lib/palette.test.ts: change the expected declaration tocolor-scheme: dark;.site/app/layout.tsx:viewport.themeColorbecomes one colour — a pair would wrap a near-black page in a pale browser toolbar on a light-mode Mac.site/app/globals.csslaunch badges: keep only the dark image.
Do not add a theme switch. A source project "disabled" its light theme by
pinning color-scheme near the top of the stylesheet, while a
[data-theme="light"] selector forty lines down had equal specificity and later
source order. Driven by a localStorage entry with no control left on screen
to undo it, it painted the wrong skin for every returning visitor — with every
check green. The palette test refuses theme-attribute selectors for this
reason.
What stays light regardless
- Email (
EMAILinsite/lib/palette.ts). Gmail re-colours dark mail by heuristic and turns light-on-dark into light-on-light. The palette test asserts the email colours stay light. - The favicon and app icon: drawn on somebody else's tab strip and Dock, whose colour is theirs.
- The OG card is dark in both cases (see
site/app/opengraph-image.tsx).
Verify
cd site && pnpm test (the palette weld and contrast checks), then
mac/scripts/check-palette.sh — which still compares both columns, so keep the
Swift pairs equal to the site's.
This page is docs/modules/theme.md in the repository, copied 2026-09-25.