/* Fußballkarte — Gestaltung der Kartenseite.
 *
 * Bewusst ohne Framework und ohne Build-Schritt: eine Datei, die in zwei Jahren
 * noch genauso funktioniert. Die Farben der Marker stehen in karte.js, weil sie
 * dort aus der Spielklasse berechnet werden.
 */

:root {
  --rasen: #2f6b3c;
  --linie: #e2e6e2;
  --text: #161a16;
  --gedaempft: #667066;
  --hintergrund: #f7f8f7;
  --schatten: 0 8px 30px rgb(20 30 20 / 16%), 0 2px 6px rgb(20 30 20 / 8%);
  --rundung: 14px;

  /* Drei Schieberegler, wie sie überall für „Filter" stehen. Inline als
     Datenadresse: ein Bild weniger, das geladen werden muss, und die Farbe
     kommt über `mask` aus dem Stylesheet statt aus der Datei. */
  --regler: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 6h11M18 6h3M3 12h3M10 12h11M3 18h11M18 18h3'/%3E%3Ccircle cx='16' cy='6' r='2' fill='%23000'/%3E%3Ccircle cx='8' cy='12' r='2' fill='%23000'/%3E%3Ccircle cx='16' cy='18' r='2' fill='%23000'/%3E%3C/svg%3E");
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--text);
  background: var(--hintergrund);
}

/* iOS blendet Adress- und Werkzeugleiste beim Scrollen ein und aus. `100%`
   und `100vh` meinen dort die Höhe *ohne* diese Leisten — sobald sie
   erscheinen, ist die Seite höher als das Sichtbare, und Kopf- und Fußzeile
   verschwinden darunter. `dvh` folgt der tatsächlichen Höhe.

   Als @supports, damit die 100 % oben die Rückfallebene bleiben. */
@supports (height: 100dvh) {
  html,
  body {
    height: 100dvh;
  }
}

/* Flex-Spalte statt gerechneter Höhen: Die Karte nimmt, was übrig bleibt.
   Vorher stand hier ein calc() mit fester Leistenhöhe — sobald die Leiste
   umbrach, stimmte die Rechnung nicht mehr und die Karte verrutschte. */
body {
  display: flex;
  flex-direction: column;
}

/* Hinter dem Filterblatt. Dunkelt die Karte ab, damit klar ist, dass sie
   gerade nicht bedient wird, und fängt das Tippen daneben ab. */
.blende {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgb(20 30 20 / 32%);
}

.blende[hidden] {
  display: none;
}

/* -- Bedienleiste -------------------------------------------------------- */

/* `position: relative` ist nicht Zierde, sondern Voraussetzung: Ohne sie ist
   `z-index` an einem statisch positionierten Element wirkungslos. Genau daran
   ist die Trefferliste der Ligasuche unsichtbar geblieben — die Karte steht
   später im Dokument und lag damit darüber. */
.leiste {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.75rem 1rem;
  flex-wrap: wrap;
  /* Die Seite liegt per `viewport-fit=cover` unter der Systemoberfläche. Ohne
     diese Abstände rutschen Titel und Felder darunter — oben unter Status-
     und Adressleiste, im Querformat seitlich unter die Aussparung. `max`
     statt `+`, damit es sonst beim gewohnten Wert bleibt.

     Der obere Abstand fehlte zunächst, und man sah genau das: Die Fußzeile
     saß richtig, die Leiste lag hinter der Adressleiste von Safari. */
  padding: max(0.55rem, env(safe-area-inset-top)) max(0.9rem, env(safe-area-inset-right))
    0.55rem max(0.9rem, env(safe-area-inset-left));
  background: #fff;
  border-bottom: 1px solid var(--linie);
  z-index: 1000;
}

.leiste h1 {
  font-size: 1.05rem;
  margin: 0 0.5rem 0 0;
  color: var(--rasen);
  white-space: nowrap;
}

/* `display: flex` schlägt das `display: none`, das der Browser dem
   hidden-Attribut mitgibt — gleiche Spezifität, eigene Regel steht später.
   Ohne die Ausnahme ließen sich Datum und Zeitraum in der Vereinsansicht
   nicht ausblenden. Denselben Fehler gab es schon beim Spielplan-Panel. */
.leiste label[hidden] {
  display: none;
}

.leiste label {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: 0.7rem;
  color: var(--gedaempft);
}

.leiste input,
.leiste select,
.leiste button {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--linie);
  border-radius: 0.45rem;
  background: #fff;
  color: var(--text);
}

.leiste button {
  align-self: flex-end;
  cursor: pointer;
}

.leiste button:hover {
  border-color: var(--rasen);
  color: var(--rasen);
}

/* -- Karte und Standfeld ------------------------------------------------- */

.huelle {
  position: relative;
  flex: 1 1 auto;
  /* Ohne min-height:0 wächst ein Flex-Element über seinen Anteil hinaus,
     sobald sein Inhalt größer wird — die Karte schöbe die Fußzeile weg. */
  min-height: 0;
}

#karte {
  height: 100%;
  width: 100%;
}

/* Den Untergrund zurücknehmen, damit die Marker vorne stehen.
 *
 * Die OSM-Karte ist bunt und stellenweise kräftig grün — Wälder, Parks,
 * Felder. Farbige Punkte darauf gehen unter, besonders die helleren. Statt die
 * Marker immer greller zu machen, wird hier die Karte leiser: entsättigt und
 * leicht aufgehellt. Beschriftungen und Straßen bleiben lesbar, die Daten
 * liegen sichtbar darüber.
 *
 * Nur der Kachel-Layer, nicht die ganze Karte — sonst verlören auch die Marker
 * ihre Farbe. */
.leaflet-tile-pane {
  filter: saturate(0.3) brightness(1.06) contrast(0.96);
}

/* Ein weicher Schatten hebt jeden Marker vom Untergrund ab. Am Layer statt an
   jedem Kreis: ein Filter für alle, statt fünfhundert. */
.leaflet-overlay-pane svg,
.leaflet-marker-pane {
  filter: drop-shadow(0 1px 2px rgb(20 20 20 / 45%));
}

/* Schwebt über der Karte, statt die Leiste zu verändern. Deshalb kann die
   Meldung beliebig lang werden, ohne dass sich am Gerüst etwas rührt. */
.stand {
  position: absolute;
  left: 0.75rem;
  bottom: 0.75rem;
  z-index: 500;
  max-width: min(26rem, calc(100% - 1.5rem));
  padding: 0.5rem 0.75rem;
  border-radius: 999px;
  background: rgb(255 255 255 / 94%);
  backdrop-filter: blur(6px);
  box-shadow: var(--schatten);
  font-size: 0.8rem;
  color: var(--gedaempft);
  line-height: 1.35;
}

