diff --git a/docs/superpowers/specs/2026-07-12-epicnext-multitheme-design.md b/docs/superpowers/specs/2026-07-12-epicnext-multitheme-design.md new file mode 100644 index 00000000..21f23b05 --- /dev/null +++ b/docs/superpowers/specs/2026-07-12-epicnext-multitheme-design.md @@ -0,0 +1,76 @@ +# EpicNext multitheme design + +## Goal + +Make every built-in EpicNext preset visually complete in both light and dark mode. The administrator selects the global preset; each visitor may independently choose its light or dark variant without replacing the selected palette with a generic hardcoded theme. + +The CMS information popup is rebranded from AtomCMS to EpicNext as part of the same visual consistency update. + +## Current problem + +The application currently combines two unrelated systems: + +- `ThemeVars` injects database-controlled colors into `:root`. +- `html.dark` in `globals.css` replaces many of those colors with one hardcoded dark palette. + +Consequently, every preset loses its identity in dark mode. Presets also define only a subset of the colors accepted by the theme editor, so values such as secondary buttons, danger buttons, outline buttons, links, and gradients can leak from the previously selected preset. + +## Theme model + +Each built-in preset will expose two complete variants: + +```ts +type ThemeMode = "light" | "dark"; +type ThemePalette = Record; +type ThemePreset = Record; +``` + +`ThemeColorKey` is the single canonical list shared by presets, the admin form, persistence, runtime CSS generation, and tests. It includes all color values used by the editor and `ThemeVars`, including semantic colors, every button family, links, borders, and gradients. + +The administrator-selected preset remains global. The visitor preference stored in `localStorage` remains only `light` or `dark`. + +## Runtime flow + +1. The administrator applies a preset. +2. Both complete variants are persisted using mode-qualified setting keys. +3. `ThemeVars` reads both variants and emits variables for `:root` and `html.dark`. +4. The pre-paint initialization script applies the visitor's saved mode, or the configured default mode. +5. The browser changes mode by toggling the existing `dark` class. It does not replace the preset. + +The hardcoded palette currently declared in `html.dark` will be reduced to non-color behavioral rules. All dark-mode colors will come from the active preset. + +## Custom themes + +The admin editor will display light and dark sections. Saving updates both variants as one operation. Existing unqualified settings remain the source for the initial light variant so current installations retain their configured appearance. + +For installations without dark-specific settings, EpicNext will use the selected preset's dark variant. This provides a deterministic migration path without trying to generate unreliable dark colors at request time. + +Applying a preset writes every canonical color key for both modes. This prevents values from an earlier preset leaking into the newly selected one. + +## Contrast and fallback behavior + +Readable foreground variables continue to be derived independently for each mode. Invalid custom color input is rejected by the existing sanitizer. Missing keys fall back to the corresponding complete built-in palette, never to values from another preset. + +## EpicNext popup + +The footer trigger and popup copy will use EpicNext branding: + +- `EpicNext Info` trigger +- `EpicNext` title +- `Modern Next.js CMS` badge +- EpicNext-focused description and credits + +The popup continues to use semantic CSS variables, so it follows both variants of every preset. + +## Verification + +Automated tests will verify: + +- every preset supplies every canonical key in both modes; +- every foreground/background semantic pair meets the existing contrast requirement; +- applying one preset cannot retain keys from another preset; +- runtime CSS contains separate light and dark values; +- the mode toggle only changes mode and preserves the active preset; +- the EpicNext popup renders its new branding. + +Build, typecheck, and the complete test suite are required before publication.