/* ============================================================
   app.css — Passwort-Gate im Flutlicht
   ------------------------------------------------------------
   Nur Token-Referenzen (var(--...)) — keine rohen Farbwerte,
   auch nicht in Schatten oder Schein.

   Bildidee (Inhaber-Entscheidung): "nachts ins Stadion kommen".
   Schwarzer Platz, blaues Flutlicht darüber, das sich sehr
   langsam bewegt. Deshalb bleibt die Grundfläche neutral
   schwarz (elftipp-Regel) und ALLES Blau kommt aus Licht-
   flächen, die darüber liegen — siehe tokens.css.

   Bewegung: ausschliesslich transform/opacity. Der Fokusring
   erscheint immer sofort, nie mit Übergang. prefers-reduced-
   motion schaltet den Lichtdrift ganz ab (nicht auf Dauer 0 —
   das liefe unendlich schnell statt still zu stehen).
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

/* [hidden] SCHLAEGT JEDES display DURCH.
   Der Browser-Standard setzt [hidden] auf display:none — aber mit der
   NIEDRIGSTEN Spezifitaet. Jede eigene Regel, die display:flex oder
   display:grid setzt, gewinnt und zeigt das Element trotzdem an.
   Gemessen am 24.08.2026 am Abschnitt fuer aufgeloeste Takes: er trug
   hidden und stand sichtbar da, weil .ch-liste-block display:flex
   setzt. Ein Fehler, der wie ein Logikfehler aussieht und keiner ist. */
[hidden] { display: none !important; }

html, body {
  overflow-x: clip;
  min-height: 100%;
}

body {
  margin: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Die Vollhöhe hängt jetzt am Rahmen und gilt nur im bare-Zustand —
   im Reiter-Betrieb scrollt die Mitte, nicht die Seite. Siehe den
   Abschnitt "App-Rahmen" am Dateiende. */

button { font: inherit; }

/* ---------- Splash ---------- */

#splash {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-0);
}
#splash::after {
  content: "";
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--line);
  border-top-color: var(--blau);
  animation: spin 0.8s linear infinite;
}

/* ============================================================
   Flutlicht
   ------------------------------------------------------------
   Drei weiche Lichtflächen über schwarzem Grund, dazu eine
   Vignette, die die Ränder wieder zudrückt. `screen` als
   Mischmodus: auf Schwarz addiert sich Licht, statt eine Fläche
   aufzuhellen — dadurch überlagern sich die drei Kegel wie
   echte Scheinwerfer, statt sich gegenseitig auszubleichen.

   Die Flächen sind absichtlich GRÖSSER als der Bildschirm und
   driften nur wenige Prozent: sichtbar ist eine Atmosphäre, die
   sich verändert, nie ein Objekt, das sich bewegt.
   ============================================================ */

.flutlicht {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.licht {
  position: absolute;
  border-radius: 50%;
  mix-blend-mode: screen;
}

/* Hauptkegel: von oben mittig, wie die Tribünenbeleuchtung. */
.licht--a {
  width: 130vmax;
  height: 130vmax;
  left: 50%;
  top: -68vmax;
  margin-left: -65vmax;
  background: radial-gradient(circle at center,
    var(--licht-kern) 0%,
    var(--licht-hof) 34%,
    transparent 66%);
  animation: drift-a var(--dur-licht) var(--ease-in-out) infinite alternate;
}

/* Gegenlicht unten links, schwächer — gibt dem Raum eine zweite
   Kante, damit der Screen nicht symmetrisch und flach wirkt. */
.licht--b {
  width: 90vmax;
  height: 90vmax;
  left: -40vmax;
  bottom: -46vmax;
  background: radial-gradient(circle at center,
    var(--licht-hof) 0%,
    transparent 62%);
  animation: drift-b calc(var(--dur-licht) * 1.45) var(--ease-in-out) infinite alternate;
}

/* Lila-Schimmer rechts: reine Tiefe. Lila ist im Farbsystem die
   Manager-Farbe — hier bewusst nur als fernes Streulicht, weit
   unter der Schwelle, an der es als Bedeutungsträger gelesen
   würde (es färbt keine Fläche und keine Zahl). */
.licht--c {
  width: 76vmax;
  height: 76vmax;
  right: -34vmax;
  top: 22vmax;
  background: radial-gradient(circle at center,
    var(--licht-fern) 0%,
    transparent 64%);
  animation: drift-c calc(var(--dur-licht) * 1.9) var(--ease-in-out) infinite alternate;
}

/* Vignette: drückt die Ränder auf die Grundfläche zurück, damit
   das Licht in der Mitte sitzt und nicht am Bildschirmrand
   abgeschnitten wirkt. */
.flutlicht::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 90% 70% at 50% 38%,
    transparent 40%,
    var(--bg-0) 92%);
}

@keyframes drift-a {
  from { transform: translate3d(-5%, 0, 0) scale(1); }
  to   { transform: translate3d(5%, 4%, 0) scale(1.14); }
}
@keyframes drift-b {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(12%, -8%, 0) scale(1.2); }
}
@keyframes drift-c {
  from { transform: translate3d(0, 0, 0) scale(1.05); }
  to   { transform: translate3d(-9%, 7%, 0) scale(1); }
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ============================================================
   Gate-Layout
   ============================================================ */

.gate {
  position: relative;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--sp-7) var(--sp-4);
  isolation: isolate;
}

.gate-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-7);
  animation: gate-auf var(--dur-rank) var(--ease-out) both;
}

@keyframes gate-auf {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Wortmarke ----------
   Bewusst echter Text statt SVG-Pfad: der Schein (text-shadow)
   lässt sich so aus denselben Licht-Tokens speisen wie das
   Flutlicht dahinter, und die Größe skaliert über die
   Typo-Skala mit. Ein echtes Logo-Bild ersetzt später den
   Inhalt dieses Blocks, ohne dass das Layout sich ändert. */

.gate-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  text-align: center;
}

.wordmark {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
}

.wordmark-main {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-display);
  line-height: .88;
  letter-spacing: -.035em;
  color: var(--text-1);
  /* Der Schein kommt aus denselben Tokens wie die Lichtflächen —
     die Schrift steht dadurch IM Licht, nicht davor. */
  text-shadow:
    0 0 32px var(--licht-kern),
    0 0 88px var(--licht-hof);
}

.wordmark-sub {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h3);
  letter-spacing: .34em;
  /* Optischer Ausgleich: letter-spacing hängt rechts einen
     Leerraum an, der die Zeile sonst links verschoben wirken
     lässt. */
  text-indent: .34em;
  color: var(--blau);
  text-transform: uppercase;
}

.gate-saison {
  margin: 0;
  font-size: var(--fs-caption);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ---------- Karte ----------
   Liegt als mattierte Scheibe über dem Licht: der Hintergrund
   scheint gedämpft durch, damit die Karte Teil der Szene bleibt
   statt ein aufgeklebtes Rechteck zu sein. */

.gate-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-modal);
  background: color-mix(in srgb, var(--bg-1) 72%, transparent);
  box-shadow: var(--schatten-karte);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* Lichtkante oben: die Karte fängt das Flutlicht an ihrer
   Oberkante — dasselbe Prinzip wie eine angestrahlte Fläche. */
.gate-card::before {
  content: "";
  display: block;
  height: 1px;
  margin: calc(var(--sp-5) * -1) calc(var(--sp-5) * -1) 0;
  border-radius: var(--r-modal) var(--r-modal) 0 0;
  background: linear-gradient(90deg,
    transparent,
    var(--line-strong) 22%,
    var(--blau-tint) 50%,
    var(--line-strong) 78%,
    transparent);
}

/* ---------- Feld ---------- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.field-label {
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text-2);
}

.input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.input-icon {
  position: absolute;
  left: var(--sp-3);
  display: flex;
  color: var(--text-3);
  pointer-events: none;
  transition: color var(--dur-fast) var(--ease-out);
}
.input-icon svg { display: block; width: 18px; height: 18px; }

.input {
  width: 100%;
  min-height: var(--touch-min);
  padding: 0 var(--sp-4) 0 calc(var(--sp-3) + 18px + var(--sp-2));
  border-radius: var(--r-ctl);
  border: 1px solid var(--line-strong);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.input::placeholder { color: var(--text-3); }

.input:hover { border-color: var(--text-3); }

.input:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-color: var(--blau);
  /* Fokusring nie einblenden: er muss im selben Moment da sein,
     in dem der Fokus ankommt. */
  transition: none;
}

.input-wrap:focus-within .input-icon { color: var(--blau); }

.input[aria-invalid="true"] { border-color: var(--live); }

/* ============================================================
   Knopf — acht Zustände
   default · hover · focus-visible · active · disabled ·
   loading · error · success
   ============================================================ */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-5);
  border: none;
  border-radius: var(--r-ctl);
  font-family: var(--font-body);
  font-size: var(--fs-btn);
  font-weight: 600;
  cursor: pointer;
  transition:
    transform var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}

.btn--block { width: 100%; }

/* default */
.btn--marke {
  background: var(--blau);
  color: var(--blau-ink);
}

/* Der blaue Schein liegt auf einer eigenen Ebene, damit die
   Zustandswechsel nur deren OPAZITÄT bewegen. Ein animierter
   box-shadow müsste bei jedem Bild neu gezeichnet werden — und
   die Regel lautet: es bewegen sich ausschliesslich transform
   und opacity. */
.btn--marke::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--schatten-knopf);
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out);
}

/* hover */
.btn--marke:hover:not(:disabled) { background: var(--blau-strong); }

/* focus-visible — sofort sichtbar, ohne Übergang auf dem Ring */
.btn:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/* active — gedrückt heißt: näher an der Fläche, also kein Schein */
.btn--marke:active:not(:disabled) {
  transform: translate3d(0, 1px, 0) scale(.99);
}

/* disabled */
.btn:disabled {
  opacity: .4;
  cursor: not-allowed;
  transform: none;
}

/* Schein aus: gesperrt, gedrückt, oder schon geschafft */
.btn--marke:disabled::after,
.btn--marke:active:not(:disabled)::after,
.btn--marke[data-state="success"]::after { opacity: 0; }

/* loading */
.btn-label { transition: opacity var(--dur-fast) var(--ease-out); }

.btn-spinner,
.btn-check {
  display: none;
  color: var(--blau-ink);
}
.btn-spinner {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: .8;
}
.btn-check svg { display: block; }

.btn[data-state="loading"] { cursor: wait; }
.btn[data-state="loading"] .btn-label { opacity: 0; position: absolute; }
.btn[data-state="loading"] .btn-spinner {
  display: block;
  animation: spin .8s linear infinite;
}

/* success — BEWUSST NICHT grün.
   Das Farbsystem (tokens.css) reserviert Grün ausschliesslich für
   verdiente Punkte. Ein bestandenes Passwort sind keine Punkte;
   würde der Knopf hier grün, wäre die Regel schon auf dem ersten
   Screen gebrochen und Grün hätte in der Managertabelle keine
   eindeutige Bedeutung mehr. Der Haken allein trägt die Meldung,
   die Marke bleibt blau. */
.btn[data-state="success"] .btn-label { opacity: 0; position: absolute; }
.btn[data-state="success"] .btn-check { display: block; }

/* error */
.btn[data-state="error"] { animation: ruck var(--dur-med) var(--ease-out); }

@keyframes ruck {
  0%, 100% { transform: translate3d(0, 0, 0); }
  25%      { transform: translate3d(-5px, 0, 0); }
  75%      { transform: translate3d(5px, 0, 0); }
}

/* ---------- Fehlerzeile: bleibt stehen, kein Toast ---------- */

.hint {
  margin: 0;
  min-height: 1em;
  font-size: var(--fs-caption);
}

.hint--err { color: var(--live); }

/* ---------- Platzhalter nach erfolgreichem Gate ---------- */

.gate-next {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  color: var(--text-2);
  font-size: var(--fs-h3);
}

/* Nur für Screenreader: kein Bildschirm-Layout, aber im Accessibility-
   Baum vorhanden. Wird von der Schrittanzeige unten gebraucht (die
   sichtbaren Punkte sind aria-hidden, dieser Text sagt "Schritt X von 3"). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   Identitäts-Auswahl — Liga -> Name -> Bestätigung
   ------------------------------------------------------------
   Sitzt in derselben .gate/.gate-inner/.gate-card-Hülle wie das
   Passwort-Gate (bewusst wiederverwendet, nicht dupliziert): der
   Screen soll sich wie die direkte Fortsetzung anfühlen, nicht wie
   ein Ortswechsel. Nur die INNEREN Bausteine sind neu.
   ============================================================ */

/* ---------- Schrittanzeige ----------
   Drei kurze Schritte, deshalb bewusst zurückhaltend: drei Punkte,
   zwei Verbindungsstriche, keine Beschriftung außer für Screenreader. */
.ident-progress {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
}

.ident-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.ident-dot.is-active {
  background: var(--blau);
  transform: scale(1.3);
}
.ident-dot.is-done { background: var(--blau); }

.ident-rule {
  width: 28px;
  height: 1px;
  background: var(--line-strong);
}

.ident-card { gap: var(--sp-5); }

.ident-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.ident-head--center { text-align: center; }

.ident-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h2);
  color: var(--text-1);
}

.ident-sub {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-2);
}

/* ---------- Zurück-Weg ----------
   Eigener Knopf über der Kopfzeile, nicht Teil der Aktionsreihe unten:
   "falsche Liga getippt" ist ein Korrekturweg, kein gleichwertiger
   dritter Knopf neben Bestätigen/Ablehnen. */
.ident-back {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: var(--touch-min);
  padding: 0 var(--sp-2) 0 0;
  border: none;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 500;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
}
.ident-back svg { transform: rotate(180deg); display: block; }
.ident-back:hover { color: var(--text-1); }
.ident-back:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-ctl);
}
.ident-back:active { transform: translate3d(-1px, 0, 0); }

/* ---------- Liga-/Manager-Liste ----------
   Echte Knöpfe statt <select>: gestaltbar und auf dem Handy leichter
   zu treffen. Liga-Liste (11 Einträge) bleibt ohne Innenscroll — sie
   ist kurz genug, um komplett auf den Bildschirm zu passen. Die
   Manager-Liste bekommt ab > 8 Einträgen ein max-height + Innenscroll
   (ident-list--scroll), damit Kopfzeile und "Andere Liga"-Weg auf dem
   Handy sichtbar bleiben, statt dass die Seite endlos wächst. */
.ident-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ident-list--scroll {
  max-height: 46vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: var(--sp-1);
  /* Weicher Ausklang statt hartem Kante: signalisiert "hier geht noch
     was", ohne einen zusätzlichen Schatten-Layer zu brauchen. */
  mask-image: linear-gradient(to bottom, black calc(100% - 28px), transparent 100%);
}

.ident-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.ident-item-icon { display: flex; color: var(--text-3); flex: none; }
.ident-item-icon svg { display: block; }

/* Liga mit Ebene: Name oben, Ebene darunter. Der Eintrag wird dadurch
   zweizeilig und wächst über die Mindesthöhe hinaus — bewusst so, eine
   zweite Zeile liest sich besser als eine gequetschte erste.
   Die Ebene ist Sachinformation und bleibt deshalb grau: Farbe ist im
   System für Bedeutung reserviert (siehe tokens.css). */
.ident-item-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.ident-item-sub {
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--text-3);
}
.ident-item:has(.ident-item-sub) {
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
}

.ident-item:hover {
  border-color: var(--text-3);
  background: var(--bg-1);
}
.ident-item:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-color: var(--blau);
  transition: none;
}
.ident-item:active {
  transform: translate3d(0, 1px, 0);
  background: var(--bg-1);
}

