/* ══════════════════════════════════════════════════════════════════════════
   Gestaltung der Wettbewerbsplattform — EINE Datei für alle Seiten.

   In App-1 ist genau das schiefgegangen: jede Seite trug ihren eigenen
   <style>-Block, und daraus wurden vier Inhaltsbreiten und vier Knopffarben,
   die zufällig nebeneinander lagen. Hier gibt es die Werte einmal.

   Hell und Dunkel folgen der Systemeinstellung. Eine Live-Tabelle wird am
   Spielfeldrand in der Sonne gelesen und abends auf dem Sofa — beides muss
   gehen, ohne dass jemand etwas umstellt.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  --bg: #f2f2f7;
  --flaeche: #ffffff;
  --flaeche2: #f7f7fa;
  --flaeche3: #ececf1;
  --text: #1c1c1e;
  --text2: #6c6c70;
  /* ⬛ Beim Nachrechnen gefunden: #9a9aa0 ergab auf dem Seitengrund Kontrast 2,6 — für die
     11- und 12-Pixel-Schrift, in der `--text3` fast immer steht (Bildunterschriften,
     Fussnoten, Fusszeile), deutlich zu wenig. Die Farbe soll zurückhaltend sein, nicht
     unlesbar. 4,6 ist zurückhaltend. */
  --text3: #6f6f78;
  --linie: rgba(0, 0, 0, .10);
  --akzent: #0a6cff;
  --akzent-bg: rgba(10, 108, 255, .10);
  --gruen: #1a9c4b;
  --gruen-bg: rgba(26, 156, 75, .12);
  --gelb: #d18700;
  /* ⬛ Vom Nutzer gemeldet: „im Dunkelmodus ist der Hinweisbanner nicht zu lesen." Der Grund
     war, dass es diese Variable ÜBERHAUPT NICHT gab — das Laufband schrieb `var(--gelb-bg,
     #fff8e6)` und bekam deshalb in beiden Modi denselben hellen Grund, während die Schrift
     `var(--text)` folgte und im Dunkelmodus fast weiss wurde. Weiss auf Hellgelb.
     Eine Variable mit Ausweichwert sieht aus wie eine Absicherung und ist in Wahrheit eine
     Stelle, an der niemand mehr nachsieht. */
  --gelb-bg: #fff8e6;
  --auf-akzent: #fff;
  /* Derselbe Fall wie `--gelb-bg`, von der neuen Prüfung gefunden: benutzt, nie definiert.
     Ein Schatten aus reinem Schwarz verschwindet auf dunklem Grund — dort trägt ihn ein
     etwas kräftigerer. */
  --schatten-gross: 0 8px 24px rgba(0,0,0,.18);
  --rot: #d92d20;
  --rot-bg: rgba(217, 45, 32, .10);

  /* Die drei Farben des Logos. Es ist dunkelgrün gezeichnet — auf hellem Grund bleibt es,
     wie es gezeichnet wurde. Wo es auf Dunkel liegt, werden Zeichen und Schriftzug hell;
     das leuchtende Grün des „it" trägt auf beiden Gründen und bleibt. */
  --logo-zeichen: #0a4526;
  --logo-wort: #066b2c;
  --logo-akzent: #1ba72f;

  --fs-2xs: 10px; --fs-xs: 11px; --fs-sm: 12px;
  --fs-md: 13px;  --fs-lg: 15px; --fs-xl: 19px; --fs-2xl: 26px;
  --hoehe: 34px; --hoehe-gr: 42px;
  --r-sm: 6px; --r-md: 10px; --r-lg: 14px;
  --breite: 1000px;
  --schatten: 0 1px 2px rgba(0,0,0,.05), 0 8px 24px rgba(0,0,0,.06);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #131316;
    --flaeche: #1e1e22;
    --flaeche2: #26262b;
    --flaeche3: #303036;
    --text: #f2f2f7;
    --text2: #a0a0a8;
    --text3: #8e8e99;
    --linie: rgba(255, 255, 255, .10);
    --akzent: #4a9bff;
    --akzent-bg: rgba(74, 155, 255, .16);
    --gruen: #34c759;
    --gruen-bg: rgba(52, 199, 89, .16);
    --gelb: #ffb020;
    --gelb-bg: rgba(255, 176, 32, .16);
    /* Weiss auf dem hellen Blau des Dunkelmodus ergibt Kontrast 2,8 — zu wenig für einen
       Knopf, der die wichtigste Handlung der Seite trägt. Dunkle Schrift darauf ergibt 7,5. */
    --auf-akzent: #101014;
    --schatten-gross: 0 10px 30px rgba(0,0,0,.55);
    --rot: #ff6257;
    --rot-bg: rgba(255, 98, 87, .14);
    --logo-zeichen: #f2f2f7;
    --logo-wort: #f2f2f7;
    --logo-akzent: #34c759;
    --schatten: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35);
  }
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ⬛ `hidden` muss gewinnen — und tut es von sich aus NICHT.
   Das Attribut wirkt über `[hidden]{display:none}` aus dem Browser-Grundstil und verliert damit
   gegen jede eigene Regel mit höherer Gewichtung (`label.feld{display:block}`) und gegen jedes
   inline gesetzte `display`. Genau das ist hier dreimal passiert: das Zahlenfeld stand in allen
   drei Modell-Karten, die Neunmeter-Felder bei jeder Partie statt nur im K.-o. Ein `!important`
   an dieser einen Stelle ist billiger als die Regel, `hidden` nie zu benutzen. */
[hidden] { display: none !important; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', Roboto, sans-serif;
  font-size: var(--fs-md);
  line-height: 1.45;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--akzent); text-decoration: none; }
a:hover { text-decoration: underline; }
.ic { flex: none; vertical-align: -.15em; }

/* ── Kopfzeile ─────────────────────────────────────────────────────────── */

header.kopf {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--flaeche) 88%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--linie);
}
.kopf-innen {
  max-width: var(--breite); margin: 0 auto; padding: 0 16px;
  height: 52px; display: flex; align-items: center; gap: 14px;
}
.marke { font-weight: 700; font-size: var(--fs-lg); letter-spacing: -.01em; color: var(--text); display: flex; align-items: center; gap: 8px; }
.marke:hover { text-decoration: none; }
/* Das Logo trägt den Namen selbst — in der Leiste steht es allein, ohne Punkt und ohne
   Wiederholung des Wortes daneben. `display:block` nimmt die Zeilenluft weg, die ein SVG
   sonst wie ein Buchstabe unter sich stehen lässt. */
.marke .logo { display: block; flex: none; }
.kopf-nav { display: flex; align-items: center; gap: 4px; margin-left: auto; flex-wrap: wrap; }
.kopf-nav a, .kopf-nav button {
  color: var(--text2); padding: 6px 10px; border-radius: var(--r-sm);
  font-size: var(--fs-md); font-weight: 500;
}
.kopf-nav a:hover { background: var(--flaeche2); color: var(--text); text-decoration: none; }
.kopf-nav a.aktiv { color: var(--text); background: var(--flaeche3); }

/* ── Eine Reihe gleichrangiger Knöpfe ──────────────────────────────────────
   Nebeneinander, solange sie nebeneinander passen; darunter jeder für sich über die volle
   Breite. Das Zwischending — zwei oben, einer unten links, einer unten rechts — sieht aus,
   als wäre etwas verrutscht. */
.knopfgitter { display: flex; gap: 8px; flex-wrap: wrap; }
.knopfgitter > .knopf { flex: 1 1 auto; }
@media (max-width: 560px) {
  .knopfgitter { display: grid; grid-template-columns: 1fr; gap: 8px; }
  .abmelden-knopf { display: flex; width: 100%; }
}

/* ── Das Menü am schmalen Bildschirm ───────────────────────────────────────
   Fünf Punkte passen bei 390 px nicht nebeneinander; sie brechen um, und der Kopf wird
   zweizeilig — die Punkte „fliegen auseinander". Unter 720 px steht deshalb ein Knopf da, und
   die Punkte stehen untereinander unter ihm. */
.menue-knopf {
  display: none; margin-left: auto; flex: 0 0 auto;
  width: 38px; height: 38px; border: 1px solid var(--linie); border-radius: var(--r-sm);
  background: none; color: var(--text2); align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
}
.menue-knopf:hover { background: var(--flaeche2); color: var(--text); }

@media (max-width: 720px) {
  .kopf-innen { position: relative; }
  .menue-knopf { display: inline-flex; }
  .kopf-nav {
    display: none; position: absolute; top: calc(100% + 6px); right: 0;
    flex-direction: column; align-items: stretch; gap: 2px; margin: 0;
    min-width: 190px; padding: 6px; z-index: 30;
    background: var(--flaeche); border: 1px solid var(--linie);
    border-radius: var(--r-md); box-shadow: var(--schatten);
  }
  .kopf-nav.offen { display: flex; }
  .kopf-nav a { padding: 11px 12px; font-size: var(--fs-lg); color: var(--text); }
}

main { max-width: var(--breite); margin: 0 auto; padding: 22px 16px 80px; }
main.breit { max-width: 1240px; }

/* ── Bausteine ─────────────────────────────────────────────────────────── */

.karte {
  background: var(--flaeche); border: 1px solid var(--linie);
  border-radius: var(--r-lg); box-shadow: var(--schatten);
  overflow: hidden; margin-bottom: 18px;
}
.karte-kopf {
  padding: 13px 16px; border-bottom: 1px solid var(--linie);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.karte-kopf h2 { font-size: var(--fs-lg); font-weight: 650; letter-spacing: -.01em; }
.karte-koerper { padding: 16px; }
.karte-kopf .rechts { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* ⬛ Ein Gitter- oder Flexelement kann NICHT schmaler werden als sein breitestes Kind — es
   sei denn, man erlaubt es ausdrücklich. Ohne diese Zeile wächst die Spalte mit dem breitesten
   Kopf mit, die Seite wird breiter als das Fenster, und am Handy zoomt der Browser heraus:
   dann sieht jede Messung so aus, als passe alles, während die Schrift winzig ist und der
   linke Rand abgeschnitten. Gemessen: 692 px Dokument bei 390 px Fenster — mit dieser Zeile
   genau 390. */
#gitter > *, .stapel > *, main > * { min-width: 0; }

/* Am schmalen Bildschirm bricht auch die rechte Gruppe eines Kartenkopfs um. Titel, Marke,
   Datum und drei Knöpfe in einer Reihe brauchen 628 px — vorhanden sind 330. */
@media (max-width: 720px) {
  .karte-kopf .rechts { margin-left: 0; flex-wrap: wrap; width: 100%; }
  .karte-kopf .rechts input[type=date] { flex: 1 1 130px; width: auto !important; }
  .karte-kopf .rechts > .knopf { flex: 1 1 auto; }
  .karte-kopf .rechts > .knopf.symbol { flex: 0 0 auto; }
}

h1.titel { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -.02em; margin-bottom: 4px; }
.unterzeile { color: var(--text2); font-size: var(--fs-md); margin-bottom: 20px; }

.knopf {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: var(--hoehe); padding: 0 14px; border-radius: var(--r-sm);
  border: 1px solid var(--linie); background: var(--flaeche2); color: var(--text);
  font-size: var(--fs-md); font-weight: 550; font-family: inherit; cursor: pointer;
  white-space: nowrap; transition: background .12s, border-color .12s;
}
.knopf:hover { background: var(--flaeche3); text-decoration: none; }
.knopf.haupt { background: var(--akzent); border-color: var(--akzent);
               color: var(--auf-akzent); }
.knopf.haupt:hover { filter: brightness(1.08); }
.knopf.gefahr { color: var(--rot); }
.knopf.gefahr:hover { background: var(--rot-bg); }
.knopf.klein { height: 28px; padding: 0 10px; font-size: var(--fs-sm); }
.knopf.gross { height: var(--hoehe-gr); padding: 0 20px; font-size: var(--fs-lg); }
.knopf:disabled { opacity: .45; cursor: default; }
/* Knopf, der nur ein Symbol trägt: quadratisch statt breit. Ein „Löschen" in voller Wortbreite
   neben jeder Zeile zieht den Blick genau auf die Handlung, die man am seltensten will. */
.knopf.symbol { width: var(--hoehe); padding: 0; flex: none; }
.knopf.symbol.klein { width: 28px; font-size: var(--fs-lg); line-height: 1; }

/* Und dieselbe Überlegung eine Stufe weiter: ein Papierkorb, der in jeder Zeile rot leuchtet,
   macht eine Liste unruhig und die Farbe bedeutungslos. Er bleibt still, bis man auf ihn zeigt —
   dann wird er rot, damit vor dem Klick klar ist, worum es geht. */
.knopf.gefahr.symbol { color: var(--text3); }
.knopf.gefahr.symbol:hover, .knopf.gefahr.symbol:focus-visible {
  color: var(--rot); background: var(--rot-bg); border-color: color-mix(in srgb, var(--rot) 35%, transparent);
}

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=time], select, textarea {
  height: var(--hoehe); width: 100%; padding: 0 10px;
  border: 1px solid var(--linie); border-radius: var(--r-sm);
  background: var(--flaeche2); color: var(--text);
  font-size: var(--fs-md); font-family: inherit;
}
textarea { height: auto; padding: 8px 10px; resize: vertical; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--akzent); box-shadow: 0 0 0 3px var(--akzent-bg);
}
label.feld { display: block; margin-bottom: 12px; }
label.feld > span { display: block; font-size: var(--fs-sm); color: var(--text2); margin-bottom: 5px; font-weight: 550; }
.zeile { display: flex; gap: 12px; flex-wrap: wrap; }
.zeile > * { flex: 1 1 160px; }
.hinweis { font-size: var(--fs-sm); color: var(--text2); }
.fehler-box { background: var(--rot-bg); color: var(--rot); padding: 10px 12px; border-radius: var(--r-sm); font-size: var(--fs-md); margin-bottom: 14px; }
.leer { padding: 44px 16px; text-align: center; color: var(--text2); }
.leer h3 { font-size: var(--fs-lg); color: var(--text); margin-bottom: 6px; font-weight: 600; }

