/* Farben, Abstaende und Formen aus IPTV/DesignSystem.
 *
 * Jede Zahl hier hat ihre Entsprechung im Swift-Bestand. Wo sie abweicht,
 * sieht dieselbe App auf dem Fernseher anders aus als auf dem Telefon, und
 * genau das ist schon passiert: der Dunkelmodus war hier neutral grau,
 * waehrend die App ihn pflaumenfarben faehrt.
 *
 * Palette.swift, Assets.xcassets, Typography.swift.
 */

:root {
  /* Palette.swift */
  --burgundy: #6B2737;
  --burgundy-15: #E5D9D8;
  --burgundy-deep: #55111F;
  --night: #4A1622;
  --plum: #3A121C;
  --rose: #8E3B4D;

  --paper: #FAF8F4;
  --paper-2: #F1EDE5;
  /* Ein feiner Rand um die Logoplatte, damit sie auch dann als Flaeche
     erkennbar ist, wenn das Logo selbst hell ist. */
  --platte-rand: rgba(26, 22, 34, 0.10);
  /* Der Umriss um ein Logo: dunkel auf heller Platte. */
  --logo-umriss: rgba(26, 22, 34, 0.45);
  --wave: #F5ECEB;

  --ink: #1A1622;
  --ink-60: #5D5668;
  --ink-35: #9A93A6;
  --lime: #C4F042;

  /* Assets.xcassets, heller Auftritt */
  --bg: #FAF8F4;          /* AppBackground */
  --surface: #FFFFFF;     /* Surface */
  --selection: #E5D9D8;   /* Selection */
  --text: #1A1622;        /* TextPrimary */
  --text-2: #5D5668;      /* TextSecondary */
  --text-3: #9A93A6;      /* TextTertiary */
  --line: #E8E2D8;        /* SeparatorLine */

  --accent: var(--burgundy);
  --pattern: var(--burgundy);

  /* Was gewaehlt ist: kraeftig, nicht verblichen. Hell: Burgundy auf Papier.
     Dunkel: Papier auf Burgundy, siehe unten. */
  --chip-on: var(--burgundy);
  --chip-on-text: var(--paper);
  --chip-off: var(--burgundy-15);

  /* Die Segmentanzeige folgt iOS: heller Trog, helle Kachel darin. */
  --segment-track: rgba(26, 22, 34, 0.08);
  --segment-fill: #FFFFFF;

  --tabbar-bg: rgba(255, 255, 255, 0.88);
  --tabbar-idle: #5D5668;

  /* Spacing.swift */
  --space-xs: 4px;
  --space-s: 8px;
  --space-m: 12px;
  --space-l: 16px;
  --space-xl: 24px;
  --space-xxl: 32px;
  --tap: 44px;

  /* Radius.swift */
  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 16px;
  --radius-poster: 8px;

  /* Symbole als Masken, damit sie die Schriftfarbe annehmen. Keine
     Symbolschrift, kein Nachladen, kein zweiter Bestand. */
  --icon-person: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 12a5 5 0 100-10 5 5 0 000 10zm0 2c-5 0-9 2.5-9 5.5V22h18v-2.5c0-3-4-5.5-9-5.5z'/%3E%3C/svg%3E");
  --icon-live: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M3 5h18a1 1 0 011 1v10a1 1 0 01-1 1H3a1 1 0 01-1-1V6a1 1 0 011-1zm1 2v8h16V7H4zm3 12h10v2H7v-2z'/%3E%3C/svg%3E");
  --icon-vod: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M4 3h16a1 1 0 011 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V4a1 1 0 011-1zm1 2v2h2V5H5zm12 0v2h2V5h-2zM5 9v6h14V9H5zm0 8v2h2v-2H5zm12 0v2h2v-2h-2z'/%3E%3C/svg%3E");
  --icon-series: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M4 7h16a1 1 0 011 1v11a1 1 0 01-1 1H4a1 1 0 01-1-1V8a1 1 0 011-1zm2-3h12v1H6V4zm2-2h8v1H8V2z'/%3E%3C/svg%3E");
  --icon-kids: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 2.1a2.6 2.6 0 1 1 0 5.2 2.6 2.6 0 0 1 0-5.2zM8.6 8.7h6.8c.9 0 1.6.7 1.6 1.6v4.1a1 1 0 0 1-2 0v-2.5h-.5v8.4a1.15 1.15 0 0 1-2.3 0v-4.7h-.4v4.7a1.15 1.15 0 0 1-2.3 0v-8.4h-.5v2.5a1 1 0 0 1-2 0v-4.1c0-.9.7-1.6 1.6-1.6z'/%3E%3C/svg%3E");
  --icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M10 2a8 8 0 105.3 14l5.4 5.4 1.4-1.4-5.4-5.4A8 8 0 0010 2zm0 2a6 6 0 110 12 6 6 0 010-12z'/%3E%3C/svg%3E");
  --icon-heart: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 21s-8-5.2-8-10.4A4.6 4.6 0 0112 7a4.6 4.6 0 018 3.6C20 15.8 12 21 12 21z'/%3E%3C/svg%3E");
  --icon-heart-outline: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='2' d='M12 20s-7-4.7-7-9.3A4 4 0 0112 8a4 4 0 017 2.7C19 15.3 12 20 12 20z'/%3E%3C/svg%3E");
  --icon-more: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='5' cy='12' r='2' fill='%23000'/%3E%3Ccircle cx='12' cy='12' r='2' fill='%23000'/%3E%3Ccircle cx='19' cy='12' r='2' fill='%23000'/%3E%3C/svg%3E");
}

/* Der Dunkelmodus der App ist pflaumenfarben, nicht grau. Die Werte stehen
   im Asset-Katalog, jeweils die dunkle Auspraegung. */
/* Dunkel ist die Voreinstellung.
 *
 * Ein Abspieler wird abends benutzt, oft als einziges Licht im Raum, und
 * ein heller Bildschirm blendet dann. Die Farben sind dieselben wie im
 * Bestand, Pflaume und Burgundy aus Palette.swift, nur andersherum verteilt.
 *
 * Die Regeln stehen doppelt: einmal fuer die Einstellung des Systems, einmal
 * fuer die eigene Wahl. `:root[data-theme="light"]` schlaegt beide.
 */
:root[data-theme="dark"] {
  --bg: #3A121C;
  --surface: #4A1622;
  --selection: #5E1F2E;
  --chip-on: #FAF8F4;
  --chip-on-text: #55111F;
  --chip-off: #5E1F2E;
  --text: #FAF8F4;
  --text-2: #E5D9D8;
  --text-3: #9A93A6;
  --line: #55111F;
  --pattern: var(--rose);
  --segment-track: rgba(250, 248, 244, 0.12);
  --segment-fill: #6B2737;
  --tabbar-bg: rgba(58, 18, 28, 0.92);
  --tabbar-idle: #E5D9D8;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #3A121C;          /* AppBackground dunkel, Plum */
    --surface: #4A1622;     /* Surface dunkel, Night */
    --selection: #5E1F2E;   /* Selection dunkel, einen Ton heller als Night */
    --chip-on: #FAF8F4;     /* gewaehlt: Papier auf Burgundy, kraeftig */
    --chip-on-text: #55111F;
    --chip-off: #5E1F2E;
    --text: #FAF8F4;        /* TextPrimary dunkel, Paper */
    --text-2: #E5D9D8;      /* TextSecondary dunkel, Burgundy 15 */
    --text-3: #9A93A6;      /* TextTertiary, in beiden gleich */
    --line: #55111F;        /* SeparatorLine dunkel */

    --pattern: var(--rose);

    --segment-track: rgba(250, 248, 244, 0.12);
    --segment-fill: #6B2737;

    --tabbar-bg: rgba(74, 22, 34, 0.92);
    --tabbar-idle: #E5D9D8;
    --accent: #FAF8F4;

    /* Die Logoplatte, auch im Dunkeln.
       Sie stand nur im hellen Block und blieb deshalb im dunklen Modus
       auf #F1EDE5, also fast weiss, waehrend `--accent` daneben auf
       #FAF8F4 sprang. Ergebnis: fast weisse Initialen auf fast weisser
       Platte, gemeldet am 3. September 2026 als "weiss auf weiss".
       Genau der Fehler, vor dem die eigene Regel warnt: eine Farbe, die
       nur einmal definiert ist, waehrend ihre Partnerin das Thema
       wechselt. */
    --paper-2: #2A1018;
    --platte-rand: rgba(250, 248, 244, 0.14);
    /* Auf dunkler Platte umgekehrt: hell, damit dunkle Logos auffallen. */
    --logo-umriss: rgba(250, 248, 244, 0.45);
  }
}

/* Fire TV: eine WebView auf 1080p, aber aus drei Metern gesehen. */
body.tv { --tap: 64px; font-size: 20px; }