/* Eine mehrzeilige Meldung sieht als Pille albern aus. */
.stand.lang {
  border-radius: var(--rundung);
}

.stand.fehler {
  color: #8f2d24;
  background: rgb(253 240 238 / 96%);
}

/* -- Legende ------------------------------------------------------------- */

.legende {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 500;
  width: 12.5rem;
  /* Elf Klassen plus fünf Gruppenköpfe werden länger als die alte Liste aus
     fünf Zeilen — auf einem flachen Fenster muss sie scrollen dürfen, statt
     unten aus der Karte zu laufen. */
  max-height: calc(100% - 1.5rem);
  overflow-y: auto;
  padding: 0.55rem 0.7rem;
  border-radius: 0.6rem;
  background: rgb(255 255 255 / 94%);
  backdrop-filter: blur(6px);
  box-shadow: var(--schatten);
}

.legende__kopf {
  margin: 0 0 0.35rem;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--gedaempft);
}

.legende__liste {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.1rem;
}

/* Die Legende ist zugleich der Filter — jede Zeile ist ein Schalter. */
.legende__zeile {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  padding: 0.2rem 0.3rem;
  border: none;
  border-radius: 0.35rem;
  background: none;
  font: inherit;
  font-size: 0.68rem;
  line-height: 1.2;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.legende__zeile:hover {
  background: rgb(20 30 20 / 6%);
}

/* Nicht im Bild: blass, aber nicht durchgestrichen.
   Die Durchstreichung stammte aus der Zeit, als ein Klick eine Klasse
   *ausblendete* — dann waren ein, zwei Zeilen betroffen und die Geste passte.
   Seit ein Klick eine Klasse *herausgreift*, sind es zehn von elf, und
   durchgestrichen sähe das nach einem Fehler aus statt nach einer Auswahl. */
.legende__zeile--aus {
  color: var(--gedaempft);
  opacity: 0.5;
}

/* Und umgekehrt: Was gezeigt wird, tritt hervor. */
.legende__zeile:not(.legende__zeile--aus) .legende__name {
  font-weight: 700;
}

.legende__zeile--aus .legende__punkt {
  background: transparent !important;
  border-color: currentColor;
  box-shadow: none;
}

/* Der Weg zurück. Seit ein Klick eine Klasse herausgreift statt sie
   auszublenden, wird er oft gebraucht — deshalb deutlicher als zuvor. */
.legende__alle {
  margin-top: 0.5rem;
  width: 100%;
  padding: 0.35rem;
  border: 1px solid var(--rasen);
  border-radius: 0.35rem;
  background: var(--rasen);
  font: inherit;
  font-size: 0.68rem;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
}

.legende__alle:hover {
  background: #25552f;
  background: color-mix(in srgb, var(--rasen) 85%, black);
}

/* Der Gruppenkopf trägt die Farbe, die einzelnen Klassen darunter nicht.
   So ist auf einen Blick zu sehen, dass sich mehrere Klassen eine Farbe
   teilen — sonst sähe die Wiederholung nach einem Fehler aus. */
.legende__gruppe {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.15rem 0.3rem;
  border: none;
  background: none;
  font: inherit;
  font-size: 0.63rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--gedaempft);
  text-align: left;
  cursor: pointer;
}

.legende__gruppe:first-child,
li:first-child .legende__gruppe {
  margin-top: 0;
}

.legende__gruppe:hover {
  color: var(--text);
}

/* Ganze Gruppe aus: wie eine abgewählte Zeile. Teilweise: nur gedämpft, denn
   es ist ja noch etwas davon zu sehen. */
.legende__gruppe--aus {
  opacity: 0.5;
}

.legende__gruppe--aus .legende__punkt {
  background: transparent !important;
  border-color: currentColor;
  box-shadow: none;
}

.legende__gruppe--teils .legende__punkt {
  opacity: 0.6;
}

/* Die einzelnen Klassen stehen unter ihrem Gruppenkopf, eingerückt auf die
   Höhe des Namens daneben. */
.legende__zeile {
  padding-left: 1.4rem;
}

.legende__punkt {
  flex: none;
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  border: 1.5px solid #fff;
  box-shadow: 0 1px 2px rgb(20 20 20 / 35%);
}

.fusszeile {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
  padding: 0.35rem max(0.9rem, env(safe-area-inset-right))
    max(0.35rem, env(safe-area-inset-bottom)) max(0.9rem, env(safe-area-inset-left));
  font-size: 0.7rem;
  color: var(--gedaempft);
  background: #fff;
  border-top: 1px solid var(--linie);
}

.fusszeile a {
  color: inherit;
}

/* Der Trennpunkt gehört zwischen die Glieder, nicht in den Text: So steht er
   nie am Anfang einer umgebrochenen Zeile. */
.fusszeile span + span::before {
  content: "·";
  margin-right: 0.3rem;
  color: var(--linie);
}

/* -- Cluster ------------------------------------------------------------- */

/* Bewusst Grün und damit außerhalb der Ligaskala: Ein Cluster ist keine
   Spielklasse, sondern eine Zusammenfassung. */
.haufen {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgb(31 84 43 / 92%);
  color: #fff;
  font-weight: 600;
  font-size: 0.8rem;
  border: 2px solid #fff;
  box-shadow: 0 2px 8px rgb(20 30 20 / 30%);
}

/* -- Beschriftung am Marker ---------------------------------------------- */

/* Leaflets eigene Hülle zurücksetzen — sie bringt Rahmen, Schatten und einen
   Pfeil mit, die hier alle stören. */
.leaflet-tooltip.etikett-huelle {
  padding: 0;
  border: none;
  border-radius: 0.5rem;
  background: none;
  box-shadow: none;
  white-space: nowrap;
}

.leaflet-tooltip.etikett-huelle::before {
  display: none;
}

.etikett {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  padding: 0.2rem 0.5rem;
  border-radius: 0.45rem;
  border-left: 3px solid var(--ligafarbe, var(--rasen));
  background: rgb(255 255 255 / 95%);
  box-shadow: 0 2px 6px rgb(20 30 20 / 22%);
  font-size: 0.72rem;
  line-height: 1.25;
  /* Anklickbar, und das soll man sehen. */
  cursor: pointer;
  transition: box-shadow 120ms ease, transform 120ms ease;
}

.leaflet-tooltip.etikett-huelle:hover .etikett {
  background: #fff;
  box-shadow: 0 4px 12px rgb(20 30 20 / 30%);
  transform: translateY(-1px);
}

.etikett__zeit {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ligafarbe, var(--text));
}