.marke-chip {
  display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 9px;
  border-radius: 11px; background: var(--flaeche3); color: var(--text2);
  font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase; letter-spacing: .04em;
}
.marke-chip.gruen { background: var(--gruen-bg); color: var(--gruen); }
.marke-chip.blau  { background: var(--akzent-bg); color: var(--akzent); }
.marke-chip.rot   { background: var(--rot-bg); color: var(--rot); }

/* Der Schwierigkeitsgrad in der Unterzeile eines Spielfests. `translateY` rückt die Sterne auf
   die Schriftlinie — ein 12px-Symbol sitzt sonst sichtbar zu hoch neben 13px-Text. */
/* Wer ausrichtet — im selben Grau wie die Unterzeile, der Name selbst etwas kräftiger.
   Es ist eine Auskunft, keine Überschrift. */
.veranstalter b { color: var(--text2); font-weight: 650; }
/* Vorschläge beim Tippen eines Vereinsnamens. Ein Kasten, keine Auswahlliste: er
   BEHAUPTET nicht, dass es derselbe Verein ist, er zeigt, was es schon gibt — die
   Entscheidung bleibt bei dem, der tippt. */
.aehnliche {
  margin: -4px 0 14px; padding: 12px 14px; border-radius: 12px;
  background: var(--flaeche3); border: 1px solid var(--linie);
}
.aehnliche-kopf { margin: 0 0 8px; font-weight: 650; font-size: var(--fs-sm); }
.aehnliche-zeile {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  padding: 4px 0; font-size: var(--fs-sm);
}
.aehnliche p.hinweis { margin: 8px 0 0; }
/* Die Absageregel unter dem Titel. Sie ist eine WARNUNG an alle Gemeldeten, keine
   Fussnote — deshalb der farbige Rand; aber sie steht unter der Unterzeile und nicht
   darüber, weil sie nicht das Erste ist, was jemand vom Wettbewerb wissen will. */
.absageregel {
  display: flex; gap: 8px; align-items: flex-start; max-width: 640px;
  margin: 10px 0 0; padding: 9px 12px; border-radius: 10px;
  background: var(--gelb-bg, var(--flaeche3)); border-left: 3px solid var(--gelb);
  color: var(--text2); font-size: var(--fs-sm); line-height: 1.5;
}
.absageregel .ic { color: var(--gelb); flex: none; margin-top: 2px; }
.absageregel b { color: var(--text); }
/* Ein Ergebnis, das nicht auf dem Platz entstanden ist. Klein und unter der Zahl —
   es soll die Zahl nicht überschreien, aber niemand soll sie für gespielt halten. */
.wertung-vermerk {
  display: block; margin-top: 1px; font-size: var(--fs-2xs); font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase; color: var(--gelb);
}
/* Eine ausgestellte Registriernummer. Gross und mit Abstand zwischen den Zeichen —
   sie wird abgetippt oder am Telefon vorgelesen, und 0/O und 1/I dürfen sich dabei
   nicht ähneln (der Zeichenvorrat lässt sie deshalb ganz weg). */
.nummern-zeile {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 0; border-bottom: 1px solid var(--linie);
}
.nummern-zeile b { flex: 1; min-width: 160px; }
.nummer {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-md); letter-spacing: .09em; padding: 4px 10px;
  border-radius: 8px; background: var(--flaeche3); user-select: all;
}
/* Der Code des Service-Zugangs steht gross und für sich — er wird vorgelesen, nicht
   überflogen. */
.service-code { margin-top: 8px; font-size: var(--fs-lg); }

/* ⬛ Grün, seit der Schwierigkeitsgrad in Fussbällen steht — vom Nutzer so gewünscht. Blau
   ist in diesem Haus die Farbe für „hier kannst du etwas tun" (Knöpfe, Links); ein Ball, der
   nur eine Auskunft ist, sah damit aus wie ein Bedienelement. */
.sterne-text { color: var(--gruen); letter-spacing: 1px; }
.sterne { display: inline-flex; align-items: center; gap: 1px; color: var(--gruen);
          vertical-align: middle; }
.sterne .ic { transform: translateY(-1px); }

/* Die Spielform unter dem Feldnamen. Zentriert, weil sie in der Mitte der Partie steht, und
   ohne Umbruch: „Minitore · 3 gegen 3" auf zwei Zeilen läse sich wie zwei Angaben. */
.modus-zeile { font-size: var(--fs-xs); text-align: center; white-space: nowrap; }

/* ── Der Rechtsfuss ────────────────────────────────────────────────────────
   Auf jeder Seite, unaufdringlich, aber immer erreichbar. `margin-top: auto` allein genügt
   nicht — der Body ist keine Spalte; deshalb schlicht Abstand nach oben. */
.rechtsfuss {
  display: flex; flex-wrap: wrap; gap: 6px 16px; justify-content: center;
  margin: 40px auto 0; padding: 18px 22px calc(18px + env(safe-area-inset-bottom));
  max-width: var(--breite); border-top: 1px solid var(--linie);
  color: var(--text3); font-size: var(--fs-xs);
}
.rechtsfuss a { color: var(--text3); }
.rechtsfuss a:hover { color: var(--akzent); }
/* Nur dort ausblenden, wo die Seite ihren EIGENEN Fuss mitbringt — nicht auf jeder breiten
   Seite. Beim ersten Versuch hing es an `main.voll`, und damit fehlten die Verweise auch auf
   den Unterseiten, die keinen eigenen Fuss haben. */
main.hat-eigenen-fuss + .rechtsfuss { display: none; }

/* ── Der Feldplan eines Spielfests ─────────────────────────────────────────
   Der Rasen ist reines CSS: ein grünes Rechteck mit Mittellinie und Mittelkreis. Ein Bild wäre
   eine Datei mehr zum Ausliefern, und ein SVG in einer JavaScript-Zeichenkette hat in diesem
   Haus schon zweimal eine Seite getötet. `aspect-ratio` hält die Anlage in Form, egal ob sie
   340 Punkte breit ist oder 900 — die Felder stehen ja in Prozent darin. */
