/* static/style.css – gewachsen ueber viele Nutzerwunsch Runden seit
   17.08.2026, kein eigenes Build/Bundling, eine einzige Datei fuer die
   ganze Oberflaeche (siehe templates/index.html, <link rel="stylesheet">).
   Grober Wegweiser, damit man nicht bei jeder Suche die ganze Datei lesen
   muss (Fund vom 23.08.2026, fuenfte Runde, "Verbessere den Code und die
   Struktur"), ungefaehre Zeilennummern zum Stand dieser Ergaenzung, echte
   Abschnittsgrenzen zwischen den Themen sind fliessend:

     ~1     Farb-/Abstands-Variablen (:root), Dunkelmodus Ueberschreibungen
     ~196   Mobile Bottom Sheet (Griffleiste/Abdunklung), Seitenleisten Kacheln
     ~333   Seitenleiste: Datenquelle Panel, Subscription-/CPO-Listen
     ~679   CSV Export, Nutzerverwaltung Link, Filterpanel (Regler, Zahlenfelder)
     ~931   Einklappbare Legende, Vergleichsansicht
     ~1133  Dashboard (Reiter, KPI Zeile, Betreiber Tabelle, Verlauf, Preise)
     ~1743  Schwebende Panels ueber der Karte (Legende, Schnellfilter,
            Entfernung Filter, Filteransaetze, Standort/Ueberschneidung Warnungen)
     ~1973  Leaflet Info Popup (Stations-/Ladepunkt Details, Vergleich Knopf)
     ~2348  Responsive/Mobile Anpassungen (@media)
     ~2507  Verwaltungsseite (/verwaltung, separates Template)

   Dark Mode Variablen stehen bewusst zweimal (@media(prefers-color-scheme)
   UND :root[data-theme="dark"], siehe Kommentar dort): beide muessen bei
   einer Farbaenderung gepflegt werden. */

:root {
  --hintergrund: #f8f9fb;
  --flaeche: rgba(255, 255, 255, 0.92);
  --flaeche-rand: var(--eingabe-hg);
  --text: #1a1d24;
  --text-schwach: #8a909c;
  --akzent: #2b6de0;
  --akzent-dunkel: #1e58c0;
  --frei: #2bb86a;
  --belegt: #e8554b;
  --gestoert: #f5b95c;
  --veraltet: #8a7ca6;
  --unbekannt: #9aa0ac;
  --radius-gross: 20px;
  --radius-klein: 12px;
  --schatten: 0 8px 30px rgba(15, 20, 30, 0.06);

  /* Design Auswahl (Nutzerwunsch 24.08.2026: "moderner/professioneller",
     drei Vorschlaege gemacht, siehe design.js und die drei Bloecke unten
     :root[data-design="enterprise"]/[data-design="kontrollzentrum"]).
     Diese Variablen fassen alles zusammen, was sich je Design aendert,
     aber bisher NICHT ueber eine der Variablen oben lief (Schriftart,
     Glas-Weichzeichnung, Rahmenfarben bei Eingaben/Knoepfen/Regler,
     Dashboard eigene Grauton Variablen). Ohne gesetztes data-design (wie
     bisher) bzw. bei data-design="glas" bleiben alle Werte exakt wie
     vorher, das Standarddesign aendert sich also nicht. */
  --schriftart: "Segoe UI", system-ui, -apple-system, sans-serif;
  --panel-blur: 8px;
  /* Bugfix 30.08.2026 (Nutzerwunsch "Beim Design Glas sieht man keine
     Umrandungen der Klickflaechen"): diese neun Variablen standen hier
     bis jetzt als KREISVERWEIS auf sich selbst (z.B. buchstaeblich
     "--knopf-rand: var(--knopf-rand);"). Eine CSS Custom Property, die
     sich selbst referenziert, gilt als "invalid at computed-value time":
     jede Stelle, die per var(--knopf-rand) darauf zugreift, bekommt dann
     NICHT etwa einen leeren/transparenten Wert, sondern faellt auf den
     Anfangswert der jeweiligen Eigenschaft zurueck (bei "border" also
     "none", voellig unsichtbar), ohne dass der Browser dafuer einen
     Fehler meldet. Betraf ausschliesslich das Standarddesign "Glas" (kein
     data-design Attribut): Enterprise/Kontrollzentrum/Dunkelmodus
     ueberschreiben alle neun Werte weiter unten in dieser Datei mit
     echten Farben und waren davon nie betroffen, siehe dortige Bloecke,
     genau das hat den Fehler bisher auf ein einzelnes Design begrenzt und
     dadurch schwerer auffindbar gemacht. Betroffen war nicht nur
     --knopf-rand (Rand von .knopf-sekundaer und aehnlichen Knoepfen mit
     background:transparent, also GENAU die "Klickflaechen" ohne eigene
     Flaeche aus der Nutzermeldung), sondern ueber die Kettenreferenz
     "--flaeche-rand: var(--eingabe-hg)" weiter oben in diesem :root Block
     auch --flaeche-rand selbst (Rand von .panel, Dropdowns, Toasts,
     Tabellen, siehe die border-Regeln, die var(--flaeche-rand) nutzen).
     Die urspruenglichen, VOR der Design Auswahl vom 24.08.2026 tatsaechlich
     hart codierten Werte liessen sich mangels einer alten Sicherung dieser
     Datei nicht mehr rekonstruieren (siehe CHANGELOG.md/docs/CHANGELOG.md).
     Die Werte unten sind deshalb bewusst identisch zu den bereits
     vorhandenen, echten Farben aus dem hellen Enterprise Block weiter
     unten (dieselbe neutrale Grau Familie, passt farblich zum sehr
     aehnlichen Glas Hintergrund #f3f4f7): Schriftart/Weichzeichnung/
     Eckenradien/Schatten bleiben die eigentlichen, gewollten Unterschiede
     zwischen den Designs (siehe Kommentar beim Enterprise Block), nicht
     diese strukturellen Rahmenfarben. */
  --knopf-rand: #d7dae1;
  --rand-schwach: #eef0f3;
  --eingabe-hg: #f6f7f9;
  --slider-thumb-rand: #ffffff;
  --dash-bg: #fdfdfe;
  --dash-rand: rgba(0, 0, 0, 0.06);
  --dash-rand-schwach: rgba(0, 0, 0, 0.03);
  --dash-rand-eingabe: rgba(0, 0, 0, 0.05);
  --dash-rand-tabelle: rgba(0, 0, 0, 0.06);
  --dash-flaeche-schwach: #fafbfc;
  --dash-hover: #fafbfc;
  --dash-tab-aktiv-bg: #fff;
  --dash-meter-spur: #e6f5ea;
}

/* Dunkelmodus (Nutzerwunsch 23.08.2026: "Dunkelmodus fuer die Nutzung am
   Abend oder im Auto"). Zwei Faelle, beide definieren dieselben Werte:
   1) Keine explizite Wahl gespeichert (kein data-theme Attribut auf
      <html>) UND das Betriebssystem/der Browser meldet eine dunkle
      Systempraeferenz: automatisch dunkel, ohne dass der Nutzer den Knopf
      ueberhaupt anfassen muss.
   2) data-theme="dark" explizit gesetzt (siehe static/js/theme.js): wirkt
      IMMER, auch wenn das System selbst hell eingestellt ist, das ist der
      Fall nach einem Klick auf den Umschalt Knopf.
   :root:not([data-theme="light"]) im ersten Block sorgt dafuer, dass ein
   explizit gewaehltes "hell" die Systempraeferenz uebersteuern kann (siehe
   themeUmschalten() in theme.js, das auch "hell" als expliziten Wert
   setzt, nicht nur "dunkel"). Alle uebrigen Regeln in dieser Datei nutzen
   ausschliesslich diese Variablen (keine fest verdrahteten Hex Farben fuer
   Hintergrund/Text), bis auf eine Handvoll gezielter Ausnahmen weiter
   unten (Seitenleisten Verlauf, Dashboard Hintergrund, aktive Tabs/Chips,
   Lade Ueberlagerung, Leaflet Popup), die eigene, ebenfalls per
   [data-theme="dark"] ueberschriebene Werte brauchen, weil sie keine der
   :root Variablen verwenden bzw. (beim Leaflet Popup) aus der externen
   leaflet.css stammen. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --hintergrund: #16181e;
    --flaeche: rgba(32, 35, 44, 0.72);
    --flaeche-rand: rgba(255, 255, 255, 0.06);
    --text: #e0e2e8;
    --text-schwach: #9aa0ac;
    --akzent: #4a7de0;
    --akzent-dunkel: #3a6df0;
    --frei: #35c37a;
    --belegt: #ff6259;
    --gestoert: #f5b95c;
    --veraltet: #a597c4;
    --unbekannt: #7d8593;
    --schatten: 0 8px 30px rgba(0, 0, 0, 0.3);
  }
}

:root[data-theme="dark"] {
  --hintergrund: #16181e;
  --flaeche: rgba(32, 35, 44, 0.72);
  --flaeche-rand: rgba(255, 255, 255, 0.06);
  --text: #e0e2e8;
  --text-schwach: #9aa0ac;
  --akzent: #4a7de0;
  --akzent-dunkel: #3a6df0;
  --frei: #35c37a;
  --belegt: #ff6259;
  --gestoert: #f5b95c;
  --veraltet: #a597c4;
  --unbekannt: #7d8593;
  --schatten: 0 8px 30px rgba(0, 0, 0, 0.3);
}

/* Gezielte Ausnahmen fuer den Dunkelmodus, siehe Begruendung im Kommentar
   ueber den :root Bloecken oben: Stellen, die keine der dortigen
   Variablen verwenden, entweder weil sie schon vor der Variablen
   Einfuehrung einen eigenen festen Wert hatten (Seitenleisten Verlauf,
   Dashboard Hintergrund) oder weil sie aus der externen leaflet.css
   stammen (Popup Huelle). Absichtlich als eigener Block mit hoeherer
   Selektor Spezifitaet statt die urspruenglichen Regeln direkt zu
   aendern: die urspruengliche Regel bleibt unveraendert fuer den
   Hellmodus lesbar, die Dunkelmodus Abweichung steht separat und
   nachvollziehbar daneben. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) #seitenleiste {
    background: linear-gradient(180deg, #1a1c24, #14161c);
    border-right-color: rgba(255, 255, 255, 0.06);
  }
  :root:not([data-theme="light"]) #dashboard-bereich {
    background: #1c1f28;
  }
  :root:not([data-theme="light"]) .dashboard-tab.aktiv,
  :root:not([data-theme="light"]) .verlauf-filter-chip.aktiv {
    background: #262932;
  }
  :root:not([data-theme="light"]) #lade-overlay, :root:not([data-theme="light"]) .seiten-lade-overlay {
    background: rgba(20, 22, 28, 0.5);
  }
  :root:not([data-theme="light"]) .leaflet-popup-content-wrapper,
  :root:not([data-theme="light"]) .leaflet-popup-tip {
    background: #1e212a;
    color: var(--text);
  }
  /* Die Standard OpenStreetMap Kacheln selbst kommen als helle Bilder vom
     Kachelserver, dafuer gibt es keine dunkle Variante ohne einen anderen
     Kachelanbieter. Dieser haeufig genutzte Filter Trick (invertieren +
     Farbton drehen) macht daraus eine abgedunkelte, dem Rest der
     Oberflaeche angepasste Karte, OHNE die Kachelbilder selbst
     auszutauschen. Wirkt bewusst NUR auf die Kachelebene, nicht auf die
     eigenen, farbigen Stations Marker (eigene Ebene, siehe
     .leaflet-marker-pane weiter unten) oder Popups, die sonst ebenfalls
     invertiert und dadurch falsch eingefaerbt wuerden. */
  :root:not([data-theme="light"]) .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.92);
  }
}

:root[data-theme="dark"] #seitenleiste {
  background: linear-gradient(180deg, #1a1d26, #16181e);
  border-right-color: rgba(255, 255, 255, 0.06);
}

:root[data-theme="dark"] #dashboard-bereich {
  background: #1c1f28;
}

:root[data-theme="dark"] .dashboard-tab.aktiv,
:root[data-theme="dark"] .verlauf-filter-chip.aktiv {
  background: #262932;
}

:root[data-theme="dark"] #lade-overlay, :root[data-theme="dark"] .seiten-lade-overlay {
  background: rgba(20, 22, 28, 0.5);
}

:root[data-theme="dark"] .leaflet-popup-content-wrapper,
:root[data-theme="dark"] .leaflet-popup-tip {
  background: #1e212a;
  color: var(--text);
}

:root[data-theme="dark"] .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.92);
}

/* ===========================================================
   Design Auswahl (Nutzerwunsch 24.08.2026), siehe design.js und
   den neuen Knopf "design-umschalt-knopf" in templates/index.html.
   Drei waehlbare Designs, unabhaengig vom bestehenden Dunkelmodus
   oben (der bleibt ein eigener Schalter):

     - kein data-design Attribut bzw. data-design="glas": das
       BESTEHENDE Erscheinungsbild, unveraendert (deshalb hier auch
       kein eigener Block noetig).
     - data-design="enterprise": flaches, kantiges Layout (naeher an
       klassischer Business Software), eigene helle UND dunkle
       Variante, der bestehende Dunkelmodus Schalter wirkt normal
       weiter.
     - data-design="kontrollzentrum": dunkles "Leitstand" Design,
       bewusst IMMER dunkel (hat keine helle Variante), unabhaengig
       vom data-theme Attribut. design.js sperrt den Dunkelmodus
       Knopf waehrend dieses Design aktiv ist (siehe dortiger
       Kommentar) und die Regel ganz unten in diesem Block erzwingt
       es zusaetzlich auch optisch.

   Jeder Block setzt ausschliesslich die Variablen von oben plus die
   immer schon vorhandenen "gezielten Ausnahmen" (Seitenleiste
   Verlauf, Lade Ueberlagerung, Leaflet Popup/Kacheln), exakt nach
   demselben Muster wie die bestehenden [data-theme="dark"] Bloecke
   direkt darueber. Keine Strukturaenderung am Markup noetig, weil
   die weit ueberwiegende Mehrheit der Oberflaeche bereits ueber
   diese Variablen bzw. .panel/.knopf-sekundaer/.schnellfilter-chip
   laeuft. */

:root[data-design="enterprise"] {
  --hintergrund: #f8f9fb;
  --flaeche: #ffffff;
  --flaeche-rand: rgba(0, 0, 0, 0.06);
  --text: #181b23;
  --text-schwach: #767c8a;
  --akzent: #2b6de0;
  --akzent-dunkel: #1e58c0;
  --frei: #2bb86a;
  --belegt: #e8554b;
  --gestoert: #f5b95c;
  --veraltet: #5b4d99;
  --unbekannt: #767c8a;
  --radius-gross: 10px;
  --radius-klein: 7px;
  --schatten: none;
  --schriftart: "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --panel-blur: 0px;
  --knopf-rand: #d7dae1;
  --rand-schwach: #eef0f3;
  --eingabe-hg: #f6f7f9;
  --dash-bg: #fdfdfe;
  --dash-rand: rgba(0, 0, 0, 0.06);
  --dash-rand-schwach: rgba(0, 0, 0, 0.03);
  --dash-rand-eingabe: rgba(0, 0, 0, 0.05);
  --dash-rand-tabelle: rgba(0, 0, 0, 0.06);
  --dash-flaeche-schwach: #fafbfc;
  --dash-hover: #fafbfc;
  --dash-tab-aktiv-bg: #eeedfb;
  --dash-meter-spur: #e5f4ea;
}

:root[data-design="enterprise"] #seitenleiste {
  background: #ffffff;
  border-right: 1px solid rgba(0, 0, 0, 0.06);
}

:root[data-design="enterprise"] #lade-overlay, :root[data-design="enterprise"] .seiten-lade-overlay {
  background: rgba(246, 247, 249, 0.75);
}

@media (prefers-color-scheme: dark) {
  :root[data-design="enterprise"]:not([data-theme="light"]) {
    --hintergrund: #16181e;
    --flaeche: #1a1d26;
    --flaeche-rand: #262a33;
    --text: #e0e2e8;
    --text-schwach: #88909c;
    --akzent: #4a7de0;
    --akzent-dunkel: #3a6df0;
    --frei: #35c37a;
    --belegt: #ff6b61;
    --gestoert: #e2a13e;
    --veraltet: #a79ae0;
    --unbekannt: #88909c;
    --schatten: none;
    --knopf-rand: #262a33;
    --rand-schwach: #1d2027;
    --eingabe-hg: #1a1d24;
    --dash-bg: #1c1f28;
    --dash-rand: #262a33;
    --dash-rand-schwach: #1d2027;
    --dash-rand-eingabe: #262a33;
    --dash-rand-tabelle: #262a33;
    --dash-flaeche-schwach: #1a1d24;
    --dash-hover: #1a1d24;
    --dash-tab-aktiv-bg: #20232b;
    --dash-meter-spur: #123322;
  }
  :root[data-design="enterprise"]:not([data-theme="light"]) #seitenleiste {
    background: #1a1d26;
    border-right-color: #262a33;
  }
  :root[data-design="enterprise"]:not([data-theme="light"]) #lade-overlay, :root[data-design="enterprise"]:not([data-theme="light"]) .seiten-lade-overlay {
    background: rgba(22, 24, 30, 0.5);
  }
  :root[data-design="enterprise"]:not([data-theme="light"]) .leaflet-popup-content-wrapper,
  :root[data-design="enterprise"]:not([data-theme="light"]) .leaflet-popup-tip {
    background: #1a1d24;
    color: var(--text);
  }
  :root[data-design="enterprise"]:not([data-theme="light"]) .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.92);
  }
}

:root[data-design="enterprise"][data-theme="dark"] {
  --hintergrund: #16181e;
  --flaeche: #1a1d26;
  --flaeche-rand: #262a33;
  --text: #e0e2e8;
  --text-schwach: #88909c;
  --akzent: #4a7de0;
  --akzent-dunkel: #3a6df0;
  --frei: #35c37a;
  --belegt: #ff6b61;
  --gestoert: #e2a13e;
  --veraltet: #a79ae0;
  --unbekannt: #88909c;
  --schatten: none;
  --knopf-rand: #262a33;
  --rand-schwach: #1d2027;
  --eingabe-hg: #1a1d24;
  --dash-bg: #1c1f28;
  --dash-rand: #262a33;
  --dash-rand-schwach: #1d2027;
  --dash-rand-eingabe: #262a33;
  --dash-rand-tabelle: #262a33;
  --dash-flaeche-schwach: #1a1d24;
  --dash-hover: #1a1d24;
  --dash-tab-aktiv-bg: #20232b;
  --dash-meter-spur: #123322;
}

:root[data-design="enterprise"][data-theme="dark"] #seitenleiste {
  background: #1a1d26;
  border-right-color: #262a33;
}

:root[data-design="enterprise"][data-theme="dark"] #lade-overlay, :root[data-design="enterprise"][data-theme="dark"] .seiten-lade-overlay {
  background: rgba(22, 24, 30, 0.5);
}

:root[data-design="enterprise"][data-theme="dark"] .leaflet-popup-content-wrapper,
:root[data-design="enterprise"][data-theme="dark"] .leaflet-popup-tip {
  background: #1a1d24;
  color: var(--text);
}

:root[data-design="enterprise"][data-theme="dark"] .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.92);
}

/* Kontrollzentrum ist bewusst IMMER dunkel (keine helle Variante), die
   Werte stehen deshalb direkt unter data-design, unabhaengig von
   data-theme. Siehe designUmschalten()/designDunkelmodusSperreAnwenden()
   in design.js fuer die zugehoerige Sperre des Dunkelmodus Knopfs. */
:root[data-design="kontrollzentrum"] {
  --hintergrund: #0a0d13;
  --flaeche: #11141c;
  --flaeche-rand: rgba(255, 255, 255, 0.08);
  --text: #e7e9ee;
  --text-schwach: #7c8494;
  --akzent: #43d8ff;
  --akzent-dunkel: #1f8fb0;
  --frei: #33e08a;
  --belegt: #ff5c62;
  --gestoert: #ffb454;
  --veraltet: #a48bff;
  --unbekannt: #5f6a7d;
  --radius-gross: 16px;
  --radius-klein: 10px;
  --schatten: 0 12px 30px -10px rgba(0, 0, 0, 0.5);
  --schriftart: "Space Grotesk", system-ui, -apple-system, sans-serif;
  --panel-blur: 0px;
  --knopf-rand: rgba(255, 255, 255, 0.12);
  --rand-schwach: rgba(255, 255, 255, 0.06);
  --eingabe-hg: #161a24;
  --slider-thumb-rand: #0a0d13;
  --dash-bg: #0d1017;
  --dash-rand: rgba(255, 255, 255, 0.08);
  --dash-rand-schwach: rgba(255, 255, 255, 0.05);
  --dash-rand-eingabe: rgba(255, 255, 255, 0.12);
  --dash-rand-tabelle: rgba(255, 255, 255, 0.08);
  --dash-flaeche-schwach: #161a24;
  --dash-hover: #161a24;
  --dash-tab-aktiv-bg: #1c2029;
  --dash-meter-spur: #123322;
}

:root[data-design="kontrollzentrum"] #seitenleiste {
  background: linear-gradient(180deg, #12151d, #0a0d13);
  border-right-color: rgba(255, 255, 255, 0.08);
}

:root[data-design="kontrollzentrum"] #lade-overlay, :root[data-design="kontrollzentrum"] .seiten-lade-overlay {
  background: rgba(10, 13, 19, 0.78);
}

:root[data-design="kontrollzentrum"] .leaflet-popup-content-wrapper,
:root[data-design="kontrollzentrum"] .leaflet-popup-tip {
  background: #11141c;
  color: var(--text);
}

:root[data-design="kontrollzentrum"] .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg) brightness(0.85) contrast(0.95);
}

/* Erzwingt optisch dunkel, selbst falls data-theme="hell" noch aus
   einer frueheren Design Wahl gespeichert war (design.js setzt beim
   Wechsel zu Kontrollzentrum data-theme zusaetzlich auch aktiv auf
   "dunkel", diese Regel ist nur ein zusaetzliches Sicherheitsnetz rein
   ueber CSS, falls das je auseinanderlaeuft). */
:root[data-design="kontrollzentrum"][data-theme="hell"] {
  color-scheme: dark;
}

/* data-design="fokusleiste" (Nutzerwunsch 02.09.2026, direkte Ergaenzung
   der drei Designs vom 24.08.2026 nach einer Runde UI-Entwuerfe): reiner
   CSS-Skin nach exakt demselben Muster wie Enterprise oben, KEINE
   Strukturaenderung am Markup (der volle Umbau zu Symbolleiste/Chipzeile
   aus dem Mockup war bewusst NICHT Teil dieser Runde, siehe CHANGELOG).
   Gedacht fuer dichte, haeufige Nutzung am Rechner: engere Eckenradien,
   kein Weichzeichner (schnelleres Rendern bei vielen Panels), etwas
   kraeftigerer Blauton als Glas fuer bessere Erkennbarkeit aktiver
   Zustaende (Checkboxen, aktiver Dashboard-Reiter). Eigene helle UND
   dunkle Variante, der bestehende Dunkelmodus-Schalter wirkt normal
   weiter (wie bei Enterprise, anders als bei Kontrollzentrum). */
