diff --git a/docs/superpowers/specs/2026-03-16-tv-dpad-fixes-design.md b/docs/superpowers/specs/2026-03-16-tv-dpad-fixes-design.md
index 3ac3129..e8c87b2 100644
--- a/docs/superpowers/specs/2026-03-16-tv-dpad-fixes-design.md
+++ b/docs/superpowers/specs/2026-03-16-tv-dpad-fixes-design.md
@@ -30,30 +30,7 @@ Die Sidebar rendert alle 26 Buchstaben + `#` (27 Einträge × 36px = 972px). Buc
### Lösung
Im Template `series.html` (Zeile 161-167): Nur Buchstaben rendern, die tatsächlich Serien haben. Das Backend liefert bereits die Serien mit `data-letter` Attribut — wir sammeln die verfügbaren Buchstaben serverseitig oder per Jinja2-Filter.
-**Ansatz:** Die verfügbaren Buchstaben werden im Template aus den Serien-Daten extrahiert:
-
-```html
-
-{% set available_letters = [] %}
-{% for s in series %}
- {% set letter = s.sort_title[0:1]|upper if s.sort_title else '#' %}
- {% set letter = letter if letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' else '#' %}
- {% if letter not in available_letters %}
- {% do available_letters.append(letter) %}
- {% endif %}
-{% endfor %}
-
-
-```
-
-**Fallback:** Falls Jinja2 `{% do %}` nicht unterstützt wird, die Filterung per JavaScript im bestehenden IIFE durchführen:
+**Ansatz:** Per JavaScript im bestehenden IIFE — Buchstaben ohne Treffer komplett entfernen statt dimmen. Das bestehende Script (series.html, Zeile 244-253) wird angepasst:
```javascript
// Buchstaben ohne Treffer komplett entfernen (statt nur dimmen)
@@ -69,7 +46,7 @@ Im Template `series.html` (Zeile 161-167): Nur Buchstaben rendern, die tatsächl
})();
```
-**Bevorzugter Ansatz:** JavaScript-Variante — einfacher, kein Backend-Change nötig.
+Kein Backend-Change nötig, kein Jinja2-Template-Change.
## Änderung 2: Alphabet-Sidebar per D-Pad erreichbar machen
@@ -153,6 +130,8 @@ if (!inNav && !inSidebar && direction === "ArrowRight") {
}
```
+**WICHTIG: Beide folgenden Änderungen sind atomar — sie müssen zusammen eingefügt werden!**
+
Zusätzlich: Die Sidebar-Elemente aus der normalen Nearest-Neighbor-Suche ausschließen (Zeile 240-243 erweitern):
```javascript
@@ -161,20 +140,37 @@ const searchEls = inNav
: focusables.filter(el => !el.closest("#tv-nav") && !el.closest(".tv-alpha-sidebar"));
```
+Außerdem: Im `focusin`-Handler (tv.js) die Sidebar aus dem `_lastContentFocus`-Tracking ausschließen, damit der ArrowLeft-Rücksprung zuverlässig funktioniert:
+
+```javascript
+// Im focusin-Handler: Sidebar-Elemente nicht als Content-Focus speichern
+if (!el.closest("#tv-nav") && !el.closest(".tv-alpha-sidebar")) {
+ this._lastContentFocus = el;
+}
+```
+
+**Enter-Handling:** Wenn der Nutzer in der Sidebar Enter drückt, simuliert der FocusManager einen Click auf das `data-focusable`-Element, was `onclick="filterByLetter()"` auslöst. Kein zusätzlicher Code nötig.
+
## Änderung 3: Episoden-Cards vergrößern
### Problem
Das Episode-Grid nutzt `minmax(180px, 1fr)` (tv.css, Zeile 1821). Auf einem 1080p-TV sind die Cards zu klein und die Laufzeit-Badge wird abgeschnitten.
### Lösung
-Grid-Spalten vergrößern und Laufzeit-Badge anpassen:
+Grid-Spalten vergrößern und Laufzeit-Badge anpassen. **Achtung:** Es gibt einen `@media (min-width: 1200px)` Breakpoint (tv.css, Zeile 2019-2020) der auf `minmax(220px, 1fr)` setzt — dieser muss ebenfalls angepasst werden.
```css
+/* Basis (tv.css, Zeile 1821) */
.tv-episode-grid {
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); /* war 180px */
gap: 1rem; /* war 0.8rem */
}
+/* Responsive: 1200px+ Breakpoint (tv.css, Zeile 2019-2020) — anpassen */
+@media (min-width: 1200px) {
+ .tv-episode-grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); } /* war 220px */
+}
+
.tv-ep-duration {
font-size: 0.8rem; /* war 0.7rem */
padding: 3px 8px; /* war 2px 6px */
@@ -202,11 +198,14 @@ Der Mark-Button (series_detail.html, Zeile 129-132) hat `tabindex="-1"` und kein
- `tabindex="-1"` entfernen
- `data-focusable` hinzufügen
-**CSS** (tv.css): Mark-Button auf TV immer sichtbar machen:
+**CSS** (tv.css): Mark-Button auf TV immer sichtbar machen. Der Base-Wert `opacity: 0` bleibt für Desktop/Mobile erhalten — nur auf TV (kein Hover-Support) wird der Button dauerhaft sichtbar:
+
```css
-/* Mark-Button auf TV immer sichtbar (halbtransparent) */
-.tv-ep-tile-mark {
- opacity: 0.5; /* war 0 — immer leicht sichtbar */
+/* TV-Geräte (kein Hover): Mark-Button immer leicht sichtbar */
+@media (hover: none) {
+ .tv-ep-tile-mark {
+ opacity: 0.5;
+ }
}
.tv-episode-tile:hover .tv-ep-tile-mark,
@@ -242,7 +241,7 @@ Es gibt nur `markSeasonWatched()` pro Staffel (series_detail.html, Zeile 96-99).
data-series-id="{{ series.id }}"
onclick="markSeriesWatched(this)">
✓
- {{ t('series.mark_all_watched') }}
+ {{ t('status.mark_series') }}
```
@@ -328,25 +327,24 @@ function markSeriesWatched(btn) {
}
```
-**i18n** — Neuer Übersetzungsschlüssel:
-```
-series.mark_all_watched = "Serie als gesehen" (de_DE)
-series.mark_all_watched = "Mark series watched" (en_US)
-```
+**i18n** — Bestehender Schlüssel `status.mark_series` wird verwendet:
+- `de.json`: `"mark_series": "Serie als gesehen"` (bereits vorhanden)
+- `en.json`: `"mark_series": "Mark series as watched"` (bereits vorhanden)
+
+Kein neuer i18n-Key nötig.
## Zusammenfassung der Änderungen
| # | Datei | Art | Beschreibung |
|---|-------|-----|-------------|
| 1 | `series.html` | JS ändern | Buchstaben ohne Serien per JS entfernen statt dimmen |
-| 2 | `tv.js` | Code einfügen | Explizite Sidebar-Navigation (ArrowRight→Sidebar, ArrowLeft→Content, sequentiell Up/Down) |
-| 2b | `tv.js` | Code ändern | Sidebar aus Nearest-Neighbor-Suche ausschließen |
+| 2 | `tv.js` | Code einfügen | **ATOMAR:** Explizite Sidebar-Navigation + Sidebar aus Nearest-Neighbor ausschließen + focusin-Handler anpassen |
| 3 | `tv.css` | CSS ändern | Episode-Grid: `minmax(240px, 1fr)`, Laufzeit-Badge größer |
| 4 | `series_detail.html` | HTML ändern | Mark-Button: `tabindex="-1"` → `data-focusable` |
-| 4b | `tv.css` | CSS ändern | Mark-Button: `opacity: 0.5` statt `0`, Focus-Ring |
+| 4b | `tv.css` | CSS ändern | Mark-Button: `opacity: 0.5` nur auf TV (hover:none), Focus-Ring |
| 5 | `series_detail.html` | HTML+JS einfügen | "Serie als gesehen"-Button + `markSeriesWatched()` |
| 5b | `tv.css` | CSS einfügen | Styling für `.tv-mark-series-btn` |
-| 5c | i18n | Key einfügen | `series.mark_all_watched` |
+| 5c | i18n | — | Bestehender Key `status.mark_series` wird verwendet (kein Change) |
## Risiken & Hinweise