# Zeitgeist Anki UI — Architektur & Debugging

Letzte Aktualisierung: 2026-06-23 (Priority-Flip-Bug + Dojo-Modus-Fix)

## Datei-Übersicht

`/media/HDD_1TB/Zeitgeist/anki.html` — ~2700 Zeilen, 128 KB. Single-File-App: CSS, HTML, JS in einer Datei.

### CSS-Sektionen (grobe Zeilenbereiche)

| Zeilen | Inhalt |
|--------|--------|
| 1–100 | CSS-Variablen, Reset, Typografie, Header |
| 101–286 | Buttons, Deck-Grid, Card-List, Editor, Toolbar |
| 287–316 | **3D-Flip-Mechanismus** (`.flip-wrap`, `.flip-inner`, `.flip-face`) |
| 317–334 | SM-2 Rating-Buttons |
| 458–472 | Pomodoro-Integration |
| 509–541 | **Mobile-Responsive-Overrides** (deaktiviert 3D-Flip!) |
| 622–663 | Priority-Toggle (Editor) |
| 665–744 | **Priority-Glow-Effekte** (`.flip-face.is-priority`, `.card-row.is-priority`) |

### JS-Sektionen

| Zeilen | Inhalt |
|--------|--------|
| 799–1023 | **FSRS-4.5 Algorithmus** (Konstanten, State-Machine, `rate()`) |
| 1028–1131 | Storage, Helpers, RIS-Auto-Links |
| 1133–1214 | Rich-Text-Rendering (`renderText`, `inlineFmt`) |
| 1216–1316 | Smart-Editor (Tab, Enter, Listen-Fortsetzung) |
| 1341–1393 | State-Management (`VIEW`, `go()`, `render()`) |
| 1397–1441 | `vDecks()` — Deck-Übersicht |
| 1443–1532 | `vDeckStats()` — Deck-Statistik |
| 1534–1630 | `vCards()` — Kartenliste mit Suche/Filter |
| 1639–1682 | `vEditor()` — Karten-Editor mit Priority-Toggle |
| 1730–1806 | `vLearn()` — Lern-Modus (Flip, Rating, Dojo-UI) |
| 1808–1845 | `vDone()` — Abschluss-Bildschirm |
| 1847–2068 | Event-Binding (alle Views) |
| 2076–2211 | **Learn-Session-Logik** (`startLearn`, `startDojo`, `rateCard`, `rateCardDojo`) |
| 2213–2344 | Modals, Card/Deck-CRUD |
| 2346–2490 | Import (CSV/TSV + .apkg via JSZip/sql.js) |

---

## 3D-Flip-Mechanismus

```css
.flip-wrap    { perspective: 1400px; }
.flip-inner   { transform-style: preserve-3d; transition: transform .55s; }
.flip-inner.flipped { transform: rotateY(180deg); }
.flip-face    { backface-visibility: hidden; }
.flip-face.back { transform: rotateY(180deg); }
```

**Funktionsweise:**
- `.flip-inner` ist ein 3D-Grid (beide Faces auf `grid-area: 1/1` gestapelt)
- `.flip-face` hat `backface-visibility: hidden` → Vorderseite unsichtbar wenn gedreht
- `.flip-face.back` ist um 180° vorrotiert → wird sichtbar wenn `.flip-inner` auf 180° flippt
- Mobile (`@media max-width:640px`): 3D-Flip wird komplett deaktiviert (`transform-style:flat`, `display:none`-Toggle)

---

## Pitfall 1: `overflow:hidden` zerstört 3D-Transforms

**Symptom:** Priority-Karten zeigen die Vorderseite spiegelverkehrt auf der Rückseite.

**Ursache:** `.flip-face.is-priority` hatte `overflow:hidden` (Zeile 710, vor Fix). Browser müssen bei `overflow:hidden` einen neuen Stacking Context und eine 2D-Projektion erstellen, um den Overflow korrekt zu clippen. Das flattet den 3D-Transform-Kontext — `backface-visibility:hidden` greift nicht mehr, die Vorderseite bleibt sichtbar und erscheint durch die `rotateY(180deg)`-Transformation spiegelverkehrt.

**Fix:** `overflow:hidden` → `clip-path:inset(0 round 22px)`. `clip-path` schneidet den Inhalt an den Kartenrändern ab, erzeugt aber **keinen** neuen Stacking Context und zerstört nicht den 3D-Kontext. Die `22px` entsprechen dem `border-radius` der Flip-Face.

**Generelle Regel:** In 3D-CSS-Containern (`transform-style:preserve-3d`, `backface-visibility:hidden`) niemals `overflow:hidden` verwenden. Alternativen:
- `clip-path:inset(0)` — sicher, kein Stacking Context
- `overflow:clip` — modernes CSS (Chrome 108+, Safari 16+), ebenfalls sicher
- Pseudo-Element-Insets anpassen, sodass kein Overflow entsteht

---

## Pitfall 2: Dojo-Modus nur bei leerer Queue

**Symptom:** Der Dojo-Modus war praktisch nie erreichbar.

**Ursache:** `startLearn()` (Zeile 2088) baut die Queue aus Priority-Karten + Learning/Relearn + Reviews + neuen Karten. Nur wenn **alle** vier Gruppen leer sind (`!queue.length`), erscheint das `showDojoConfirm()`-Modal. In der Praxis hat fast jedes Deck neue Karten oder Priority-Karten → Dojo-Modal erscheint nie.

**Fix:** Direkter "⚔️ Dojo"-Button in zwei Views:
1. `vCards()` — neben dem "Lernen"-Button, ruft `startDojo(deckId)` auf
2. `vDeckStats()` — neben "Lernen starten", gleiche Funktion

Die Buttons werden in `bindCards()` und `bindDeckStats()` gebunden. Das bestehende Modal für leere Queues bleibt erhalten als Fallback.

**Pattern:** Wenn eine Aktion nur unter einer extrem seltenen Bedingung angeboten wird, immer einen direkten Zugang zusätzlich zum konditionalen anbieten.

---

## Priority-Karten: Besonderheiten

- Priority-Karten werden **immer** zuerst in der Queue platziert (vor Learning/Review/New)
- Priority-Karten durchlaufen **keinen** FSRS-Schedule — `rateCard()` erkennt `card.priority === true` und requeued sie nur (wie Dojo), ohne State-Update
- Priority-Karten haben nur einen "Gemerkt!"-Button (kein Again/Hard/Good/Easy)
- Im Editor: Priority-Toggle mit Stern-Icon und Lila-Slider
- Visuell: Rainbow-Glow-Bokeh-Effekt auf `.flip-face.is-priority` und `.card-row.is-priority`

---

## Mobile-Responsive: 3D-Flip deaktiviert

Auf `<640px` Breite wird der 3D-Flip komplett abgeschaltet:
- `transform-style:flat` statt `preserve-3d`
- `.flip-inner.flipped { transform:none }`
- Faces werden per `display:none` getoggelt statt rotiert
- `backface-visibility:visible` (irrelevant, da kein 3D)

Der `overflow:hidden`-Bug trat auf Mobile **nicht** auf, weil dort kein 3D-Transform existiert.