/* Auf dem Fernseher gilt das helle Kleid der nativen App: Papier, weisse
   Kacheln, burgunder Leiste. Die WebView des Sticks meldet dunkel, deshalb
   stehen die Werte hier noch einmal und schlagen die Systemfarbe. Wer die
   APK neben dem iPad sieht, soll dieselbe App sehen. */
body.tv {
  --bg: #FAF8F4;
  --surface: #FFFFFF;
  --selection: #E5D9D8;
  --chip-on: var(--burgundy);
  --chip-on-text: var(--paper);
  --chip-off: var(--burgundy-15);
  --text: #1A1622;
  --text-2: #5D5668;
  --text-3: #9A93A6;
  --line: #E8E2D8;
  --pattern: var(--burgundy);
  --segment-track: rgba(26, 22, 34, 0.08);
  --segment-fill: #FFFFFF;
  --tabbar-bg: rgba(255, 255, 255, 0.88);
  --tabbar-idle: #5D5668;
  --accent: var(--burgundy);
  background: var(--bg);
}

* { box-sizing: border-box; }

/* ------------------------------------------------------------- Geruest */

/* Aufbau wie in der App. Schmal: Markenleiste oben, Bereiche unten, wie die
   TabView auf dem iPhone. Breit: eine Seitenleiste links, wie
   NavigationSplitView auf dem iPad. */

/* Was ausserhalb des Koerpers liegt, hat die Farbe der Bereichsleiste. In
   der installierten Fassung ist das der Streifen ueber dem Home-Balken. */
html { background: var(--bg); }