:root[data-design="fokusleiste"] {
  --hintergrund: #f4f6fa;
  --flaeche: #ffffff;
  --flaeche-rand: rgba(20, 40, 80, 0.09);
  --text: #161a23;
  --text-schwach: #6b7280;
  --akzent: #1e56c9;
  --akzent-dunkel: #163f96;
  --frei: #2bb86a;
  --belegt: #e8554b;
  --gestoert: #f5b95c;
  --veraltet: #8a7ca6;
  --unbekannt: #767c8a;
  --radius-gross: 14px;
  --radius-klein: 9px;
  --schatten: 0 3px 10px rgba(20, 40, 80, 0.06);
  --schriftart: "Segoe UI", system-ui, -apple-system, sans-serif;
  --panel-blur: 0px;
  --knopf-rand: #d3d9e3;
  --rand-schwach: #eaedf3;
  --eingabe-hg: #f1f3f8;
  --dash-bg: #fdfdfe;
  --dash-rand: rgba(20, 40, 80, 0.08);
  --dash-rand-schwach: rgba(20, 40, 80, 0.04);
  --dash-rand-eingabe: rgba(20, 40, 80, 0.06);
  --dash-rand-tabelle: rgba(20, 40, 80, 0.08);
  --dash-flaeche-schwach: #f6f8fb;
  --dash-hover: #eef2fa;
  --dash-tab-aktiv-bg: #fff;
  --dash-meter-spur: #e2ecfb;
}

:root[data-design="fokusleiste"] #seitenleiste {
  background: #ffffff;
  border-right: 1px solid rgba(20, 40, 80, 0.08);
}

:root[data-design="fokusleiste"] #lade-overlay, :root[data-design="fokusleiste"] .seiten-lade-overlay {
  background: rgba(244, 246, 250, 0.75);
}

@media (prefers-color-scheme: dark) {
  :root[data-design="fokusleiste"]:not([data-theme="light"]) {
    --hintergrund: #12161f;
    --flaeche: #181d29;
    --flaeche-rand: #262d3c;
    --text: #e4e7ee;
    --text-schwach: #8b93a3;
    --akzent: #5a8bf0;
    --akzent-dunkel: #4a7de0;
    --frei: #35c37a;
    --belegt: #ff6b61;
    --gestoert: #e2a13e;
    --veraltet: #a79ae0;
    --unbekannt: #8b93a3;
    --schatten: 0 3px 10px rgba(0, 0, 0, 0.3);
    --knopf-rand: #262d3c;
    --rand-schwach: #1c2130;
    --eingabe-hg: #181d29;
    --dash-bg: #181d29;
    --dash-rand: #262d3c;
    --dash-rand-schwach: #1c2130;
    --dash-rand-eingabe: #262d3c;
    --dash-rand-tabelle: #262d3c;
    --dash-flaeche-schwach: #1c2130;
    --dash-hover: #1c2130;
    --dash-tab-aktiv-bg: #202638;
    --dash-meter-spur: #17325b;
  }
  :root[data-design="fokusleiste"]:not([data-theme="light"]) #seitenleiste {
    background: #181d29;
    border-right-color: #262d3c;
  }
  :root[data-design="fokusleiste"]:not([data-theme="light"]) #lade-overlay, :root[data-design="fokusleiste"]:not([data-theme="light"]) .seiten-lade-overlay {
    background: rgba(18, 22, 31, 0.5);
  }
  :root[data-design="fokusleiste"]:not([data-theme="light"]) .leaflet-popup-content-wrapper,
  :root[data-design="fokusleiste"]:not([data-theme="light"]) .leaflet-popup-tip {
    background: #181d24;
    color: var(--text);
  }
  :root[data-design="fokusleiste"]:not([data-theme="light"]) .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.92);
  }
}

:root[data-design="fokusleiste"][data-theme="dark"] {
  --hintergrund: #12161f;
  --flaeche: #181d29;
  --flaeche-rand: #262d3c;
  --text: #e4e7ee;
  --text-schwach: #8b93a3;
  --akzent: #5a8bf0;
  --akzent-dunkel: #4a7de0;
  --frei: #35c37a;
  --belegt: #ff6b61;
  --gestoert: #e2a13e;
  --veraltet: #a79ae0;
  --unbekannt: #8b93a3;
  --schatten: 0 3px 10px rgba(0, 0, 0, 0.3);
  --knopf-rand: #262d3c;
  --rand-schwach: #1c2130;
  --eingabe-hg: #181d29;
  --dash-bg: #181d29;
  --dash-rand: #262d3c;
  --dash-rand-schwach: #1c2130;
  --dash-rand-eingabe: #262d3c;
  --dash-rand-tabelle: #262d3c;
  --dash-flaeche-schwach: #1c2130;
  --dash-hover: #1c2130;
  --dash-tab-aktiv-bg: #202638;
  --dash-meter-spur: #17325b;
}

:root[data-design="fokusleiste"][data-theme="dark"] #seitenleiste {
  background: #181d29;
  border-right-color: #262d3c;
}

:root[data-design="fokusleiste"][data-theme="dark"] #lade-overlay, :root[data-design="fokusleiste"][data-theme="dark"] .seiten-lade-overlay {
  background: rgba(18, 22, 31, 0.5);
}

:root[data-design="fokusleiste"][data-theme="dark"] .leaflet-popup-content-wrapper,
:root[data-design="fokusleiste"][data-theme="dark"] .leaflet-popup-tip {
  background: #181d24;
  color: var(--text);
}

:root[data-design="fokusleiste"][data-theme="dark"] .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg) brightness(0.85) contrast(0.95);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--schriftart);
  background: var(--hintergrund);
  color: var(--text);
}

#app {
  display: flex;
  height: 100vh;
  width: 100vw;
}

#seitenleiste {
  width: 320px;
  /* Nutzerwunsch 18.08.2026 (dreizehnter Teil): das Seitenfenster soll
     nach rechts oder links vergroessert/verkleinert werden koennen. Die
     tatsaechliche Breite wird ab jetzt per JS gesetzt (Ziehgriff, siehe
     seitenleisteGroesseInitialisieren() in static/app.js, Breite in
     localStorage gemerkt), min-width nur noch als untere Grenze, damit
     der Inhalt nicht unbrauchbar eng wird. flex-shrink:0 verhindert, dass
     der Flexbox Algorithmus die per JS gesetzte Breite bei wenig Platz
     wieder eigenmaechtig veraendert. */
  min-width: 260px;
  flex-shrink: 0;
  padding: 18px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
  background: linear-gradient(180deg, #f8f9fb, #f5f6f8);
  border-right: 1px solid rgba(0, 0, 0, 0.03);
}

#seitenleiste-groesse-griff {
  width: 6px;
  flex-shrink: 0;
  cursor: col-resize;
  background: transparent;
  transition: background 0.15s ease;
}

#seitenleiste-groesse-griff:hover,
#seitenleiste-groesse-griff.aktiv {
  background: rgba(58, 109, 240, 0.35);
}

/* Griffleiste und Abdunklung fuer die mobile Bottom Sheet Seitenleiste
   (Nutzerwunsch 19.08.2026, Variante A), siehe sheetInitialisieren() in
   static/app.js. Auf dem Desktop beide bewusst komplett unsichtbar
   (display:none), erst die @media(max-width:720px) Regel weiter unten
   schaltet sie sichtbar/interaktiv. Hier oben nur als Grundzustand, damit
   sie beim Laden der Seite bzw. bei jeder Fensterbreite ausserhalb des
   mobilen Bereichs garantiert keinen Platz einnehmen und nicht anklickbar
   sind. */
#sheet-griffleiste,
#sheet-abdunklung {
  display: none;
}

/* "Kartenstapel" (Nutzerwunsch 02.09.2026), gleiches Prinzip wie direkt
   darueber: auf dem Desktop komplett unsichtbar, erst die
   @media(max-width:720px) Regel weiter unten schaltet sie sichtbar,
   siehe dort fuer die eigentliche Optik. */
.mobil-kartenstapel {
  display: none;
}

/* Anpassbare Reihenfolge/Sichtbarkeit der Seitenleisten Kacheln,
   Nutzerwunsch 23.08.2026 (zweite Runde), siehe kacheln.js. Nur die drei
   direkten Kind Kacheln unterhalb der Titel Kachel sind betroffen (die
   Titel Kachel selbst hat weder id="filter-panel" noch die passende Klasse/
   Elementart, bleibt also unberuehrt), .versteckt gleiches Namensmuster wie
   an anderen Stellen der Oberflaeche, hier extra fuer diesen Kontext
   definiert. */
#seitenleiste > .panel.versteckt,
#seitenleiste > details.panel-einklappbar.versteckt {
  display: none;
}

.panel {
  background: var(--flaeche);
  border: 1px solid var(--flaeche-rand);
  border-radius: var(--radius-gross);
  padding: 16px 18px;
  backdrop-filter: blur(var(--panel-blur));
  -webkit-backdrop-filter: blur(var(--panel-blur));
  box-shadow: var(--schatten);
}

.panel h1 {
  font-size: 1.25rem;
  margin: 0 0 4px 0;
}

.panel h2 {
  font-size: 0.95rem;
  margin: 0 0 10px 0;
  color: var(--text-schwach);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.unterzeile {
  margin: 0;
  color: var(--text-schwach);
  font-size: 0.85rem;
}

/* Kleine Fakten unter dem Titel ("AFIR Ladepunkte"), Nutzerwunsch vom
   18.08.2026 (UI Feedback): Anzahl geladener Ladepunkte und Live Status
   Abdeckung auf einen Blick, ohne erst im Filter/Legende Panel
   nachzaehlen zu muessen. Wird von kopfstatistikAktualisieren() in
   static/app.js befuellt, bleibt leer solange noch nichts geladen wurde. */
.kopf-statistik {
  margin: 6px 0 0 0;
  color: var(--text-schwach);
  font-size: 0.8rem;
  font-weight: 600;
}

/* Letzter kompletter Ladevorgang (Nutzerwunsch 23.08.2026, zweite Runde),
   siehe kopfLetzterLadevorgangAktualisieren() in static/js/karte.js. Bleibt
   vor dem ersten Ladevorgang leer, :empty blendet die Zeile dann komplett
   aus (gleiches Muster wie .legende-stand:empty weiter unten), statt einer
   sichtbaren, aber inhaltslosen Zeile. */
#kopf-letzter-ladevorgang:empty {
  display: none;
}

/* Kennzahlen Kacheln (Punkte/Live/Betreiber), Nutzerwunsch 24.08.2026
   (Design Runde): dieselben drei Zahlen wie auf den Design Vorschlaegen,
   siehe kopfKennzahlenAktualisieren() in static/js/karte.js. .versteckt
   erst per JS entfernt, sobald wirklich Daten geladen sind (gleiches
   Prinzip wie die :empty Regel oben, hier per Klasse statt :empty, weil
   der Inhalt aus drei Kindelementen statt reinem Text besteht). */
.kopf-kennzahlen {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

.kopf-kennzahlen.versteckt {
  display: none;
}

.kopf-kennzahl {
  flex: 1;
  min-width: 0;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid var(--flaeche-rand);
  border-radius: var(--radius-klein);
  padding: 8px 10px;
}

/* Bugfix 31.08.2026 (Nutzerwunsch, per Screenshot: "184..." statt
   "184.234"): text-overflow:ellipsis+white-space:nowrap haben die Zahl bei
   wachsendem Datenbestand (mittlerweile ueber 184.000 Ladepunkte) einfach
   abgeschnitten, statt sie umbrechen zu lassen, die urspruengliche
   Groessenannahme (kleinere Zahlen) passte nicht mehr. Gleiche Haltung wie
   beim Steckertyp Text in .lp-mitte (siehe Kommentar dort): lieber
   umbrechen als Information stillschweigend verstecken. overflow-wrap
   sorgt zusaetzlich dafuer, dass auch eine einzelne, sehr lange Zahl ohne
   Leerzeichen (z.B. "1.234.567") die Kachel nicht seitlich sprengt, falls
   sie selbst umgebrochen die verfuegbare Breite je Zeile uebersteigt. Die
   drei Kacheln bleiben durch das gemeinsame Flex Grid (.kopf-kennzahlen,
   align-items per Default stretch) weiterhin gleich hoch, auch wenn nur
   eine von ihnen zweizeilig wird. */
.kopf-kennzahl b {
  display: block;
  font-size: 1.02rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
}

.kopf-kennzahl span {
  font-size: 0.66rem;
  color: var(--text-schwach);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

:root[data-design="enterprise"] .kopf-kennzahl,
:root[data-design="kontrollzentrum"] .kopf-kennzahl,
:root[data-design="fokusleiste"] .kopf-kennzahl {
  background: var(--dash-flaeche-schwach);
}

/* Kacheln anpassen, Nutzerwunsch 23.08.2026 (zweite Runde, seit der dritten
   Runde Teil der Einstellungen Kachel statt der Titel Kachel, siehe
   templates/index.html und kacheln.js). Die umgebende .zugang-gruppe
   (siehe weiter oben) liefert bereits Abstand/Trennlinie/Ueberschrift
   Optik, hier nur noch die Liste selbst. */
.kacheln-liste {
  list-style: none;
  margin: 10px 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.kacheln-zeile {
  display: flex;
  align-items: center;
  gap: 6px;
}

.kacheln-name {
  flex: 1 1 auto;
}

.kacheln-pfeil-knopf {
  border: 1px solid var(--flaeche-rand);
  background: transparent;
  color: var(--text);
  border-radius: var(--radius-klein);
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.kacheln-pfeil-knopf:hover:not(:disabled) {
  background: rgba(58, 109, 240, 0.12);
}

.kacheln-pfeil-knopf:disabled {
  opacity: 0.35;
  cursor: default;
}

/* Merkliste/Favoriten Kachel (Nutzerwunsch 31.08.2026), siehe
   favoriten.js. Gleiches Listen-Grundmuster wie .kacheln-liste direkt
   darueber (eigene Regeln statt Wiederverwendung, da hier zwei statt nur
   ein Knopf je Zeile noetig sind, plus Name/Betreiber Text mit eigener
   Typografie statt eines einzelnen kacheln-name Labels). */
.favoriten-liste {
  list-style: none;
  margin: 10px 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.favoriten-eintrag {
  display: flex;
  align-items: center;
  gap: 6px;
}

.favoriten-sprung-knopf {
  flex: 1 1 auto;
  text-align: left;
  border: 1px solid var(--flaeche-rand);
  background: transparent;
  color: var(--text);
  border-radius: var(--radius-klein);
  padding: 6px 10px;
  font-family: inherit;
  font-size: 0.82rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow-wrap: break-word;
}

.favoriten-sprung-knopf span {
  font-size: 0.72rem;
  color: var(--text-schwach);
}

.favoriten-sprung-knopf:hover {
  background: rgba(58, 109, 240, 0.12);
}

.favoriten-entfernen-knopf {
  flex-shrink: 0;
  border: 1px solid var(--flaeche-rand);
  background: transparent;
  color: var(--text-schwach);
  border-radius: var(--radius-klein);
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
}

.favoriten-entfernen-knopf:hover {
  background: rgba(220, 68, 68, 0.14);
  color: #dc4444;
}

.kacheln-sichtbar-label {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--text-schwach);
  font-size: 0.76rem;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Hinweis: der Dunkelmodus Knopf stand hier kurzzeitig (23.08.2026) direkt
   neben dem Dashboard Knopf in einer eigenen Reihe (.titel-knopf-reihe).
   Auf Nutzerwunsch noch am selben Tag in die Sonstiges Kachel verschoben
   (siehe dort in templates/index.html), die Reihen Regel entfaellt damit
   wieder, der Dashboard Knopf ist seither wieder ein normaler, einzelner
   .knopf-sekundaer in voller Breite. */

/* Visuelle Gruppierung im Zugang Panel (Nutzerwunsch vom 18.08.2026,
   UI Feedback "Zugang aufraeumen", Variante "visuelle Gruppierung"
   gewaehlt: nichts verstecken, nur optisch trennen). Trennt die
   Standort Auswahl (oben, kein eigener Titel noetig) von der Live
   Status Gruppe und den erweiterten/seltener genutzten Optionen. */
.zugang-gruppe {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.zugang-gruppe h3 {
  margin: 0 0 2px 0;
  font-size: 0.72rem;
  color: var(--text-schwach);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.85;
}

/* Ganze Kachel einklappbar, gleiches <details>/<summary> Grundmuster wie
   .zugang-ausklappbar oben, nur fuer das komplette .panel statt nur eines
   Teilbereichs. Generische Klasse (Stand 20.08.2026), genutzt u.a. von der
   Einstellungen Kachel (id="einstellungen-panel", seit 03.09.2026 auch mit
   dem Inhalt der zusammengelegten, ehemaligen Sonstiges Kachel), startet
   ohne "open" Attribut immer zugeklappt, siehe Kommentare in
   templates/index.html. Die summary
   uebernimmt bewusst genau die bisherige .panel h2 Optik (Schriftgroesse/
   -farbe, Grossbuchstaben, Sperrung), damit die Kachel im aufgeklappten
   Zustand aussieht wie zuvor, nur jetzt anklickbar mit Pfeil Symbol davor.
   Nutzerwunsch 20.08.2026: "Text soll linksbuendig (wie die anderen
   Kacheln) sein und vertikal mittig sein" - Korrektur eines ersten,
   falsch verstandenen Anlaufs, der den Text bei zugeklapptem Zustand
   HORIZONTAL zentriert hatte, das war nicht gemeint.
   Horizontal bleibt der Text deshalb linksbuendig (Flexbox Standardwert
   justify-content:flex-start, keine eigene Regel noetig). Vertikal
   mittig wird ueber die Panel Polsterung selbst erreicht, NICHT ueber
   align-items/justify-content: im zugeklappten Zustand hat die summary
   KEINEN Bottom Margin, dadurch ist die obere und untere Polsterung des
   .panel (je 16px, siehe .panel oben) symmetrisch um die einzeilige
   summary herum, der Text sitzt automatisch mittig in der Kachelhoehe.
   Der bisherige 10px Bottom Margin (Abstand zwischen Ueberschrift und dem
   folgenden Inhalt) gilt jetzt nur noch im AUFGEKLAPPTEN Zustand (siehe
   [open] Regel unten), sonst waere die zugeklappte Kachel durch den
   ungenutzten Margin unten hoeher/asymmetrisch als oben. align-items:
   center bleibt bestehen, das zentriert nur den Pfeil vertikal zur
   Textzeile (Cross Achse), nicht die ganze Kachel. */
.panel-einklappbar > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-schwach);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}

.panel-einklappbar[open] > summary {
  margin: 0 0 10px 0;
}

.panel-einklappbar > summary::-webkit-details-marker {
  display: none;
}

.panel-einklappbar > summary::before {
  content: "▸";
  display: inline-block;
  width: 1em;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.panel-einklappbar[open] > summary::before {
  transform: rotate(90deg);
}

label {
  display: block;
  font-size: 0.8rem;
  color: var(--text-schwach);
  margin: 10px 0 4px 0;
}

.optional {
  font-weight: normal;
  opacity: 0.7;
}

input[type="text"],
input[type="password"],
select,
textarea {
  width: 100%;
  padding: 10px 12px;
  border-radius: var(--radius-klein);
  border: 1px solid var(--rand-schwach);
  background: var(--eingabe-hg);
  font-size: 0.9rem;
  outline: none;
  transition: border-color 0.15s ease;
}

textarea {
  font-family: inherit;
  resize: vertical;
  min-height: 40px;
}

input[type="text"]:focus,
input[type="password"]:focus,
select:focus,
textarea:focus {
  border-color: var(--akzent);
}

.checkbox-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0;
  font-size: 0.85rem;
  color: var(--text);
}

.checkbox-zeile input {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}


.knopf-primaer {
  width: 100%;
  margin-top: 14px;
  padding: 11px 16px;
  border: none;
  border-radius: var(--radius-klein);
  background: var(--akzent);
  color: white;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}

.knopf-primaer:hover {
  background: var(--akzent-dunkel);
}

.knopf-primaer:active {
  transform: scale(0.98);
}

/* CSV Export Knopf im Filterbereich, seit 19.08.2026 (Nutzerwunsch).
   Bewusst als zurueckhaltende Umriss Variante (nicht .knopf-primaer),
   damit "Karte laden" oben in der Seitenleiste weiterhin die einzige
   optisch dominante Aktion bleibt, der Export ist ein selteneres
   Nebenwerkzeug. */
.knopf-sekundaer {
  width: 100%;
  margin-top: 10px;
  padding: 9px 16px;
  border: 1px solid var(--knopf-rand);
  border-radius: var(--radius-klein);
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}

.knopf-sekundaer:hover {
  background: rgba(0, 0, 0, 0.05);
}

.knopf-sekundaer:active {
  transform: scale(0.98);
}

/* Nutzerverwaltung Link in der "Sonstiges" Kachel (templates/index.html),
   Nutzerwunsch 20.08.2026: soll optisch denselben Rahmen wie der CSV
   Export Knopf direkt darueber bekommen (per .knopf-sekundaer auf dem
   <a> selbst), nicht mehr nur ein schlichter Textlink. Diese Ergaenzung
   sorgt nur fuer die Anpassungen, die ein <a> zusaetzlich zu einem
   <button> braucht (Block Darstellung fuer width:100%, zentrierter Text,
   keine Unterstreichung). Bewusst eine EIGENE Klasse statt die geteilte
   .verwaltung-zurueck Klasse zu aendern (volle Breite passt dort nicht,
   dort stehen ueblicherweise zwei Knoepfe nebeneinander; .verwaltung-
   zurueck bekam am 11.09.2026 aber ebenfalls Knopf-Optik, siehe dortiger
   Kommentar - nur eben als kompakter inline-flex Knopf statt block). */
.verwaltung-link-knopf {
  display: block;
  text-align: center;
  text-decoration: none;
}

/* Auswertung Knopf in der Seitenleiste (templates/index.html), Nutzerwunsch
   31.08.2026: gleiche Notwendigkeit wie bei .verwaltung-link-knopf direkt
   oberhalb (ein <a> braucht dieselben Ergaenzungen wie ein <button>, um
   optisch wie .knopf-sekundaer auszusehen), bewusst eine eigene Klasse,
   da .verwaltung-link-knopf inhaltlich an die Verwaltungsseite gebunden
   ist (Kommentar dort). */
.auswertung-link-knopf {
  display: block;
  text-align: center;
  text-decoration: none;
}

/* Abmelden Formular (templates/index.html/hauptseite.html), ergaenzt
   03.09.2026 (Session-Login): ein <form> ist wie ein <button> von Haus
   aus bereits block-level, hier nur der Innenabstand entfernt (der
   .knopf-sekundaer Knopf darin bringt sein eigenes Padding schon mit),
   damit das Formular optisch nicht breiter/anders wirkt als die
   umliegenden Knopf-Links. */
.abmelden-formular {
  margin: 0;
  padding: 0;
}
.abmelden-formular > button {
  width: 100%;
}

.stand-anzeige {
  margin: 10px 0 0 0;
  font-size: 0.75rem;
  color: var(--text-schwach);
  text-align: center;
}

/* Hintergrund-Lade-Hinweis (ergaenzt 08.09.2026, siehe Kommentar bei
   #hintergrund-lade-hinweis in templates/index.html): kleiner, dezenter
   Indikator statt des vollflaechigen #lade-overlay, bleibt sichtbar
   solange ein Hintergrund-Ladevorgang tatsaechlich laeuft, damit ein
   ungewoehnlich langer/haengender Abruf nicht wie ein unveraenderter
   Zustand wirkt. */
.hintergrund-lade-hinweis {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.hintergrund-lade-hinweis.versteckt {
  display: none;
}

.hintergrund-lade-kreis {
  width: 11px;
  height: 11px;
  flex: none;
  border-radius: 50%;
  border: 2px solid rgba(58, 109, 240, 0.25);
  border-top-color: var(--akzent);
  animation: drehen 0.8s linear infinite;
}

.hinweis {
  margin: 10px 0 0 0;
  font-size: 0.78rem;
  color: var(--text-schwach);
}

/* Groesserer Text im Filter Bereich, Nutzerwunsch 19.08.2026: "wirkt sehr
   klein, gerade bei Status". Bewusst nur auf #filter-panel begrenzt (nicht
   .checkbox-zeile/label global vergroessert), damit z.B. die eng bemessene,
   scrollbare Subscription/CPO Liste in der Seitenleiste unveraendert bleibt,
   dort war kein Problem gemeldet und mehr Text pro Zeile wuerde dort eher
   stoeren. */
#filter-panel label {
  font-size: 0.9rem;
}

#filter-panel .checkbox-zeile {
  font-size: 0.95rem;
}

#filter-panel .hinweis {
  font-size: 0.85rem;
}

/* Doppel Griff Schieberegler fuer die Ladeleistung, Nutzerwunsch
   18.08.2026 (vierzehnter Teil). Zwei <input type="range"> Elemente liegen
   uebereinander (siehe templates/index.html, #leistung-slider-bereich);
   die eigentliche Schiene/Fuellung wird als separate Balken darunter
   gezeichnet, die range Elemente selbst bleiben unsichtbar bis auf ihren
   Griff (Thumb), damit nur die beiden Griffe bedienbar wirken, nicht die
   ganze Breite. */
.bereich-slider {
  position: relative;
  height: 22px;
  margin: 8px 0 2px;
}

.bereich-slider-schiene {
  position: absolute;
  top: 9px;
  left: 0;
  right: 0;
  height: 4px;
  border-radius: 2px;
  background: var(--rand-schwach);
}

.bereich-slider-fuellung {
  position: absolute;
  top: 9px;
  height: 4px;
  border-radius: 2px;
  background: var(--akzent);
}

.bereich-slider input[type="range"] {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 22px;
  margin: 0;
  background: none;
  pointer-events: none;
  -webkit-appearance: none;
  appearance: none;
}

.bereich-slider input[type="range"]::-webkit-slider-runnable-track {
  background: transparent;
}

.bereich-slider input[type="range"]::-moz-range-track {
  background: transparent;
}

.bereich-slider input[type="range"]::-webkit-slider-thumb {
  pointer-events: auto;
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--akzent);
  border: 2px solid var(--slider-thumb-rand);
  box-shadow: 0 1px 3px rgba(20, 24, 40, 0.35);
  cursor: pointer;
  margin-top: 2px;
}

.bereich-slider input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--akzent);
  border: 2px solid var(--slider-thumb-rand);
  box-shadow: 0 1px 3px rgba(20, 24, 40, 0.35);
  cursor: pointer;
}