.etikett__paarung {
  color: var(--text);
  /* Ein langer Vereinsname darf die Karte nicht zustellen. Schmaler als es
     bequem wäre: Je breiter ein Etikett, desto mehr Nachbarn verdrängt es aus
     der Überlappungsrechnung. Der vollständige Name steht im Aufklapper. */
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* -- Aufklapper ---------------------------------------------------------- */

.leaflet-popup-content-wrapper {
  border-radius: var(--rundung);
  box-shadow: var(--schatten);
  padding: 0;
}

.leaflet-popup-content {
  margin: 0;
  width: auto !important;
  min-width: 15rem;
  /* Reicht weder oben noch unten der Platz, bekommt der Inhalt eine
     Höhengrenze statt aus dem Fenster zu ragen — dann muss er scrollen
     können. Gesetzt wird die Grenze in karte.js, sie hängt vom Fenster ab. */
  overflow-y: auto;
  overscroll-behavior: contain;
}

.leaflet-popup-tip {
  box-shadow: none;
}

/* Der Aufklapper rückt sich selbst in den sichtbaren Bereich, statt die Karte
   unter sich wegzuziehen — siehe `aufklapperEinpassen` in karte.js. Zwei
   Dinge braucht er dafür aus dem Stylesheet.

   Erstens: Rückt der Kasten seitlich, muss die Spitze stehen bleiben. Sie
   sitzt in der Mitte des Kastens und wandert sonst mit — und zeigte dann auf
   eine Stelle, an der kein Marker ist. `--aufklapper-versatz` trägt den
   Betrag, um den gerückt wurde, und wird hier gegengerechnet. */
.leaflet-popup-tip-container {
  margin-left: calc(-20px - var(--aufklapper-versatz, 0px));
}

/* Zweitens: Geht der Aufklapper nach unten auf, gehört die Spitze nach oben.
   Sie liegt sonst unter dem Kasten und zeigte von ihm weg. `top` statt der
   statischen Lage, und gedreht, damit sie in die richtige Richtung läuft. */
.leaflet-popup--unten .leaflet-popup-tip-container {
  top: -19px;
  transform: rotate(180deg);
}

.leaflet-container a.leaflet-popup-close-button {
  width: 1.75rem;
  height: 1.75rem;
  padding: 0.35rem 0 0 0;
  color: var(--gedaempft);
  font-size: 1.1rem;
}

.leaflet-container a.leaflet-popup-close-button:hover {
  color: var(--text);
  background: none;
}

.spiel {
  padding: 0.85rem 0.95rem 0.75rem;
  /* Die Ligafarbe kommt je Aufklapper aus karte.js. */
  --ligafarbe: var(--rasen);
}

.spiel__liga {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.55rem;
  padding: 0.15rem 0.55rem 0.15rem 0.4rem;
  border-radius: 999px;
  /* Einfacher Wert zuerst: color-mix() gibt es erst seit 2023, und ohne
     Rückfall stünde das Abzeichen in älteren Browsern ohne Hintergrund da. */
  background: #eef2ee;
  background: color-mix(in srgb, var(--ligafarbe) 12%, white);
  color: var(--ligafarbe);
  color: color-mix(in srgb, var(--ligafarbe) 75%, black);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.spiel__liga::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ligafarbe);
}

/* Das Abzeichen ist seit dem Ligafilter ein Knopf. Es soll aussehen wie
   vorher — nur der Zeiger und ein leichtes Aufhellen verraten, dass man es
   drücken kann. */
button.spiel__liga {
  border: 0;
  font-family: inherit;
  cursor: pointer;
}

button.spiel__liga:hover,
button.spiel__liga:focus-visible {
  background: color-mix(in srgb, var(--ligafarbe) 22%, white);
}

/* Heim und Gast stehen untereinander, jeweils mit Wappen davor.
   Vorher war es ein Absatz mit „gegen" als Pseudoelement — mit Bildern
   braucht jede Mannschaft eine eigene Zeile, damit die Wappen untereinander
   fluchten. */
.spiel__mannschaft {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 1rem;
  line-height: 1.3;
  font-weight: 600;
}

/* Feste Maße, damit die Zeile beim Nachladen des Bildes nicht springt.
   `contain` verhindert, dass ein Wappen mit ungewöhnlichem Seitenverhältnis
   verzerrt wird — es gibt querformatige darunter. */
.spiel__wappen {
  flex: none;
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.spiel__mannschaftsname {
  min-width: 0;
}

/* Das Trennwort zwischen den Mannschaften. Eingerückt auf die Höhe der
   Namen, damit es nicht unter den Wappen klebt. */
.spiel__gegen {
  display: block;
  margin: 0.1rem 0 0.1rem 0.15rem;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--gedaempft);
}

/* Nach der zweiten Mannschaft folgt der Anstoß — der Abstand saß vorher am
   Absatz, den es nicht mehr gibt. */
.spiel__mannschaft + .spiel__zeit {
  margin-top: 0.6rem;
}

.spiel__zeit {
  display: inline-block;
  margin-bottom: 0.55rem;
  padding: 0.2rem 0.55rem;
  border-radius: 0.5rem;
  background: #f2f4f2;
  font-size: 0.82rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.spiel__ort {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--gedaempft);
}

.spiel__platz {
  display: block;
  color: var(--text);
  font-weight: 500;
}

/* Route und Quelle stehen nebeneinander und brechen um, wenn der Aufklapper
   dafür zu schmal wird — auf dem Telefon ist er das. */
.spiel__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.65rem;
}

/* Beide Verweise sind Beiwerk, nicht die Hauptsache.
 *
 * „Route" war einmal eine gefüllte grüne Fläche und zog damit den Blick auf
 * sich, obwohl der Kern dieser Karte ist, WELCHE Spiele wo stattfinden — die
 * Navigation dorthin erledigen andere besser. Jetzt stehen beide als
 * zurückhaltende Umrisse nebeneinander.
 *
 * Der `a.`-Präfix ist notwendig, nicht kosmetisch: Leaflet färbt mit
 * `.leaflet-container a` jeden Verweis im Aufklapper blau ein. Diese Regel
 * hat Spezifität (0,1,1) und schlug die frühere `.spiel__route` (0,1,0) —
 * heraus kam Blau auf Dunkelgrün mit einem Kontrast von 1,29:1, also
 * praktisch unlesbar. Mit `a.` steht es 1:1, und diese Datei wird nach
 * Leaflet geladen.
 */
a.spiel__route,
a.spiel__quelle {
  display: inline-block;
  padding: 0.3rem 0.65rem;
  border: 1px solid var(--linie);
  border-radius: 0.45rem;
  background: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  text-decoration: none;
}