body {
  margin: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;

  /* Am Bildschirm festgenagelt, nicht `100dvh` hoch.
   *
   * Hier stand `height: 100dvh`. Auf einem iPhone, das die Seite vom
   * Startbildschirm oeffnet, ist `dvh` um den unteren Sicherheitsbereich
   * kuerzer als der Schirm. Der Koerper endete damit 34 Punkte ueber der
   * Kante, darunter kam der Hintergrund von `html` zum Vorschein, und
   * weil der dieselbe Farbe traegt, sah es aus, als schwebe die
   * Bereichsleiste. Zusammen mit dem Sicherheitsabstand in der Leiste
   * selbst wurde daraus der doppelt so hohe Streifen, der am
   * 3. September 2026 gemeldet wurde: gemessen 99 Punkte unter der
   * letzten Beschriftung, wo 40 richtig waeren.
   *
   * `inset: 0` bindet den Koerper an den sichtbaren Bereich, und mit
   * `viewport-fit=cover` ist das der ganze Schirm. Die Leiste liegt damit
   * auf der Kante, und ihr eigener Sicherheitsabstand haelt die Schrift
   * ueber dem Bedienstrich.
   *
   * Ohne `height`, mit Absicht: sind Hoehe und `inset` zugleich gesetzt,
   * gewinnt die Hoehe und `bottom: 0` wird verworfen. Der Fehler waere
   * dann derselbe geblieben.
   */
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Nur der Schriftzug der Marke ist eine Serife. Die grosse Ueberschrift ist
   der System-Font, so wie navigationTitle es in der App macht. */
.display {
  font-family: Fraunces, Georgia, 'Times New Roman', serif;
  font-weight: 600;
  letter-spacing: -0.01em;
}

h1 {
  margin: 0 0 var(--space-s);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

h2 { margin: var(--space-l) 0 var(--space-xs); font-size: 20px; font-weight: 600; }

/* ------------------------------------------------------- Markenleiste */

/* BrandHeader.swift: Logo 28 hoch auf dem Telefon, 34 auf dem iPad, Name in
   der Serife 17 beziehungsweise 19, Zusatz in 12 auf 70 Prozent Deckung,
   Raender 16 mal 8. */
.brandbar {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  padding: var(--space-s) var(--space-l);
  padding-top: max(var(--space-s), env(safe-area-inset-top));
  background: var(--burgundy);
  color: var(--paper);
}

.brandbar .mark { height: 28px; width: auto; flex: 0 0 auto; }

.brandbar .wordmark {
  display: flex;
  align-items: baseline;
  gap: var(--space-s);
  flex: 1;
  min-width: 0;
}

.brandbar .display { font-size: 17px; white-space: nowrap; }

.brandbar .subtitle {
  font-size: 12px;
  color: rgba(250, 248, 244, 0.7);
  white-space: nowrap;
  /* Bei wenig Platz weicht der Zusatz, nicht der Name. */
  overflow: hidden;
  text-overflow: ellipsis;
}

.profile {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(250, 248, 244, 0.5);
  background: transparent;
  color: var(--paper);
  cursor: pointer;
}

.profile::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: currentColor;
  -webkit-mask: var(--icon-person) center / 16px no-repeat;
  mask: var(--icon-person) center / 16px no-repeat;
}

/* ----------------------------------------------------- Bereichsleiste */

/* Unten wie auf dem iPhone: eine schwebende helle Leiste, der gewaehlte
   Bereich hervorgehoben. Auf dem iPad wird daraus die burgundy
   Seitenleiste, siehe weiter unten. */
/* Am unteren Rand, wie die Tab-Leiste in der App, nicht als schwebende
   Pille darueber. Die Pille sass mit `space-s + safe-area` Abstand ueber
   dem Rand, und im Safari kam dessen eingeklappte Leiste noch darunter: die
   Bereiche standen dann fast ein Daumen breit ueber dem Boden. Jetzt fuellt
   der sichere Bereich die Leiste selbst, und nichts schwebt. */
.tabbar {
  display: flex;
  margin: 0;
  /* Ganz runter, bis in den Sicherheitsbereich hinein.
   *
   * Hier stand der volle `env(safe-area-inset-bottom)`, auf einem iPhone
   * 34 Punkte. Zusammen mit dem kurzen Koerper standen unter der letzten
   * Beschriftung 99 Punkte leer, gemessen am Bildschirmfoto vom
   * 3. September 2026, wo 37 richtig gewesen waeren.
   *
   * Der Bedienstrich ist rund fuenf Punkte hoch und sitzt acht Punkte
   * ueber der Kante. Zwoelf Punkte Abstand halten die Schrift frei davon,
   * ohne einen Streifen stehen zu lassen. Ausdruecklich so gewuenscht:
   * "mach es ganz runter in den sicherheitsbereich".
   */
  padding: var(--space-xs) var(--space-s)
           max(var(--space-xs), min(12px, env(safe-area-inset-bottom)));
  border-radius: 0;
  background: var(--tabbar-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 2px 16px rgba(58, 18, 28, 0.18);
}

.tabbar a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 44px;
  padding: 3px 2px;
  border-radius: var(--radius-m);
  color: var(--tabbar-idle);
  text-decoration: none;
  font-size: 11px;
}

.tabbar a[aria-current='page'] {
  color: var(--accent);
  background: var(--selection);
}

.tabbar .icon {
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* ------------------------------------------------------------ Inhalt */

.content {
  position: relative;
  min-width: 0;
  padding: var(--space-l);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* Das Traubenmuster, wie BrandBackground in der App: Marke 62 breit, jede
   zweite Reihe versetzt, leicht gedreht, auf 25 Prozent zurueckgenommen.
   Die Kachel traegt nur Deckung, die Farbe kommt von hier. */
.content::before {
  content: "";
  position: fixed;
  inset: 0;
  background: var(--pattern);
  opacity: 0.25;
  -webkit-mask-image: url("./icons/pattern.png");
  mask-image: url("./icons/pattern.png");
  -webkit-mask-size: 298px 604px;
  mask-size: 298px 604px;
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  pointer-events: none;
  z-index: 0;
}

.content > * { position: relative; z-index: 1; }

/* -------------------------------------------------------------- iPad */

@media (min-width: 820px) {
  body {
    grid-template-rows: auto 1fr;
    grid-template-columns: 220px 1fr;
  }

  /* Marke und Profil sitzen IN der Leiste, wie in der nativen App. */
  .brandbar {
    grid-row: 1;
    grid-column: 1;
    margin: var(--space-m) 0 0 var(--space-m);
    border-radius: var(--radius-l) var(--radius-l) 0 0;
    flex-wrap: wrap;
  }
  .brandbar .mark { height: 30px; }
  .brandbar .display { font-size: 16px; white-space: normal; }
  .brandbar .subtitle { display: none; }
  .content { grid-row: 1 / -1; grid-column: 2; }

  .tabbar {
    grid-row: 2;
    grid-column: 1;
    flex-direction: column;
    justify-content: flex-start;
    gap: var(--space-xs);
    margin: 0 0 var(--space-m) var(--space-m);
    padding: var(--space-m) var(--space-s);
    border-radius: 0 0 var(--radius-l) var(--radius-l);
    background: var(--burgundy);
    box-shadow: 0 8px 32px rgba(58, 18, 28, 0.25);
    backdrop-filter: none;
  }

  .tabbar a {
    flex: 0 0 auto;
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--space-m);
    min-height: var(--tap);
    padding: 0 var(--space-m);
    border-radius: var(--radius-m);
    font-size: 16px;
    color: rgba(250, 248, 244, 0.7);
  }

  .tabbar a[aria-current='page'] {
    color: var(--paper);
    background: rgba(250, 248, 244, 0.16);
  }

  .content { grid-row: 2; grid-column: 2; padding: var(--space-xl); }
}

/* -------------------------------------------------------- Fokusrahmen */

/* Auf dem Fernseher gibt es keinen Mauszeiger. Was den Fokus hat, muss man
   aus drei Metern sehen. */
:focus-visible {
  outline: 3px solid var(--rose);
  outline-offset: 2px;
  border-radius: var(--radius-s);
}

/* Der Ring liegt an, er schwebt nicht.
   Vier Punkte Abstand sahen aus, als sei der Knopf nur ungefaehr gemeint. */
body.tv :focus-visible { outline-width: 3px; outline-offset: 2px; }

/* ------------------------------------------------------------- Chips */

/* GalleryView.chip: Kapsel, Schrift 13, Raender 12 mal 8, Mindesthoehe 44.
   Gewaehlt in Burgundy mit Papierschrift, sonst Selection mit Textfarbe.
   Die Zahl daneben ist blasser. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--tap);
  padding: var(--space-s) var(--space-m);
  border: 0;
  border-radius: 999px;
  background: var(--chip-off);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.14s ease, color 0.14s ease, transform 0.14s ease;
}

.chip:hover { filter: brightness(1.06); }
.chip:active { transform: scale(0.97); }

.chip[aria-pressed='true'],
.chip.primary {
  background: var(--chip-on);
  color: var(--chip-on-text);
  font-weight: 600;
}
.chip .count { color: var(--text-3); font-variant-numeric: tabular-nums; }
.chip[aria-pressed='true'] .count,
.chip.primary .count { color: var(--chip-on-text); opacity: 0.72; }

.strip {
  display: flex;
  gap: var(--space-s);
  overflow-x: auto;
  padding: var(--space-s) 0;
  scrollbar-width: thin;
}

/* Wie pickerStyle(.segmented): ein Block, keine losen Knoepfe. */
.segmented {
  display: flex;
  width: 100%;
  margin: var(--space-s) 0;
  padding: 3px;
  border-radius: 999px;
  background: var(--segment-track);
}

.segmented .chip {
  flex: 1;
  justify-content: center;
  min-height: 36px;
  background: transparent;
  color: var(--text);
  font-weight: 500;
}

.segmented .chip[aria-pressed='true'] {
  background: var(--chip-on);
  color: var(--chip-on-text);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(58, 18, 28, 0.14);
}

/* ------------------------------------------------------------ Listen */

.row {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  min-height: var(--tap);
  padding: var(--space-xs) var(--space-s);
  border-bottom: 1px solid var(--line);
}

.list { margin-top: var(--space-s); }
.list .more { margin: var(--space-l) auto; display: flex; }

.channel { display: flex; align-items: center; border-bottom: 1px solid var(--line); }

.channel .open {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  flex: 1;
  min-width: 0;
  min-height: var(--tap);
  padding: var(--space-xs) var(--space-s);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.channel img, .channel .placeholder {
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  object-fit: contain;
  border-radius: var(--radius-s);
  background: var(--selection);
}

/* Weisse Logos brauchen eine Kante, sonst verschwinden sie auf heller
   Flaeche spurlos. Siehe die Erklaerung bei `.chlogo img`. */
.channel img { filter: drop-shadow(0 0 1px var(--logo-umriss)); }

/* Ein langer Sendername darf die Zeile nicht sprengen. */
.title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
  font-weight: 500;
}

/* ------------------------------------------------------------ Raster */

/* GalleryView: Poster 132 breit auf dem Telefon, 150 auf dem iPad,
   16 Abstand zwischen den Spalten, 24 zwischen den Reihen. */
.grid {
  display: grid;
  gap: var(--space-xl) var(--space-l);
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
}

@media (min-width: 820px) {
  .grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

.poster { font: inherit; color: inherit; }
.poster .frame { position: relative; }

.poster img, .poster .placeholder {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: var(--radius-poster);
  background: var(--selection);
}

/* PosterCard: Titel 16 mittel, zwei Zeilen mit festem Platz, damit das
   Raster nicht springt. Darunter der Zusatz in 13. */
.poster .name {
  margin-top: var(--space-s);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.25;
  min-height: 2.5em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.poster .count { font-size: 13px; }

/* Der Knopf mit den drei Punkten. Sichtbar, nicht auf einer Geste: mit Maus
   und Fernbedienung kommt man an langes Druecken nicht heran. */
.rowmenu {
  position: absolute;
  top: var(--space-xs);
  right: var(--space-xs);
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(58, 18, 28, 0.55);
  cursor: pointer;
}

.rowmenu::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: var(--paper);
  -webkit-mask: var(--icon-more) center / 18px no-repeat;
  mask: var(--icon-more) center / 18px no-repeat;
}

.rowmenu.inline {
  position: static;
  flex: 0 0 auto;
  background: transparent;
  margin-right: var(--space-xs);
}

.rowmenu.inline::before { background: var(--burgundy); }

/* ---------------------------------------------------------- Formular */

.field {
  width: 100%;
  max-width: 520px;
  min-height: var(--tap);
  padding: 0 var(--space-m);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

.form { display: grid; gap: var(--space-s); max-width: 420px; margin-top: var(--space-s); }
.problem { color: var(--rose); }
.group { font-size: 17px; margin: var(--space-l) 0 var(--space-xs); }

.muted { color: var(--text-2); }
.hint { margin: var(--space-xs) 0; font-size: 13px; }
.count { color: var(--text-3); font-variant-numeric: tabular-nums; }

.empty {
  padding: var(--space-xxl) var(--space-l);
  text-align: center;
  color: var(--text-2);
}

/* -------------------------------------------------------- Wiedergabe */

/* Steht ausserhalb der Bereiche, damit ein Wechsel nach Filme sie nicht
   abreisst. Auf dem Fernseher fuellt sie den Bildschirm. */
#surface {
  position: fixed;
  /* Ganz in die Ecke unten links. Mit Abstand ringsum schnitt sie ein
     Stueck aus der Liste heraus, das man nicht mehr lesen konnte. */
  left: 0;
  bottom: 0;
  /* Acht Prozent schmaler als vorher: die Senderliste daneben soll
     lesbar bleiben. */
  width: min(386px, calc(100vw - 2 * var(--space-l)));
  background: #000;
  border-radius: var(--radius-l) var(--radius-l) 0 0;
  overflow: hidden;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  z-index: 10;
}

#surface video { width: 100%; aspect-ratio: 16 / 9; background: #000; display: block; }

/* Oben rechts ueber dem Bild. Immer sichtbar, auch wenn nichts laeuft und
   auch wenn die Zeile ausgeblendet ist. */
/* In der Huelle zeichnet ExoPlayer das Bild, nicht die WebView.
   Das `video` bleibt leer, und der schwarze Kasten darum ist ein hoher
   Balken ohne Inhalt. Weg damit: sichtbar bleibt nur die Beschriftung. */
body.shell #surface { background: transparent; box-shadow: none; }

/* Im Vollbild aber doch: ein Film mit anderem Seitenverhaeltnis liesse
   sonst die Liste an den Raendern durchscheinen. */
body.shell #surface.full { background: #000; }
body.shell #surface video { display: none; }
body.shell #surface-note {
  background: rgba(0, 0, 0, 0.62);
  border-radius: var(--radius-l);
}

#surface:focus { outline: 4px solid var(--burgundy); outline-offset: 2px; }

/* In der Huelle gibt es kein Zeigegeraet. Das X ist dort nicht zu treffen
   und liegt nur ueber der Liste. Die Zurueck-Taste macht dasselbe. */
body.shell #surface-close { display: none; }

#surface-close {
  position: absolute;
  top: var(--space-s);
  right: var(--space-s);
  z-index: 2;
  /* 44 Punkte, das Mass fuer einen Fingertipp.
     Vorher 32 mit einem Zeichen in 15 Punkt: auf dem Telefon schwer zu
     treffen und kaum zu sehen, gemeldet am 3. September 2026. */
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.62);
  color: var(--paper);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

#surface-close:hover { background: rgba(0, 0, 0, 0.8); }
#surface-note { margin: 0; padding: var(--space-s) var(--space-m); color: var(--paper); font-size: 13px; }
#surface-note .title { flex: 1; min-width: 0; font-weight: 600; font-size: 14px; }
#surface-note .heart { width: 36px; height: 36px; flex: 0 0 auto; }
#surface-note .heart[aria-pressed='true'] { color: #F06A85; }

/* Erst klein, dann gross.
   Vorher war die Flaeche auf dem Fernseher immer der ganze Schirm. Damit gab
   es keine Vorschau, und wer etwas anschaute, konnte nicht weitersuchen. */
#surface.full { inset: 0; width: 100%; border-radius: 0; }
#surface.full video { height: 100dvh; aspect-ratio: auto; }

/* Auf dem Fernseher steht die Seitenleiste links und liegt ueber der
   Vorschau (z-index 20 gegen 10). Die Meldung "der Zugang erlaubt nur eine
   Verbindung" stand deshalb unsichtbar HINTER der Leiste, waehrend der
   Bildschirm schwarz blieb. Also nach rechts unten, wie in der nativen
   App, und ueber alles andere. */
body.tv #surface {
  bottom: calc(2 * var(--space-m));
  left: calc(2 * var(--space-m));
  right: auto;
  width: calc(220px - 2 * var(--space-m));
  z-index: 41;
  border-radius: var(--radius-m);
  overflow: visible;
}
/* Gross ist gross, auch auf dem Fernseher.
 *
 * `body.tv #surface` traegt eine Klasse und einen Typ mehr als
 * `#surface.full` und gewinnt damit, unabhaengig von der Reihenfolge. Im
 * Vollbild blieb die schwarze Ebene deshalb der kleine Kasten unten
 * links. Zusammen mit der nativen Flaeche, die ihre Balken durchsichtig
 * laesst, schien ueber und unter einem Film im Kinoformat die Liste
 * durch. Gemeldet am 4. September 2026 mit Bild.
 *
 * Diese Regel hat eine Klasse mehr und gewinnt gegen beide Fassungen von
 * `body.tv #surface`, auch die im Medienausdruck weiter unten.
 */
