/* ==========================================================================
   Modul Turnierbetrieb

   Baut auf den Gestaltungswerten in app.css auf — hier steht kein einziger
   fester Farbwert, nur Variablen. Zwei Farbschemata, ein Regelwerk.

   Aufbau nach ARCHITEKTUR.md, Abschnitt 1: Das Grundlayout gilt ab 360 px,
   breitere Geräte bekommen über min-width mehr. Der Desktop ist dabei nicht
   die breitere Handyansicht — ab 1000 px stehen Liste und Einzelheiten
   nebeneinander, Tabellen bleiben Tabellen, und die Dichte steigt.
   ========================================================================== */


/* --- 1  Rückmeldungen und Dialoge ----------------------------------------
   Ersatz für alert() und confirm(), die im Browser unzuverlässig sind
   (UEBERGABE.md, Abschnitt 5).
   ------------------------------------------------------------------------- */

.meldungsplatz {
  position: fixed;
  top: calc(var(--safe-top) + var(--s3));
  left: 50%;
  z-index: 80;
  display: grid;
  gap: var(--s2);
  width: min(440px, calc(100vw - 2 * var(--s4)));
  transform: translateX(-50%);
  pointer-events: none;
}

.meldung {
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.9rem;
  box-shadow: var(--sh2);
}

.meldung.erfolg { border-color: var(--brand); background: var(--brand-soft); color: var(--brand-ink); }
.meldung.fehler { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }
/* Eine Warnung ist kein Fehler und kein Erfolg: Es ist etwas geschehen, aber
   der Hinweis darauf verlangt eine Entscheidung. Erster Fall war die zu klein
   hochgeladene Urkundenvorlage — angenommen, aber unscharf im Druck. */
.meldung.warnung { border-color: var(--warn); background: var(--warn-soft); color: var(--warn); }

.dialoghuelle {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: var(--s5);
  background: rgba(10, 20, 16, 0.55);
}

.dialog {
  width: min(440px, 100%);
  max-height: 90dvh;
  padding: var(--s6);
  border-radius: var(--r3);
  background: var(--surface);
  box-shadow: var(--sh3);
  overflow-y: auto;
}

/* Rückfragen dürfen mehrzeilig sein.
 *
 * Die Frage kommt als Text mit Zeilenumbrüchen — beim Sonderfall etwa Fall,
 * Sieger, Verlierer und Stand untereinander. Im Absatz fielen die Umbrüche
 * bisher weg, und alles lief zu einem Satz zusammen: „Disqualifikation
 * Gewertet als Sieger: … Verlierer: …“. Ausgerechnet dort, wo man vor dem
 * Speichern noch einmal prüfen soll, war es am schlechtesten zu lesen.
 *
 * pre-line und nicht pre: Umbrüche bleiben, überflüssige Leerzeichen und
 * Einrückungen aus den Textbausteinen verschwinden weiterhin. */
#dialogfrage {
  white-space: pre-line;
}

/* Was die Karte bewirkt, unter der Frage „für wen?“. Gedämpft gesetzt, aber
   vorhanden: Seit die Karte das Ergebnis verändert, gehört die Folge in die
   Rückfrage und nicht erst in den Stand danach. */
.dialogfolge {
  margin-top: var(--s2);
  color: var(--ink-3);
  font-size: 0.88rem;
}

/* Der Haken in einer Rückfrage — „Alle annehmen, und die Melder
   benachrichtigen?“. Die ganze Zeile ist Trefferfläche: In einem Dialog trifft
   niemand ein 16-Pixel-Kästchen, schon gar nicht am Telefon. */
.dialoghaken {
  display: flex;
  gap: var(--s3);
  align-items: center;
  min-height: var(--touch);
  margin-top: var(--s4);
  padding: var(--s2) var(--s3);
  border-radius: var(--r1);
  cursor: pointer;
  font-size: 0.9rem;
}

.dialoghaken:hover { background: var(--surface-2); }
.dialoghaken input { width: 22px; height: 22px; flex: none; cursor: pointer; }

.dialogknoepfe {
  display: flex;
  gap: var(--s3);
  justify-content: flex-end;
  margin-top: var(--s5);
  flex-wrap: wrap;
}

.dialogknoepfe .knopf { flex: 1 1 auto; }

/* Der Losentscheid (§ 10 Nr. 5 der DBV-Spielordnung).
   Große Flächen zum Antippen: Gelost wird am Turniertisch, im Stehen, oft am
   Tablet — und ein Fehlgriff hier verdreht eine Platzierung. */
.losliste {
  list-style: none;
  margin: var(--s4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s2);
}