/* 5,15:1 gegen Weiß. Zurückgenommen, weil der Weg zum Platz nicht der Kern
   dieser Karte ist — das erledigen Kartendienste besser. */
a.spiel__route {
  color: var(--gedaempft);
}

/* 6,38:1 gegen Weiß. */
a.spiel__quelle {
  color: var(--rasen);
}

/* Angepfiffen: Dahinter steht ein Ergebnis, und das ist das Interessanteste,
   was der Aufklapper zu bieten hat — wir selbst haben es nicht, weil
   fussball.de Spielstände nur verschleiert ausliefert. Weiß auf Rasengrün
   ergibt 6,38:1. */
a.spiel__quelle--ergebnis {
  border-color: var(--rasen);
  background: var(--rasen);
  color: #fff;
}

a.spiel__route:hover,
a.spiel__quelle:hover,
a.spiel__route:focus-visible,
a.spiel__quelle:focus-visible {
  border-color: var(--rasen);
  background: var(--hintergrund);
  color: var(--rasen);
}

a.spiel__quelle--ergebnis:hover,
a.spiel__quelle--ergebnis:focus-visible {
  background: #25552f;
  background: color-mix(in srgb, var(--rasen) 85%, black);
  color: #fff;
}

.spiel__status {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.15rem 0.45rem;
  border-radius: 0.4rem;
  background: #fdf0ee;
  color: #8f2d24;
  font-size: 0.72rem;
  font-weight: 600;
}

/* Ehrlichkeit gegenüber dem Betrachter: Wenn wir nur den Ortskern kennen,
   soll der Marker nicht so tun, als stünde er auf dem Platz. */
.ungenau {
  margin: 0.65rem 0 0;
  padding: 0.4rem 0.55rem;
  border-radius: 0.5rem;
  background: #fdf6e7;
  color: #7a5a1e;
  font-size: 0.74rem;
  line-height: 1.35;
}

/* -- Ligasuche ------------------------------------------------------------ */

.ligasuche {
  position: relative;
}

.ligasuche input {
  min-width: 11rem;
}

/* Die Trefferliste hängt unter dem Feld und über allem anderen — auch über
   der Karte, die als eigener Stapelkontext sonst darüberläge. */
.ligasuche__treffer {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1200;
  width: max(100%, 20rem);
  max-height: 19rem;
  margin: 0.25rem 0 0;
  padding: 0.25rem;
  overflow-y: auto;
  list-style: none;
  border-radius: 0.6rem;
  background: #fff;
  box-shadow: var(--schatten);
}

.ligasuche__eintrag {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 0.5rem;
  align-items: baseline;
  padding: 0.4rem 0.5rem;
  border-radius: 0.4rem;
  cursor: pointer;
}

.ligasuche__eintrag:hover,
.ligasuche__eintrag:focus-visible {
  background: var(--hintergrund);
  outline: none;
}

.ligasuche__punkt {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ligafarbe);
}

.ligasuche__titel {
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
}

.ligasuche__ort {
  grid-column: 2;
  font-size: 0.72rem;
  color: var(--gedaempft);
}

.ligasuche__leer {
  padding: 0.5rem;
  font-size: 0.8rem;
  color: var(--gedaempft);
}

/* -- Spielplan der gewählten Liga ----------------------------------------- */

/* Steht an derselben Stelle wie die Legende und ersetzt sie: Bei einer
   einzelnen Liga gibt es keine Spielklassen mehr zu unterscheiden. */
/* `display: flex` schlägt das `display: none`, das der Browser dem
   hidden-Attribut mitgibt — beide haben dieselbe Spezifität, und die eigene
   Regel steht später. Ohne die Ausnahme unten ließ sich der Spielplan nicht
   mehr schließen. Die Legende hat das Problem nicht, weil sie kein `display`
   setzt. */
.ligaplan[hidden] {
  display: none;
}

.ligaplan {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 500;
  display: flex;
  flex-direction: column;
  width: 17rem;
  max-height: calc(100% - 1.5rem);
  padding: 0.6rem 0.7rem;
  border-radius: 0.6rem;
  background: rgb(255 255 255 / 96%);
  backdrop-filter: blur(6px);
  box-shadow: var(--schatten);
}

.ligaplan__kopf {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  justify-content: space-between;
}

.ligaplan__name {
  margin: 0;
  padding-left: 0.85rem;
  position: relative;
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1.3;
}

.ligaplan__name::before {
  content: "";
  position: absolute;
  top: 0.35rem;
  left: 0;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ligafarbe);
}

.ligaplan__zu {
  flex: none;
  padding: 0 0.25rem;
  border: 0;
  background: none;
  color: var(--gedaempft);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.ligaplan__zu:hover {
  color: var(--text);
}

.ligaplan__zahl {
  margin: 0.15rem 0 0.4rem;
  font-size: 0.72rem;
  color: var(--gedaempft);
}

.ligaplan__liste {
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.ligaplan__tag {
  margin-top: 0.5rem;
  padding: 0.15rem 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--gedaempft);
  border-bottom: 1px solid var(--linie);
}

.ligaplan__tag:first-child {
  margin-top: 0;
}

.ligaplan__spiel {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 0.45rem;
  padding: 0.35rem 0.4rem;
  border-radius: 0.4rem;
  cursor: pointer;
}

.ligaplan__spiel:hover,
.ligaplan__spiel:focus-visible {
  background: var(--hintergrund);
  outline: none;
}

.ligaplan__zeit {
  font-size: 0.75rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ligaplan__paarung {
  font-size: 0.78rem;
  line-height: 1.3;
}

.ligaplan__ort {
  grid-column: 2;
  font-size: 0.7rem;
  color: var(--gedaempft);
}

/* Auf schmalen Geräten würden Legende und Spielplan die halbe Karte
   verdecken. Der Spielplan bleibt, weil er dort der eigentliche Nutzen ist —
   er legt sich aber flacher an den unteren Rand. */
@media (max-width: 34rem) {
  .ligaplan {
    top: auto;
    right: 0.5rem;
    bottom: 0.5rem;
    left: 0.5rem;
    width: auto;
    max-height: 45%;
  }
}

/* -- Der Weg zu den Ergebnissen ------------------------------------------ */

.ergebnisse {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--linie);
}

.ergebnisse[hidden] {
  display: none;
}

/* 6,38:1 gegen Weiß — geprüft wie die übrigen Flächen. Betont, weil dahinter
   die Ergebnisse stehen, die wir selbst nicht haben. */
a.ergebnisse__knopf {
  display: inline-block;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--rasen);
  border-radius: 0.45rem;
  background: var(--rasen);
  font-size: 0.75rem;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
}