body.tv #surface.full {
  inset: 0;
  left: 0;
  right: 0;
  width: 100%;
  border-radius: 0;
  overflow: hidden;
}

body.tv #surface-note { padding: var(--space-xs) var(--space-s); }
.notenknopf {
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: 17px;
  cursor: pointer;
}
.notenknopf:hover { background: rgba(255, 255, 255, 0.15); }

/* ------------------------------------------------------ Werkzeugzeile */

/* In der App sitzen Sortierung und "nur Favoriten" in einem Menue rechts
   oben. Auf einer Webseite gibt es keine Werkzeugleiste, also stehen sie
   hier, in einer Zeile ueber den Kategorien. */
.toolrow {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  flex-wrap: wrap;
  margin: var(--space-s) 0;
}

.select {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--tap);
  padding: 0 var(--space-m);
  border-radius: 999px;
  background: var(--selection);
  color: var(--text);
  font-size: 13px;
}

.select select {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 500;
}

/* Mehrfachauswahl. `details` statt `select multiple`, weil das auf dem
   Telefon nicht zufaellt und ein Tipp darin abwaehlt statt dazu. */
.select.multi {
  display: block;
  width: 100%;
  padding: 0;
  border-radius: var(--radius-l);
  overflow: hidden;
}

.select.multi > summary {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--space-m);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
}

/* Der eigene Pfeil, weil Safari den seinen anders setzt als der Rest. */
.select.multi > summary::-webkit-details-marker { display: none; }
.select.multi > summary::after { content: '\25BE'; margin-left: auto; opacity: 0.6; }
.select.multi[open] > summary::after { content: '\25B4'; }

.multilist {
  display: flex;
  flex-direction: column;
  padding: var(--space-xs) 0;
  border-top: 1px solid var(--line);
}

/* Lang genug zum Lesen, kurz genug, dass der Knopf darunter sichtbar
   bleibt. Bei 340 Gruppen waere die Seite sonst nicht mehr bedienbar. */
.multilist.tall {
  max-height: 46vh;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  background: var(--selection);
}

.multirow {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  min-height: var(--tap);
  padding: 0 var(--space-m);
  cursor: pointer;
}

.multirow .title { flex: 1; }
.multirow input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--burgundy); }

/* Der Kopplungscode. Gross genug, um ihn aus drei Metern abzulesen, und
   mit gleicher Zeichenbreite, damit man beim Abtippen die Stelle wiederfindet. */
.code {
  margin: var(--space-m) 0 var(--space-s);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: clamp(28px, 5vw, 44px);
  letter-spacing: 0.08em;
  color: var(--text);
}

/* Code und Bild nebeneinander. Untereinander sind sie zusammen hoeher als
   ein Fernsehbild, und der QR-Code haengt unten heraus. */
.pairbox {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-l);
  padding: var(--space-m) 0;
}

.pairbox .qr {
  padding: var(--space-s);
  border-radius: var(--radius-l);
  background: #FAF8F4;
}

.pairbox .qr:focus { outline: 3px solid var(--accent); outline-offset: 3px; }
.pairbox > div { flex: 1; min-width: 240px; }
.pairbox .code { margin-top: 0; }

/* Das Eingabefeld fuer den Kopplungscode. Gross genug, dass die
   dreizehn Zeichen samt Strichen hineinpassen, ohne zu wandern. */
.paircode {
  flex: 1;
  min-width: 15ch;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 20px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.qr { display: block; image-rendering: pixelated; }

.strip.wrap { flex-wrap: wrap; overflow: visible; }

.chip.small { min-height: 28px; padding: 0 var(--space-s); font-size: 12px; }

.chip.round {
  min-width: var(--tap);
  padding: 0;
  justify-content: center;
  border-radius: 50%;
  font-size: 17px;
}

/* --------------------------------------------------------- Senderkacheln */

/* Live sieht anders aus als Filme, und das mit Absicht: dort gibt es
   Poster, hier Logos. Ein Sender wird am Logo erkannt, `USA - ABC WEST HD`
   liest niemand aus drei Metern. */
.chgrid {
  display: grid;
  /* Dichter als vorher, 190 waren zu breit.
     Auf einem iPad im Querformat passten damit sechs Kacheln nebeneinander,
     jetzt neun. Gewuenscht am 3. September 2026: kleiner, damit mehr
     nebeneinander passt. */
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: var(--space-s);
  padding-bottom: var(--space-l);
}

.chcard {
  position: relative;
  border-radius: var(--radius-l);
  background: var(--surface);
  overflow: hidden;
}

.chcard .open {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  width: 100%;
  padding: var(--space-m);
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 0.16s ease;
}

.chcard .open:focus-visible,
.chcard .open:focus {
  transform: scale(1.04);
  outline: 3px solid var(--accent);
  outline-offset: -3px;
}

/* Das Logo auf hellem Grund. Viele Sender liefern weisse Schrift ohne
   Hintergrund, die auf Pflaume unsichtbar waere. */
.chlogo {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  margin-bottom: var(--space-xs);
  border-radius: var(--radius-m);
  background: var(--paper-2);
  border: 1px solid var(--platte-rand);
}

.chlogo img {
  max-width: 82%;
  max-height: 44px;
  object-fit: contain;

  /* Ein hauchduenner Umriss um jedes Logo.
     Sehr viele Senderlogos sind weiss auf durchsichtig gezeichnet, fuer
     dunkle Programmfuehrer. Auf einer hellen Platte verschwinden sie
     spurlos, und die Kachel sieht leer aus. Ein Schatten in beide
     Richtungen macht sie sichtbar, ohne dunkle Logos anzufassen: hinter
     einem dunklen Logo faellt er nicht auf, hinter einem weissen zeichnet
     er die Kante. */
  filter: drop-shadow(0 0 1px var(--logo-umriss));
}

.chcard .title { font-weight: 600; line-height: 1.25; }
.chcard .count { color: var(--text-3); font-size: 12px; }

/* Herz und Menue in die Ecke, sie sollen die Kachel nicht auseinanderziehen. */
.chcard .heart, .chcard .rowmenu {
  position: absolute;
  top: var(--space-xs);
  width: 40px;
  height: 40px;
}

.chcard .heart { right: 44px; }
.chcard .rowmenu { right: var(--space-xs); }

@media (prefers-reduced-motion: reduce) {
  .chcard .open { transition: none; }
}

/* ------------------------------------------------------------- Reihen */

/* Eine Zeile je Gruppe, quer zu blaettern. Ein Raster ueber 103.000 Filme
   ist eine Wand, an der man nichts findet. */
.railhead {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  margin: var(--space-l) 0 var(--space-s);
}

/* `See All` als leiser Knopf neben dem Titel. Als volle Kapsel sass er wie
   ein Ball auf der Zeile und ueberdeckte auf dem Fernseher die Anzahl. */
.railhead .chip {
  min-height: 0;
  padding: 4px 14px;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--text-2);
  flex: 0 0 auto;
}
.railhead .chip:hover, .railhead .chip:focus-visible { color: var(--text); border-color: var(--accent); }