/* Direkt eintippbare Zahlenfelder neben dem Ladeleistung Regler (Nutzerwunsch
   20.08.2026), ersetzen die vorherige rein lesbare Anzeige. Bewusst kompakt
   (kurze feste Breite statt volle Zeilenbreite wie die uebrigen Textfelder
   in diesem Panel), da hier nur eine kurze Zahl hineinpasst, keine laengere
   Freitexteingabe. */
.bereich-eingabe-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
  font-size: 0.78rem;
  color: var(--text-schwach);
}

.bereich-eingabe-zeile input[type="number"] {
  width: 64px;
  padding: 5px 8px;
  border-radius: 8px;
  border: 1px solid var(--rand-schwach);
  background: var(--eingabe-hg);
  font-size: 0.82rem;
  color: var(--text);
  text-align: center;
  /* Pfeil Spinner der Browser werden bewusst nicht extra entfernt: bei
     einem Zahlenfeld mit deutlich eingeschraenktem Wertebereich (z.B. 0
     bis 350 kW) sind sie ein nuetzlicher, nativer Hinweis, dass hier
     geklickt/gescrollt statt nur getippt werden kann, kein reines
     Stilproblem, das eine Entfernung rechtfertigen wuerde. */
}

.bereich-eingabe-zeile input[type="number"]:focus {
  border-color: var(--akzent);
  outline: none;
}

.bereich-eingabe-trenner,
.bereich-eingabe-einheit {
  flex-shrink: 0;
}

.legende-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  margin: 6px 0;
}

/* Anzahl je Status Kategorie, seit 18.08.2026 (Nutzerwunsch aus dem UI
   Review: "Statistik-Uebersicht", Zahlen statt nur Farbpunkte). Bezieht
   sich auf die aktuell GEFILTERT angezeigten Ladepunkte, nicht auf alle
   geladenen, siehe karteNeuZeichnen()/legendeAktualisieren() in app.js,
   passt damit zur "X von Y angezeigt" Anzeige im Filter Bereich. */
.legende-anzahl {
  margin-left: auto;
  color: var(--text-schwach);
  font-size: 0.78rem;
}

.punkt {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
}

.punkt.frei { background: var(--frei); }
.punkt.belegt { background: var(--belegt); }
.punkt.gestoert { background: var(--gestoert); }
.punkt.veraltet { background: var(--veraltet); }
/* Nutzerwunsch 23.08.2026 (zweite Runde): "unbekannt" (kein Live Status,
   nie eine Meldung) optisch klar von "veraltet" unterscheidbar, nicht nur
   durch die bisher recht aehnlichen Grau/Lila Toene. Gestrichelter, blasser
   Ring statt vollem Punkt, gleiches Prinzip wie bei den Kartenmarkern
   (siehe markerFuerStation in infokarte.js). box-sizing:border-box haelt
   die sichtbare Groesse trotz Rand identisch zu den anderen, randlosen
   Legendenpunkten. */
.punkt.unbekannt {
  background: transparent;
  border: 2px dashed var(--unbekannt);
  box-sizing: border-box;
}

/* Barrierefreier Statusmodus (Nutzerwunsch 23.08.2026, fuenfte Runde):
   "zusaetzliche Symbole/Muster je Status Kategorie neben der Farbe, fuer
   Farbenblindheit", als Option in der Einstellungen Kachel aktivierbar,
   siehe barrierefreierModusAnwenden() in karte.js. Nur ueber die Klasse
   .barrierefrei-modus auf <html> gesetzt (gleiches Muster wie
   data-theme), betrifft dadurch automatisch JEDE Stelle, an der die
   gemeinsame .punkt.<kategorie> Klasse verwendet wird (Legende, Status
   Filter Checkboxen, Statuspunkte im Popup, siehe statusPunkteHtml in
   infokarte.js), ohne dass jede einzelne Stelle im Markup angepasst
   werden musste. text-shadow sorgt fuer Lesbarkeit des weissen Symbols
   auch auf den helleren Status Farben (gestoert, veraltet). */
.barrierefrei-modus .punkt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.45);
}

.barrierefrei-modus .punkt.frei::after { content: "✓"; }
.barrierefrei-modus .punkt.belegt::after { content: "✕"; }
.barrierefrei-modus .punkt.gestoert::after { content: "!"; }
.barrierefrei-modus .punkt.veraltet::after { content: "~"; }
.barrierefrei-modus .punkt.unbekannt::after {
  content: "?";
  color: var(--unbekannt);
  text-shadow: none;
}

/* Kartenmarker im barrierefreien Statusmodus, siehe markerFuerStation()
   in infokarte.js: ein L.divIcon statt des sonst genutzten leichteren
   L.circleMarker (der kann keinen Textinhalt aufnehmen), gleiche
   Farblogik wie beim normalen Marker. */
.status-marker-divicon {
  background: transparent;
  border: none;
}

.status-marker-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--marker-farbe);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.45);
}

.status-marker-icon.unbekannt {
  background: transparent;
  border: 2px dashed var(--marker-farbe);
  color: var(--marker-farbe);
  text-shadow: none;
  box-shadow: none;
}

/* Cluster Marker mit Ampelfarbe statt der drei festen Blautoene aus der
   externen MarkerCluster.Default.css (Nutzerwunsch 31.08.2026), siehe
   clusterIconErstellen() in karte.js. .cluster-ampel selbst traegt bewusst
   KEINE eigene Groesse/Form (Leaflet setzt iconSize direkt als
   width/height des Icon-Wurzelelements ueber Inline-Styles), die
   sichtbare Kreisform samt Farbe steckt im inneren
   .cluster-ampel-inhalt div, dessen Schriftgroesse hier je Stufe (klein/
   mittel/gross, dieselben Schwellen wie Leaflet.markercluster selbst:
   <10/<100/sonst) gestaffelt ist. */
.cluster-ampel-inhalt {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.8);
  box-shadow: 0 1px 5px rgba(20, 24, 40, 0.4);
  color: #fff;
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.cluster-klein .cluster-ampel-inhalt {
  font-size: 0.72rem;
}

.cluster-mittel .cluster-ampel-inhalt {
  font-size: 0.8rem;
}

.cluster-gross .cluster-ampel-inhalt {
  font-size: 0.88rem;
}

:root:not([data-theme="light"]) .cluster-ampel-inhalt {
  border-color: rgba(30, 33, 42, 0.65);
}

:root[data-theme="dark"] .cluster-ampel-inhalt {
  border-color: rgba(30, 33, 42, 0.65);
}

/* Kurzes Aufblitzen fuer Marker, deren Status sich seit dem letzten
   karteNeuZeichnen() geaendert hat (Nutzerwunsch 31.08.2026), siehe die
   stationsKategorieVoriger Diff-Schleife in karte.js. Bewusst KEIN
   box-shadow (rendert nicht auf dem SVG <path> von circleMarker) und
   KEIN transform: scale() (Transform-Origin auf SVG-Pfaden ist
   unzuverlaessig), stattdessen filter: drop-shadow() + opacity, beides
   funktioniert zuverlaessig auf sowohl SVG <path> als auch <div>
   (divIcon). Farbe bewusst der neutrale Akzentton (--akzent), nicht
   frei/belegt-Gruen/Rot, damit "hier hat sich gerade etwas geaendert"
   klar von der Status-Farbsprache selbst unterscheidbar bleibt. */
@keyframes marker-puls {
  0% {
    filter: drop-shadow(0 0 0 rgba(58, 109, 240, 0));
    opacity: 1;
  }
  30% {
    filter: drop-shadow(0 0 10px var(--akzent));
    opacity: 0.75;
  }
  100% {
    filter: drop-shadow(0 0 0 rgba(58, 109, 240, 0));
    opacity: 1;
  }
}

.marker-frisch-geaendert {
  animation: marker-puls 1.8s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .marker-frisch-geaendert {
    animation: none;
  }
}

/* Letzter Live Status Aktualisierungszeitpunkt am Ende der Legende, seit
   19.08.2026 (Nutzerwunsch). Bewusst kleiner als .legende-zeile und mit
   einer duennen Trennlinie abgesetzt, das ist eine Nebeninfo, keine
   weitere Legendenzeile, soll also erkennbar zurueckhaltender wirken,
   nicht mit den Status Zeilen konkurrieren. */
.legende-stand {
  margin: 8px 0 0 0;
  padding-top: 6px;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  font-size: 0.68rem;
  color: var(--text-schwach);
  /* Todos.xlsx (14.09.2026): standardmaessig Platz fuer zwei Zeilen Text
     reservieren (line-height * 2), damit ein kurzer Text ("Daten werden
     geladen") die Legende nicht schmaler wirken laesst als ein zweizeiliger
     Text und - wichtiger - damit #legende-schwebend (feste Breite, siehe
     dort) nicht bei jedem Wechsel in der Hoehe springt. line-height explizit
     gesetzt, damit die min-height Rechnung nicht vom Browser-Default abhaengt. */
  line-height: 1.35;
  min-height: calc(1.35em * 2);
  overflow-wrap: break-word;
}

.legende-stand:empty {
  display: none;
}

/* Einklappbare Legende, Nutzerwunsch 23.08.2026, siehe
   legendeUmschalten()/legendeEingeklapptAnwenden() in static/js/karte.js.
   Auch von #vergleich-schwebend weiter unten mitgenutzt (dieselbe Kopf
   Zeile aus Ueberschrift + Knopf). */
.legende-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.legende-kopf h2 {
  margin: 0;
}

.legende-umschalt-knopf {
  appearance: none;
  border: none;
  background: rgba(0, 0, 0, 0.06);
  color: var(--text-schwach);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 0.15s ease, background 0.15s ease;
}

.legende-umschalt-knopf:hover {
  background: var(--rand-schwach);
  color: var(--text);
}

.legende-umschalt-knopf svg {
  width: 9px;
  height: 6px;
}

/* Zugeklappt: Pfeil zeigt nach oben (statt unten), #legende-inhalt
   verschwindet komplett, das Panel schrumpft dadurch von selbst auf die
   Kopfzeile (kein fester eigener Zustand fuer die Panel Groesse noetig). */
#legende-schwebend.eingeklappt .legende-umschalt-knopf svg {
  transform: rotate(180deg);
}

#legende-schwebend.eingeklappt #legende-inhalt {
  display: none;
}

#legende-schwebend.eingeklappt {
  padding-bottom: 16px;
}

/* Vergleichsansicht, Nutzerwunsch 23.08.2026, siehe vergleich.js. Oben
   rechts ueber der Karte (Legende bleibt unten rechts, siehe
   #legende-schwebend weiter oben), damit beide Panels sich nicht
   ueberlappen. */
#vergleich-schwebend {
  position: absolute;
  right: 18px;
  top: 18px;
  z-index: 500;
  max-width: 360px;
}

#vergleich-schwebend.versteckt {
  display: none;
}

.vergleich-anzahl {
  color: var(--text-schwach);
  font-weight: 400;
  font-size: 0.7rem;
}

.vergleich-leeren-knopf {
  appearance: none;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
  border-radius: var(--radius-klein);
  padding: 3px 10px;
  font-size: 0.72rem;
  cursor: pointer;
  flex-shrink: 0;
}

.vergleich-leeren-knopf:hover {
  color: var(--text);
  background: rgba(0, 0, 0, 0.05);
}

.vergleich-sortier-zeile {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 10px;
  font-size: 0.72rem;
  color: var(--text-schwach);
}

.vergleich-sortier-knopf {
  appearance: none;
  border: 1px solid var(--rand-schwach);
  background: transparent;
  color: var(--text-schwach);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 0.72rem;
  cursor: pointer;
}

.vergleich-sortier-knopf.aktiv {
  background: var(--akzent);
  border-color: var(--akzent);
  color: #fff;
}

.vergleich-tabellen-huelle {
  max-height: 260px;
  overflow-y: auto;
}

.vergleich-tabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.78rem;
}

.vergleich-tabelle td {
  padding: 6px 4px;
  border-top: 1px solid rgba(0, 0, 0, 0.06);
  vertical-align: middle;
}

.vergleich-tabelle tr:first-child td {
  border-top: none;
}

.vergleich-status-zelle {
  width: 16px;
}

.vergleich-name-zelle {
  max-width: 160px;
}

.vergleich-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vergleich-neben {
  color: var(--text-schwach);
  font-size: 0.7rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vergleich-zahl-zelle {
  text-align: right;
  white-space: nowrap;
  color: var(--text-schwach);
}

.vergleich-entfernen-zelle {
  width: 20px;
}

.vergleich-entfernen-knopf {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-schwach);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
  padding: 2px 4px;
}

.vergleich-entfernen-knopf:hover {
  color: var(--belegt);
}

#karten-bereich {
  position: relative;
  flex: 1;
}

#karten-bereich.versteckt,
#seitenleiste.versteckt,
#seitenleiste-groesse-griff.versteckt {
  display: none;
}

/* Dashboard (Nutzerwunsch 19.08.2026, dritter Anlauf: "richtig gut, setze
   das so um" nach einem eigenen Mockup). Nimmt beim Anzeigen denselben
   Platz ein wie #karten-bereich (flex: 1), aber mit eigenem Scrollbereich
   statt einer Karte. Bewusst hell und reduziert (Vorbild Linear/Notion):
   duenne Trennlinien statt Kartenschatten, ein Reiter zeigt jeweils genau
   eine Ansicht, keine lange Kachelwand mehr. Alle Grafiken sind schlichte
   CSS Balken, kein Chart.js/Canvas mehr noetig. */
#dashboard-bereich {
  flex: 1;
  overflow-y: auto;
  background: var(--dash-bg);
  padding: 40px 28px 80px;
  /* Nutzerwunsch 10.09.2026 ("milchiges Overlay + XX/XX geladen auf allen
     Seiten"): Bezugsrahmen fuer .seiten-lade-overlay (position: absolute,
     siehe dort), gleiches Prinzip wie #karten-bereich fuer #lade-overlay
     auf der Kartenseite. */
  position: relative;
}

#dashboard-bereich.versteckt {
  display: none;
}

#dashboard-bereich {
  font-size: 13.5px;
}

.dashboard-kopf {
  max-width: 880px;
  margin: 0 auto 28px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

/* Landesfilter Kasten im Dashboard-Kopf, Nutzerwunsch 14.09.2026 ("Genau
   da muss dann ein Filterkasten rein"): eigener kleiner, umrandeter Kasten
   statt der langen vertikalen .checkbox-zeile Liste aus dem Filterpanel der
   Kartenseite (dort passend, hier in der Kopfzeile zu hoch), Checkboxen
   deshalb nebeneinander statt untereinander. */
.dashboard-land-filter {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 8px 14px;
  border: 1px solid var(--dash-rand);
  border-radius: 8px;
  background: var(--dash-bg);
}

.dashboard-land-filter .checkbox-zeile {
  margin: 0;
}

.dashboard-land-filter-titel {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-schwach);
  margin-right: 2px;
}

.dashboard-kopf h1 {
  margin: 0;
  font-size: 1.3rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

/* Excel-Export Knopf im Dashboard-Kopf (Fehlerbehebung 11.09.2026, siehe
   Kommentar in templates/dashboard.html): .knopf-sekundaer ist sonst
   width:100% fuer volle Knopfreihen in der Seitenleiste gedacht, hier
   steht der Knopf aber einzeln rechts neben der Ueberschrift in der
   .dashboard-kopf Flex-Zeile. */
.dashboard-export-knopf {
  width: auto;
  margin-top: 0;
  flex-shrink: 0;
}

.dashboard-unter {
  margin: 3px 0 0;
  color: var(--text-schwach);
  font-size: 0.82rem;
}

/* Reiter (Uebersicht/Betreiber/Ladevorgaenge/Preise), ersetzen die
   vorherige lange Kachelwand: jeweils nur eine Ansicht sichtbar, siehe
   dashboardTabWechseln() in static/app.js. */
.dashboard-tabs {
  display: inline-flex;
  background: var(--dash-rand-schwach);
  border-radius: 9px;
  padding: 3px;
  gap: 2px;
}

.dashboard-tab {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: inherit;
  font-size: 0.79rem;
  font-weight: 550;
  color: var(--text-schwach);
  padding: 6px 12px;
  border-radius: 7px;
  transition: background 0.12s ease, color 0.12s ease;
}

.dashboard-tab svg { width: 14px; height: 14px; opacity: 0.75; }
.dashboard-tab:hover { color: var(--text); }
.dashboard-tab.aktiv { background: var(--dash-tab-aktiv-bg); color: var(--text); box-shadow: 0 1px 2px rgba(15, 15, 20, 0.08); }
.dashboard-tab.aktiv svg { opacity: 1; }

/* Optionaler Filterbezug (Nutzerwunsch 23.08.2026, siebte Runde): kleine
   Optionszeile direkt unter dem Dashboard Kopf, gleiche Zeilenbreite wie
   die .dashboard-block Karten darunter. */
.dashboard-optionen-zeile {
  padding: 10px 28px 0;
}

/* Suchfeld + CSV Export ueber der Betreiber Tabelle (Nutzerwunsch
   23.08.2026, siebte Runde), gleiche Bausteine wie das bestehende
   Adresssuche Formular in der oberen Bedienleiste. */
.dashboard-betreiber-werkzeugzeile {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.dashboard-betreiber-suchfeld {
  flex: 1;
  min-width: 160px;
  padding: 7px 10px;
  border: 1px solid var(--dash-rand-eingabe);
  border-radius: var(--radius-klein);
  font: inherit;
  font-size: 0.82rem;
}

table.dashboard-tabelle-neu thead th .listenansicht-sortknopf {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
}

table.dashboard-tabelle-neu thead th .listenansicht-sortknopf.aktiv {
  color: var(--text);
}

.dashboard-ansicht {
  max-width: 880px;
  margin: 0 auto;
}

.dashboard-ansicht[hidden] { display: none; }

.dashboard-block {
  padding: 22px 0;
  border-bottom: 1px solid var(--dash-rand);
}

.dashboard-block:last-child { border-bottom: none; }

.dashboard-block-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.dashboard-block-kopf h2,
.dashboard-mini-titel {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-schwach);
}

.dashboard-block-hinweis {
  font-size: 0.76rem;
  color: var(--text-schwach);
  white-space: nowrap;
}

/* Hero Zahl (Ladepunkte insgesamt) mit ehrlichem Hinweis, wie viele davon
   ueberhaupt einen bekannten Live Status haben (siehe README, Abschnitt
   "Layout Fehler behoben"): bei echten Daten oft nur ein kleiner Teil, das
   sollte nicht verschwiegen werden. */
.dashboard-hero-zeile {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  flex-wrap: wrap;
  padding-top: 4px;
}

.dashboard-hero-zahl {
  font-size: 2.6rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text);
}

.dashboard-hero-label {
  font-size: 0.85rem;
  color: var(--text-schwach);
  margin-bottom: 6px;
}

.dashboard-hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-radius: 999px;
  padding: 4px 11px 4px 8px;
  font-size: 0.72rem;
  color: var(--text-schwach);
  margin-bottom: 6px;
}

.dashboard-punkt {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-schwach);
  flex-shrink: 0;
  display: inline-block;
}

/* KPI Reihe: keine Kacheln mehr, nur duenne Trennlinien, wie in
   Uebersicht (frei/belegt/gestoert/Betreiber) und Preise (min/avg/max). */
.dashboard-kpi-reihe {
  display: flex;
  flex-wrap: wrap;
  margin-top: 4px;
}

.dashboard-kpi {
  padding: 0 22px;
  border-right: 1px solid var(--dash-rand);
}

.dashboard-kpi:first-child { padding-left: 0; }
.dashboard-kpi:last-child { border-right: none; }

.dashboard-kpi-kopf {
  display: flex;
  align-items: center;
  gap: 6px;
}

.dashboard-kpi .dashboard-punkt { width: 7px; height: 7px; }

.dashboard-kpi-wert {
  font-size: 1.15rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.dashboard-kpi-label {
  font-size: 0.72rem;
  color: var(--text-schwach);
  margin-top: 2px;
}

/* Duenne Statusleiste statt Kreisdiagramm: bei echten Daten ist oft ueber
   90% "unbekannt" (kein Live Status), ein Kreisdiagramm wuerde die
   eigentlichen frei/belegt/gestoert Anteile darin unsichtbar machen. Die
   Zahlen in der KPI Reihe direkt darueber tragen die eigentliche Aussage,
   die Leiste ist nur die kompakte visuelle Ergaenzung. */
.dashboard-statusleiste-duenn {
  display: flex;
  height: 7px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--dash-rand);
  margin-top: 16px;
}