.ident-loading, .ident-empty {
  margin: 0;
  padding: var(--sp-4) 0;
  text-align: center;
  font-size: var(--fs-small);
  color: var(--text-3);
}

/* ---------- Bestätigung ----------
   Der Kern des Screens: Name groß und ruhig, Liga darunter, dann eine
   eigene, gedämpfte Hinweisbox ("hier bitte kurz hinschauen") — sie
   bekommt bewusst nur eine ORANGE KANTE, keine volle Fläche: Orange ist
   im Farbsystem "Warnung", und eine falsch gewählte Prognose-Person
   ist noch KEIN Fehler, nur eine Stelle, an der man kurz hinschauen
   sollte, solange es noch gratis korrigierbar ist. */
.ident-confirm-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-5) var(--sp-4);
  border-radius: var(--r-card);
  background: var(--bg-0);
  border: 1px solid var(--line);
  text-align: center;
}
.ident-confirm-lead {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-2);
}
.ident-confirm-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-h1);
  line-height: 1.15;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.ident-confirm-liga {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-2);
}

.ident-caution {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
}
.ident-caution-icon { flex: none; color: var(--warn); display: flex; margin-top: 1px; }
.ident-caution-icon svg { display: block; }
.ident-caution-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ident-caution-title {
  margin: 0;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-1);
}
.ident-caution-text {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-2);
}

.ident-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* ---------- Platzhalter nach dem Bestätigen ---------- */
.ident-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-2);
  text-align: center;
  color: var(--text-2);
}
.ident-placeholder-icon {
  display: flex;
  width: 48px;
  height: 48px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--blau-tint);
  color: var(--blau);
}
.ident-placeholder-icon svg { width: 24px; height: 24px; }
.ident-placeholder p { margin: 0; font-size: var(--fs-h3); color: var(--text-1); }

/* Schrittwechsel: leichter Versatz, kein Karussell. Läuft jedes Mal neu
   an, weil das Panel per innerHTML ausgetauscht wird (frisches Element). */
@keyframes ident-panel-auf {
  from { opacity: 0; transform: translate3d(0, 8px, 0); }
  to   { opacity: 1; transform: none; }
}
.ident-card > * { animation: ident-panel-auf var(--dur-med) var(--ease-out) both; }

/* ---------- Toast (aus ui.js) ---------- */

#toasts {
  position: fixed;
  left: 0;
  right: 0;
  bottom: var(--sp-5);
  z-index: 50;
  display: flex;
  justify-content: center;
  padding: 0 var(--sp-4);
  pointer-events: none;
}

.toast {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-2);
  color: var(--text-1);
  font-size: var(--fs-small);
  box-shadow: var(--schatten-karte);
  animation: toast-auf var(--dur-med) var(--ease-out);
}

.toast--err { color: var(--live); }

@keyframes toast-auf {
  from { opacity: 0; transform: translate3d(0, 8px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Offline / leer (aus router.js) ---------- */

.offline, .empty {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  color: var(--text-2);
}

.offline b, .empty b {
  color: var(--text-1);
  font-family: var(--font-display);
  font-size: var(--fs-h2);
}

/* ---------- Leerzustand INNERHALB einer Liste ----------
   `.empty` ist als GANZSEITIGER Zustand gebaut: 100dvh hoch, mittig, für
   den Fall "diese Ansicht hat gar nichts". Das ist dort richtig.

   In einer Liste ist es falsch, und zwar sichtbar: gemessen am 24.08.2026
   war der Leerzustand der offenen Takes 812 Pixel hoch — eine volle
   Bildschirmhöhe für zwei Zeilen Text, mit einer Lücke davor, die aussah,
   als wäre etwas nicht geladen.

   Deshalb hier eine gedämpfte Variante: derselbe Bau, dieselben Farben,
   nur ohne den Anspruch auf die ganze Höhe. Die Schriftgröße geht mit
   herunter — eine h2-große Überschrift für "noch kein Take" nähme dem
   Abschnittstitel darüber den Rang. */
.ch-liste .empty,
.fd-liste .empty,
.lt-takes .empty {
  min-height: 0;
  padding: var(--sp-6) var(--sp-4);
  border: 1px dashed var(--line);
  border-radius: var(--r-card);
}
.ch-liste .empty b,
.fd-liste .empty b,
.lt-takes .empty b { font-size: var(--fs-h3); }
.ch-liste .empty p,
.fd-liste .empty p,
.lt-takes .empty p { margin: 0; font-size: var(--fs-small); }
.offline-stand { color: var(--text-3); font-size: var(--fs-caption); }

.btn--ghost {
  background: transparent;
  color: var(--text-1);
  border: 1px solid var(--line-strong);
}
.btn--ghost:hover:not(:disabled) {
  border-color: var(--text-3);
  background: var(--bg-1);
}

/* ============================================================
   Bewegung reduziert
   ------------------------------------------------------------
   Der Lichtdrift wird ABGESCHALTET, nicht beschleunigt: eine
   Animationsdauer von 0 würde endlos schnell laufen. Die
   Lichtflächen bleiben sichtbar — die Atmosphäre geht nicht
   verloren, sie steht nur still.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .licht { animation: none; }
  .gate-inner { animation: none; }
  .ident-card > * { animation: none; }
  .ident-dot { transition: none; }
  .btn[data-state="error"] { animation: none; }
  .btn--marke:active:not(:disabled) { transform: none; }
  .toast { animation: none; }
  .btn-spinner,
  #splash::after { animation: blinken 1.2s steps(1) infinite; }

  /* Tabellenprognose: der Fortschrittsbalken springt statt zu gleiten,
     der Einrast-Puls entfällt ganz, Hover-Anhebungen bleiben aus. */
  .tp-progress-fill { transition: none; }
  .tp-picker { animation: none; }
  .tp-row.is-just-placed .tp-feld { animation: none; }
  .tp-feld,
  .tp-slot-chevron,
  .tp-opt { transition: none; }
}

@keyframes blinken {
  0%, 49%   { opacity: .85; }
  50%, 100% { opacity: .35; }
}

/* ============================================================
   Klein (geprüft bei 320 / 375 / 414 px)
   ============================================================ */

@media (max-width: 380px) {
  .gate { padding: var(--sp-6) var(--sp-3); }
  .gate-inner { gap: var(--sp-6); }
  .gate-card { padding: var(--sp-4); }
  .gate-card::before {
    margin: calc(var(--sp-4) * -1) calc(var(--sp-4) * -1) 0;
  }
  .wordmark-sub { letter-spacing: .22em; text-indent: .22em; }
}

/* ============================================================
   Tabellenprognose — 18 Vereine auf 18 Tabellenplätze
   ------------------------------------------------------------
   Mobile-first und einspaltig: Fortschritt oben, darunter die 18
   Tabellenplätze als Liste, unten eine sticky Aktionsleiste. Jeder
   Platz klappt bei Bedarf eine Auswahl mit Suchfeld unter sich auf.
   Der frühere Wappen-Vorrat (seitlich scrollender Streifen mobil,
   sticky Spalte ab 880px) ist am 25.08.2026 ersatzlos entfallen —
   die Auswahl kommt jetzt zum Platz statt der Platz zum Wappen.
   Deshalb bleibt es auf JEDER Breite eine Spalte (nur Grid-Areas
   + flex-direction ändern sich) — kein zweites Markup fürs
   breite Layout.

   Zonen-Markierung OHNE Grün (Grün ist ausschliesslich für
   verdiente Punkte reserviert, siehe tokens.css): Champions-
   League-Plätze (1-4) bekommen die Blau-Familie — Blau markiert
   im Farbsystem ohnehin "Rang 1", das passt inhaltlich. Europa
   League und Conference League benutzen DIESELBE Farbe in
   ABGESTUFTER Kantenstärke/-art (dick durchgezogen -> dünn
   durchgezogen -> gestrichelt) statt einer weiteren Farbe, dazu
   IMMER eine Text-Pille (CL/EL/Conf.) — Farbe ist nie die einzige
   Information. Relegation bekommt Orange (im Farbsystem exakt
   "Warnung"), Abstieg Rot (im Farbsystem für Absteiger
   ausdrücklich zugelassen).

   Auswahl-Zustand (Antippen-und-Setzen) bewusst über box-shadow
   statt border-color gelöst: die Zonen-Kante links (border-left)
   bleibt dadurch auch bei ausgewähltem/Drop-Target-Platz farblich
   unangetastet, es gibt keinen Kollisions-Fall zwischen "diese
   Zeile ist Abstiegsplatz" und "dieser Platz ist gerade Ziel".
   ============================================================ */

.tp {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas: "head" "table" "footer";
  gap: var(--sp-5);
  max-width: 720px;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
}

/* ---------- Kopf + Fortschritt ---------- */

.tp-head { grid-area: head; display: flex; flex-direction: column; gap: var(--sp-3); }

.tp-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h1);
  color: var(--text-1);
  overflow-wrap: anywhere;
}

.tp-sub { margin: 0; font-size: var(--fs-small); color: var(--text-2); }

.tp-progress { display: flex; flex-direction: column; gap: var(--sp-2); }

.tp-progress-track {
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--bg-1);
  border: 1px solid var(--line);
  overflow: hidden;
}

.tp-progress-fill {
  height: 100%;
  width: 100%;
  transform: scaleX(var(--pct, 0));
  transform-origin: left center;
  background: var(--blau);
  border-radius: inherit;
  transition: transform var(--dur-med) var(--ease-out);
}

.tp-progress-text {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* ---------- Wappen ----------
   FREIGESTELLT, sobald ein echtes Bild vorliegt: keine runde
   Farbfläche darunter, keine Rundung, kein Schleier — nur die Form
   des Wappens (Ansage des Inhabers, 25.08.2026). Die Vereinsfarbe
   bleibt ausschliesslich der RÜCKFALL: solange das Bild lädt und
   wenn das CDN ausfällt. ui.js nimmt `crest-frei` im onerror des
   Bildes wieder ab, dann steht das Kürzel wieder auf dem farbigen
   Kreis. Die Farbe kommt weiterhin als DATENWERT (--crest-color per
   inline style), nie als feste CSS-Regel je Verein. */
.tp-crest-visual {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--crest-color, var(--bg-2));
}

.tp-crest-visual--klein { width: 28px; height: 28px; }

/* Das Kürzel darunter wäre hinter dem echten Wappen ein zweites,
   halb durchscheinendes Wappen — es geht mit dem Kreis zusammen weg. */
.tp-crest-visual.crest-frei {
  background: none;
  background-image: none;
  border-radius: 0;
}
.tp-crest-visual.crest-frei .tp-crest-kuerzel { display: none; }
/* Ohne Fläche braucht das Bild auch keinen Abstand zur Rundung mehr. */
.tp-crest-visual.crest-frei .crest-bild { padding: 0; }

.tp-crest-kuerzel {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 12px;
  letter-spacing: .01em;
  color: var(--crest-ink);
}

/* ---------- Tabelle ---------- */

.tp-table { grid-area: table; list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }

/* flex-wrap, damit die aufgeklappte Auswahl als eigene Zeile unter
   Platznummer, Feld und Zonen-Pille sitzt — sie ist Teil DIESER Zeile
   und darf deshalb nicht daneben, sondern muss darunter stehen. */
.tp-row { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }

.tp-row-pos {
  flex: none;
  width: 26px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* ---------- Das Feld: Platz + Kreuz in EINEM Rahmen ----------
   Der Rahmen liegt auf dem Wrapper, nicht auf dem Knopf: das Kreuz
   soll IM Feld neben der Mannschaft stehen ("per Kreuz neben der
   Mannschaft rückgängig"), und ein Knopf im Knopf ist ungültiges
   HTML — der Screenreader liest ihn nicht, und der Klick landet
   unzuverlässig. Also zwei Knöpfe nebeneinander in einem Rahmen,
   getrennt durch eine Haarlinie: der eine öffnet die Auswahl, der
   andere macht den Platz frei. */
.tp-feld {
  /* Basis 0, nicht auto: mit auto ist die hypothetische Breite des
     Feldes sein Inhalt, und bei 320px schiebt das die Zonen-Pille in
     eine eigene Zeile, statt das Feld schrumpfen zu lassen. */
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.tp-feld:hover { border-color: var(--text-3); background: var(--bg-1); }

/* Offen = betont, aber NICHT über border-color: die Zonen-Kante links
   bleibt dadurch farblich unangetastet (siehe Kopf des Abschnitts). */
.tp-row.is-offen .tp-feld { background: var(--blau-tint); box-shadow: inset 0 0 0 1px var(--blau); }

.tp-slot {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border: none;
  border-radius: inherit;
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
}
/* Der Ring liegt INNEN, sonst überdeckt er den Rahmen des Feldes. */
.tp-slot:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.tp-slot:active { transform: translate3d(0, 1px, 0); }

.tp-slot-chevron {
  flex: none;
  display: grid;
  place-items: center;
  color: var(--text-3);
  transform: rotate(90deg);
  transition: transform var(--dur-fast) var(--ease-out);
}
.tp-slot-chevron svg { width: 16px; height: 16px; }
.tp-row.is-offen .tp-slot-chevron { transform: rotate(-90deg); }

.tp-clear {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  align-self: stretch;
  border: none;
  border-left: 1px solid var(--line);
  /* Die Ecken folgen dem Feld, sonst steht die Hover-Flaeche eckig
     ueber dessen Rundung. Minus 1px fuer den Rahmen des Feldes. */
  border-radius: 0 calc(var(--r-ctl) - 1px) calc(var(--r-ctl) - 1px) 0;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.tp-clear:hover { color: var(--text-1); background: var(--bg-1); }
.tp-clear:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; transition: none; }
.tp-clear svg { width: 16px; height: 16px; }

.tp-slot-placeholder { flex: 1 1 auto; color: var(--text-3); font-size: var(--fs-small); }

.tp-slot-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-small);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Kurzer Einrast-Puls, wenn ein Wappen NEU auf diesem Platz landet —
   nur skalieren + einblenden, kein Überschwingen. */
@keyframes tp-slot-snap {
  from { transform: scale(.94); opacity: .65; }
  to   { transform: scale(1); opacity: 1; }
}
.tp-row.is-just-placed .tp-feld { animation: tp-slot-snap var(--dur-fast) var(--ease-out); }

/* ---------- Zonen-Pille ----------
   Steht IMMER neben der Kante — Farbe ist damit nie die einzige
   Information (siehe Datei-Kopf-Kommentar). */
.tp-zone-pill {
  flex: none;
  min-width: 40px;
  padding: 2px var(--sp-2);
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: .02em;
  white-space: nowrap;
}
.tp-zone-pill--cl   { color: var(--blau-ink); background: var(--blau); }
.tp-zone-pill--el   { color: var(--blau); background: var(--blau-tint); border: 1px solid var(--blau); }
.tp-zone-pill--conf { color: var(--blau); background: transparent; border: 1px dashed var(--blau); }
.tp-zone-pill--rel  { color: var(--warn); background: transparent; border: 1px solid var(--warn); }
.tp-zone-pill--down { color: var(--bg-0); background: var(--down); }

/* ---------- Zonen-Kante ----------
   Dieselbe Farbe in Abstufungen (CL/EL/Conf.) statt einer dritten
   oder vierten Farbe — "Abstufungen, Kanten, Beschriftung" (siehe
   Datei-Kopf-Kommentar), nicht Grün.

   Stärke: höchstens 2px, und zwar über var(--edge-marke) aus
   tokens.css. Das ist kein beliebiger Wert, sondern das dokumentierte
   Signaturelement des Markenkits ("Kante links, Rang 1"). Der
   Design-Prüfer schlägt bei linken Farbkanten grundsätzlich an, weil
   dicke Akzentstreifen an Karten ein typisches KI-Muster sind — hier
   ist es aber die reale Konvention für Fußballtabellen (Europa- und
   Abstiegszonen) UND die Hausmarke. Bewusst beibehalten, aber von
   4px auf die Signaturstärke zurückgenommen: als Kartenstreifen
   gelesen wäre 4px genau das gemeinte Muster, als Tabellenkante ist
   2px die gewachsene Form. Die Zonen-Pille daneben trägt ohnehin die
   eindeutige Beschriftung — die Kante ist Verstärkung, nicht die
   einzige Auskunft. */
.tp-row--cl .tp-feld   { border-left: var(--edge-marke); }
.tp-row--el .tp-feld   { border-left: 2px dashed var(--blau); }
.tp-row--conf .tp-feld { border-left: 1px dashed var(--blau); }
.tp-row--rel .tp-feld  { border-left: 2px solid var(--warn); }
.tp-row--down .tp-feld { border-left: 2px solid var(--down); }

/* ---------- Sticky Aktionsleiste ---------- */
.tp-footer {
  grid-area: footer;
  position: sticky;
  bottom: 0;
  z-index: 5;
  margin: 0 calc(var(--sp-4) * -1) calc(var(--sp-4) * -1);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--bg-0) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.tp-footer-inner {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-4);
}
.tp-footer-hint {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-2);
  text-align: right;
}