.railtitle {
  margin: 0;
  font-family: Fraunces, Georgia, 'Times New Roman', serif;
  font-size: clamp(17px, 2.2vw, 22px);
  color: var(--text);
}

.rail {
  display: flex;
  gap: var(--space-m);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: var(--space-s);
  /* Die Leiste selbst bleibt unsichtbar: auf dem Fernseher gibt es nichts
     zu greifen, und auf dem Telefon wischt man ohnehin. */
  scrollbar-width: none;
}

.rail::-webkit-scrollbar { display: none; }

.rail .poster {
  flex: 0 0 auto;
  width: clamp(120px, 16vw, 190px);
  scroll-snap-align: start;
}

/* Was gerade gewaehlt ist, tritt hervor. Ohne das sieht man auf einem
   Fernseher aus drei Metern nicht, wo man steht. */
.poster .open:focus-visible,
.rail .poster .open:focus {
  transform: scale(1.06);
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

.poster .open { transition: transform 0.16s ease; }

@media (prefers-reduced-motion: reduce) {
  .poster .open { transition: none; }
}

/* ---------------------------------------------------------- Suchfeld */

.searchrow { padding: var(--space-s) 0 var(--space-m); }

.searchfield {
  width: 100%;
  min-height: var(--tap);
  padding: 0 var(--space-m);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

.searchfield::placeholder { color: var(--text-3); }

/* ------------------------------------------------------------ Ladeschirm */

/* --- Ladebildschirm -----------------------------------------------------
   Ganzflaechig und ruhig. Vorher drehte sich das Logo, und ein sich drehendes
   Logo sieht aus wie 2005. Gewartet wird hier ohnehin selten: der Start liest
   aus der lokalen Datenbank und wartet nie auf das Netz. Was man sieht, ist
   der Moment zwischen Tippen und Da-Sein, und der soll ruhig aussehen und
   nicht beschaeftigt. */

.splash {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-s);
  background: var(--burgundy);
  text-align: center;
}

.splash .splashmark {
  width: clamp(96px, 18vw, 168px);
  height: auto;
  /* Das Logo ist dunkel auf hell. Auf Burgundy braucht es die Umkehrung,
     sonst verschwindet es im Grund. */
  filter: brightness(0) invert(1);
  opacity: 0;
  transform: scale(0.94);
  animation: auftauchen 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}

.splashtitle {
  margin: var(--space-m) 0 0;
  font-family: Fraunces, Georgia, 'Times New Roman', serif;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.1;
  color: var(--paper);
  opacity: 0;
  animation: auftauchen 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) 0.08s forwards;
}

.splashsub {
  margin: 2px 0 0;
  font-size: clamp(13px, 1.6vw, 16px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(250, 248, 244, 0.62);
  opacity: 0;
  animation: auftauchen 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) 0.16s forwards;
}

/* Eine Linie statt eines Kreisels. Sie sagt dasselbe und draengt nicht. */
.splashbar {
  width: clamp(120px, 22vw, 220px);
  height: 2px;
  margin-top: var(--space-xl);
  border-radius: 2px;
  background: rgba(250, 248, 244, 0.18);
  overflow: hidden;
}

.splashbar > span {
  display: block;
  width: 38%;
  height: 100%;
  border-radius: 2px;
  background: var(--paper);
  animation: wandern 1.3s ease-in-out infinite;
}

@keyframes auftauchen {
  to { opacity: 1; transform: scale(1); }
}

@keyframes wandern {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(300%); }
}

/* Wer eine ruhige Darstellung eingestellt hat, bekommt keine Bewegung. */
@media (prefers-reduced-motion: reduce) {
  .splash .splashmark,
  .splashtitle,
  .splashsub { animation: none; opacity: 1; transform: none; }
  .splashbar > span { animation: none; width: 100%; }
}

/* --------------------------------------------------------------- Herz */

/* FavoriteMark in der App: Rand, wenn nicht gemerkt, voll, wenn gemerkt,
   immer in Burgundy. */
.heart {
  flex: 0 0 auto;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.heart::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: var(--burgundy);
  -webkit-mask: var(--icon-heart-outline) center / 22px no-repeat;
  mask: var(--icon-heart-outline) center / 22px no-repeat;
}

.heart[aria-pressed='true']::before {
  -webkit-mask-image: var(--icon-heart);
  mask-image: var(--icon-heart);
}

@media (prefers-color-scheme: dark) {
  .heart::before { background: var(--burgundy-15); }
}

:root[data-theme="dark"] .heart::before { background: var(--burgundy-15); }

/* Wer ausdruecklich hell will, bekommt hell, auch wenn das System dunkel
   steht. Deshalb steht diese Gruppe zuletzt. */
:root[data-theme="light"] {
  --bg: #FAF8F4;
  --surface: #FFFFFF;
  --selection: #E5D9D8;
  --text: #1A1622;
  --text-2: #5D5668;
  --text-3: #9A93A6;
  --line: #E8E2D8;
  --pattern: var(--burgundy);
  --segment-track: rgba(26, 22, 34, 0.08);
  --segment-fill: #FFFFFF;
  --tabbar-bg: rgba(255, 255, 255, 0.88);
  --tabbar-idle: #5D5668;
}

:root[data-theme="light"] .heart::before { background: var(--burgundy); }

/* ------------------------------------------------------------- Raster */

.poster .frame {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.posteractions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-xs);
}

/* Beim endlosen Nachladen: der Merker am Ende der Liste. */
.sentinel { height: 1px; }

/* -------------------------------------------------------------- Blatt */

.sheetbackdrop {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(26, 22, 34, 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.sheet {
  width: min(680px, 100%);
  max-height: 88dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-radius: var(--radius-l) var(--radius-l) 0 0;
  box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.35);
}

@media (min-width: 820px) {
  .sheetbackdrop { align-items: center; }
  .sheet { border-radius: var(--radius-l); max-height: 80dvh; }
}

.sheethead {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  padding: var(--space-m) var(--space-l);
  border-bottom: 1px solid var(--line);
}

.sheettitle { flex: 1; margin: 0; font-size: 17px; font-weight: 600; }

.sheetbody {
  padding: var(--space-l);
  padding-bottom: calc(var(--space-l) + env(safe-area-inset-bottom));
  overflow-y: auto;
}

/* ------------------------------------------------------ Detailansicht */

.detailhead { display: flex; gap: var(--space-l); }

.detailposter {
  flex: 0 0 120px;
  width: 120px;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: var(--radius-poster);
  background: var(--selection);
}

.detailfacts { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-m); }
.detailmeta { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
.detailbuttons { display: flex; align-items: center; gap: var(--space-s); }

/* ---------------------------------------------------- Favoritenlisten */

.listchip { display: inline-flex; align-items: center; }

/* -------------------------------------------------------- Wiedergabe */

.playerrow {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin-bottom: var(--space-xs);
}

.playerrow:last-child { margin-bottom: 0; }
.playerrow .title { color: var(--paper); font-size: 14px; }
.playerrow .count { color: rgba(250, 248, 244, 0.6); }
.playerrow .chip.round { min-width: 36px; height: 36px; background: rgba(250, 248, 244, 0.12); color: var(--paper); }
.playerrow .time { min-width: 46px; text-align: center; }

.scrubber, .volume { flex: 1; min-width: 60px; accent-color: var(--rose); }
.volume { max-width: 120px; }

.searchbar { margin: var(--space-s) 0; }

/* Die Einblendung verschwindet nach vier Sekunden, wie in der App. Ein
   Tipp holt sie zurueck. */
#surface.quiet #surface-note { opacity: 0; pointer-events: none; }
#surface-note { transition: opacity 0.35s ease; }

/* In der Huelle blendet nichts aus. Es gibt keinen Tipp, der die Zeile
   zurueckholt, und so stand die Vorschau ohne Namen und ohne Knoepfe da.
   Gemessen am 28. August 2026: opacity 0 nach vier Sekunden, fuer immer. */
body.shell #surface.quiet #surface-note { opacity: 1; pointer-events: auto; }

/* Auf der Profilseite gibt es keine Leiste darunter: das Markenfeld
   bekommt dann auch unten runde Ecken. */
body.gated .brandbar { border-radius: var(--radius-l); }

/* Solange die Vorschau unten angedockt ist, macht die Leiste ihr Platz,
   sonst verdeckt das Bild die letzten Menuepunkte. */
body.tv .tabbar { overflow-y: auto; scrollbar-width: none; }
body.tv.preview .tabbar { padding-bottom: 210px; }

/* Ein Fehler gehoert auf den Bildschirm, nicht in eine Konsole, die auf
   einem Telefon niemand oeffnet. */
.failure {
  margin: var(--space-l) 0;
  padding: var(--space-m);
  border: 1px solid var(--rose);
  border-radius: var(--radius-m);
  background: var(--surface);
  color: var(--text);
}

.failure pre {
  margin: var(--space-s) 0 0;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 12px;
  color: var(--text-2);
}

/* ------------------------------------------------- Anmeldung und Profile */

/* Solange eine der beiden Tueren zu ist, gibt es keine Bereichsleiste. Sie
   fuehrt sonst an der Anmeldung vorbei. */
body.gated .tabbar { display: none; }

.gate {
  max-width: 460px;
  margin: 0 auto;
  padding: var(--space-l) 0 var(--space-xxl);
}

.gate h1 { font-size: 28px; }

.profilegrid {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  margin: var(--space-l) 0;
}

.profiletile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-m) var(--space-s);
  border: 0;
  border-radius: var(--radius-l);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--burgundy);
  color: var(--paper);
  font-size: 26px;
  font-weight: 600;
}

