315 lines
25 KiB
Markdown
315 lines
25 KiB
Markdown
# 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.
|
||
|
||
## Nachtrag 2026-07-22 — Nutzerfeedback (erledigt)
|
||
|
||
- **TechTacular:** Unbeantwortete Fragen lassen sich per ×, Klick auf den Hintergrund
|
||
oder Escape schließen und später erneut öffnen; sie werden dabei weder gewertet noch
|
||
als beantwortet markiert.
|
||
- **Produktverständnis:** Vor dem Login erklärt eine sichtbare Einordnung Zielgruppe,
|
||
Lernformen und Nutzen der Plattform. Das Dashboard wiederholt den Zweck mit einem
|
||
kompakten „Was du hier machst“-Abschnitt.
|