/* ---------- Die Auswahl ----------
   Klappt unter dem Platz auf, um den es geht — eingerückt auf die
   Höhe des Feldes, damit sichtbar bleibt, zu welcher Zeile sie
   gehört. Sie liegt bewusst NICHT als Overlay über der Liste: ein
   Overlay verdeckt genau die Nachbarplätze, gegen die man den Verein
   abwägt.

   --bg-2 ist im Farbsystem die Ebene für Modals und Dropdowns; die
   Auswahl darf sich vom Seitengrund abheben, ohne eine neue Fläche
   zu erfinden. */
.tp-picker {
  flex: 0 0 100%;
  margin-left: calc(26px + var(--sp-3));
  border-radius: var(--r-ctl);
  border: 1px solid var(--line-strong);
  background: var(--bg-2);
  box-shadow: var(--schatten-karte);
  overflow: hidden;
  animation: tp-picker-auf var(--dur-fast) var(--ease-out) both;
}

@keyframes tp-picker-auf {
  from { opacity: 0; transform: translate3d(0, -4px, 0); }
  to   { opacity: 1; transform: none; }
}

.tp-picker-such {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
}
/* Der Fokusring sitzt auf der ganzen Suchzeile, nicht auf dem nackten
   Eingabefeld: das Feld hat keinen eigenen Rahmen, ein Ring mitten im
   Kasten sähe aus wie ein zweites Bauteil. */
.tp-picker-such:focus-within { box-shadow: inset 0 0 0 2px var(--focus); }

.tp-picker-lupe { flex: none; display: grid; place-items: center; color: var(--text-3); }
.tp-picker-lupe svg { width: 16px; height: 16px; }

.tp-picker-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 36px;
  border: none;
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-small);
}
.tp-picker-input::placeholder { color: var(--text-3); }
.tp-picker-input:focus { outline: none; }

.tp-picker-close {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.tp-picker-close:hover { color: var(--text-1); background: var(--bg-1); }
.tp-picker-close:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; transition: none; }
.tp-picker-close svg { width: 16px; height: 16px; }

/* overscroll-behavior: contain — sonst scrollt am Ende der Liste die
   ganze Seite weiter, und man verliert den Platz aus dem Blick, den
   man gerade vergibt. */
.tp-picker-liste {
  display: flex;
  flex-direction: column;
  max-height: min(46vh, 320px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-1);
}

.tp-opt {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.tp-opt:hover { background: var(--bg-1); }
.tp-opt:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; transition: none; }

.tp-opt-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tp-opt-meta {
  flex: none;
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.tp-picker-trenner {
  margin: var(--sp-3) var(--sp-3) var(--sp-1);
  font-size: var(--fs-caption);
  color: var(--text-3);
}

.tp-picker-leer {
  margin: 0;
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
  font-size: var(--fs-small);
  color: var(--text-3);
}

/* ============================================================
   Klein (geprüft bei 320 / 375 / 414 px)
   ============================================================ */
@media (max-width: 380px) {
  .tp { padding: var(--sp-4) var(--sp-3) var(--sp-3); gap: var(--sp-4); }
  /* Auf 320px zählt jeder Pixel für den Vereinsnamen: das Wappen wird
     kleiner, die Auswahl rückt bis an die Platznummer heran. */
  .tp-row { gap: var(--sp-2); }
  .tp-crest-visual { width: 30px; height: 30px; }
  .tp-crest-visual--klein { width: 26px; height: 26px; }
  .tp-slot { gap: var(--sp-2); padding: var(--sp-2); }
  .tp-row-pos { width: 22px; }
  .tp-zone-pill { min-width: 34px; }
  /* Auf einem belegten Platz traegt das Kreuz die Auskunft "hier laesst
     sich etwas tun" — der Chevron daneben sagt dasselbe ein zweites Mal
     und kostet den Platz, an dem der Vereinsname abgeschnitten wird.
     Auf einem FREIEN Platz bleibt er: dort ist er das einzige Zeichen,
     dass sich eine Liste oeffnet. */
  .tp-row.is-occupied .tp-slot-chevron { display: none; }
  .tp-picker { margin-left: 0; }
  .tp-footer { margin: 0 calc(var(--sp-3) * -1) calc(var(--sp-3) * -1); padding-left: var(--sp-3); padding-right: var(--sp-3); }
}

/* ============================================================
   Weg-Fortschritt — Gesamtfortschritt über den GANZEN Prognose-Weg
   ------------------------------------------------------------
   EIN gemeinsames Bauteil für prognose-tabelle.js (Schritt 1) UND
   prognose-stats.js (Schritt 2-6) — der Übergang zwischen beiden
   Views soll sich wie EIN Weg anfühlen, nicht wie zwei getrennte
   Formulare. Bewusst ZUSÄTZLICH zur eigenen 18-Felder-Anzeige der
   Tabellenprognose (.tp-progress): die eine sagt "wie weit bin ich
   in DIESER Aufgabe", die andere "wie weit bin ich im GANZEN Weg".
   ============================================================ */
.weg {
  position: relative;
  z-index: 1;
  max-width: 720px;
  margin: 0 auto;
  padding: var(--sp-4) var(--sp-4) 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.weg-track {
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--bg-1);
  overflow: hidden;
}
.weg-fill {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(var(--weg-pct, 0));
  transform-origin: left center;
  background: var(--blau);
  border-radius: inherit;
  transition: transform var(--dur-med) var(--ease-out);
}
.weg-label {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}
/* Ruhige Zeile mit dem festen Stichtag (Aufgabe 3): kein Countdown-Banner,
   nur die reine Information, dass es einen Stichtag gibt. */
.weg-deadline {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}

/* ============================================================
   Statistik-Prognose (prognose-stats.js)
   ------------------------------------------------------------
   Fünf Fragen in EINEM View, dasselbe State-Maschine-Muster wie
   identitaet.js/prognose-tabelle.js: Panel wird per innerHTML
   getauscht, EIN delegierter Klick-Handler bleibt über alle
   Schritte bestehen.
   ============================================================ */
.ps {
  position: relative;
  z-index: 1;
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--sp-4) var(--sp-4);
  display: flex;
  flex-direction: column;
}

.ps-panel { display: flex; flex-direction: column; gap: var(--sp-5); padding-top: var(--sp-5); }

.ps-head { display: flex; flex-direction: column; gap: var(--sp-1); }
.ps-head--center { text-align: center; align-items: center; }
.ps-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h1);
  color: var(--text-1);
}
/* tabindex="-1" macht die Überschrift zum Fokusziel nach jedem
   Schrittwechsel (siehe prognose-stats.js) — kein sichtbarer Ring
   nötig, das ist reine Tastatur-/Screenreader-Navigation. */
.ps-h1:focus-visible { outline: none; }
.ps-sub { margin: 0; font-size: var(--fs-small); color: var(--text-2); }
.ps-note {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px dashed var(--line-strong);
  font-size: var(--fs-caption);
  color: var(--text-2);
}

