Acceptance Criteria
- Every
--rf-*: value; declaration in packages/lumina/tokens/base.css has a corresponding entry in the new ThemeTokensConfig — luminaTokens exported from @refrakt-md/lumina/transform covers all 60+ declarations - Every dark-mode declaration in
packages/lumina/tokens/dark.css migrated to modes.dark per WORK-188 packages/lumina/tokens/base.css and dark.css deleted; the generated stylesheet from the config replaces them in the published package (deferred — hand-authored CSS continues to ship through the v0.14.0 window so consumers see no behavioural change. A follow-up replaces it with build-time generation once the SvelteKit adapter integration lands.)- CSS coverage tests in
packages/lumina/test/token-config-coverage.test.ts pass against the generated output — every declaration in the hand-authored CSS is present in the generated CSS with the same value, scoped to the right block (:root for base, [data-theme="dark"] for dark) - Visual regression: a baseline screenshot of the refrakt site rendered against today's Lumina matches the same site rendered against the new config-driven Lumina, pixel for pixel (deferred to follow-up — meaningful once generation replaces hand-authored CSS at build time)
- The published
@refrakt-md/lumina package's runtime output (CSS file, types) preserves the current --rf-* custom property names — the hand-authored CSS continues to ship; the new luminaTokens export is purely additive - No site or plugin needs to change anything to render identically — Lumina remains a drop-in for what existed before
Scope split. This work item ships the source-of-truth migration — Lumina now exports luminaTokens as a typed ThemeTokensConfig that adapters and downstream tooling can consume. The hand-authored tokens/base.css and tokens/dark.css continue to ship alongside; a coverage test keeps the two in lockstep, so any drift fails CI. Replacing the hand-authored CSS with build-time generation is deferred to a follow-up PR alongside the SvelteKit adapter integration — both are needed for the runtime injection of site-level token overrides, which is the user-visible feature.
Approach
Mechanical conversion. Read base.css and dark.css, build the equivalent ThemeTokensConfig object, run side-by-side visual checks.
Where the current CSS does things the JSON config can't directly express (e.g. color-mix() calculations, media queries beyond prefers-color-scheme), keep those as a small supplementary CSS file imported alongside the generated stylesheet. Document any such exceptions in the config or a comment in the lumina package — they're escape hatches the contract intentionally leaves open.
The Plex Sans / Plex Mono fonts that tideline will use are not set on Lumina's base here — Lumina's base keeps Outfit for the migration step. The font swap is part of WORK-203 (Google Fonts loading) and WORK-200 / WORK-204 (which surface gets which fonts).
This is the work item that lets later items in the milestone proceed against a config-driven Lumina without rebuilding the migration each time.
Dependencies
- WORK-185 — types must exist.
- WORK-187 — stylesheet generation pipeline must work.
- WORK-188 — mode overlay support must work.
- WORK-186 — syntax token rename must land first so the contract reflects the new names.
References
- SPEC-048 — the contract this work materialises in Lumina
packages/lumina/tokens/base.css, packages/lumina/tokens/dark.css — files being migrated