.profilename { font-size: 15px; font-weight: 500; }
.profiletile.add .avatar { background: var(--selection); color: var(--text-2); }

.color-burgundy { background: #6B2737; }
.color-rose { background: #8E3B4D; }
.color-plum { background: #3A121C; }
.color-night { background: #4A1622; }
.color-lime { background: #C4F042; color: #1A1622; }

.swatch {
  width: 40px;
  height: 40px;
  border: 2px solid transparent;
  border-radius: 50%;
  cursor: pointer;
}

.swatch[aria-pressed='true'] { border-color: var(--text); }

.check {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  min-height: var(--tap);
  font-size: 15px;
}

/* --------------------------------------------------------- Quellenkarte */

/* Der Name oben, die Knoepfe darunter. Nebeneinander hat ein langer Name
   sie zerdrueckt, und bei mehreren Quellen wird es enger, nicht weiter. */
.sourcecard {
  padding: var(--space-m) 0;
  border-bottom: 1px solid var(--line);
}

.sourcehead { display: flex; flex-direction: column; gap: 2px; }
.sourcehead strong { font-size: 17px; }
.sourcehead .count { font-size: 13px; word-break: break-all; }
.sourcecard .toolrow { margin-top: var(--space-s); margin-bottom: 0; }

/* ----------------------------------------------------------- Filterzeile */

/* Marke, Jahrzehnt, Sparte und Format nebeneinander. Als Leisten aus
   Kapseln braeuchten vierzig Sparten die halbe Seite, und man scrollt
   waagerecht an ihnen entlang, statt zu waehlen. */
.filterrow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin: var(--space-s) 0;
}

.filterrow .select { flex: 1 1 auto; min-width: 140px; }

.select select {
  width: 100%;
  /* Sonst schneidet Safari den Text am eigenen Pfeil ab. */
  padding-right: var(--space-l);
}

/* --- Reihen -------------------------------------------------------------
   Eine je Sparte oder Land, waagerecht zu blaettern. Der Abstand zwischen
   den Reihen ist grosszuegig: auf einem Fernseher aus drei Metern verschmelzen
   enge Reihen zu einem Teppich, und man findet die Zeile nicht wieder. */

.railblock { margin-bottom: var(--space-l); }

/* Noch nicht gefuellte Reihen halten Platz, damit die Seite beim
   Nachladen nicht springt, und werden erst gezeichnet, wenn sie ins Bild
   kommen. Das entlastet den Fernseher spuerbar. */
.railblock { content-visibility: auto; contain-intrinsic-size: auto 220px; }
.railblock.pending { min-height: 180px; }

.railblock .railhead { margin-bottom: var(--space-s); }

/* Die Kachel eines Senders. Logo gross, Name klein und erst wenn gewaehlt.
   Aus drei Metern liest niemand `USA - BIG BROTHER CAMERA 3`, und dreissig
   solcher Zeilen nebeneinander sind eine Wand aus Text. */
.rail .chtile {
  flex: 0 0 auto;
  width: clamp(120px, 14vw, 168px);
  scroll-snap-align: start;
}

.rail .chtile .open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: var(--radius-l);
  transition: transform 0.16s ease;
}

.rail .chtile .chlogo {
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(52px, 6vw, 72px);
  margin: 0;
  border-radius: var(--radius-m);
  background: var(--paper-2);
}

.rail .chtile .chlogo img { max-width: 78%; max-height: 72%; object-fit: contain; }

/* Der Name bleibt Platz halten, auch wenn er unsichtbar ist. Sonst
   verschieben sich beim Fokuswechsel alle Reihen darunter. */
.rail .chtitle {
  display: block;
  /* Acht Pixel: die gewaehlte Kachel waechst um vier Prozent und traegt
     einen Rahmen mit Abstand. Bei zweien lag beides auf dem Namen. */
  margin-top: 8px;
  min-height: 1.3em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 13px;
  line-height: 1.2;
  color: var(--text-2);
  opacity: 0;
  transition: opacity 0.12s ease;
}

.rail .chtile:focus-within .chtitle,
.rail .chtile:hover .chtitle,
.rail .chtile:has(.open[aria-pressed="true"]) .chtitle { opacity: 1; color: var(--text); }

/* Was gewaehlt ist, tritt hervor. Ohne das sieht man auf einem Fernseher
   nicht, wo man steht. */
.rail .chtile .open:focus-visible,
.rail .chtile .open:focus {
  transform: scale(1.08);
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.rail .chtile .open[aria-pressed="true"] .chlogo {
  box-shadow: inset 0 0 0 3px var(--accent);
}

/* Der Weg zurueck. Ohne Krumen weiss nach zwei Ebenen niemand mehr, wo er
   steht. */
.crumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-bottom: var(--space-m);
}

.crumbs .sep { color: var(--text-3); }

.crumbs .crumb {
  padding: 6px 12px;
  border: 0;
  border-radius: 999px;
  background: var(--selection);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.crumbs .crumb[aria-current="page"] {
  background: var(--chip-on);
  color: var(--chip-on-text);
}

.crumbs .crumb:focus-visible,
.crumbs .crumb:focus { outline: 3px solid var(--accent); outline-offset: 2px; }

/* Der Fortschritt unter einem Plakat. Ohne ihn sieht man nicht, ob noch
   fuenf Minuten fehlen oder eine Stunde. */
.rail .poster .progress,
.grid .poster .progress {
  display: block;
  height: 3px;
  margin-top: 4px;
  border-radius: 2px;
  background: var(--selection);
  overflow: hidden;
}

.rail .poster .progress > span,
.grid .poster .progress > span {
  display: block;
  height: 100%;
  background: var(--burgundy);
}


/* Initialen, wenn ein Sender oder Film kein brauchbares Bild liefert.
   Weisse leere Kacheln sahen aus wie eine kaputte App. */
.initials {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  min-height: 48px;
  font-family: Fraunces, Georgia, serif;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.04em;
  /* `--text`, nicht `--accent`.
     Die Initialen stehen auf der Logoplatte, und die wechselt mit dem
     Thema. `--accent` ist im Dunkeln fast weiss und stand damit auf einer
     fast weissen Platte. `--text` wechselt mit, hell auf dunkel und
     dunkel auf hell, und trifft in beiden Themen. */
  color: var(--text);
  opacity: 0.75;
}

/* Der ganze Name statt zweier Buchstaben.
 *
 * `SN` und `KB` sagen niemandem etwas. Wo die Kachel Platz hat, steht
 * der Name: klein, umgebrochen, hoechstens drei Zeilen, und lange
 * Woerter duerfen brechen, damit `SUPERSPORT` nicht ueber den Rand
 * laeuft. Gewuenscht am 3. September 2026.
 *
 * Die Schrift des Textes, nicht Fraunces: eine Groteske bleibt bei
 * 11 Punkt lesbar, eine Serife nicht. */
.initials.vollname {
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0;
  padding: 4px 5px;
  text-align: center;
  overflow: hidden;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  opacity: 0.9;
}

/* Auf dem Fernseher nur das, was ohne neues Layout auskommt.
   Vorher stand hier `transition-duration: 0s` fuer alles. Das war zu grob:
   damit sprang die Auswahl hart von Kachel zu Kachel, und genau das fuehlt
   sich hakelig an. Netflix macht es umgekehrt, siehe deren TechBlog: die
   Bewegung laeuft ueber `transform` und `opacity`, weil beides der
   Compositor allein erledigt, ohne Layout und ohne neues Zeichnen.
   Alles andere bleibt aus, denn Farbverlaeufe und Schatten je Kachel
   kosten auf der Mali des Sticks mehr als der Rest zusammen. */
body.tv * {
  transition-property: transform, opacity;
  transition-duration: 0.13s;
  transition-timing-function: cubic-bezier(0.2, 0, 0.2, 1);
}
body.tv .rail, body.tv .content { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  body.tv * { transition-duration: 0s; }
  body.tv .rail, body.tv .content { scroll-behavior: auto; }
}

/* ------------------------------------------------- Fernseher: Farbe

   Aus drei Metern verliert jede Farbe an Kraft, und ein Fernseher zeigt
   sie flauer als ein iPad. Deshalb hier kraeftiger als in der App: die
   Kapseln tragen echtes Burgundy statt eines Hauchs davon, die Schrift
   steht dunkler, die Linien sind zu sehen. */
body.tv {
  --chip-off: #DCC9CC;          /* statt Burgundy 15, deutlich sichtbar */
  --selection: #DCC9CC;
  --text-2: #4A4353;
  --text-3: #6E6678;
  --line: #D8CEC2;
  --segment-track: rgba(26, 22, 34, 0.13);
}

/* Knoepfe mit Kante. Ohne Rand verschwimmt eine helle Kapsel auf hellem
   Papier, und man sieht nicht, was ein Knopf ist. */
body.tv .chip {
  border: 1px solid rgba(107, 39, 55, 0.22);
  font-size: 15px;
  font-weight: 600;
}
body.tv .chip[aria-pressed='true'], body.tv .chip.primary {
  border-color: var(--burgundy);
  box-shadow: 0 2px 8px rgba(107, 39, 55, 0.28);
}
body.tv .segmented { padding: 4px; }
body.tv .segmented .chip { border: 0; min-height: 44px; }

/* Der Titel einer Reihe traegt die Marke, nicht nur Schwarz. */
body.tv .railtitle { font-size: 26px; color: var(--burgundy); }
body.tv .count { font-size: 16px; }
body.tv h1 { font-size: 40px; }

/* Die Kachel: heller Grund, klare Kante, und beim Waehlen waechst sie,
   ohne dass sich darunter etwas verschiebt. */
body.tv .rail .chtile { width: clamp(140px, 15vw, 180px); }
body.tv .rail .chtile .chlogo {
  height: clamp(78px, 9vw, 104px);
  background: #FFFFFF;
  border: 1px solid var(--line);
}
/* Der Ring sitzt auf dem weissen Feld, nicht um den Knopf herum.
   Der Knopf ist groesser als das Bild darin, und ein Rahmen an seiner
   Kante liess rechts und unten einen Streifen Luft stehen. Genau das
   war gemeint mit `die buttons haben luft im auswahlrand`. Als
   Innenschatten liegt der Ring da, wo das Auge die Kachel sieht.
   Dieselbe Zeichnung wie beim Favoritenzustand darunter. */
body.tv .rail .chtile .open:focus-visible,
body.tv .rail .chtile .open:focus {
  transform: scale(1.10);
  outline: none;
}

body.tv .rail .chtile .open:focus-visible .chlogo,
body.tv .rail .chtile .open:focus .chlogo {
  box-shadow: inset 0 0 0 4px var(--burgundy);
  border-color: var(--burgundy);
}

/* Der Rahmen liegt am Bild an, nicht drei Punkte daneben.
   Ein Ring mit Luft sieht aus, als sei die Kachel nur ungefaehr gemeint. */
body.tv .chcard .open:focus-visible,
body.tv .chcard .open:focus,
body.tv .channel .open:focus-visible,
body.tv .channel .open:focus {
  outline: 3px solid var(--burgundy);
  outline-offset: -3px;
  border-radius: var(--radius-l);
}
body.tv .rail .chtile .open[aria-pressed="true"] .chlogo {
  box-shadow: inset 0 0 0 4px var(--burgundy);
}
/* Mehr Luft als in der App: die gewaehlte Kachel waechst um zehn Prozent
   und traegt einen vier Punkt starken Rahmen mit Abstand. Bei acht Punkten
   lag beides auf dem Namen. */
body.tv .rail .chtitle { margin-top: 15px; font-size: 15px; font-weight: 600; color: var(--text); }

/* Ein Filmplakat waechst genauso. */
body.tv .rail .poster .open:focus-visible,
body.tv .rail .poster .open:focus,
body.tv .poster .frame:focus-visible,
body.tv .poster .frame:focus {
  transform: scale(1.07);
  outline: 4px solid var(--burgundy);
  outline-offset: 0;
}

/* Die Seitenleiste: der gewaehlte Punkt traegt Papier auf Burgundy,
   nicht einen Schleier davon. */
body.tv .tabbar a { font-size: 18px; font-weight: 500; }
body.tv .tabbar a[aria-current='page'] {
  background: rgba(250, 248, 244, 0.22);
  font-weight: 600;
}
body.tv .tabbar a:focus-visible, body.tv .tabbar a:focus {
  outline: 3px solid var(--paper);
  outline-offset: -3px;
}


/* =====================================================  Ladebildschirm TV

   Drei Bewegungen, in dieser Reihenfolge:

     1. Die Trauben leuchten langsam auf, aus dem Nichts ins Licht.
     2. Der Schriftzug wird von links nach rechts freigelegt, als schriebe
        ihn jemand.
     3. Alles zieht nach rechts weg und wird dabei durchsichtig.

   Nur auf dem Fernseher. Im Browser ist der Ladebildschirm nach einem
   Wimpernschlag vorbei, dort waere jede Inszenierung nur im Weg. Die
   Klasse `tv` steht deshalb schon im Kopf von `index.html`, lange bevor
   ein Modul geladen ist.

   Bewegt werden `opacity`, `transform` und `clip-path`. Alle drei
   erledigt der Compositor allein, ohne Layout und ohne neues Zeichnen.
   Ein wanderndes `filter: drop-shadow` waere auf der Mali des Sticks das
   Teuerste am ganzen Start. */

html.tv .splash {
  gap: 0;
  transition: transform 0.45s cubic-bezier(0.4, 0, 1, 1), opacity 0.45s ease-in;
}

/* Der Schein hinter den Trauben. Ein eigenes Feld, damit die Deckkraft
   wandert und nicht der Schatten. */
html.tv .splash::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(46vw, 520px);
  height: min(46vw, 520px);
  transform: translate(-50%, -62%);
  background: radial-gradient(circle,
    rgba(250, 248, 244, 0.30) 0%,
    rgba(250, 248, 244, 0.10) 42%,
    rgba(250, 248, 244, 0) 70%);
  opacity: 0;
  animation: traubenSchein 2.1s cubic-bezier(0.3, 0, 0.2, 1) forwards;
  pointer-events: none;
}

html.tv .splash .splashmark {
  position: relative;
  width: clamp(120px, 15vw, 190px);
  opacity: 0;
  transform: scale(0.86);
  animation: traubenAuf 1.5s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}

/* Von links nach rechts freigelegt. `clip-path` schneidet, es bewegt
   nichts, deshalb bleibt der Text an seinem Platz und die Zeile darunter
   springt nicht. */
html.tv .splash .splashtitle {
  margin-top: var(--space-l);
  font-size: clamp(30px, 4.4vw, 52px);
  opacity: 1;
  clip-path: inset(0 100% 0 0);
  animation: schriftWischen 0.85s cubic-bezier(0.22, 0.61, 0.36, 1) 1.05s both;
}

html.tv .splash .splashsub {
  margin-top: 6px;
  opacity: 1;
  clip-path: inset(0 100% 0 0);
  animation: schriftWischen 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) 1.5s both;
}

/* Die wandernde Linie hat ausgedient: die Bewegung sagt schon, dass
   etwas passiert. */
html.tv .splash .splashbar { display: none; }

/* Der Abgang. Wird von `splashVerabschieden` in app.js gesetzt, kurz
   bevor der Bildschirm weicht. */
html.tv .splash.geht {
  transform: translateX(14vw);
  opacity: 0;
}

@keyframes traubenAuf {
  0%   { opacity: 0; transform: scale(0.86); }
  55%  { opacity: 1; transform: scale(1.02); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes traubenSchein {
  0%   { opacity: 0; }
  55%  { opacity: 1; }
  100% { opacity: 0.55; }
}

@keyframes schriftWischen {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* Wer keine Bewegung will, bekommt das Bild sofort und ganz. */
@media (prefers-reduced-motion: reduce) {
  html.tv .splash::before,
  html.tv .splash .splashmark,
  html.tv .splash .splashtitle,
  html.tv .splash .splashsub {
    animation: none;
    opacity: 1;
    transform: none;
    clip-path: none;
  }
  html.tv .splash { transition: none; }
}


/* ===============================================  Fernseher: die Listen

   Bis hierher galt die Fernseher-Gestaltung nur den Reihen. Wer auf
   `Alle ansehen` ging, in die Suche oder in die Favoriten, landete in
   einer Ansicht, die noch das alte Kleid trug: duenne Trennlinien, kleine
   Schrift, Bilder in Originalgroesse. Am 29. August 2026 mit einem Foto
   gemeldet, und zu Recht: es sah aus wie eine Webseite auf einem
   Fernseher.

   Dieselben Mittel wie bei den Reihen: weisse Flaechen mit Kante statt
   Haarlinien, das Logo in einem hellen Kasten, kraeftige Schrift, und der
   Auswahlrahmen liegt an. */

/* Aus Zeilen mit Trennstrich werden Karten mit Abstand. */
body.tv .channel {
  align-items: stretch;
  margin-bottom: var(--space-s);
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius-l);
  background: var(--surface);
  overflow: hidden;
}

body.tv .channel .open {
  gap: var(--space-l);
  min-height: 92px;
  padding: var(--space-s) var(--space-m);
  font-size: 19px;
}

body.tv .channel .title {
  font-weight: 600;
  font-size: 19px;
  line-height: 1.25;
}

body.tv .channel .count {
  font-size: 15px;
  color: var(--text-2);
}

/* Das Logo bekommt einen eigenen hellen Kasten, wie in den Reihen. Viele
   Sender liefern weisse Schrift ohne Grund, die sonst verschwindet. */
body.tv .channel .open > img,
body.tv .channel .open > .placeholder,
body.tv .channel .open > .initials {
  width: 132px;
  height: 74px;
  flex: 0 0 auto;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: #FFFFFF;
  object-fit: contain;
}

body.tv .channel .initials { font-size: 24px; }

body.tv .channel .heart,
body.tv .channel .rowmenu,
body.tv .channel .chip {
  width: 56px;
  height: 56px;
  align-self: center;
  flex: 0 0 auto;
}

/* Die Karten der Senderliste: mehrere je Zeile, nicht eine Wand. */
body.tv .chgrid {
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--space-l);
}

body.tv .chcard {
  border: 1px solid var(--line);
}

body.tv .chcard .chlogo {
  height: 104px;
  background: #FFFFFF;
  border: 1px solid var(--line);
}

body.tv .chcard .title {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.25;
}

body.tv .chcard .count { font-size: 14px; }

/* Auch die schlichten Zeilen, etwa in den Einstellungen. */
body.tv .row {
  min-height: 68px;
  padding: var(--space-s) var(--space-m);
  border-bottom-color: var(--line);
  font-size: 18px;
}

/* Der Zaehler ueber einer Liste steht nicht klein in der Ecke. */
body.tv .muted.count,
body.tv .content > .count {
  font-size: 17px;
  color: var(--text-2);
}


/* ==========================================  Fernseher: sichtbare Auswahl

   In den Einstellungen war nicht zu erkennen, worauf man gerade steht:
   ein Auswahlfeld bekommt vom Browser keinen sichtbaren Rahmen, wenn der
   Fokus mit dem Steuerkreuz kommt und nicht mit der Tabulatortaste.
   Gemeldet am 29. August 2026: "wenn ich bei einstellungen auf Quelle und
   so gehe, sehe ich garnicht damit es markiert ist".

   Deshalb hier `:focus` und nicht nur `:focus-visible`. Auf einem
   Fernseher gibt es keinen Mauszeiger, der die Unterscheidung
   rechtfertigen wuerde. */

body.tv .select:focus-within {
  outline: 3px solid var(--burgundy);
  outline-offset: 2px;
  border-radius: 999px;
}

/* Die Pillenform gilt der geschlossenen Zeile. Die Quellen-Box ist ein
   `details`: aufgeklappt ist sie hunderte Punkte hoch, und 999px Rundung
   machen aus dem Kasten eine Ellipse, die das halbe Formular verdeckt.
   Am 30. August 2026 auf dem Pruefstand gesehen, im Bild kaum zu
   uebersehen. Sie behaelt ihre eigene Rundung. */
body.tv .select.multi:focus-within {
  border-radius: var(--radius-l);
}

/* Der Rahmen gehoert um das ganze Feld, nicht um das nackte Auswahlfeld
   darin. */
body.tv .select select:focus,
body.tv .select select:focus-visible { outline: none; }

body.tv .content button:focus,
body.tv .content a:focus,
body.tv .content input:focus,
body.tv .content summary:focus,
body.tv .sheet button:focus,
body.tv .sheet .select:focus-within {
  outline: 3px solid var(--burgundy);
  outline-offset: 2px;
}

/* Die Kacheln haben ihren eigenen, kraeftigeren Rahmen. Der hier soll
   ihn nicht ueberschreiben. */
body.tv .rail .chtile .open:focus,
body.tv .chcard .open:focus,
body.tv .channel .open:focus { outline-offset: 0; }


/* =========================================  Fernseher: schmale Leiste

   Nur Symbole, bis man hingeht. Sobald der Fokus in der Leiste steht,
   klappt sie auf und zeigt die Namen dazu.

   Zwei Dinge machen das ruhig statt zappelig:

   Erstens liegt die Leiste fest ueber dem Inhalt, statt eine Spalte im
   Raster breiter zu machen. Sonst wuerde bei jedem Fokuswechsel die ganze
   Seite neu umbrechen, und auf einem Stick mit vier schwachen Kernen sieht
   man das.

   Zweitens wandert nur die Breite und die Deckkraft der Namen. Die
   Symbole bleiben, wo sie sind, damit das Auge sie nicht verliert.

   `:has` waehlt die Marke oben mit aus, denn sie gehoert zur selben
   Leiste, ist aber ein eigenes Feld im Raster. Chromium 138 auf dem Stick
   kann das seit langem. */

@media (min-width: 820px) {
  body.tv {
    grid-template-columns: 96px 1fr;
  }

  body.tv .brandbar,
  body.tv .tabbar {
    position: fixed;
    left: var(--space-m);
    width: 84px;
    overflow: hidden;
    transition: width 0.18s cubic-bezier(0.2, 0, 0.2, 1);
    z-index: 30;
  }

  /* Feste Hoehe, damit die Leiste darunter buendig anschliesst. Ohne sie
     klaffte beim Aufklappen eine Luecke, weil der Schriftzug zwei Zeilen
     braucht und der Kopf dabei waechst. */
  /* Das Logo ist dunkel auf hell gezeichnet. In der schmalen Leiste steht
     es auf Burgundy und war dort kaum zu sehen. Umgekehrt wird es weiss,
     wie im Ladebildschirm. */
  body.tv .brandbar .mark { filter: brightness(0) invert(1); }

  body.tv .brandbar {
    top: var(--space-m);
    height: 64px;
    margin: 0;
    padding: var(--space-s);
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    border-radius: var(--radius-l) var(--radius-l) 0 0;
  }

  body.tv .tabbar {
    top: calc(var(--space-m) + 64px);
    bottom: var(--space-m);
    margin: 0;
    border-radius: 0 0 var(--radius-l) var(--radius-l);
  }

  /* Zusammengeklappt bleibt vom Kopf nur das Zeichen. */
  body.tv .brandbar .wordmark,
  body.tv .brandbar .profile { display: none; }

  body.tv .tabbar a {
    gap: 0;
    padding: 0;
    justify-content: center;
  }

  body.tv .tabbar a span:not(.icon) {
    max-width: 0;
    opacity: 0;
    white-space: nowrap;
    overflow: hidden;
    transition: opacity 0.14s ease, max-width 0.18s ease;
  }

  /* Aufgeklappt: sobald der Fokus in der Leiste steht. */
  body.tv:has(.tabbar:focus-within) .brandbar,
  body.tv:has(.tabbar:focus-within) .tabbar {
    width: 268px;
  }

  body.tv:has(.tabbar:focus-within) .brandbar {
    justify-content: flex-start;
    padding: var(--space-s) var(--space-l);
  }

  body.tv:has(.tabbar:focus-within) .brandbar .wordmark,
  body.tv:has(.tabbar:focus-within) .brandbar .profile { display: flex; }

  /* Einzeilig, damit die feste Hoehe reicht. */
  body.tv:has(.tabbar:focus-within) .brandbar .display {
    font-size: 15px;
    white-space: nowrap;
  }

  body.tv:has(.tabbar:focus-within) .tabbar a {
    gap: var(--space-m);
    padding: 0 var(--space-m);
    justify-content: flex-start;
  }

  body.tv:has(.tabbar:focus-within) .tabbar a span:not(.icon) {
    max-width: 180px;
    opacity: 1;
  }

  /* Die Vorschau sitzt NEBEN der Leiste, nicht darin.
     Dieselben Masse wie `boundsFor` in PlayerBridge.kt, sonst steht die
     Zeile mit Name und Knoepfen woanders als das Bild. 12 Rand plus 84
     Leiste plus 12 Abstand ergibt 108.

     Vorher lag der Kasten in der eingeklappten Leiste und war 84 Punkte
     breit. Die Meldung `es kommt nichts an` stand darin auf sechs Zeilen
     und war nicht zu lesen. Beim Aufklappen wuchs er auf 268 und schob
     sich ueber den Inhalt. */
  body.tv #surface { left: 108px; width: 196px; }
}

@media (prefers-reduced-motion: reduce) {
  body.tv .brandbar,
  body.tv .tabbar,
  body.tv .tabbar a span:not(.icon),
  body.tv #surface { transition: none; }
}