.dashboard-statusleiste-teil { height: 100%; }

/* Verfuegbarkeit als Meter statt Kreisdiagramm, bewusst bezogen auf die
   Punkte mit bekanntem Status (nicht auf alle geladenen Ladepunkte), siehe
   dashboardUebersichtRendern() in static/app.js. */
.dashboard-meter-zeile {
  display: flex;
  align-items: center;
  gap: 14px;
}

.dashboard-meter-prozent {
  font-size: 1.15rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  width: 46px;
  flex-shrink: 0;
  color: var(--text);
}

.dashboard-meter-spur {
  flex: 1;
  height: 7px;
  border-radius: 4px;
  background: var(--dash-meter-spur);
}

.dashboard-meter-fuellung {
  height: 100%;
  border-radius: 4px;
  background: var(--frei);
}

.dashboard-zwei-spalten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}

.dashboard-balken-liste {
  list-style: none;
  margin: 0;
  padding: 0;
}

.dashboard-balken-zeile {
  display: grid;
  grid-template-columns: minmax(90px, 42%) 1fr auto;
  align-items: center;
  gap: 10px;
  margin-bottom: 9px;
  font-size: 0.8rem;
}

.dashboard-balken-zeile .name {
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dashboard-balken-spur {
  position: relative;
  height: 6px;
  background: var(--dash-rand);
  border-radius: 3px;
}

.dashboard-balken-fuellung {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--akzent);
  border-radius: 3px;
}

.dashboard-balken-fuellung.gut { background: var(--frei); }
.dashboard-balken-fuellung.teuer { background: var(--gestoert); }

.dashboard-balken-zeile .wert {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-schwach);
  font-size: 0.76rem;
  min-width: 40px;
}

.dashboard-mini-zeile {
  display: flex;
  justify-content: space-between;
  font-size: 0.79rem;
  margin-bottom: 5px;
}

.dashboard-mini-zeile .label { color: var(--text); }
.dashboard-mini-zeile .wert { color: var(--text-schwach); font-variant-numeric: tabular-nums; }

.dashboard-mini-gruppe { margin-bottom: 18px; }
.dashboard-mini-gruppe:last-child { margin-bottom: 0; }
.dashboard-mini-titel { margin-bottom: 8px; }

.dashboard-link-mehr {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.76rem;
  font-weight: 550;
  color: var(--akzent);
  padding: 0;
  margin-top: 12px;
}

.dashboard-link-mehr svg { width: 11px; height: 11px; }

.dashboard-vorschau-liste { list-style: none; margin: 0; padding: 0; }

.dashboard-vorschau-zeile {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 7px 0;
  font-size: 0.82rem;
}

.dashboard-vorschau-zeile .standort { color: var(--text); }
.dashboard-vorschau-zeile .betreiber { color: var(--text-schwach); font-size: 0.74rem; }
.dashboard-vorschau-zeile .dauer {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  white-space: nowrap;
  margin-left: 12px;
}

.dashboard-leer {
  color: var(--text-schwach);
  font-size: 0.82rem;
}

/* Betreiber Tabelle (eigener Reiter): schlicht, duenne Trennlinien, Balken
   direkt in der Zelle statt eigenem Diagramm. Scrollt bei vielen
   Betreibern selbst (siehe .dashboard-tabellen-huelle), statt eine feste
   Anzahl abzuschneiden - das war der Grund fuer den Kartenraster Fehler
   im vorherigen Anlauf. */
.dashboard-tabellen-huelle {
  max-height: 460px;
  overflow-y: auto;
}

table.dashboard-tabelle-neu {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem;
}

table.dashboard-tabelle-neu thead th {
  text-align: left;
  padding: 8px 12px 8px 0;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
  font-weight: 600;
  border-bottom: 1px solid var(--dash-rand-tabelle);
}

table.dashboard-tabelle-neu td {
  padding: 9px 12px 9px 0;
  border-bottom: 1px solid var(--dash-rand);
  vertical-align: middle;
}

table.dashboard-tabelle-neu tbody tr:last-child td { border-bottom: none; }
table.dashboard-tabelle-neu tbody tr:hover { background: var(--dash-hover); }

table.dashboard-tabelle-neu td.zahl,
table.dashboard-tabelle-neu th.zahl {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

td.dashboard-zell-balken { width: 200px; }

.dashboard-zell-zeile { display: flex; align-items: center; gap: 8px; }

.dashboard-zell-spur {
  flex: 1;
  position: relative;
  height: 5px;
  background: var(--dash-rand);
  border-radius: 3px;
}

.dashboard-zell-fuellung {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 3px;
  background: var(--akzent);
}

.dashboard-zell-fuellung.gut { background: var(--frei); }

.dashboard-zell-wert {
  font-variant-numeric: tabular-nums;
  color: var(--text-schwach);
  font-size: 0.76rem;
  min-width: 40px;
  text-align: right;
}

.dashboard-fussnote {
  color: var(--text-schwach);
  font-size: 0.76rem;
  margin: 12px 0 0;
}

/* Verlauf (Nutzerwunsch 20.08.2026, "ich haette gerne einen Log, der
   alles dokumentiert und speichert"), siehe verlaufRendern() in
   static/app.js und protokoll.py. Urspruenglich ein eigener Dashboard
   Reiter, noch am selben Tag auf Nutzerwunsch ("Packe das (verlauf) in
   die Kachel 'Sonstiges'") in die Sonstiges Kachel der Seitenleiste
   verschoben, siehe .verlauf-liste-seitenleiste weiter unten fuer die
   dafuer noetige Anpassung. Filter Chips im gleichen Pill Stil wie
   .dashboard-tab, nur kleiner (zwei unabhaengige Gruppen: Kategorie/
   Stufe), damit die Optik konsistent zum Rest des Programms bleibt. */
.verlauf-filter-zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
}

.verlauf-filter-gruppe {
  display: inline-flex;
  background: var(--dash-rand-schwach);
  border-radius: 8px;
  padding: 3px;
  gap: 2px;
}

.verlauf-filter-chip {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.74rem;
  font-weight: 550;
  color: var(--text-schwach);
  padding: 5px 10px;
  border-radius: 6px;
  transition: background 0.12s ease, color 0.12s ease;
}

.verlauf-filter-chip:hover { color: var(--text); }
.verlauf-filter-chip.aktiv { background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(15, 15, 20, 0.08); }

.verlauf-aktualisieren-knopf { margin-left: auto; }

/* Stufe Abzeichen in der Verlauf Tabelle, gleiche Farblogik wie die
   bestehenden Toast Meldungen (.toast.fehler/.warnung/.erfolg weiter
   oben): fehler=rot (--belegt), warnung=orange (--gestoert), info=grau
   (--unbekannt), damit eine Farbe im ganzen Programm immer dieselbe
   Bedeutung hat. */
.verlauf-stufe {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

.verlauf-stufe-info { background: rgba(154, 160, 172, 0.16); color: var(--unbekannt); }
.verlauf-stufe-warnung { background: rgba(242, 169, 59, 0.16); color: var(--gestoert); }
.verlauf-stufe-fehler { background: rgba(224, 71, 62, 0.14); color: var(--belegt); }

.verlauf-kategorie { color: var(--text-schwach); font-size: 0.78rem; }

table.verlauf-tabelle td.verlauf-zeit {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--text-schwach);
  font-size: 0.76rem;
}

table.verlauf-tabelle td.verlauf-nachricht { font-size: 0.79rem; }

/* Verlauf Liste innerhalb der Sonstiges Kachel (Nutzerwunsch 20.08.2026,
   "Packe das (verlauf) in die Kachel 'Sonstiges'"): die Seitenleiste ist
   deutlich schmaler (260-900px, siehe seitenleisteGroesseInitialisieren
   in static/app.js) als der frueher volle Dashboard Bereich, in dem diese
   Tabelle urspruenglich stand. Begrenzte Hoehe mit eigenem Scrollbalken,
   damit eine lange Ereignisliste nicht die ganze Seitenleiste sprengt und
   CSV Export/Nutzerverwaltung darueber aus dem sichtbaren Bereich
   schiebt; Breite bleibt scrollbar, falls die Tabelle trotz kleinerer
   Schrift (siehe oben) bei sehr schmaler Seitenleiste nicht ganz passt. */
.verlauf-liste-seitenleiste {
  max-height: 320px;
  overflow-y: auto;
  overflow-x: auto;
}

/* Ladevorgaenge Reiter */
.dashboard-lv-zeile {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid var(--dash-rand);
  font-size: 0.82rem;
}

.dashboard-lv-zeile:last-child { border-bottom: none; }
.dashboard-lv-links .standort { color: var(--text); }
.dashboard-lv-links .betreiber { color: var(--text-schwach); font-size: 0.75rem; margin-top: 1px; }
.dashboard-lv-dauer {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  margin-left: 16px;
  color: var(--text);
}

/* Preise Reiter */
.dashboard-preis-schiene-wrap { margin: 10px 0 4px; }

.dashboard-preis-schiene {
  position: relative;
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--frei) 0%, var(--gestoert) 55%, var(--belegt) 100%);
  opacity: 0.85;
}

.dashboard-preis-marker {
  position: absolute;
  top: -4px;
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: var(--text);
  box-shadow: 0 0 0 2px #fafafa;
}

.dashboard-preis-schiene-labels {
  display: flex;
  justify-content: space-between;
  margin-top: 8px;
  font-size: 0.74rem;
  color: var(--text-schwach);
}

.dashboard-preis-schiene-labels strong { color: var(--text); font-weight: 650; }

.dashboard-preis-zwei-spalten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}

@media (max-width: 640px) {
  .dashboard-zwei-spalten,
  .dashboard-preis-zwei-spalten {
    grid-template-columns: 1fr;
    gap: 22px;
  }
  .dashboard-kpi { padding: 0 14px; }
}

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

#toast-behaelter {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 340px;
}

/* Legende als schwebendes Panel auf der Karte, seit 18.08.2026
   (achtzehnter Teil, Nutzerwunsch: "macht es Sinn die Legende rechts unten
   hinzutun?", per AskUserQuestion "Nur auf der Karte" statt zusaetzlich in
   der Seitenleiste entschieden). bottom:34px statt 18px, damit genug
   Abstand zum Leaflet Attribution Hinweis bleibt, der standardmaessig
   ebenfalls unten rechts sitzt und sonst ueberlappen wuerde. z-index
   niedriger als #toast-behaelter/#lade-overlay (beide wichtiger/dringender
   als eine staendig sichtbare Legende), aber ueber der Karte selbst.
   Keine feste width gesetzt, das Panel schrumpft als absolut positioniertes
   Element automatisch auf seinen Inhalt. */
#legende-schwebend {
  position: absolute;
  right: 18px;
  bottom: 34px;
  z-index: 500;
  /* Feste Breite, Todos.xlsx (14.09.2026): die durchlaufende Push-Anzeige
     (#legende-stand-anzeige, siehe pushAnzeigeRotationTick() in
     live_status.js) zeigt unterschiedlich lange Texte, ohne feste Breite
     hier wuerde sich dadurch bei jedem Wechsel die Breite der gesamten
     Legende sichtbar aendern. Breite so gewaehlt, dass die Status Zeilen
     (.legende-zeile, z.B. "unbekannt / nur Standort") bequem hineinpassen,
     siehe auch .legende-stand weiter unten (zwei Zeilen Platz statt
     Breitenwachstum). */
  width: 240px;
}

/* Legende komplett aus-/einblendbar (Nutzerwunsch 23.08.2026, sechste
   Runde), siehe legendeSichtbarAnwenden() in karte.js und die Checkbox
   #einstellungen-legende-sichtbar in templates/index.html. Unabhaengig
   von .eingeklappt weiter oben (die klappt nur den Inhalt weg, der Kopf
   mit Pfeil Knopf bleibt sichtbar) - .versteckt blendet die Legende
   komplett aus. */
#legende-schwebend.versteckt {
  display: none;
}

/* Sortierbare Listenansicht als Alternative zur Karte (Nutzerwunsch
   23.08.2026, fuenfte Runde): "eine Tabelle der aktuell gefilterten
   Ladepunkte... praktisch bei sehr vielen Treffern oder zum schnellen
   Vergleichen ohne Popup Klicks". Liegt im DOM ueber der Karte, gleiche
   Groesse wie #karte, aber standardmaessig unsichtbar (display:none),
   die .listenansicht-aktiv Klasse an #karten-bereich (siehe
   listenansichtAnwenden()) blendet Karte und Listenansicht gegenseitig
   um. Die kartenbezogenen schwebenden Panels (Adresssuche/Schnellfilter,
   Vergleich, Legende, Kartenhintergrund Schalter) ergeben ohne
   sichtbare Karte keinen Sinn und werden im Listenmodus mit ausgeblendet.
   padding-top laesst Platz fuer die oben schwebende Bedienleiste. Bewusst
   NUR #adresssuche-leiste/#schnellfilter-leiste hier (nicht der ganze
   #obere-bedienleiste Container): #ansicht-umschalter-zeile darin bleibt
   sichtbar, sonst gaebe es in der Listenansicht keinen Weg mehr zurueck
   zur Karte, siehe Kommentar bei #obere-bedienleiste weiter unten und in
   templates/index.html. */
#karten-bereich.listenansicht-aktiv #karte,
#karten-bereich.listenansicht-aktiv #adresssuche-leiste,
#karten-bereich.listenansicht-aktiv #stationsuche-leiste,
#karten-bereich.listenansicht-aktiv #schnellfilter-leiste,
#karten-bereich.listenansicht-aktiv #vergleich-schwebend,
#karten-bereich.listenansicht-aktiv #legende-schwebend,
#karten-bereich.listenansicht-aktiv .leaflet-control-container {
  display: none;
}

#listenansicht {
  display: none;
  height: 100%;
  width: 100%;
  overflow-y: auto;
  padding: 70px 18px 18px;
  box-sizing: border-box;
}

#karten-bereich.listenansicht-aktiv #listenansicht {
  display: block;
}

/* Wiederverwendet die bestehende Dashboard Tabellen Optik (siehe
   table.dashboard-tabelle-neu weiter oben), statt eigene Tabellenregeln
   zu duplizieren. */
.listenansicht-tabellen-huelle {
  overflow-x: auto;
}

#listenansicht-tabelle {
  width: 100%;
  min-width: 620px;
  border-collapse: collapse;
  font-size: 0.82rem;
  background: var(--flaeche);
  border: 1px solid var(--flaeche-rand);
  border-radius: var(--radius-gross);
  backdrop-filter: blur(var(--panel-blur));
  -webkit-backdrop-filter: blur(var(--panel-blur));
  box-shadow: var(--schatten);
  overflow: hidden;
}

#listenansicht-tabelle th,
#listenansicht-tabelle td {
  text-align: left;
  padding: 10px 14px;
  border-bottom: 1px solid var(--dash-rand);
}

#listenansicht-tabelle tbody tr:last-child td {
  border-bottom: none;
}

#listenansicht-tabelle tbody tr:hover {
  background: var(--dash-hover);
}

.listenansicht-sortknopf {
  display: flex;
  align-items: center;
  gap: 4px;
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--text-schwach);
  cursor: pointer;
  padding: 0;
}

.listenansicht-sortknopf.aktiv {
  color: var(--text);
}

.listenansicht-sortpfeil {
  font-size: 0.7rem;
}

.listenansicht-karte-knopf {
  border: 1px solid var(--knopf-rand);
  border-radius: var(--radius-klein);
  background: transparent;
  color: var(--text);
  font-size: 0.76rem;
  font-family: inherit;
  padding: 5px 10px;
  cursor: pointer;
}

.listenansicht-karte-knopf:hover {
  background: rgba(58, 109, 240, 0.12);
}

#listenansicht-leer-hinweis {
  margin-top: 16px;
}

#listenansicht-leer-hinweis.versteckt {
  display: none;
}

/* EIN gemeinsames Panel oben links ueber der Karte (Ansicht Umschalter,
   Adresssuche, Schnellfilter Chips/Standort Knopf), Nutzerwunsch
   23.08.2026 (sechste Runde): vorher drei separate schwebende Karten
   (eigener Hintergrund/Schatten je Panel), das wirkte zusammen mit den
   Kartenmarkern ueberladen/unruhig. Jetzt EIN .panel Hintergrund fuer den
   ganzen Bereich, die drei inneren Abschnitte sind nur noch per
   duennem border-top optisch getrennt (siehe die drei Kind Selektoren
   unten), kein eigener Rahmen/Schatten je Abschnitt mehr. Komplett
   ausblendbar ueber die Checkbox "Obere Bedienleiste anzeigen" in der
   Einstellungen Kachel, siehe obereBedienleisteAnwenden() in karte.js
   und .versteckt weiter unten. Vergleich schwebt oben rechts, Legende
   unten rechts, siehe dortige Regeln. */
#obere-bedienleiste {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 500;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 10px;
  max-width: calc(100% - 36px);
}

#obere-bedienleiste.versteckt {
  display: none;
}

#ansicht-umschalter-zeile {
  display: flex;
  gap: 6px;
  padding-bottom: 10px;
}

#adresssuche-leiste {
  position: relative;
  padding: 10px 0;
  border-top: 1px solid var(--dash-rand);
}

#adresssuche-formular {
  display: flex;
  gap: 6px;
}

#adresssuche-eingabe {
  width: 220px;
  max-width: 100%;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--rand-schwach);
  background: var(--eingabe-hg);
  font-size: 0.82rem;
  color: var(--text);
}

#adresssuche-eingabe:focus {
  border-color: var(--akzent);
  outline: none;
}

.adresssuche-ergebnisse {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% - 2px);
  background: var(--flaeche);
  backdrop-filter: blur(var(--panel-blur));
  -webkit-backdrop-filter: blur(var(--panel-blur));
  border: 1px solid var(--flaeche-rand);
  border-radius: var(--radius-klein);
  box-shadow: var(--schatten);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 220px;
  overflow-y: auto;
}

.adresssuche-ergebnisse.versteckt {
  display: none;
}

.adresssuche-treffer-knopf {
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text);
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 0.78rem;
  font-family: inherit;
  cursor: pointer;
}

.adresssuche-treffer-knopf:hover {
  background: rgba(58, 109, 240, 0.12);
}

/* Echte Stationssuche (Nutzerwunsch 31.08.2026), siehe stationsuche.js.
   Gleiche Optik wie #adresssuche-leiste direkt darueber (gemeinsames
   .panel, nur per border-top abgesetzt), .adresssuche-ergebnisse wird
   bewusst wiederverwendet statt dupliziert (siehe class Attribut auf
   #stationsuche-ergebnisse in templates/index.html). Kein eigener
   "Suchen" Knopf noetig (anders als bei der Adresssuche): die Suche
   laeuft bereits live waehrend des Tippens, das Feld nimmt deshalb die
   volle Breite ein statt sich einen Knopf daneben zu teilen. */
#stationsuche-leiste {
  position: relative;
  padding: 10px 0;
  border-top: 1px solid var(--dash-rand);
}

#stationsuche-formular {
  display: flex;
}

#stationsuche-eingabe {
  width: 220px;
  max-width: 100%;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--rand-schwach);
  background: var(--eingabe-hg);
  font-size: 0.82rem;
  color: var(--text);
}

#stationsuche-eingabe:focus {
  border-color: var(--akzent);
  outline: none;
}

/* Schnellfilter Chips, Nutzerwunsch 23.08.2026 (zweite Runde), siehe
   schnellfilter.js. flex-wrap, falls die Seitenleiste sehr schmal gezogen
   wird oder die Chip Texte auf einem schmalen Fenster nicht nebeneinander
   passen. */
#schnellfilter-leiste {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--dash-rand);
}

.schnellfilter-chip {
  border: 1px solid var(--flaeche-rand);
  background: transparent;
  color: var(--text);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.schnellfilter-chip:hover {
  background: rgba(58, 109, 240, 0.12);
}

.schnellfilter-chip.aktiv {
  background: var(--akzent);
  border-color: var(--akzent);
  color: #fff;
}

.schnellfilter-chip:disabled {
  opacity: 0.6;
  cursor: default;
}

/* Entfernung Filter Block, Nutzerwunsch 23.08.2026 (vierte Runde), siehe
   #entfernung-filter-block in templates/index.html: per Default versteckt,
   solange kein eigener Standort ermittelt wurde (siehe standort.js). */
#entfernung-filter-block.versteckt {
  display: none;
}

/* Speicherbare Filteransaetze (Nutzerwunsch 23.08.2026, vierte Runde),
   siehe filter_presets.js. Eigene, schmalere Eingabezeile statt der
   .bereich-eingabe-zeile Regler Zahlenfelder (die sind bewusst kurz und
   zentriert, ein Freitext Namensfeld braucht dagegen die volle Breite). */
.filter-preset-eingabe-zeile {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}

.filter-preset-eingabe-zeile input[type="text"] {
  flex: 1;
  min-width: 0;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--rand-schwach);
  background: var(--eingabe-hg);
  font-size: 0.82rem;
  color: var(--text);
}

.filter-preset-eingabe-zeile input[type="text"]:focus {
  border-color: var(--akzent);
  outline: none;
}

.filter-presets-liste {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
}

.filter-presets-liste .optional {
  margin: 0;
}

.filter-preset-zeile {
  display: flex;
  align-items: center;
  gap: 6px;
}

.filter-preset-anwenden-knopf {
  flex: 1;
  text-align: left;
}

.filter-preset-loeschen-knopf {
  border: 1px solid var(--flaeche-rand);
  background: transparent;
  color: var(--text-schwach);
  border-radius: 8px;
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.filter-preset-loeschen-knopf:hover {
  color: var(--text);
  border-color: var(--text-schwach);
}

.toast {
  background: var(--flaeche);
  backdrop-filter: blur(var(--panel-blur));
  -webkit-backdrop-filter: blur(var(--panel-blur));
  border: 1px solid var(--flaeche-rand);
  border-radius: var(--radius-klein);
  box-shadow: var(--schatten);
  padding: 12px 14px;
  font-size: 0.85rem;
  animation: einblenden 0.2s ease;
  border-left: 4px solid var(--akzent);
}

.toast.fehler { border-left-color: var(--belegt); }
.toast.warnung { border-left-color: var(--gestoert); }
.toast.erfolg { border-left-color: var(--frei); }

/* Statuszeile im Meldeformular (templates/melden.html), Todo 10.09.2026:
   eigene, immer sichtbare Rueckmeldung statt des Toast-Systems, siehe
   Kommentar dort/in static/js/melden_seite.js. Gleiche Farblogik wie die
   Toast Randfarben oben, nur als Textfarbe statt Rand. */
.meldung-status-fehler { color: var(--belegt); }
.meldung-status-erfolg { color: var(--frei); }

/* Punkt 7 der Datenqualitaets Vorschlaege (21.08.2026): Warnbox bei
   ueberschneidenden Standort Subscriptions, siehe
   ueberschneidungsWarnungAktualisieren() in app.js. Bewusst aehnliche
   Optik wie .toast.warnung (gleiche Randfarbe), aber fest im Fluss der
   Subscription Liste statt schwebend, da sie so lange sichtbar bleiben
   soll, wie die Auswahl ueberlappt, nicht nur kurz wie ein Toast. */
#subscription-ueberschneidung-warnung {
  background: rgba(242, 169, 59, 0.14);
  border: 1px solid var(--gestoert);
  border-radius: var(--radius-klein);
  padding: 10px 12px;
  margin-bottom: 10px;
  font-size: 0.85rem;
}

#subscription-ueberschneidung-warnung.versteckt { display: none; }