/* ---------- Vereins-Auswahlgitter (Überraschung/Enttäuschung) ---------- */
.ps-club-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--sp-2);
}
.ps-club {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.ps-club:hover:not(:disabled) { border-color: var(--text-3); background: var(--bg-1); }
.ps-club:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.ps-club:active:not(:disabled) { transform: translate3d(0, 1px, 0); }
.ps-club.is-selected { background: var(--blau-tint); box-shadow: inset 0 0 0 1px var(--blau); }
.ps-club:disabled, .ps-club.is-disabled { opacity: .45; cursor: not-allowed; }
.ps-club-name { flex: 1 1 auto; min-width: 0; font-size: var(--fs-small); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-club-note { flex: none; font-size: 10.5px; color: var(--text-3); max-width: 72px; }

/* ---------- gemeinsames Vereins-/Spieler-Abzeichen ----------
   Wie .tp-crest-visual: Vereinsfarbe kommt als DATENWERT
   (--crest-color, inline style), nie als feste Regel je Verein.
   Spieler-Badges nutzen dieselbe Klasse mit den Initialen statt dem
   Vereinskürzel (siehe playerBadgeHtml in prognose-stats.js) — es
   gibt noch keine Spielerfotos (photoUrl bleibt bis zur
   Kickbase-Anbindung null). */
.ps-crest {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--crest-color, var(--bg-2));
  box-shadow: var(--schatten-crest);
}
.ps-crest-kuerzel {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 11px;
  color: var(--crest-ink);
}

/* ---------- Ränge 1./2./3. ---------- */
.ps-slots { display: flex; flex-direction: column; gap: var(--sp-2); }
.ps-slot { display: flex; align-items: center; gap: var(--sp-2); }
.ps-slot-rank {
  flex: none;
  width: 22px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--text-3);
}
.ps-slot-btn {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.ps-slot-btn:hover { border-color: var(--text-3); }
.ps-slot-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.ps-slot.is-active .ps-slot-btn { background: var(--blau-tint); box-shadow: inset 0 0 0 1px var(--blau); }
.ps-slot.is-filled .ps-slot-btn { font-weight: 600; }
.ps-slot-placeholder { color: var(--text-3); font-size: var(--fs-small); }
.ps-slot-name { font-size: var(--fs-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-slot-remove {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--touch-min);
  height: var(--touch-min);
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.ps-slot-remove svg { width: 18px; height: 18px; display: block; }
.ps-slot-remove:hover { color: var(--live); background: var(--bg-1); }
.ps-slot-remove:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* ---------- Suche + Vereinsfilter ---------- */
.ps-search-row { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.ps-search-field { position: relative; flex: 1 1 200px; display: flex; align-items: center; }
.ps-search-icon { position: absolute; left: var(--sp-3); color: var(--text-3); pointer-events: none; display: flex; }
.ps-search-icon svg { width: 18px; height: 18px; display: block; }
.ps-search-input { padding-left: calc(var(--sp-3) + 18px + var(--sp-2)); }

.select {
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line-strong);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  flex: 1 1 160px;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.select:hover { border-color: var(--text-3); }
.select:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-color: var(--blau); transition: none; }

.ps-active-hint { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Trefferliste ----------
   max-height + Innenscroll statt beliebiger Seitenlänge — bei bis zu
   24 Kandidaten (siehe filterPlayers in prognose-stats.js) bliebe die
   Seite sonst sehr lang, und die sticky Fußleiste würde weit
   wegrutschen. */
.ps-results { display: flex; flex-direction: column; gap: var(--sp-2); max-height: 46vh; overflow-y: auto; overscroll-behavior: contain; padding-right: var(--sp-1); }
.ps-results-empty { margin: 0; padding: var(--sp-4); text-align: center; color: var(--text-3); font-size: var(--fs-small); }
/* Wie viele Spieler die Startansicht nicht zeigt. Ohne diese Zeile haelt
   man einen gekappten Spieler fuer einen fehlenden — genau die
   Verwechslung, die der alte Positionsfilter erzeugt hat. */
.ps-results-rest {
  margin: var(--sp-3) 0 0;
  padding: 0 var(--sp-1);
  font-size: var(--fs-caption);
  color: var(--text-3);
  text-align: center;
}
.ps-result {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  color: var(--text-1);
  cursor: pointer;
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.ps-result:hover { border-color: var(--text-3); background: var(--bg-1); }
.ps-result:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.ps-result:active { transform: translate3d(0, 1px, 0); }
.ps-result-body { display: flex; flex-direction: column; min-width: 0; }
.ps-result-name { font-size: var(--fs-small); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-result-meta { font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Zusammenfassung vorm Absenden ---------- */
.ps-summary { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-card); background: var(--bg-1); }
.ps-summary-row { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-small); }
.ps-summary-label { color: var(--text-2); }
.ps-summary-value { color: var(--text-1); font-weight: 600; text-align: right; overflow-wrap: anywhere; }

/* ---------- Sticky Fußleiste (wie .tp-footer) ---------- */
.ps-footer {
  position: sticky;
  bottom: 0;
  z-index: 5;
  margin: 0 calc(var(--sp-4) * -1) calc(var(--sp-4) * -1);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--bg-0) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.ps-footer-inner { max-width: 720px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.ps-footer-inner--confirm .btn--marke { flex: 1 1 auto; }

@media (max-width: 380px) {
  .ps { padding: 0 var(--sp-3) var(--sp-3); }
  .ps-club-grid { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); }
  .ps-footer { margin: 0 calc(var(--sp-3) * -1) calc(var(--sp-3) * -1); padding-left: var(--sp-3); padding-right: var(--sp-3); }
}

/* ============================================================
   Reveal (prognose-reveal.js) — Zwischenstand vs. Vollvergleich
   ------------------------------------------------------------
   ZUSTIMMUNG/ABWEICHUNG OHNE GRÜN: eine Übereinstimmung mit der
   Mehrheit ist noch KEIN verdienter Punkt (die gibt es erst nach
   Saisonende) — Grün bliebe hier falsch belegt. Gelöst über
   Blau-Abstufung + Beschriftung (.match-pill), siehe Datei-Kopf von
   prognose-reveal.js.
   ============================================================ */
.pr {
  position: relative;
  z-index: 1;
  max-width: 720px;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-7);
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.pr-head { display: flex; flex-direction: column; gap: var(--sp-1); }
.pr-h1 { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h1); color: var(--text-1); }
.pr-h1:focus-visible { outline: none; }
.pr-sub { margin: 0; font-size: var(--fs-small); color: var(--text-2); }

.pr-counter { display: flex; flex-direction: column; gap: var(--sp-2); }
.pr-counter-text { margin: 0; font-size: var(--fs-small); color: var(--text-2); font-variant-numeric: tabular-nums; }
/* Macht ausdrücklich klar, dass der Zähler NICHT mehr die Bedingung ist —
   nur noch Info, entschieden wird über den Stichtag (siehe .pr-deadline). */
.pr-counter-hint { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Restzeit-Karte (Zustand A, Aufgabe 1) ----------
   Deutlich sichtbar, aber ruhig: keine laufende Uhr, nur Tage/Stunden
   (unter einer Stunde Minuten), einmal beim Rendern berechnet. --warn
   erst ab .pr-deadline--knapp (unter 6 Stunden) — Dringlichkeit ist die
   Ausnahme, nicht der Grundzustand. */
.pr-deadline {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-4);
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  background: var(--bg-1);
}
.pr-deadline-restzeit {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  color: var(--text-1);
}
.pr-deadline-wann { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }
.pr-deadline--knapp {
  border-color: var(--warn);
  background: rgba(255, 122, 69, .08); /* --warn-Ton, gleiche rgba-Machart wie --blau-tint in tokens.css */
}
.pr-deadline--knapp .pr-deadline-restzeit { color: var(--warn); }

/* ---------- "Nicht abgegeben" im Vollvergleich (Aufgabe 3/4) ----------
   Sachlich, ohne Häme, ohne Entschuldigung — keine Warnfarbe, keine rote
   Kante: das ist keine Fehlermeldung, nur eine Feststellung. */
.pr-missed {
  padding: var(--sp-4);
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  background: var(--bg-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pr-missed-title { margin: 0; font-size: var(--fs-small); font-weight: 600; color: var(--text-1); }
.pr-missed-text { margin: 0; font-size: var(--fs-caption); color: var(--text-2); }

.pr-body { display: flex; flex-direction: column; gap: var(--sp-6); }

.pr-block { display: flex; flex-direction: column; gap: var(--sp-2); }
.pr-block-title { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: var(--fs-h3); color: var(--text-1); }
.pr-block-hint, .pr-block-own { margin: 0; font-size: var(--fs-caption); color: var(--text-2); }
.pr-empty { margin: 0; padding: var(--sp-3); text-align: center; color: var(--text-3); font-size: var(--fs-small); }

/* ---------- Match-Pillen: nie grün, immer mit Text ---------- */
.match-pill {
  flex: none;
  padding: 2px var(--sp-2);
  border-radius: var(--r-pill);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  white-space: nowrap;
}
.match-pill--mehrheit { color: var(--blau-ink); background: var(--blau); }
.match-pill--eigen { color: var(--text-2); background: transparent; border: 1px dashed var(--line-strong); }

/* ---------- Tabellen-Vergleich (18 Zeilen) ---------- */
.pr-table { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.pr-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  flex-wrap: wrap;
}
.pr-row-pos { flex: none; width: 22px; text-align: center; font-family: var(--font-display); font-weight: 700; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pr-row-main { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); }
.pr-row-club { flex: 1 1 auto; min-width: 0; font-size: var(--fs-small); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-row-pct { flex: none; font-size: var(--fs-caption); color: var(--text-2); font-variant-numeric: tabular-nums; }
.pr-row-own { flex: none; font-size: 10.5px; color: var(--text-3); }

.pr-crest {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--crest-color, var(--bg-2));
}
.pr-crest-kuerzel { font-family: var(--font-display); font-weight: 800; font-size: 10px; color: var(--crest-ink); }

/* ---------- Häufigkeits-Listen (Überraschung/Enttäuschung/Spieler) ---------- */
.pr-freq-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.pr-freq-row { display: grid; grid-template-columns: 56px 1fr auto auto; align-items: center; gap: var(--sp-2); }
.pr-freq-bar-track { height: 6px; border-radius: var(--r-pill); background: var(--bg-1); overflow: hidden; }
.pr-freq-bar-fill { display: block; height: 100%; width: 100%; transform: scaleX(var(--pct, 0)); transform-origin: left center; background: var(--blau); border-radius: inherit; }
.pr-freq-label { min-width: 0; font-size: var(--fs-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-freq-pct { font-size: var(--fs-caption); color: var(--text-2); font-variant-numeric: tabular-nums; }
.pr-freq-row.is-own .pr-freq-label { font-weight: 700; color: var(--text-1); }

/* ---------- Vollvergleich (Zustand B) ----------
   190 benannte Einträge: Liga-Gruppen (native <details>, offen) mit
   Manager-Zeilen darin (native <details>, geschlossen) — Begründung
   siehe Datei-Kopf von prognose-reveal.js. */
.pr-search { max-width: 420px; }

.pr-leagues { display: flex; flex-direction: column; gap: var(--sp-3); }
.pr-league { border: 1px solid var(--line); border-radius: var(--r-card); background: var(--bg-1); overflow: hidden; }
.pr-league[hidden] { display: none; }
.pr-league-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-1);
  list-style: none;
}
.pr-league-summary::-webkit-details-marker { display: none; }
.pr-league-summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.pr-league-count {
  flex: none;
  min-width: 28px;
  padding: 1px var(--sp-2);
  border-radius: var(--r-pill);
  background: var(--bg-2);
  color: var(--text-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  text-align: center;
}
.pr-league-body { display: flex; flex-direction: column; gap: 1px; background: var(--line); }

.pr-manager { background: var(--bg-0); }
.pr-manager[hidden] { display: none; }
.pr-manager.is-me { border-left: var(--edge-marke); }
.pr-manager-summary {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-4);
  cursor: pointer;
  list-style: none;
}
.pr-manager-summary::-webkit-details-marker { display: none; }
.pr-manager-summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.pr-manager-name { font-size: var(--fs-small); font-weight: 600; color: var(--text-1); }
.pr-manager-line { font-size: var(--fs-caption); color: var(--text-3); }
.pr-me-tag { color: var(--blau); font-weight: 700; }

.pr-manager-detail { padding: 0 var(--sp-4) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.pr-mini-table { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px var(--sp-3); }
.pr-mini-row { display: flex; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-2); }
.pr-mini-row span:first-child { color: var(--text-3); width: 18px; }
.pr-manager-stats { margin: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.pr-manager-stats div { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-caption); }
.pr-manager-stats dt { color: var(--text-3); }
.pr-manager-stats dd { margin: 0; color: var(--text-2); text-align: right; }

.pr-own-card {
  padding: var(--sp-4);
  border: 1px solid var(--blau);
  border-radius: var(--r-card);
  background: var(--blau-tint);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

@media (max-width: 380px) {
  .pr { padding: var(--sp-4) var(--sp-3) var(--sp-6); }
  .pr-freq-row { grid-template-columns: 44px 1fr auto; }
}

@media (prefers-reduced-motion: reduce) {
  .weg-fill,
  .pr-freq-bar-fill,
  .tp-progress-fill { transition: none; }
}

/* ============================================================
   App-Rahmen: Kopfzeile, Inhalt, Reiterleiste
   ------------------------------------------------------------
   Zwei Zustände, gesteuert über data-bare am #shell (shell.js):

   bare="true"   Einstiegsweg (Passwort bis Reveal). Kein Chrome, die
                 Seite scrollt als Ganzes — genau das Verhalten, das
                 die fünf bestehenden Screens schon hatten.
   bare="false"  Reiter-Betrieb. Fester Rahmen in Sichtfeldhöhe,
                 gescrollt wird NUR die Mitte. Wäre die Höhe hier
                 min-height statt height, wüchse der Rahmen mit dem
                 Inhalt und die Reiterleiste stünde am Ende einer
                 langen Managertabelle statt am unteren Rand.

   Warum überhaupt eine feste Höhe: eine Leiste, die beim Scrollen
   mitwandert, kostet auf einem Handy die halbe Orientierung. 190
   Managerzeilen sind der Normalfall, nicht die Ausnahme.
   ============================================================ */

.shell { display: grid; }

.shell[data-bare="true"] {
  min-height: 100dvh;
  grid-template-rows: 1fr;
}

.shell[data-bare="false"] {
  height: 100dvh;
  /* minmax(0, 1fr) statt 1fr: eine Grid-Zeile hat als Minimum sonst
     ihre Inhaltshöhe, und der Scroller in der Mitte würde nie scrollen,
     sondern den Rahmen aufblähen. */
  grid-template-rows: auto minmax(0, 1fr) auto;
}

/* Nur im bare-Zustand füllt die Ansicht selbst das Sichtfeld. Im
   Reiter-Betrieb ist die Höhe Sache des Rahmens (siehe oben). */
.shell[data-bare="true"] > #view { min-height: 100dvh; }

.shell[data-bare="false"] > #view {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  width: 100%;
  max-width: 720px;
  margin-inline: auto;
  /* Kein padding-bottom am Scroller selbst: Chrome zieht es von einer
     sticky-Kante ab. Der Abstand nach unten lebt in .view-in. */
  padding: var(--sp-4) var(--sp-4) 0;
}
.shell[data-bare="false"] > #view > .view-in { padding-bottom: var(--sp-6); }

/* ---------- Kopfzeile ---------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  padding-top: calc(var(--sp-3) + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--line);
  /* Der Grund liegt ÜBER dem Flutlicht, sonst driften Lichtkegel durch
     die Kopfzeile und lassen sie flackern. Bewusst nicht durchsichtig:
     ein Milchglas-Effekt kostet auf älteren Handys jeden Scroll-Frame. */
  background: var(--bg-0);
  position: relative;
  z-index: 2;
}

.topbar__marke {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
}
.topbar__marke b {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text-1);
}
.topbar__marke span {
  font-size: var(--fs-caption);
  color: var(--text-3);
  white-space: nowrap;
}

.topbar__ich {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  /* 44px, nicht 36. Das ist die Ergonomie-Vorgabe aus tokens.css
     (--touch-min) und hier keine Formsache: dieser Knopf ist der einzige
     Weg zurueck in die Identitaet, und er sitzt am oberen Bildschirmrand,
     wo der Daumen ohnehin ungenau wird. */
  min-height: var(--touch-min);
  max-width: 55%;
  padding: 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-1);
  color: var(--text-2);
  font-size: var(--fs-caption);
  font-weight: 500;
  text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.topbar__ich svg { width: 16px; height: 16px; flex: 0 0 auto; }
.topbar__ich:hover { border-color: var(--line-strong); color: var(--text-1); }
.topbar__ich:active { transform: scale(.97); }
.topbar__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Reiterleiste ---------- */

.tabs {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  border-top: 1px solid var(--line);
  background: var(--bg-1);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  position: relative;
  z-index: 2;
}

.tab {
  position: relative;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-1) 9px;
  display: grid;
  place-items: center;
  gap: 3px;
  /* 11px, nicht --fs-caption: vier Beschriftungen müssen auch auf einem
     320px breiten Gerät nebeneinander passen, ohne umzubrechen. Ein
     zweizeiliger Reiter ist kein anklickbares Ziel mehr, sondern ein
     Suchbild. */
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.tab svg { width: 20px; height: 20px; }
.tab span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tab:hover { color: var(--text-2); }
.tab:active { transform: scale(.92); transition-duration: 60ms; }

/* Die Farbe sagt, WO man ist — nie, was man hat (tokens.css).
   Blau: Prognose · Lila: Manager · Orange: Hot Takes. Der Feed gehört
   keinem Bereich und bleibt weiß. */
.tab[aria-current="page"] { color: var(--text-1); }
.tab[aria-current="page"][data-farbe="blau"] { color: var(--blau); }
.tab[aria-current="page"][data-farbe="lila"] { color: var(--lila); }
.tab[aria-current="page"][data-farbe="warn"] { color: var(--warn); }

/* Farbe ist nie die einzige Information: der aktive Reiter trägt
   zusätzlich eine Kante. Wer die vier Töne nicht unterscheiden kann,
   sieht trotzdem, wo er steht. */
.tab[aria-current="page"]::before {
  content: "";
  position: absolute;
  top: 0;
  width: 28px;
  height: 2px;
  border-radius: 0 0 var(--r-pill) var(--r-pill);
  background: currentColor;
}

/* ---------- Wischen zwischen den Reitern (wischen.js) ----------
   Nur WÄHREND der Geste liegen zwei Ansichten nebeneinander. Solange
   trägt die Schiene das senkrechte Scrollen: #view selbst steht still,
   sonst hingen beide Platten an einem gemeinsamen Scrollstand. Die
   waagerechte Polsterung bleibt bewusst stehen — sie wegzunehmen ließe
   die laufende Ansicht im Moment des Zupackens sichtbar zur Seite
   springen. */
.body--wischt { overflow: hidden; touch-action: none; }
.body--wischt > .swipe-track {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--sp-5);
  min-height: 0;
  width: 100%;
  will-change: transform;
}
.body--wischt > .swipe-track > .view-in {
  flex: 0 0 100%;
  min-width: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ---------- Ladeplatzhalter ----------
   Der Router hängt <div class="skel skel--card"> ein, während eine
   Ansicht gebaut wird. Ohne Gestalt war das bisher ein unsichtbares
   Nichts — beim Reiterwechsel blieb das Bild für einen Moment leer und
   wirkte wie ein Fehler. */
.skel {
  border-radius: var(--r-card);
  background: linear-gradient(90deg, var(--bg-1) 0%, var(--bg-2) 50%, var(--bg-1) 100%);
  background-size: 200% 100%;
  animation: skel-wandern 1.4s linear infinite;
}
.skel--card { height: 180px; }

@keyframes skel-wandern {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}

@media (prefers-reduced-motion: reduce) {
  /* Dauer 0 würde die Animation nicht anhalten, sondern unendlich
     schnell laufen lassen (dieselbe Falle wie beim Flutlicht). */
  .skel { animation: none; }
}

/* ============================================================
   Die vier Reiter — gemeinsame Bausteine
   ------------------------------------------------------------
   Vier Ansichten, ein Aufbau: Kopfzeile, dann Blöcke mit Titel und
   Liste. Die gemeinsamen Teile stehen hier einmal, statt viermal mit
   anderem Präfix. Die reiterspezifischen Teile behalten ihr Präfix
   (sa- / mg- / ch- / fd-), wie schon bei tp-, ps-, pr-.
   ============================================================ */

.sa, .mg, .ch, .fd {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  position: relative;
  z-index: 1; /* über dem Flutlicht */
}

.sa-head, .mg-head, .ch-head, .fd-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.sa-h1, .mg-h1, .ch-h1, .fd-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text-1);
  /* Lange Wörter dürfen im Wort umbrechen statt die Seite zu weiten —
     „Saisonprognose" passt sonst auf 320px nicht neben die Polsterung. */
  overflow-wrap: anywhere;
  min-width: 0;
}
.sa-sub, .mg-sub, .ch-sub, .fd-sub {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-3);
}

.sa-block, .mg-block, .ch-liste-block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.sa-block-head, .mg-block-head { display: flex; flex-direction: column; gap: 2px; }
.sa-block-title, .mg-block-title, .ch-block-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  color: var(--text-1);
}
.sa-block-hint, .mg-block-hint { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }

/* Hinweiskarte (Vorstart, ohne Abgabe, Managerduell). Ein Muster für
   alle drei — sie sagen dasselbe: „hier fehlt gerade etwas, und zwar
   aus diesem Grund". */
.sa-notiz, .mg-duell {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
.sa-notiz svg, .mg-duell svg { flex: none; width: 20px; height: 20px; color: var(--text-3); }
.sa-notiz b, .mg-duell b { display: block; font-size: var(--fs-small); color: var(--text-1); }
.sa-notiz p, .mg-duell p { margin: var(--sp-1) 0 0; font-size: var(--fs-caption); color: var(--text-2); line-height: 1.5; }
.sa-notiz--warn { border-color: var(--warn); }
.sa-notiz--warn svg { color: var(--warn); }
.sa-notiz-link {
  /* inline-flex mit voller Tipphoehe statt inline-block: als reine Textzeile
     war das Ziel 15 Pixel hoch. Auf einem Handy trifft man das nicht, und
     es ist der Weg zur Abgabe — der einzige Link auf diesem Screen, den
     jemand WIRKLICH braucht, solange er nicht getippt hat. */
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  margin-top: var(--sp-1);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--blau);
}

/* ============================================================
   Reiter 1 — Saisonprognose
   ============================================================ */

.sa-table, .sa-rang {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.sa-row {
  display: grid;
  /* minmax(0, 1fr) für die Namensspalte: mit blankem 1fr weitet ein
     langer Vereinsname die Zeile über den Bildschirm hinaus. */
  grid-template-columns: 24px 28px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-1);
}
.sa-row-pos {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.sa-crest {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--crest, var(--bg-2));
}
.sa-crest-kuerzel { font-family: var(--font-display); font-weight: 800; font-size: 10px; color: var(--crest-ink); }