a.ergebnisse__knopf:hover,
a.ergebnisse__knopf:focus-visible {
  background: #25552f;
  background: color-mix(in srgb, var(--rasen) 85%, black);
  color: #fff;
}

/* Die Wege aus einem Aufklapper heraus — „Spielstätte anzeigen", „Spiele
   dieses Vereins", „Derbys einordnen".

   Es sind Aktionen auf der Karte und keine Verweise nach außen. Genau das
   sagten sie vorher nicht: Sie waren unterstrichener grüner Text, also das
   Zeichen für einen Link, und der einzige echte Link im Aufklapper — der zu
   fussball.de — sieht als gefüllter Knopf ganz anders aus. Zwei Arten von
   Ziel, zwei Erscheinungen, und die unauffälligere trug das Zeichen der
   auffälligeren.

   Der zweite Grund für den Umbau war handfester: Die Symbole waren
   Unicode-Zeichen („⌖", „→", „⚔"). Solche Zeichen sind unterschiedlich breit,
   je nach Schrift verschieden weit vom Rand entfernt und teils gar nicht
   vorhanden. Die drei Beschriftungen begannen deshalb an drei verschiedenen
   Stellen, und „⚔" kam auf manchen Geräten als leeres Rechteck. Jetzt stehen
   die Symbole in einem festen Kästchen und fluchten. */
.spiel__wege {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0.5rem -0.4rem 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--linie);
}

.spiel__hin {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  /* Gilt für den Knopf, der allein steht — im Aufklapper eines Spiels führt
     nur ein Weg heraus, nämlich an den Platz. In der Gruppe wird das gleich
     wieder aufgehoben. */
  margin: 0.35rem -0.4rem 0;
  padding: 0.45rem 0.4rem;
  border: 0;
  border-radius: 8px;
  background: none;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--rasen);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.spiel__wege .spiel__hin {
  margin: 0;
}

/* Das Symbol.
   `mask` statt `background`: So nimmt es `currentColor` an und wechselt beim
   Überfahren die Farbe mit der Schrift. Ein eingefärbtes Hintergrundbild
   müsste dafür zweimal in der Datei stehen, einmal je Farbe.

   Feste Kantenlänge und `flex: none` — daran hängt das Fluchten der drei
   Beschriftungen. */
.spiel__hin::before {
  content: "";
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  background-color: currentColor;
  mask-position: center;
  mask-repeat: no-repeat;
  mask-size: contain;
  -webkit-mask-position: center;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%277%27%2F%3E%3Cpath%20d%3D%27M12%202v3M12%2019v3M2%2012h3M19%2012h3%27%2F%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%271.2%27%20fill%3D%27black%27%20stroke%3D%27none%27%2F%3E%3C%2Fsvg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%277%27%2F%3E%3Cpath%20d%3D%27M12%202v3M12%2019v3M2%2012h3M19%2012h3%27%2F%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%271.2%27%20fill%3D%27black%27%20stroke%3D%27none%27%2F%3E%3C%2Fsvg%3E");
}

/* Der Weg in eine andere Ansicht, nicht zu einem Ort — deshalb ein Pfeil und
   kein Fadenkreuz. Im Vereins-Aufklapper stehen alle drei untereinander, und
   zweimal dasselbe Zeichen hieße zweimal dieselbe Art von Aktion.

   Muss NACH der Grundregel stehen: Beide Selektoren wiegen gleich schwer, es
   gewinnt der spätere. */
.spiel__hin--weiter::before {
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M4%2012h14M12%206l6%206-6%206%27%2F%3E%3C%2Fsvg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M4%2012h14M12%206l6%206-6%206%27%2F%3E%3C%2Fsvg%3E");
}

/* Dritter Weg im Vereins-Aufklapper: die Nachbarn einordnen. Ein Stapel
   Karten, weil genau das dahinter erscheint — und weil es weder um einen Ort
   noch um eine andere Ansicht geht, sondern um eine Frage an den Betrachter. */
.spiel__hin--derby::before {
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Crect%20x%3D%273%27%20y%3D%277%27%20width%3D%2712%27%20height%3D%2714%27%20rx%3D%272%27%2F%3E%3Cpath%20d%3D%27M8%204h9a2%202%200%200%201%202%202v11%27%2F%3E%3C%2Fsvg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%272%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Crect%20x%3D%273%27%20y%3D%277%27%20width%3D%2712%27%20height%3D%2714%27%20rx%3D%272%27%2F%3E%3Cpath%20d%3D%27M8%204h9a2%202%200%200%201%202%202v11%27%2F%3E%3C%2Fsvg%3E");
}

/* Die Fläche erscheint erst beim Überfahren. Dauerhaft gefüllt konkurrierten
   drei graue Balken mit dem einen grünen Knopf darunter, der die Hauptsache
   ist. */
.spiel__hin:hover,
.spiel__hin:focus-visible {
  /* Erst die Fassung, die jeder Browser kennt, dann die aus der Variable
     gerechnete — wie überall sonst in dieser Datei. */
  background: rgb(47 107 60 / 9%);
  background: color-mix(in srgb, var(--rasen) 9%, transparent);
  color: #25552f;
  color: color-mix(in srgb, var(--rasen) 85%, black);
}

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

.spiel__hin:active {
  background: rgb(47 107 60 / 16%);
  background: color-mix(in srgb, var(--rasen) 16%, transparent);
}

/* Auf dem Telefon wird mit dem Daumen getroffen, nicht mit dem Zeiger. */
@media (pointer: coarse) {
  .spiel__hin {
    min-height: 44px;
    font-size: 0.85rem;
  }
}

/* -- Vereine einordnen ---------------------------------------------------- */

/* Eigene Fläche über der Karte statt im Aufklapper: Dort ist auf dem Telefon
   kein Platz für Wappen, Spielklasse und drei Antworten. */
.derby {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgb(20 30 20 / 45%);
}

.derby[hidden] {
  display: none;
}

.derby__kasten {
  width: min(420px, 100%);
  padding: 18px 20px 20px;
  border-radius: var(--rundung);
  background: #fff;
  box-shadow: var(--schatten);
}

.derby__kopf {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  justify-content: space-between;
}

.derby__titel {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.35;
}

/* Neben dem Schließkreuz, aber als Wort: Ein zweites Zeichen daneben wäre
   Rätselraten, und geteilt wird selten genug, dass es Platz haben darf. */