/* Proaktive Warnung bei Datenquellen-Ausfaellen (Verbesserungsvorschlag
   06.09.2026 "Proaktive Warnung bei Datenquellen-Ausfaellen"): Banner auf
   der Hauptseite (siehe routen_hauptseite.py/templates/hauptseite.html)
   und dem Kontrollzentrum (siehe routen_leitstand.py/templates/
   leitstand.html), erscheint nur bei tatsaechlichem rotem Status. Deutlich
   auffaelligere Optik als .toast.warnung/#subscription-ueberschneidung-
   warnung (var(--belegt) statt var(--gestoert) als Randfarbe): hier geht
   es um einen echten Ausfall einer ganzen Datenquelle, nicht nur eine
   Ueberschneidung in der Auswahl. */
.hauptseite-ausfall-warnung {
  background: rgba(217, 68, 68, 0.12);
  border: 1px solid var(--belegt);
  border-radius: var(--radius-klein);
  padding: 12px 14px;
  font-size: 0.9rem;
}

.hauptseite-ausfall-warnung a { color: inherit; text-decoration: underline; }


#subscription-ueberschneidung-warnung ul {
  margin: 6px 0 0;
  padding-left: 18px;
}

#subscription-ueberschneidung-warnung li { margin: 2px 0; }

@keyframes einblenden {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Kurze Einfuehrungstour (Nutzerwunsch 23.08.2026, fuenfte Runde), siehe
   einfuehrung.js. position:fixed statt absolute (anders als
   #lade-overlay direkt darunter, das nur ueber der Karte selbst liegt):
   die Tour soll bei Bedarf auch die Seitenleiste abdecken koennen,
   deshalb ueber das ganze Browserfenster, nicht nur ueber
   #karten-bereich. z-index hoeher als #toast-behaelter (1000): waehrend
   der Tour soll nichts anderes davorliegen. */
#einfuehrung-overlay {
  position: fixed;
  inset: 0;
  background: rgba(20, 24, 40, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: 18px;
  box-sizing: border-box;
}

#einfuehrung-overlay.versteckt {
  display: none;
}

#einfuehrung-dialog {
  position: relative;
  max-width: 420px;
  width: 100%;
  /* Undurchsichtiger als die sonst leicht transparenten schwebenden Panels
     (siehe .panel), damit der abgedunkelte Hintergrund den Text nicht
     zusaetzlich schwerer lesbar macht. */
  background: var(--hintergrund);
}

.einfuehrung-schliessen-knopf {
  position: absolute;
  top: 10px;
  right: 12px;
  border: none;
  background: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--text-schwach);
  cursor: pointer;
  padding: 4px;
}

#einfuehrung-titel {
  margin: 0 24px 8px 0;
}

#einfuehrung-text {
  color: var(--text-schwach);
  line-height: 1.5;
}

.einfuehrung-punkte {
  display: flex;
  gap: 6px;
  margin-top: 16px;
}

.einfuehrung-punkte span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--knopf-rand);
}

.einfuehrung-punkte span.aktiv {
  background: var(--akzent);
}

.einfuehrung-knopfzeile {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 18px;
}

.einfuehrung-knopfzeile .knopf-sekundaer,
.einfuehrung-knopfzeile .knopf-primaer {
  width: auto;
  margin-top: 0;
  flex: 1;
}

.einfuehrung-knopfzeile .knopf-sekundaer:disabled {
  opacity: 0.4;
  cursor: default;
}

#lade-overlay, .seiten-lade-overlay {
  position: absolute;
  inset: 0;
  background: rgba(243, 244, 247, 0.55);
  backdrop-filter: blur(3px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  z-index: 900;
  color: var(--text-schwach);
  font-size: 0.9rem;
}

#lade-overlay.versteckt, .seiten-lade-overlay.versteckt {
  display: none;
}

.lade-kreis {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid rgba(58, 109, 240, 0.25);
  border-top-color: var(--akzent);
  animation: drehen 0.8s linear infinite;
}

/* Fortschrittsbalken waehrend eines Ladevorgangs (seit 18.08.2026, siehe
   /api/fortschritt und static/app.js). Bei mehreren Anbietern
   gleichzeitig kann ein Ladevorgang ueber eine Minute dauern, ein reiner
   Kreis ohne jeden Fortschritt wirkte da wie ein Haenger. */
.lade-balken-huelle {
  width: 220px;
  height: 6px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
}

.lade-balken {
  height: 100%;
  width: 0%;
  background: var(--akzent);
  transition: width 0.3s ease;
}

@keyframes drehen {
  to { transform: rotate(360deg); }
}

/* Gemeinsame Zeile fuer die Zurueck-Knoepfe (links) und die Konto-Leiste
   (rechts), Nutzerwunsch 10.09.2026 samt Nachbesserung 11.09.2026
   (Todos.xlsx, Niedrig: "Topspalte mit Accountverwaltung und Zurueck
   Knoepfen uneinheitlich"): vorher stand die Konto-Leiste als EIGENE,
   volle Zeile ueber/unter den Zurueck-Knoepfen (zwei optisch nicht
   aufeinander abgestimmte Zeilen). Jetzt eine gemeinsame Zeile auf den
   acht Seiten OHNE eigenen umschliessenden Panel-Rahmen (Dashboard,
   Auswertung, Kontrollzentrum, Verwaltung, Einstellungen, Datenquellen,
   Melden, Meldungen), Zurueck-Knoepfe links, Konto-Info rechts, siehe
   die jeweiligen Vorlagen ({% include "_konto_leiste.html" %} steht dort
   jetzt direkt NEBEN statt UEBER der .verwaltung-zurueck-reihe, beide
   umschlossen von diesem .kopf-navigation-reihe Element). Bewusst im
   normalen Dokumentfluss (kein position:fixed/absolute): die Seiten haben
   alle voneinander abweichende Kopfbereiche/Layouts, ein schwebendes
   Element haette auf mindestens einer davon mit vorhandenen Elementen
   (Leaflet Zoom-Steuerung, Reiterleisten, Live-Badge) kollidieren koennen.

   Auf der Kartenseite (templates/index.html) steht der Konto-Baustein
   dagegen bereits INNERHALB der bestehenden Titel-Kachel (siehe dortiger
   Kommentar bei "Zur Übersicht") - dort soll er ausdruecklich WIE BISHER
   aussehen (eigene volle Zeile, unterstrichene Textlinks statt Knoepfe),
   siehe die .panel .konto-leiste/-konto-leiste-knopf Ausnahmen unten. */
.kopf-navigation-reihe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  margin-bottom: 18px;
}

/* Fehlerbehebung 13.09.2026 (Todos.xlsx, Niedrig: "Die obere Leiste mit
   'Zurueck ...' und 'Konto'-Knoepfen soll nicht breiter als der Rest
   sein, also nicht weiter nach links/rechts ragen als z.B.
   'Kontrollzentrum' oder 'Aktualisiert um ...'"): Ursache war, dass
   .kopf-navigation-reihe auf Dashboard/Auswertung/Kontrollzentrum als
   direktes Kind des VOLLEN Seitencontainers steht (#dashboard-bereich/
   #auswertung-seite/#leitstand-seite, siehe jeweilige Vorlage), waehrend
   die darunterliegende Ueberschriftenzeile (.dashboard-kopf/
   .auswertung-kopf) dort bereits mit eigenem max-width zentriert ist -
   die obere Leiste ragte dadurch auf breiten Fenstern sichtbar weiter
   nach links und rechts als Titel/"Aktualisiert um"-Anzeige darunter.
   Auf Verwaltung/Einstellungen/Datenquellen/Melden/Meldungen tritt das
   Problem nicht auf, dort steckt .kopf-navigation-reihe bereits INNERHALB
   des jeweiligen schmalen Inhalts-Containers (.verwaltung-inhalt/
   .es-inhalt/.dq-inhalt) - deshalb hier bewusst nur fuer die drei
   betroffenen, vollbreiten Seiten mit denselben max-width Werten wie
   ihre jeweilige Kopfzeile (.dashboard-kopf: 880px, .auswertung-kopf: 1180px). */
#dashboard-bereich .kopf-navigation-reihe {
  max-width: 880px;
  margin-left: auto;
  margin-right: auto;
}

#auswertung-seite .kopf-navigation-reihe,
#leitstand-seite .kopf-navigation-reihe {
  max-width: 1180px;
  margin-left: auto;
  margin-right: auto;
}

.konto-leiste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  font-size: 0.78rem;
  color: var(--text-schwach);
}

/* Ausnahme fuer die Kartenseite (siehe Kommentar oben): dort ist
   .konto-leiste keine rechte Haelfte einer .kopf-navigation-reihe,
   sondern weiterhin die volle, eigene Zeile innerhalb der Titel-Kachel -
   braucht deshalb weiterhin justify-content:space-between (Text/Knoepfe
   an den beiden Raendern), das die anderen acht Seiten seit 11.09.2026
   nicht mehr brauchen (dort spreizt bereits .kopf-navigation-reihe). */
.panel .konto-leiste {
  justify-content: space-between;
  padding-bottom: 10px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--flaeche-rand);
}

.konto-leiste-formular {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}

/* Konto wechseln/Abmelden als umrandete Knoepfe im selben Stil wie
   .verwaltung-zurueck (siehe dortiger Kommentar), Nachbesserung
   11.09.2026 - vorher unterstrichene Textlinks ohne jede Rahmung, wirkten
   dadurch selbst nach dem .kopf-navigation-reihe Umbau weiterhin
   uneinheitlich gegenueber den knopffoermigen Zurueck-Links links davon. */
.konto-leiste-knopf {
  display: inline-flex;
  align-items: center;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid var(--knopf-rand);
  border-radius: var(--radius-klein);
  padding: 7px 14px;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}

.konto-leiste-knopf:hover {
  color: var(--akzent);
  background: rgba(0, 0, 0, 0.05);
}

.konto-leiste-knopf:active {
  transform: scale(0.98);
}

.konto-leiste-knopf-betont {
  color: var(--akzent);
  border-color: var(--akzent);
}

/* Ausnahme fuer die Kartenseite (siehe Kommentar oben an .kopf-navigation-
   reihe): dort bleiben Konto wechseln/Abmelden bewusst unterstrichene
   Textlinks wie bisher, keine Knopf-Optik. */
.panel .konto-leiste-knopf {
  display: inline;
  border: none;
  border-radius: 0;
  padding: 0;
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--text-schwach);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.panel .konto-leiste-knopf:hover {
  color: var(--akzent);
  background: none;
}

.panel .konto-leiste-knopf.konto-leiste-knopf-betont {
  color: var(--akzent);
  font-weight: 600;
}

/* Fehlerbehebung 11.09.2026 (Todos.xlsx, "UI fuer Kontoeinstellungen
   passt nicht immer, nur bei der Seite 'Einstellung' sieht es gut aus"):
   Ursache war die unterschiedliche Container-Breite der acht Seiten, in
   die .konto-leiste eingebunden ist. .es-inhalt (Einstellungen, 900px)
   und .dq-inhalt (Datenquellen, 1100px) sowie die volle Breite von
   Dashboard/Auswertung/Kontrollzentrum boten genug Platz fuer Text und
   Knoepfe nebeneinander. Verwaltung/Melden/Meldungen nutzen dagegen die
   schmale .verwaltung-inhalt Breite von nur 480px: dort brach die Zeile
   durch flex-wrap unkontrolliert um, mal mitten im Text, mal zwischen den
   beiden Knoepfen, je nach Laenge des Benutzernamens - wirkte kaputt statt
   nur schmal. Fix: unterhalb 560px Container-Breite (deckt die drei
   schmalen Seiten zuverlaessig ab, greift auf breiteren Seiten nicht)
   werden Text und Knoepfe stattdessen sauber untereinander gestapelt;
   .kopf-navigation-reihe selbst braucht keine eigene Regel, flex-wrap
   dort laesst Zurueck-Knoepfe und Konto-Info ohnehin bereits in zwei
   Zeilen umbrechen. */
@media (max-width: 560px) {
  .konto-leiste {
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
  }

  .konto-leiste-formular {
    width: 100%;
    justify-content: flex-end;
  }
}

/* Info Karte im Leaflet Popup */
.leaflet-popup-content-wrapper {
  border-radius: var(--radius-klein) !important;
  box-shadow: var(--schatten) !important;
}

.info-karte {
  font-family: inherit;
  min-width: 210px;
}

.info-karte h3 {
  margin: 0 0 6px 0;
  font-size: 1rem;
}

/* Kopfzeile des Stations Popups mit Stern Knopf fuer die Merkliste/
   Favoriten (Nutzerwunsch 31.08.2026), siehe favoriten.js. h3 bekommt
   hier kein eigenes margin-bottom mehr (das uebernimmt jetzt der
   Flex-Container), sonst stuende der Stern nicht mittig neben dem Namen. */