/* ---------- Weisses Kuerzel auf JEDER Vereinsfarbe lesbar ----------
   GEMESSEN am 24.08.2026: das Kuerzel erreichte auf den hellsten
   Vereinsfarben nur 3,25:1 — deutlich unter den 4,5:1, die eine Schrift
   dieser Groesse braucht. Betroffen waren genau die Vereine mit hellem
   Trikot (Dortmunds Gold, Frankfurts Braunton).

   Die naheliegende Loesung waere, die Schriftfarbe je Verein umzuschalten.
   Verworfen: dann steht in der Datenbank neben jeder Vereinsfarbe eine
   zweite Angabe, die jemand pflegen muss, und beim naechsten Aufsteiger
   vergisst sie jemand.

   Stattdessen liegt ein Schleier von 22 % Schwarz ueber der Flaeche. Er
   hebt die hellen Farben unter die Schwelle und laesst die dunklen
   praktisch unberuehrt — Dortmunds Gold kommt damit auf 4,9:1, Bremens
   Gruen auf ueber 12:1. Die Vereinsfarbe bleibt erkennbar, sie wird nur
   etwas satter.

   Gilt NUR fuer das Platzhalter-Wappen: liegt ein echtes Bild darueber
   (.crest-bild), deckt es den Schleier ohnehin ab. */
.sa-crest, .ps-crest, .pr-crest, .tp-crest-visual {
  background-image: linear-gradient(rgba(0, 0, 0, .22), rgba(0, 0, 0, .22));
}
.sa-row-main { display: flex; flex-direction: column; min-width: 0; }
.sa-row-name {
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sa-row-meta { font-size: var(--fs-caption); color: var(--text-3); font-variant-numeric: tabular-nums; }
.sa-row-pkt {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-table-pts);
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}

/* Abweichungs-Pille: NEUTRAL, nie grün oder rot. Ein getroffener
   Tabellenplatz im Oktober ist kein verdienter Punkt (tokens.css,
   Regel 1), und eine Abweichung ist kein Fehler. Der Treffer bekommt
   die Blau-Kontur — Blau sagt „hier stehst du", nicht „das war gut". */
.sa-delta {
  padding: 2px var(--sp-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sa-delta--treffer { border-color: var(--blau); color: var(--blau); }
.sa-delta--tipp { border-style: dashed; }

.sa-rang-row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-1);
}
/* Blaue Fläche und Kante für die eigene Zeile: Blau markiert, WO man
   ist. Die Zahl daneben bleibt unbunt. */
