Files
mindflux/mindfluxrefine2.md
T
AliceDarkest 3bc6c8f75c
mindflux-ci / build (push) Successful in 36s
Refine Light Mode, UX und Mail-Diagnose
2026-07-22 13:04:25 +02:00

306 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mindflux — Refine 2: Light-Mode-Konzept, Scroll-Verhalten, Restpunkte
## Kontext
Folgeplan zu `mindfluxrefine.md`. Die Code-Verifikation (2026-07-21) bestätigt: **alle „vollständig"-Claims aus Refine 1 halten der Prüfung stand**; offen sind AP 1e (Glow im Light Mode), der AP-7-Rest sowie einige Zusatzfunde (s. AP R5). Dieser Plan liefert das, was Refine 1 offen ließ: ein **echtes Light-Mode-Konzept**, das alle Probleme an der Wurzel behebt (statt Glow-Alphas weiter zu dimmen), plus das neue Thema **Scroll-Verhalten** (Ergebnisanzeigen u. ä. müssen oben starten, nicht unten).
**Audit-Kurzbefunde (2026-07-21, drei unabhängige Durchgänge):**
- **Light-Mode-Strukturfehler:** Der Light-Block in `theme.css` tauscht nur *Farbwerte/Alphas* der Glow-Tokens. Die *Geometrie* der Effekte (`box-shadow:0 0 20px …`, `text-shadow:0 0 12px …`, `drop-shadow(0 0 8px …)`) steht hart in ~70 Komponentenregeln quer durch `theme.css`, alle Spiele-CSS und Template-`<style>`-Blöcke. Ein Halo mit reduziertem Alpha bleibt ein Halo — auf Fast-Weiß liest er sich als Schmutz/Haze. Einzige strukturell adaptierte Stelle heute: `--g-soft` (`0 0 18px` dark → `0 6px 18px` light, `theme.css:31/53`). Genau **eine** Regel neutralisiert einen Glow explizit im Light Mode (`auth.css:127–128`).
- **5 im Light Mode kaputte Stellen:** Login-Overlay weiß-auf-weiß (auth.css:123–127 × platform-neural.css:94), SyntaxSaga-Bühne bleibt schwarz (`syntaxsaga.css:250–251`), CodeEscape-Eingaben dunkel-auf-dunkel (`codeescape.css` `.esc-input` `#080604`), NetWorker-Guide-Panel dunkelnavy mit Light-`--muted` (`networker-guide.css`), Farbenblind-Palette × Light = Hellgelb/Hellblau auf Weiß (`accessibility.css:15–23`, `!important` schlägt die Light-Kartenakzente).
- **Theme-Bootstrap-Lücken:** `color-scheme` fehlt komplett (native Scrollbars/Form-Controls folgen dem UA-Default), kein `theme-color`-Meta, kein `prefers-color-scheme`-Fallback (Erstbesucher mit OS-Light starten dunkel), alle Templates hardcoden `data-theme="dark"`.
- **Scroll:** Im gesamten Projekt existiert **kein einziger** `scrollTo`/`scrollIntoView`/`scrollRestoration`-Aufruf (außer Chat-Autoscroll `neuralnet.js:84`, der korrekt ist). Die vier SPA-Spiele (BugHunter, CodeEscape, NetWorker, ServiceClash) ersetzen Views per `innerHTML` ohne Reset; der FinalProtocol-Quiz kollabiert am Ende einer langen Lernseite (Browser clampt ans neue Seitenende); SyntaxSaga/DevLab fokussieren Inputs ohne `preventScroll`.
- **CSS-Leichen:** `achievements.css`, `progress.css`, `settings.css`, `soziales.css` werden nirgends mehr referenziert (repo-weiter Grep leer); `style.css` wird nur noch von `finalflux.html` geladen, ~90 % davon ist toter Dark-Code.
Basis-Pfad: `RES` = `src\main\resources`
---
## Das Konzept: „Licht statt Leuchten"
**Prinzip:** Dark Mode und Light Mode sind Geschwister mit derselben Farbidentität, aber unterschiedlicher *Physik*:
| | Dark Mode | Light Mode |
|---|---|---|
| Metapher | Neon in der Nacht — Elemente **emittieren** Licht | Druck/Material am Tag — Elemente **werfen Schatten** |
| Betonung | farbiger Glow (Halo) | **Elevation** (weicher, warm getönter neutraler Schatten) |
| Identität/Wiedererkennung | Glow-Farbe | **Akzentfarbe direkt am Element** (Border, Text, Icon) — ist durch `--border-accent`, Icon-Farben und Kartenakzente bereits überall vorhanden |
| Text-Halos | ja (`text-shadow`) | **nie** (liest sich als Unschärfe) |
| Fokus-Ringe | farbig, weich | farbig, **crisp** (Ring statt Blur — funktional, bleibt farbig) |
| Scrims/Overlays | dunkel | dunkel (funktional), aber leicht entschärft |
**Mechanik:** Effekte werden zu **Primitives** — komplette `box-shadow`/`filter`/`text-shadow`-*Werte* als Tokens, nicht nur Farben. Komponenten schreiben nie mehr `0 0 20px var(--glow-s)`, sondern `var(--g-strong)`. Der Light-Block tauscht dann die *Kategorie* des Effekts (Glow → Elevation), nicht nur die Farbe. Dark bleibt visuell gleich (Blur-Radien werden auf die Primitive normalisiert; ±4 px sind nicht unterscheidbar). `--glow-s`/`--glow-w` bleiben als Farb-Tokens bestehen — die Spiele-CSS remappen sie bereits per `color-mix` auf ihre Akzente, und die Primitives referenzieren sie per `var()`, sodass Spiel-Glows im Dark Mode automatisch die Spielfarbe behalten.
---
## AP R0 — Aufräumen (erledigt 2026-07-22)
1. **Erledigt:** Verwaiste CSS gelöscht: `achievements.css`, `progress.css`, `settings.css`, `soziales.css`. Die Referenzprüfung ergab 0 Treffer; STYLEGUIDE bereinigt.
2. **Erledigt:** `style.css` auf eine vierzeilige Basis für die 40 statischen
FinalProtocol-Lernseiten reduziert; FinalProtocol-Hub lädt sie nicht mehr.
3. **Erledigt:** Nicht eingebundenes `finalflux-check.js` entfernt. `fluxtimer.css` bleibt separat offen, da die Datei in diesem Paket nicht geändert wurde.
---
## AP R1 — Effekt-Primitives (Kern des Light-Konzepts)
### R1a. Tokens in `RES\static\css\theme.css` — erledigt 2026-07-22
In den Dark-Block (Z. 11–32) und Light-Block (Z. 33–54) ergänzen. Schattenfarbe Light ist **warmes Braun** `rgb(67,48,26)` (zur Creme-Palette passend, kein totes Grau/Schwarz):
```css
:root, [data-theme="dark"] {
/* … bestehende Tokens … */
color-scheme:dark;
--g-text:0 0 12px var(--glow-s); /* Text-Halo: Logo, Headline-Akzent, *-brand b */
--g-icon:drop-shadow(0 0 8px var(--glow-s)); /* leuchtende Glyphen/Embleme */
--g-strong:0 0 20px var(--glow-s); /* starke Betonung: aktive Nav/Tabs, Primär-Btn */
--g-amb:0 0 14px var(--glow-w); /* dezenter Schein: Icon-Hover, Toggle, Burger */
--g-card:drop-shadow(0 0 7px var(--glow-w)); /* Spielkarten-Grundzustand */
--g-card-hover:drop-shadow(0 0 16px var(--glow-s));
--g-overlay:0 24px 60px rgba(0,0,0,.5); /* schwebende Panels: Guide, Drawer, A11y */
--g-focus:0 0 0 3px var(--glow-w); /* Fokus-Ring (bleibt in beiden Themes farbig) */
--scroll-thumb:var(--line);
}
[data-theme="light"] {
/* … bestehende Tokens … */
color-scheme:light;
--bg-glow: radial-gradient(900px 420px at 60% -10%, rgba(214,81,22,.05), transparent 60%); /* statt .10 — Haze halbieren */
--g-text:none;
--g-icon:none;
--g-strong:0 2px 10px rgba(67,48,26,.18), 0 1px 3px rgba(67,48,26,.10);
--g-amb:0 1px 5px rgba(67,48,26,.10);
--g-card:drop-shadow(0 2px 5px rgba(67,48,26,.10));
--g-card-hover:drop-shadow(0 8px 18px rgba(67,48,26,.16));
--g-overlay:0 18px 44px rgba(67,48,26,.20);
--g-focus:0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
--scroll-thumb:#d9cbb2; /* --line #f1e8d8 ist auf #fbf6ec unsichtbar */
}
```
Scrollbar-Regel `theme.css:64` auf `background:var(--scroll-thumb)` umstellen.
### R1b. Mechanische Migration in `theme.css`
| Zeile | Selektor | Alt | Neu |
|---|---|---|---|
| 79 | `.mf-logo .mark` | `drop-shadow(0 0 8px var(--glow-s))` | `filter:var(--g-icon)` |
| 80 | `.mf-logo .txt b` | `text-shadow:0 0 12px var(--glow-s)` | `text-shadow:var(--g-text)` |
| 87 | `.mf-nav a.active` | `0 0 20px var(--glow-s)` | `box-shadow:var(--g-strong)` |
| 94 | `.mf-avatar` | `0 0 14px var(--glow-s)` | `box-shadow:var(--g-strong)` (gleiche Farbstärke-Familie wie heute) |
| 102/104 | `.mf-streak .fire` / `.mf-brain` | drop-shadows | `filter:var(--g-icon)` |
| 109 | `.mf-hello h1 .nm` | `text-shadow:0 0 16px var(--glow-s)` | `text-shadow:var(--g-text)` |
| 113/120/202 | iconbtn-Hover / `.mf-theme` / `.mf-burger` | `0 0 14px var(--glow-w)` | `box-shadow:var(--g-amb)` |
| 128/130 | `.mf-card` / `:hover` | drop-shadow 7/16px | `filter:var(--g-card)` / `var(--g-card-hover)` |
| 131 | `.mf-card .ico` | drop-shadow | `filter:var(--g-icon)` |
| 136 | `.mf-card:hover .mf-play` | `0 0 16px var(--glow-s)` | `box-shadow:var(--g-strong)` |
| 146 | `.mf-panel.accent` | `0 0 20px var(--glow-w)` | `box-shadow:var(--g-amb)` |
| 151 | `.mf-bar > i` | `0 0 10px var(--glow-s)` | eigenes Primitive `--g-bar` (dark `0 0 10px var(--glow-s)` / light `none`) — der Balken trägt seine Farbe selbst, im Light braucht er keinen Hof |
| 154 | `.mf-btn` | `0 0 18px var(--glow-s)` | `box-shadow:var(--g-strong)` |
| 168 | Input-Fokus | `0 0 0 3px var(--glow-w)` | `box-shadow:var(--g-focus)` |
| 182 | `.mf-cardbox` | `0 0 30px var(--glow-w)` | Hero-Aura: Zweizeiler — Basis `box-shadow:var(--g-strong)`, plus `[data-theme="dark"] .mf-cardbox{box-shadow:0 0 30px var(--glow-w)}` |
| 223 | Mobile `.mf-sidebar` | `0 18px 50px rgba(0,0,0,.55)` | `box-shadow:var(--g-overlay)` |
| 238 | `.mf-tab.active` | `0 0 18px var(--glow-s)` | `box-shadow:var(--g-strong)` |
### R1c. `platform-neural.css`
Hat als einzige Datei schon gute Struktur-Overrides (Z. 91 ersetzt Schwarz- durch Grünschatten — Vorbild). Nachziehen: Z. 87 Logo-Drop-Shadow im Light auf `filter:none`; Z. 90 äußeren `0 0 13px`-Glow der aktiven Nav im Light streichen (Inset-Ring reicht). Die `--glow-s`-Kartenwerte (Z. 41–49/99–107) bleiben — sie speisen nach R1b nur noch Dark-Effekte.
### R1d. Spiele-CSS + Guide/Widget-CSS migrieren
Gleiches Muster in allen Dateien; die Spiel-`--glow-s`-Remaps (z. B. `mindmatch.css:364`) bleiben unverändert und speisen die Primitives automatisch mit der Spielfarbe. Betroffene Stellen (Audit-Inventar):
- **Text-Halos** → `text-shadow:var(--g-text)`: `syntaxsaga.css:40`, `mindmatch.css:53`, `techtacular.css:48`, `devlab.css` (`.dl-tube span`), `devlabgame.css` (Header-Titel), `codeescape.css` (`.esc-brand b`, `.esc-result .score`), `bughunter.css` (`.bh-brand b`, Stamp), `networker.css` (`.nw-brand b`, `.nw-final-score`), `serviceclash.css` (`.sc-brand b`, `.sc-score`), `auth.css:74` (`.auth-head b`), `style.css:89` (falls nach R0 noch vorhanden), Template-`<style>`: `progress.html:14` (Prozentzahl).
- **Box-Glows** → `var(--g-strong)`/`var(--g-amb)` nach Gewicht: `syntaxsaga.css:37/70/100/125/136/200/229/233`, `mindmatch.css:40/106/226/237/280/287/299/324`, `techtacular.css:39/75/174/207/299`, `devlab.css:102/158/173`, `devlabgame.css:10/12/23/49/61/70/78/106/108`, `codeescape.css` (Buttons/Dialog/Hero — Hero-`0 0 50px` als Dark-only-Zweizeiler wie `.mf-cardbox`), `codeescape-guide.css` (`.esc-how .active`, `.esc-door.ready`, `.esc-input.bad`), `bughunter.css`, `networker.css`, `serviceclash.css` (`.sc-meter i`), `fluxtimer.css:6/7`, `accessibility.css:29`, `accessibility-placement.css:2/16`, `auth.css:14/34/88/98` (`.neon-btn` inkl.: den `::before`-Conic-Blur-Rotor Z. 95/99 im Light per `display:none`).
- **Fokus-Ringe** → `var(--g-focus)`: `syntaxsaga.css:160`, `devlabgame.css:35/39`, CodeEscape-Inputs.
- **Schwarz-Schatten** → `var(--g-overlay)` bzw. warm getönt: `game-guide.css:72`, `accessibility.css:30`, `accessibility-placement.css:17`, `fluxtimer.css:8` (+ Z. 14 `inset`-Schwarz auf hellem Display im Light entfernen), `serviceclash.css` (`.sc-card`), `bughunter.css` (Drawer, dort auch die im Light unsichtbaren `rgba(255,255,255,.09–.16)`-Inset-Highlights auf Light-Varianten umstellen).
- **Scrims** (funktional, bleiben dunkel, aber vereinheitlichen): `mindmatch.css:309`, `techtacular.css:192`, `syntaxsaga.css:216`, `devlabgame.css:104` — im Light auf das Muster `game-guide.css:138` (`rgba(15,23,42,.5)`) wechseln, damit sich nicht zusätzlich der warme `--bg-glow`-Radial über den Scrim legt (`var(--bg-glow)` aus den Scrim-Deklarationen entfernen).
- **Hint-Glow** `game-guide.css:155/160–161` (`#ffd54a`): Light-Override `[data-theme="light"] .mm-card.hinted { box-shadow:0 0 0 2px #8a6a06, 0 4px 12px rgba(67,48,26,.18); filter:none; }` (Warn-Ton aus dem Light-Block).
### R1e. Chart/Dashboard-`<style>`-Blöcke
`dashboard.html:14/16/18/20/29/31/43/46/171`, `achievements.html:12–16`, `admin/dashboard.html:17–19`, `impressum.html:12`, `profile.html:11`: alle `text-shadow`/`drop-shadow`/`0 0 Npx`-Vorkommen auf die Primitives umstellen (Suchmuster: `grep -n "glow\|text-shadow\|drop-shadow" RES\templates -r`).
---
## AP R2 — Kaputte Light-Stellen (kritische Punkte erledigt 2026-07-22)
### R2a. Login/Registrierung: Overlay weiß-auf-weiß (kritisch)
Ursache: `auth.css:123–127` setzt für Light `#fff`-Text/weiße Ghost-Border (Annahme: kräftiges Orange-Panel), aber auf der Plattform übersteuert `platform-neural.css:94` den Overlay-Grund mit Fast-Weiß. Fix in `platform-neural.css` (Light-Sektion, höhere Spezifität durch `.sn-platform` gewinnt gegen auth.css):
```css
html[data-theme="light"].sn-platform body .overlay-panel h3 { color:#10291f; text-shadow:none; }
html[data-theme="light"].sn-platform body .overlay-panel p { color:#3c554a; }
html[data-theme="light"].sn-platform body .ghost-btn { color:#167a52; border-color:rgba(22,122,82,.55); }
html[data-theme="light"].sn-platform body .ghost-btn:hover { background:rgba(22,122,82,.10); }
```
### R2b. SyntaxSaga: Bühne bleibt schwarz (kritisch)
`syntaxsaga.css:250–251` hardcodet `#07100b` + grüne Scanlines. Light-Block ergänzen (Palette: helles Bühnen-Grün zur Light-`--ss-accent` `#277d49`):
```css
[data-theme="light"] body.ss-body {
background:radial-gradient(1100px 500px at 50% -10%, rgba(39,125,73,.08), transparent 60%), #eef6f0;
}
[data-theme="light"] body.ss-body::before {
background:repeating-linear-gradient(0deg, rgba(16,64,40,.05) 0 1px, transparent 1px 4px);
}
```
### R2c. CodeEscape: Terminal-Eingaben & Dark-Inks (kritisch)
- `.esc-input, .esc-select` (`#080604`): Light-Override `[data-theme="light"] .esc-input, [data-theme="light"] .esc-select { background:#fffaf0; color:var(--text); border-color:var(--border); }` — Dark behält den Terminal-Look.
- Hardcodierte Dark-Inks auf Akzentflächen durch das Token ersetzen (funktioniert in beiden Themes): `.esc-btn:hover`/`.primary` `#160d00` → `var(--accent-ink)`; `codeescape-guide.css` `.esc-fragment small` `#160d00` → `var(--accent-ink)`; `.esc-how .done b` `#06120a` → `var(--accent-ink)`.
- Tote Scanlines `rgba(255,255,255,.018)` (`codeescape.css`, `theme.css:138`): im Light-Override auf `rgba(67,48,26,.04)` drehen oder streichen.
### R2d. NetWorker-Guide: dunkles Panel (kritisch)
`networker-guide.css` (`.nw-guide` `color-mix(#0b2540 74%, var(--surface))`): Light-Block ergänzen:
```css
[data-theme="light"] .nw-guide { background:var(--surface); border-color:#d3e2f0; box-shadow:var(--g-soft); }
```
(Textfarben laufen dort über `var(--muted)`/`var(--text)` und stimmen dann automatisch.)
### R2e. Farbenblind-Palette × Light (kritisch)
`accessibility.css:15–23` erzwingt helle Okabe-Ito-Akzente per `!important` — auf weißen Karten < 1.5:1. Neuen Satz `html[data-theme="light"][data-mf-color="safe"]` mit **abgedunkelten** Okabe-Ito-Entsprechungen ergänzen (gleiche Zuordnung Spiel→Farbfamilie wie im Dark-Satz, Werte rechnerisch ≥ 4.5:1 auf Weiß, beim Umsetzen mit Kontrast-Tool gegenprüfen):
| Okabe-Ito (dark) | Light-safe |
|---|---|
| `#e69f00` Orange | `#8a5f00` |
| `#56b4e9` Himmelblau | `#19607f` |
| `#009e73` Grün | `#007054` |
| `#f0e442` Gelb | `#7a6a00` |
| `#0072b2` Blau | `#0072b2` (bleibt) |
| `#d55e00` Vermillion | `#a94500` |
| `#cc79a7` Purpur | `#9c4f79` |
Die zugehörigen Glow-Alphas entfallen im Light automatisch über die Primitives (R1).
### R2f. Kleinere Light-Fixes
1. **Cancel-Hover** `mindmatch.css:128–129`, `techtacular.css:94` (`#fff` auf Blassrosa): Light-Override `[data-theme="light"] .mm-cancel:hover, …` → `background:var(--danger); color:#fff;` (Light-Danger `#be123c`, 7:1). Dark bleibt unverändert.
2. **A11y-Widget-Inks:** `accessibility-placement.css:7–15` hardcodet dunkle `--mf-a11y-ink`-Werte — im Light sind die Akzente selbst dunkel. Eine Regel ergänzt: `html[data-theme="light"] body { --mf-a11y-ink:#fff; }` (gewinnt per Spezifität gegen die Skin-Zuweisungen). Panel-Kopf optional angleichen: `[data-theme="light"] .mf-a11y-head { background:var(--surface-2); color:var(--heading); }`.
3. **finalflux-Altlast:** `finalflux.css:345` (`#0b0d1b`-Hardcode) funktioniert nur über die fragile `background:transparent`-Kaskade aus `platform-neural.css:61`. Hardcode durch `var(--bg)`-basierte Deklaration ersetzen, damit die Seite auch ohne `sn-platform` beide Themes überlebt.
**Erledigt:** Login-Overlay, SyntaxSaga-Bühne, CodeEscape-Eingaben und Akzent-Inks,
NetWorker-Guide, Farbenblind-Palette für Light Mode, A11y-Widget-Inks sowie der
FinalProtocol-Hintergrund. Die noch offenen kleineren Cancel-Hover- und Detaileffekte
werden zusammen mit der vollständigen CSS-Migration aus R1 abgeschlossen.
---
## AP R3 — Theme-Bootstrap (erledigt 2026-07-22)
In `RES\static\js\theme.js`:
1. **Erledigt:** `prefers-color-scheme` wird verwendet, wenn noch keine lokale Auswahl gespeichert ist.
2. **Erledigt:** `theme-color` wird beim initialen Anwenden und Umschalten auf `#0a0806` bzw. `#fbf6ec` aktualisiert.
3. **Erledigt:** `color-scheme` wird im Dark-/Light-Tokenblock gesetzt.
4. **Teilweise erledigt:** geänderte FinalProtocol-Assets tragen neue Versionen; die übrigen Template-Referenzen werden bei ihrer jeweiligen Migration angehoben.
---
## AP R4 — Scroll: Ergebnisanzeigen & Ansichten starten oben (weitgehend erledigt 2026-07-22)
Es gibt projektweit keinen Scroll-Reset. Drei Schichten (zentraler Helper + gezielte Aufrufe), Chat-Autoscroll `neuralnet.js:84` bleibt unangetastet:
### R4a. Helper in `theme.js` (läuft auf jeder Seite)
```js
window.MindfluxUX = {
toTop: function () { window.scrollTo(0, 0); },
focusQuiet: function (el) { if (el) el.focus({ preventScroll: true }); }
};
```
**Umsetzungshinweis:** Der zentrale Helper ist vorhanden. Die vier SPA-Spiele setzen
`history.scrollRestoration` nur auf Spielrouten auf `manual`; ein zentraler,
ereignisbasierter Übergangs-Reset deckt Ansichtswechsel ab und lässt Antwort- bzw.
Zeilenfeedback unverändert. FinalProtocol, SyntaxSaga, DevLab, MindMatch und
TechTacular haben die zusätzlich beschriebenen gezielten Resets/Fokusoptionen.
**Offen für die visuelle E2E-Prüfung:** die asynchron gerenderten Ergebniswechsel von
CodeEscape, NetWorker und BugHunter müssen im Browser gegen die Scroll-Checkliste
validiert und bei Bedarf direkt in den jeweiligen Render-Funktionen präzisiert werden.
### R4b. SPA-Spiele — Reset bei jedem Ansichtswechsel
Muster pro Spiel: Mini-Wrapper `function setView(html){ view.innerHTML = html; window.scrollTo(0,0); }`, alle Render-Funktionen darüber. Zusätzlich **nur in diesen vier Skripten** beim Init: `if ('scrollRestoration' in history) history.scrollRestoration = 'manual'; window.scrollTo(0,0);` — verhindert, dass der Browser nach Reload/Back die alte, untere Position auf den neu aufgebauten Katalog anwendet. (Nicht global in `theme.js`: auf Lernseiten/Dashboard ist die Back-Position erwünscht.)
| Spiel | Funktionen |
|---|---|
| BugHunter (`bughunter.js`) | `renderBriefing` :29, `renderHunt` :36 (nur bei Fallwechsel, nicht bei Zeilen-Re-Render), `showDebrief` :82, `renderResult` :88 |
| CodeEscape (`codeescape.js`) | `renderLobby` :6, `renderRoom` :8, `renderResult` :17 |
| NetWorker (`networker.js`) | `renderCatalog` :3, `renderIntro` :5, `renderLevel` :6, `finish` :11 |
| ServiceClash (`serviceclash.js`) | `renderCatalog` :2, `renderRun` :4 (**nur bei Ticket-/Indexwechsel**, nicht beim Feedback-Re-Render), `finish` :9 |
### R4c. FinalProtocol-Quiz (`finalflux-test.js`)
- `finishIfDone()` Z. 101–104: nach `testResult.hidden = false` → `elements.testResult.scrollIntoView({ block: 'start' });` (Auswertung beginnt oben im Blick, statt dass der Viewport ans geclampte Seitenende fällt).
- `restartTest()` Z. 151–158: nach dem Wiedereinblenden → `elements.testRoot.scrollIntoView({ block: 'start' });`
### R4d. Fokus ohne Scroll-Sprung
- `syntaxsaga.js`: `renderMission()` — `window.scrollTo(0,0)` vor Z. 209, dann Z. 210 `first.focus({preventScroll:true})`. (`nextBtn.focus()` Z. 297 bleibt — Nutzeraktion am selben Ort.)
- `devlabgame.js`: `renderTask()` Z. 243 — `window.scrollTo(0,0)` am Ende; Z. 83 und Z. 233 `focus({preventScroll:true})`.
- `codeescape.js:8/15` bleiben (Fokus am Türterminal ist dort korrekt).
### R4e. Niedrige Prio (nur Mobile relevant)
`mindmatch.js` `newGame()` :332 und `techtacular.js` `newGame()` :265: `window.scrollTo(0,0)` — Desktop-Bodys sind `overflow:hidden`, mobil scrollt die Seite.
---
## AP R5 — Carry-over: Rest aus Refine 1 + Zusatzfunde der Verifikation
Aus Refine 1 (dort AP 7 / offen):
1. **Bean Validation:** `@Valid` + Constraints auf alle Request-DTOs — `BugHunterApiController:17–18`, `DevLabApiController:37/43`, `SyntaxSagaApiController:32/38`, `TechtacularApiController:50/75`, `CodeEscapeApiController` (4 DTOs), `NetworkerApiController` (2), `ServiceClashApiController` (2); `NeuralNetApiController:14/19` `Map<String,String>` → typisierte DTOs.
2. **Spring Boot** 3.4.4 → aktuelles 3.4.x-Patch (`pom.xml:11`), Testlauf.
3. **CSRF:** Blanket-Exemption `/api/**` (`SecurityConfig:46`) durch Cookie-basierte Tokens ersetzen.
4. **Web-Layer-Test** für `GET /profile/export`.
Zusatzfunde (neu):
5. **`UserController:25/45`** bindet die **Entity `User`** direkt als `@RequestBody` ohne Validierung → auf DTO + `@Valid` umstellen (gehört in die Runde von Punkt 1).
6. **5 Admin-Templates ohne Footer:** `admin\bughunter.html`, `admin\bughunter-hunt.html`, `admin\codeescape.html`, `admin\codeescape-room.html`, `admin\codeescape-scenario.html` → `th:replace="~{fragments/layout :: footer}"` ergänzen.
7. **HSTS** explizit für Prod konfigurieren statt Spring-Default (`SecurityConfig:56–57`).
8. Optional (unverändert Phase 2): BugHunter progressive Hinweise (Refine 1, AP 4d).
---
## Reihenfolge
1. **AP R0** Aufräumen → 2. **AP R1** Primitives + Migration (theme.css zuerst, dann platform-neural, dann Spiele-CSS, dann Templates) → 3. **AP R2** kaputte Light-Stellen → 4. **AP R3** Bootstrap → 5. **AP R4** Scroll (unabhängig von 1–4, parallelisierbar) → 6. **AP R5** Carry-over → 7. Gesamtverifikation. STYLEGUIDE.md (Abschnitt „Glow, Schatten & Radien" → Primitives-Tabelle) und CHANGELOG nach R1–R3 nachziehen.
## Verifikation
- **Build:** `mvn test` bleibt grün (54/54); App-Boot gegen Wegwerf-Postgres wie gehabt.
- **Grep-Gates nach R1:** `grep -rnE "0 0 [0-9]+px var\(--" RES\static\css` → Treffer nur noch in den Primitive-Definitionen von `theme.css`; `grep -rn "text-shadow:0 0" RES\static\css RES\templates` → nur `--g-text`-Definition; `grep -rn "rgba(0,0,0,.5" RES\static\css` → nur Scrims/`--g-overlay`-Definition.
- **Visuell (hell UND dunkel):** Dashboard (Karten + Hover), Login/Registrierung (insb. Overlay-Panel!), Settings, Progress, Soziales, NeuralNet, alle 9 Spiele (insb. SyntaxSaga-Bühne, CodeEscape-Eingaben, NetWorker-Guide), FinalProtocol-Lernseite + Quiz, A11y-Panel. Dark Mode muss vor/nach R1 visuell deckungsgleich sein (Stichprobe per Screenshot-Vergleich).
- **A11y-Kombinationen:** Light × Hochkontrast (bleibt bewusst dunkel), Light × Farbenblind (neue dunkle Okabe-Ito-Werte sichtbar, Kontrast-Tool ≥ 4.5:1), Light × Mono.
- **Native Controls:** Light Mode → helle Scrollbars und helle `<select>`-Dropdowns (Chrome + Firefox); mobile Adressleiste folgt `theme-color`.
- **Erstbesuch:** localStorage leeren, OS auf Light stellen → Seite startet hell; OS Dark → dunkel; Umschalter persistiert weiter.
- **Scroll:** je SPA-Spiel: langes Board nach unten scrollen → Aktion abschließen → Ergebnis-/Folge-View beginnt **oben**; ServiceClash-Antwort-Feedback und BugHunter-Zeilenauswahl dürfen **nicht** nach oben springen; FinalProtocol: langen Lernartikel bis zum Quiz scrollen, Quiz abschließen → Auswertung oben im Viewport; Reload mitten im Spiel → Katalog startet oben; SyntaxSaga/DevLab: Missions-/Taskwechsel startet oben, Fokus springt nicht; NeuralNet-Chat scrollt weiterhin ans Ende.
## Offene Punkte (unverändert aus Refine 1, vor Launch)
- Echte Impressumsdaten (`impressum.html:44–52`) + §1 Datenschutzerklärung.
- Support-/Feedback-Adressen bestätigen (`fragments/layout.html:88–89`).
## Nachtrag 2026-07-22 — E-Mail-Diagnose (erledigt)
- Der Versand von Bestätigungs- und Reset-Links protokolliert nun korrelierbare
Ereignisse: Token-Ausstellung, SMTP-Übergabe begonnen/angenommen/fehlgeschlagen,
erneute Anforderung und erfolgreiche Verifikation. Logs enthalten User-/Token-IDs
sowie einen gekürzten E-Mail-Fingerprint, niemals den Link oder das Roh-Token.
- Wichtig für die Analyse: `SMTP_SUBMISSION_ACCEPTED` bedeutet nur, dass der
konfigurierte SMTP-Server die Nachricht angenommen hat. Spamfilter, Bounces und
die finale Postfachzustellung müssen zusätzlich im Mailserver bzw. über DSN geprüft
werden.
- Der Registrierungsabschluss meldet keinen Versand-Erfolg mehr, falls der gerade
angelegte Benutzer beim Versand nicht geladen werden kann oder bereits als bestätigt
vorliegt; der Grund erscheint als `VERIFICATION_SKIPPED` im Betriebslog.