.stations-info-kopf {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.stations-info-kopf h3 {
  margin: 0;
}

/* Gruppiert Link- und Favoriten-Knopf im Popup Kopf (Todo 10.09.2026,
   Direktlink zu einem Ladepunkt), damit beide zusammen rechtsbuendig
   stehen statt durch .stations-info-kopf's justify-content: space-between
   auseinandergezogen zu werden. */
.stations-info-kopf-knoepfe {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.favoriten-stern-knopf,
.ladepunkt-link-knopf {
  flex-shrink: 0;
  border: none;
  background: none;
  font-size: 1.1rem;
  line-height: 1;
  padding: 2px;
  cursor: pointer;
  color: var(--text-schwach);
}

.favoriten-stern-knopf.aktiv {
  color: #f0b13a;
}

.favoriten-stern-knopf:hover {
  color: #f0b13a;
}

.ladepunkt-link-knopf:hover {
  color: var(--akzent);
}

.info-karte .status-zeile {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  margin-bottom: 8px;
}

.info-karte dl {
  margin: 0;
  font-size: 0.82rem;
  color: var(--text-schwach);
}

.info-karte dt {
  font-weight: 600;
  color: var(--text);
  margin-top: 4px;
}

.info-karte dd {
  margin: 0 0 2px 0;
}

/* "In Karten App oeffnen" Link, Nutzerwunsch 23.08.2026 (fuenfte Runde),
   siehe navigationsLinkHtml() in infokarte.js. */
.info-karte-navigations-link {
  display: inline-block;
  margin-top: 8px;
  font-size: 0.78rem;
  color: var(--akzent);
  text-decoration: none;
}

.info-karte-navigations-link:hover {
  text-decoration: underline;
}

/* Stations Infokarte, Nutzerwunsch 18.08.2026 (sechzehnter Teil, per
   Skizze): eine Ladestation mit mehreren Ladepunkten zeigt jetzt nur noch
   EINEN Marker, die Infokarte listet die Ladepunkte gruppiert nach
   Ladeleistung auf, statt eines Markers/Popups pro einzelnem Ladepunkt.
   Siehe stationsInfoKarteHtml/leistungsGruppenHtml in static/app.js.
   min-width ist nur noch eine UNTERE Grenze fuer kurze Inhalte, keine
   feste Breite mehr: Nutzerwunsch 19.08.2026 (vierundzwanzigster Teil,
   zweite Runde), woertlich "Passe den Code noch so an, dass das Fenster
   sich dynamisch an die Breite des Textes anpasst". Vorher wurde hier
   eine feste, immer groessere Zahl (260 -> 310px) probiert, um
   abgeschnittenen Text in der Detailliste zu vermeiden, das haette bei
   echten Daten mit langen Steckertyp Kombinationen (z.B. "CCS (Typ 2)/
   CHAdeMO") trotzdem wieder abgeschnitten. Die eigentliche Ursache war
   .lp-mitte (overflow:hidden + 1fr Spalte, siehe .lp-liste), nicht eine
   zu kleine min-width, siehe dort. */
.stations-info-karte {
  min-width: 260px;
}

.leistung-liste {
  margin-top: 8px;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
}

/* Aufbau je Leistungsgruppe, Stand 19.08.2026 (vierundzwanzigster Teil,
   per Skizze). Vorgeschichte: siebzehnter Teil ersetzte die urspruengliche
   Punkte Zeile durch einen Status Ring (Donut Chart), achtzehnter/
   neunzehnter Teil ergaenzte die X/X Zahl im Ring wieder, zwanzigster
   Teil kehrte zu einer aufgeraeumten Rasteranordnung mit Punkten statt
   Ring zurueck. Bis hierhin stand "belegt seit" (siehe
   laengsterLadevorgangText in static/app.js) immer fest sichtbar als
   dritte Zeile in der Karte. Nutzerwunsch jetzt: diese Zeile
   standardmaessig verstecken, dafuer ein kleiner Pfeil neben der
   Punktereihe, der beim Klick eine Detailliste MIT EINER ZEILE PRO
   EINZELNEM LADEPUNKT ausklappt (Leistung, Steckertyp, Preis, Status
   samt "seit wann" je Ladepunkt einzeln statt nur zusammengefasst).
   Zwei flache Zeilen (leistung-kopf, zweite-zeile) statt eines
   durchgehenden Grids, siehe leistungsGruppenHtml/
   ladepunktDetailZeileHtml in static/app.js. */
.leistung-zeile {
  padding: 9px 0;
}

.leistung-zeile + .leistung-zeile {
  border-top: 1px solid rgba(0, 0, 0, 0.06);
}

.leistung-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.leistung-kw-zeile {
  display: flex;
  align-items: baseline;
  gap: 5px;
  white-space: nowrap;
}

.leistung-kw {
  font-weight: 700;
  font-size: 0.84rem;
  color: var(--text);
}

/* Verfuegbarkeitszahl ("frei/gesamt", z.B. "1/2") dezent neben der
   Leistung, bewusst klein und grau statt fett hervorgehoben.
   Nutzerwunsch: "Gerade X/X sollte eher dezenter werden. und nicht
   direkt links von den Punkten." (vorher stand sie im Status Ring bzw.
   direkt vor der Punktereihe). */
.leistung-ratio {
  font-size: 0.68rem;
  color: var(--text-schwach);
  font-weight: 600;
}

/* Fasst Punktereihe und Details Pfeil rechts in der Kopfzeile zusammen,
   Nutzerwunsch: der Details Knopf soll direkt neben den oberen
   Statuspunkten stehen, nicht als eigene Zeile darunter. */
.kopf-rechts {
  display: flex;
  align-items: center;
  gap: 8px;
}

.zweite-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 3px;
}

.anschluss-zeile {
  font-size: 0.72rem;
  color: var(--text-schwach);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Statuspunkte, ein Punkt pro Ladepunkt (siehe statusPunkteHtml in
   static/app.js). Ab MAX_SICHTBARE_PUNKTE Punkten wird gekappt
   (".mehr-badge" zeigt den Rest als Zahl), damit Stationen mit vielen
   Ladepunkten (z.B. 18) nicht unuebersichtlich werden. */
.punkte-reihe {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  max-width: 100px;
  justify-content: flex-end;
}

.punkt {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.mehr-badge {
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--text-schwach);
}

.leistung-preis {
  color: var(--text-schwach);
  font-size: 0.76rem;
  white-space: nowrap;
}

/* Details Knopf, ersetzt seit 19.08.2026 (vierundzwanzigster Teil) die
   vorher immer sichtbare "belegt seit" Zeile. Der Pfeil dreht sich beim
   Ausklappen (siehe .leistung-zeile.offen), der Text bleibt bewusst
   immer "Details", nur der Pfeil zeigt den Zustand an. */
.details-knopf {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: none;
  background: none;
  color: var(--text-schwach);
  font: inherit;
  font-size: 0.68rem;
  font-weight: 600;
  cursor: pointer;
  padding: 2px 0;
  flex-shrink: 0;
}

.details-knopf svg {
  width: 9px;
  height: 9px;
  transition: transform 0.15s ease;
}

.leistung-zeile.offen .details-knopf svg {
  transform: rotate(180deg);
}

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

/* Ausklappbarer Detailbereich: eine Zeile pro einzelnem Ladepunkt dieser
   Leistungsgruppe, siehe ladepunktDetailZeileHtml in static/app.js. Per
   Grid Hoehen Animation (0fr -> 1fr) statt max-height, damit die Hoehe
   nicht geschaetzt werden muss. */
.lp-details {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.18s ease;
}

.leistung-zeile.offen .lp-details {
  grid-template-rows: 1fr;
}

/* Nur overflow-x hier (nicht "overflow: hidden" fuer beide Achsen): eine
   Kurzschreibweise "overflow: hidden" auf .lp-details > div hat wegen
   hoeherer Selektor-Spezifitaet (Klasse + Kind-Kombinator + Element,
   0-1-1) das overflow-y:auto der WEITER UNTEN stehenden .lp-liste Regel
   (nur Klasse, 0-1-0) bisher IMMER ueberstimmt, unabhaengig von der
   Reihenfolge im Stylesheet. .lp-details > div ist exakt dasselbe
   Element wie .lp-liste (siehe ladepunktDetailZeileHtml/leistungsGruppenHtml
   in infokarte.js: <div class="lp-details"><div class="lp-liste">...),
   die Liste war dadurch bei vielen Ladepunkten weiterhin unsichtbar
   abgeschnitten statt scrollbar, obwohl max-height/overflow-y:auto im
   Code stand (Nutzerwunsch 01.09.2026, betraf denselben Fehler wie
   31.08.2026 bereits gemeldet: das war KEIN Browser-Cache-Problem,
   sondern dieser Spezifitaets-Konflikt). overflow-x:hidden bleibt hier
   fuer die Grid-Hoehen-Animation (0fr -> 1fr) bestehen, overflow-y wird
   bewusst NICHT mehr gesetzt, damit .lp-liste weiter unten die einzige
   Quelle fuer overflow-y bleibt. */
.lp-details > div {
  overflow-x: hidden;
}

/* Gemeinsames Grid ueber ALLE Zeilen (nicht pro Zeile einzeln), damit
   Spalten bei jeder Zeile exakt an derselben Stelle beginnen, egal wie
   lang der Text in Spalte 2/4 ist. .lp-zeile selbst bleibt dank
   display:contents nur eine semantische Gruppierung ohne eigene Grid
   Zelle. Der Status Punkt hat bewusst eine EIGENE, feste Spalte (9px):
   ein rechtsbuendiger Flex Block aus Punkt+Text (fruehere Version)
   verschiebt den Punkt je nach Textlaenge der Zeile, das widersprach dem
   Nutzerwunsch "Achte auch darauf, dass die ausgeklappten Statuspunkte
   in einer vertikalen Linie sind". Mit einer eigenen Spalte bleibt der
   Punkt fix, nur die "seit wann" Spalte rechts daneben ist je Zeile
   unterschiedlich breit.
   Spalte 2 (.lp-mitte) und Spalte 4 (.lp-seit) sind bewusst "auto" statt
   "1fr", Nutzerwunsch 19.08.2026 (vierundzwanzigster Teil, zweite
   Runde): "Passe den Code noch so an, dass das Fenster sich dynamisch
   an die Breite des Textes anpasst". Eine "1fr" Spalte in einem Popup,
   das selbst nur so breit wie sein Inhalt ist (kein festes Fenster),
   erzwingt zusammen mit overflow:hidden auf .lp-mitte einen
   Automatismus, der die Spalte auf 0 statt auf den Inhalt schrumpft,
   das Popup wird dadurch NIE breiter, egal wie lang der Steckertyp
   Text ist, siehe vorheriger, mit fester min-width (260 -> 310px)
   geflickter Versuch, der bei echten Daten trotzdem wieder abgeschnitten
   hat (z.B. "CCS (Typ 2)/CHAdeMO"). Mit "auto" bestimmt der tatsaechliche
   Inhalt die Spaltenbreite, das Popup waechst mit (bis zur maxWidth
   Grenze bei marker.bindPopup() in static/app.js), kuerzere Inhalte
   bleiben weiterhin kompakt. */
.lp-liste {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed rgba(0, 0, 0, 0.1);
  display: grid;
  /* Fuenfte Spalte (18px) seit 23.08.2026 fuer den Vergleichsansicht Knopf
     (siehe .lp-vergleich-knopf unten und ladepunktDetailZeileHtml() in
     infokarte.js). Sechste Spalte (18px) seit 31.08.2026 fuer den Verlauf/
     Sparkline Knopf (.lp-verlauf-knopf, siehe belegungsverlauf.js). .lp-zeile
     bleibt display:contents (siehe unten), jedes seiner Kind Elemente ist
     deshalb weiterhin ein eigenes Feld genau dieses Grids, kein
     verschachteltes Layout noetig. */
  grid-template-columns: 26px auto 9px auto 18px 18px;
  align-items: center;
  row-gap: 5px;
  column-gap: 6px;
  font-size: 0.7rem;
  /* Scrollbar statt endlos wachsender Liste, Nutzerwunsch 31.08.2026: "Bei
     sehr vielen Ladepunkten waere es auch gut, wenn die Fenster mit den
     Detailansichten der Ladepunkt ... scrollbar waeren." Bewusst NUR hier
     (nicht am ganzen Popup, siehe marker.bindPopup in infokarte.js ohne
     maxHeight): Stationsname, Adresse und die Status Uebersicht oben im
     Popup sowie der "Details" Knopf/Leistungskopf jeder Gruppe bleiben so
     beim Scrollen fest sichtbar, nur die einzelnen Ladepunkt Zeilen
     darunter scrollen. 260px sind bei der aktuellen Zeilenhoehe rund neun
     bis zehn Zeilen, bleibt bei kleineren Ladeparks also folgenlos (kein
     overflow, kein Scrollbalken). overflow-x:hidden verhindert, dass ein
     einzelner sehr langer Steckertyp Text die Liste seitlich aufreisst,
     das Popup soll weiterhin nur in der Hoehe, nicht in der Breite
     scrollen (siehe width:max-content Kommentar direkt darunter, davon
     unberuehrt: nur die Hoehe wird hier begrenzt). */
  max-height: 260px;
  overflow-y: auto;
  overflow-x: hidden;
}

/* width:max-content bewusst NUR im ausgeklappten Zustand (siehe
   .leistung-zeile.offen), nicht dauerhaft auf .lp-liste selbst: sonst
   waere jedes Popup schon beim OEFFNEN so breit wie sein ausgeklappter
   Zustand, auch wenn die Detailliste noch zugeklappt (unsichtbar, 0px
   Hoehe) ist, das widerspraeche dem "dynamisch an den Text anpassen".
   Ohne dieses width:max-content misst sowohl Leaflets eigene
   Breitenberechnung (marker.bindPopup -> Popup._updateLayout, siehe
   aktuellesPopup.update() Aufruf in ereignisseVerbinden) als auch eine
   manuelle white-space:nowrap Messung hier zu schmal (Test ergab
   weiterhin ~260px statt der tatsaechlich benoetigten ~300px+), obwohl
   die "auto" Spalten fuer sich genommen breiter sein wollen. Grund: das
   Leaflet Popup ist selbst absolut positioniert und "schrumpft" auf
   seinen Inhalt (kein fester eigener width Wert), diese Grid Ebene
   steckt mehrere Bloecke tief darin, ueber so viele verschachtelte
   "width:auto" Bloecke hinweg wird die Breitenberechnung unzuverlaessig.
   width:max-content erzwingt hier direkt die tatsaechlich benoetigte
   Breite, unabhaengig von den Ahnen Elementen. */
.leistung-zeile.offen .lp-liste {
  width: max-content;
}

.lp-zeile {
  display: contents;
}

.lp-nummer {
  font-weight: 700;
  font-size: 0.62rem;
  color: var(--text-schwach);
  background: rgba(0, 0, 0, 0.05);
  border-radius: 5px;
  padding: 2px 0;
  text-align: center;
}

/* Kein overflow:hidden/text-overflow:ellipsis mehr (siehe Erklaerung bei
   .lp-liste): der Text soll das Popup in die Breite wachsen lassen statt
   abgeschnitten zu werden. white-space bewusst NICHT nowrap, falls der
   Inhalt trotzdem einmal an Leaflets maxWidth Grenze stoesst, dann darf
   er umbrechen statt seitlich aus der Karte hinauszulaufen, das ist
   ehrlicher als stillschweigend etwas zu verstecken. */
.lp-mitte {
  color: var(--text-schwach);
}

.lp-mitte b {
  color: var(--text);
  font-weight: 600;
}

.lp-punkt {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  justify-self: center;
}

.lp-seit {
  color: var(--text-schwach);
  justify-self: end;
  text-align: right;
  /* Anders als .lp-mitte bewusst WEITERHIN nowrap: "belegt seit HH:MM
     (X Min)" ist immer kurz und einzeilig, ein Umbruch hier waere nur
     unschoen, nicht durch fehlenden Platz begruendet (siehe .lp-mitte
     fuer die eigentliche Begruendung, wann Umbruch statt Abschneiden
     sinnvoll ist). */
  white-space: nowrap;
}

.lp-seit.betont {
  color: var(--text);
  font-weight: 600;
}

/* Vergleichsansicht Knopf je Ladepunkt, Nutzerwunsch 23.08.2026, siehe
   vergleich.js. Bewusst klein und zurueckhaltend (fuenfte, schmale
   Grid Spalte in .lp-liste oben), damit er neben der ohnehin schon
   kompakten Detailzeile nicht dominiert. */
.lp-vergleich-knopf {
  appearance: none;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
  width: 18px;
  height: 18px;
  border-radius: 5px;
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  justify-self: end;
  padding: 0;
}

.lp-vergleich-knopf:hover {
  color: var(--text);
  background: rgba(0, 0, 0, 0.06);
}

/* Verlauf/Sparkline je Ladepunkt (Nutzerwunsch 31.08.2026), siehe
   belegungsverlauf.js. Gleiche Groesse/Optik wie .lp-vergleich-knopf
   direkt darueber, eigene Klasse statt Wiederverwendung: unterschiedliche
   Bedeutung (kein An/Aus Zustand wie beim Vergleich, rein ein Auf-/
   Zuklapp Knopf), .aktiv markiert hier "gerade aufgeklappt" statt
   "im Vergleich enthalten". */
.lp-verlauf-knopf {
  appearance: none;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
  width: 18px;
  height: 18px;
  border-radius: 5px;
  font-size: 0.68rem;
  line-height: 1;
  cursor: pointer;
  justify-self: end;
  padding: 0;
}

.lp-verlauf-knopf:hover,
.lp-verlauf-knopf.aktiv {
  color: var(--text);
  background: rgba(0, 0, 0, 0.06);
}

/* Aufklappbare Verlaufsanzeige unter der Ladepunkt Zeile: bewusst KEIN
   unbedingtes display:flex/block in dieser Basisregel (das war die
   Ursache des .lp-anreicherung-formular Cascade Bugs vom 31.08.2026,
   siehe dortiger Kommentar und CHANGELOG), sondern display:none als
   Standard und ein :not([hidden]) Override, damit [hidden] zuverlaessig
   greift. */
.lp-verlauf-anzeige {
  grid-column: 1 / -1;
  display: none;
  padding: 4px 0 2px 26px;
}

.lp-verlauf-anzeige:not([hidden]) {
  display: block;
}

.lp-verlauf-sparkline svg {
  display: block;
  border-radius: 3px;
  overflow: hidden;
}

.lp-verlauf-hinweis {
  margin: 0;
}

.lp-vergleich-knopf.aktiv {
  background: var(--akzent);
  border-color: var(--akzent);
  color: #fff;
}

/* Saeulennummer/ueberdacht (Nutzerwunsch 30.08.2026, siehe
   static/js/anreicherung.js). Der Bearbeiten Knopf steckt bewusst OHNE
   eigenes Grid Feld direkt IN der .lp-mitte Zelle (siehe dortiger
   Kommentar in ladepunktMitteInnerHtml), deshalb hier nur ein schlichter,
   randloser Knopf statt eines eigenen Kastens wie bei
   .lp-vergleich-knopf. */
.lp-anreicherung-knopf {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-schwach);
  font-size: 0.68rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0 0 3px;
  vertical-align: middle;
  /* Bearbeitungsmodus Schalter, Nutzerwunsch 31.08.2026: "Säulennummer und
     Überdachung sollen auch nicht dauerhaft angezeigt werden. Am besten
     verstecken wir das wieder hinter einer Element, das aktiviert werden
     muss." Der Stift ist deshalb per Default unsichtbar, siehe die
     .anreicherung-bearbeitungsmodus Regel weiter unten, die ihn nur
     einblendet, wenn der gleichnamige Schalter in den Einstellungen aktiv
     ist (#einstellungen-anreicherung-bearbeitungsmodus in
     templates/index.html, siehe anreicherungBearbeitungsmodusAnwenden()
     in anreicherung.js). Gleiches Grundmuster wie .barrierefrei-modus
     weiter oben in dieser Datei, nur mit umgekehrtem Standardzustand
     (dort ist ohne die Klasse alles normal sichtbar, hier ist ohne die
     Klasse der Stift versteckt). */
  display: none;
}

.lp-anreicherung-knopf:hover {
  color: var(--text);
}

.anreicherung-bearbeitungsmodus .lp-anreicherung-knopf {
  display: inline-block;
}

/* Formular zum Eintragen von Saeulennummer/ueberdacht. Bewusst ueber ALLE
   5 Spalten von .lp-liste gespannt (grid-column:1/-1), sonst wuerde ein
   einzelnes zusaetzliches Element pro Ladepunkt die Spaltenzuordnung
   jeder nachfolgenden Zeile in diesem gemeinsamen Grid verschieben
   (siehe ausfuehrlicher Kommentar bei .lp-liste weiter oben).

   Bugfix 31.08.2026 (Nutzerwunsch, per Screenshot: das Formular stand bei
   ALLEN Ladepunkten gleichzeitig offen, nicht nur beim angeklickten): der
   Kommentar hier behauptete bisher faelschlich, das [hidden] Attribut
   reiche allein aus. Tatsaechlich gewinnt ein direktes display:flex in
   einer Autoren Regel wie dieser IMMER gegen die display:none Regel aus
   dem [hidden] Attribut, egal wie hoch dessen Spezifitaet ist (beides
   Autoren Ebene bei gleicher Spezifitaet, aber die explizite Klassen
   Regel hier stand bisher IMMER an, unabhaengig vom Attribut). Fix:
   display:none ist jetzt der Normalfall, display:flex gilt nur noch
   ausdruecklich fuer den NICHT versteckten Zustand (:not([hidden])),
   siehe anreicherungFormularUmschalten() in static/js/anreicherung.js,
   das weiterhin nur genau ein Formular pro Klick umschaltet. */
.lp-anreicherung-formular {
  grid-column: 1 / -1;
  display: none;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  padding: 4px 0 2px 26px;
}

.lp-anreicherung-formular:not([hidden]) {
  display: flex;
}

.lp-anreicherung-saeule,
.lp-anreicherung-ueberdacht {
  font-size: 0.68rem;
  padding: 2px 4px;
  border: 1px solid var(--knopf-rand);
  border-radius: 4px;
  background: var(--eingabe-hg);
  color: var(--text);
}

.lp-anreicherung-saeule {
  width: 90px;
}

.lp-anreicherung-speichern-knopf,
.lp-anreicherung-abbrechen-knopf {
  appearance: none;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text);
  font-size: 0.68rem;
  padding: 2px 8px;
  border-radius: 4px;
  cursor: pointer;
}

.lp-anreicherung-speichern-knopf:hover,
.lp-anreicherung-abbrechen-knopf:hover {
  background: rgba(0, 0, 0, 0.06);
}

.lp-anreicherung-fehler {
  color: #c0392b;
  font-size: 0.65rem;
  flex-basis: 100%;
}

/* Responsives Verhalten fuer schmale Fenster/Handys, seit 19.08.2026,
   Nutzerwunsch: "Wie muss die Webseite mobil freundlich werden?", darauf
   drei Mockups gezeigt (Bottom Sheet / ausklappbares Seitenmenue / eigene
   Tableiste), Nutzer waehlte "Variante A" (Bottom Sheet).
   Vorherige Loesung (bis 19.08.2026): Seitenleiste stapelte sich fest auf
   45% der Hoehe UEBER der Karte, kein Ein-/Ausklappen moeglich, der Karte
   blieb auf einem Handy kaum Platz UND die Filter waren nicht mehr per
   Ziehgriff erreichbar (der wird hier ohnehin ausgeblendet, siehe unten,
   eine Breite laesst sich auf einem Handy sinnvoll nicht ziehen).
   Jetzt: die Karte (#karten-bereich) nimmt automatisch die volle Hoehe
   ein, sobald die Seitenleiste per position:fixed aus dem normalen Fluss
   herausgenommen wird (kein eigenes flex:1 noetig, das war schon vorher
   gesetzt). Die Seitenleiste selbst wird zu einer von unten hochziehbaren
   Schublade (siehe sheetInitialisieren() in static/app.js): standardmaessig
   nur eine schmale Griffleiste sichtbar (#sheet-griffleiste), per Ziehen
   oder Antippen auf fast Vollbild ausklappbar, mit Abdunklung dahinter zum
   Wieder-Einklappen per Antippen. Wird das Dashboard angezeigt
   (dashboardUmschalten() versteckt #seitenleiste dafuer komplett), bleibt
   dieses Verhalten unberuehrt, .versteckt gewinnt in jedem Fall. */
@media (max-width: 720px) {
  #seitenleiste-groesse-griff {
    display: none;
  }

  #seitenleiste {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    height: 58px;
    max-height: 88vh;
    padding: 0;
    border-right: none;
    border-radius: 22px 22px 0 0;
    box-shadow: 0 -10px 34px rgba(20, 24, 40, 0.22);
    z-index: 800;
    overflow: hidden;
    transition: height 0.28s cubic-bezier(0.22, 0.85, 0.32, 1);
  }

  /* Wird von sheetInitialisieren() gesetzt, sobald die Schublade (per
     Ziehen ueber die Mitte hinaus oder per Antippen) ausgeklappt wird.
     86vh statt voller Hoehe, damit ein kleiner Kartenstreifen samt der
     Abdunklung dahinter sichtbar bleibt, das signalisiert "hier geht es
     weiter", statt wie ein komplett neuer, unabhaengiger Bildschirm zu
     wirken. */
  #seitenleiste.sheet-ausgeklappt {
    height: 86vh;
    padding: 0 18px 18px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Waehrend des Ziehens setzt sheetInitialisieren() die Hoehe direkt per
     Inline Style (folgt dem Finger 1:1), da wuerde die obige 0.28s
     Transition nur hinterherhinken/rucken. Diese Klasse schaltet die
     Transition fuer die Dauer des Ziehens komplett ab, beim Loslassen wird
     sie wieder entfernt, damit das anschliessende Einrasten (Klasse
     hinzufuegen/entfernen plus Inline Style leeren) sauber animiert. */
  #seitenleiste.sheet-ziehend {
    transition: none;
  }

  /* Griffleiste: einzige immer sichtbare Bedienelement der Schublade im
     eingeklappten Zustand. touch-action:none verhindert, dass der Browser
     das Ziehen selbst als Seiten-Scroll interpretiert (siehe Pointer
     Events in sheetInitialisieren()). Eigenes Padding statt sich auf das
     (im eingeklappten Zustand auf 0 gesetzte) #seitenleiste Padding zu
     verlassen, damit die Griffleiste unabhaengig vom Ein-/Ausklapp
     Zustand immer gleich aussieht. */
  #sheet-griffleiste {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    padding: 10px 18px 8px;
    cursor: grab;
    touch-action: none;
    -webkit-tap-highlight-color: transparent;
  }

  #sheet-griffleiste:active {
    cursor: grabbing;
  }

  #sheet-griff {
    width: 38px;
    height: 4px;
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.22);
  }

  #sheet-kurzinfo {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-schwach);
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  /* "Kartenstapel" (Nutzerwunsch 02.09.2026), siehe mobil_kartenstapel.js
     und die Markup-Stelle direkt nach #sheet-griffleiste in
     templates/index.html. Eigenes Padding wie die Griffleiste oben (die
     Seitenleiste selbst hat im eingeklappten Zustand padding:0), bleibt
     dadurch unabhaengig vom Ein-/Ausklapp Zustand gleich ausgerichtet. */
  .mobil-kartenstapel {
    display: block;
    padding: 0 14px 10px;
  }

  .mobil-chipzeile {
    display: flex;
    gap: 7px;
    overflow-x: auto;
    padding-bottom: 8px;
    -webkit-overflow-scrolling: touch;
  }

  .mobil-chip {
    flex: 0 0 auto;
    font: inherit;
    font-weight: 700;
    font-size: 0.78rem;
    padding: 7px 14px;
    border-radius: 999px;
    border: 1px solid var(--knopf-rand);
    background: var(--flaeche);
    color: var(--text-schwach);
    white-space: nowrap;
    cursor: pointer;
  }

  .mobil-chip.aktiv {
    background: var(--akzent);
    border-color: var(--akzent);
    color: #fff;
  }

  .mobil-stationskarten {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    padding-bottom: 4px;
    -webkit-overflow-scrolling: touch;
  }

  .mobil-stationskarten-leer {
    margin: 4px 0 0;
    font-size: 0.82rem;
    color: var(--text-schwach);
  }

  .mobil-stationskarte {
    flex: 0 0 168px;
    text-align: left;
    font: inherit;
    background: var(--flaeche);
    border: 1px solid var(--flaeche-rand);
    border-radius: var(--radius-klein);
    padding: 10px 12px;
    cursor: pointer;
  }

  .mobil-stationskarte-status {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-schwach);
    margin-bottom: 6px;
  }

  .mobil-stationskarte h5 {
    margin: 0 0 3px;
    font-size: 0.86rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .mobil-stationskarte p {
    margin: 0;
    font-size: 0.74rem;
    color: var(--text-schwach);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Abdunklung hinter der ausgeklappten Schublade, nur dann sichtbar/
     klickbar (siehe .sichtbar, von sheetInitialisieren() gesetzt), sonst
     waere die Karte im ausgeklappten Zustand nicht mehr erreichbar. Liegt
     unter der Seitenleiste (z-index 800), aber ueber der Karte. */
  #sheet-abdunklung {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(5, 8, 14, 0.35);
    z-index: 750;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }

  #sheet-abdunklung.sichtbar {
    opacity: 1;
    pointer-events: auto;
  }

  #toast-behaelter {
    max-width: calc(100% - 36px);
  }

  /* Die schwebende Legende (siehe #legende-schwebend weiter oben,
     urspruenglich bottom:34px, um Abstand zu Leaflets eigenem Attribution
     Hinweis zu halten) ueberschneidet sich sonst mit der neuen Griffleiste
     der Bottom Sheet Seitenleiste (58px hoch, z-index 800, gewinnt gegen
     die Legende mit z-index 500). Deshalb hier zusaetzlich um die
     Griffleiste hoehe nach oben versetzt, der urspruengliche 34px Abstand
     zur Attribution bleibt oben drauf erhalten. Wird die Seitenleiste
     ausgeklappt, verschwindet die Legende ohnehin dahinter (unkritisch,
     sie ist dann nicht der Fokus). */
  #legende-schwebend {
    bottom: calc(58px + 34px);
  }

  /* Vergleichs Panel (siehe #vergleich-schwebend weiter oben), Nutzerwunsch
     23.08.2026: die feste max-width von 360px waere auf einem schmalen
     Handybildschirm breiter als der verfuegbare Platz, gleiches Muster wie
     bei #toast-behaelter oben (calc(100% - 36px), 18px Abstand auf jeder
     Seite). */
  #vergleich-schwebend {
    max-width: calc(100% - 36px);
  }

  /* Obere Bedienleiste (siehe #obere-bedienleiste weiter oben), gleicher
     Grund/gleiches Muster wie beim Vergleichs Panel direkt darueber: auf
     einem schmalen Handybildschirm sonst breiter als der verfuegbare
     Platz. */
  #obere-bedienleiste {
    max-width: calc(100% - 36px);
  }

  #adresssuche-eingabe {
    width: 100%;
  }

  /* Listenansicht Tabelle (siehe oben): auf schmalen Handybreiten wird
     horizontal statt der ganzen Seite gescrollt (siehe .listenansicht-scroll
     Huelle in templates/index.html), sonst wuerden die Spalten zu eng
     gequetscht. */
  #listenansicht {
    padding: 60px 10px 10px;
  }

  #listenansicht-tabelle th,
  #listenansicht-tabelle td {
    padding: 8px 8px;
  }
}

/* Verwaltungsseite fuer die Netzwerkzugriff Benutzer (Stand 19.08.2026,
   Nutzerwunsch "wie kann ich weitere Nutzer anlegen?"), siehe
   templates/verwaltung.html. Eigener, einfacher Seitenaufbau (kein
   #app Flex Layout wie bei der Karte, das ist hier nicht noetig), nutzt
   aber dieselben .panel/.knopf-primaer/.knopf-sekundaer/Toast Bausteine
   wie die Hauptseite, damit es sich nicht wie eine Fremdseite anfuehlt. */
.verwaltung-seite {
  min-height: 100vh;
  padding: 32px 18px;
  display: flex;
  justify-content: center;
}

.verwaltung-inhalt {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Fehlerbehebung 11.09.2026 (Todos.xlsx, "Zurueck zur Karte"/"Zurueck zur
   Uebersicht" Knoepfe optisch noch nicht passend, soll im Stil der
   anderen Elemente sein"): bisher ein schlichter, unterstrichener
   Textlink ohne jede Rahmung - wirkte gegenueber den sonst durchgaengig
   verwendeten .knopf-primaer/.knopf-sekundaer Knoepfen unfertig. Bekommt
   deshalb dieselbe Umriss-Optik wie .knopf-sekundaer (Rahmen/Radius/
   Hover-Flaeche, siehe :root Variablen oben), aber bewusst KEINE Aenderung
   an .knopf-sekundaer selbst (dort width:100%, als volle Knopfreihe fuer
   einzelne Aktionsknoepfe gedacht) - hier stehen haeufig zwei Knoepfe
   nebeneinander, deshalb inline-flex mit eigener, kompakter Breite. */
.verwaltung-zurueck {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid var(--knopf-rand);
  border-radius: var(--radius-klein);
  padding: 7px 14px;
  transition: background 0.15s ease, transform 0.05s ease;
}

.verwaltung-zurueck:hover {
  color: var(--akzent);
  background: rgba(0, 0, 0, 0.05);
}

.verwaltung-zurueck:active {
  transform: scale(0.98);
}

/* Gemeinsame Reihe fuer die "Zurueck zur Karte"/"Zurueck zur Uebersicht"
   Knoepfe (siehe .verwaltung-zurueck oben), auf allen acht Seiten
   verwendet, teils vorher ganz ohne umschliessendes Element (z.B.
   templates/dashboard.html: .dashboard-kopf-navigation hatte bislang gar
   keine eigene CSS-Regel, die beiden <a> liefen nur als normale Inline-
   Elemente nebeneinander). */
.verwaltung-zurueck-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.verwaltung-benutzerliste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.verwaltung-benutzerliste li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--radius-klein);
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba(0, 0, 0, 0.06);
  font-size: 0.9rem;
}