.rasen {
  position: relative; width: 100%; aspect-ratio: 100 / 64; border-radius: 10px;
  background: repeating-linear-gradient(90deg, #4e9c52 0 8%, #549f58 8% 16%);
  border: 3px solid rgba(255, 255, 255, .55); overflow: hidden;
}
/* ⬛ Die Mittellinie steht QUER zur Längsachse — bei einem quer liegenden Platz also
   senkrecht. Sie lag hier waagerecht, und damit sah die Skizze aus wie ein Platz, der doppelt
   so breit wie lang ist. Vom Nutzer gemeldet. */
.rasen::before {   /* Mittellinie */
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%; width: 2px;
  background: rgba(255, 255, 255, .45);
}
/* Hochkant: dieselbe Anlage, von der Seite gesehen. Die Kacheln kommen schon gekippt vom
   Server; hier dreht sich der Rasen — Seitenverhältnis, Streifen und Mittellinie. */
.rasen.hochkant {
  aspect-ratio: 64 / 100;
  background: repeating-linear-gradient(0deg, #4e9c52 0 8%, #549f58 8% 16%);
}
.rasen.hochkant::before {
  top: 50%; bottom: auto; left: 0; right: 0; height: 2px; width: auto;
}
.rasen::after {    /* Mittelkreis */
  content: ''; position: absolute; left: 50%; top: 50%; width: 18%; aspect-ratio: 1;
  transform: translate(-50%, -50%); border: 2px solid rgba(255, 255, 255, .45);
  border-radius: 50%;
}
.plan-feld {
  position: absolute; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; padding: 2px; overflow: hidden; cursor: pointer;
  border: 2px solid rgba(255, 255, 255, .9); border-radius: 6px; color: #fff;
  background: rgba(0, 0, 0, .16); font: inherit; text-align: center;
  transition: background .15s, transform .15s;
}
.plan-feld:hover { background: rgba(0, 0, 0, .3); }
/* Jugendtore bekommen den kräftigeren Rahmen — auf der Skizze soll man die grossen Felder
   auch dann erkennen, wenn zwei Minitorfelder zufällig ähnlich gross geraten sind. */
.plan-feld.jugendtor { border-width: 3px; background: rgba(0, 0, 0, .26); }
/* Ein Feld, auf dem an diesem Tag niemand spielt. Gestrichelt statt weggelassen: es
   gehört zur Anlage, und der Ausrichter soll sehen, dass er es nicht braucht. */
.plan-feld.leer { border-style: dashed; opacity: .55; background: rgba(0, 0, 0, .08); }
/* Für Besucher ausgeblendet — in der Verwaltung noch da, aber unübersehbar anders. Ein
   Schalter, nach dem sich nichts sichtbar ändert, wirkt kaputt. */
.plan-feld.verborgen {
  opacity: .38; border-style: dotted;
  background: repeating-linear-gradient(45deg, rgba(0,0,0,.22) 0 6px, rgba(0,0,0,.06) 6px 12px);
}
/* Der Griff zum Drehen sitzt oben LINKS — der zum Vergrössern unten rechts. Zwei Griffe an
   derselben Ecke wären zwei Bedeutungen für einen Fingerbreit. */
.plan-drehen {
  position: absolute; top: 2px; left: 2px; width: 22px; height: 22px; border-radius: 5px;
  background: rgba(0, 0, 0, .35); border: 1px solid rgba(255, 255, 255, .8); cursor: pointer;
  display: flex; align-items: center; justify-content: center; padding: 0; color: #fff;
  font: inherit; font-size: 13px; line-height: 1;
}
.plan-drehen:hover { background: rgba(0, 0, 0, .6); }
.plan-name { font-weight: 700; font-size: var(--fs-sm); line-height: 1.1; }
.plan-art  { font-size: var(--fs-xs); opacity: .85; line-height: 1.1; }
/* Bei sehr vielen Feldern wird die Kachel zu klein für zwei Zeilen — dann bleibt der Name. */
@media (max-width: 560px) { .plan-art { display: none; } }

/* Was gerade gesucht wurde. Zwei Sekunden, dann ist es wieder ruhig: ein dauerhaft leuchtendes
   Feld sähe beim nächsten Blick aus wie eine Eigenschaft des Feldes. */
@keyframes leuchten {
  0%, 70% { box-shadow: 0 0 0 4px var(--akzent); background: rgba(0, 0, 0, .42); }
  100%    { box-shadow: 0 0 0 0 transparent; }
}
.plan-feld.leuchtet { animation: leuchten 2s ease-out; }
.spiel.leuchtet { animation: leuchten-zeile 2s ease-out; }
@keyframes leuchten-zeile {
  0%, 70% { background: var(--akzent-bg); }
  100%    { background: transparent; }
}
.feldplan-bild { display: block; width: 100%; height: auto; border-radius: 10px; }
.feldplan-fuss { margin: 8px 0 0; }
/* Die Pause zwischen zwei Durchgängen. Sie steht ZWISCHEN den Karten, nicht in einer:
   am Platz ist sie der Weg vom einen Feld zum nächsten, kein Programmpunkt. */
.pausen-zeile {
  display: flex; align-items: center; gap: 10px; margin: 2px 0 14px;
  color: var(--text2); font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: .05em; font-weight: 650;
}
.pausen-zeile::before, .pausen-zeile::after {
  content: ''; flex: 1; height: 1px; background: var(--linie);
}
/* Ein Hinweis, der eine HANDLUNG verlangt — nicht bloss erklärt. Deshalb farbig und mit
   Rand: er soll sich von den erklärenden Sätzen darüber unterscheiden. */
.veraltet { color: var(--rot); border-left: 3px solid var(--rot); padding-left: 10px; }
/* Der Feldname an einer Partie ist beim Spielfest ein Knopf — er führt in den Plan. Er soll
   trotzdem aussehen wie die Marke, die er vorher war. */
button.marke-chip { border: 0; cursor: pointer; font-family: inherit; }
button.marke-chip:hover { background: var(--akzent-bg); color: var(--akzent); }

/* ── Die Tabelle ───────────────────────────────────────────────────────── */

.tabelle-huelle { overflow-x: auto; }
table.liga { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
table.liga th {
  font-size: var(--fs-xs); font-weight: 650; color: var(--text2);
  text-transform: uppercase; letter-spacing: .04em;
  padding: 9px 6px; border-bottom: 1px solid var(--linie); text-align: right; white-space: nowrap;
}
table.liga th.links, table.liga td.links { text-align: left; }
table.liga td { padding: 0 6px; height: 46px; border-bottom: 1px solid var(--linie); text-align: right; white-space: nowrap; }
table.liga tbody tr:last-child td { border-bottom: none; }
table.liga tr.hebt td { background: var(--akzent-bg); }

td.platz { width: 44px; padding-left: 14px; font-weight: 650; color: var(--text2); text-align: left; }
td.verein { text-align: left; width: 99%; }
.verein-zelle { display: flex; align-items: center; gap: 10px; }
.wappen {
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-2xs); font-weight: 800; color: #fff; letter-spacing: -.02em;
  background: var(--text3);
}
.verein-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
td.punkte { font-weight: 750; font-size: var(--fs-lg); padding-right: 14px; }
td.dezent { color: var(--text2); }

.bewegung { display: inline-block; width: 12px; font-size: var(--fs-2xs); margin-right: 2px; }
.bewegung.hoch { color: var(--gruen); }
.bewegung.runter { color: var(--rot); }
.bewegung.gleich { color: var(--text3); }

.form-punkte { display: inline-flex; gap: 3px; }
.form-punkt {
  width: 17px; height: 17px; border-radius: 5px; font-size: var(--fs-2xs);
  font-weight: 750; color: #fff; display: inline-flex; align-items: center; justify-content: center;
}
.form-punkt.S { background: var(--gruen); }
.form-punkt.U { background: var(--text3); }
.form-punkt.N { background: var(--rot); }

/* Zeilen, die den Platz wechseln, gleiten dorthin. Ohne das springt an einem
   Spieltag die halbe Tabelle, und niemand sieht, WER sich bewegt hat. */
table.liga tbody tr { transition: transform .55s cubic-bezier(.22,.61,.36,1); }
table.liga tbody tr.frisch td { animation: aufblitzen 2.2s ease-out; }
@keyframes aufblitzen {
  0%, 20% { background: var(--gruen-bg); }
  100% { background: transparent; }
}

/* ── Spiele ────────────────────────────────────────────────────────────── */

.spiel-liste { display: flex; flex-direction: column; }
/* minmax(0, 1fr) statt 1fr: derselbe Grund wie beim Gitter oben — eine 1fr-Spalte wird nicht
   schmaler als ihr längster Mannschaftsname, und dann ist die Zeile drei Pixel zu breit und das
   Torfeld daneben gequetscht. Mit minmax(0,…) darf der Name umbrechen. */
.spiel {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center; gap: 12px;
  padding: 11px 16px; border-bottom: 1px solid var(--linie);
}
.spiel:last-child { border-bottom: none; }
.spiel .heim { text-align: right; }
.spiel .gast { text-align: left; }
.spiel .mannschaft { display: flex; align-items: center; gap: 8px; font-weight: 550; min-width: 0; }
.spiel .heim .mannschaft { justify-content: flex-end; }
.spiel .mannschaft span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ergebnis {
  min-width: 62px; text-align: center; font-weight: 750; font-size: var(--fs-lg);
  font-variant-numeric: tabular-nums; padding: 3px 9px; border-radius: var(--r-sm);
  background: var(--flaeche3);
}
.ergebnis.offen { color: var(--text3); font-weight: 550; font-size: var(--fs-md); background: transparent; }
.ergebnis.laeuft { background: var(--gruen); color: #fff; }

/* Nur für Vorleseprogramme: sichtbar für sie, unsichtbar auf dem Bildschirm. Gebraucht,
   wo eine Auskunft in einer Farbe oder einer Bewegung steckt — beides hört niemand. */
.nur-vorlesen {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ── „Läuft gerade" ────────────────────────────────────────────────────────
   ⬛ Vom Nutzer gewünscht: ein Ball, der zeigt, dass hier JETZT gespielt wird — damit ein
   Zuschauer die laufenden Partien auf einen Blick findet, statt Anstosszeiten mit der Uhr zu
   vergleichen.

   Gezeichnet mit CSS und nicht als Symbol aus `icons.json`: Das Ding bewegt sich, gehört also
   ohnehin ins Stilblatt — und ein Emoji (⚽) wäre bunt, auf jedem Gerät anders und hier
   ausdrücklich nicht erwünscht. Der Ball ist ein Kreis mit fünf Flecken. */
.ball-laeuft {
  display: inline-block; width: 14px; height: 14px; flex: none; border-radius: 50%;
  background:
    radial-gradient(circle at 50% 34%, var(--text) 0 2.4px, transparent 2.6px),
    radial-gradient(circle at 22% 62%, var(--text) 0 1.7px, transparent 1.9px),
    radial-gradient(circle at 78% 62%, var(--text) 0 1.7px, transparent 1.9px),
    radial-gradient(circle at 34% 96%, var(--text) 0 1.5px, transparent 1.7px),
    radial-gradient(circle at 66% 96%, var(--text) 0 1.5px, transparent 1.7px),
    var(--gruen);
  box-shadow: 0 0 0 0 rgba(26, 156, 75, .55);
  animation: ball-pulst 1.8s ease-out infinite;
  vertical-align: -2px;
}
@keyframes ball-pulst {
  0%   { box-shadow: 0 0 0 0 rgba(26, 156, 75, .55); }
  70%  { box-shadow: 0 0 0 9px rgba(26, 156, 75, 0); }
  100% { box-shadow: 0 0 0 0 rgba(26, 156, 75, 0); }
}
/* ⬛ Wer Bewegung abgestellt hat, bekommt keine: Die Auskunft „läuft" darf nicht an der
   Animation hängen — sie steht in der Farbe und im Text daneben. */
/* ── Das Laufband ──────────────────────────────────────────────────────────
   ⬛ Vom Nutzer beauftragt: ein Banner, der durchs Bild geht. Er steht ÜBER allem, in der
   Warnfarbe und über die volle Breite — wer die Seite öffnet, soll ihn nicht suchen.

   Kein Rot: Ein Hinweis „wir unterbrechen bis 14 Uhr" ist eine Auskunft, keine Katastrophe.
   Rot wäre eine Aufregung, die nach dem dritten Mal niemand mehr ernst nimmt. */
.laufband {
  position: relative; overflow: hidden; margin: 0 0 14px; padding: 9px 0;
  background: var(--gelb-bg, #fff8e6); border: 1px solid var(--gelb);
  border-radius: var(--r-sm); color: var(--text);
}
.laufband-bahn {
  display: flex; gap: 64px; width: max-content;
  animation: laufband-zug linear infinite;
}
/* Der Weg eines Durchlaufs — die Breite EINES Stücks, vom Browser gerechnet. */
.laufband-bahn { --laufband-weg: -50%; }
.laufband-text { white-space: nowrap; font-weight: 650; font-size: var(--fs-md); }
@keyframes laufband-zug {
  from { transform: translateX(0); }
  /* Genau ein Stück weit — danach steht dasselbe Wort wieder an derselben Stelle, und der
     Rücksprung ist nicht zu sehen. */
  to   { transform: translateX(var(--laufband-weg)); }
}
/* ⬛ Wer Bewegung abgestellt hat, bekommt den Satz trotzdem — nur eben still und umgebrochen.
   Eine Auskunft, die an einer Animation hängt, ist für ihn keine. */
@media (prefers-reduced-motion: reduce) {
  .laufband-bahn { animation: none; width: 100%; }
  .laufband-text { white-space: normal; }
  .laufband-text[aria-hidden="true"] { display: none; }
}
/* Auf der Anzeigetafel im Vereinsheim gross genug für fünf Meter Abstand. */
.tafel .laufband-text { font-size: clamp(1.1rem, 2.2vw, 2rem); }

/* ── Der Vereinskalender ───────────────────────────────────────────────────
   ⬛ Vom Nutzer beauftragt: „einmal als klassische Kalenderform, andererseits als Liste."
   Das Monatsblatt ist ein Gitter aus sieben Spalten; am Handy schrumpfen die Zellen mit, statt
   zu scrollen — eine Woche muss nebeneinander stehen, sonst ist es kein Kalender mehr. */
.kalender-kopf {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
}
.kalender-werkzeuge { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.kalender-gitter {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px;
  background: var(--linie); border-radius: 12px; overflow: hidden;
}
.kalender-wochentag {
  background: var(--flaeche2); padding: 6px 8px; font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--text3); text-align: center;
}
.kalender-tag {
  background: var(--flaeche); min-height: 96px; padding: 5px 5px 7px;
  display: flex; flex-direction: column; gap: 3px;
}
/* Tage des Nachbarmonats gehören dazu, aber nicht in den Vordergrund. */
.kalender-tag.fremd { background: var(--flaeche2); }
.kalender-tag.fremd .kalender-zahl { color: var(--text3); }
.kalender-tag.heute { box-shadow: inset 0 0 0 2px var(--akzent); }
.kalender-zahl { font-size: var(--fs-xs); font-weight: 700; color: var(--text2); }
.kalender-eintrag {
  display: block; width: 100%; text-align: left; border: 0; cursor: pointer;
  background: var(--akzent-bg); color: var(--text); border-left: 3px solid var(--akzent);
  border-radius: 4px; padding: 2px 5px; font-size: var(--fs-xs); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Ein Vereinseintrag sieht anders aus als ein Mannschaftstermin — es sind zwei Dinge:
   das eine fragt „kommst du?", das andere sagt etwas. */
.kalender-eintrag.verein { background: var(--gruen-bg); border-left-color: var(--gruen); }
.kalender-eintrag.info { border-left-style: dotted; }
.kalender-liste .kalender-eintrag {
  white-space: normal; cursor: default; padding: 9px 12px; border-radius: 0;
  border-bottom: 1px solid var(--linie); background: none; border-left-width: 4px;
}
.kalender-liste .kalender-eintrag.verein { background: var(--gruen-bg); }
.kalender-liste .kalender-eintrag:last-child { border-bottom: none; }
.kalender-zeile { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.kalender-titel { font-weight: 650; }
@media (max-width: 640px) {
  .kalender-tag { min-height: 68px; padding: 3px; }
  .kalender-eintrag { font-size: 10px; padding: 1px 3px; }
}

/* ── Turnierleitung ────────────────────────────────────────────────────────────────────
   ⬛ Vom Nutzer beauftragt: „Optimiert für Handys, Pads, aber auch Monitore." Deshalb keine
   festen Spalten, sondern ein Raster, das sich selbst einteilt: ein Platz je Zeile am Handy,
   zwei auf dem Tablet, vier auf dem Fernseher. Und grosse Tasten — bedient wird das hier im
   Stehen, mit einer Hand, oft mit kalten Fingern. */
/* ⬛ Auf einem Monitor im Vereinsheim wären 1000 px zwei Kacheln und viel Weiss. Die Leitung
   darf deshalb breiter werden als jede andere Seite — sie ist die einzige, die mit jeder
   zusätzlichen Spalte tatsächlich mehr sagt: einen Platz mehr auf einen Blick. */
main.leitung-seite { max-width: 1800px; }

.leitung-kopf {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
}
.leitung-werkzeuge { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.leitung-felder {
  display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  align-items: start;
}
.leitung-feld { margin: 0; }

/* Die laufende Partie ist das Grösste auf dem Bildschirm — sie ist der Grund, warum jemand
   hersieht. */
.laeuft-block { padding: 12px 14px; border-bottom: 1px solid var(--linie); background: var(--gruen-bg); }
.laeuft-zeile { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.laeuft-uhr {
  margin-left: auto; font-size: var(--fs-sm); font-weight: 650; color: var(--text2);
  font-variant-numeric: tabular-nums;
}
/* Über der Zeit: die einzige Stelle, an der die Leitung rot sein darf — hier hängt der ganze
   Tagesplan dran. */
.laeuft-uhr.drueber { color: var(--rot); }

.stand-reihe { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: start; }
.stand-seite { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.stand-name { font-size: var(--fs-sm); font-weight: 650; line-height: 1.2; }
.stand-tore { font-size: 40px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.stand-doppelpunkt { font-size: 32px; font-weight: 700; color: var(--text2); padding-top: 34px; }
.stand-tasten { display: flex; gap: 6px; }
/* 44 px ist die kleinste Fläche, die ein Daumen zuverlässig trifft — darunter zählt man
   irgendwann ein Tor für die falsche Mannschaft. */
.knopf.gross { min-height: 44px; min-width: 44px; font-size: var(--fs-md); padding: 0 16px; }
.leitung-knoepfe { display: flex; gap: 8px; margin-top: 10px; }
.leitung-knoepfe .knopf { flex: 1; }

.leitung-liste { border-bottom: 1px solid var(--linie); }
.leitung-liste:last-child { border-bottom: none; }
.leitung-abschnitt {
  padding: 8px 14px 4px; font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text2);
}
summary.leitung-abschnitt { cursor: pointer; }
.leitung-zeile {
  display: flex; align-items: center; gap: 8px; padding: 8px 14px; flex-wrap: wrap;
  border-top: 1px solid var(--linie);
}
.leitung-partie { display: flex; align-items: baseline; gap: 8px; flex: 1 1 150px; min-width: 0; }
.leitung-zeit { font-variant-numeric: tabular-nums; font-weight: 650; white-space: nowrap; }
.leitung-namen { font-size: var(--fs-sm); color: var(--text2); overflow-wrap: anywhere; }
.leitung-ergebnis { font-weight: 700; font-variant-numeric: tabular-nums; }
/* Was gelaufen ist, tritt zurück — es steht da, um nachgesehen zu werden, nicht um zu rufen. */
.leitung-liste.fertig .leitung-zeile { opacity: .72; }

/* ⬛ Die Umschalter der Altersgruppen über einem Turnier: U9 · U10 · U11.
   Waagerecht scrollbar statt umbrechend — bei acht Klassen wäre eine zweite Zeile am Handy die
   halbe Seite, und der Rest rutschte aus dem Blick. Die gewählte Klasse steht kräftig da:
   Wer sie nicht erkennt, hält das Gefilterte für alles, was es gibt. */
.klassen-leiste {
  display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 16px;
  scrollbar-width: thin;
}
.klassen-knopf {
  flex: none; height: 34px; padding: 0 14px; border-radius: 17px;
  border: 1px solid var(--linie); background: var(--flaeche); color: var(--text2);
  font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
}
.klassen-knopf:hover { border-color: var(--akzent); color: var(--akzent); }
.klassen-knopf.an {
  background: var(--akzent); border-color: var(--akzent); color: #fff;
}

/* ⬛ Ein Auswahlfeld, in dem noch nichts steht, obwohl etwas stehen MUSS: die Altersgruppe
   einer gemeldeten Mannschaft. Ohne sie spielt sie nirgends mit — und das würde sonst erst am
   Spieltag auffallen. Kein Rot: Es ist eine offene Aufgabe, kein Fehler. */
select.fehlt { border-color: var(--gelb); color: var(--gelb); }

/* ⬛ Der Verzug — die zweite Uhrzeit hinter der geplanten.

   Sie steht in der Warnfarbe und nicht in Rot: Ein Platz, der zehn Minuten hinterherhängt, ist
   der Normalfall eines Turniertags und kein Fehler. Rot wäre eine Aufregung, die niemandem
   hilft. Zahlen in Tabellenziffern, damit „→ 10:34" unter „→ 9:05" nicht verrutscht. */
.verzug {
  display: inline-block; margin-left: 4px; padding: 0 6px; border-radius: 8px;
  background: var(--gelb-bg, var(--flaeche3)); color: var(--gelb, var(--text2));
  font-size: var(--fs-xs); font-weight: 650; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Früher als geplant ist keine Warnung, sondern eine Auskunft — deshalb im ruhigen Grün. */
.verzug.frueher { background: var(--gruen-bg); color: var(--gruen); }
.marke-chip.verzug-chip { background: var(--gelb-bg, var(--flaeche3)); color: var(--gelb, var(--text2)); }
.marke-chip.verzug-chip.frueher { background: var(--gruen-bg); color: var(--gruen); }

@media (prefers-reduced-motion: reduce) {
  .ball-laeuft { animation: none; }
}

/* ── Erfassung (Handy zuerst) ──────────────────────────────────────────── */

.erfassung .spiel { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); padding: 14px 16px; }
/* ⬛ `input.tor-feld` und nicht `.tor-feld`: die allgemeine Regel weiter oben
   (`input[type=number] { width: 100% }`) ist spezifischer als eine blosse Klasse und hat die
   54 px stillschweigend überstimmt. Aufgefallen ist es erst, als das Feld in einen breiten
   Kasten wanderte und plötzlich die halbe Zeile einnahm. */
input.tor-feld {
  width: 54px; height: 46px; text-align: center; font-size: var(--fs-xl);
  font-weight: 700; padding: 0; font-variant-numeric: tabular-nums;
}
.tor-trenner { color: var(--text3); font-weight: 700; padding: 0 2px; }
.erfass-mitte { display: flex; align-items: center; gap: 6px; }
.gespeichert { color: var(--gruen); font-size: var(--fs-sm); font-weight: 600; }

.stapel { display: flex; flex-direction: column; gap: 10px; }
.eintrag {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  background: var(--flaeche); border: 1px solid var(--linie); border-radius: var(--r-md);
  /* ⬛ Umbrechen statt überlaufen. Gemessen am Handy: Ein Verein mit zwei Merkzeichen und
     einer Kennung brauchte 520 px in einer 351 px breiten Zeile — der Rest stand ausserhalb
     des Fensters, und die ganze SEITE liess sich seitwärts schieben. `min-width: 0` allein
     hilft nicht: Chips schrumpfen nicht, sie sind so breit wie ihr Wort. */
  flex-wrap: wrap; row-gap: 6px;
}
/* Steht ein Eintrag IN einer Karte, ist er eine Zeile und kein zweiter Kasten: Rahmen im
   Rahmen mit doppelt gerundeten Ecken sieht aus wie ein Fehler. Getrennt wird mit einer Linie,
   wie überall sonst auch. */
.karte > .eintrag,
.karte > div > .eintrag {
  border: none; border-radius: 0; border-top: 1px solid var(--linie); background: none;
}
.karte > .eintrag:first-child,
.karte > div > .eintrag:first-child { border-top: none; }
a.eintrag:hover { background: var(--flaeche2); }

.eintrag .haupt { flex: 1; min-width: 0; }
/* Eine E-Mail-Adresse ist ein einziges „Wort" — ohne diese Zeile schiebt sie die Zeile
   auseinander oder läuft unter das Feld daneben. */
.eintrag .haupt small { overflow-wrap: anywhere; }
/* In einer schmalen Spalte hat neben dem Namen kein Auswahlfeld mehr Platz. Statt beides
   zusammenzuquetschen, rutscht das Feld unter den Namen und nimmt die volle Breite. */
.eintrag.gestapelt { flex-wrap: wrap; }
.eintrag.gestapelt .haupt { flex: 1 1 100%; }
.eintrag.gestapelt select { flex: 1 1 100%; width: 100%; }

/* Eine Zeile der Nutzerverwaltung: Name, Rolle, Zustand. Die Rollennamen sind lang („Verbands-
   Administrator (alle Wettbewerbe)"), und ein festes Feld daneben schiebt am Handy die halbe
   Zeile aus dem Bild. Unter 620 px steht deshalb alles untereinander. */
.stab-zeile { grid-template-columns: 1fr auto auto; }
.stab-zeile select { width: 240px; }
@media (max-width: 620px) {
  .stab-zeile { grid-template-columns: 1fr; gap: 8px; }
  .stab-zeile select { width: 100%; }
  .stab-zeile > .marke-chip { justify-self: start; }
}
.eintrag .haupt b { display: block; font-weight: 620; }
/* ⬛ Der Name ist ein eigener Block — die Unterzeile darf aber etwas hervorheben, ohne
   dafür eine Zeile zu bekommen. Ohne diese Regel stand die Entfernung allein auf einer
   Zeile, mitten zwischen Ortsname und Kennung. */
.eintrag .haupt small b { display: inline; font-weight: 640; }
.eintrag .haupt small { color: var(--text2); }

/* ── Klappbare Abschnitte ──────────────────────────────────────────────────
   Bei drei Mannschaften mit je zwanzig Spielern ist die Seite zwei Bildschirme
   lang, bevor man die zweite Mannschaft überhaupt sieht. Der Kopf bleibt, der
   Inhalt klappt weg. */

.klapp-kopf { cursor: pointer; user-select: none; }
.klapp-kopf:hover { background: var(--flaeche3) !important; }
/* Der Pfeil ist das einzige Bedienelement des Kopfes — als Zeichen „▾" war er ein Fussel
   neben einer 15-px-Überschrift, und wie gross ein Zeichen ausfällt, entscheidet die Schrift
   des Geräts, nicht diese Datei. Deshalb GEZEICHNET: zwei Kanten eines Quadrats, um 45° gedreht.
   Die Grösse steht damit in Pixeln fest und die Strichstärke auch. */
.klapp-pfeil {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text2); width: 24px; height: 24px; margin-left: -3px; flex: none;
  transition: transform .15s ease; transform-origin: 50% 50%;
}
.klapp-pfeil::before {
  content: ''; width: 9px; height: 9px; margin-top: -4px;
  border-right: 2.2px solid currentColor; border-bottom: 2.2px solid currentColor;
  border-radius: 1px; transform: rotate(45deg);
}
.klapp-kopf:hover .klapp-pfeil { color: var(--text); }
.klapp-kopf.zu .klapp-pfeil { transform: rotate(-90deg); }

@media (pointer: coarse) {
  .klapp-pfeil { width: 30px; height: 30px; }
  .klapp-pfeil::before { width: 11px; height: 11px; border-width: 2.5px; }
}

/* ── Das „i" neben einer Überschrift ───────────────────────────────────────
   Klein und ruhig: es soll auffindbar sein, wenn man es sucht, und nicht mit der Überschrift
   um Aufmerksamkeit streiten. */
.hilfe-knopf {
  flex: 0 0 auto; width: 17px; height: 17px; border-radius: 50%;
  border: 1px solid var(--linie); background: none; color: var(--text3);
  font-size: 11px; font-weight: 700; font-family: Georgia, 'Times New Roman', serif;
  font-style: italic; line-height: 1; cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 6px; vertical-align: middle;
}
.hilfe-knopf:hover { border-color: var(--akzent); color: var(--akzent); background: var(--flaeche2); }
/* ⬛ Beim systemweiten Durchgang durch die Knöpfe gemessen: Das „i" war mit 22 × 22 Pixeln der
   einzige Knopf im ganzen System unter der Grenze, ab der ein Daumen zuverlässig trifft — und
   es steht an jeder zweiten Überschrift.
   Vergrössert wird deshalb die TREFFFLÄCHE, nicht das Symbol: Ein „i", das so gross ist wie
   eine Schaltfläche, zieht Aufmerksamkeit auf sich, die der Überschrift daneben gehört. Das
   Pseudoelement legt sich unsichtbar darüber und macht aus 22 Pixeln 44. */
@media (pointer: coarse) {
  .hilfe-knopf { width: 22px; height: 22px; font-size: 13px; position: relative; }
  .hilfe-knopf::after { content: ''; position: absolute; inset: -11px; }
}

.hilfe-beispiel {
  margin-top: 14px; padding: 12px 14px; border-radius: var(--r-md);
  background: var(--flaeche2); border: 1px solid var(--linie);
}
.hilfe-beispiel b { display: block; font-size: var(--fs-xs); text-transform: uppercase;
                    letter-spacing: .05em; color: var(--text2); margin-bottom: 6px; }

.zaehlleiste { display: flex; gap: 18px; flex-wrap: wrap; padding: 14px 16px; border-bottom: 1px solid var(--linie); }
.zaehler b { display: block; font-size: var(--fs-xl); font-weight: 700; }
.zaehler span { font-size: var(--fs-xs); color: var(--text2); text-transform: uppercase; letter-spacing: .04em; }

.live-punkt { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--text2); }
.live-punkt i { width: 7px; height: 7px; border-radius: 50%; background: var(--gruen); display: inline-block; }
.live-punkt.aus i { background: var(--text3); }
.live-punkt.aktiv i { animation: pulsieren 1.8s ease-in-out infinite; }
@keyframes pulsieren { 50% { opacity: .25; } }

/* ── Kästen (Dialoge) ──────────────────────────────────────────────────────
   ⬛ Der Kasten wächst bis fast zur Bildschirmhöhe, und gescrollt wird IN ihm —
   nicht in einer Liste darin. Vorher hatte jede Liste ihre eigene Höhengrenze
   (46vh), wodurch am Handy zwei Drittel des Kastens leer blieben und die Liste
   trotzdem mitten in einer Zeile abschnitt. `dvh` statt `vh`, weil die Leisten
   mobiler Browser ein- und ausfahren und `vh` dabei zu gross rechnet. */

dialog {
  border: none; border-radius: var(--r-lg); background: var(--flaeche); color: var(--text);
  padding: 0; box-shadow: var(--schatten); max-width: 460px; width: calc(100% - 32px);
  max-height: 88dvh;
}
/* Nur der GEÖFFNETE Dialog ist eine Spalte. Steht „display" am nackten
   dialog, schlägt es die Browserregel dialog:not([open]) { display: none }
   — dann steht jeder geschlossene Dialog offen auf der Seite. */
/* margin:auto zentriert den Dialog im Bild — der Stern-Reset oben setzt
   margin auf 0 und nimmt dem Browser genau diese Regel weg. */
dialog[open] { display: flex; flex-direction: column; margin: auto; }
dialog::backdrop { background: rgba(0,0,0,.45); backdrop-filter: blur(3px); }
dialog .karte-kopf, dialog .fuss { flex: none; }
dialog .karte-koerper { padding: 18px; overflow-y: auto; flex: 1 1 auto; }
dialog .fuss { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end;
               padding: 14px 18px 18px;
               border-top: 1px solid var(--linie); background: var(--flaeche); }
/* ⬛ `flex-wrap` ist hier kein Schönheitswunsch: Im Einstellungsfenster steht links
   „Wettbewerb löschen" und rechts Abbrechen und Speichern. Am Handy passte das nicht in eine
   Zeile — der linke Knopf lief aus dem Fenster heraus und stand als „ettbewerb löschen" da.
   Aufgefallen ist es erst, als ihn nicht mehr nur der Verband zu sehen bekam, der am Rechner
   sitzt. */

/* ── Finger statt Zeiger ───────────────────────────────────────────────────
   Auf einem Berührungsbildschirm gibt es kein „darüberfahren" und keine Feinmotorik:
   ein 28 Pixel hoher Knopf wird zur Geduldsprobe. */
@media (pointer: coarse) {
  .knopf.klein { height: 36px; padding: 0 12px; }
  .knopf.symbol.klein { width: 36px; }
  input[type=checkbox] { width: 20px; height: 20px; }
  dialog { max-width: none; width: calc(100% - 20px); }
}

@media (max-width: 680px) {
  main { padding: 16px 12px 70px; }
  .kopf-innen { padding: 0 12px; }
  h1.titel { font-size: 22px; }
  table.liga td.verbergen-klein, table.liga th.verbergen-klein { display: none; }
  td.platz { width: 34px; padding-left: 10px; }
  .spiel { padding: 12px; gap: 8px; }
  /* Am Handy bleiben von „Witterschlick" 56 Pixel übrig — mit Auslassungspunkten heisst das
     „Witters…", und am Spielfeldrand weiss dann niemand, wer gegen wen spielt. Lieber zwei
     Zeilen als ein abgeschnittener Name.
     `break-word` und NICHT `anywhere`: anywhere darf mitten im Wort trennen, und dann steht da
     „RW Lessenic / h 1". So wird an Leerzeichen umgebrochen und nur ein Wort getrennt, das
     allein nicht passt. */
  .spiel .mannschaft span {
    white-space: normal; overflow-wrap: break-word; line-height: 1.25; min-width: 0;
  }
  /* Die Torfelder etwas schmaler: jeder Punkt, den sie hergeben, ist ein Punkt mehr für die
     Namen daneben — und 46 sind mit dem Daumen genauso gut zu treffen wie 54. */
  input.tor-feld { width: 46px; }

  /* ⬛ In der ERFASSUNG reicht auch das nicht: Name, Wappen, zwei Torfelder, Wappen, Name
     nebeneinander lassen je Namen rund 70 Punkte — „Witterschlick" braucht 97 und bricht
     mitten im Wort. Deshalb hier zwei Zeilen: die Namen aussen nebeneinander, die Torfelder
     darunter in der Mitte. Jeder Name hat dann rund 150 Punkte und steht am Stück da. */
  .erfassung .spiel {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); row-gap: 10px;
  }
  .erfassung .spiel > .heim { grid-column: 1; grid-row: 1; text-align: left; }
  .erfassung .spiel > .gast { grid-column: 2; grid-row: 1; text-align: right; }
  .erfassung .spiel > .heim .mannschaft { justify-content: flex-start; }
  .erfassung .spiel > .gast .mannschaft { justify-content: flex-end; }
  .erfassung .spiel > .erfass-mitte { grid-column: 1 / -1; grid-row: 2; justify-content: center; }
}

/* ── Turnierbaum ───────────────────────────────────────────────────────────
   Die Runden stehen nebeneinander und scrollen waagerecht, wenn es eng wird.
   Ein Baum, der sich auf dem Handy in die Breite quetscht, ist unlesbar; einer,
   den man schiebt, bleibt lesbar. */

.baum { display: flex; gap: 18px; overflow-x: auto; padding: 16px; align-items: stretch; }
.baum-runde { flex: 0 0 240px; display: flex; flex-direction: column; }
.baum-runde > h3 {
  font-size: var(--fs-xs); font-weight: 650; color: var(--text2);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px; text-align: center;
}
.baum-spiele { flex: 1; display: flex; flex-direction: column; justify-content: space-around; gap: 10px; }
.baum-spiel {
  border: 1px solid var(--linie); border-radius: var(--r-md); overflow: hidden;
  background: var(--flaeche2);
}
.baum-seite {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  font-size: var(--fs-md); border-bottom: 1px solid var(--linie);
}
.baum-seite:last-child { border-bottom: none; }
.baum-seite .wappen { width: 20px; height: 20px; border-radius: 5px; font-size: 8px; }
.baum-seite .nam { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.baum-seite .tor { font-weight: 750; font-variant-numeric: tabular-nums; color: var(--text2); }
.baum-seite.gewinnt { background: var(--gruen-bg); }
.baum-seite.gewinnt .nam { font-weight: 700; }
.baum-seite.gewinnt .tor { color: var(--gruen); }
.baum-seite.leer { color: var(--text3); font-style: italic; }

/* ── Wappen mit echtem Logo ────────────────────────────────────────────────
   Kein farbiger Grund mehr: ein Logo bringt seinen eigenen mit, und ein zweiter
   dahinter macht aus einem freigestellten Wappen eine Briefmarke.
   `contain` statt `cover`, weil Zuschneiden bei einem Wappen genau das wegnimmt,
   worauf es ankommt. */

.wappen.mit-logo { background: transparent; }
.wappen img { width: 100%; height: 100%; object-fit: contain; display: block; }
.wappen.gross {
  width: 52px; height: 52px; border-radius: 14px; font-size: var(--fs-lg);
}
.wappen.anklickbar { cursor: pointer; position: relative; }
.wappen.anklickbar::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 2px var(--akzent); opacity: 0; transition: opacity .12s;
}
.wappen.anklickbar:hover::after { opacity: 1; }

/* ── Torschützen unter einer Partie ────────────────────────────────────────
   Zwei Spalten wie das Spiel darüber: was links steht, gehört der Heimelf. */

.torschuetzen {
  grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px 14px;
  margin-top: 6px; font-size: var(--fs-sm); color: var(--text2);
}
.torschuetze::before { content: '◂ '; color: var(--text3); }
.torschuetze.gast { margin-left: auto; }
.torschuetze.gast::before { content: ''; }
.torschuetze.gast::after { content: ' ▸'; color: var(--text3); }

/* Ein abgesagter Termin bleibt STEHEN, wird aber blass: wer schon zugesagt hat, soll sehen,
   dass er ausfällt. Ihn zu löschen hiesse, dass er kommentarlos verschwindet und die Hälfte
   der Mannschaft trotzdem am Platz steht. Keine Durchstreichung — der Text muss lesbar
   bleiben, es ist ja noch eine Auskunft. */
.termin-abgesagt { opacity: .62; }
.termin-abgesagt b { color: var(--text2); }

/* Das Foto eines Spielers. Klein in der Kaderliste, gross im Profil — beide Male rund und
   beschnitten: ein Porträt in einem Rechteck sieht in einer Liste aus wie ein Ausweisbild,
   und darum geht es hier nicht. Ohne Foto bleibt ein leerer Kreis stehen, damit die Zeilen
   nicht springen, sobald jemand eines hochlädt. */
.spielerbild {
  width: 32px; height: 32px; border-radius: 50%; overflow: hidden; flex: none;
  background: var(--flaeche3);
  /* In einer Rasterzelle dehnt sich ein Kasten sonst auf die Zeilenhöhe — aus dem Kreis würde
     ein Ei, sobald in der Zeile etwas Zweizeiliges steht. */
  align-self: center;
}
.spielerbild img { width: 100%; height: 100%; object-fit: cover; display: block; }
.spielerbild.gross { width: 96px; height: 96px; }
/* ⬛ NICHT `.leer`: so heisst schon der Kasten „hier steht noch nichts" mit 44 Pixeln
   Polsterung. Beides an einem Element machte aus dem Kreis ein 90 Pixel hohes Ei. */
.spielerbild.ohne { border: 1px dashed var(--linie); background: transparent; }
.profil-foto { display: flex; gap: 16px; align-items: center; margin: 0 0 16px; }
/* Der Erklärkasten zur Einwilligung. Kein Warnton — es ist keine Warnung, sondern die
   Auskunft, wohin diese Daten gehen. */
.einwilligung {
  margin: 4px 0 14px; padding: 12px 14px; border-radius: 12px;
  background: var(--flaeche3); border: 1px solid var(--linie);
  font-size: var(--fs-sm); color: var(--text2); line-height: 1.5;
}
.einwilligung p { margin: 0 0 8px; }
.einwilligung p:last-child { margin-bottom: 0; }

/* Eine Zeile in „wer kommt?". Enger als eine Spielzeile — es sind zwanzig Namen, und der
   Dialog soll ohne Scrollen so viele wie möglich zeigen. */
.antwort-zeile {
  display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center;
  padding: 9px 2px; border-bottom: 1px solid var(--linie);
}
.antwort-zeile:last-child { border-bottom: none; }
/* Die beiden Knöpfe am Termin im Elternbereich. Der gedrückte bleibt sichtbar gefärbt —
   sonst weiss man nach dem Neuladen nicht mehr, ob man geantwortet hat. */
.antwort-knoepfe { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.knopf.gewaehlt-ja { background: var(--gruen-bg); color: var(--gruen); border-color: var(--gruen); }
.knopf.gewaehlt-nein { background: var(--rot-bg); color: var(--rot); border-color: var(--rot); }

/* ── Zeilen, die am Handy nicht hinauslaufen dürfen ────────────────────────
   ⬛ Vom Nutzer am Handy gemeldet: „die Liste läuft nach rechts raus, und die Label sind
   verschoben." Zwei Ursachen, beide hier behoben:

   1. Eine Marke mit fester Höhe und umbrechendem Text wird zum Klotz — aus „0 VON 18" wurden
      zwei Zeilen in einem 22 Pixel hohen Kasten. `nowrap` heisst: eine Marke bricht NIE.
   2. Eine Rasterzeile mit `1fr` wird nicht schmaler als ihr längster Inhalt. Am Handy schob
      das die Knöpfe über den Rand hinaus. `minmax(0, …)` erlaubt der Spalte zu schrumpfen —
      und unter 700 Pixeln stapeln sich Datum, Inhalt und Knöpfe untereinander. */
.marke-chip { white-space: nowrap; flex: none; }

.termin-zeile {
  display: grid; grid-template-columns: 148px minmax(0, 1fr) auto; gap: 12px;
  align-items: start; padding: 11px 16px; border-bottom: 1px solid var(--linie);
}
.termin-zeile:last-child { border-bottom: none; }
.termin-wann { font-variant-numeric: tabular-nums; }
.termin-knoepfe { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
/* Die Angaben unter der Überschrift: Ort, Marken, Frist — nebeneinander, mit Abstand,
   und sie dürfen umbrechen statt zu schieben. */
.termin-unten {
  display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; margin-top: 3px;
}

@media (max-width: 700px) {
  .termin-zeile { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .termin-knoepfe { justify-content: flex-start; margin-top: 4px; }
  /* Das Datum steht dann ÜBER dem Termin und nicht mehr daneben — als Zeile gelesen, nicht
     als Spalte. */
  .termin-wann { display: flex; gap: 10px; align-items: baseline; }
  .termin-wann small { display: inline !important; }
}
/* Eine Terminzeile ohne Knopfspalte (Elternbereich): zwei Spalten statt drei. */
.termin-zeile.ohne-knoepfe { grid-template-columns: 148px minmax(0, 1fr); }
@media (max-width: 700px) {
  .termin-zeile.ohne-knoepfe { grid-template-columns: minmax(0, 1fr); }
}

/* ── Suchfeld über einer langen Liste ──────────────────────────────────────
   Es sitzt IN der Liste und nicht im Kartenkopf: dort stehen die Knöpfe, und am Handy wäre
   die Kopfzeile mit Zähler, Knopf und Suchfeld drei Zeilen hoch, bevor eine einzige Zeile
   der Liste zu sehen ist. */
.such-zeile {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 16px; border-bottom: 1px solid var(--linie);
  background: var(--flaeche2);
}
.such-zeile input {
  flex: 1; min-width: 0; height: 36px; padding: 0 12px;
  border: 1px solid var(--linie); border-radius: var(--r-sm);
  background: var(--flaeche); color: var(--text); font: inherit; font-size: var(--fs-md);
}
.such-zeile input:focus { outline: 2px solid var(--akzent); outline-offset: -1px; }
.such-zeile .hinweis { flex: none; font-variant-numeric: tabular-nums; }
.such-leer { padding: 28px 16px; }

/* ── Eine Kaderzeile ───────────────────────────────────────────────────────
   ⬛ Flexbox mit Umbruch statt Raster. Als Raster brauchte sie für jede Kombination aus Foto,
   Toren und Knöpfen eine eigene Spaltenangabe — vier waren es —, und am Handy passte keine
   davon: dort überlappten Name und Marke. Was nicht mehr hinpasst, rutscht jetzt einfach in
   die nächste Zeile. */
.kader-zeile {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 16px; border-bottom: 1px solid var(--linie);
}
.kader-zeile:last-child { border-bottom: none; }
.kader-zeile .k-nummer {
  width: 26px; flex: none; text-align: center; font-weight: 750; color: var(--text2);
  font-variant-numeric: tabular-nums;
}
/* Der Name darf schrumpfen, aber nicht unter eine lesbare Breite — darunter bricht die Zeile
   lieber um. */
.kader-zeile .k-name { flex: 1 1 150px; min-width: 0; }
.kader-zeile .k-knoepfe { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }

/* ── Der Zählzettel ────────────────────────────────────────────────────────
   Er wird ausgedruckt und ans Tor gehängt. Alles darauf ist so gross, dass man es aus zwei
   Metern liest — und beim Drucken bleibt nur der Zettel übrig. */
.zettel {
  max-width: 520px; margin: 0 auto; padding: 30px 24px 34px; text-align: center;
  background: var(--flaeche); border: 1px solid var(--linie); border-radius: var(--r-lg);
}
.zettel-oben { margin: 0; color: var(--text2); font-size: var(--fs-sm); }
.zettel-ort { margin: 4px 0 20px; font-size: 34px; font-weight: 800; letter-spacing: -.02em; }
.zettel-qr { display: flex; justify-content: center; }
.zettel-qr svg { width: 260px; height: 260px; }
.zettel-anleitung { margin: 18px 0 6px; color: var(--text2); font-size: var(--fs-sm); }
.zettel-code {
  margin: 0; font-size: 40px; font-weight: 800; letter-spacing: .16em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.zettel-klein { margin: 18px 0 0; color: var(--text3); font-size: var(--fs-xs); line-height: 1.5; }
@media print {
  .kopf, .fuss, .rechtsfuss, .nicht-drucken, .menue-knopf { display: none !important; }
  .zettel { border: none; max-width: none; }
  .zettel-qr svg { width: 320px; height: 320px; }
  /* ⬛ Der Feldplan wird am Eingang aufgehängt: Er bekommt die ganze Seite, und die Farben
     müssen mitgedruckt werden — ohne `print-color-adjust` lässt der Browser den Rasen weiss,
     und übrig bleiben ein paar Rechtecke ohne Zusammenhang. */
  .druckblatt { max-width: none; }
  .druck-plan .rasen { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .druck-legende { column-count: 3; }
}

/* Eine Listenzeile mit Stern daneben: der Eintrag nimmt den Platz, der Stern steht fest. */
.eintrag-reihe { display: flex; align-items: center; gap: 2px; }
.eintrag-reihe > .eintrag { flex: 1 1 auto; min-width: 0; }

/* ── Die Anzeigetafel ──────────────────────────────────────────────────────
   ⬛ Für drei Entfernungen zugleich: Handy in der Hand, Tablet auf dem Tresen, Fernseher an
   der Wand. Deshalb wachsen die Schriften mit der Fensterbreite (`clamp` mit `vw`) statt mit
   einer Einstellung, die jemand vornehmen müsste — auf einem 55-Zoll-Bildschirm hat niemand
   eine Maus, um etwas zu vergrössern. */
/* ── Der Vor-Ort-Modus ─────────────────────────────────────────────────────
   ⬛ Die gewohnte Kopfleiste verschwindet, und an ihre Stelle tritt eine, die nur zwei Dinge
   kann: sagen, wo man ist, und wieder heraus. Sie ist deutlich gefärbt — wer den Laptop
   übernimmt, soll auf den ersten Blick sehen, dass diese Sitzung eingesperrt ist, und nicht
   erst nach dem dritten Klick ins Leere. */
body.vor-ort > .kopf { display: none; }
.vor-ort-leiste {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 16px; background: var(--gruen-bg);
  border-bottom: 2px solid var(--gruen);
}
.vor-ort-marke { display: inline-flex; align-items: center; gap: 6px; font-weight: 700;
                 color: var(--gruen); font-size: var(--fs-sm); }
.vor-ort-name { font-size: var(--fs-md); }
.vor-ort-satz { color: var(--text2); font-size: var(--fs-sm); }
#vor-ort-beenden { margin-left: auto; }
/* Am Handy passt der Erklärsatz nicht neben den Namen — dann steht er gar nicht da. Der
   grüne Balken und das Schloss sagen es auch. */
@media (max-width: 680px) {
  .vor-ort-satz { display: none; }
  #vor-ort-beenden { margin-left: auto; }
}

.tafel-seite .kopf, .tafel-seite .rechtsfuss { display: none; }
/* ⬛ Gefunden beim Nachmessen im Browser: `main` ist überall auf 1000px begrenzt — richtig für
   eine Textspalte, falsch für einen Fernseher. Auf einem 55-Zöller stand die Tafel damit als
   schmaler Streifen in der Mitte, links und rechts nichts. Aufgefallen wäre es lange nicht:
   In der Vorführung steckt die Tafel in einem Rahmen, der ohnehin nur 1000px breit ist. */
.tafel-seite main.voll { max-width: none; padding: 0; }
.tafel { padding: clamp(12px, 2vw, 32px); }
.tafel-kopf { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
              margin-bottom: clamp(10px, 1.5vw, 22px); }
.tafel-kopf h1 { font-size: clamp(1.5rem, 3.4vw, 3rem); font-weight: 800;
                 letter-spacing: -.02em; }
.tafel-stand { margin-left: auto; display: flex; align-items: center; gap: 8px;
               color: var(--text2); font-size: clamp(.85rem, 1.2vw, 1.3rem); }
/* An der Tafel steht der Code oben in der Kopfzeile und darf sie nicht dominieren — auf dem
   Tabellen-Monitor unten hat er mehr Platz. Dieselbe Kachel, kleiner gesetzt. */
.tafel-codes { margin-left: 0; }
.tafel-codes .bildschirm-code-bild svg { width: clamp(56px, 5vw, 96px);
                                         height: clamp(56px, 5vw, 96px); }
/* Ein Punkt, der sagt „ich hole noch". Wird er grau, steht der Stand still — und genau das
   muss man einem Bildschirm ansehen können, an dem niemand steht. */
.tafel-punkt { width: 10px; height: 10px; border-radius: 50%; background: var(--gruen); }
.tafel-punkt.still { background: var(--text3); }
.tafel-h2 { font-size: clamp(1.05rem, 1.9vw, 1.9rem); font-weight: 750; margin: 0 0 8px; }
.tafel-h3 { font-size: clamp(.95rem, 1.4vw, 1.4rem); font-weight: 650; color: var(--text2);
            margin: 12px 0 6px; }
.tafel-saison { color: var(--text2); font-weight: 500; }
.tafel-leer { color: var(--text2); padding: 8px 0; }

/* Was gerade läuft, steht oben und gross — das ist die Frage, mit der jemand hinschaut. */
.tafel-laeuft { display: grid; gap: 10px; margin-bottom: clamp(14px, 2vw, 28px);
                grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.laeuft-kachel { background: var(--flaeche); border: 1px solid var(--gruen);
                 border-radius: var(--r-md); padding: clamp(10px, 1.2vw, 18px); }
.laeuft-oben { display: flex; align-items: center; gap: 6px; color: var(--text2);
               font-size: clamp(.8rem, 1.1vw, 1.1rem); margin-bottom: 4px; }
.laeuft-paarung { font-size: clamp(1rem, 1.7vw, 1.8rem); font-weight: 700; line-height: 1.2; }
/* Die Uhrzeit auf einer Kachel ohne Ergebnis: deutlich kleiner als ein Spielstand und in der
   ruhigen Farbe. Sonst liest sie sich aus fünf Metern wie ein 10:38. */
.laeuft-stand.nur-zeit {
  font-size: clamp(.95rem, 1.5vw, 1.5rem); font-weight: 650; color: var(--text2);
}
.laeuft-wort { font-size: var(--fs-sm); font-weight: 600; color: var(--text3); }
.laeuft-stand { font-size: clamp(1.4rem, 2.6vw, 3rem); font-weight: 800;
                font-variant-numeric: tabular-nums; color: var(--gruen); }
.laeuft-wb { color: var(--text3); font-size: clamp(.75rem, 1vw, 1rem); }

/* Die Tabellen nebeneinander: am Handy eine, am Tablet zwei, am Fernseher drei oder vier. */
.tafel-raster { display: grid; gap: clamp(12px, 1.6vw, 26px);
                grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.tafel-raster .liga th, .tafel-raster .liga td { font-size: clamp(.85rem, 1.15vw, 1.25rem); }
.tafel-raster .liga td { height: auto; padding: clamp(6px, .7vw, 12px) 6px; }
.tafel-raster .wappen { width: clamp(22px, 1.8vw, 34px); height: clamp(22px, 1.8vw, 34px); }

/* ── Der zweite Bildschirm: nur Tabellen ───────────────────────────────────
   ⬛ Vom Nutzer beauftragt („einen zweiten Monitor, wo die Tabellen draufgegeben werden").
   Anders als die Tafel scrollt diese Seite NICHT: Ein Bildschirm im Zelt hat niemanden, der
   ihn bedient. Was nicht draufpasst, wird deshalb geblättert — und damit das Blättern messen
   kann, wo Schluss ist, ist die Seite genau so hoch wie das Fenster und das Tabellenfeld
   dazwischen der einzige Teil, der wachsen darf. */
.tabellen-seite, .tabellen-seite main.voll { height: 100dvh; overflow: hidden; }
.tabellen-seite-innen {
  height: 100dvh; display: flex; flex-direction: column;
  padding: clamp(12px, 2vw, 32px); gap: clamp(8px, 1vw, 16px);
}
/* `--zoom` wächst, wenn alles auf ein Blatt passt und noch Platz bleibt: Ein Turnier mit drei
   Gruppen zu vier Mannschaften füllte sonst ein Drittel des Fernsehers, und der Rest wäre
   weiss. Gesetzt wird der Wert gemessen (siehe `tabellen.html`), nicht geraten. */
.tabellen-raster {
  --zoom: 1;
  flex: 1; min-height: 0; overflow: hidden;
  display: grid; gap: clamp(12px, 1.6vw, 28px); align-content: start;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
}
.tabellen-block { min-width: 0; }
.tabellen-h2 { font-size: calc(clamp(1.05rem, 1.9vw, 2.1rem) * var(--zoom));
               font-weight: 750; margin: 0 0 8px; }
.tabellen-wb { color: var(--text2); font-weight: 500; }
/* Hier stehen die vollen Spalten — Siege, Tore, Form. Das ist der ganze Unterschied zur
   Anzeigetafel, auf der nur Platz, Verein, Spiele, Differenz und Punkte Platz haben. */
.tabellen-raster .liga th, .tabellen-raster .liga td {
  font-size: calc(clamp(.85rem, 1.05vw, 1.35rem) * var(--zoom));
}
.tabellen-raster .liga td { height: auto; padding: calc(clamp(6px, .7vw, 13px) * var(--zoom)) 6px; }
.tabellen-raster .wappen { width: calc(clamp(22px, 1.7vw, 36px) * var(--zoom));
                           height: calc(clamp(22px, 1.7vw, 36px) * var(--zoom)); }
.tabellen-blatt {
  font-variant-numeric: tabular-nums; padding: 2px 10px; border-radius: 999px;
  background: var(--flaeche2); color: var(--text2);
}

/* Der Weg vom Bildschirm in die Hand. Steht unten und bleibt stehen, auch wenn geblättert
   wird — wer stehen bleibt und den Code sucht, soll ihn nicht erst abwarten müssen. */
.tabellen-fuss {
  display: flex; align-items: center; gap: clamp(12px, 2vw, 32px);
  border-top: 1px solid var(--linie); padding-top: clamp(8px, 1vw, 16px);
}
.tabellen-fuss-titel { font-weight: 700; font-size: clamp(.9rem, 1.3vw, 1.5rem); }
.tabellen-fuss-satz { color: var(--text2); font-size: clamp(.8rem, 1.1vw, 1.3rem);
                      word-break: break-all; }
.bildschirm-codes { margin-left: auto; display: flex; gap: clamp(10px, 1.4vw, 22px); }
.bildschirm-code { text-align: center; }
/* Weiss hinterlegt, auch im dunklen Erscheinungsbild: Ein QR-Code aus schwarzen Punkten auf
   dunklem Grund wird von keiner Kamera gelesen. */
.bildschirm-code-bild { background: #fff; padding: 6px; border-radius: 8px; line-height: 0; }
.bildschirm-code-bild svg { width: clamp(64px, 6vw, 120px); height: clamp(64px, 6vw, 120px); }
.bildschirm-code-name { font-size: clamp(.7rem, .9vw, 1rem); color: var(--text2);
                      margin-top: 4px; max-width: clamp(84px, 9vw, 162px); }

/* Am Handy ist der zweite Bildschirm kein zweiter Bildschirm: Dort darf gescrollt werden,
   sonst sieht man von einer Tabelle mit zwölf Mannschaften vier Zeilen. */
@media (max-width: 700px) {
  .tabellen-seite, .tabellen-seite main.voll,
  .tabellen-seite-innen { height: auto; overflow: visible; }
  .tabellen-raster { overflow: visible; }
  .tabellen-fuss { flex-wrap: wrap; }
  .bildschirm-codes { margin-left: 0; }
}

/* ── Der Merkzettel-Stern ──────────────────────────────────────────────────
   ⬛ EIN Pfad, zwei Zustände: gefüllt wird über die Klasse, nicht über ein zweites Symbol.
   So springt beim Umschalten nichts, und der Knopf behält seine Grösse.

   Er steckt oft IN einem Listeneintrag, der selbst ein Link ist — deshalb ein eigener,
   grosszügiger Klickbereich: Am Handy trifft man sonst den Eintrag statt den Stern. */
.stern {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none; padding: 0; border: none; border-radius: 50%;
  background: none; color: var(--text3); cursor: pointer;
}
.stern:hover { background: var(--flaeche3); color: var(--text2); }
.stern.voll { color: var(--gelb); }
.stern.voll .ic { fill: currentColor; }

/* ── Die Schnellanleitung für die ersten Anmeldungen ───────────────────────
   Breiter als ein gewöhnlicher Dialog, weil Bilder darin stehen: 460 px zeigen von einem
   Bildschirmfoto nichts, was man erkennt. */
.anleitung-dlg { max-width: 620px; }
.anleitung-zeile { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
                   margin: -6px 0 16px; }
.anleitung-zaehler { font-size: var(--fs-xs); font-weight: 650; color: var(--text2);
                     text-transform: uppercase; letter-spacing: .04em; }
.anleitung-schritt h3 { font-size: var(--fs-xl); font-weight: 700; margin: 4px 0 2px; }
.anleitung-frage { color: var(--text2); margin-bottom: 12px; }
.anleitung-schritt p { margin-bottom: 10px; line-height: 1.55; }
/* Das Bild zeigt die Stelle, um die es geht — mit Rahmen, damit es als Bildschirmfoto
   lesbar bleibt und nicht in die Seite ausläuft. */
.anleitung-bild { display: block; width: 100%; height: auto; border-radius: var(--r-md);
                  border: 1px solid var(--linie); margin: 0 0 12px; }
.anleitung-liste { margin: 0 0 12px 18px; }
.anleitung-liste li { margin-bottom: 6px; line-height: 1.5; }
/* Das Häkchen steht links, die Knöpfe rechts — es ist keine Handlung, sondern eine
   Einstellung zu dem, was hier gerade passiert. */
.anleitung-fuss { justify-content: flex-end; }
.anleitung-fuss .haken-zeile { margin-right: auto; }

/* ── Die Wahl der Wettbewerbsart im offenen Rechner ────────────────────────
   Drei Karten statt eines Auswahlfeldes: Sie stehen nebeneinander, und unter jeder steht in
   einem Satz, wofür sie gut ist. Ein Auswahlfeld mit drei Wörtern verlangt Vorwissen, das
   gerade der nicht hat, der zum ersten Mal hier ist. */
.w-arten { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px;
           margin: 20px 0 4px; }
.w-art {
  display: flex; gap: 9px; align-items: flex-start; cursor: pointer;
  padding: 12px 14px; border: 1px solid var(--linie); border-radius: var(--r-md);
  background: var(--flaeche); font-size: var(--fs-sm); color: var(--text2); line-height: 1.4;
}
.w-art:has(input:checked) { border-color: var(--akzent); background: var(--akzent-bg); }
.w-art input { margin: 2px 0 0; flex: none; }
.w-art b { color: var(--text); font-size: var(--fs-md); }
@media (max-width: 700px) { .w-arten { grid-template-columns: 1fr; } }

/* Ein Spieltag, eine Gruppe, eine K.-o.-Runde: alle drei sind dasselbe — eine Überschrift und
   ein paar Zeilen darunter. */
.spieltag-block {
  border: 1px solid var(--linie); border-radius: var(--r-md); background: var(--flaeche);
  padding: 12px 14px; margin-bottom: 10px;
}
.spieltag-block h3 { font-size: var(--fs-lg); font-weight: 700; margin-bottom: 6px; }
.partienliste { list-style: none; margin: 0; padding: 0; }
.partienliste li { padding: 3px 0; font-size: var(--fs-lg); line-height: 1.35; }
/* Das Ergebnis steht am Ende der Zeile und etwas kräftiger — man liest die Paarung und sucht
   danach die Zahl. */
.partienliste .ergebnis { color: var(--text); margin-left: 6px; }
.gruppen-raster { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
                  gap: 10px; }

/* ── Der Zeitplan eines Spielfests ─────────────────────────────────────────
   Am Rechner und auf dem Papier eine Tabelle: Zeilen sind Durchgänge, Spalten die Felder.
   Man sucht darin eine Uhrzeit und liest quer.

   ⬛ Am HANDY geht das nicht mehr. Bei vier Feldern ist die Tabelle doppelt so breit wie das
   Gerät; sie seitwärts zu rollen ist bedienbar, aber nicht lesbar — man verliert beim Schieben
   die Zeile. Deshalb wird hier aus JEDER Zeile ein Block: die Uhrzeit als Überschrift, darunter
   eine Zeile je Feld, und der Feldname steht davor (er kommt aus `data-feld`, weil es über der
   Zelle keinen Spaltenkopf mehr gibt).

   Und Felder, auf denen in diesem Durchgang niemand spielt, fallen ganz weg: Am Rechner ist ein
   Strich in der Spalte eine Auskunft, am Handy ist er eine Zeile, die man liest und wegwirft. */
.spielplan td.ohne-spiel { color: var(--text3); }

@media (max-width: 700px) {
  table.spielplan, table.spielplan tbody, table.spielplan tr, table.spielplan td,
  table.spielplan th { display: block; }
  table.spielplan thead { display: none; }
  table.spielplan tr {
    border: 1px solid var(--linie); border-radius: var(--r-md);
    background: var(--flaeche); margin-bottom: 10px; padding: 4px 0 8px;
  }
  table.spielplan th.zeit {
    height: auto; padding: 8px 14px 6px; border: none;
    font-size: var(--fs-xl); font-weight: 750; color: var(--text);
    text-transform: none; letter-spacing: -.01em;
  }
  table.spielplan td {
    height: auto; padding: 5px 14px; border: none;
    font-size: var(--fs-lg); line-height: 1.35; white-space: normal;
  }
  table.spielplan td::before {
    content: attr(data-feld); display: block;
    font-size: var(--fs-xs); font-weight: 650; color: var(--text2);
    text-transform: uppercase; letter-spacing: .04em;
  }
  /* Ein Feld ohne Partie braucht am Handy keine Zeile. */
  table.spielplan td.ohne-spiel { display: none; }
  /* Die Hülle rollt dann nichts mehr — sonst bliebe ein Rollbalken ohne Zweck stehen. */
  .tabelle-huelle:has(> table.spielplan) { overflow-x: visible; }
}

/* Der Absender unter einem Aushang oder einer Seite: klein, grau, mit dem Logo davor. Auf
   dem Papier ist er das Einzige, was sagt, wo die Tabelle zu diesem Plan steht — im Netz
   sagt er, wo man gerade ist. Gebaut wird er über das Makro in `_absender.html`. */
.absender {
  display: flex; align-items: center; gap: 10px; margin: 18px 0 0;
  padding-top: 12px; border-top: 1px solid var(--linie);
  color: var(--text2); font-size: var(--fs-sm);
}
.absender .logo { flex: none; }
.absender a { color: var(--text2); text-decoration: underline; }
/* Über dem Handbuchtitel, mit etwas Luft nach unten — es ist ein Deckblatt, keine Leiste. */
.hb-logo { display: block; margin: 0 0 12px; }

/* ── Der Feldplan zum Ausdrucken ───────────────────────────────────────── */
.druckblatt { max-width: 900px; margin: 0 auto; }
.druck-oben { color: var(--text2); margin: 0; }
.druck-titel { font-size: var(--fs-2xl); font-weight: 700; margin: 2px 0 4px; }
.druck-unter { color: var(--text2); margin: 0 0 18px; }
.druck-plan { margin-bottom: 14px; }
.druck-legende {
  list-style: none; padding: 0; margin: 0; column-count: 2; column-gap: 24px;
  color: var(--text2); font-size: var(--fs-sm);
}
.druck-legende li { break-inside: avoid; padding: 2px 0; }

/* ── Die Zähloberfläche ────────────────────────────────────────────────────
   ⬛ Für dicke Daumen im Stehen: die Zahl so gross, dass man sie aus einem Meter liest, das
   Plus als Fläche von 88 Pixeln. Das Minus ist kleiner und blasser — ein Tor zurückzunehmen
   ist selten, und der häufigere Fehlgriff soll nicht der teure sein. */
.zaehl-dialog .karte-koerper { padding: 18px 16px 20px; }
.zaehl-brett { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; }
.zaehl-brett.ruht .zaehl-zahl { color: var(--text3); }
.zaehl-spalte { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.zaehl-wappen .wappen { width: 46px; height: 46px; font-size: 15px; }
.zaehl-name {
  font-size: var(--fs-sm); font-weight: 650; color: var(--text2); text-align: center;
  line-height: 1.25; min-height: 2.5em;
}
.zaehl-zahl {
  font-size: 72px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums;
  letter-spacing: -.03em;
}
.zaehl-plus {
  width: 100%; height: 88px; border: none; border-radius: var(--r-md);
  background: var(--akzent); color: #fff; font-size: 40px; font-weight: 700;
  font-family: inherit; cursor: pointer; touch-action: manipulation;
}
.zaehl-plus:active { filter: brightness(.9); }
.zaehl-minus {
  width: 100%; height: 46px; border: 1px solid var(--linie); border-radius: var(--r-sm);
  background: var(--flaeche2); color: var(--text2); font-size: 24px; font-family: inherit;
  cursor: pointer; touch-action: manipulation;
}
.zaehl-dialog .knopf.gross { margin-top: 10px; }
/* Der Knopf, mit dem ein Zähler ein Spiel öffnet — er steht IN der öffentlichen Tabelle und
   muss sich davon abheben, ohne sie zu übertönen. */
.zaehl-knopf { margin: 6px auto 0; display: block; }

/* ── Felder im Plan verschieben ────────────────────────────────────────────
   ⬛ Nur in der Verwaltung. Auf der öffentlichen Seite ist der Plan eine Auskunft, kein
   Werkzeug — dort bleibt eine Kachel ein Knopf, der zum Spielplan springt. */
.plan-bearbeiten .plan-feld { cursor: grab; touch-action: none; }
.plan-bearbeiten .plan-feld.zieht { cursor: grabbing; z-index: 5; box-shadow: var(--schatten-gross, 0 8px 24px rgba(0,0,0,.18)); }
/* Der Griff sitzt in der Ecke und ist gross genug für einen Daumen — 26 Pixel, auch wenn er
   nur 12 davon zeigt. Eine 6-Pixel-Ecke trifft am Handy niemand. */
.plan-griff {
  position: absolute; right: 0; bottom: 0; width: 26px; height: 26px;
  cursor: nwse-resize; touch-action: none;
}
.plan-griff::before {
  content: ''; position: absolute; right: 5px; bottom: 5px; width: 11px; height: 11px;
  border-right: 2.5px solid currentColor; border-bottom: 2.5px solid currentColor;
  border-radius: 1px; opacity: .55;
}
.plan-bearbeiten .plan-feld:hover .plan-griff::before { opacity: .9; }
/* Ein selbst gelegtes Feld bekommt einen Punkt — sonst weiss man später nicht mehr, welche
   Felder die Rechnung gesetzt hat und welche man selbst. */
.plan-feld.eigen::after {
  content: ''; position: absolute; left: 6px; top: 6px; width: 6px; height: 6px;
  border-radius: 50%; background: currentColor; opacity: .5;
}

/* Die Zeile „Kennung eingeben" über der Wettbewerbsliste. Am Handy bricht der Knopf unter das
   Feld, statt es auf ein Drittel zu quetschen. */
.kennung-suche { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.kennung-suche .knopf { flex: none; }
/* Die Kennung selbst — überall dieselbe Form: Schreibmaschinenschrift, weit gesetzt, damit man
   sie ablesen und vorlesen kann. */
.kennung {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .08em;
  font-weight: 700;
}

/* Die Umkreiszeile über der Wettbewerbsliste. Am Handy bricht sie um, statt drei Felder auf
   je ein Drittel zu quetschen. */
.umkreis { margin-bottom: 12px; }
.umkreis-zeile { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.umkreis-zeile .feld span { white-space: nowrap; }

/* ── Handbuch ──────────────────────────────────────────────────────────────
   Ein Artikel ist ein <details>: aufgeklappt wird von Hand, ohne eine Zeile Skript. Das ist
   nicht Sparsamkeit — eine Antwort, die erst nach dem Laden eines Skripts erscheint, fehlt
   genau dann, wenn am Spielfeldrand das Netz stockt. */
.hb { background: var(--flaeche); border: 1px solid var(--linie); border-radius: var(--r-md);
      padding: 0; }
.hb + .hb { margin-top: 8px; }
.hb > summary { cursor: pointer; padding: 12px 14px; list-style: none;
                display: flex; flex-direction: column; gap: 2px; }
.hb > summary::-webkit-details-marker { display: none; }
/* Der Griff ist ein Zeichen, kein Bild: Er dreht sich beim Aufklappen und braucht dafür
   nichts nachzuladen. */
.hb > summary::after { content: '+'; position: absolute; right: 14px; margin-top: -2px;
                       color: var(--text2); font-size: 18px; line-height: 1; }
.hb[open] > summary::after { content: '−'; }
.hb > summary { position: relative; padding-right: 34px; }
.hb > summary:hover { background: var(--flaeche2); border-radius: var(--r-md); }
.hb .hb-titel { font-weight: 620; }
.hb > summary small { color: var(--text2); }
.hb-koerper { padding: 0 14px 14px; border-top: 1px solid var(--linie); margin-top: 2px;
              padding-top: 12px; }
.hb-koerper p { margin: 0 0 10px; }
.hb-schritte { margin: 0 0 10px; padding-left: 22px; }
.hb-schritte li { margin-bottom: 7px; }
.hb-merke { border-left: 3px solid var(--akzent); padding-left: 10px; color: var(--text2); }

/* Mehrfachauswahl in einem Dialog — ein Kästchen je Zeile, damit am Handy sichtbar ist,
   dass mehrere gehen. */
.haken-gruppe { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.haken-zeile { display: flex; align-items: center; gap: 8px; font-weight: 400;
               padding: 7px 10px; border: 1px solid var(--linie); border-radius: var(--r-sm);
               background: var(--flaeche); cursor: pointer; }
.haken-zeile input { width: auto; height: auto; margin: 0; flex: none; }

/* Der Infotext eines Wettbewerbs. Die Elemente darin stammen aus `auszeichnung.py` und sind
   abzählbar: p, br, b, i, h3, ul, li, a. */
.infotext > :first-child { margin-top: 0; }
.infotext > :last-child { margin-bottom: 0; }
.infotext p { margin: 0 0 10px; }
.infotext h3 { font-size: var(--fs-md); font-weight: 650; margin: 16px 0 6px; }
.infotext ul { margin: 0 0 10px; padding-left: 22px; }
.infotext li { margin-bottom: 4px; }
.infotext a { overflow-wrap: anywhere; }

/* Der kleine Editor: eine Leiste, ein Textfeld, eine Vorschau an derselben Stelle. */
.editor { border: 1px solid var(--linie); border-radius: var(--r-sm); overflow: hidden;
          margin-bottom: 14px; background: var(--flaeche); }
.editor-leiste { display: flex; gap: 6px; flex-wrap: wrap; padding: 8px;
                 border-bottom: 1px solid var(--linie); background: var(--flaeche2); }
.editor textarea { width: 100%; border: none; border-radius: 0; padding: 12px;
                   font: inherit; resize: vertical; background: var(--flaeche);
                   color: var(--text); }
.editor textarea:focus { outline: none; }
.editor-vorschau { padding: 12px; min-height: 80px; }

/* Der Rahmen eines Wettbewerbs: Angabe und Wert nebeneinander, am Handy untereinander. */
.rahmen { display: grid; grid-template-columns: minmax(0, 190px) 1fr; gap: 6px 16px; margin: 0; }
.rahmen dt { color: var(--text2); }
.rahmen dd { margin: 0; font-weight: 560; }
@media (max-width: 560px) {
  .rahmen { grid-template-columns: 1fr; gap: 2px; }
  .rahmen dd { margin-bottom: 8px; }
}

/* Der QR-Code im Weitersagen-Dialog. Mittig und nicht zu gross: Er wird abfotografiert, nicht
   bewundert — und darunter muss der Link noch ins Bild passen. */
.qr-block { display: flex; justify-content: center; margin-bottom: 10px; }
.qr-block svg { width: 190px; height: 190px; }

/* ── Die Team-Einteilung ───────────────────────────────────────────────────
   ⬛ Eine Zeile je Kind, rechts die Wahl. Der erste Entwurf hatte je Team eine Liste ALLER
   Kinder — bei 22 Kindern und drei Teams waren das 66 Zeilen mit dreimal denselben Namen. */
.team-kopf { display: flex; gap: 8px; flex-wrap: wrap; padding: 10px 14px;
             border-bottom: 1px solid var(--linie); }
.team-zeile {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 14px; border-bottom: 1px solid var(--linie);
}
.team-zeile:last-child { border-bottom: 0; }
.team-name { flex: 1; min-width: 140px; }
/* Die Schalter stehen zusammen: Sie beantworten EINE Frage, und die Antwort ist genau eine. */
.team-wahl { display: flex; gap: 4px; flex: none; }
.team-wahl .knopf { min-width: 38px; padding: 0 8px; }

/* Im Monatsblatt: Zeit und Titel in der ersten Zeile, wessen Termin es ist in der zweiten.
   ⬛ Vom Nutzer gemeldet — vorher stand die Mannschaft nur im Tooltip, und den sieht am Handy
   niemand. */
.kalender-eintrag { display: flex; flex-direction: column; gap: 1px; text-align: left; }
.kalender-eintrag-titel { display: block; overflow: hidden; text-overflow: ellipsis;
                          white-space: nowrap; }
.kalender-eintrag-wer {
  display: block; font-size: var(--fs-2xs); opacity: .75;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Die Vereinbarung zur Auftragsverarbeitung ─────────────────────────────
   ⬛ Gelb, solange sie fehlt — aber nur, wenn sie überhaupt fällig ist. Eine Warnung ohne
   Anlass macht die nächste unglaubwürdig. */
.av-offen { background: var(--gelb-bg, #fff8e6); border-bottom: 1px solid var(--linie); }
.av-kopf { font-weight: 700; margin-bottom: 6px; }
.av-offen p { margin-bottom: 8px; }
.av-weg { overflow-wrap: anywhere; }
.av-fertig { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
             border-bottom: 1px solid var(--linie); }

/* ── Das Taktikbrett ─────────────────────────────────────────────────────────
   ⬛ Vom Nutzer beauftragt. Die Farben stehen HIER und nicht im SVG: Ein Fernseher im
   Vereinsheim steht oft im Hellen, ein iPad im Schatten — und wer die Darstellung nachschärfen
   will, soll das an einer Stelle tun und nicht in zwei Vorlagen. */
.tb-flaeche { width: 100%; height: auto; display: block; touch-action: none;
              user-select: none; -webkit-user-select: none; }
.tb-rasen { fill: #3f8f4a; }
.tb-rasen.dunkel { fill: #388342; }
.tb-linie { stroke: rgba(255,255,255,.85); stroke-width: .35; }
.tb-punkt { fill: rgba(255,255,255,.85); }
/* ⬛ Die Tore stehen AUSSERHALB des Rasens — dort ist der Grund der Seitenhintergrund, und
   weiss auf weiss ist kein Tor. Deshalb eine Kontur: Sie trägt auf hellem wie auf dunklem
   Grund, und auf dem Minitorfeld sind die vier Tore der halbe Sinn der Spielform. */
.tb-tor { fill: #fff; stroke: #33383d; stroke-width: .25; }
.tb-figur { cursor: grab; }
.tb-figur.zieht { cursor: grabbing; }
.tb-heim .tb-kreis { fill: #1b52c4; stroke: #fff; stroke-width: .3; }
.tb-gast .tb-kreis { fill: #c8371f; stroke: #fff; stroke-width: .3; }
.tb-ball .tb-kreis { fill: #fff; stroke: #1a1a1a; stroke-width: .28; }
.tb-huetchen-form { fill: #f3a712; stroke: #8a5a00; stroke-width: .2; }
.tb-stange-form { stroke: #f3f3f3; stroke-width: .5; stroke-linecap: round; }
.tb-tor-form { fill: none; stroke: #fff; stroke-width: .45; }
.tb-text { fill: #fff; text-anchor: middle; font-weight: 700;
           font-family: system-ui, sans-serif; pointer-events: none; }
.tb-ball .tb-text { fill: #1a1a1a; }
.tb-strich { stroke-width: .45; stroke-linecap: round; stroke-linejoin: round; }
.tb-strich.lauf { stroke: #ffe27a; }
.tb-strich.pass { stroke: #ffe27a; stroke-dasharray: 1.6 1.2; }
.tb-strich.frei { stroke: #fff; }
.tb-spitze { fill: #ffe27a; }
.tb-spitze.frei { fill: #fff; }

/* ⬛ Vom Nutzer gewünscht: „dass der Ball … ein bisschen leuchtet, also pulsiert."
   Der Schein sitzt HINTER dem Ball und wächst; der Ball selbst behält seine Grösse, damit man
   auch aus zehn Metern sieht, wo er wirklich liegt. */
.tb-ball-schein { fill: #fff; opacity: .55; transform-box: fill-box; transform-origin: center;
                  animation: tb-puls 1.6s ease-in-out infinite; pointer-events: none; }
@keyframes tb-puls {
  0%, 100% { transform: scale(1); opacity: .5; }
  50%      { transform: scale(2.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  /* Wer Bewegung abgestellt hat, bekommt einen ruhigen Schein statt gar keines Hinweises. */
  .tb-ball-schein { animation: none; transform: scale(1.7); opacity: .3; }
}

/* Die Werkzeugleiste: am Tablet gross genug für einen Daumen.
   ⬛ Vom Nutzer gemeldet: „lasse doch bei den Buttons und Schriften usw. zu den Rändern ein
   wenig Platz." Die Karte selbst polstert nicht — das tun `.karte-kopf` und `.karte-koerper`;
   die Taktikseite hatte ihren Inhalt daran vorbei direkt in die Karte gelegt. Hier steht
   zusätzlich der Abstand ZWISCHEN den Leisten und zum Feld darunter. */
.tb-leiste { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center;
             margin: 0 0 12px; }
.tb-leiste:last-of-type { margin-bottom: 16px; }
.tb-leiste .knopf { min-height: 42px; }
.tb-leiste > .hinweis { margin-right: 2px; }
/* Ein Auswahlmenü mit seiner Beschriftung — schmal untereinander, damit die Beschriftung
   nicht die halbe Zeile frisst. */
.tb-gruppe { display: flex; flex-direction: column; gap: 3px; min-width: 160px; }
/* Am Handy zwei nebeneinander — sonst wird jede Auswahl eine eigene Zeile und die Leiste
   höher als das Feld darunter. Bei Platz richtet sich die Breite nach dem Inhalt. */
@media (max-width: 760px) { .tb-gruppe { flex: 1 1 46%; min-width: 140px; } }
.tb-gruppe .hinweis { font-size: var(--fs-sm); }
.tb-gruppe select { width: 100%; min-height: 42px; }
/* Die Brettwahl in der Kartenkopfzeile darf nicht die ganze Breite nehmen — daneben steht
   noch der Monitor-Knopf. */
.karte-kopf #brett-wahl { max-width: 190px; min-height: 36px; }
@media (max-width: 520px) { .karte-kopf #brett-wahl { max-width: 100%; flex: 1 1 100%; } }
.tb-vorrat { display: flex; gap: 8px; flex-wrap: wrap; }
.tb-vorrat button { min-width: 64px; min-height: 42px; }
/* Das Feld bekommt Luft nach oben und unten — es klebte sonst an der Leiste. */
.tb-flaeche { margin: 4px 0 10px; border-radius: var(--r-md); overflow: hidden; }

/* Die Vorführung auf der Startseite — nur das Feld, mittig.
   ⬛ Diese Regeln gehören HIERHER und nicht ins Stilblatt der Startseite: Die Vorführung ist
   eine eigene Seite im Geräterahmen, und die lädt `willkommen.css` gar nicht. Beim ersten
   Versuch stand sie deshalb oben im Rahmen statt in der Mitte — die Regeln waren da, nur eben
   in einer Datei, die niemand geladen hatte. */
.tb-vorfuehrung {
  min-height: 100vh; display: flex; flex-direction: column; justify-content: center;
  padding: 14px; gap: 8px;
}
.tb-vorfuehrung-fuss { text-align: center; margin: 0; }

/* Der grosse Bildschirm: nur das Feld, schwarz drumherum, nichts zum Anfassen. */
.tb-monitor { background: #0b0b0b; min-height: 100vh; display: flex; flex-direction: column;
              align-items: center; justify-content: center; gap: 10px; padding: 12px; }
.tb-monitor .tb-flaeche { max-height: 92vh; width: auto; max-width: 100%; }
.tb-monitor-kopf { color: #eee; font-size: clamp(16px, 2.2vw, 30px); font-weight: 700;
                   letter-spacing: .01em; }
.tb-monitor-still { color: #c88; font-size: 14px; }

/* ── Aufzeichnungen am Taktikbrett ───────────────────────────────────────────
   ⬛ Vom Nutzer gewünscht: „kannst du das optisch etwas schicker da unten gestalten." Die
   Abspielleiste ist deshalb ein eigenes Bedienfeld und keine Knopfreihe mehr — wer zusieht,
   bedient ein Abspielgerät, und das sieht überall auf der Welt gleich aus. */
.tb-abspiel {
  margin: 4px 0 14px; padding: 12px 14px 14px; border-radius: var(--r-md);
  background: var(--flaeche2); border: 1px solid var(--linie);
}
.tb-abspiel-kopf { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.tb-abspiel-kopf b { font-size: var(--fs-lg); letter-spacing: -.01em; }
.tb-abspiel-kopf .hinweis { font-size: var(--fs-sm); }
.tb-abspiel-kopf > .knopf { margin-left: auto; }
.tb-abspiel-knoepfe { display: flex; gap: 8px; align-items: center; justify-content: center; }
.tb-abspiel-knoepfe .knopf { width: 46px; height: 40px; }
/* Der Durchlauf ist die Handlung, um die es geht — er steht in der Mitte und ist grösser. */
.tb-abspiel-knoepfe .tb-los {
  width: 58px; height: 46px; background: var(--akzent); border-color: var(--akzent);
  color: var(--auf-akzent);
}
.tb-abspiel-knoepfe .tb-los .ic { color: currentColor; }

/* Ein Balken sagt auf einen Blick, wo man ist; die Marken darauf, wie weit es bis zum
   nächsten Zug ist. Eine Zahl allein sagt nur das Erste. */
.tb-fortschritt {
  position: relative; height: 6px; margin: 12px 0 6px; border-radius: 999px;
  background: var(--flaeche3); overflow: hidden;
}
.tb-fortschritt-fuellung {
  position: absolute; inset: 0 auto 0 0; background: var(--akzent);
  border-radius: 999px; transition: width .12s linear;
}
.tb-fortschritt-marke {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: var(--flaeche); opacity: .9;
}
.tb-abspiel-stand { text-align: center; font-size: var(--fs-sm); }

/* Der laufende Aufnahmezustand: ein ruhig pulsender Punkt statt eines Zeichens im Text. */
.tb-laeuft { display: inline-flex; align-items: center; gap: 7px; color: var(--rot);
             font-size: var(--fs-sm); font-weight: 650; }
.tb-laeuft::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%; background: var(--rot);
  animation: tb-blinkt 1.4s ease-in-out infinite;
}
@keyframes tb-blinkt { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .tb-laeuft::before { animation: none; } }

/* Eine Kachel je Aufzeichnung — der Name ist das, wonach man greift. */
.tb-aufnahmen-kopf { margin: 16px 0 8px; }
.tb-aufnahmen {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}
.tb-aufnahme {
  display: flex; flex-direction: column; gap: 7px; padding: 12px 13px;
  border-radius: var(--r-md); background: var(--flaeche); border: 1px solid var(--linie);
}
.tb-aufnahme.laeuft { border-color: var(--akzent); box-shadow: 0 0 0 1px var(--akzent); }
.tb-aufnahme-kopf { display: flex; align-items: flex-start; gap: 8px; }
.tb-aufnahme-kopf b { flex: 1; line-height: 1.25; word-break: break-word; }
.tb-aufnahme-marken { display: flex; flex-wrap: wrap; gap: 5px; }
.tb-aufnahme-los { align-self: flex-start; margin-top: 3px; }