.derby__teilen {
  flex: none;
  align-self: center;
  padding: 4px 10px;
  border: 1px solid var(--linie);
  border-radius: 999px;
  background: #fff;
  color: var(--gedaempft);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.derby__teilen:hover,
.derby__teilen:focus-visible {
  border-color: var(--rasen);
  color: var(--rasen);
}

.derby__zu {
  flex: none;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--gedaempft);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

/* Der Stapel. Feste Höhe, weil die Karten darin übereinanderliegen und ein
   mitwachsender Container beim Wischen zusammenklappen würde.

   Etwas mehr als die ursprünglichen 190 Pixel: Namen wie „SG Eversburg/Gaste-
   Hasbergen/Hellern" brauchen drei Zeilen, und auf dem Telefon standen sie
   sonst unten aus der Karte heraus. */
.derby__karte {
  position: relative;
  height: 230px;
  margin: 16px 0;
}

/* Eine Karte. Der farbige Streifen links zeigt die Spielklasse — dieselbe
   Farbe wie der Marker auf der Karte, damit beides zusammengehört.

   `touch-action: none` ist nicht Kosmetik: Ohne diese Zeile scrollt der
   Browser auf dem Telefon die Seite, statt die Karte ziehen zu lassen, und die
   Geste kommt im Skript nie an. */
.derby__blatt {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 16px 18px;
  border: 1px solid var(--linie);
  border-left: 4px solid var(--ligafarbe, var(--rasen));
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 4px 16px rgb(20 30 20 / 10%);
  cursor: grab;
  touch-action: none;
  user-select: none;
  /* Nichts tritt über den Rand — auf dem Telefon ragten lange Vereinsnamen
     seitlich über die Karte hinaus, mitten in die Landkarte hinein. Die
     eigentliche Ursache steht bei `.derby__seite`; dies ist der Riegel
     dahinter, damit so etwas nie wieder aus dem Kasten läuft. */
  overflow: hidden;
  transition:
    transform 180ms ease-out,
    opacity 180ms ease-out;
}

/* Die Karte darunter. Sie macht aus einer Karte einen Stapel — ohne sie wischt
   man ins Leere und das Nächste erscheint aus dem Nichts. */
.derby__blatt--hinten {
  transform: scale(0.94) translateY(10px);
  opacity: 0.55;
  pointer-events: none;
}

/* Während der Daumen zieht, folgt die Karte unmittelbar. Der Übergang steht
   deshalb an der Karte und wird hier abgeschaltet, nicht umgekehrt: Blieb eine
   Flugklasse nach dem Loslassen kleben, lief der nächste Zug hinterher — genau
   das fühlte sich holprig an. */
.derby__blatt--zieht {
  cursor: grabbing;
  transition: none;
}

.derby__paarung {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.derby__seite {
  display: flex;
  /* `min-width: 0` ist die eigentliche Reparatur. Ein Flex-Element schrumpft
     ohne diese Zeile nicht unter die Breite seines Inhalts — bei „SG
     Eversburg/Gaste-Hasbergen/Hellern" ist das breiter als das Telefon, und
     der Name stand links und rechts über die Karte hinaus. */
  flex: 1;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
}

.derby__wappen {
  object-fit: contain;
}

.derby__name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  /* Vereinsnamen sind aneinandergehängte Ortsnamen mit Schrägstrichen und ohne
     Leerzeichen. Ohne diese Zeile findet der Umbruch keine Stelle und die
     ganze Kette bleibt eine einzige lange Zeile. */
  overflow-wrap: anywhere;
  hyphens: auto;
  /* Und wenn es trotzdem zu lang wird, endet es mit Auslassungspunkten statt
     die Karte zu sprengen. Drei Zeilen fassen die längsten echten Namen. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.derby__vs {
  flex: none;
  color: var(--gedaempft);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.derby__beiwerk {
  margin: 12px 0 0;
  color: var(--gedaempft);
  font-size: 12px;
  text-align: center;
}

/* Die Marken erscheinen beim Ziehen und sagen, was gleich passiert. Sie liegen
   von Anfang an auf der Karte und werden nur ein- und ausgeblendet — sie erst
   im Skript zu erzeugen wäre ein Layoutwechsel mitten in der Geste. */
.derby__marke {
  position: absolute;
  top: 14px;
  padding: 4px 10px;
  border: 2px solid currentcolor;
  border-radius: 6px;
  opacity: 0;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  pointer-events: none;
}

.derby__marke--derby {
  right: 14px;
  transform: rotate(8deg);
  color: #b4402c;
}

.derby__marke--freund {
  left: 14px;
  transform: rotate(-8deg);
  color: var(--rasen);
}

.derby__marke--neutral {
  left: 50%;
  translate: -50% 0;
  color: var(--gedaempft);
}

.derby__fertig {
  margin: 0;
  color: var(--gedaempft);
  font-size: 14px;
}

.derby__wahl {
  display: grid;
  gap: 8px;
}

.derby__wahl[hidden] {
  display: none;
}

.derby__knopf {
  padding: 11px 14px;
  border: 1px solid var(--linie);
  border-radius: 10px;
  background: #fff;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  text-align: left;
  cursor: pointer;
}

.derby__knopf:hover,
.derby__knopf:focus-visible {
  border-color: var(--rasen);
  color: var(--rasen);
}

/* Die Pfeile stehen für die Wischrichtung, nicht für ein Symbol der Sache
   selbst. Wer einmal geklickt hat, weiß danach, wohin er wischen kann. */
.derby__knopf--derby::before {
  content: "→  ";
}

.derby__knopf--freund::before {
  content: "←  ";
}

.derby__knopf--neutral::before {
  content: "↑  ";
}

.derby__hinweis {
  margin: 0 0 4px;
  color: var(--gedaempft);
  font-size: 12px;
  text-align: center;
}

/* Wer Bewegung abbestellt hat, bekommt keine. Die Karte springt dann an ihren
   Platz beziehungsweise verschwindet, statt zu fliegen — die Funktion bleibt
   dieselbe. */
@media (prefers-reduced-motion: reduce) {
  .derby__blatt {
    transition: none;
  }
}

/* Überspringen ist kein Urteil und sieht deshalb auch nicht wie eines aus. */
.derby__weiter {
  margin-top: 2px;
  padding: 6px;
  border: 0;
  background: none;
  color: var(--gedaempft);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.derby__stand {
  margin: 12px 0 0;
  text-align: center;
}

/* Der Weg zu den eigenen Einschätzungen. Ein Knopf, kein Verweis: Er führt
   nicht woandershin, sondern klappt an Ort und Stelle etwas auf. */
.derby__schalter {
  padding: 2px 4px;
  border: 0;
  background: none;
  color: var(--gedaempft);
  font: inherit;
  font-size: 12px;
  text-decoration: underline;
  cursor: pointer;
}

.derby__schalter:disabled {
  text-decoration: none;
  cursor: default;
}

/* Die Liste der eigenen Urteile. Sie tritt an die Stelle des Stapels, statt
   darunter zu erscheinen — sonst wüchse der Kasten über den Schirm hinaus. */
.derby__liste {
  max-height: 260px;
  margin: 16px 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.derby__liste[hidden] {
  display: none;
}

.derby__zeile {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: space-between;
  padding: 8px 2px;
  border-bottom: 1px solid var(--linie);
}

.derby__zeilentext {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.derby__zeilenname {
  font-size: 14px;
  font-weight: 600;
}

.derby__zeilenurteil {
  color: var(--gedaempft);
  font-size: 12px;
}

.derby__zurueck {
  flex: none;
  padding: 5px 9px;
  border: 1px solid var(--linie);
  border-radius: 8px;
  background: #fff;
  color: var(--gedaempft);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.derby__zurueck:hover,
.derby__zurueck:focus-visible {
  border-color: var(--rasen);
  color: var(--rasen);
}

.derby__karte[hidden] {
  display: none;
}

/* -- Schmale Geräte ------------------------------------------------------- */

/* Auf breiten Bildschirmen gibt es den Aufklappknopf nicht, und die Filter
   sind unmittelbar Teil der Leiste. `display: contents` ist dafür der Kniff:
   Der Container verschwindet aus dem Layout, seine Kinder bleiben Flex-Items
   der Leiste — das Bild ändert sich also gegenüber vorher um nichts. */
.leiste__auf {
  display: none;
}

/* Innenleben der Pille. Steht außerhalb des Media-Query, weil es nur greift,
   wenn die Pille überhaupt sichtbar ist — und das entscheidet die Regel oben. */
.leiste__auf-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  min-width: 0;
  text-align: left;
}

.leiste__auf-was {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
}

.leiste__auf-wie {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--gedaempft);
}

/* Beide Zeilen einzeilig halten: Eine Pille, die je nach Filter zwei- oder
   dreizeilig wird, ließe die Karte darunter springen. */
.leiste__auf-was,
.leiste__auf-wie {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Die drei Schieberegler — dasselbe Zeichen, das Airbnb und andere für
   „Filter" benutzen. Als Pseudo-Element, damit kein Bild nachgeladen wird. */
.leiste__auf-zeichen {
  flex: none;
  width: 1.35rem;
  height: 1.35rem;
  background: currentcolor;
  color: var(--rasen);
  mask: var(--regler) center / contain no-repeat;
  -webkit-mask: var(--regler) center / contain no-repeat;
}

.leiste__filter {
  display: contents;
}

@media (max-width: 52rem) {
  /* Auf dem Telefon ist die Karte nicht ein Element auf der Seite, sondern
     die Seite. Alles andere schwebt darüber.

     Der Anlass war Rechnerei am falschen Ende: Leiste und Fußzeile nahmen
     zusammen rund ein Fünftel der Bildhöhe für Bedienelemente, die man selten
     anfasst. Google Maps, Airbnb und komoot machen es alle drei so — dort
     füllt die Karte den Bildschirm, und darüber liegen Pillen und Knöpfe.

     Das Standfeld unten und der Spielklassen-Reiter rechts schwebten ohnehin
     schon; sie waren der Beweis, dass es trägt. */
  body {
    display: block;
    position: relative;
    overflow: hidden;
  }

  .huelle {
    position: absolute;
    inset: 0;
  }

  /* Die Leiste ist jetzt nur noch der Träger der Pille — ohne eigene Fläche,
     ohne Trennlinie, ohne Höhe über das hinaus, was die Pille braucht.

     Die Abstände stehen hier noch einmal, obwohl die Grundregel sie schon
     nennt: `padding` ist eine Kurzform und überschreibt sie vollständig. Genau
     daran ist der obere Sicherheitsabstand zuerst wirkungslos geblieben — er
     stand in der Grundregel und wurde hier weggeräumt. */
  .leiste {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    /* Über die Blende. Die Leiste hat einen eigenen Stapelkontext, also gilt
       der z-index des Blattes nur innerhalb davon — steht die Leiste unter der
       Blende, liegt das Blatt es auch, und man sieht die Felder wie durch
       Milchglas. Genau so war es beim ersten Versuch. */
    z-index: 1200;
    gap: 0.5rem;
    background: none;
    border-bottom: 0;
    pointer-events: none;
    padding: max(0.55rem, env(safe-area-inset-top)) max(0.6rem, env(safe-area-inset-right))
      0.55rem max(0.6rem, env(safe-area-inset-left));
  }

  /* Der Träger lässt Tippen durch, seine Kinder fangen es wieder ein — sonst
     läge über dem oberen Kartenrand eine unsichtbare Sperre. */
  .leiste > * {
    pointer-events: auto;
  }

  /* Der Titel entfällt hier. Keines der Vorbilder zeigt auf dem Telefon einen
     Seitennamen über der Karte; er steht im Reiter des Browsers, und die
     Fläche ist auf einem Telefon zu kostbar. */
  .leiste h1 {
    display: none;
  }

  .leiste__auf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    /* Über die ganze Breite, wie die Suchleiste bei den Vorbildern. Der
       Spielklassen-Reiter rückt dafür darunter — nebeneinander bliebe für
       beide zu wenig, und ein abgeschnittenes „SPIELKL…" hilft niemandem. */
    flex: 1 1 100%;
    padding: 0.45rem 0.8rem;
    border: 0;
    border-radius: 999px;
    background: rgb(255 255 255 / 96%);
    backdrop-filter: blur(6px);
    box-shadow: var(--schatten);
    font: inherit;
    cursor: pointer;
    /* Fingerbreit: Alles darunter trifft man auf einem Telefon nicht. */
    min-height: 2.75rem;
  }

  .leiste__filter {
    display: none;
  }

  /* Das Blatt fährt von unten herein, nicht von oben herunter.

     Von oben hätte es an der Pille gehangen und ausgerechnet den Teil der
     Karte zugedeckt, den man gerade betrachtet. Von unten ist es außerdem
     dort, wo der Daumen ohnehin ist — bei acht Feldern macht das den
     Unterschied zwischen bequem und Verrenkung. */
  .leiste__filter--offen {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1200;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 0.7rem 0.8rem;
    max-height: 82dvh;
    overflow-y: auto;
    padding: 1.4rem max(1rem, env(safe-area-inset-right))
      max(1rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));
    border-radius: 1.1rem 1.1rem 0 0;
    background: #fff;
    box-shadow: 0 -8px 30px rgb(20 30 20 / 18%);
  }

  /* Der Griff. Kein Bedienelement — er sagt nur, dass hier etwas liegt, das
     man wieder wegschieben kann. */
  .leiste__filter--offen::before {
    content: "";
    position: absolute;
    top: 0.55rem;
    left: 50%;
    transform: translateX(-50%);
    width: 2.5rem;
    height: 0.25rem;
    border-radius: 999px;
    background: var(--linie);
  }

  .leiste__filter--offen label {
    /* Zwei Felder je Zeile, die Suchfelder über die volle Breite. */
    flex: 1 1 8rem;
  }

  .leiste__filter--offen .ligasuche {
    flex-basis: 100%;
  }

  /* Fingerbreite Bedienelemente — und mindestens 16 Pixel Schrift.
     
     Die Schriftgröße ist hier keine Geschmacksfrage, sondern der Unterschied
     zwischen einer benutzbaren und einer kaputten Seite: Bekommt auf iOS ein
     Eingabefeld mit weniger als 16 Pixeln den Fokus, zoomt Safari von sich
     aus hinein — und zoomt nicht wieder heraus. Der sichtbare Ausschnitt ist
     danach schmaler als das Layout, und alles am rechten Rand ist
     abgeschnitten: die Leaflet-Zeile, der Spielklassen-Reiter, das Standfeld,
     die Fußzeile.

     Aus der Ferne sieht das aus, als wäre die Seite nicht responsiv. Sie ist
     es; sie wird nur vergrößert dargestellt. Deshalb steht hier `1rem` und
     nicht das `0.85rem` der Grundregel.

     Der andere Weg — `maximum-scale=1` in der Viewport-Angabe — verbietet
     zugleich das absichtliche Aufziehen mit zwei Fingern. Auf einer Karte
     wäre das besonders daneben. */
  .leiste input,
  .leiste select,
  .leiste button {
    min-height: 2.75rem;
    font-size: 1rem;
  }

  /* Die Legende ist mit elf Spielklassen und fünf Gruppen zu lang für ein
     Telefon — sie verdeckte sonst die halbe Karte. Zugeklappt zeigt sie nur
     ihren Kopf, der zugleich der Schalter ist. */
  /* Unter die Pille statt neben sie. `--leiste-hoehe` misst das Skript nach
     jeder Änderung nach — gerechnet ließe sie sich nicht, weil der obere
     Sicherheitsabstand von Gerät und Ausrichtung abhängt. Der Rückfallwert
     gilt nur für den Augenblick vor der ersten Messung. */
  .legende {
    max-width: 11rem;
    top: calc(var(--leiste-hoehe, 4rem) + 0.4rem);
    right: max(0.5rem, env(safe-area-inset-right));
    max-height: calc(100% - var(--leiste-hoehe, 4rem) - 1.5rem);
    padding: 0.4rem 0.55rem;
  }

  /* Leaflets Zoomknöpfe sitzen oben links — also genau dort, wo jetzt die
     Pille liegt. Sie rücken darunter, gemessen an derselben Variablen wie die
     Legende. Ohne das verdeckten sie den Anfang des Pillentextes. */
  .leaflet-top.leaflet-left {
    top: var(--leiste-hoehe, 4rem);
  }

  /* Die Fußzeile wird zur dünnen Zeile am unteren Kartenrand. Sie muss
     bleiben — die Herkunft der Karte ist keine Zierde, sondern Bedingung der
     Lizenz —, darf aber keine eigene Bank mehr sein. */
  .fusszeile {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 500;
    justify-content: center;
    gap: 0.3rem;
    padding: 0.15rem max(0.5rem, env(safe-area-inset-right))
      max(0.15rem, env(safe-area-inset-bottom)) max(0.5rem, env(safe-area-inset-left));
    font-size: 0.6rem;
    background: rgb(255 255 255 / 82%);
    border-top: 0;
  }

  /* Leaflets eigene Herkunftszeile entfällt dafür: Sie stünde unmittelbar
     darüber und nennte dieselbe Quelle ein zweites Mal. Unsere Fußzeile
     verlinkt OpenStreetMap, damit ist der Lizenz genügt. */
  .leaflet-control-attribution {
    display: none;
  }

  /* Über die Fußzeile heben, sonst läge das Standfeld darauf. Die Breite
     bleibt gedeckelt wie überall — eine Pille über die ganze Bildbreite ist
     keine Pille mehr, sondern eine zweite Leiste. */
  .stand {
    bottom: calc(2.1rem + env(safe-area-inset-bottom));
    left: max(0.5rem, env(safe-area-inset-left));
    max-width: min(26rem, calc(100% - 1rem));
  }

  .legende--zu .legende__liste,
  .legende--zu .legende__alle {
    display: none;
  }

  .legende__kopf {
    margin: 0;
    cursor: pointer;
  }

  .legende:not(.legende--zu) .legende__kopf {
    margin-bottom: 0.35rem;
  }

  .legende__kopf::after {
    content: " ▾";
  }

  .legende--zu .legende__kopf::after {
    content: " ▸";
  }

  /* Der Aufklapper darf nicht breiter sein als das Gerät. */
  .leaflet-popup-content {
    max-width: calc(100vw - 4rem);
  }
}

/* Das Ansichtsfeld ist der wichtigste Schalter der Leiste — es entscheidet,
   was die Karte überhaupt zeigt. Deshalb steht es vorn. */
.leiste__ansicht select {
  font-weight: 600;
}

/* -- Mehrere Vereine an einem Platz --------------------------------------- */

/* Rund jede zehnte Spielstätte gehört mehr als einem Verein, eine sogar acht.
   Ihre Marker liegen exakt übereinander — ohne diese Leiste ist nur der
   zuletzt gezeichnete erreichbar, die übrigen sind unsichtbar vorhanden. */
.aufteiler {
  margin: 0 0 10px;
  padding: 0 0 8px;
  border-bottom: 1px solid var(--linie);
}

.aufteiler__hinweis {
  display: block;
  margin-bottom: 6px;
  color: var(--gedaempft);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.aufteiler__reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

/* Der farbige Punkt vor dem Namen ist dieselbe Spielklassenfarbe wie auf der
   Karte — sonst müsste man raten, welcher der Verein aus der höchsten Klasse
   ist, und genau der steht voreingestellt vorn. */
.aufteiler__knopf {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  border: 1px solid var(--linie);
  border-radius: 999px;
  background: #fff;
  color: var(--gedaempft);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.aufteiler__knopf::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ligafarbe, var(--rasen));
}

.aufteiler__knopf:hover {
  border-color: var(--rasen);
  color: var(--text);
}

.aufteiler__knopf--aktiv {
  border-color: var(--rasen);
  color: var(--text);
  font-weight: 600;
}