.verwaltung-benutzerliste .verwaltung-leer {
  color: var(--text-schwach);
  font-size: 0.85rem;
  background: none;
  border-style: dashed;
  justify-content: center;
}

.verwaltung-loeschen-knopf {
  border: none;
  background: none;
  color: var(--belegt);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 6px;
}

.verwaltung-loeschen-knopf:hover {
  background: rgba(224, 71, 62, 0.1);
}

/* Kleines Abzeichen fuer die Administrator Rolle in der Benutzerliste
   (Stand 19.08.2026, Nutzerwunsch "wir brauchen also noch einen Account
   Status. Admin / alle anderen"), siehe templates/verwaltung.html. */
.verwaltung-rolle {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--akzent-dunkel);
  background: rgba(58, 109, 240, 0.12);
  border-radius: 6px;
  padding: 2px 6px;
  vertical-align: middle;
}

/* Meldungsuebersicht (templates/meldungen.html), Todo 10.09.2026: gleiche
   Listenoptik wie .verwaltung-benutzerliste oben, aber mit mehrzeiligem
   Beschreibungstext je Eintrag statt einer einzeiligen Zeile, deshalb
   align-items: flex-start statt center. */
#meldungsliste li {
  align-items: flex-start;
  flex-wrap: wrap;
}

.meldung-eintrag-meta {
  color: var(--text-schwach);
  font-size: 0.78rem;
  margin-left: 8px;
}

.meldung-eintrag-text {
  margin: 6px 0 4px;
  white-space: pre-wrap;
  word-break: break-word;
}

.meldung-status-knopf {
  border: 1px solid var(--flaeche-rand);
  background: none;
  color: var(--akzent-dunkel);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  padding: 5px 10px;
  border-radius: 6px;
  white-space: nowrap;
}

.meldung-status-knopf:hover {
  background: rgba(58, 109, 240, 0.1);
}

/* Erledigte Meldungen bleiben sichtbar (Nachvollziehbarkeit), aber
   optisch zurueckgenommen, gleiches Prinzip wie erledigte Eintraege
   anderswo in der Anwendung. */
#meldungsliste li.meldung-status-erledigt {
  opacity: 0.6;
}

/* ===========================================================================
   Auswertungsseite (/auswertung, separates Template, Nutzerwunsch
   31.08.2026): eigenstaendige Seite fuer die historische Ladevorgaenge
   Analyse (Filterleiste, KPI Kacheln, Diagramme, Vergleichsmodus,
   aufklappbare Tabelle). Bewusst dieselben Bausteine wie das bestehende
   Dashboard (dashboard-kpi-reihe/-kpi, dashboard-tabs/-tab,
   dashboard-balken-*, dashboard-tabelle-neu, verlauf-filter-chip,
   panel-einklappbar, knopf-primaer/-sekundaer, siehe deren jeweilige
   Kommentare weiter oben in dieser Datei), nur wenige neue, seiten-
   spezifische Klassen fuer Filterleiste/Heatmap/Liniendiagramm/
   Vergleichsraster. Volle Seite statt Fragment (anders als das Dashboard,
   das ein <main> INNERHALB von #app ist): #auswertung-seite traegt
   deshalb selbst Hintergrund/Polsterung, kein umschliessendes #app noetig.
   ========================================================================= */

#auswertung-seite {
  min-height: 100vh;
  background: var(--dash-bg);
  color: var(--text);
  padding: 32px 28px 80px;
  font-size: 13.5px;
  /* Nutzerwunsch 10.09.2026 ("milchiges Overlay + XX/XX geladen auf allen
     Seiten"): Bezugsrahmen fuer .seiten-lade-overlay, siehe dortiger
     Kommentar und #dashboard-bereich oben. */
  position: relative;
}

.auswertung-kopf {
  max-width: 1180px;
  margin: 0 auto 20px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.auswertung-kopf h1 {
  margin: 6px 0 0;
  font-size: 1.3rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

/* Filterleiste: horizontale Reihe (Auftrag: "Filterleiste oben
   horizontal"), umbricht auf schmalen Fenstern automatisch (flex-wrap),
   ein Feld je Filterart. Gleiche Eingabe-Grundoptik wie der Rest der
   Oberflaeche (input/select Regeln weiter oben in dieser Datei gelten
   automatisch mit, keine eigenen Feld-Stile noetig). */
.auswertung-filterleiste {
  max-width: 1180px;
  margin: 0 auto 6px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  padding: 16px;
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-radius: var(--radius-klein);
}

.auswertung-filterfeld {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 140px;
}

.auswertung-filterfeld label {
  margin: 0;
  font-size: 0.72rem;
}

.auswertung-filterfeld input,
.auswertung-filterfeld select {
  min-width: 0;
}

/* Landesfilter im Kontrollzentrum UND in der Auswertung, UMGEBAUT
   14.09.2026 (Nutzerwunsch "Ein Filter wie im Dashboard waere super", dann
   "Selbe fuer die Auswertung"): Checkboxen statt <select>/<select
   multiple>, siehe templates/leitstand.html/leitstand.js sowie
   templates/auswertung.html/auswertung.js (gemeinsame Klasse, da optisch
   und strukturell identisch: beide sitzen in einem .auswertung-filterfeld
   neben weiteren Dropdowns). Checkboxen nebeneinander statt der langen
   vertikalen .checkbox-zeile Liste aus dem Filterpanel der Kartenseite,
   gleicher Gedanke wie .dashboard-land-filter, hier aber ohne eigenen
   Rahmen/Hintergrund: sitzt bereits innerhalb von .auswertung-filterfeld,
   das optisch genauso wirkt wie die Dropdowns direkt daneben. */
.land-filter-checkboxen-liste {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  min-height: 30px;
}

.land-filter-checkboxen-liste .checkbox-zeile {
  margin: 0;
}

.auswertung-bereich-zeile {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-schwach);
}

.auswertung-bereich-zeile input {
  width: 90px;
}

.auswertung-filter-knoepfe {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  margin-left: auto;
}

.auswertung-filter-knoepfe .knopf-primaer,
.auswertung-filter-knoepfe .knopf-sekundaer {
  width: auto;
  margin-top: 0;
  white-space: nowrap;
}

/* Markierung fehlerhafter Ladevorgaenge in der Rohdaten-Tabelle der
   Auswertungsseite, ergaenzt 03.09.2026 (siehe Kommentar in
   templates/auswertung.html/static/js/auswertung.js). Die frueher hier
   eingeklappte Schwellenwert-Zeile (.auswertung-schwellen-zeile) steht
   seit 11.09.2026 oben in der Filterleiste und nutzt dort die normalen
   .auswertung-filterfeld-Regeln, eigene Klasse entfaellt. */
.auswertung-zeile-auffaellig {
  background: rgba(224, 71, 62, 0.08);
}

.auswertung-auffaellig-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.85em;
  white-space: nowrap;
}

.auswertung-status-hinweis {
  max-width: 1180px;
  margin: 10px auto 0;
  font-size: 0.8rem;
  color: var(--text-schwach);
}

.auswertung-status-hinweis.auswertung-status-fehler {
  color: var(--belegt);
}

#auswertung-ansicht-einzel,
#auswertung-ansicht-vergleich {
  max-width: 1180px;
  margin: 0 auto;
}

/* Einfaches SVG Liniendiagramm (Zeitverlauf), kein Chart.js (siehe
   Projektkonvention CLAUDE.md). preserveAspectRatio="none" auf dem SVG
   selbst laesst die Breite ueber CSS width:100% frei skalieren. */
.auswertung-svg {
  width: 100%;
  height: 160px;
  display: block;
}

.auswertung-svg-achse {
  stroke: var(--dash-rand);
  stroke-width: 1;
}

.auswertung-svg-linie {
  stroke: var(--akzent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.auswertung-svg-beschriftung {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  color: var(--text-schwach);
  margin-top: 4px;
}

/* Heatmap Wochentag x 4h-Zeitband als CSS Grid: erste Spalte/Zeile sind
   Beschriftungen (auto Breite), die uebrigen 6 Spalten (Zeitbaender)
   gleich breit (1fr je Spalte). */
.auswertung-heatmap-grid {
  display: grid;
  grid-template-columns: 42px repeat(6, 1fr);
  gap: 3px;
}

.auswertung-heatmap-ecke {
  background: transparent;
}

.auswertung-heatmap-kopf {
  font-size: 0.68rem;
  color: var(--text-schwach);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 0;
}

.auswertung-heatmap-zelle {
  aspect-ratio: 1.4;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.auswertung-vergleich-spalten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 16px;
}

.auswertung-vergleich-spalten .auswertung-filterfeld {
  margin-bottom: 10px;
}

.auswertung-vergleich-spalten .auswertung-bereich-zeile {
  margin-bottom: 12px;
}

.auswertung-vergleich-spalten .auswertung-bereich-zeile input {
  width: auto;
  flex: 1;
}

@media (max-width: 900px) {
  .auswertung-vergleich-spalten {
    grid-template-columns: 1fr;
  }
  .auswertung-heatmap-grid {
    grid-template-columns: 34px repeat(6, 1fr);
  }
}

/* ===========================================================
   Leitstand (/leitstand, Nutzerwunsch 02.09.2026): Live-Ueberblick
   je Betreiber. Wiederverwendet .dashboard-block/.dashboard-kpi-reihe/
   .dashboard-kpi/.dashboard-statusleiste-duenn/.auswertung-filterleiste/
   .auswertung-status-hinweis/.dashboard-meter-spur/-fuellung/
   .dashboard-balken-liste/-zeile/-spur/-fuellung/.dashboard-tabelle-neu
   unveraendert (siehe templates/leitstand.html), nur die Status-Farben
   und die seitenspezifischen Bloecke unten sind hier neu. Die Seite ist
   IMMER im Kontrollzentrum-Design (siehe dortiges FOUC-Skript), diese
   Regeln gelten deshalb automatisch fuer alle drei Skins mit (falls die
   Seite spaeter doch je ein zweites Design bekommen sollte), keine
   eigene :root[data-design="kontrollzentrum"] Einschraenkung noetig.

   UI-Umbau 03.09.2026 (siehe afir-leitstand-ui-ueberarbeitung-03-09.md):
   #leitstand-seite hatte bis hierhin UEBERHAUPT KEIN eigenes Container-CSS
   (anders als #auswertung-seite direkt darueber in dieser Datei), Inhalt
   klebte deshalb oben links ohne Polsterung/Begrenzung. Das war der
   eigentliche Grund fuer den vom Nutzer gemeldeten schlecht lesbaren
   Look, keine Geschmacksfrage. Gleichzeitig kamen auf Nutzerwunsch fuenf
   neue Bloecke dazu (grosse Verfuegbarkeitszahl, KPI-Karten, Tabelle/
   Balken je Ladepark, Aktive Ladevorgaenge jetzt, Belegunsstatus der
   Ladeparks), siehe leitstand.py fuer die zugehoerige Backend-Logik. */

#leitstand-seite {
  min-height: 100vh;
  background: var(--dash-bg);
  color: var(--text);
  padding: 32px 28px 80px;
  font-size: 13.5px;
  /* Nutzerwunsch 10.09.2026 ("milchiges Overlay + XX/XX geladen auf allen
     Seiten"): Bezugsrahmen fuer .seiten-lade-overlay, siehe dortiger
     Kommentar und #dashboard-bereich oben. */
  position: relative;
  /* Nutzerwunsch 03.09.2026 (Punkt 1, anhand Screenshots): "aktive
     Ladevorgänge" (bisher --belegt = rot) soll Orange werden, "gestörte
     Ladepunkte" (bisher --gestoert = orange) soll Rot werden. Bewusst NUR
     hier als lokale Ueberschreibung der beiden geteilten Variablen
     (kaskadiert automatisch in ALLE bestehenden var(--belegt)/
     var(--gestoert) Verwendungen innerhalb von #leitstand-seite: KPI
     Punkte, Statusleiste, Park-Balken, Stoerungs-/Ladevorgaenge-Karten),
     NICHT im globalen :root: die Hauptkarte/Auswertung nutzen dieselben
     Variablennamen mit der bisherigen, andernorts bereits etablierten
     Bedeutung (rot = belegt), das soll durch diesen rein auf den
     Leitstand bezogenen Wunsch nicht veraendert werden. Werte: die
     bisherigen Kontrollzentrum-Farbtoene von --gestoert/--belegt einfach
     vertauscht (Leitstand ist ohnehin IMMER im Kontrollzentrum-Design,
     siehe FOUC-Skript in leitstand.html), dadurch bleiben Kontrast/
     Sättigung konsistent mit dem Rest der Seite. */
  --belegt: #ffb454;
  --gestoert: #ff5c62;
}

#leitstand-inhalt {
  max-width: 1180px;
  margin: 0 auto;
}

.dashboard-punkt.frei,
.dashboard-punkt.belegt,
.dashboard-punkt.gestoert,
.dashboard-punkt.veraltet,
.dashboard-punkt.unbekannt {
  width: 8px;
  height: 8px;
}
.dashboard-punkt.frei { background: var(--frei); }
.dashboard-punkt.belegt { background: var(--belegt); }
.dashboard-punkt.gestoert { background: var(--gestoert); }
.dashboard-punkt.veraltet { background: var(--veraltet); }
.dashboard-punkt.unbekannt { background: var(--unbekannt); }

.dashboard-statusleiste-teil.frei { background: var(--frei); }
.dashboard-statusleiste-teil.belegt { background: var(--belegt); }
.dashboard-statusleiste-teil.gestoert { background: var(--gestoert); }
.dashboard-statusleiste-teil.veraltet { background: var(--veraltet); }
.dashboard-statusleiste-teil.unbekannt { background: var(--unbekannt); }

.leitstand-betreiber-feld {
  min-width: 260px;
}

/* Live-Badge oben rechts ("Aktualisiert um HH:MM:SS", Nutzerwunsch aus
   dem UI-Umbau): reiner Statustext, kein eigener Datenabruf, wird bei
   jedem erfolgreichen datenLaden() in leitstand.js neu gesetzt. */
.leitstand-live-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-radius: 999px;
  padding: 7px 14px 7px 11px;
  font-size: 0.78rem;
  color: var(--text-schwach);
  white-space: nowrap;
  margin-bottom: 10px;
}

.leitstand-puls {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--frei);
  flex-shrink: 0;
  animation: leitstand-puls 2s infinite;
}

@keyframes leitstand-puls {
  0% { box-shadow: 0 0 0 0 rgba(51, 224, 138, 0.55); }
  70% { box-shadow: 0 0 0 6px rgba(51, 224, 138, 0); }
  100% { box-shadow: 0 0 0 0 rgba(51, 224, 138, 0); }
}

/* Grosse Verfuegbarkeitszahl (Nutzerwunsch: "fehlende KPI, wie viel
   Prozent sind frei, auf einen Blick"), nutzt die bestehenden
   .dashboard-meter-spur/-fuellung fuer den Balken darunter. */
.leitstand-verfuegbarkeit-zeile {
  display: flex;
  align-items: center;
  gap: 22px;
  padding-bottom: 20px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--dash-rand);
  flex-wrap: wrap;
}

.leitstand-verfuegbarkeit-zahl {
  font-family: var(--schriftart);
  font-size: 2.4rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text);
  flex-shrink: 0;
}

.leitstand-verfuegbarkeit-zahl span { color: var(--akzent); }

.leitstand-verfuegbarkeit-info { flex: 1; min-width: 220px; }

.leitstand-verfuegbarkeit-label {
  font-size: 0.82rem;
  color: var(--text-schwach);
  margin-bottom: 8px;
}

.leitstand-legende {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 12px;
}

.leitstand-legende-eintrag {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.72rem;
  color: var(--text-schwach);
}

/* KPI-Karten fuer "Letzte 24 Stunden" (statt der duennen Linien-Reihe
   .dashboard-kpi-reihe, die "Live-Status jetzt" weiterhin nutzt): mit
   fuenf Kacheln (inkl. der neuen Stoerungsdauer-Kennzahl) wirkten duenne
   Linien zu unauffaellig, Karten setzen die Zahlen klarer voneinander ab. */
.leitstand-kpi-karten {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 14px;
  margin-top: 4px;
}

.leitstand-kpi-karte {
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-radius: var(--radius-klein);
  padding: 16px 18px;
}

.leitstand-kpi-karte .dashboard-kpi-label {
  display: flex;
  align-items: center;
  gap: 5px;
}

.leitstand-info-icon {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid var(--text-schwach);
  color: var(--text-schwach);
  font-size: 8px;
  font-style: normal;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: default;
}

.leitstand-unterkopf {
  margin: 22px 0 12px;
  font-size: 0.68rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-schwach);
}

/* Zaehl-Badges neben Block-Ueberschriften ("9 aktive Stoerungen",
   "588 laufend"), zwei Farbvarianten passend zur jeweiligen Bedeutung. */
.leitstand-zaehl-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 4px 11px;
  font-size: 0.76rem;
  font-weight: 600;
}
.leitstand-zaehl-badge-warnung { background: rgba(255, 180, 84, 0.14); color: var(--gestoert); }
.leitstand-zaehl-badge-laden { background: rgba(255, 92, 98, 0.12); color: var(--belegt); }

/* Stoerungen jetzt / Aktive Ladevorgaenge jetzt: gleiche Listenstruktur
   fuer beide (leitstand.js rendert beide mit .leitstand-stoerung-zeile,
   die Ladevorgaenge-Variante zusaetzlich mit dem Modifikator
   -laden). Als Karten statt duenner Trennlinien (Nutzerwunsch aus dem
   UI-Umbau: "Stoerungsliste unuebersichtlich"), scrollt bei vielen
   Eintraegen INNERHALB des Blocks statt die Seite zu sprengen. */
.leitstand-stoerungsliste {
  list-style: none;
  margin: 14px 0 0;
  padding-right: 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 420px;
  overflow-y: auto;
}

.leitstand-stoerungsliste::-webkit-scrollbar { width: 7px; }
.leitstand-stoerungsliste::-webkit-scrollbar-track { background: transparent; }
.leitstand-stoerungsliste::-webkit-scrollbar-thumb { background: var(--dash-rand-eingabe); border-radius: 4px; }

.leitstand-stoerung-zeile {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 13px 16px;
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-left: 3px solid var(--gestoert);
  border-radius: 9px;
}

.leitstand-stoerung-zeile-laden { border-left-color: var(--belegt); }

.leitstand-stoerung-zeile .dashboard-punkt {
  flex-shrink: 0;
}

.leitstand-stoerung-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  color: var(--text);
  font-size: 0.88rem;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.leitstand-stoerung-adresse {
  font-weight: 400;
  font-size: 0.76rem;
  color: var(--text-schwach);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.leitstand-stoerung-seit {
  flex-shrink: 0;
  font-size: 0.78rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--gestoert);
  background: rgba(255, 180, 84, 0.12);
  border-radius: 999px;
  padding: 5px 12px;
  white-space: nowrap;
}

.leitstand-stoerung-seit-laden {
  color: var(--belegt);
  background: rgba(255, 92, 98, 0.12);
}

.leitstand-keine-stoerungen,
.leitstand-keine-ladeparks-24h {
  margin-top: 14px;
}

/* Belegungsstatus der Ladeparks: Mini-Statusleiste je Standort statt
   einer weiteren Zahlenreihe, sortiert vom Server nach hoechstem
   Stoerungsanteil (siehe leitstand._ladeparks_live_gruppieren).
   Fehlerbehebung (Todos.xlsx, Niedrig, 11.09.2026: "nur scrollbar
   machen, wie beim Feld 'Aktive Ladevorgaenge jetzt'"): scrollt jetzt
   ebenso INNERHALB des Blocks statt die Seite zu sprengen, gleiches
   Prinzip/gleiche Scrollbar-Optik wie .leitstand-stoerungsliste oben. */
.leitstand-park-liste {
  list-style: none;
  margin: 14px 0 0;
  padding-right: 4px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-height: 420px;
  overflow-y: auto;
}

.leitstand-park-liste::-webkit-scrollbar { width: 7px; }
.leitstand-park-liste::-webkit-scrollbar-track { background: transparent; }
.leitstand-park-liste::-webkit-scrollbar-thumb { background: var(--dash-rand-eingabe); border-radius: 4px; }

/* Suchfeld ueber der Belegungsstatus-Liste (Todos.xlsx, Niedrig,
   11.09.2026: "Suchfunktion nach Ladepark/Adresse einfuegen"), gleiche
   Eingabefeld-Optik wie die uebrigen Filterfelder. */
.leitstand-park-suche {
  width: 100%;
  margin-top: 14px;
  box-sizing: border-box;
  font: inherit;
  font-size: 0.82rem;
  padding: 8px 12px;
  border: 1px solid var(--dash-rand-eingabe);
  border-radius: var(--radius-klein);
  background: var(--dash-flaeche-schwach);
  color: var(--text);
}

.leitstand-park-suche:focus {
  outline: 2px solid var(--akzent);
  outline-offset: 1px;
}

.leitstand-park-keine-treffer {
  margin-top: 14px;
}

.leitstand-park-zeile {
  display: flex;
  align-items: center;
  gap: 16px;
  cursor: pointer;
}

.leitstand-park-name-spalte {
  width: 190px;
  flex-shrink: 0;
  min-width: 0;
  /* Fehlerbehebung 03.09.2026 (Punkt 3, "Text ragt in das Diagramm"):
     .leitstand-park-titel/-unterzeile sind <span> Elemente (siehe
     leitstand.js parkListeRendern), also standardmaessig INLINE. Ein
     inline-Element hat KEINE eigene Breite, gegen die white-space:nowrap/
     overflow:hidden/text-overflow:ellipsis auf .leitstand-park-titel
     wirken koennten - genau deshalb lief ein langer Standortname trotz
     dieser drei Eigenschaften ungekuerzt in die danebenliegende
     Statusleiste hinein. overflow:hidden auf dem Spalten-Container hier
     schneidet das jetzt zusaetzlich zuverlaessig ab, unabhaengig vom
     display-Typ der Kinder. */
  overflow: hidden;
}