.sa-rang-row--ich { border-color: var(--blau); background: var(--blau-tint); }
.sa-rang-pos {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.sa-rang-main { display: flex; flex-direction: column; min-width: 0; }
.sa-rang-name {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sa-rang-liga { font-size: var(--fs-caption); color: var(--text-3); }
.sa-ich-tag, .mg-ich-tag {
  flex: none;
  padding: 1px var(--sp-2);
  border-radius: var(--r-pill);
  background: var(--blau);
  color: var(--blau-ink);
  font-size: 10px;
  font-weight: 700;
}
.mg-ich-tag { background: var(--lila); color: var(--lila-ink); }
.sa-rang-wert { display: flex; flex-direction: column; align-items: flex-end; }
.sa-rang-wert b {
  font-family: var(--font-display);
  font-size: var(--fs-table-pts);
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.sa-rang-wert small { font-size: 11px; color: var(--text-3); }

.sa-rang-eigen { display: flex; flex-direction: column; gap: var(--sp-2); }
.sa-rang-eigen-label { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }
.sa-rang-alle > summary {
  cursor: pointer;
  padding: var(--sp-2) 0;
  font-size: var(--fs-caption);
  color: var(--text-2);
}
.sa-rang-alle[open] > summary { margin-bottom: var(--sp-2); }
.sa-mehr { text-decoration: none; }

/* ============================================================
   Reiter 2 — Manager (Lila)
   ============================================================ */

.mg-eigen {
  padding: var(--sp-4);
  border: 1px solid var(--lila);
  border-radius: var(--r-card);
  background: var(--lila-tint);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.mg-eigen-label { margin: 0; font-size: var(--fs-caption); color: var(--text-2); }
.mg-eigen-zahlen { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.mg-eigen-rang { display: flex; flex-direction: column; min-width: 0; }
.mg-eigen-rang b {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.mg-eigen-rang small { font-size: var(--fs-caption); color: var(--text-3); overflow-wrap: anywhere; }

.mg-werkzeuge { display: flex; flex-direction: column; gap: var(--sp-2); }
.mg-filter { display: flex; gap: var(--sp-1); }
.mg-filter-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: 36px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-1);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: 500;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mg-filter-btn:hover { color: var(--text-2); }
.mg-filter-btn[aria-pressed="true"] {
  background: var(--bg-2);
  border-color: var(--lila);
  color: var(--text-1);
}
.mg-suche { position: relative; display: block; }
.mg-suche-icon {
  position: absolute;
  left: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-3);
  pointer-events: none;
}
.mg-suche-input { padding-left: calc(var(--sp-3) * 2 + 20px); width: 100%; }

.mg-table { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.mg-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-1);
}
.mg-row--ich { border-color: var(--lila); background: var(--lila-tint); }
.mg-row-pos {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.mg-row-main { display: flex; flex-direction: column; min-width: 0; }
.mg-row-name {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mg-row-liga {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mg-ebene {
  flex: none;
  padding: 0 5px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  font-size: 10px;
  font-weight: 700;
  color: var(--text-2);
}
.mg-row-zahlen { display: flex; flex-direction: column; align-items: flex-end; }
.mg-row-punkte {
  font-family: var(--font-display);
  font-size: var(--fs-table-pts);
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.mg-row-spieltag { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
/* Die EINZIGE grüne Zahl je Zeile, und nur bei echten Punkten: die
   Spieltagspunkte sind verdient (tokens.css, Regel 1). Null wird nie
   grün (Regel 2) — das entscheidet manager.js, nicht das Stylesheet. */
.mg-row-spieltag--stark { color: var(--up); }

.mg-leer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  color: var(--text-3);
}
.mg-leer b { color: var(--text-1); font-size: var(--fs-small); }
.mg-leer p { margin: 0; font-size: var(--fs-caption); }

/* ============================================================
   Reiter 2 — Challenges (Orange-Familie, drei Stufen)
   ------------------------------------------------------------
   KEINE sechste Farbe: Hot ist die Kontur, Superhot die Fläche mit
   Schein. So in tokens.css vorgemerkt, hier eingelöst. Der Schein
   benutzt --warn mit Alpha über color-mix, damit kein roher Farbwert
   im Stylesheet steht.

   DIE DRITTE STUFE BEKOMMT KEINE FARBE. „meh" bleibt in --text-3 mit
   der normalen Hairline — es ist die neutrale Stufe, und jede Farbe
   würde sie zu einer Meinung machen. Grau ist hier die Aussage.

   Das Managerduell holt sich LILA (--lila), die Zuordnung aus
   tokens.css für Manager und Spielfeld. Der Reiter selbst bleibt
   orange; die lila Fläche steht innerhalb und markiert genau den
   einen Block, der zum Managerbereich gehört.
   ============================================================ */

/* ---------- Managerduell: der ehrliche Platzhalter ----------
   Er soll nach etwas aussehen, das kommt, und nicht nach einer
   kaputten Karte. Deshalb ein linker Farbstreifen statt eines vollen
   Rahmens: gedämpft genug, um nicht mit den Takes darunter zu
   konkurrieren, sichtbar genug, um nicht übersehen zu werden. */
/* Das Managerduell-Widget behaelt seinen Lila-Schimmer: die
   Farbsemantik in tokens.css weist Lila dem Managerbereich und
   ausdruecklich dem Managerduell zu. Beim Umbau auf die Widget-Klassen
   waere er beinahe verlorengegangen — dann haette das Duell ausgesehen
   wie jede andere Karte, obwohl das System ihm eine Farbe gibt.

   ZWEI Gruende fuer die Zurueckhaltung (4 %, keine farbige Kante links):
   die Kante war das bekannteste Erkennungszeichen generierter
   Oberflaechen (Impeccable-Detektor, 24.08.2026), und sie liess einen
   Platzhalter wichtig aussehen. Der Schimmer sagt "gehoert zum
   Managerbereich" und sonst nichts. */
.ch-widget--duell {
  background: color-mix(in srgb, var(--lila) 4%, var(--bg-1));
}
.ch-widget--duell .ch-widget-fuss svg { color: var(--lila); }

/* ---------- Eigener Take und Fensterzustand ---------- */
.ch-mein-block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
.ch-fenster {
  margin: 0;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.ch-fenster svg { flex: none; width: 15px; height: 15px; margin-top: 1px; }
/* Wartet und Voll sind ZUSTÄNDE, keine Fehler — deshalb kein Rot und
   keine Warnfarbe. Der Unterschied zum Normalfall ist nur die
   Helligkeit des Textes plus das Symbol. */
.ch-fenster--wartet,
.ch-fenster--voll { color: var(--text-2); }

.ch-mein-text { display: flex; flex-direction: column; gap: 3px; flex: 1 1 auto; min-width: 0; }
.ch-mein-grund {
  font-size: var(--fs-caption);
  color: var(--text-2);
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.ch-mein-fenster {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* ---------- Begründungsfeld ---------- */
.ch-bk-grund-label { display: flex; align-items: baseline; gap: var(--sp-2); }
.ch-bk-freiwillig {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.ch-bk-grund-feld { resize: vertical; min-height: 62px; line-height: 1.45; }
.ch-bk-grund-fuss { font-size: var(--fs-caption); color: var(--text-3); }
.ch-bk-grund-fuss b { font-variant-numeric: tabular-nums; color: var(--text-2); }
/* Der Restzähler wird erst auf den letzten zwanzig Zeichen auffällig.
   Eine Zahl, die von Anfang an warnt, warnt nie. */
.ch-bk-grund-fuss b[data-knapp="true"] { color: var(--warn); }

/* ---------- Ergebnis eines aufgelösten Takes ----------
   DIE EINZIGE STELLE IN DIESER APP, AN DER GRÜN RICHTIG IST.
   Regel 1 aus tokens.css: Grün nur für schon verdiente Punkte. Ein
   eingetretener Take IST ein verdienter Punkt — eine offene Prognose
   und ein getroffener Tabellenplatz im Oktober sind es nicht, und
   deshalb sind die dort grau.

   Farbe ist nie die einzige Information: Symbol und Text sagen
   dasselbe. */
.ch-ergebnis {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  padding: 3px var(--sp-2);
  border-radius: var(--r-pill);
  font-size: var(--fs-caption);
  font-weight: 600;
  white-space: nowrap;
}
.ch-ergebnis svg { width: 14px; height: 14px; }
.ch-ergebnis--wahr {
  background: color-mix(in srgb, var(--up) 14%, transparent);
  color: var(--up);
}
.ch-ergebnis--falsch {
  background: color-mix(in srgb, var(--down) 12%, transparent);
  color: var(--down);
}

/* Eine abgeschlossene Karte tritt zurück: kein Schein, keine Kontur,
   gedämpfter Text. Das Ergebnis trägt die Aufmerksamkeit. */
.ch-take--fertig { border-color: var(--line); background: var(--bg-0); }
.ch-take--fertig .ch-take-satz { color: var(--text-2); }
.ch-take-abschluss {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
}
.ch-take-bilanz { font-size: var(--fs-caption); color: var(--text-3); font-variant-numeric: tabular-nums; }
/* Die eigene Stimme, nachdem die Abstimmung zu ist. Kraeftiger als die
   Bilanz daneben (--text-2 statt --text-3): sie ist die einzige Angabe in
   dieser Zeile, die nur fuer diesen einen Leser gilt. */
.ch-take-meine { font-size: var(--fs-caption); color: var(--text-2); }
.ch-take-grund {
  margin: 0;
  padding-left: var(--sp-3);
  border-left: 2px solid var(--line);
  font-size: var(--fs-caption);
  color: var(--text-2);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.ch-meine-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.ch-mein {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--warn);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.ch-mein-satz { flex: 1 1 auto; min-width: 0; font-size: var(--fs-small); color: var(--text-1); overflow-wrap: anywhere; }
.ch-mein-weg, .fd-post-weg {
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}
.ch-mein-weg:hover, .fd-post-weg:hover { color: var(--down); }
.ch-mein-weg svg, .fd-post-weg svg { width: 16px; height: 16px; }

.ch-bk {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-card);
  background: var(--bg-2);
}
.ch-bk-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.ch-bk-head b { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--text-1); }
.ch-bk-zu {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}
.ch-bk-zu:hover { color: var(--text-1); }
/* ============================================================
   Umfragen (25.08.2026)
   ------------------------------------------------------------
   Zwei Zustaende, und sie sehen bewusst verschieden aus: VOR der eigenen
   Stimme ein Knopf ohne jede Zahl, DANACH derselbe Knopf mit Balken und
   Prozent. Der Wechsel ist die Belohnung fuers Mitmachen — deshalb faellt
   er auch deutlich aus und nicht als beilaeufige Ergaenzung.

   Der Balken liegt HINTER dem Text als eigene Flaeche, nicht als
   Hintergrundverlauf: so laesst er sich ueber transform skalieren
   (--anteil), und der Text darueber bleibt beim Wachsen ruhig stehen.

   KEIN GRUEN. Eine Umfrage bringt keine Punkte (siehe Migration
   20260901510000), und Gruen ist im Farbsystem fuer verdiente Punkte
   reserviert. Die eigene Antwort wird ueber Lila markiert — dieselbe
   Farbe, die im System die Manager-/Mitspielerseite traegt.
   ============================================================ */
.um-karten { display: flex; flex-direction: column; gap: var(--sp-3); }

.um-karte {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  background: var(--bg-1);
}
.um-karte--zu { background: var(--bg-0); }

.um-frage {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--text-1);
  overflow-wrap: anywhere;
}

.um-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }

.um-wahl {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.um-wahl:hover:not(:disabled) { border-color: var(--line-strong); }
.um-wahl:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.um-wahl:disabled { cursor: default; }
.um-wahl[aria-pressed="true"] { border-color: var(--lila); }

.um-wahl-text { position: relative; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.um-wahl-zahl {
  position: relative;
  flex: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}
.um-wahl[aria-pressed="true"] .um-wahl-zahl { color: var(--lila); }

/* Waechst per transform, nicht per width — dieselbe Regel wie beim
   Fortschrittsbalken der Tabellenprognose. */
.um-balken {
  position: absolute;
  inset: 0;
  transform: scaleX(var(--anteil, 0));
  transform-origin: left center;
  background: var(--bg-2);
  transition: transform var(--dur-med) var(--ease-out);
}
.um-wahl[aria-pressed="true"] .um-balken { background: var(--lila-tint); }

.um-fuss { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Ligaleitung: Umfragen verwalten ---------- */
.lt-um-felder { display: flex; flex-direction: column; gap: var(--sp-2); border: none; margin: 0; padding: 0; }

.lt-um-karten { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-4); }

.lt-um-karte {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
}

.lt-um-frage {
  margin: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-1);
}
.lt-um-status { flex: none; font-size: var(--fs-caption); font-weight: 500; color: var(--text-3); }

.lt-um-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.lt-um-zeile { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-caption); }
.lt-um-text { color: var(--text-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lt-um-zahl { flex: none; color: var(--text-1); font-variant-numeric: tabular-nums; }
.lt-um-anteil { color: var(--text-3); }

.lt-um-fuss {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.lt-um-aktionen { display: flex; gap: var(--sp-2); }

.lt-klein {
  /* 44px ist die Hausregel (--touch-min): auch die Ligaleitung wird am
     Handy bedient, und zwar oft unterwegs vor dem Anpfiff. */
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line-strong);
  background: var(--bg-1);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: 600;
  cursor: pointer;
}
.lt-klein:hover { border-color: var(--text-3); }
.lt-klein:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Der Loeschknopf wird erst rot, wenn er WIRKLICH loescht — im ersten
   Zustand fragt er nur nach. Ein von Anfang an roter Knopf warnt nie. */
.lt-klein--weg[data-state="sicher"] { border-color: var(--down); color: var(--down); }

@media (prefers-reduced-motion: reduce) {
  .um-balken { transition: none; }
}

/* ---------- Zwei Reiter: Offen / Abgeschlossen ----------
   Ersetzt die zwei Abschnitte untereinander (bis 25.08.2026). Der Grund
   ist nicht Platz, sondern Bedeutung: offene Takes will man BEWERTEN,
   abgeschlossene will man LESEN. Zwei Taetigkeiten, zwei Ansichten —
   untereinander scrollt man am einen vorbei, um ans andere zu kommen. */
.ch-reiter {
  display: flex;
  gap: var(--sp-2);
  padding-bottom: var(--sp-1);
  border-bottom: 1px solid var(--line);
}

.ch-reiter-btn {
  flex: 1 1 0;
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border: none;
  border-radius: var(--r-ctl) var(--r-ctl) 0 0;
  background: transparent;
  color: var(--text-3);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 600;
  cursor: pointer;
  /* Der aktive Reiter traegt eine Linie UNTEN, kein Fuellflaeche: die
     Farbe bleibt damit fuer die Hitze der Takes reserviert. */
  box-shadow: inset 0 -2px 0 transparent;
  transition: color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.ch-reiter-btn:hover { color: var(--text-2); }
.ch-reiter-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; transition: none; }
.ch-reiter-btn[aria-selected="true"] { color: var(--text-1); box-shadow: inset 0 -2px 0 var(--text-1); }

.ch-reiter-zahl {
  display: inline-block;
  min-width: 1.6em;
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: var(--bg-2);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
}
.ch-reiter-btn[aria-selected="true"] .ch-reiter-zahl { color: var(--text-1); }

/* ---------- Take-Rangliste ----------
   Steht ÜBER den zwei Spalten, nicht darunter: sie beantwortet die Frage,
   mit der man den Reiter öffnet ("wer hat gewonnen"), und die Spalten
   beantworten die Frage danach ("womit").

   Die eigene Zeile ist in Lila markiert — im Farbsystem die Manager- und
   Mitspielerseite. Grün wäre falsch: es ist kein verdienter Punkt, dort zu
   stehen, sondern nur der Hinweis "das bist du". */
.ch-rangliste { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-4); }

.ch-rang-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }

.ch-rang {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 40px;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.ch-rang:last-child { border-bottom: none; }

.ch-rang.is-ich {
  background: var(--lila-tint);
  border-radius: var(--r-ctl);
  border-bottom-color: transparent;
}

.ch-rang-nr {
  flex: none;
  width: 22px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.ch-rang.is-ich .ch-rang-nr { color: var(--lila); }

.ch-rang-name {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ch-rang-name small { font-size: 11px; font-weight: 500; color: var(--text-3); }

.ch-rang-punkte {
  flex: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--up);
}

/* Die Lücke zwischen den ersten Zehn und der eigenen Zeile weiter unten.
   Drei Punkte statt einer leeren Zeile: sie sagen "hier fehlt etwas", eine
   Lücke sagt nur "hier ist nichts". */
.ch-rang-luecke {
  padding: 2px var(--sp-3);
  color: var(--text-3);
  font-size: var(--fs-caption);
  letter-spacing: .2em;
}

/* ---------- Zwei Spalten: eingetroffen gegen danebengelegen ----------
   Auch auf dem Handy ZWEI Spalten, nicht zwei Abschnitte untereinander:
   der Vergleich links gegen rechts IST die Aussage dieses Reiters. Wer
   sie stapelt, hat zwei Listen und keine Gegenueberstellung mehr.

   Die Karten sind deshalb bewusst schmal und kurz — nur Satz, Name und
   Punktzahl. Alles Weitere (Stimmknoepfe, Begruendung) gehoert in den
   offenen Reiter, wo es etwas zu tun gibt. */
.ch-spalten { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }

.ch-spalte { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }

.ch-spalte-titel {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-caption);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
}
/* GRUEN IST HIER ERLAUBT — die einzige Stelle des Reiters, an der Regel 1
   aus tokens.css es zulaesst: ein eingetroffener Take ist ein verdienter
   Punkt. Die rechte Spalte bekommt KEIN Rot als Flaeche, nur gedaempfte
   Schrift: danebenzuliegen ist kein Fehler, sondern der Preis des Mutes. */
.ch-spalte--wahr .ch-spalte-titel { color: var(--up); }
.ch-spalte--falsch .ch-spalte-titel { color: var(--text-3); }

.ch-spalte-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }

.ch-spalte-karte {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-2);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-1);
  min-width: 0;
}
.ch-spalte--falsch .ch-spalte-karte { background: var(--bg-0); }

.ch-spalte-satz {
  margin: 0;
  font-size: var(--fs-caption);
  line-height: 1.35;
  color: var(--text-1);
  overflow-wrap: anywhere;
  /* Vier Zeilen, dann Ellipse: eine Spalte, in der eine Karte doppelt so
     hoch ist wie ihre Nachbarin, liest sich nicht mehr als Rangliste. */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ch-spalte--falsch .ch-spalte-satz { color: var(--text-2); }

.ch-spalte-fuss {
  margin: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1);
  font-size: 11px;
}
.ch-spalte-wer { color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ch-spalte-punkte {
  flex: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--up);
}
.ch-spalte--falsch .ch-spalte-punkte { color: var(--text-3); }

.ch-spalte-leer {
  padding: var(--sp-3) var(--sp-2);
  border-radius: var(--r-ctl);
  border: 1px dashed var(--line);
  font-size: var(--fs-caption);
  color: var(--text-3);
  text-align: center;
}

/* ---------- Der Trichter ----------
   Fuenf Schritte untereinander, jeder mit seiner Nummer. Die Nummer
   steht als eigenes rundes Zeichen davor und nicht als "Schritt 3 von
   5": bei einem Trichter, der sich erst aufbaut, waere die Gesamtzahl
   eine Behauptung ueber Schritte, die es noch gar nicht gibt.

   Ein aufgegangener Schritt blendet sich ein statt zu springen — die
   Liste waechst nach unten, und ohne Uebergang sieht das aus wie ein
   Ruckeln der ganzen Karte. */
.ch-tr {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
  animation: ch-tr-auf var(--dur-fast) var(--ease-out) both;
}
.ch-tr:first-of-type { border-top: none; padding-top: 0; }

@keyframes ch-tr-auf {
  from { opacity: 0; transform: translate3d(0, -4px, 0); }
  to   { opacity: 1; transform: none; }
}

.ch-tr-titel {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-1);
}
.ch-tr-nr {
  flex: none;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--bg-2);
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
}

/* Zwei grosse Knoepfe nebeneinander. Bei zwei Moeglichkeiten ist ein
   Aufklappmenue ein Tap zu viel — und beide Antworten gleichzeitig zu
   sehen ist die halbe Entscheidung. */
.ch-wahl { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }

.ch-wahl-btn {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: var(--touch-min);
  padding: var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.ch-wahl-btn:hover { border-color: var(--line-strong); }
.ch-wahl-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.ch-wahl-btn[aria-pressed="true"] { border-color: var(--warn); background: var(--bg-2); }
.ch-wahl-label { font-size: var(--fs-small); font-weight: 600; }
.ch-wahl-hilfe { font-size: var(--fs-caption); color: var(--text-3); }

/* Kennzahlen als Pillen: vier bis sechs Stueck, alle gleichwertig. */
.ch-kennzahlen { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.ch-kennzahl {
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--bg-0);
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.ch-kennzahl:hover { border-color: var(--line-strong); color: var(--text-1); }
.ch-kennzahl:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; transition: none; }
.ch-kennzahl[aria-pressed="true"] { border-color: var(--warn); color: var(--warn); background: var(--bg-2); }

.ch-auswahl-label { margin: var(--sp-2) 0 0; font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Vereinsraster ----------
   Achtzehn Wappen, vier je Zeile auf dem Handy. Alle auf einen Blick,
   deshalb ohne Suche: bei achtzehn ist Tippen langsamer als Zeigen. */
.ch-vereine { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); }

.ch-verein {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) 2px;
  border-radius: var(--r-ctl);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-body);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.ch-verein:hover { background: var(--bg-2); }
.ch-verein:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; transition: none; }

.ch-verein-wappen {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
}
.ch-verein-kuerzel { display: none; }
.ch-verein-name { font-size: 11px; font-weight: 600; }

/* ---------- Spielersuche ----------
   468 Spieler: hier ist die Suche der Kern, nicht die Zugabe. Die
   Treffer stehen als Liste UNTER dem Feld — dasselbe Muster wie die
   Tabellenprognose und wie elftipp2s Bonusfragen, wo die Auswahl-Sheets
   bewusst durch Listen ersetzt wurden. */
.ch-suche {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0 var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
}
.ch-suche:focus-within { box-shadow: inset 0 0 0 2px var(--focus); }
.ch-suche-lupe { display: grid; place-items: center; color: var(--text-3); flex: none; }
.ch-suche-lupe svg { width: 16px; height: 16px; }
.ch-suche-feld {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--touch-min);
  border: none;
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-small);
}
.ch-suche-feld:focus { outline: none; }
.ch-suche-feld::placeholder { color: var(--text-3); }

.ch-spieler {
  display: flex;
  flex-direction: column;
  max-height: 300px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
}

.ch-spieler-btn {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border: none;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
}
.ch-spieler-btn:last-child { border-bottom: none; }
.ch-spieler-btn:hover { background: var(--bg-2); }
.ch-spieler-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Das Spielerfoto ist FREIGESTELLT wie die Wappen (25.08.2026): kein
   Kreis, keine Flaeche. Kickbase liefert die Bilder bereits ohne
   Hintergrund. */
.ch-spieler-foto { flex: none; width: 30px; height: 34px; display: grid; place-items: end center; }
.ch-spieler-foto img { width: 100%; height: 100%; object-fit: contain; object-position: bottom; }

.ch-spieler-text { display: flex; flex-direction: column; min-width: 0; }
.ch-spieler-text b { font-size: var(--fs-small); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-spieler-text small { font-size: var(--fs-caption); color: var(--text-3); }

.ch-suche-leer, .ch-suche-rest {
  margin: 0;
  padding: var(--sp-3);
  font-size: var(--fs-caption);
  color: var(--text-3);
  text-align: center;
}

/* ---------- Was gewaehlt ist ----------
   Steht als eine Zeile da, mit Kreuz zum Aendern — dieselbe Geste wie
   in der Tabellenprognose. Wer gewaehlt hat, soll die Liste NICHT mehr
   sehen: sie waere ab da nur noch Laerm. */
.ch-gewaehlt {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border-radius: var(--r-ctl);
  border: 1px solid var(--warn);
  background: var(--bg-2);
}
.ch-gewaehlt-rolle { flex: none; font-size: var(--fs-caption); color: var(--text-3); }
.ch-gewaehlt-name { flex: 1 1 auto; min-width: 0; font-size: var(--fs-small); font-weight: 600; color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-gewaehlt-weg {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}
.ch-gewaehlt-weg:hover { color: var(--text-1); background: var(--bg-1); }
.ch-gewaehlt-weg:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.ch-gewaehlt-weg svg { width: 16px; height: 16px; }

/* ---------- Die Zahl ----------
   Direkteingabe statt Schieberegler (25.08.2026). Mit dem Daumen
   trifft man auf einem Regler keinen exakten Wert, und genau der ist
   hier die ganze Aussage. Die beiden Schrittknoepfe gehen um EINEN
   Schritt der Vorlage, nicht um 1. */
.ch-zahl { display: flex; align-items: stretch; gap: var(--sp-2); }

.ch-zahl-btn {
  flex: none;
  display: grid;
  place-items: center;
  width: var(--touch-min);
  min-height: var(--touch-min);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
  color: var(--text-1);
  cursor: pointer;
}
.ch-zahl-btn:hover { border-color: var(--line-strong); }
.ch-zahl-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.ch-zahl-btn:active { transform: translate3d(0, 1px, 0); }

.ch-zahl-mitte {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border-radius: var(--r-ctl);
  border: 1px solid var(--line);
  background: var(--bg-0);
}
.ch-zahl-mitte:focus-within { box-shadow: inset 0 0 0 2px var(--focus); }

.ch-zahl-feld {
  width: 3.5ch;
  border: none;
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.ch-zahl-feld:focus { outline: none; }
.ch-zahl-einheit { font-size: var(--fs-small); color: var(--text-3); }
.ch-zahl-grenzen { margin: 0; font-size: var(--fs-caption); color: var(--text-3); }

.ch-bk-vorlage {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-1);
  color: var(--text-2);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.ch-bk-vorlage:hover { border-color: var(--line-strong); }
.ch-bk-vorlage[aria-pressed="true"] { border-color: var(--warn); background: var(--bg-2); }
.ch-bk-vorlage-kat { font-size: 11px; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.ch-bk-vorlage-text { font-size: var(--fs-small); color: var(--text-1); overflow-wrap: anywhere; }
.ch-bk-felder { display: flex; flex-direction: column; gap: var(--sp-3); }
.ch-bk-feld { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-caption); color: var(--text-2); }
.ch-bk-feld b { font-family: var(--font-display); color: var(--text-1); font-variant-numeric: tabular-nums; }
.ch-bk-regler { width: 100%; accent-color: var(--warn); min-height: var(--touch-min); }
.ch-bk-vorschau {
  margin: 0;
  padding: var(--sp-3);
  border-left: 2px solid var(--warn);
  background: var(--bg-1);
  font-size: var(--fs-small);
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.ch-bk-aufloesung {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.ch-bk-aufloesung svg { flex: none; width: 15px; height: 15px; }

.ch-sicht { display: flex; gap: var(--sp-1); }
.ch-sicht button {
  flex: 1 1 0;
  min-height: 36px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-1);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: 500;
  cursor: pointer;
}
.ch-sicht button[aria-pressed="true"] { border-color: var(--warn); background: var(--bg-2); color: var(--text-1); }

.ch-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.ch-take {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
/* Stufe 1: Kontur. */
.ch-take--hot { border-color: var(--warn); }
/* Stufe 2: Fläche und Schein. color-mix statt eines rohen rgba-Werts —
   die Farbe bleibt damit an --warn gebunden und zieht mit, wenn das
   Token sich ändert. */
.ch-take--super {
  border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, var(--bg-1));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--warn) 35%, transparent),
              0 8px 28px color-mix(in srgb, var(--warn) 18%, transparent);
}
.ch-take--mein { border-style: dashed; }
.ch-take-satz { margin: 0; font-size: var(--fs-small); color: var(--text-1); line-height: 1.45; overflow-wrap: anywhere; }
.ch-take-von { margin: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-2); }
.ch-take-liga { color: var(--text-3); }
.ch-take-stimmen { display: flex; gap: var(--sp-2); }
.ch-vote {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 36px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-0);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.ch-vote svg { width: 15px; height: 15px; }
.ch-vote--super svg + svg { margin-left: -9px; }
.ch-vote-zahl { font-variant-numeric: tabular-nums; }

/* MEH BLEIBT NEUTRAL, in jedem Zustand. Kein Orange, kein Rot: die
   Stufe ist kein Downvote, und eine Farbe würde sie zu einer machen.
   Gedrückt erkennt man sie an der kräftigeren Kontur und am helleren
   Text, nicht an einem Farbwechsel. */
.ch-vote--meh:hover:not(:disabled) { border-color: var(--line-strong); color: var(--text-2); }
.ch-vote--meh[aria-pressed="true"] {
  border-color: var(--line-strong);
  background: var(--bg-2);
  color: var(--text-1);
}

.ch-vote--hot:hover:not(:disabled),
.ch-vote--super:hover:not(:disabled) { border-color: var(--warn); color: var(--text-1); }
.ch-vote--hot[aria-pressed="true"] { border-color: var(--warn); color: var(--warn); }
/* Superhot ist die FLÄCHE mit Schein — die zweite Stufe der
   Orange-Familie, wie in tokens.css vorgemerkt. */
.ch-vote--super[aria-pressed="true"] {
  border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 18%, var(--bg-0));
  color: var(--text-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 12%, transparent);
}

.ch-vote:active:not(:disabled) { transform: scale(.94); transition-duration: 60ms; }
.ch-vote:disabled { opacity: .45; cursor: default; }
/* Laufender Netzaufruf: der Knopf bleibt stehen, wird aber sichtbar
   beschäftigt. Kein Spinner — bei drei Knöpfen nebeneinander wäre er
   mehr Unruhe als Auskunft. */
.ch-vote[data-state="loading"] { opacity: .6; cursor: progress; }
.ch-vote[data-state="error"] { border-color: var(--down); color: var(--down); }


/* ============================================================
   Ligaleitung — die Werkzeugseite (#/leitung)
   ------------------------------------------------------------
   SIE SIEHT ABSICHTLICH ANDERS AUS als die drei Reiter. Kein Blau,
   kein Orange, keine Lichtflaeche: das hier ist Werkzeug, nicht
   Spiel. Wer sie oeffnet, soll am ersten Blick merken, dass er den
   Produktbereich verlassen hat — sonst verschiebt jemand einen
   Stichtag in derselben Haltung, in der er eben noch abgestimmt hat.

   Die Marke taucht genau einmal auf: am primaeren Knopf jedes
   Blocks. Alles andere ist Graustufe plus die zwei Funktionsfarben,
   die etwas bedeuten (--up fuer eingetreten, --down fuer Gefahr).
   ============================================================ */

.lt {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-4) var(--sp-8);
  max-width: 640px;
  margin: 0 auto;
}

