# Theme + Sprache Toggle (Issue #13) — Design **Status:** Design (Shift-1, Inventor) — Pilot auf 4 Sites. Awaiting m's go-ahead vor Rollout. **Branch:** `mai/cronus/issue-13-light-dark-en` **Issue:** [m/onepager#13](https://mgit.msbls.de/m/onepager/issues/13) ## Was bereits da ist (Stand 2026-05-07) - `shared/i18n.js` — DE/EN Toggle, `[data-i18n-toggle]` Buttons, navigator.language Detection, localStorage Persistence (`onepager-lang`), MutationObserver auf `lang`. Alle 59 Sites annotiert. - 33 Dark-Sites haben unique-Palette (Issue #12 Audit + Lift). - Existing Toggle-Position: **Footer** — kleine Pill `EN`/`DE` plus statische Disclaimer-Zeile "Maschinell übersetzt". - 4 Light-Templates existieren (`person-light.html`, `product-light.html`) — werden derzeit von keiner Site benutzt; Custom-Sites haben hardcoded Dark. ## Ziel Kombiniertes Toggle-Widget oben rechts, **fixed**. Zwei Buttons in einer Pill: ``` ┌──────────────┐ │ ☀ │ EN │ ← Dark-Mode aktiv: Sonne (Klick → light), "EN" (Klick → english) └──────────────┘ ``` - **Theme-Toggle**: Sonne/Mond Icon, persistiert in `localStorage("onepager-theme")`, Initial-Default = `prefers-color-scheme` Media-Query. - **Lang-Toggle**: existing `[data-i18n-toggle]` Pattern (recht-Button im Widget bekommt das Attribut, i18n.js übernimmt Logik). ## Architektur-Entscheidungen ### 1. Eine Datei oder zwei? **Entscheidung:** Zwei Dateien — `shared/theme.js` (theme logic) + `shared/toggles.js` (UI widget). - **Trennung Logic ↔ UI** — theme.js ist die Quelle der Wahrheit für `data-theme` Attribut + localStorage. Tests, alternative UI, programmatischer Aufruf bleiben möglich. - **toggles.js** ist ein optionales UI-Layer das beide bestehenden Skripte konsumiert (i18n.js's `[data-i18n-toggle]` + theme.js's `window.onepagerTheme`). - Sites mit eigenem custom-Toggle-UI (zukünftig denkbar) können `toggles.js` weglassen, aber `theme.js` behalten. ### 2. CSS-Pattern: `[data-theme]` Attribut auf `` ```css /* Default = dark, no attr */ :root { --bg: #0a0a0c; --text: #e8e8ed; --accent: #c9a84c; } /* Light overrides — gleiche Variablen, andere Werte */ [data-theme="light"] { --bg: #faf9f6; --text: #1a1a1a; /* --accent bleibt erhalten (Site-Identität) */ } ``` **Warum `[data-theme]` auf ``** (nicht `class="light"`): - HTML-Attribut ist von der CSS-Cascade aus exakt gleich spezifisch wie `:root`. Per Source-Order kann man Defaults setzen und überschreiben — vorhersehbar. - Kompatibel mit dem `prefers-color-scheme` Pattern: ein Dataset-Hook ohne Klassen-Kollision. - Inline-Anti-FOUC-Script muss nur **ein Attribut** setzen, nicht eine Klasse + DOM-Manipulation. ### 3. Anti-FOUC: Inline-Pre-Script in `` **Kritisch.** Wenn der Theme erst nach Page-Load gesetzt wird, sieht der User für ~50–200ms das Default-Theme bevor sein gespeichertes Theme angewandt wird → flackernder Modus-Switch. ```html ... ``` - Inline IIFE — synchron, **vor** `