.losknopf {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.losknopf:hover:not(:disabled) { background: var(--surface-2); }

.losknopf .zahl {
  flex: none;
  min-width: 2ch;
  text-align: center;
  font-weight: 700;
  color: var(--ink-3);
}

/* Gezogen: Die Ziffer wird kräftig, der Knopf tritt zurück. Der Blick soll
   auf dem liegen, was noch in der Urne ist. */
.losknopf.gezogen {
  background: var(--surface-2);
  opacity: 0.7;
  cursor: default;
}

.losknopf.gezogen .zahl { color: var(--gold); }

/* Woher ein Platz kommt, wenn nicht aus den Ergebnissen: „dV“ oder „Los“. */
.tb-entschieden {
  margin-left: var(--s2);
  padding: 1px var(--s2);
  border-radius: var(--r1);
  background: var(--surface-2);
  color: var(--gold-ink);
  font-size: 0.75em;
  font-weight: 700;
  text-decoration: none;
  cursor: help;
}


/* --- 2  Reiterleiste ------------------------------------------------------
   Am Handy waagerecht scrollbar, damit alle sechs Reiter erreichbar bleiben,
   ohne dass die Seite selbst scrollt.
   ------------------------------------------------------------------------- */

.reiterleiste {
  display: flex;
  gap: var(--s1);
  margin-bottom: var(--s5);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: thin;
  scroll-snap-type: x proximity;
}

.reiter {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  flex: 0 0 auto;
  min-height: var(--touch);
  padding: 0 var(--s4);
  border-radius: var(--r2);
  color: var(--ink-3);
  font-size: 0.9rem;
  font-weight: 650;
  white-space: nowrap;
  scroll-snap-align: start;
}

.reiter:hover { background: var(--surface-2); color: var(--ink); }
.reiter.aktiv { background: var(--brand-soft); color: var(--brand-ink); }
.reiter .symbol { font-size: 1.05rem; line-height: 1; }


/* --- 3  Liste und Einzelheiten -------------------------------------------- */

.tb-zweispalt {
  display: grid;
  /* minmax(0, 1fr) wie beim Rahmen: Sonst zwingt eine breite Tabelle oder
     ein Turnierbaum die Spalte auf ihre Maximalbreite, statt in sich zu
     scrollen. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s5);
  align-items: start;
}

/* Der Haken „ohne Aufruf“ neben den Ansageknöpfen. Klein und gedämpft: Er ist
   die Ausnahme und soll die Knöpfe nicht überstimmen, zu denen er gehört. */
.cb-stumm {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.76rem;
  color: var(--ink-2);
  white-space: nowrap;
}

/* Der Kasten mit den liegen gebliebenen Durchsagen. Gedämpft warnend: Es ist
   nichts kaputt, es hat nur niemand zugehört — und was zu einer beendeten
   Partie gehört, tritt zurück, weil es die leichte Entscheidung ist. */
.cb-liegen { border-color: var(--warn); }
.cb-liegen .tb-karte.erledigt { opacity: 0.72; }

/* Was aus dem Aufruf eines Spiels geworden ist (Migration 078).

   Zwei Fälle, zwei Farben, und beide sind Hinweise und keine Fehler: Die
   Partie ist in Ordnung, es weiß nur niemand in der Halle davon. Rot wäre
   falsch — rot gehört einer Sperre, und hier gibt es nichts zu sperren.

   „Gesprochen“ bekommt **keine** Marke: Das ist der Normalfall, und eine
   Marke an jedem Spiel wäre das Rauschen, in dem die beiden hier untergingen. */
.aufrufmarke {
  display: inline-block;
  /* Sie soll ihren Text umschließen und nicht die Karte durchziehen: Die
     Karte ist ein Raster, und ein Kind darin dehnt sich sonst über die ganze
     Spalte — dann sieht die Marke aus wie eine Warnung und nicht wie eine
     Anmerkung. */
  justify-self: start;
  margin-top: var(--s2);
  padding: 2px var(--s2);
  border-radius: var(--r1);
  font-size: 0.76rem;
  font-weight: 600;
}

.aufrufmarke.offen  { background: var(--warn-soft);   color: var(--warn); }
.aufrufmarke.fehler { background: var(--danger-soft); color: var(--danger); }

/* Die Filterleiste über Callboard und Spiele. Gedämpft, solange sie nichts
   tut — sie ist ein Werkzeug und keine Meldung. Ist gefiltert, bekommt sie
   einen farbigen Rand: Eine Liste, die weniger zeigt als da ist, muss das
   auf einen Blick sagen, sonst hält man das Turnier für leer. */
.tb-disziplinfilter {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  /* Deutlich mehr Luft nach unten als nach oben: Die Leiste gehört zu allem,
     was darunter kommt, und stand vorher so dicht daran, dass sie wie eine
     Zeile der ersten Liste aussah. Der Abstand ist das, was sie zur
     Überschrift macht. */
  margin-bottom: var(--s7);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.tb-disziplinfilter.aktiv {
  border-color: var(--brand);
  background: var(--brand-soft);
}

.tb-disziplinfilter label { font-weight: 600; }
.tb-disziplinfilter select { max-width: 22rem; }
/* Der Erklärsatz darf umbrechen und drängt die Auswahl nicht aus der Zeile. */
.tb-disziplinfilter .zusatztext { flex: 1 1 16rem; min-width: 0; }

.tb-listenkopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
  flex-wrap: wrap;
}

.kartenliste {
  display: grid;
  gap: var(--s3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tb-karte {
  display: grid;
  gap: var(--s2);
  width: 100%;
  padding: var(--s4);
  border: 1px solid var(--line);
  border-left: 3px solid transparent;
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink);
  text-align: left;
  transition: border-color 0.12s ease, background-color 0.12s ease;
}

.tb-karte:hover { border-color: var(--line-2); background: var(--surface-2); }

.tb-karte.gewaehlt {
  border-left-color: var(--brand);
  background: var(--brand-soft);
}

.tb-karte.statisch { cursor: default; }

.tb-karte-kopf {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
}

.tb-karte-kopf strong { flex: 1; min-width: 0; }

.tb-zahlen {
  display: flex;
  gap: var(--s4);
  flex-wrap: wrap;
  color: var(--ink-3);
  font-size: 0.78rem;
}

.tb-archiv { margin-top: var(--s4); }
.tb-archiv summary { padding: var(--s3) 0; color: var(--ink-3); cursor: pointer; font-size: 0.9rem; }
.tb-archiv[open] summary { margin-bottom: var(--s3); }


/* --- 4  Werte und Kennzahlen ---------------------------------------------- */

.tb-werte { display: grid; gap: var(--s3); margin: 0; }
.tb-werte > div { display: grid; gap: 2px; }
.tb-werte dt { color: var(--ink-3); font-size: 0.78rem; font-weight: 650; }
.tb-werte dd { margin: 0; font-size: 0.92rem; }

.tb-zahlenraster {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3);
}

.tb-kennzahl {
  display: grid;
  gap: 2px;
  padding: var(--s3) var(--s4);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.tb-kennzahl .zahl { font-size: 1.4rem; font-weight: 700; line-height: 1.1; }
.tb-kennzahl small { color: var(--ink-3); font-size: 0.76rem; }


/* --- 5  Formulare --------------------------------------------------------- */

.tb-feldpaar,
.tb-vierfach {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s4);
}

.tb-gruppe {
  display: grid;
  gap: var(--s4);
  margin: 0;
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
}

.tb-gruppe legend {
  padding: 0 var(--s2);
  color: var(--ink-2);
  font-size: 0.82rem;
  font-weight: 700;
}

/* Auswahl mit Beschreibung — die Fläche ist ganz antippbar. */
.tb-wahl,
.tb-kasten {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  min-height: var(--touch);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  cursor: pointer;
}

.tb-wahl:hover,
.tb-kasten:hover { background: var(--surface-2); }

/* Das Feld für eine einzelne Platzkorrektur. Abgesetzt, aber kein eigener
   Kasten zum Anklicken — es steht innerhalb der Platzierungsliste. */
.tb-verschiebefeld {
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.tb-verschiebefeld h4 { margin: 0; font-size: 1rem; }

.tb-wahl input,
.tb-kasten input {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--brand);
}

.tb-wahl span { display: grid; gap: 2px; }
.tb-wahl small { color: var(--ink-3); font-size: 0.8rem; }
.tb-kasten span { font-size: 0.9rem; }

.tb-ausklapp {
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
}

.tb-ausklapp summary {
  min-height: 32px;
  color: var(--ink-2);
  font-size: 0.9rem;
  font-weight: 650;
  cursor: pointer;
}


/* --- 6  Tabellen ----------------------------------------------------------
   Auf schmalen Geräten wird jede Zeile zu einem Block mit Beschriftung je
   Wert (ARCHITEKTUR.md, Abschnitt 1). Die Beschriftung steht in data-spalte
   und wird hier eingeblendet — es gibt also keine zweite Auszeichnung, die
   auseinanderlaufen könnte.
   ------------------------------------------------------------------------- */

.tabellenkasten {
  overflow-x: auto;
  border-radius: var(--r2);
}

.tb-tabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.tb-tabelle th {
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--line-2);
  color: var(--ink-3);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Spaltenüberschriften, in denen ein **Name** steht.
   `text-transform: uppercase` bildet nach Unicode ab, und dort wird aus „ß“
   ein „SS“ — aus André Haßlocher würde ANDRÉ HASSLOCHER. Bei einem Wort wie
   „Satz“ ist das Geschmack, bei einem Personennamen eine falsche
   Schreibweise. Deshalb bleiben Namen, wie sie gemeldet wurden. */
.tb-tabelle th.eigenname {
  font-size: 0.85rem;
  letter-spacing: 0;
  text-transform: none;
}

.tb-tabelle td {
  padding: var(--s3);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.tb-zeilenaktionen {
  display: flex;
  gap: var(--s2);
  align-items: center;
  flex-wrap: wrap;
}

/* Der Inhalt einer Tabellenzelle, sobald er aus mehr als einem Knoten besteht.
   Auf dem Desktop fällt er nicht auf — ein Block in einer Zelle. Auf schmalen
   Geräten ist er das, was die Zelle zu **einem** Rasterfeld macht und damit
   ganz in der Wertspalte hält (Begründung in der Abfrage unten).

   Innen gilt gewöhnlicher Textfluss, und das ist Absicht: Ein `<div>` darin
   bricht um, ein `<span>` läuft weiter. Damit sieht die Karte genauso aus wie
   die Tabellenzelle auf dem Desktop — vorher machte das Raster aus jedem
   Knoten eine eigene Zeile, auch aus dem Wörtchen „gegen“. */
.zellinhalt { min-width: 0; }

@media (max-width: 767px) {
  .tb-tabelle,
  .tb-tabelle tbody,
  .tb-tabelle tr,
  .tb-tabelle td { display: block; width: 100%; }

  .tb-tabelle thead { display: none; }

  .tb-tabelle tr {
    margin-bottom: var(--s3);
    padding: var(--s2);
    border: 1px solid var(--line);
    border-radius: var(--r2);
    background: var(--surface);
  }

  .tb-tabelle td {
    display: grid;
    grid-template-columns: 38% minmax(0, 1fr);
    gap: var(--s3);
    padding: var(--s2) var(--s3);
    border-bottom: 0;
  }

  .tb-tabelle td::before {
    content: attr(data-spalte);
    color: var(--ink-3);
    font-size: 0.78rem;
    font-weight: 650;
  }

  /* **Eine Zelle mit mehreren Knoten braucht einen Hüllknoten** — dafür gibt
     es `.zellinhalt` (siehe unten). Die beiden Zeilen hier sind die
     Rückfalllinie für den Fall, dass jemand das vergisst:

     Die Kinder einer Zelle sind gewöhnliche Rasterfelder und werden der Reihe
     nach verteilt. Das Pseudoelement belegt Zeile 1 Spalte 1, der erste Knoten
     Zeile 1 Spalte 2 — und der **zweite** rutscht in Zeile 2 Spalte 1, also
     unter die Beschriftung. Bei einem Doppel stand die Spielerzeile damit
     links neben dem eigenen Namen.

     Für **Elemente** ist das hiermit ausgeschlossen. Für blanken Text nicht:
     Er wird zu einem anonymen Rasterfeld, das kein Suchausdruck erreicht.
     Genau deshalb bleibt der Hüllknoten die Regel und dies nur das Netz.

     Zellen ohne `data-spalte` sind ausgenommen: Sie sind einspaltig (siehe
     unten), und eine Zuweisung auf Spalte 2 legte dort eine zweite Spalte an,
     die es gar nicht geben soll. */
  .tb-tabelle td[data-spalte]::before { grid-column: 1; grid-row: 1; }
  /* `-2 / -1` und nicht `2`: Das ist die **letzte** Spalte, gezählt von hinten.
     Bei den zwei Spalten hier ist das die Wertspalte. Einzelne Zellen erklären
     sich weiter unten aber für einspaltig — die Systemspalte der
     Empfehlungstabelle etwa, die ihre Beschriftung ausblendet und die volle
     Breite nimmt. Eine feste `2` legte dort eine zweite Spalte an, die es gar
     nicht geben soll, und rückte den Inhalt grundlos ein. */
  .tb-tabelle td[data-spalte] > * { grid-column: -2 / -1; }

  .tb-tabelle td:not([data-spalte]) { grid-template-columns: 1fr; }

  /* Eine Zelle ohne Beschriftung — die Aktionsspalte — soll auch keine leere
     Beschriftungszeile bekommen. `attr()` liefert dort nichts, das
     Pseudoelement entstünde aber trotzdem und nähme sich eine Zeile samt
     Abstand. */
  .tb-tabelle td:not([data-spalte])::before { display: none; }
}


/* --- 6a  Stapelweise ansetzen (UEBERGABE.md, Abschnitt 10.5) --------------
   Im Auswahlmodus ist die ganze Zeile eine Trefferfläche. Damit das am
   Telefon zuverlässig funktioniert, braucht sie einen sichtbaren Zustand und
   die Fingerhöhe aus ARCHITEKTUR.md, Abschnitt 1.
   -------------------------------------------------------------------------- */

.tb-tabelle.auswahlmodus tbody tr[data-auswahl] {
  cursor: pointer;
  /* Verhindert, dass ein Tippen auf dem Telefon Text markiert statt zu wählen. */
  -webkit-user-select: none;
  user-select: none;
}

.tb-tabelle.auswahlmodus tbody tr[data-auswahl]:hover { background: var(--surface-2); }

.tb-tabelle.auswahlmodus tbody tr.markiert {
  background: var(--brand-soft);
  box-shadow: inset 3px 0 0 var(--brand);
}

.auswahlkasten {
  width: 22px;
  height: 22px;
  min-height: 0;
  cursor: pointer;
}

.tb-berichtliste {
  display: grid;
  gap: var(--s2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.9rem;
}

.tb-berichtliste li {
  display: flex;
  gap: var(--s3);
  align-items: baseline;
  flex-wrap: wrap;
}

@media (max-width: 767px) {
  /* Als Karte ist die ganze Karte die Trefferfläche — der Haken steht oben. */
  .tb-tabelle.auswahlmodus tbody tr[data-auswahl] { min-height: var(--touch); }

  /* Eine Karte hat keine Spalten, die auszurichten wären: Die leere Zelle
     einer nicht auswählbaren Partie fällt hier ganz weg. */
  .tb-tabelle td.leer-auswahl { display: none; }
}


/* --- 6b  Meldungsimport ---------------------------------------------------
   Das Dateifeld bekommt eine eigene Gestaltung: Es fällt sonst aus der Reihe,
   weil `input[type="file"]` nicht zu den Eingabearten in app.css gehört und
   auf der Standardhöhe des Browsers bliebe — bei 44 px Fingerfläche zu wenig
   (ARCHITEKTUR.md, Abschnitt 1).
   ------------------------------------------------------------------------- */

.dateifeld input[type="file"] {
  width: 100%;
  min-height: var(--touch);
  padding: var(--s3) var(--s4);
  border: 1px dashed var(--line-2);
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 0.95rem;
}

.dateifeld input[type="file"]::file-selector-button {
  min-height: 32px;
  margin-right: var(--s4);
  padding: 0 var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r1);
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}

.dateifeld input[type="file"]:focus {
  border-color: var(--brand);
  outline: none;
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.importliste { display: grid; gap: var(--s3); }

.importblock {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
}

.importblock .tb-kasten { border: 0; background: none; padding: 0; }
.importblock small { display: block; color: var(--ink-3); font-size: 0.8rem; }


/* --- 7  Felder ------------------------------------------------------------ */

.feldraster {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s4);
}

.feldkachel {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
}

.feldkachel.belegt { border-color: var(--st-live); }
.feldkachel.ausgeschaltet { opacity: 0.55; }

.feldkachel-kopf { display: flex; align-items: center; gap: var(--s3); }

.feldnummer {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px; height: 44px;
  border-radius: var(--r2);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 1.2rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.feldmarke {
  display: inline-grid;
  place-items: center;
  min-width: 32px;
  padding: 2px var(--s2);
  border-radius: var(--r1);
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: 0.78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.feldmarke.gross {
  min-width: 48px;
  min-height: 48px;
  border-radius: var(--r2);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 1.25rem;
}

.freifelder { display: flex; gap: var(--s3); flex-wrap: wrap; }

.feldzugang,
.zugangskasten {
  display: grid;
  gap: var(--s3);
  padding: var(--s3);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.feldzugang small,
.zugangskasten small {
  display: block;
  color: var(--ink-3);
  font-size: 0.74rem;
}

/* Der QR-Code steht auf weißem Grund, auch im dunklen Farbschema.
   Kameras erwarten dunkle Module auf hellem Grund; ein umgekehrter Code
   wird von vielen Geräten nicht erkannt — und ausgerechnet in der Halle
   gibt es keinen zweiten Versuch mit einem anderen Gerät. */
.qr-kasten {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  padding: var(--s4);
  border-radius: var(--r2);
  background: #fff;
}

.qr-kasten .qr {
  width: min(200px, 100%);
  height: auto;
}

/* Der erklärende Satz steht mit im weißen Kasten und braucht deshalb eine
   Farbe, die auch dort trägt — var(--ink-3) ist im dunklen Schema für
   Weiß gedacht und wäre hier zu blass. */
.qr-kasten .zusatztext {
  max-width: 34ch;
  color: #414d47;
  text-align: center;
}

/* Einstieg in die Zählansicht auf der Anmeldeseite. Abgesetzt, weil er
   nicht zur Anmeldung gehört, sondern der Ausweg für Geräte ist, die sich
   gar nicht anmelden sollen. */
.zaehleinstieg {
  display: grid;
  gap: var(--s3);
  margin-top: var(--s5);
  padding-top: var(--s5);
  border-top: 1px solid var(--line);
  text-align: center;
}

.grosser-code {
  font-family: var(--font-num);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.12em;
}

.feldlink code {
  font-family: var(--font-num);
  font-size: 0.76rem;
  overflow-wrap: anywhere;
}


/* --- 8  Spiele ------------------------------------------------------------ */

.spielkarte.laeuft { border-left-color: var(--st-live); }
.spielkarte.beendet { opacity: 0.75; }

.paarung {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--s3);
  font-size: 0.92rem;
}

.paarung > span:first-child { text-align: right; }

/* Das Fangnetz. `<wbr>` nach dem Schrägstrich deckt den Regelfall ab
   (`ui.meldungsname`); bleibt ein einzelner Name trotzdem zu lang für seine
   Spalte — „Keo Boun Khoune“ in einer schmalen Halle —, wird er hier notfalls
   mitten im Wort gebrochen. Hässlich, aber lesbar; ein Überlauf war es nicht:
   Am Tablet schoben sich die beiden Namen übereinander. */
.paarung > span { overflow-wrap: anywhere; }
.paarung .sieger { font-weight: 700; color: var(--brand-ink); }

.paarung .stand {
  padding: 2px var(--s3);
  border-radius: var(--r1);
  background: var(--surface-3);
  font-weight: 700;
  font-size: 0.85rem;
  white-space: nowrap;
}

.setzplatz { color: var(--gold-ink); font-weight: 700; }

.spieltafel {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3);
}

.spieltafel-seite {
  display: grid;
  gap: var(--s1);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface-2);
  text-align: center;
}

.spieltafel-seite.sieger { border-color: var(--brand); background: var(--brand-soft); }
.spieltafel-name { font-weight: 700; overflow-wrap: anywhere; }
.spieltafel-spieler { font-size: 0.78rem; }
.spieltafel-saetze { font-size: 2.2rem; font-weight: 800; line-height: 1; }

.satztabelle td.zahl { font-size: 1rem; font-weight: 700; }


/* --- 9  Callboard --------------------------------------------------------- */

.callboardliste {
  display: grid;
  gap: var(--s3);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: rang;
}

.callboardeintrag {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
}

.callboard-rang {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  color: var(--ink-2);
  font-weight: 800;
  font-size: 0.85rem;
}

/* Der Platz, den die Namen tatsächlich bekommen — und danach richtet sich
   ihre Anordnung. Eine **Container-Abfrage** und keine Bildschirmbreite: Wie
   schmal es hier wird, hängt nicht am Gerät, sondern daran, ob das Modul
   Ansagen freigeschaltet ist. Mit ihm stehen rechts fünf weitere Knöpfe, und
   dieselbe Tabletbreite lässt der Paarung auf einmal die Hälfte. */
.callboard-inhalt {
  display: grid;
  gap: var(--s2);
  min-width: 0;
  container-type: inline-size;
  container-name: cbeintrag;
}

/* Zu schmal für zwei Doppelnamen nebeneinander: Dann untereinander.
   „Kalle Rosenbaur/Thao Zhang gegen Theodor Schröder/Laura Brach“ braucht in
   drei Spalten je Seite gut zwölf Zeichen Breite; darunter zerfällt jeder
   Name in einzelne Wörter, und am Ende bricht er mitten im Wort. Untereinander
   bekommt jeder die volle Breite und liest sich wie hingeschrieben. */
@container cbeintrag (max-width: 26rem) {
  .callboardeintrag .paarung {
    grid-template-columns: minmax(0, 1fr);
    justify-items: start;
    gap: 2px;
  }

  .callboardeintrag .paarung > span:first-child { text-align: left; }

  /* „gegen“ rückt ein — so ist auf einen Blick zu sehen, dass es die
     Trennung ist und nicht ein dritter Name. */
  .callboardeintrag .paarung .stand { margin-left: var(--s4); }
}

.callboard-aktionen {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
}

.callboard-pfeile { display: flex; gap: var(--s1); }

.callboard-pfeile .knopf {
  min-width: var(--touch);
  padding: 0;
}

.callboard-feldwahl,
.baum-feldwahl {
  width: auto;
  min-width: 120px;
  min-height: 40px;
  padding: var(--s1) var(--s3);
  font-size: 0.85rem;
}


/* --- 10  Planung und Turnierbaum ------------------------------------------
   Der Baum kann sehr breit werden. Er scrollt deshalb in einem eigenen
   Kasten — die Seite selbst scrollt nie waagerecht.
   ------------------------------------------------------------------------- */

.setzliste { display: grid; gap: var(--s2); }

.setzzeile {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  border-radius: var(--r1);
  background: var(--surface-2);
  font-size: 0.9rem;
}

.setzzeile input { min-height: 40px; text-align: center; }

/* Die Aufteilung vor einer Qualifikation. Dieselbe Zeile wie die Setzliste,
   aber mit einem Schalter statt einer Zahl — und mit dem Wort „Quali“ daneben,
   damit ein leeres Kästchen nicht raten lässt, wofür es steht. Die angehakten
   Zeilen sind zusätzlich unterlegt: Bei sechzig Meldungen ist die Frage
   „wer spielt die Qualifikation“ sonst nur durch Zählen zu beantworten. */
.qualizeile { grid-template-columns: minmax(0, 1fr) auto; }

.qualizeile.in-quali { background: var(--brand-soft); color: var(--brand-ink); }

.qualischalter {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: 0.8rem;
}

.qualischalter input { min-height: 24px; width: 24px; }

.gruppenraster {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s5);
}

.gruppenraster h4 { margin-bottom: var(--s2); }

.baumkasten {
  overflow-x: auto;
  padding-bottom: var(--s3);
}

.baum {
  display: flex;
  gap: var(--s5);
  align-items: flex-start;
  min-width: min-content;
}

.baumrunde {
  display: grid;
  gap: var(--s3);
  align-content: start;
  min-width: 190px;
}

.baumrunde h4,
.baumrunde h5 {
  color: var(--ink-3);
  font-size: 0.76rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

/* Überschrift über einem einzelnen Baum. Ein Ranglistensystem bringt
   Gewinner-, Verlierer- und Platzierungsbaum mit; ohne Titel wüsste niemand,
   welcher davon gerade dasteht. */
.baumtitel {
  margin-top: var(--s4);
  font-size: 0.95rem;
}

.baumtitel:first-of-type { margin-top: 0; }

.baumspiel {
  display: grid;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
  overflow: hidden;
}

.baumspiel.laeuft { border-color: var(--st-live); }
.baumspiel.freilos { opacity: 0.6; }

.baumseite {
  padding: var(--s2) var(--s3);
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}

.baumseite + .baumseite { border-top: 1px solid var(--line); }
.baumseite.sieger { background: var(--brand-soft); color: var(--brand-ink); font-weight: 700; }
.baumseite.offen { color: var(--ink-3); }

/* Der Platzhalter einer vorgelagerten Qualifikation (UEBERGABE.md 12.2).
   Kursiv, damit auf dem gedruckten Plan und aus zwei Metern Abstand sofort
   erkennbar ist, dass „Sieger Gruppe A“ kein Name ist, sondern eine
   Ankündigung — er darf nicht mit einer Meldung verwechselt werden. */
.platzhalter {
  font-style: italic;
  color: var(--ink-3);
}

/* Die Umschaltung zwischen Qualifikation und Hauptfeld. Am Telefon
   untereinander wäre sie verschwendeter Platz — zwei Knöpfe passen auch auf
   360 px nebeneinander, solange sie umbrechen dürfen. */
.tb-phasenwahl { flex-wrap: wrap; gap: var(--s2); }
.tb-phasenwahl .zusatztext { margin-left: var(--s2); }

.baumergebnis {
  padding: var(--s1) var(--s3);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-3);
  font-size: 0.76rem;
}


/* --- 10a  Systemempfehlung (UEBERGABE.md, Abschnitt 12.1) -----------------
   Eine Vergleichstabelle, sortierbar nach jeder Kennzahl. Keine Zeile ist
   hervorgehoben — die Anwendung ruft keinen Sieger aus, und eine Farbe wäre
   genau das. Auffällig ist nur, was schiefgehen kann: die Warnungen.
   ------------------------------------------------------------------------- */

.empfehlung-wahl {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s2);
}

/* Der Sortierknopf sitzt im Tabellenkopf und übernimmt dessen Aussehen —
   sichtbar als Bedienelement wird er erst beim Überfahren und beim Fokus.
   Ein Knopf und kein Klick auf die Zelle, damit die Sortierung auch mit der
   Tastatur erreichbar ist (ARCHITEKTUR.md, Abschnitt 1). */
.sortierknopf {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  width: 100%;
  min-height: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: left;
  text-transform: inherit;
  cursor: pointer;
}

.sortierknopf:hover { color: var(--ink); }
.sortierknopf span { margin-left: var(--s2); color: var(--ink-3); }

/* „Spiele je Meldung“ steht einmal über beiden Zahlenspalten. Ausgeschrieben
   in jeder der beiden Überschriften wäre die Tabelle rund 180 px breiter —
   und müsste dann auch am Rechner seitlich scrollen, obwohl es beim
   Vergleichen gerade darauf ankommt, alle Kennzahlen nebeneinander zu sehen.
   Die ausführliche Bedeutung steht im aria-label der Sortierknöpfe und, für
   die Kartenansicht am Telefon, in data-spalte. */
.empfehlung-obergruppe {
  border-bottom: 0;
  text-align: center;
}

.empfehlung-warnung {
  margin-top: var(--s2);
  padding: var(--s2) var(--s3);
  border-radius: var(--r1);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 0.8rem;
}

@media (min-width: 600px) {
  .empfehlung-wahl { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
}

/* Die Sortierung für schmale Geräte. Sie erscheint genau dort, wo der
   Tabellenkopf mit seinen Sortierknöpfen verschwindet — sonst wäre
   „sortierbar nach jeder Kennzahl“ nur am Rechner erfüllt. */
.empfehlung-sortierleiste { display: none; }

/* Am Telefon wird die Tabelle zu Karten. Der Systemname trägt dort die
   Entscheidung und bekommt deshalb Gewicht, statt in einer Zeile mit der
   Beschriftung „System“ unterzugehen. */
@media (max-width: 767px) {
  .empfehlungstabelle td[data-spalte="System"] { grid-template-columns: 1fr; }
  .empfehlungstabelle td[data-spalte="System"]::before { display: none; }

  /* Einspaltig, solange die Beschriftungen sonst abgeschnitten würden:
     „Spiele je Meldung, wenigstens“ braucht die volle Breite. Erst ab
     480 px passen Auswahl und Richtung nebeneinander. */
  .empfehlung-sortierleiste {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: end;
    gap: var(--s3);
  }

  .empfehlung-sortierleiste .knopf { min-height: var(--touch); }
}

@media (min-width: 480px) and (max-width: 767px) {
  .empfehlung-sortierleiste { grid-template-columns: minmax(0, 1fr) auto; }
}


/* --- 11  Zählansicht ------------------------------------------------------
   Die einzige Ansicht, die den ganzen Bildschirm einnimmt. Sie muss aus zwei
   Metern Entfernung lesbar und mit einer Hand bedienbar sein
   (UEBERGABE.md, Abschnitt 3.5).
   ------------------------------------------------------------------------- */

.zaehlanmeldung {
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: var(--s5);
  padding-top: calc(var(--s5) + var(--safe-top));
  background: var(--nav-bg);
}

.codeeingabe {
  font-family: var(--font-num);
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.35em;
  text-align: center;
}

/* Gerät hängt an einem Feld, auf dem gerade nichts läuft. */
.zaehlwarten {
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: var(--s5);
  background: var(--nav-bg);
}

.wartekarte {
  display: grid;
  justify-items: center;
  gap: var(--s4);
  width: min(420px, 100%);
  padding: var(--s7) var(--s6);
  border-radius: var(--r3);
  background: var(--surface);
  text-align: center;
  box-shadow: var(--sh3);
}

.zaehlansicht {
  display: grid;
  /* Kopf, Hinweisleiste, Namen, Zählflächen, Fußleiste. Die Namen haben eine
     eigene Zeile, damit beide Zählflächen gleich groß bleiben — siehe
     `.zaehlnamen`. */
  grid-template-rows: auto auto auto minmax(0, 1fr) auto;
  min-height: 100dvh;
  background: var(--page);
}

.zaehlkopf {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  padding-top: calc(var(--s3) + var(--safe-top));
  background: var(--nav-bg);
  color: var(--nav-ink);
}

.zaehlkopf-links { display: grid; gap: 2px; min-width: 0; }
.zaehlkopf-links .zusatztext { color: var(--nav-ink-2); }
.zaehlkopf-mitte { flex: 1; display: grid; place-items: center; }

.satzuebersicht { display: grid; justify-items: center; gap: 2px; }
.satzstand { color: #fff; font-size: 1.5rem; font-weight: 800; line-height: 1; }
.satzuebersicht .zusatztext { color: var(--nav-ink-2); font-size: 0.76rem; }

.zaehlhinweis {
  padding: var(--s2) var(--s4);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 0.95rem;
  font-weight: 650;
  text-align: center;
}

.zaehlhinweis.ball { background: var(--st-live-soft); color: var(--st-live); }
.zaehlhinweis.pause { background: var(--warn-soft); color: var(--warn); }
.zaehlhinweis.einspielen { background: var(--st-ready-soft); color: var(--st-ready); }
.zaehlhinweis.fertig { background: var(--brand-soft); color: var(--brand-ink); }

/* **Ein Raster für die Namen, ein zweites für die Flächen** — und nicht eine
   Spalte je Seite, in der beides untereinander steht.

   Der Unterschied fällt erst mit langen Namen auf, dafür sofort: Stand links
   „Shi/Liu“ auf einer Zeile und rechts „De Oliveira Cantante De Matos/Finck“
   auf zweien, dann bestimmte jede Seite ihre Zeilenhöhen selbst — die rechte
   Zählfläche begann eine Zeilenhöhe tiefer und war um genau so viel kleiner.
   Zwei ungleich große Tippflächen nebeneinander sind bei einem Gerät, das im
   Stehen mit einer Hand bedient wird, nicht nur unschön.

   Getrennte Raster lösen das ohne Sonderfall: Die Namenszeile ist so hoch wie
   der längere der beiden Namen, und darunter beginnen beide Flächen auf
   derselben Höhe — auf jedem Gerät und bei jeder Namenslänge. */
.zaehlnamen {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
  padding: var(--s2) var(--s2) 0;
}

/* Der kürzere Name hängt sich an die Unterkante seiner Zeile und steht damit
   ebenso dicht über seiner Fläche wie der längere. */
.zaehlnamen-feld { align-self: end; }

.zaehlfeld {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
  padding: var(--s2);
  min-height: 0;
}

.zaehlseite {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: var(--s2);
  min-height: 0;
}

.zaehlname {
  font-size: 1rem;
  line-height: 1.2;
  text-align: center;
  overflow-wrap: anywhere;
}

.zaehlspieler {
  color: var(--ink-3);
  font-size: 0.76rem;
  text-align: center;
  overflow-wrap: anywhere;
}

/* Die Punktfläche ist bewusst groß — sie wird im Stehen mit einer Hand
   getroffen. Das Minus liegt getrennt darunter, damit ein Streifschuss
   keinen Punkt kostet. */
.punktflaeche {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 140px;
  border: 2px solid var(--line-2);
  border-radius: var(--r3);
  background: var(--surface);
  color: var(--ink);
  transition: background-color 0.08s ease, transform 0.08s ease;
  touch-action: manipulation;
}

.punktflaeche:active:not(:disabled) { background: var(--brand-soft); transform: scale(0.99); }
.punktflaeche.arbeitet { opacity: 0.6; }

.punktzahl {
  font-size: clamp(3.5rem, 22vw, 8rem);
  font-weight: 800;
  line-height: 1;
}

.punktplus {
  position: absolute;
  right: var(--s3);
  bottom: var(--s2);
  color: var(--ink-3);
  font-size: 1.6rem;
  font-weight: 700;
}

.minusflaeche {
  min-height: 52px;
  border: 1px solid var(--line-2);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 1.6rem;
  font-weight: 700;
  touch-action: manipulation;
}

.minusflaeche:active:not(:disabled) { background: var(--surface-3); }

.zaehlfuss {
  display: flex;
  gap: var(--s2);
  padding: var(--s3);
  padding-bottom: calc(var(--s3) + var(--safe-bottom));
  border-top: 1px solid var(--line);
  background: var(--surface);
  overflow-x: auto;
}

.zaehl-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 1 0 auto;
  min-width: 96px;
  min-height: 56px;
  padding: 0 var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 0.95rem;
  font-weight: 650;
  white-space: nowrap;
}

.zaehl-knopf:hover:not(:disabled) { background: var(--surface-3); }
.zaehl-knopf.hervor { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.zaehl-knopf.klein { flex: none; min-width: var(--touch); min-height: var(--touch); padding: 0 var(--s3); }
.zaehlkopf .zaehl-knopf.klein { background: rgba(255, 255, 255, 0.12); border-color: transparent; color: #fff; }


/* --- 11b  Schiedsrichter-Zählansicht --------------------------------------
   Eine eigene Oberfläche für Spiele mit Schiedsrichter (UEBERGABE.md,
   Abschnitt 8.1 c). Bedient wird das **Spielfeld**: Angetippt wird die
   Hälfte, auf der der Ball gewonnen wurde.

   Sie ist für ein Tablet im Querformat gebaut — so steht es am
   Schiedsrichterstuhl. Auf einem Telefon im Hochformat rutschen Kopfzeile
   und Zusatzfunktionen untereinander, das Feld bleibt aber quer: Ein
   hochkant gedrehtes Badmintonfeld wäre nicht wiederzuerkennen.
   ------------------------------------------------------------------------- */

.schiri-ansicht {
  /* Spalte statt Raster, und das aus einem Grund: Die Ansage über dem Feld
     kann fehlen (Option „Ansagehilfen ausblenden“). Mit festen Rasterzeilen
     verschiebt sich dann alles um eine Zeile, und das Feld bekommt die Höhe
     der Minusleiste. Im Flusslayout wächst schlicht das Feld — gleichgültig,
     wie viele Kinder darüber stehen. */
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: var(--s3);
  min-height: 100dvh;
  padding: var(--s4);
  padding-top: calc(var(--s4) + var(--safe-top));
  padding-bottom: calc(var(--s4) + var(--safe-bottom));
  background: var(--nav-bg);
  color: #fff;
  /* Zwei schnelle Tipps auf denselben Knopf sind hier zwei Tipps und kein
     Doppeltippen: Safari auf dem iPad zoomte sonst die Ansicht heran, sobald
     der Schiedsrichter „↺ Zurück“ zweimal hintereinander drückte. Die Angabe
     gilt für alles, was in dieser Ansicht berührt wird — auch für die Knöpfe
     in den Dialogen —, und lässt Wischen und Auseinanderziehen unberührt.
     `none` wäre falsch: Dann ließe sich die Ansicht nicht mehr scrollen. */
  touch-action: manipulation;
}

.schiri-kopf {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
}

.schiri-kopf-text { min-width: 0; }
.schiri-kopf h1 { font-size: clamp(1.1rem, 2.6vw, 1.9rem); color: #fff; }
.schiri-kopf p { color: var(--nav-ink-2); font-size: clamp(0.78rem, 1.4vw, 1rem); }

.schiri-marken { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s2); }

.schiri-marke {
  padding: 2px var(--s3);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.12);
  color: var(--nav-ink);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.schiri-marke.online { background: rgba(63, 170, 129, 0.28); color: #8fd8b8; }
.schiri-marke.offline { background: var(--danger); color: #fff; }
.schiri-marke.warnung { background: rgba(217, 168, 60, 0.24); color: var(--gold-bright); }

/* Umbrechen erlaubt: Auf einem schmalen Gerät passen die vier Knöpfe sonst
   nicht in eine Zeile und schieben die Seite waagerecht heraus. */
.schiri-werkzeuge {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2);
  min-width: 0;
}

.schiri-rund {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--r-pill);
  background: #fff;
  color: #16201a;
  font-size: 1.3rem;
}

.schiri-rund.gold { background: var(--gold-bright); }
.schiri-rund:disabled { opacity: 0.35; }

/* Das Federballzeichen nimmt die Schriftfarbe des Knopfes an (currentColor)
   und stimmt damit in beiden Farbschemata ohne zweiten Farbwert. */
.schiri-symbol { width: 28px; height: 28px; display: block; }

/* Gilt für <button> **und** <a>: Der Spielbericht ist ein Verweis auf ein
   PDF und kein Knopf, soll aber wie einer aussehen. Ein Verweis ist von Haus
   aus `inline` und unterstrichen — ohne diese beiden Zeilen säße seine
   Schrift oben in der Fläche statt mittig darin und wäre unterstrichen.
   `.knopf` in app.css macht es seit jeher genauso. */
.schiri-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch);
  padding: 0 var(--s5);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--r2);
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 0.9rem;
  font-weight: 700;
  text-decoration: none;
}

.schiri-knopf.hell { background: #dff0e6; border-color: transparent; color: #12402c; }
.schiri-knopf.rot { background: #c0392b; border-color: transparent; color: #fff; }
.schiri-knopf.aktiv { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.schiri-knopf.breit { display: grid; gap: 2px; width: 100%; padding: var(--s3) var(--s4); text-align: left; }
.schiri-knopf.breit small { color: var(--nav-ink-2); font-weight: 400; }

/* Die Ansage: was der Schiedsrichter jetzt sagt. Kursiv und mittig, damit
   sie sich vom Bedienteil abhebt — sie ist Text zum Vorlesen, kein Knopf. */
.schiri-ansage-text {
  color: #fff;
  font-size: clamp(1.1rem, 3vw, 2.1rem);
  font-style: italic;
  font-weight: 700;
  text-align: center;
  text-wrap: balance;
}

/* Der Knopf mit der Ansage (Abschnitt 117, umgestaltet in 121).
   Auf der dunklen Bühne eine **helle, angehobene Fläche** mit dunkler
   Schrift — wie eine Taste, nicht wie ein Hinweiskasten. Die untere Kante
   ist dicker (Schatten ohne Unschärfe), beim Antippen sinkt die Taste um
   genau diese Kante ein. Unten in Gold der Anpfiff „Null beide, bitte
   spielen.“ — der Teil der Ansage, mit dem das Spiel beginnt. */
.schiri-ansageknopf {
  display: grid;
  width: 100%;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: var(--r3, 14px);
  background: #f6f3ea;
  color: #1b221e;
  font: inherit;
  text-align: center;
  cursor: pointer;
  box-shadow: 0 6px 0 #b8a36a, 0 10px 24px rgba(0, 0, 0, 0.45);
  transform: translateY(0);
  transition: transform 80ms ease, box-shadow 80ms ease, background 120ms ease;
}

.schiri-ansageknopf-text {
  padding: var(--s4) var(--s5);
  font-size: clamp(1rem, 2.6vw, 1.7rem);
  font-style: italic;
  font-weight: 700;
  line-height: 1.3;
  text-wrap: balance;
}

.schiri-ansageknopf-tat {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  min-height: 56px;
  padding: var(--s3) var(--s5);
  background: var(--gold-bright, #e2b544);
  color: #1b221e;
  /* Auch die Leiste ist Text zum Vorlesen („Null beide, bitte spielen.“) —
     deshalb in gewöhnlicher Schreibung, nicht in Versalien, und so groß wie
     die Ansage darüber. */
  font-size: clamp(1.1rem, 2.6vw, 1.7rem);
  font-style: italic;
  font-weight: 800;
}

.schiri-ansageknopf:hover,
.schiri-ansageknopf:focus-visible { background: #fffdf6; }

.schiri-ansageknopf:focus-visible {
  outline: 3px solid var(--gold-bright, #e2b544);
  outline-offset: 3px;
}

.schiri-ansageknopf:active {
  transform: translateY(6px);
  box-shadow: 0 0 0 #b8a36a, 0 4px 10px rgba(0, 0, 0, 0.4);
}

.schiri-ansage-text[hidden] { display: none; }

/* Schlussansage und „Spiel beenden“ nebeneinander (Abschnitt 127) —
   **immer**, auch auf Tablet und Telefon. Rutschte der Knopf unter die
   Ansage, nähme er dem Spielfeld eine ganze Zeile Höhe (Auftraggeber,
   24.09.2026). Auf schmalen Bildschirmen werden deshalb Ansage und Knopf
   kleiner, und „Spiel beenden“ darf zweizeilig stehen. */
.schiri-schlussreihe {
  display: flex;
  align-items: center;
  gap: clamp(var(--s3), 2vw, var(--s5));
}

.schiri-schlussreihe .schiri-ansage-text {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  font-size: clamp(0.95rem, 2.6vw, 2.1rem);
}

.schiri-schlussreihe .schiri-knopf {
  flex: 0 0 auto;
  width: clamp(110px, 26vw, 300px);
  min-height: clamp(64px, 11dvh, 110px);
  padding: var(--s3) var(--s4);
  border-radius: var(--r3);
  font-size: clamp(1.05rem, 3vw, 2rem);
  font-weight: 800;
  line-height: 1.15;
  white-space: normal;
}

.schiri-schlussreihe.allein { justify-content: center; }
.schiri-schlussreihe.allein .schiri-knopf { width: min(100%, 520px); }

.schiri-buehne {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  /* Zwei Zeilen: oben die Karten, unten die „+1“-Knöpfe (Abschnitt 71). Das
     Feld reicht über beide — die Knöpfe stehen unten **neben** ihm. */
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: stretch;
  gap: var(--s3);
  /* Das Feld nimmt den Platz, der übrig bleibt — und gibt ihn auch wieder
     her, wenn ein Fenster darüber liegt. */
  flex: 1 1 auto;
  min-height: 0;
}

.schiri-buehne > .schiri-karten-spalte.links { grid-area: 1 / 1; }
.schiri-buehne > .schiri-plus.links { grid-area: 2 / 1; }
.schiri-buehne > .schiri-feld { grid-area: 1 / 2 / 3 / 3; }
.schiri-buehne > .schiri-karten-spalte.rechts { grid-area: 1 / 3; }
.schiri-buehne > .schiri-plus.rechts { grid-area: 2 / 3; }

/* „+1“ — ein Punkt für die Seite, unter deren Hälfte er steht (Abschnitt 71).
   Bis dahin war die ganze Spielfeldhälfte der Knopf. Groß und quadratisch,
   in der hellen Farbe der übrigen Hauptknöpfe, damit er auf dem dunklen Grund
   ohne Suchen getroffen wird. */
.schiri-plus {
  align-self: end;
  display: grid;
  place-items: center;
  /* Ein Drittel größer als im ersten Entwurf (84–150 px) — Wunsch des
     Auftraggebers vom 13.09.2026. */
  width: clamp(112px, 14.5vw, 200px);
  aspect-ratio: 1;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--r2);
  background: #dff0e6;
  color: #12402c;
  font-size: clamp(2.6rem, 6.6vw, 4.8rem);
  font-weight: 800;
  line-height: 1;
  touch-action: manipulation;
  transition: opacity 0.15s ease, filter 0.15s ease;
}

.schiri-plus:active:not(:disabled) { transform: scale(0.96); }

/* Während der Sperrzeit nach einem Tipp (Abschnitt 96): grau, und ohne das
   Einsinken beim Drücken — ein Knopf, der gerade nichts annimmt, soll auch
   nicht so tun. Etwas heller als „entschieden“ (:disabled), damit beides
   auseinanderzuhalten bleibt. */
.schiri-plus.abkuehlend {
  filter: grayscale(1);
  opacity: 0.45;
}

.schiri-plus.abkuehlend:active { transform: none; }
/* Gesperrt, sobald das Spiel entschieden ist (Abschnitt 67) — der Server
   nähme keinen Punkt mehr an. */
.schiri-plus:disabled { opacity: 0.35; }

.schiri-karten-spalte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  padding-top: var(--s2);
}

/* Gelb, Rot und Schwarz sind im Regelwerk festgelegt — die eine Stelle im
   Projekt, an der die Farbe selbst die Bedeutung trägt. Deshalb tragen die
   Knöpfe eine Beschriftung für Screenreader (aria-label). */
.schiri-kartenknopf {
  width: 40px;
  height: 56px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--r1);
}

.schiri-kartenknopf.gelb { background: #f2c94c; }
.schiri-kartenknopf.rot { background: #c0392b; }
.schiri-kartenknopf.schwarz { background: #101010; }
.schiri-kartenknopf:active { transform: scale(0.95); }

.schiri-kartenzahl {
  padding: 1px var(--s2);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.16);
  font-size: 0.75rem;
  font-weight: 800;
}

/* Handy, hochkant: Die Karten stehen **über** den Feldhälften.
 *
 * Seitlich kosten sie zweimal rund 50 px — auf 360 px ist das ein Drittel der
 * Breite, und die fehlt dem Feld: Lange Doppelnamen quetschen sich dann in
 * einen halben Kasten. Über den Hälften steht dieselbe Reihe waagerecht, das
 * Feld bekommt die ganze Breite, und die Zuordnung bleibt: Die linke Reihe
 * gehört zur linken Hälfte.
 *
 * Nur hier. Am Turniertisch und auf dem Tablet ist die Breite da, und seitlich
 * liegen die Karten näher an der Hand, die ohnehin auf der Feldhälfte tippt.
 *
 * Umgestellt wird allein über das Raster — die Reihenfolge im Dokument bleibt
 * „links, Feld, rechts“, damit die Tabulatorreihenfolge und das Vorlesen dem
 * Feld folgen und nicht dem Bildschirm. */
@media (max-width: 560px) and (orientation: portrait) {
  .schiri-buehne {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: var(--s2);
  }

  .schiri-buehne > .schiri-karten-spalte.links { grid-area: 1 / 1; }
  .schiri-buehne > .schiri-karten-spalte.rechts { grid-area: 1 / 2; }
  .schiri-buehne > .schiri-feld { grid-area: 2 / 1 / 3 / 3; }

  /* Die „+1“-Knöpfe hier **unter** dem Feld, je halbe Breite: Seitlich nähmen
     sie dem Feld auf 360 px ein Drittel. Links bleibt links. */
  .schiri-buehne > .schiri-plus.links { grid-area: 3 / 1; }
  .schiri-buehne > .schiri-plus.rechts { grid-area: 3 / 2; }
  .schiri-plus { width: 100%; aspect-ratio: auto; min-height: 76px; }

  .schiri-karten-spalte {
    flex-direction: row;
    justify-content: center;
    padding-top: 0;
  }

  /* Waagerecht liegend braucht eine Karte nicht die Höhe einer stehenden. */
  .schiri-kartenknopf { width: 44px; height: 44px; }
}

/* Das Spielfeld. Zwei Hälften, dazwischen das Netz als gestrichelte Linie. */
.schiri-feld {
  /* Bezugsrahmen für den Aufschlagpfeil (Abschnitt 73). */
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4px minmax(0, 1fr);
  min-height: clamp(220px, 42vh, 520px);
  border: 2px solid var(--gold);
  border-radius: var(--r2);
  background: #0e1a13;
  overflow: hidden;
}

.schiri-netz {
  background: repeating-linear-gradient(
    to bottom, var(--gold-bright) 0 8px, transparent 8px 16px
  );
}

/* Der goldene Pfeil vom Aufschläger zum Rückschläger (Abschnitt 73). Über den
   Hälften, unter der Punktzahl (z-index 2), und ohne Tippfläche. Die
   Koordinaten stehen in Prozent ohne viewBox — so bleibt die Spitze auf jedem
   Seitenverhältnis unverzerrt. Der Schatten hält ihn auf dem goldenen Grund
   der hervorgehobenen Felder sichtbar. */
.schiri-pfeil {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  color: var(--gold-bright);
  pointer-events: none;
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.75));
}

.schiri-pfeil line {
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
}

/* Eine Spielfeldhälfte — seit Abschnitt 71 nur noch Anzeige. Gezählt wird
   über die „+1“-Knöpfe daneben. */
.schiri-haelfte {
  position: relative;
  display: grid;
  align-items: stretch;
  padding: var(--s3);
  background: transparent;
  color: #fff;
  text-align: left;
}

/* Wie vorher die gesperrte Taste: entschieden oder beendet — gedämpft. */
.schiri-haelfte.gesperrt { opacity: 0.6; }

/* Die Punktzahl steht außen — links am linken Rand, rechts am rechten. */
.schiri-punktzahl {
  position: absolute;
  top: 50%;
  z-index: 2;
  font-size: clamp(3rem, 11vw, 9rem);
  font-weight: 800;
  line-height: 1;
  transform: translateY(-50%);
  pointer-events: none;
}

.schiri-haelfte.links .schiri-punktzahl { left: var(--s4); }
.schiri-haelfte.rechts .schiri-punktzahl { right: var(--s4); }

.schiri-boxen {
  display: grid;
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
  width: 100%;
}

.schiri-aufschlagfeld {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 2px;
  padding: var(--s3);
  border: 1px dashed rgba(255, 255, 255, 0.22);
  border-radius: var(--r1);
  text-align: center;
}

/* `justify-items: center` misst die Kinder an ihrem Inhalt und nicht an der
   Spalte — ohne diese Schranke wird der Kasten von einem langen Namen
   auseinandergedrückt, statt ihn umzubrechen. */
.schiri-aufschlagfeld > * { max-width: 100%; }

/* Das Feld, in dem gerade jemand steht — flächig, damit es aus dem
   Augenwinkel erkennbar ist. */
.schiri-aufschlagfeld.belegt {
  border-style: solid;
  border-color: var(--gold);
  background: rgba(217, 168, 60, 0.2);
}

/* Im Doppel: das Feld des Partners (UEBERGABE.md, Abschnitt 65). Jemand steht
   darin, aber er ist beim nächsten Ballwechsel weder Aufschläger noch
   Annehmender — deshalb durchgezogen umrandet, aber ohne Gold. Leuchteten alle
   vier Felder, fände das Auge den Aufschläger nicht mehr. */
.schiri-aufschlagfeld.besetzt {
  border-style: solid;
  border-color: rgba(255, 255, 255, 0.28);
}

/* Gold gehört allein dem Aufschläger (Abschnitt 122): Die Beschriftung
   „Rückschlag“ im Feld des Annehmenden steht deshalb hell, nicht golden. */
.schiri-aufschlagfeld.besetzt small { color: var(--nav-ink); }

/* „Spiel beenden“ (UEBERGABE.md, Abschnitt 67): Solange er nicht gedrückt
   ist, bleibt das Feld belegt. Deshalb pulsiert er — ein roter Knopf unter
   anderen roten Knöpfen fiele sonst nicht auf. Wer Bewegung abgeschaltet hat,
   bekommt ihn ruhig, aber mit kräftigem Rand. */
@keyframes schiri-pulsieren {
  0%, 100% { box-shadow: 0 0 0 0 rgba(169, 55, 50, 0.7); }
  50%      { box-shadow: 0 0 0 10px rgba(169, 55, 50, 0); }
}

.schiri-knopf.pulsiert {
  animation: schiri-pulsieren 1.4s ease-in-out infinite;
  font-weight: 800;
}

/* Die Marke in den gesperrten Spielfeldhälften, solange das Spiel entschieden,
   aber noch nicht beendet ist. Unten mittig, damit sie weder Punktzahl noch
   Aufschlagfelder verdeckt. */
.schiri-entschieden {
  position: absolute;
  left: 50%;
  bottom: var(--s3);
  transform: translateX(-50%);
  padding: 2px var(--s3);
  border-radius: var(--r-pill);
  background: rgba(169, 55, 50, 0.85);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .schiri-knopf.pulsiert {
    animation: none;
    outline: 3px solid var(--gold-bright);
    outline-offset: 2px;
  }
}

.schiri-aufschlagfeld b {
  font-size: clamp(0.95rem, 2vw, 1.5rem);
  overflow-wrap: anywhere;
}

.schiri-aufschlagfeld small {
  color: var(--gold-bright);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.schiri-zusatzknopf {
  width: 100%;
  min-height: var(--touch);
  border-radius: var(--r2);
  background: #dff0e6;
  color: #12402c;
  font-size: 1rem;
  font-weight: 800;
}

/* --- Fenster über dem Feld ------------------------------------------------
   Einrichtung, Zusatzfunktionen, Sonderfall und die Timeline liegen **über**
   dem Feld, sie klappen nichts auf. Ein Bereich, der sich unten öffnet,
   schiebt das Spielfeld zusammen — und das Spielfeld ist hier die
   Bedienfläche: Wer danach einen Punkt eintragen will, trifft woanders hin.
   -------------------------------------------------------------------------- */

.schiri-huelle {
  position: fixed;
  inset: 0;
  z-index: 85;
  display: grid;
  place-items: center;
  padding: var(--s4);
  background: rgba(6, 12, 9, 0.72);
  /* Noch einmal am Dialog selbst: Die einfache Zählansicht (werten.js) setzt
     ihn außerhalb der Schiedsrichteransicht ein, und dort gälte die Angabe
     von oben nicht. */
  touch-action: manipulation;
}

/* Der Einrichtungsdialog lässt sich nicht wegtippen: Ohne Aufstellung fehlt
   dem Schiedsrichterzettel der Anfang, und der lässt sich später nicht
   nachtragen. */
.schiri-huelle.fest { background: rgba(6, 12, 9, 0.88); }

/* Die Kartenfrage im Doppel (Abschnitt 91): oben die beiden Spieler gleich
   breit nebeneinander, darunter „Abbrechen“ über die ganze Breite. Der Dialog
   hängt am Seitenkörper und nicht in der Schiedsrichteransicht — deshalb steht
   das Doppeltippen hier noch einmal (Abschnitt 84). */
.schiri-kartendialog { touch-action: manipulation; }

.schiri-kartenwahl {
  display: grid;
  gap: var(--s3);
}

.schiri-kartenwahl-spieler {
  display: flex;
  gap: var(--s3);
}

/* `flex: 1 1 0` teilt die Breite gleich auf — unabhängig davon, wie lang die
   Namen sind. Ein langer Name bricht im eigenen Knopf um, statt den anderen
   schmal zu drücken. */
.schiri-kartenwahl-spieler .knopf {
  flex: 1 1 0;
  min-width: 0;
  min-height: 56px;
  white-space: normal;
  overflow-wrap: break-word;
  text-align: center;
}

.schiri-kartenwahl-abbrechen {
  width: 100%;
  min-height: 52px;
}

.schiri-fenster {
  position: relative;
  display: grid;
  gap: var(--s4);
  width: min(560px, 100%);
  max-height: 88dvh;
  padding: var(--s6);
  border-radius: var(--r3);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--sh3);
  overflow-y: auto;
}

.schiri-fenster h2 { font-size: 1.1rem; }
.schiri-fenster h3 { margin-top: var(--s2); font-size: 0.9rem; color: var(--ink-2); }
.schiri-fenster p { color: var(--ink-2); font-size: 0.9rem; }

.schiri-fenster-zu {
  position: absolute;
  top: var(--s3);
  right: var(--s3);
  display: grid;
  place-items: center;
  width: var(--touch);
  height: var(--touch);
  border-radius: var(--r-pill);
  color: var(--ink-3);
  font-size: 1.4rem;
  line-height: 1;
}

/* „↺ Zurück“ in den festen Fenstern (Abschnitt 77). Im Fluss und nicht
   übergelegt: Oben rechts neben einer langen Überschrift überdeckte ein
   absolut gesetzter Knopf sonst die letzten Wörter. */
.schiri-fenster-zurueck {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  min-height: 40px;
  padding: 0 var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 0.9rem;
  font-weight: 700;
}

.schiri-fenster-zurueck:disabled { opacity: 0.4; }

.schiri-fenster-notiz {
  padding: var(--s2) var(--s3);
  border-left: 3px solid var(--gold);
  border-radius: var(--r1);
  background: var(--surface-2);
  font-size: 0.85rem;
}

/* Der Hinweis auf eine Disqualifikation (UEBERGABE.md, Abschnitt 24.7).
   In Warnfarbe und ganz oben, aber ohne jede Sperre darunter: Er soll gelesen
   und nicht weggeklickt werden. */
.schiri-warnung {
  margin-bottom: var(--s4);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--warn);
  border-radius: var(--r2);
  background: var(--warn-soft);
  color: var(--warn);
}

.schiri-warnung p { margin: 0; font-size: 0.92rem; line-height: 1.45; }
.schiri-warnung p + p { margin-top: var(--s2); }

.schiri-fenster .schiri-knopf {
  border-color: var(--line-2);
  background: var(--surface-2);
  color: var(--ink-2);
}

.schiri-fenster .schiri-knopf.hell { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.schiri-fenster .schiri-knopf.rot { background: var(--danger); border-color: var(--danger); color: var(--on-danger); }
.schiri-fenster .schiri-knopf.breit { width: 100%; }

/* Die großen Wahlflächen des Einrichtungsdialogs. Groß, weil sie im Stehen
   getroffen werden, und zweizeilig, weil unter der Frage die Antwort steht. */
.schiri-wahlraster {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s3);
}

.schiri-grosswahl {
  display: grid;
  gap: 2px;
  min-height: 64px;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r2);
  background: var(--surface);
  text-align: left;
}

/* Alle Spieler nebeneinander — die eine Frage „Wer schlägt auf?“.
   Nebeneinander schon bei 360 px: Vier untereinander schöben die nächste
   Frage („Wer nimmt an?“) aus dem Bild.

   Die Spaltenzahl richtet sich nach der Zahl der Knöpfe und nicht nach dem
   Platz: Zwei füllen die Zeile, vier stehen paarweise — im Doppel gehören je
   zwei zusammen, und ein Umbruch drei zu eins stellte sie durcheinander. Erst
   ab 720 px stehen alle vier in einer Reihe. */
.schiri-wahlraster.spieler-2,
.schiri-wahlraster.spieler-4 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}

@media (min-width: 720px) {
  .schiri-wahlraster.spieler-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.schiri-grosswahl span {
  color: var(--ink-3);
  font-size: 0.78rem;
  overflow-wrap: anywhere;
}
.schiri-grosswahl strong { font-size: 1rem; overflow-wrap: anywhere; }
.schiri-grosswahl.gewaehlt { border-color: var(--brand); background: var(--brand-soft); }
.schiri-grosswahl.gewaehlt strong { color: var(--brand-ink); }

.schiri-spielerwahl { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* --- Die Wahlflächen im Eröffnungsfenster, groß (Abschnitt 120) ----------
   Auftraggeber, 24.09.2026: Die Knöpfe sollen auf Tablet und Telefon klar
   als Auswahl erkennbar sein und den Platz ausnutzen. Nur im **festen**
   Fenster (Eröffnung, Übernahme, Stellung nach einer Korrektur) — dort ist
   die Wahl das Einzige, was zu tun ist. Die Fenster unter „Weiteres“
   bleiben, wie sie sind.

   Das Fenster wird breiter (bis 1100 px), die Flächen hoch und die Namen
   groß. Ein kräftiger Rand, ein Schatten und ein Druckeffekt machen aus
   einer Fläche mit Text sichtbar einen Knopf. */
.schiri-huelle.fest .schiri-fenster {
  width: min(1100px, 100%);
  max-height: 94dvh;
  padding: clamp(var(--s4), 3vw, var(--s6));
}

.schiri-huelle.fest .schiri-fenster h2 { font-size: clamp(1.2rem, 2.6vw, 1.6rem); }
.schiri-huelle.fest .schiri-fenster h3 {
  font-size: clamp(1rem, 2.2vw, 1.3rem);
  color: var(--ink);
}

/* Zwei Wahlen (rechte Seite, Münzwurf, Rückschläger) stehen nebeneinander,
   wo Platz ist; am schmalen Telefon untereinander, damit die Namen groß
   bleiben dürfen. */
.schiri-huelle.fest .schiri-wahlraster {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: clamp(var(--s2), 1.6vw, var(--s4));
}

.schiri-huelle.fest .schiri-wahlraster.spieler-2,
.schiri-huelle.fest .schiri-wahlraster.spieler-4 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 900px) {
  .schiri-huelle.fest .schiri-wahlraster.spieler-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.schiri-huelle.fest .schiri-grosswahl {
  align-content: center;
  gap: var(--s1, 4px);
  min-height: clamp(110px, 20dvh, 200px);
  padding: clamp(var(--s3), 2vw, var(--s5)) clamp(var(--s3), 2vw, var(--s5));
  border: 3px solid var(--line-2);
  border-radius: var(--r3);
  background: var(--surface-2, var(--surface));
  box-shadow: 0 3px 0 var(--line-2), var(--sh1, 0 1px 3px rgba(0, 0, 0, 0.12));
  text-align: center;
  cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease, border-color 120ms ease;
}

.schiri-huelle.fest .schiri-grosswahl span {
  font-size: clamp(0.85rem, 1.8vw, 1.05rem);
}

.schiri-huelle.fest .schiri-grosswahl strong {
  font-size: clamp(1.35rem, 3.4vw, 2.1rem);
  line-height: 1.15;
  overflow-wrap: normal;
  word-break: normal;
  hyphens: auto;
}

.schiri-huelle.fest .schiri-grosswahl:hover { border-color: var(--brand); }

.schiri-huelle.fest .schiri-grosswahl:active {
  transform: translateY(3px);
  box-shadow: 0 0 0 var(--line-2);
}

.schiri-huelle.fest .schiri-grosswahl.gewaehlt {
  border-color: var(--brand);
  background: var(--brand-soft);
  box-shadow: 0 3px 0 var(--brand);
}

/* Auch der Ersatzknopf „Aufstellung übernehmen“ und „Steuerung übernehmen“
   bekommen die Höhe der Wahlflächen. */
.schiri-huelle.fest .schiri-knopf.breit {
  min-height: clamp(72px, 12dvh, 120px);
  justify-content: center;
  text-align: center;
  font-size: clamp(1.1rem, 2.6vw, 1.5rem);
}

.schiri-spielerwahl button {
  min-height: var(--touch);
  padding: 0 var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.9rem;
  font-weight: 650;
}

.schiri-spielerwahl button.gewaehlt {
  border-color: var(--brand);
  background: var(--brand);
  color: var(--on-brand);
}

/* Die Eröffnungsansage wird vorgelesen — deshalb groß und ruhig gesetzt. */
.schiri-eroeffnung {
  margin: 0;
  padding: var(--s4);
  border-left: 3px solid var(--gold);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 1.02rem;
  font-style: italic;
  line-height: 1.5;
}

.schiri-zusatzraster {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s2);
}

.schiri-zusatzraster .schiri-knopf { width: 100%; }

.schiri-korrektur { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s4); }

.schiri-uhr {
  display: block;
  color: var(--ink);
  font-family: var(--font-num);
  font-size: 2.6rem;
  font-weight: 800;
  text-align: center;
}

.schiri-zusammenfassung {
  margin: 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink-2);
  font-family: var(--font);
  font-size: 0.86rem;
  white-space: pre-wrap;
}