.lt-head { display: flex; flex-direction: column; gap: var(--sp-1); }
.lt-zurueck {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  align-self: flex-start;
  min-height: var(--touch-min);
  color: var(--text-3);
  font-size: var(--fs-caption);
  text-decoration: none;
}
.lt-zurueck:hover { color: var(--text-1); }
/* Der Pfeil zeigt zurueck, also gespiegelt. Ein eigenes Symbol dafuer
   waere ein zweites Icon fuer dieselbe Sache. */
.lt-zurueck svg { width: 16px; height: 16px; transform: scaleX(-1); }
.lt-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.lt-sub { margin: 0; font-size: var(--fs-small); color: var(--text-2); }

/* ---------- Ueberblick ----------
   Zwei Zahlen, sonst nichts. Keine erfundene dritte Kennzahl, um die
   Reihe zu fuellen — was nicht gezaehlt wurde, steht hier auch nicht. */
/* ZWEI ZAHLEN, KEINE ZWEI KARTEN. Gleich grosse Kaesten mit je einer Zahl
   und einem Label sind die Standardform, in die jede Uebersicht rutscht —
   und sie geben zwei Angaben dieselbe Wichtigkeit, die sie nicht haben.
   Hier steht eine Zeile mit einem Trenner dazwischen: die Zahlen tragen
   sich selbst, ein Rahmen drumherum fuegt nichts hinzu. */
.lt-ueberblick {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4) var(--sp-6);
  padding: var(--sp-2) 0 var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.lt-zahl {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.lt-zahl b {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-1);
}
/* Die Gesamtzahl tritt zurueck: "43" ist die Nachricht, "/ 190" der
   Massstab. Gleiche Groesse machte aus einer Zahl zwei. */
.lt-zahl-von { font-size: var(--fs-body); color: var(--text-3); font-weight: 500; }
.lt-zahl span { font-size: var(--fs-caption); color: var(--text-3); }

/* ---------- Bloecke ---------- */
.lt-block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
/* Der Gefahrenblock traegt eine rote Kante links, keinen roten Rahmen.
   Ein ganz roter Kasten schreit dauerhaft; die Kante sagt einmal, worum
   es geht, und laesst den Inhalt lesbar. */
/* KEINE rote Kante links (siehe ch-duell). Die Gefahr steht im Text und
   am Knopf — dort, wo sie wirkt. Der Block selbst bekommt nur einen etwas
   kraeftigeren Rahmen, damit er sich vom Rest der Seite abhebt, ohne
   dauerhaft zu schreien. */
.lt-block--gefahr { border-color: color-mix(in srgb, var(--down) 35%, var(--line)); }
.lt-block-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  color: var(--text-1);
}
.lt-block-title svg { flex: none; width: 18px; height: 18px; color: var(--text-3); }
.lt-block-text { margin: 0; font-size: var(--fs-small); color: var(--text-2); line-height: 1.5; }
.lt-hinweis { margin: 0; font-size: var(--fs-caption); color: var(--text-3); line-height: 1.45; }
.lt-leer { margin: 0; font-size: var(--fs-small); color: var(--text-3); }
.lt-trenner { height: 1px; background: var(--line); margin: var(--sp-1) 0; }

.lt-form { display: flex; flex-direction: column; gap: var(--sp-3); }
.lt-textarea { resize: vertical; min-height: 120px; line-height: 1.55; }
.lt-knopfreihe { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* Das Kaestchen bleibt 18px — so sehen Kaestchen aus. Getippt wird auf das
   LABEL, und das traegt die volle Hoehe. Ein 44px grosses Kaestchen waere
   die falsche Antwort auf die richtige Regel. */
.lt-check {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  font-size: var(--fs-small);
  color: var(--text-2);
  cursor: pointer;
}
.lt-check input { width: 18px; height: 18px; accent-color: var(--blau); }

/* ---------- Medien im Formular ---------- */
.lt-medien { display: flex; flex-direction: column; gap: var(--sp-2); }
.lt-medien-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.lt-medium {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  font-size: var(--fs-caption);
  color: var(--text-2);
}
.lt-medium svg { flex: none; width: 16px; height: 16px; color: var(--text-3); }
.lt-medium-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.lt-medium-weg {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}
.lt-medium-weg:hover { color: var(--down); }
.lt-medium-weg svg { width: 15px; height: 15px; }

.lt-medien-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  color: var(--text-2);
  font-size: var(--fs-btn);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lt-medien-knopf:hover { border-color: var(--blau); color: var(--text-1); }
/* Der Fokusring liegt am label, weil das echte input hidden ist — ohne
   diese Regel bekaeme man mit der Tastatur keinen sichtbaren Fokus. */
.lt-medien-knopf:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }
.lt-medien-knopf[data-state="loading"] { opacity: .6; cursor: progress; }
.lt-medien-knopf svg { width: 18px; height: 18px; }