.leitstand-park-titel {
  /* Fehlerbehebung Punkt 3 (siehe Kommentar oben an .leitstand-park-name-
     spalte): erst mit display:block greifen white-space/overflow/
     text-overflow ueberhaupt, ausserdem noetig, damit der Titel in einer
     eigenen Zeile ueber der Unterzeile steht statt direkt danebenzukleben
     (beide waren bisher inline <span>s ohne Zeilenumbruch dazwischen). */
  display: block;
  font-weight: 600;
  color: var(--text);
  font-size: 0.85rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.leitstand-park-unterzeile {
  display: block;
  font-size: 0.72rem;
  color: var(--text-schwach);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.leitstand-park-pfeil {
  flex-shrink: 0;
  color: var(--text-schwach);
  font-size: 0.7rem;
  transition: transform 0.15s ease;
}

.leitstand-park-zeile.leitstand-offen .leitstand-park-pfeil {
  transform: rotate(90deg);
}

/* Ausklappmenue je Ladepark (Nutzerwunsch Punkt 4: "mehr Infos zu dem
   Ladepark, Groesse, Anzahl der LP der jeweiligen Leistungen, Matrix mit
   Wochentag x Uhrzeit und Auslastung"). Wiederverwendet die bestehenden
   .auswertung-heatmap-* Klassen aus der Auswertungsseite unveraendert
   (siehe leitstandHeatmapRendern in leitstand.js), keine Duplikation. */
.leitstand-park-detail {
  margin: 2px 0 4px 30px;
  padding: 14px 16px;
  background: var(--dash-flaeche-schwach);
  border: 1px solid var(--dash-rand);
  border-radius: var(--radius-klein);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.leitstand-park-detail-kennzahlen {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
}

.leitstand-park-detail-kennzahl {
  font-size: 0.76rem;
  color: var(--text-schwach);
}

.leitstand-park-detail-kennzahl b {
  display: block;
  font-size: 1.1rem;
  color: var(--text);
  font-weight: 650;
}

.leitstand-park-detail-spalten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}

.leitstand-park-detail-ladehinweis {
  font-size: 0.78rem;
  color: var(--text-schwach);
}

@media (max-width: 760px) {
  .leitstand-park-detail-spalten { grid-template-columns: 1fr; }
}

/* Stuendlicher 24h-Auslastungsverlauf (Nutzerwunsch Punkt 5). War
   urspruenglich ein Balkenchart aus 24 Saeulen, auf Nutzerwunsch
   (Todos.xlsx, Niedrig, 11.09.2026: "als Liniendiagramm darstellen")
   auf dasselbe SVG-Liniendiagramm umgestellt, das die Auswertungsseite
   fuer den Zeitverlauf verwendet (.auswertung-svg/-svg-linie/-svg-achse/
   -svg-beschriftung, siehe zeitverlaufSvgRendern in auswertung.js bzw.
   stundenverlaufRendern in leitstand.js - bewusst dieselben Klassen
   statt eigener Duplikate, identisches Diagrammprinzip). */
.leitstand-stundenverlauf {
  margin-top: 6px;
}

/* Verteilung nach Leistung/Steckertyp (Nutzerwunsch Punkt 5), zwei
   nebeneinander liegende .dashboard-balken-liste Listen (bestehende
   Komponente, unveraendert wiederverwendet). */
.leitstand-verteilung-spalten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 4px;
}

@media (max-width: 760px) {
  .leitstand-verteilung-spalten { grid-template-columns: 1fr; }
}

/* "Siehe Antworten" (Nutzerwunsch Punkt 2): Ladepunkt-ID direkt in der
   Stoerungs-/Ladevorgangs-Zeile plus ein Knopf, der die zuletzt bekannte
   Rohantwort (status_roh/letzte_aktualisierung/Leistung/Preis) darunter
   aufklappt, ohne Extra-Request (die Daten kommen bereits mit
   api_leitstand_daten, siehe leitstand.py "antwort"-Feld). */
.leitstand-stoerung-id-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}

.leitstand-stoerung-id {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 0.68rem;
  color: var(--text-schwach);
}

.leitstand-antwort-knopf {
  border: none;
  background: transparent;
  color: var(--akzent);
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.leitstand-antwort-box {
  flex-basis: 100%;
  margin-top: 8px;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.75);
  border-radius: var(--radius-klein);
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 0.72rem;
  color: #cbd5e1;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
}

.leitstand-antwort-box dt { color: #8b93a3; }
.leitstand-antwort-box dd { margin: 0; word-break: break-all; }

.leitstand-park-leiste-spalte { flex: 1; }

.leitstand-park-leiste {
  display: flex;
  height: 9px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--dash-rand);
}

.leitstand-park-zahlen {
  width: 190px;
  flex-shrink: 0;
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-schwach);
}

.leitstand-park-zahlen b { color: var(--text); font-weight: 650; }

@media (max-width: 860px) {
  .leitstand-kpi-karten { grid-template-columns: repeat(2, 1fr); }
  .leitstand-park-name-spalte,
  .leitstand-park-zahlen { width: 130px; }
}

/* ===================== Datenquellen-Verwaltung (/datenquellen) =====================
   Neue Admin/Dev Seite, Nutzerwunsch 03.09.2026 (siehe Projektnotiz
   afir-verwaltung-datenquellen-03-09 und templates/datenquellen.html):
   Uebersicht/Verwaltung der Mobilithek-Subscriptions je Datenanbieter.
   Nutzt bewusst dieselben Bausteine wie /verwaltung (.verwaltung-seite/
   -inhalt/-zurueck, .panel, .knopf-primaer/-sekundaer), .dq-inhalt
   ueberschreibt nur die max-width (480px waere fuer eine Tabellenseite
   viel zu schmal). Alle Farben ueber die bestehenden :root Variablen
   (siehe ganz oben in dieser Datei), damit Design-Wechsel (Glas/
   Enterprise/Kontrollzentrum) und Dunkelmodus automatisch mitgelten,
   ohne hier je eigene Farben pflegen zu muessen. */

.dq-inhalt {
  max-width: 1100px;
}

/* ===================== Einstellungen (/einstellungen) =====================
   Neue globale, Admin-only Einstellungsseite, Nutzerwunsch 03.09.2026
   ("Neue Seite, die aber nur im Adminmodus einsehbar/erreichbar ist [...]
   soll alle Einstellungen enthalten [...] eine Verwaltung, eine
   Datenquelle und die Moeglichkeit alle Daten einmal zu speichern und den
   Cache der Seite zu loeschen"), siehe templates/einstellungen.html und
   routen_einstellungen.py. Nutzt bewusst dieselben Bausteine wie /
   datenquellen (.verwaltung-seite/-inhalt/-zurueck, .panel, .dq-kopf-panel,
   .dq-panel-titel, .dq-hinweis, .knopf-sekundaer/-primaer,
   .verwaltung-link-knopf), .es-inhalt ueberschreibt nur die max-width
   (gleiches Prinzip wie .dq-inhalt/.anmeldung-inhalt/.hauptseite-inhalt
   oberhalb). .es-link-reihe reiht mehrere Link-/Aktions-Knoepfe (z.B.
   Nutzerverwaltung + Datenquellen-Verwaltung, oder die drei Cache
   Knoepfe) nebeneinander statt jeden einzeln auf volle Breite
   (.verwaltung-link-knopf/.knopf-sekundaer sind sonst block-weit), mit
   Zeilenumbruch auf schmalen Bildschirmen. */
.es-inhalt {
  max-width: 900px;
}

.es-link-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.es-link-reihe > .verwaltung-link-knopf {
  display: inline-block;
  width: auto;
  flex: 1 1 220px;
}

/* CSV Export/Bildschirmfoto/Teilen Link auf dieser Seite bewusst
   deaktiviert (siehe Kommentar in templates/einstellungen.html, Abschnitt
   "Aktionen"): sichtbar als deaktiviert statt wie ein normaler, aktiver
   Knopf auszusehen. */
.es-link-reihe > .knopf-sekundaer:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Anmeldung (/login) und Hauptseite (/), ergaenzt 03.09.2026 (Session-
   Login/Hauptseiten-Umbau). Gleiches Grundmuster wie .dq-inhalt direkt
   oberhalb: .verwaltung-seite/-inhalt/.panel/.knopf-primaer/-sekundaer
   werden unveraendert wiederverwendet, nur die max-width angepasst. */
.anmeldung-inhalt {
  max-width: 380px;
}

.anmeldung-fehler {
  margin: 0;
  padding: 9px 12px;
  border-radius: var(--radius-klein);
  background: rgba(224, 71, 62, 0.12);
  color: var(--belegt);
  font-size: 0.85rem;
}

.hauptseite-inhalt {
  max-width: 720px;
}

.hauptseite-kopf {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.hauptseite-kopf .abmelden-formular {
  width: auto;
}

.hauptseite-kopf .abmelden-formular > button {
  width: auto;
  margin-top: 0;
}

.hauptseite-kacheln {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}

.hauptseite-kachel {
  display: block;
  padding: 16px 18px;
  border-radius: var(--radius-klein);
  border: 1px solid var(--flaeche-rand);
  background: rgba(255, 255, 255, 0.4);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.hauptseite-kachel:hover {
  border-color: var(--akzent);
  background: rgba(58, 109, 240, 0.06);
}

.hauptseite-kachel h2 {
  margin: 0 0 6px 0;
  font-size: 1rem;
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
}

.hauptseite-kachel p {
  margin: 0;
  color: var(--text-schwach);
  font-size: 0.85rem;
}

.dq-kopf-zeile {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.dq-kopf-knoepfe {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.dq-kopf-knoepfe .knopf-primaer,
.dq-kopf-knoepfe .knopf-sekundaer {
  width: auto;
  margin-top: 0;
  white-space: nowrap;
}

.dq-kpi-reihe {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  margin-top: 16px;
}

.dq-kpi-kachel {
  background: var(--dash-bg);
  border: 1px solid var(--dash-rand);
  border-radius: var(--radius-klein);
  padding: 10px 12px;
}

.dq-kpi-kachel .dq-kpi-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
  margin-bottom: 4px;
}

.dq-kpi-kachel .dq-kpi-wert {
  font-family: var(--schriftart);
  font-size: 1.3rem;
  font-weight: 700;
}

.dq-hinweis {
  font-size: 0.85rem;
  color: var(--text-schwach);
  margin: 0;
}

.dq-konflikt-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: var(--radius-klein);
  background: rgba(245, 185, 92, 0.16);
  border: 1px solid rgba(245, 185, 92, 0.4);
  color: var(--text);
  font-weight: 600;
}

/* Fix 04.09.2026: "display: flex" oben schlug bisher IMMER die native
   [hidden] Browser-Regel (Autor-CSS gewinnt gegen die UA-Regel
   "[hidden] { display: none }" unabhaengig von der Spezifitaet). Der
   Banner blieb dadurch dauerhaft sichtbar (mit dem zuletzt gesetzten,
   ggf. veralteten Text), selbst nachdem datenquellen.js
   konfliktBanner.hidden = true gesetzt hatte, weil alle Konflikte
   geloest waren. Diese Regel stellt das Ausblenden wieder her. */
.dq-konflikt-banner[hidden] {
  display: none;
}

.dq-tabelle-panel {
  padding: 0;
  overflow: hidden;
}

.dq-tabellenkopf {
  display: grid;
  grid-template-columns: 1.8fr 1fr 1.2fr 1.4fr 1.1fr 0.5fr;
  gap: 10px;
  padding: 12px 18px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
  border-bottom: 1px solid var(--flaeche-rand);
}

.dq-zeile {
  border-bottom: 1px solid var(--flaeche-rand);
}

.dq-zeile:last-child {
  border-bottom: none;
}

.dq-zeile-hauptreihe {
  display: grid;
  grid-template-columns: 1.8fr 1fr 1.2fr 1.4fr 1.1fr 0.5fr;
  gap: 10px;
  padding: 12px 18px;
  align-items: center;
  cursor: pointer;
}

.dq-anbieter-zelle {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.dq-pfeil {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 6px;
  border: 1px solid var(--knopf-rand);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.15s ease;
  color: var(--text-schwach);
}

.dq-zeile.dq-offen .dq-pfeil {
  transform: rotate(90deg);
}

.dq-anbieter-name {
  font-weight: 600;
  font-size: 0.92rem;
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dq-anbieter-cpos-kurz {
  font-size: 0.75rem;
  color: var(--text-schwach);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dq-konflikt-punkt {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gestoert);
  flex-shrink: 0;
}

.dq-badge {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 99px;
  border: 1px solid var(--knopf-rand);
  background: var(--eingabe-hg);
  color: var(--text-schwach);
  white-space: nowrap;
}

.dq-badge.dq-badge-dynamisch {
  border-color: rgba(43, 109, 224, 0.35);
  background: rgba(43, 109, 224, 0.1);
  color: var(--akzent);
}

.dq-uebertragung-zelle {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dq-schalter {
  position: relative;
  width: 42px;
  height: 22px;
  border-radius: 99px;
  border: 1px solid var(--knopf-rand);
  background: var(--eingabe-hg);
  flex-shrink: 0;
  cursor: pointer;
  padding: 0;
}

.dq-schalter.dq-schalter-an {
  background: var(--akzent);
  border-color: var(--akzent);
}

.dq-schalter:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.dq-schalter-knopf {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  transition: left 0.15s ease;
}

.dq-schalter-an .dq-schalter-knopf {
  left: 22px;
}

.dq-uebertragung-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-schwach);
  min-width: 30px;
}

.dq-portal-zelle {
  font-size: 0.75rem;
  line-height: 1.4;
}

.dq-portal-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
}

.dq-punkt {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.dq-punkt-gruen { background: var(--frei); }
.dq-punkt-rot { background: var(--belegt); }
.dq-punkt-gelb { background: var(--gestoert); }
.dq-punkt-grau { background: var(--unbekannt); }

.dq-portal-status.dq-status-bestaetigt { color: var(--frei); }
.dq-portal-status.dq-status-nicht_bestaetigt { color: var(--belegt); }
.dq-portal-status.dq-status-unbekannt { color: var(--gestoert); }

.dq-portal-unterzeile {
  color: var(--text-schwach);
  margin-top: 2px;
}

.dq-health-zelle {
  font-size: 0.75rem;
}

.dq-health-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
}

.dq-health-status.dq-status-gruen { color: var(--frei); }
.dq-health-status.dq-status-rot { color: var(--belegt); }
.dq-health-status.dq-status-gelb { color: var(--gestoert); }
.dq-health-status.dq-status-unbekannt { color: var(--unbekannt); }

.dq-health-unterzeile {
  color: var(--text-schwach);
  margin-top: 2px;
}

.dq-mobilithek-link {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--knopf-rand);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-schwach);
  float: right;
}

.dq-mobilithek-link:hover {
  color: var(--akzent);
  border-color: var(--akzent);
}

.dq-aufklapp {
  padding: 4px 18px 18px 48px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.dq-unterueberschrift {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
  margin-bottom: 8px;
}

.dq-cpo-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-klein);
  background: var(--dash-bg);
  border: 1px solid var(--dash-rand);
  font-size: 0.85rem;
  margin-bottom: 6px;
}

.dq-cpo-zeile.dq-cpo-konflikt,
.dq-cpo-zeile.dq-cpo-geloest {
  align-items: flex-start;
  flex-wrap: wrap;
}

.dq-cpo-zeile.dq-cpo-konflikt {
  background: rgba(245, 185, 92, 0.14);
  border-color: rgba(245, 185, 92, 0.4);
}

.dq-cpo-zeile.dq-cpo-geloest {
  background: rgba(43, 184, 106, 0.08);
  border-color: rgba(43, 184, 106, 0.3);
}

.dq-cpo-name {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}

.dq-cpo-konflikt-hinweis {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.78rem;
  color: #8a6209;
}

.dq-cpo-konflikt-knopf {
  padding: 4px 10px;
  border-radius: 7px;
  font-size: 0.75rem;
  font-weight: 700;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
  cursor: pointer;
}

.dq-cpo-konflikt-knopf.dq-aktiv {
  background: var(--akzent);
  border-color: var(--akzent);
  color: #fff;
}

/* Nutzerwunsch 03.09.2026 Punkt 2: nach dem Festlegen eines federfuehrenden
   Anbieters bleiben ALLE Anbieter-Knoepfe (inkl. eines "Zuruecksetzen"
   Knopfes) sichtbar und waehlbar, statt zu verschwinden. Eigener
   Wrapper statt eines gemeinsamen Flex-Containers mit den umgebenden
   Texten, damit die Knopfreihe bei schmalen Fenstern sauber umbricht. */
.dq-cpo-konflikt-knoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.dq-cpo-konflikt-zuruecksetzen {
  color: #b3261e;
  border-color: rgba(179, 38, 30, 0.35);
}

.dq-push-url-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: var(--radius-klein);
  background: rgba(0, 0, 0, 0.75);
  color: #cbd5e1;
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 0.75rem;
  word-break: break-all;
}

.dq-test-knopf {
  padding: 8px 14px;
  border-radius: var(--radius-klein);
  border: 1px solid rgba(43, 109, 224, 0.35);
  background: rgba(43, 109, 224, 0.1);
  color: var(--akzent);
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  /* Nutzerwunsch 03.09.2026 Punkt 4: mehr Abstand zwischen den Knoepfen
     ("Bestätigt"/"Nicht bestätigt"/"Unbekannt"/Testknoepfen), vorher per
     Inline-style margin-left:8px auf einzelnen Knoepfen geloest, jetzt
     einheitlich per margin auf allen .dq-test-knopf-Elementen. */
  margin-right: 10px;
  margin-top: 6px;
}

.dq-test-knopf:disabled {
  opacity: 0.6;
  cursor: wait;
}

/* Punkt 4: einheitlicher, grosszuegigerer Abstand fuer die Portal-Status
   Knopfreihe (Bestaetigt/Nicht bestaetigt/Unbekannt), vorher per Inline-
   style "gap:6px" geloest. */
.dq-portal-status-auswahl {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}

/* Nutzerwunsch 03.09.2026 Punkt 1: Statisch/Dynamisch als zwei klar
   getrennte, gleichrangige Abschnitte je Anbieter-Zeile. */
.dq-quellart-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.dq-quellart-abschnitt {
  flex: 1 1 260px;
  min-width: 240px;
  padding: 12px 14px;
  border-radius: var(--radius-klein);
  background: var(--dash-bg);
  border: 1px solid var(--dash-rand);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.dq-unterueberschrift-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
}

.dq-unterueberschrift-zeile .dq-unterueberschrift {
  margin-bottom: 0;
}

.dq-uebertragung-hinweis {
  font-size: 0.78rem;
  color: var(--text-schwach);
}

.dq-uebertragung-hinweis-schwach {
  opacity: 0.7;
}

/* Editierbare Subscription-ID Zeilen je Datenart (Punkt 1), z. B. um bei
   einem bisher rein statischen Anbieter wie 'gls-mobility' auch eine
   Dynamisch-ID nachzutragen, oder eine bestehende ID zu korrigieren. */
.dq-id-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.dq-id-wert {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 0.78rem;
  color: var(--text);
  word-break: break-all;
}

.dq-id-formular {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.dq-id-eingabe {
  flex: 1 1 160px;
  min-width: 140px;
  padding: 6px 10px;
  border-radius: 7px;
  border: 1px solid var(--knopf-rand);
  background: var(--eingabe-bg, transparent);
  color: var(--text);
  font-size: 0.8rem;
}

.dq-id-knopf {
  padding: 6px 10px;
  border-radius: 7px;
  font-size: 0.75rem;
  font-weight: 700;
  border: 1px solid rgba(43, 109, 224, 0.35);
  background: rgba(43, 109, 224, 0.1);
  color: var(--akzent);
  cursor: pointer;
}

.dq-id-knopf-sekundaer {
  border-color: var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
}

.dq-id-knopf-loeschen {
  border-color: rgba(179, 38, 30, 0.35);
  background: transparent;
  color: #b3261e;
}

/* Nutzerwunsch Punkt 5: Kette-Gruppierung (z. B. "ALDI SE & Co. KG" ueber
   alle Standorte hinweg), Detailliste je Standort bleibt per <details>
   erhalten. */
.dq-kette-umschalt-knopf {
  padding: 5px 10px;
  border-radius: 7px;
  font-size: 0.72rem;
  font-weight: 700;
  border: 1px solid var(--knopf-rand);
  background: transparent;
  color: var(--text-schwach);
  cursor: pointer;
  white-space: nowrap;
}

.dq-kette-zeile {
  border-radius: var(--radius-klein);
  background: var(--dash-bg);
  border: 1px solid var(--dash-rand);
  margin-bottom: 6px;
  padding: 2px 4px;
}

.dq-kette-zeile > summary {
  list-style: none;
  cursor: pointer;
  padding: 7px 8px;
}

.dq-kette-zeile > summary::-webkit-details-marker {
  display: none;
}

.dq-kette-mitglieder {
  padding: 4px 8px 8px;
}

.dq-kette-mitglieder .dq-cpo-zeile {
  background: var(--panel-bg, var(--dash-bg));
}

/* Nutzerwunsch Punkt 6: eigener Ueberblicks-Bereich fuer CPOs mit mehreren
   Datenanbietern, siehe templates/datenquellen.html/dq-konflikt-panel. */
.dq-konflikt-panel {
  margin-bottom: 18px;
}

.dq-panel-titel {
  font-size: 1rem;
  margin-bottom: 4px;
}

.dq-test-ergebnis {
  margin-top: 8px;
  padding: 9px 13px;
  border-radius: var(--radius-klein);
  font-size: 0.8rem;
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.dq-test-ergebnis.dq-erfolg {
  background: rgba(43, 184, 106, 0.1);
  border: 1px solid rgba(43, 184, 106, 0.3);
  color: #1e8a4c;
}

.dq-test-ergebnis.dq-fehler {
  background: rgba(224, 71, 62, 0.1);
  border: 1px solid rgba(224, 71, 62, 0.3);
  color: #b13b32;
}

/* Bugfix 03.09.2026: gleicher Cascade Bug wie bei .lp-anreicherung-formular
   (siehe dortiger Kommentar, 31.08.2026) - ein unbedingtes display:flex in
   dieser Autoren Regel gewinnt IMMER gegen display:none aus dem [hidden]
   Attribut, egal wie hoch dessen Spezifitaet ist. Der Schliessen-Knopf im
   Excel-Import Dialog setzte importOverlay.hidden = true korrekt per JS,
   das Overlay blieb aber sichtbar. Fix: display:none ist jetzt der
   Normalfall, display:flex gilt nur noch ausdruecklich fuer den NICHT
   versteckten Zustand (:not([hidden])), siehe static/js/datenquellen.js. */
.dq-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 15, 20, 0.45);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 20px;
}

.dq-overlay:not([hidden]) {
  display: flex;
}

.dq-dialog {
  width: 100%;
  max-width: 420px;
  max-height: 90vh;
  overflow-y: auto;
}

.dq-dialog form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}

.dq-dialog label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-schwach);
}

.dq-dialog input[type="text"],
.dq-dialog select,
.dq-dialog input[type="file"] {
  padding: 9px 11px;
  border-radius: var(--radius-klein);
  border: 1px solid var(--knopf-rand);
  background: var(--eingabe-hg);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
}

.dq-dialog-knoepfe {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 6px;
}

.dq-dialog-knoepfe .knopf-primaer,
.dq-dialog-knoepfe .knopf-sekundaer {
  width: auto;
  margin-top: 0;
}

.dq-formular-fehler {
  color: var(--belegt);
  font-size: 0.8rem;
  margin: 0;
}

.dq-formular-erfolg {
  color: #1e8a4c;
  font-size: 0.8rem;
  margin: 0;
}

.dq-protokoll-seitenleiste {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 360px;
  max-width: 90vw;
  background: var(--flaeche);
  backdrop-filter: blur(var(--panel-blur));
  border-left: 1px solid var(--flaeche-rand);
  padding: 20px;
  overflow-y: auto;
  z-index: 40;
  box-shadow: -16px 0 40px rgba(0, 0, 0, 0.15);
}

.dq-protokoll-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.dq-schliessen-knopf {
  background: none;
  border: none;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--text-schwach);
  cursor: pointer;
}

.dq-protokoll-eintrag {
  padding: 10px 4px;
  border-bottom: 1px solid var(--flaeche-rand);
  font-size: 0.8rem;
}

.dq-protokoll-eintrag:last-child {
  border-bottom: none;
}

.dq-protokoll-zeit {
  color: var(--text-schwach);
  font-size: 0.72rem;
  margin-top: 3px;
}

@media (max-width: 760px) {
  .dq-tabellenkopf {
    display: none;
  }
  .dq-zeile-hauptreihe {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  .dq-aufklapp {
    padding-left: 18px;
  }
}