/* Die Folge der Sieger-Auswahl im Sonderfall: wer damit ausscheidet.
   Bewusst auffällig und dicht an der Auswahl — hier fällt auf, wenn jemand
   die falsche Seite erwischt hat, und danach fragt keine Runde mehr nach. */
.sonderfall-folge {
  margin: 0;
  padding: var(--s3) var(--s4);
  border-left: 3px solid var(--warn);
  border-radius: var(--r1);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 0.95rem;
}

.sonderfall-folge strong { font-weight: 800; }
.sonderfall-folge[hidden] { display: none; }

/* Die Karten eines Spielers, klein hinter seinem Namen. */
.schiri-kartenmarken { display: inline-flex; gap: 3px; margin-left: var(--s2); }

.schiri-kartenmarke {
  display: inline-block;
  width: 9px;
  height: 13px;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 2px;
  vertical-align: middle;
}

.schiri-kartenmarke.gelb { background: #f2c94c; }
.schiri-kartenmarke.rot { background: #c0392b; }
.schiri-kartenmarke.schwarz { background: #101010; }

/* Im Doppel steht jeder Name für sich, damit die Karte hinter **seinem**
   Namen sitzen kann. Zusammen sehen sie aus wie bisher — „Meier/Schulz“ —,
   nur dass der Trennstrich ein eigenes Zeichen ist und keine Zeichenkette.

   **Ein Name bricht, bevor er übersteht.** Vorher stand hier `nowrap`: Ein
   langer Name lief dann über den Rand des Aufschlagfelds hinaus, quer über
   die Mittellinie. Der Umbruch trennt zwar einen Namen, aber er trennt ihn
   sichtbar — ein abgeschnittener Name sieht aus wie ein anderer Name. */
.schiri-spielername { overflow-wrap: anywhere; }

.schiri-namenstrenner {
  margin: 0 0.15em;
  color: var(--nav-ink-2);
  font-weight: 400;
}

.schiri-protokoll {
  display: grid;
  gap: var(--s1);
  max-height: 46dvh;
  margin: 0;
  padding: var(--s3);
  border-radius: var(--r2);
  background: var(--surface-2);
  list-style: none;
  overflow-y: auto;
  font-size: 0.82rem;
}

.schiri-protokoll li {
  display: grid;
  grid-template-columns: 3.4em minmax(0, 1fr);
  gap: var(--s3);
  padding: 2px 0;
  border-bottom: 1px solid var(--line);
}

.schiri-zeit { color: var(--ink-3); font-family: var(--font-num); }
.schiri-leer { color: var(--ink-3); font-size: 0.85rem; }


/* --- 12  Breitere Geräte -------------------------------------------------- */

@media (min-width: 600px) {
  .schiri-formular { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .schiri-formular .reihe { grid-column: 1 / -1; }
  .tb-feldpaar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tb-vierfach { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .feldraster { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
  .tb-zahlenraster { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .gruppenraster { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
  .zaehlname { font-size: 1.25rem; }
  /* Die mittlere Spalte hat eine **Untergrenze**. Mit `minmax(0, 1fr)` durfte
     sie auf null schrumpfen, und genau das tat sie: Ist das Modul Ansagen
     freigeschaltet, stehen rechts Pfeile, Feldwahl, „Aufrufen“ und fünf
     Ansageknöpfe. Die inhaltsbestimmte dritte Spalte forderte über 500 Pixel,
     die Paarung bekam null — die Namen lagen übereinander und über dem
     „gegen“. Die Namen sind der Inhalt der Zeile; die Knöpfe dürfen
     umbrechen, sie können es (`flex-wrap`). */
  .callboardeintrag { grid-template-columns: auto minmax(12rem, 1fr) auto; }
  .callboard-aktionen { grid-column: auto; justify-content: flex-end; }
}

/* Ab hier stehen Liste und Einzelheiten nebeneinander. Der Turnierleiter
   springt dann nicht mehr hin und her (ARCHITEKTUR.md, Abschnitt 1). */
@media (min-width: 1000px) {
  .tb-zweispalt { grid-template-columns: minmax(300px, 380px) minmax(0, 1fr); }

  .tb-liste {
    position: sticky;
    top: var(--s5);
    max-height: calc(100dvh - 2 * var(--s6));
    overflow-y: auto;
    padding-right: var(--s2);
  }

  .tb-vierfach { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* Höhere Dichte: mehr Zeilen auf einen Blick. */
  .tb-tabelle { font-size: 0.86rem; }
  .tb-tabelle td { padding: var(--s2) var(--s3); }
  .tb-karte { padding: var(--s3) var(--s4); }

  .zaehlnamen { gap: var(--s4); padding: var(--s4) var(--s4) 0; }
  .zaehlfeld { gap: var(--s4); padding: var(--s4); }
  .punktflaeche { min-height: 220px; }
  .punktzahl { font-size: clamp(5rem, 14vw, 11rem); }
}

@media (min-width: 1400px) {
  .tb-zweispalt { grid-template-columns: minmax(320px, 420px) minmax(0, 1fr); }
  .baumrunde { min-width: 220px; }
}

/* Fingerbedient heißt große Flächen — unabhängig von der Breite.
   Ein Tablet im Querformat ist breit *und* fingerbedient
   (UEBERGABE.md, Abschnitt 5). */
@media (pointer: coarse) {
  .reiter { min-height: var(--touch); }
  .callboard-feldwahl,
  .baum-feldwahl { min-height: var(--touch); }
  .setzzeile input { min-height: var(--touch); }
  .tb-zeilenaktionen .knopf.klein { min-height: var(--touch); }
}

/* ---------------------------------------------------------------------------
   Feld-Schnellsprung mit Sprechblase
   Am Turniertisch wird nach dem Feld gefragt, nicht nach dem Listenplatz.
   Die Knopfreihe führt zur Karte, die Blase beantwortet „wer spielt da?“
   auch ohne Sprung.
   --------------------------------------------------------------------------- */

.feldsprung {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-bottom: var(--s3);
}

.feldsprung-knopf {
  position: relative;
  min-width: 44px;            /* Trefferfläche, auch am Feldrand mit dem Daumen */
  min-height: 44px;
  padding: 0 var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.feldsprung-knopf:hover { background: var(--surface-3); }

/* Der Zustand des Spiels färbt den linken Rand — dieselbe Sprache wie in der
   Kartenliste, damit man nicht zweimal lernen muss, was „läuft“ bedeutet. */
.feldsprung-knopf.laeuft         { border-left: 4px solid var(--st-live); }
.feldsprung-knopf.pausiert       { border-left: 4px solid var(--warn); }
.feldsprung-knopf.freigeschaltet { border-left: 4px solid var(--ink-3); }

/* Die Blase ------------------------------------------------------------- */
/* Sie hängt am Seitenkörper, nicht im Knopf: Die Spielliste scrollt, und
   alles darin wird an ihrer Kante abgeschnitten. Platziert wird sie von
   `blaseZeigen()` in spiele.js. */

.schnellblick {
  position: fixed;
  z-index: 60;
  display: grid;
  gap: 2px;
  width: max-content;
  max-width: min(280px, calc(100vw - 32px));
  padding: var(--s2) var(--s3);
  border-radius: var(--r2);
  background: var(--ink);
  color: var(--surface);
  font-size: 13px;
  line-height: 1.35;
  text-align: left;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
  pointer-events: none;
}

.schnellblick[hidden] { display: none; }
.schnellblick strong { font-weight: 700; }
.schnellblick-paarung { font-weight: 600; }
.schnellblick-stand { font-size: 15px; font-weight: 700; }

/* Das Aufblinken nach dem Sprung ---------------------------------------- */

.spielkarte.springziel {
  animation: springziel-puls 1.6s ease-in-out 2;
}

@keyframes springziel-puls {
  0%, 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); border-color: var(--line); }
  35%      { box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.55); border-color: #f59e0b; }
  70%      { box-shadow: 0 0 0 8px rgba(245, 158, 11, 0);    border-color: #fbbf24; }
}

/* Wer weniger Bewegung eingestellt hat, bekommt keinen Puls, sondern einen
   ruhigen Rahmen — die Auskunft „diese Karte ist gemeint“ bleibt erhalten. */
@media (prefers-reduced-motion: reduce) {
  .spielkarte.springziel {
    animation: none;
    border-color: #f59e0b;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.45);
  }
  .schnellblick { transition: none; }
}

/* Berührungsgeräte haben kein Überfahren: Dort würde die Blase beim Antippen
   kurz aufblitzen und mitscrollen. Sie bleibt deshalb aus — getippt wird
   gesprungen, und das ist die schnellere Antwort. */
@media (hover: none) {
  .schnellblick { display: none; }
}

/* --- 11c  Fenster der einfachen Zählansicht -------------------------------
   Sonderfall und Satzkorrektur benutzen dieselben Kästen wie die
   Schiedsrichter-Steuerung (`.schiri-huelle`, `.schiri-fenster`) — es ist
   dasselbe Fenster mit demselben Zweck, nur an einer anderen Ansicht.
   ------------------------------------------------------------------------- */

.zaehl-korrekturliste { display: grid; gap: var(--s2); }

.zaehl-korrekturzeile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.zaehl-korrekturzeile strong { font-size: 0.85rem; }
.zaehl-korrekturzeile input { min-width: 0; text-align: center; }

/* Ein Satz, der noch nicht gespielt wurde, steht blasser da — er lässt sich
   eintragen, ist aber selten gemeint. */
.zaehl-korrekturzeile.kuenftig { opacity: 0.6; }

/* --- 11d  Einspielzeit ----------------------------------------------------
   Der Zwischenschritt vor dem ersten Ballwechsel. Aufgebaut wie die
   Warteansicht am Feld: eine Karte in der Mitte, große Flächen, nichts
   daneben — wer hier steht, hat das Tablet in der Hand und schaut nicht auf
   Kleingedrucktes.
   ------------------------------------------------------------------------- */

.zaehlansicht.einspielen { grid-template-rows: auto minmax(0, 1fr); }

.einspielkarte {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--s4);
  width: min(460px, 100%);
  margin: 0 auto;
  padding: var(--s6);
  text-align: center;
}

.einspielkarte h1 { font-size: 1.4rem; }
.einspielkarte .stapel { width: 100%; }

.einspieluhr {
  font-size: clamp(3.5rem, 18vw, 6rem);
  font-weight: 800;
  line-height: 1;
  color: var(--gold-ink);
}

/* Der Zwischenschirm nach einem Satz — dieselbe Karte wie bei der
   Einspielzeit, nur mit dem Satzergebnis statt der Uhr. */
.zaehlansicht.satzwechsel { grid-template-rows: auto minmax(0, 1fr); }

.satzwechsel-stand {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  font-size: clamp(3rem, 16vw, 5.5rem);
  font-weight: 800;
  line-height: 1;
}

.satzwechsel-stand span { color: var(--ink-3); font-size: 0.5em; }

/* Die drei Aufrufstufen am Callboard stehen zusammen — sie gehören zu einer
   Sache, und der Abstand zu „Aufrufen“ daneben soll größer sein als der
   zwischen ihnen. Sonst greift man am Turniertisch daneben. */
.callboard-ansagen {
  display: inline-flex;
  gap: 2px;
}

/* Die drei Aufrufstufen am Spiel: „1 2 3“ eng beieinander, mit einer kleinen
   Beschriftung davor. Ohne sie wären drei nackte Ziffern zwischen „Beenden“
   und „Löschen“ ein Rätsel — mit ihr braucht es kein größeres Bedienelement. */
.tb-ansagestufen {
  display: inline-flex;
  gap: 2px;
  align-items: center;
}

.tb-ansagestufen small {
  margin-right: var(--s2);
  color: var(--ink-3);
  font-size: 0.8rem;
}

.tb-ansagestufen .knopf {
  min-width: 2.2rem;
  padding-inline: var(--s2);
}

/* ---------------------------------------------------------------------------
   Spielbot — sichtbar anders als die übrigen Kästen
   Er ist ein Werkzeug für den Prüfstand. Auf einem Schirm, auf dem gerade ein
   echtes Turnier läuft, soll er nicht wie eine gewöhnliche Bedienung wirken —
   deshalb der gestrichelte Rand statt des vollen.
   --------------------------------------------------------------------------- */

.tb-bot {
  border-style: dashed;
  border-width: 2px;
}

.tb-bot.laeuft { border-color: var(--brand); }

/* Eine Konkurrenz, die nicht gemeldet wird. Zurückgenommen und nicht
   durchgestrichen: Es ist kein Fehler, sondern eine Entscheidung. */
.rl-draussen { opacity: 0.6; }

/* ---------------------------------------------------------------------------
   Wahlkästen — zwei bis vier Möglichkeiten mit Erklärung
   Für Entscheidungen, bei denen die Aufschrift allein nicht reicht. Ein
   Auswahlfeld mit vier Zeilen Text wäre unlesbar; nebeneinander stehende
   Kästen zeigen die Möglichkeiten samt ihrer Folge.
   --------------------------------------------------------------------------- */

.tb-wahlgruppe {
  margin: var(--s4) 0 0;
  padding: 0;
  border: 0;
  display: grid;
  gap: var(--s2);
}

.tb-wahlgruppe legend {
  padding: 0;
  margin-bottom: var(--s2);
  font-size: 0.9rem;
  font-weight: 650;
  color: var(--ink-2);
}

.tb-wahlkasten {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
  cursor: pointer;
}

.tb-wahlkasten:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-soft, var(--surface-2));
}

.tb-wahlkasten input { margin-top: 3px; flex: 0 0 auto; }

.tb-wahlkasten strong { display: block; }

.tb-wahlkasten small {
  display: block;
  margin-top: 2px;
  color: var(--ink-3);
  line-height: 1.4;
}

/* ---------------------------------------------------------------------------
   Schalter mit Info-i
   Für Einstellungen, die mehr Erklärung brauchen als ihre Aufschrift. Das i
   klappt sie darunter auf statt sie in eine Sprechblase zu legen: Drei Absätze
   in einer Blase, die beim Wegschauen zugeht, liest niemand zu Ende.
   --------------------------------------------------------------------------- */

.tb-schalterzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.tb-schalter {
  display: flex;
  align-items: center;
  gap: var(--s3);
  cursor: pointer;
  min-width: 0;
}

/* Das Kästchen selbst verschwindet, der Schieber daneben übernimmt seine
   Rolle — sichtbar, aber weiterhin mit der Tastatur bedienbar. */
.tb-schalter input { position: absolute; opacity: 0; width: 0; height: 0; }

.tb-schieber {
  flex: 0 0 auto;
  width: 44px; height: 26px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  border: 1px solid var(--line);
  position: relative;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.tb-schieber::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
  transition: transform 0.15s ease;
}

.tb-schalter input:checked + .tb-schieber {
  background: var(--brand);
  border-color: var(--brand);
}

.tb-schalter input:checked + .tb-schieber::after { transform: translateX(18px); }

.tb-schalter input:focus-visible + .tb-schieber {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.tb-info {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  font-weight: 800;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
}

.tb-info:hover { background: var(--surface-3); color: var(--ink); }

.tb-info[aria-expanded="true"] {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

/* ---------------------------------------------------------------------------
   Nächste Spiele — der Kopf des Callboards
   Was gespielt werden könnte, über dem, was gespielt werden soll. Die Zeilen
   sind absichtlich schmaler als die Vormerkungen: Hier wird ausgewählt, nicht
   gearbeitet.
   --------------------------------------------------------------------------- */

.cb-naechste .kartenliste { gap: var(--s2); }

.cb-naechste .tb-karte {
  padding-block: var(--s2);
}

/* Die Paarung steht hier **links** und nicht um ein Mittelstück herum wie in
   der Vormerkliste. Dort ist sie der Inhalt einer schmalen Karte und trägt
   sich selbst; hier läuft die Zeile über die ganze Breite, und eine mittig
   ausgerichtete Paarung schwämme neben einer linksbündigen Kopfzeile und
   einem linksbündigen Knopf. Gelesen wird sie ohnehin von links. */
.cb-naechste .paarung {
  grid-template-columns: auto auto auto;
  justify-content: start;
}

.cb-naechste .paarung > span:first-child { text-align: left; }

/* Die Bremse sitzt hier unter der Paarung und nicht darüber wie in der
   Vormerkliste: Oben zählt zuerst, wer spielt — die Pause ist der Zusatz. */
.cb-naechste .cb-bremse {
  margin-block: var(--s2) 0;
}

.cb-naechste .tb-karte.gebremst { opacity: 0.92; }

/* ---------------------------------------------------------------------------
   Pausenanzeige im Callboard
   Eine Partie kann spielbereit sein und trotzdem nicht dran — weil einer der
   beiden gerade erst fertig wurde. Der Ring läuft entgegen dem Uhrzeigersinn
   leer (UEBERGABE.md, Abschnitt 18).
   --------------------------------------------------------------------------- */

.callboardeintrag.gebremst { opacity: 0.92; }

.cb-bremse {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s2);
  padding: 4px var(--s2) 4px 4px;
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 600;
  width: fit-content;
}

.cb-bremse.pause  { background: var(--warn-soft);  color: var(--warn); }
.cb-bremse.spielt { background: var(--st-live-soft); color: var(--st-live); padding-left: var(--s2); }
/* Die Startzeit der Konkurrenz. Gedämpft wie ein Hinweis und nicht wie eine
   Warnung: Die Partie ist in Ordnung, sie ist nur noch nicht dran. */
.cb-bremse.startzeit { background: var(--surface-3); color: var(--ink-2); padding-left: var(--s2); }

/* Ist die Pause abgelaufen, bevor der Server es bestätigt hat, wird die
   Marke grün — der Turnierleiter soll nicht auf den nächsten Abruf warten. */
.cb-bremse.pause.frei { background: var(--brand); color: #fff; }
.cb-bremse.pause.frei .cb-ring-lauf { stroke: #fff; }

.cb-punkt {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
}

.cb-ring {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 30px; height: 30px;
  flex: none;
}

/* Gespiegelt und gedreht: Der Ring beginnt oben und läuft **gegen** den
   Uhrzeigersinn leer. Ohne die Spiegelung liefe er im Uhrzeigersinn. */
.cb-ring svg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  transform: rotate(-90deg) scaleX(-1);
  transform-origin: 50% 50%;
}

.cb-ring-grund {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  opacity: 0.22;
}

.cb-ring-lauf {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  /* Der Übergang glättet den Sekundensprung, ohne ihn zu verschleppen. */
  transition: stroke-dashoffset 0.9s linear;
}

.cb-ring-zahl {
  position: relative;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Der Aufrufen-Knopf bleibt bedienbar — die Turnierleitung darf sich über die
   Pause hinwegsetzen, etwa wenn jemand ausdrücklich früher spielen will.
   Er sagt nur deutlich, dass hier etwas dagegen spricht. */
.knopf.warnt {
  background: var(--warn-soft);
  color: var(--warn);
  border-color: currentColor;
}

@media (prefers-reduced-motion: reduce) {
  .cb-ring-lauf { transition: none; }
}

/* Die DSQ-Marke im Turnierbaum (UEBERGABE.md, Abschnitt 24.8).
 *
 * Klein und in Warnfarbe, direkt hinter dem Namen: Sie ist ein Hinweis auf
 * eine Tatsache und keine Auszeichnung — wer den Baum überfliegt, soll sie
 * sehen, ohne dass sie den Namen verdrängt. Im Doppel steht sie an der
 * Paarung, denn ausgeschieden ist die Paarung. */
.dsq-marke {
  display: inline-block;
  margin-left: 0.4em;
  padding: 0 0.35em;
  border-radius: var(--r1);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 0.7em;
  font-weight: 700;
  letter-spacing: 0.03em;
  vertical-align: 0.08em;
}

/* Die Pausenuhr — Einspielzeit, Satzpause und Pause im Satz.
 *
 * Ein Streifen und keine große Fläche: Die Uhr ist eine Auskunft und nicht die
 * Bedienung. Sie steht dort, wo ohnehin hingesehen wird — über dem Spielfeld
 * beziehungsweise im Fenster, das gerade offen ist —, und sie darf das Zählen
 * nicht verdrängen.
 *
 * Läuft die Zeit ab, wechselt die Farbe. Sie **sperrt nichts**: Wer weiter
 * zählt, zählt weiter; über die Regel entscheidet der Schiedsrichter.
 *
 * Die Grundfassung ist die für **hellen** Grund — die einfache Zählansicht am
 * Feld und das Einrichtungsfenster. Nur der Streifen auf der dunklen Bühne der
 * Schiedsrichter-Ansicht bekommt seine eigene; er ist der direkte Nachbar des
 * Spielfelds und darum als einziger ein Kind von `.schiri-ansicht`. */
.pausenuhr {
  display: flex;
  gap: var(--s3);
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  padding: var(--s2) var(--s4);
  border: 1px solid var(--gold);
  border-radius: var(--r2);
  background: var(--surface-2);
  color: var(--ink);
  text-align: center;
}

.pausenuhr-wort {
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.pausenuhr-zeit {
  font-size: clamp(1.4rem, 5vw, 2.2rem);
  font-weight: 800;
  line-height: 1;
  /* Gleich breite Ziffern: Sonst zappelt die Uhr bei jedem Wechsel. */
  font-variant-numeric: tabular-nums;
}

/* Abgelaufen heißt: Die Zeit ist überschritten, die Uhr zählt mit Minus
   weiter (Abschnitt 117). Rot, wie vom Auftraggeber gewünscht — der
   Schiedsrichter soll es aus dem Augenwinkel sehen. */
.pausenuhr.abgelaufen {
  border-color: var(--danger);
  background: var(--danger-soft);
  color: var(--danger);
}

/* Auf der dunklen Bühne der Schiedsrichter-Ansicht. */
.schiri-ansicht > .pausenuhr {
  background: rgba(217, 168, 60, 0.14);
  color: var(--gold-bright);
}

.schiri-ansicht > .pausenuhr.abgelaufen {
  border-color: #c0392b;
  background: rgba(192, 57, 43, 0.22);
  color: #f3c7c1;
}

/* Im Fenster des Einrichtungsdialogs und in der einfachen Zählansicht bleibt
   es bei der hellen Fassung; dort braucht die Uhr nur ihren Platz. */
.schiri-fenster .pausenuhr { margin-bottom: var(--s4); }
.zaehlansicht .pausenuhr { margin: 0 var(--s3); }

/* Die Platzierungen im Reiter Planung: aufklappbar und ganz unten.
 *
 * `display: list-item` auf der Zusammenfassung, damit das Dreieck des Browsers
 * stehen bleibt — mit `flex` verschwindet es in WebKit, und dann sieht ein
 * zugeklappter Abschnitt wie eine tote Überschrift aus. */
.tb-platzierungen > summary {
  display: list-item;
  cursor: pointer;
  list-style-position: inside;
}

.tb-platzierungen > summary h3 { display: inline; }
.tb-platzierungen > summary .zusatztext { margin-left: var(--s3); }
.tb-platzierungen > summary::marker { color: var(--ink-3); }

/* Der Schalter im Spielkarten-Abschnitt: Kästchen links, Beschriftung rechts.
 *
 * Eine eigene Klasse und nicht `.schalterzeile` aus der Benutzerverwaltung —
 * die steht in einem Stilblatt, das auf dieser Seite nicht geladen wird, und
 * ohne sie rutschte das Kästchen auf eine eigene Zeile über den Text. */
.sk-schalter {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  cursor: pointer;
}

.sk-schalter input { margin-top: 0.2em; flex: none; }
.sk-schalter > span { min-width: 0; }
.sk-schalter small { display: block; margin-top: 2px; }

/* Der Zeitplan im Reiter „Planung“ — UEBERGABE.md, Abschnitt 26p.

   Ein Raster: eine Zeile je Abschnitt, eine Spalte je Feld. Es rollt in
   seinem eigenen Kasten und reißt die Seite bei 360 px nicht in die Breite
   (ARCHITEKTUR.md, Abschnitt 1) — bei acht Feldern ginge das sonst nicht
   anders. */
.zp-rollfeld { overflow-x: auto; }

.zp-raster {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.zp-raster th,
.zp-raster td {
  border: 1px solid var(--line);
  padding: 0;
  text-align: center;
  min-width: 5.5rem;
}

.zp-raster thead th {
  padding: var(--s2);
  background: var(--surface-2);
  font-size: 0.78rem;
  white-space: nowrap;
}

.zp-raster tbody th {
  padding: var(--s2);
  text-align: left;
  white-space: nowrap;
  background: var(--surface-2);
}

.zp-raster tbody th small { display: block; font-weight: 400; }

.zp-zelle {
  width: 100%;
  min-height: var(--touch);
  padding: var(--s2);
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.zp-zelle[disabled] { cursor: default; }

/* Belegt, frei, gewählt — drei Zustände, die aus der Entfernung
   auseinanderzuhalten sein müssen, weil das Raster am Turniertisch überflogen
   und nicht gelesen wird. */
.zp-belegt { background: var(--brand-soft); }
.zp-belegt.fertig { background: var(--surface-3); color: var(--ink-3); }
.zp-frei .zp-zelle { color: var(--ink-3); font-size: 0.78rem; }
.zp-frei .zp-zelle:not([disabled]):hover { background: var(--brand-soft); }
.zp-zelle.gewaehlt {
  background: var(--brand);
  color: var(--auf-brand, #fff);
  font-weight: 700;
}

/* Ein Platz, den es in diesem Abschnitt nicht gibt — im Feldverbund der
   Regelfall für die Felder des Nachbarturniers. */
.zp-fremd { background: repeating-linear-gradient(
  45deg, transparent, transparent 4px, var(--line) 4px, var(--line) 5px); }

/* Die voraussichtliche Anfangszeit an einer Vormerkung. Zurückhaltend: Sie
   ist eine Auskunft und keine Handlung, und im Callboard zählt zuerst, wer
   dran ist. */
.cb-zeit {
  padding: 2px var(--s2);
  border-radius: var(--r1);
  background: var(--surface-3);
  color: var(--ink-3);
  font-size: 0.76rem;
  font-weight: 700;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Chessminton — Ergebniseingabe und Berechnungshilfe
   UEBERGABE.md, Abschnitt 34
   --------------------------------------------------------------------------- */

/* Der Gesamtstand steht groß über der Eingabe: Er ist das, wonach am
   Turniertisch gefragt wird, und die vier Phasen sind der Weg dorthin. */
.cm-gesamt {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r2);
  background: var(--surface-2);
}

.cm-gesamt-name {
  min-width: 0;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.cm-gesamt-name:last-of-type { text-align: right; }

.cm-gesamt strong {
  font-size: clamp(1.6rem, 6vw, 2.4rem);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cm-sieger { margin: 0; color: var(--ink-2); }

/* Eine Phase. Der Zwischenstand steht in der Beschriftung — beim Eintragen
   will man sehen, was die Phase gerade ergibt, ohne nach unten zu sehen. */
.cm-phase legend {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s3);
}

.cm-phasenstand {
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* Der Eingabeweg (Abschnitt 34.6): sichtbar, aber nicht vorgewählt. */
.cm-wegwahl {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s4);
  margin-bottom: var(--s4);
}

.cm-wegwahl label {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: 0.9rem;
}

.cm-brett {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r2);
}

.cm-brett + .cm-brett { margin-top: var(--s4); }

.cm-brettkopf { display: grid; gap: 2px; }
.cm-brettkopf small { color: var(--ink-2); }

/* Die Schachuhr ist eine Eingabehilfe und kein gespeicherter Zustand
   (Abschnitt 34.7) — deshalb zurückhaltend und eingeklappt. */
.cm-uhrkasten { display: grid; gap: var(--s4); margin-top: var(--s4); }

.cm-uhrseiten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s3);
}

.cm-uhrseite {
  display: grid;
  gap: 2px;
  /* Große Fläche: Am Brett wird sie im Stehen getroffen
     (ARCHITEKTUR.md, Abschnitt 1). */
  min-height: 72px;
  text-align: center;
}

.cm-uhrseite .zahl {
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
}

.cm-uhrseite.laeuft {
  border-color: var(--st-live);
  background: var(--st-live-soft);
  color: var(--st-live);
}

.cm-hinweise {
  margin: 0;
  padding: var(--s4) var(--s4) var(--s4) var(--s6);
  border-radius: var(--r2);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 0.9rem;
}

.cm-streichung {
  margin: 0;
  padding: var(--s4);
  border-radius: var(--r2);
  background: var(--st-done-soft);
  color: var(--st-done);
  font-size: 0.9rem;
}

.cm-regelliste { margin: 0; display: grid; gap: var(--s3); }
.cm-regelliste dt { font-weight: 700; }
.cm-regelliste dd { margin: 0 0 var(--s3); color: var(--ink-2); }

@media (min-width: 700px) {
  .cm-regelliste {
    grid-template-columns: max-content 1fr;
    column-gap: var(--s5);
  }
  .cm-regelliste dd { margin-bottom: 0; }
}

/* `hidden` muss auch gegen `.feld { display: grid }` gelten.
   Ohne diese Zeile standen Restzeit und Schwarzwahl an jeder Partie, auch
   wenn das Ergebnis noch offen war — die Vorgabe des Browsers für [hidden]
   ist `display: none`, und eine eigene `display`-Angabe schlägt sie. */
.cm-eingabe [hidden] { display: none !important; }


/* --- Sortierbare Spaltenköpfe (web/js/ui.js, `sortierkopf`) ----------------
   Der Knopf füllt die ganze Zelle, damit die Trefferfläche der Spaltenkopf
   ist und nicht nur das Wort darin. Er erbt die Schrift des Kopfes und sieht
   deshalb nicht wie ein Knopf aus — bis man darüberfährt.
   -------------------------------------------------------------------------- */

.tb-tabelle th:has(.sortknopf) { padding: 0; }

.sortknopf {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: var(--s2) var(--s3);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: var(--r1);
}

.sortknopf:hover { background: var(--surface-2); }

.sortknopf:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* Der Pfeil steht immer da, damit die Spaltenbreite beim Sortieren nicht
   springt — im Ruhezustand nur blasser. */
.sortpfeil {
  margin-left: auto;
  font-size: 0.75em;
  opacity: 0.35;
}

.sortknopf.aktiv { font-weight: 700; }
.sortknopf.aktiv .sortpfeil { opacity: 1; }


/* --- Die Sortierwahl für schmale Geräte ------------------------------------
   Unter 768 px verschwindet der Tabellenkopf und die Zeilen werden zu Karten
   — das Sortieren muss trotzdem erreichbar bleiben. Darüber ist die Wahl
   überflüssig, weil die Spaltenköpfe dasselbe tun.
   -------------------------------------------------------------------------- */

.sortierwahl { display: none; }

@media (max-width: 767px) {
  .sortierwahl {
    display: flex;
    align-items: center;
    gap: var(--s2);
    flex-wrap: wrap;
    margin-bottom: var(--s3);
  }
  .sortierwahl label { font-size: 0.85rem; color: var(--ink-2); }
  .sortierwahl select { flex: 1; min-width: 140px; }
}

/* Der Ballstand auf dem Federball-Knopf — UEBERGABE.md, Abschnitt 24.

   Er sitzt als Marke in der Ecke und verdrängt das Zeichen nicht: Der Knopf
   wird am Feld mit einer Hand und ohne Hinsehen getroffen, seine Gestalt darf
   sich also nicht ändern, nur weil aus der 9 eine 10 wird. */
.schiri-ball { position: relative; }

.schiri-ballzahl {
  position: absolute;
  right: -2px;
  bottom: -2px;
  min-width: 20px;
  height: 20px;
  padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--gold-bright);
  color: #17251f;
  font-size: 0.72rem;
  font-weight: 800;
  line-height: 20px;
  text-align: center;
}


/* --- Das Löschkreuz an der Ecke eines Spielkastens -------------------------
   Löschen ist keine der Handlungen, die man am Spiel vornimmt — es nimmt das
   Spiel weg. Deshalb steht es nicht in der Knopfreihe zwischen „Freischalten“
   und „Beenden“, sondern an der Ecke des Kastens, zu dem es gehört.

   Rot und trotzdem zurückhaltend: gefüllt wäre es das Auffälligste im Kopf
   des Kastens, und das Auffälligste sollte nicht die Handlung sein, die man
   am seltensten will. Erst beim Überfahren füllt es sich.

   Die volle Grifffläche (`--touch`) bleibt: Am Turniertisch wird mit dem
   Finger getroffen, und ein Kreuz von 20 Pixeln ist auf einem Tablet keine
   Schaltfläche, sondern ein Glücksspiel. Sichtbar ist nur der Rahmen darum. */
.knopf-kreuz {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--touch);
  height: var(--touch);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: transparent;
  color: var(--danger);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}

.knopf-kreuz:hover {
  background: var(--danger-soft);
  border-color: var(--danger);
}

.knopf-kreuz:focus-visible {
  outline: 2px solid var(--danger);
  outline-offset: 2px;
}

/* Der Zähltafel-Hinweis an einer Vormerkung. Gedämpft und nicht warnend: Die
   Partie ist ansetzbar, es wäre nur unpraktisch — eine rote Marke stünde für
   eine Sperre, die es hier ausdrücklich nicht gibt. */
.callboard-zaehlt {
  color: var(--warn);
}

/* --------------------------------------------------------------------------
   Ampel an der Zähltafel (Migration 084)

   Grün frei, gelb selbst angesetzt, rot spielt gerade. Der Punkt trägt seine
   Aussage **nicht allein in der Farbe**: Daneben steht der Name, im Titel die
   ausgeschriebene Lage („spielt gerade (Feld 5)“). Wer Rot und Grün nicht
   unterscheiden kann, liest sie trotzdem.
   -------------------------------------------------------------------------- */
.zaehlerzeile { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.zaehlerzeile .zaehler { display: inline-flex; align-items: center; gap: var(--s1); }

.ampel {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.25);
  flex: none;
}
.ampel.gruen { background: #2e9e5b; }
.ampel.gelb  { background: #f2c94c; }
.ampel.rot   { background: #c0392b; }

/* Zählansicht am Feldtablet: Das Spiel zählt gerade ein anderes Gerät
   (UEBERGABE.md, 13.21). Oben angeheftet, damit es über jeder Ansicht
   steht — der Zählfläche, der Einspielzeit, dem Satzwechsel. */
.zaehl-fremdgeraet {
  position: sticky;
  top: 0;
  z-index: 20;
  padding: var(--s2) var(--s3);
  background: var(--warn-soft);
  color: var(--ink);
  border-bottom: 2px solid var(--warn);
  font-weight: 600;
  text-align: center;
}

/* Der Sonderfall unter den Zusatzfunktionen („Weiteres“), abgesetzt durch
   eine Linie: Darüber wird dokumentiert, hier wird das Spiel entschieden. */
.schiri-sonderfallblock {
  display: grid;
  gap: var(--s3);
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.schiri-sonderfallblock h3 { margin: 0; }
.schiri-zusatzraster a.schiri-knopf {
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

/* Gescannter Spielcode, Spiel wartet auf ein Feld (13.26): große Knöpfe,
   am Feld mit dem Daumen getroffen. */
.zaehl-feldwahl {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--s2);
}
.zaehl-feldwahl .knopf { min-height: 56px; font-size: 1.05rem; }