/* ---------- Takes ---------- */
.lt-takes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.lt-take {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.lt-take-satz { font-size: var(--fs-small); color: var(--text-1); line-height: 1.45; overflow-wrap: anywhere; }
.lt-take-von { font-size: var(--fs-caption); color: var(--text-3); }
.lt-take-knoepfe { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* ---------- Manager ---------- */
.lt-manager { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.lt-manager-zeile {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.lt-manager-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 160px; min-width: 0; }
.lt-manager-name { font-size: var(--fs-small); color: var(--text-1); overflow-wrap: anywhere; }
.lt-manager-liga { font-size: var(--fs-caption); color: var(--text-3); }
/* Die einzige Stelle dieser Seite mit --up: "hat abgegeben" ist ein
   erledigter Zustand, kein verdienter Punkt — deshalb NICHT gruen,
   sondern nur heller. Regel 1 aus tokens.css gilt auch hier. */
.lt-abgegeben { color: var(--text-2); font-weight: 600; }

/* ---------- Kleine Knoepfe ---------- */
.lt-mini {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 36px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-0);
  color: var(--text-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.lt-mini svg { width: 14px; height: 14px; }
.lt-mini:hover:not(:disabled) { border-color: var(--line-strong); color: var(--text-1); }
.lt-mini:active:not(:disabled) { transform: scale(.96); transition-duration: 60ms; }
.lt-mini:disabled { opacity: .45; cursor: default; }
.lt-mini[data-state="loading"] { opacity: .6; cursor: progress; }
.lt-mini[data-state="error"] { border-color: var(--down); color: var(--down); }
.lt-mini--ja:hover:not(:disabled) { border-color: var(--up); color: var(--up); }
.lt-mini--nein:hover:not(:disabled) { border-color: var(--down); color: var(--down); }
.lt-mini--gefahr { border-color: color-mix(in srgb, var(--down) 45%, var(--line)); color: var(--down); }
.lt-mini--gefahr:hover:not(:disabled) { border-color: var(--down); color: var(--down); }
/* SCHARF: der Knopf hat nachgefragt und wartet auf den zweiten Klick.
   Er wird zur Flaeche, nicht nur zur Kontur — der Unterschied muss auch
   im Augenwinkel auffallen, sonst tippt man ihn im Vorbeigehen. */
.lt-mini--gefahr[data-scharf="1"] {
  background: var(--down);
  border-color: var(--down);
  color: var(--bg-0);
}

.lt-abmelden { margin-top: var(--sp-2); }
.fd-leitung { margin-top: var(--sp-4); }

/* ---------- Medien im Feed ---------- */
/* minmax(0, 1fr) statt 1fr: ein Bild in einer 1fr-Spur kann die Spur
   breiter druecken als den Container, und dann scrollt die Seite
   waagerecht. Bei 320px ist das kein Randfall, sondern der Normalfall. */
.fd-medien {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2);
}
.fd-medien--eins { grid-template-columns: minmax(0, 1fr); }
.fd-medium {
  width: 100%;
  max-width: 100%;
  height: auto;
  display: block;
  border-radius: var(--r-ctl);
  background: var(--bg-2);
}
.fd-medien:not(.fd-medien--eins) .fd-medium {
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

@media (max-width: 380px) {
  /* Zwei Spalten auf einem schmalen Handy ergeben Briefmarken. Ab hier
     steht alles untereinander, auch wenn es mehr Scrollen bedeutet. */
  .fd-medien { grid-template-columns: minmax(0, 1fr); }
  .fd-medien:not(.fd-medien--eins) .fd-medium { aspect-ratio: auto; object-fit: contain; }
  .lt-ueberblick { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   Reiter 3 — Feed
   ============================================================ */

.fd-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.fd-post {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
.fd-post--fix { border-left: var(--edge-marke); }
.fd-fix-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: flex-start;
  font-size: 11px;
  font-weight: 700;
  color: var(--blau);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.fd-fix-tag svg { width: 13px; height: 13px; }
.fd-post-titel {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.fd-post-text { margin: 0; font-size: var(--fs-small); line-height: 1.6; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; }
.fd-post-fuss {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
}

.fd-schreiben {
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
.fd-schreiben > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  cursor: pointer;
  font-size: var(--fs-small);
  color: var(--text-2);
}
.fd-schreiben > summary svg { width: 16px; height: 16px; }
.fd-form { display: flex; flex-direction: column; gap: var(--sp-3); padding: 0 var(--sp-4) var(--sp-4); }
.fd-textarea { min-height: 120px; resize: vertical; line-height: 1.5; padding: var(--sp-3); }
.fd-check { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-small); color: var(--text-2); }
.fd-check input { width: 18px; height: 18px; accent-color: var(--blau); }

/* ---------- Enge Geräte ----------
   320px ist der Boden: darunter gibt es kein aktuelles Gerät mehr.
   Die Polsterung schrumpft, die Trefferflächen (--touch-min) nicht. */
@media (max-width: 380px) {
  .shell[data-bare="false"] > #view { padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .sa-row { grid-template-columns: 20px 24px minmax(0, 1fr) auto auto; gap: 5px; }
  .sa-crest { width: 24px; height: 24px; }
  .mg-eigen-zahlen { gap: var(--sp-4); }
}

/* Rückweg aus dem Vollvergleich in den Saison-Reiter. Das Chevron zeigt
   im Icon-Satz nach rechts und wird hier gedreht, statt ein zweites,
   fast identisches Icon anzulegen. */
.pr-zurueck {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  align-self: flex-start;
  min-height: 36px;
  margin-bottom: var(--sp-1);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: 500;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}
.pr-zurueck:hover { color: var(--text-1); }
.pr-zurueck svg { width: 16px; height: 16px; transform: rotate(180deg); }

.ch-stimmen-hinweis { margin: 0 0 var(--sp-1); font-size: var(--fs-caption); color: var(--text-3); }

/* ============================================================
   Das echte Wappen
   ------------------------------------------------------------
   Liegt ALS BILD ueber der Vereinsfarbe, nicht statt ihr. Solange es
   laedt — oder wenn das Sportmonks-CDN ausfaellt — steht darunter das
   Kuerzel auf der Vereinsfarbe, und der Uebergang ist ein Aufblenden
   statt eines Sprungs aus einem grauen Loch.

   object-fit: contain, nicht cover: Wappen sind unterschiedlich hoch
   und breit, und ein beschnittenes Wappen ist ein falsches Wappen.

   Eine Regel fuer alle vier Wappen-Groessen der App (Saisontabelle,
   Tabellenprognose, Statistik, Reveal): das Bild fuellt schlicht sein
   Elternelement aus und uebernimmt dessen Mass.
   ============================================================ */

.crest-bild {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Ein Wappen auf farbiger Flaeche braucht etwas Luft, sonst stoesst
     es an die Rundung. */
  padding: 2px;
  animation: crestAuf var(--dur-fast) var(--ease) both;
}
@keyframes crestAuf { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .crest-bild { animation: none; } }

/* Die vier Wappen-Rahmen brauchen position:relative, damit sich das
   Bild ueber sie legen kann. Manche tragen es schon; die Sammelregel
   ist die Absicherung dafuer, dass eine spaetere Aenderung es nicht
   wegnimmt. */
.sa-crest, .ps-crest, .pr-crest, .tp-crest-visual { position: relative; }

/* Freigestellt gilt fuer JEDE der vier Groessen, nicht nur fuer die
   Tabellenprognose: seit dem Kickbase-Import tragen auch die Spieler
   echte, hintergrundfreie Bilder. Faellt eines aus, nimmt das onerror die
   Klasse ab, und darunter steht wieder Farbe plus Kuerzel. */
.sa-crest.crest-frei, .ps-crest.crest-frei, .pr-crest.crest-frei {
  background: none;
  background-image: none;
  box-shadow: none;
  border-radius: 0;
}
.sa-crest.crest-frei .sa-crest-kuerzel,
.ps-crest.crest-frei .ps-crest-kuerzel,
.pr-crest.crest-frei .pr-crest-kuerzel { display: none; }
.sa-crest.crest-frei .crest-bild,
.ps-crest.crest-frei .crest-bild,
.pr-crest.crest-frei .crest-bild { padding: 0; }

/* Ein Spielerfoto ist ein Portrait: es steht auf der Grundlinie, nicht in
   der Mitte. Zentriert schwebte der Kopf, und unten bliebe Luft. */
.ps-crest.crest-frei .crest-bild { object-position: bottom; }

/* ============================================================
   Saison-Reiter · zwei Ausklapper (Umbau 25.08.2026)
   ------------------------------------------------------------
   Native <details>. Dasselbe Muster wie .pr-league in
   prognose-reveal.js — der Browser merkt sich den Zustand beim
   Neuzeichnen, und Strg+F findet auch zugeklappten Text.

   KEINE Bedeutungsfarbe in diesem Block. Der Abweichungsbalken
   trägt seine Aussage über FORM (Lage des Punktes zur Mitte),
   nicht über Grün/Rot — Begründung im Kopf von saison.js.
   ============================================================ */

.sa-fach {
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
  overflow: hidden;
}

.sa-fach-kopf {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "titel pfeil" "befund pfeil";
  align-items: center;
  gap: 0 var(--sp-2);
  padding: var(--sp-3);
  cursor: pointer;
  list-style: none;
  /* 44px Mindesthöhe auch bei einzeiligem Befund — Tap-Ziel. */
  min-height: 44px;
}
.sa-fach-kopf::-webkit-details-marker { display: none; }
.sa-fach-kopf:hover { background: var(--bg-2); }
.sa-fach-kopf:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.sa-fach-titel {
  grid-area: titel;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-body);
  color: var(--text-1);
  /* Lange Titelwörter brechen im Wort statt die Zeile zu sprengen. */
  overflow-wrap: anywhere;
  min-width: 0;
}
.sa-fach-befund {
  grid-area: befund;
  font-size: var(--fs-caption);
  color: var(--text-3);
  overflow-wrap: anywhere;
  min-width: 0;
}
.sa-fach-kopf .icon {
  grid-area: pfeil;
  flex: none;
  color: var(--text-3);
  transform: rotate(90deg);
  transition: transform var(--dur-fast) var(--ease-out);
}
.sa-fach[open] > .sa-fach-kopf .icon { transform: rotate(-90deg); }

.sa-fach-koerper {
  padding: 0 var(--sp-3) var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

/* Der Ändern-Knopf unter der Tippliste. Abgesetzt durch eine Linie: er
   gehört zur Liste darüber, ist aber keine weitere Zeile davon. */
.sa-fach-aktion {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}
.sa-fach-aktion .sa-fach-hint { margin-top: var(--sp-2); text-align: center; }
.sa-fach-hint {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}

/* ---------- Ausklapper 1 · Die Tipps ---------- */

.sa-tipps, .sa-stand {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.sa-tipp-row {
  display: grid;
  grid-template-columns: 24px 28px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.sa-tipp-pos {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.sa-tipp-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sa-tipp-name {
  font-size: var(--fs-table);
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sa-tipp-meta { font-size: var(--fs-caption); color: var(--text-3); }

.sa-tipp-abstand {
  flex: none;
  padding: 2px var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  font-size: var(--fs-caption);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Einigkeit ist keine Leistung, also keine Farbe — nur ein ruhigerer
   Rand und kräftigerer Text. Die Pille sagt es ohnehin im Wort. */
.sa-tipp-abstand.is-einig {
  border-color: transparent;
  background: var(--bg-2);
  color: var(--text-2);
}

/* ---------- Ausklapper 2 · Der echte Stand ---------- */

.sa-stand-row {
  display: grid;
  grid-template-columns: 22px 26px minmax(0, 1fr) auto 56px 40px;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.sa-stand-pos {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.sa-stand-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sa-stand-name {
  font-size: var(--fs-table);
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sa-stand-meta { font-size: var(--fs-caption); color: var(--text-3); }
.sa-stand-pkt {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-table);
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.sa-stand-quote {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.sa-stand-quote b { font-size: var(--fs-small); color: var(--text-2); font-weight: 700; }
.sa-stand-quote small { font-size: 9px; color: var(--text-3); }
.sa-stand-quote-leer { color: var(--text-3); }

/* Der Abweichungsbalken.
   --sa-abw     -1 bis +1, Abweichung geteilt durch 17 (groesste moegliche)
   --sa-rahmen  Halbe Breite des Rahmen-Bandes, ebenfalls als Anteil

   Nur transform bewegt sich, nichts im Layout. */
.sa-abw {
  position: relative;
  display: block;
  width: 56px;
  height: 18px;
}
.sa-abw::before {
  /* Die Grundlinie über die ganze Breite. */
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: 1px;
  background: var(--line);
}
.sa-abw-band {
  /* Der ruhige Bereich um die Erwartung. */
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: calc(50% - var(--sa-rahmen) * 50%);
  width: calc(var(--sa-rahmen) * 100%);
  border-radius: 2px;
  background: var(--bg-2);
}
.sa-abw-mitte {
  /* Die Erwartung selbst. */
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-3);
  opacity: .55;
}
.sa-abw-punkt {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--text-1);
  transform: translate3d(calc(var(--sa-abw) * 24px), 0, 0);
}
.sa-abw--leer { opacity: .3; }

/* ---------- Statistikfragen ---------- */

.sa-stat {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
.sa-stat-titel {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-2);
}
.sa-stat-frage { display: flex; flex-direction: column; gap: var(--sp-1); }
.sa-stat-frage-titel {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-2);
  font-weight: 600;
}
.sa-stat-hinweis, .sa-stat-leer {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.sa-stat-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sa-stat-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
}
.sa-stat-name {
  font-size: var(--fs-table);
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sa-stat-pct {
  font-size: var(--fs-caption);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.sa-stat-pct small { font-size: 9px; color: var(--text-3); }
.sa-stat-lage {
  font-size: var(--fs-caption);
  color: var(--text-3);
  white-space: nowrap;
}
.sa-stat-lage.is-drin { color: var(--text-1); font-weight: 600; }

/* Schmale Geräte: die Punktzahl fällt weg, bevor der Name bricht.
   Der Balken bleibt, weil er die Aussage dieses Ausklappers trägt. */
@media (max-width: 359px) {
  .sa-stand-row { grid-template-columns: 20px 24px minmax(0, 1fr) 48px 36px; }
  .sa-stand-pkt { display: none; }
  .sa-abw { width: 48px; }
  .sa-abw-punkt { transform: translate3d(calc(var(--sa-abw) * 20px), 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .sa-fach-kopf .icon { transition: none; }
}

/* ============================================================
   Challenges-Kopf · angepinnte Umfrage + zwei Widgets (25.08.2026)
   ============================================================ */

.ch-pin {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
}
.ch-pin-marke {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: .06em;
}
/* Das Nadel-Symbol steht auf 20px im Raster und ist hier eine Marke,
   kein Bedienelement — auf Textgroesse herunter. */
.ch-pin-marke .icon, .ch-pin-marke svg { width: 14px; height: 14px; flex: none; }
.ch-pin-titel { margin: 0; }

.ch-widgets {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-2);
}
/* Unter 400px untereinander. Zwei Karten nebeneinander schrumpfen auf
   einem 320er nicht auf die haelfte Aussage, sondern auf gar keine. */
@media (max-width: 399px) {
  .ch-widgets { grid-template-columns: minmax(0, 1fr); }
}

.ch-widget {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--bg-1);
  min-width: 0;
}
.ch-widget-titel {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.ch-widget-text {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
  overflow-wrap: anywhere;
}
.ch-widget-fuss {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: auto 0 0;
  padding-top: 2px;
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.ch-widget-fuss .icon, .ch-widget-fuss svg { width: 14px; height: 14px; flex: none; }

/* Die Zahl im Take-Widget. Gross, weil sie die eine Auskunft ist, fuer
   die man das Widget ueberhaupt ansieht: wie viele habe ich gesetzt. */
.ch-widget-zahl {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0;
}
.ch-widget-zahl b {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-score);
  line-height: 1;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.ch-widget-zahl span {
  font-size: var(--fs-caption);
  color: var(--text-3);
}

/* ============================================================
   Feed · angepinnter Zugang zur Ligaleitung (25.08.2026)
   ------------------------------------------------------------
   Dasselbe Muster wie .tp-footer: sticky am unteren Rand des
   Scrollers, negative Aussenabstaende, damit die Flaeche bis an
   die Kante reicht, und safe-area unten fuer Geraete mit
   Gestenleiste.
   ============================================================ */
.fd-leitung-pin {
  position: sticky;
  bottom: 0;
  z-index: 5;
  margin: var(--sp-3) calc(var(--sp-4) * -1) calc(var(--sp-6) * -1);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--bg-0) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.fd-leitung-pin .fd-leitung { margin: 0; }

/* ============================================================
   Challenges · Widgets sind Tueren (25.08.2026)
   ------------------------------------------------------------
   Sie waren <section> und sind jetzt <a>. Damit erben sie die
   Linkfarbe des Browsers und den Unterstrich — beides muss weg,
   sonst sieht eine Karte aus wie ein Absatz mit Fehler.
   ============================================================ */

.ch-widget {
  position: relative;
  color: inherit;
  text-decoration: none;
  /* Platz rechts unten fuer den Pfeil, damit kein Text darunter laeuft. */
  padding-right: var(--sp-5);
}
.ch-widget:hover { background: var(--bg-2); }
.ch-widget:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* Gedrueckt heisst: naeher an der Flaeche, also kein Schein. Dasselbe
   Muster wie .btn--marke:active. */
.ch-widget:active { transform: translate3d(0, 1px, 0) scale(.995); }

.ch-widget-pfeil {
  position: absolute;
  right: var(--sp-2);
  bottom: var(--sp-3);
  display: flex;
  color: var(--text-3);
  transition: transform var(--dur-fast) var(--ease-out);
}
.ch-widget-pfeil svg { width: 16px; height: 16px; }
.ch-widget:hover .ch-widget-pfeil { transform: translate3d(2px, 0, 0); }

/* Zurueck in den Vorraum. Gleiche Form wie .lt-zurueck auf der
   Ligaleitung — zwei Rueckwege in einer App sollen gleich aussehen. */
.ch-zurueck {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  margin-left: calc(var(--sp-2) * -1);
  padding: 0 var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
  text-decoration: none;
  border-radius: var(--r-ctl);
}
.ch-zurueck:hover { color: var(--text-1); }
.ch-zurueck:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.ch-zurueck svg { width: 16px; height: 16px; transform: rotate(180deg); }

.ch-duell-seite {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--lila) 4%, var(--bg-1));
}
.ch-duell-text { margin: 0; font-size: var(--fs-small); color: var(--text-2); line-height: 1.5; }

@media (prefers-reduced-motion: reduce) {
  .ch-widget-pfeil { transition: none; }
  .ch-widget:active { transform: none; }
}

/* ============================================================
   Feed · Grossansicht eines Bildes (25.08.2026)
   ============================================================ */

/* Das Bild sitzt in einem Knopf. Der Knopf darf nichts eigenes
   mitbringen — kein Rand, kein Grund, keine Polsterung —, sonst
   veraendert sich das Raster der Galerie. */
.fd-medium-knopf {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--r-ctl);
  overflow: hidden;
  /* Ohne min-width:0 sprengt ein breites Bild die Rasterspur. */
  min-width: 0;
}
.fd-medium-knopf:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.fd-medium-knopf img { display: block; }

.fd-lupe {
  max-width: 100vw;
  max-height: 100dvh;
  width: 100vw;
  height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  overflow: hidden;
}
.fd-lupe::backdrop {
  /* Fast schwarz, nicht ganz: ein Rest Durchblick sagt „der Feed ist
     noch da", und genau das macht das Tippen daneben erwartbar. */
  background: rgba(0, 0, 0, .92);
}
.fd-lupe-bild {
  position: absolute;
  inset: 0;
  margin: auto;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  /* contain und nicht cover: ein Bild in der Grossansicht soll ganz zu
     sehen sein, nicht formatfuellend beschnitten. Das ist der ganze
     Zweck des Knopfes. */
  object-fit: contain;
}
.fd-lupe-zu {
  position: absolute;
  top: calc(var(--sp-3) + env(safe-area-inset-top, 0px));
  right: var(--sp-3);
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  cursor: pointer;
}
.fd-lupe-zu:hover { background: rgba(0, 0, 0, .75); }
.fd-lupe-zu:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Ein Take, der schon Stimmen hat, steht fest (25.08.2026).
   Kein ausgegrauter Muelleimer: ein Knopf, der aussieht wie ein Knopf
   und nichts tut, laesst den Manager dreimal tippen. Ein Schloss sagt,
   dass es keinen Knopf mehr gibt — und der Titel sagt warum. */
.ch-mein-fest {
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-ctl);
  color: var(--text-3);
  opacity: .7;
}
.ch-mein-fest svg { width: 15px; height: 15px; }

/* ============================================================
   Umfragen · Mehrfachstimmen und Auswahl aus dem Bestand
   (25.08.2026)
   ============================================================ */

.um-hinweis {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--text-3);
}

/* ---------- Die 18 Vereine ---------- */
.um-vereine {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: var(--sp-1);
}
/* Gewaehlt ist KEINE Wertung, sondern ein Zustand — deshalb der
   Markenrand und keine Bedeutungsfarbe. Blau sagt „wo man ist", und
   genau das ist hier gemeint (tokens.css, Farbsemantik). */
.um-verein.is-gewaehlt {
  border-color: var(--blau);
  background: var(--blau-tint);
}
.um-verein:disabled { opacity: .5; cursor: default; }

/* ---------- Schon gewaehlte Spieler ---------- */
.um-plaketten {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin-bottom: var(--sp-2);
}
.um-plakette {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--blau);
  border-radius: var(--r-pill);
  background: var(--blau-tint);
  color: var(--text-1);
  font-size: var(--fs-caption);
  cursor: pointer;
  /* Lange Spielernamen brechen im Wort statt die Zeile zu sprengen. */
  overflow-wrap: anywhere;
  min-width: 0;
}
.um-plakette svg { width: 13px; height: 13px; flex: none; color: var(--text-3); }
.um-plakette:hover { background: color-mix(in srgb, var(--blau) 18%, var(--bg-1)); }
.um-plakette:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.um-plakette:disabled { opacity: .5; cursor: default; }

/* ---------- Rangliste der Nennungen ---------- */
.um-ergebnis {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.um-ergebnis-titel {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-3);
}
.um-nennungen {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.um-nennung {
  position: relative;
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-ctl);
  background: var(--bg-0);
  overflow: hidden;
}
.um-nennung-rang {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-caption);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.um-nennung-name {
  position: relative;
  z-index: 1;
  font-size: var(--fs-table);
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Der Balken liegt HINTER dem Text und misst gegen den Spitzenreiter,
   nicht gegen die Gesamtzahl: bei drei Stimmen auf 40 Nennungen waeren
   alle Balken gleich unsichtbar. */
.um-nennung-balken {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--anteil) * 100%);
  background: var(--bg-2);
}
.um-nennung-zahl {
  position: relative;
  z-index: 1;
  font-size: var(--fs-caption);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.um-nennung.is-meine .um-nennung-name { font-weight: 700; }
.um-nennung.is-meine .um-nennung-balken { background: var(--blau-tint); }

/* Die eigene Nennung, wenn sie unter den Top 5 nicht auftaucht. */
.um-nennungen--meine {
  padding-top: var(--sp-1);
  border-top: 1px dashed var(--line);
}

.um-mehr > summary {
  min-height: 36px;
  display: flex;
  align-items: center;
  font-size: var(--fs-caption);
  color: var(--text-3);
  cursor: pointer;
}
.um-mehr > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.um-mehr[open] > summary { margin-bottom: var(--sp-1); }

/* ---------- Ligaleitung: Sorte und Stimmenzahl ---------- */
.lt-um-sorte {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-1);
}
.lt-um-sorte button {
  min-height: 44px;
  padding: var(--sp-1);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--bg-1);
  color: var(--text-2);
  font-size: var(--fs-caption);
  cursor: pointer;
  overflow-wrap: anywhere;
  min-width: 0;
}
.lt-um-sorte button[aria-pressed="true"] {
  border-color: var(--blau);
  background: var(--blau-tint);
  color: var(--text-1);
}
.lt-um-sorte button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
