Index: test/ward-theme.test.js
===================================================================
--- test/ward-theme.test.js	(revision 39dab6b0c3b5fd70bb2f06743430f0014384b3b7)
+++ test/ward-theme.test.js	(revision 39dab6b0c3b5fd70bb2f06743430f0014384b3b7)
@@ -0,0 +1,29 @@
+// De themakleur (SkyPalette): de presets en de leesbaarheidsregel.
+//
+// Deze acht kleuren en de luminantie-regel staan ook in Swift en Kotlin; dit is
+// de derde plek en dus de derde kans op drift. Bewaakt: dezelfde acht presets,
+// en dat de tekstkleur luminantie volgt (donker op zon, wit op nacht), niet een
+// handgehouden lijstje.
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+
+// De module leunt op localStorage en document; die bestaan niet in node. We
+// testen alleen de pure export (onSky) door hem los te importeren met een
+// minimale stub, zodat de rekenkant bewaakt is zonder een browser.
+globalThis.localStorage = { getItem: () => null, setItem: () => {} };
+globalThis.document = { documentElement: { style: { setProperty() {} } } };
+
+const { PRESETS, onSky } = await import('../src/assets/js/ward-theme.js');
+
+test('acht presets, en de vertrouwde paarse staat vooraan', () => {
+  assert.equal(PRESETS.length, 8);
+  assert.equal(PRESETS[0], 0x5A32E6);
+  assert.equal(PRESETS[7], 0x1F2937);   // nacht
+});
+
+test('de tekstkleur volgt luminantie, geen handgehouden lijst', () => {
+  // Zon is licht: donkere tekst. Nacht en paars zijn donker: witte tekst.
+  assert.equal(onSky(0xF59E0B), '#1f2430', 'zon kreeg geen donkere tekst');
+  assert.equal(onSky(0x1F2937), '#ffffff', 'nacht kreeg geen witte tekst');
+  assert.equal(onSky(0x5A32E6), '#ffffff', 'paars kreeg geen witte tekst');
+});
