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

    :root {
      --bg:       #0f172a;
      --surface:  #1e293b;
      --surface2: #263348;
      --border:   #334155;
      --text:     #f1f5f9;
      --text2:    #94a3b8;
      --text3:    #64748b;
      --accent:   #06b6d4;
      --accent2:  #0891b2;
      --green:    #22c55e;
      --yellow:   #eab308;
      --red:      #ef4444;
      --orange:   #f97316;
      --radius:   14px;
      /* Der Abstand zwischen den Kacheln UND zum Rand der Seite — eine Zahl
         fuer beides, damit das Raster gleichmaessig bleibt. Von 16 auf 10 px
         verkleinert: auf dem Wandtablet ist jeder Pixel Rand ein Pixel, den
         kein Messwert bekommt, und die Kacheln trennen sich ohnehin durch
         Rahmen und Flaeche voneinander, nicht durch Luft. */
      --gap:      10px;
      --header-basis: 57px;
      /* Waren einmal zwei Werte: das Kopie-Band klemmte oben unter der
         Kopfzeile und schob den Inhalt um seine Hoehe nach unten. Seit alle
         Meldungen unten schweben, schiebt nichts mehr. */
      --header-h: var(--header-basis);
    }

    /* Kein Nachladen durch Ziehen und kein Ueberscrollen.
       In der installierten Wandfassung loeste die Zwei-Finger-Geste beim
       Umschalten der Spalten fast jedes Mal das Neuladen der Seite aus: zwei
       Finger, die sich nach unten bewegen, sind fuer den Browser eine
       Zieh-zum-Neuladen-Geste. */
    html { height: 100%; overscroll-behavior-y: contain; }
    /* body MUSS mitwachsen duerfen. Mit height:100% war die Box exakt
       bildschirmhoch, waehrend der Inhalt darueber hinauslief — und ein
       haftendes Element (die Statusleiste) ist an die Box seines Elternteils
       gebunden. Am Telefon rutschte sie deshalb nach etwa 600 px doch noch
       aus dem Bild. */
    body { min-height: 100%; background: var(--bg); color: var(--text);
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      -webkit-font-smoothing: antialiased; }

    /* ── Nichts markieren, wo bedient wird ───────────────────────────────
       Das Armaturenbrett ist kein Text zum Lesen, sondern eine Flaeche zum
       Anfassen — und seit Tippen, Ziehen und Halten dort verschiedene Dinge
       bedeuten, faengt der Browser bei jedem Halten an, Text zu markieren.
       Es reichte NICHT, das an den einzelnen Feldern zu setzen: eine Auswahl,
       die auf einem nicht markierbaren Element beginnt, greift trotzdem auf
       den Text daneben ueber.
       Die Unterseiten sind ausgenommen: dort stehen Adressen, Seriennummern
       und Notizen, die jemand herauskopieren will. Sie liegen ausserhalb von
       <main>. */
    main, .statusbar {
      user-select: none; -webkit-user-select: none;
      -webkit-touch-callout: none;
    }
    /* Eingabefelder bleiben Eingabefelder. */
    main input, main textarea, main [contenteditable] {
      user-select: text; -webkit-user-select: text;
    }

    /* ── Header ── */
    header {
      display: grid; grid-template-columns: 1fr auto 1fr;
      align-items: center;
      padding: 14px 20px 12px; border-bottom: 1px solid var(--border);
      background: var(--surface); position: fixed; top: 0; left: 0; right: 0; z-index: 101;
    }
    .logo { font-size: 20px; font-weight: 700; letter-spacing: .18em;
      color: var(--accent); text-transform: uppercase;
      /* Nie umbrechen: die Versionsnummer rutschte sonst unter den Schriftzug
         und machte die Kopfzeile eine Zeile hoeher. Passt sie nicht mehr
         daneben, wird sie ausgeblendet (siehe _kopfLogoPruefen in core.js). */
      white-space: nowrap; min-width: 0; }
    .logo.ohne-version .logo-ver { display: none; }
    .logo span { color: var(--text2); font-weight: 400; font-size: 13px;
      letter-spacing: .04em; margin-left: 10px; }
    .header-right { display: flex; align-items: center; gap: 10px; justify-self: end; grid-column: 3; }
    .conn-badge { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text2); }
    .conn-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--red); transition: background .4s; }
    .conn-dot.ok   { background: var(--green); }
    .conn-dot.warn { background: var(--yellow); animation: pulse 1.5s infinite; }
    @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.35} }

    /* ── Icon button (shared) ── */
    .icon-btn {
      background: none; border: 1px solid var(--border); border-radius: 8px;
      color: var(--text2); cursor: pointer; padding: 6px 8px;
      display: flex; align-items: center; transition: all .15s;
    }
    .icon-btn:hover { background: var(--surface2); color: var(--accent); border-color: var(--accent2); }
    .icon-btn:focus { outline: none; }
    /* aktive Seite: blauer Rahmen-Indikator (wie zuvor nur beim Internet-Button) */
    .icon-btn.nav-active { border-color: var(--accent2); color: var(--accent);
      box-shadow: 0 0 0 1px var(--accent2); }

    /* ── Wandbetrieb: Bildschirm anlassen, Nachtmodus ── */
    .wand-knoepfe { display: flex; align-items: center; gap: 8px; }
    .wand-knopf.an { border-color: var(--accent2); color: var(--accent);
      box-shadow: 0 0 0 1px var(--accent2); }
    /* „Gewollt, aber steht nicht": ein eigener Zustand, kein dritter Anstrich
       von „an". Der Schalter steht auf an, die Sperre haelt gerade nicht —
       wer das nicht sieht, wundert sich spaeter ueber einen dunklen Bildschirm. */
    .wand-knopf.wartet { border-color: var(--yellow); color: var(--yellow); }

    /* ── Das Band auf /wand ─────────────────────────────────────────────── */
    /* Eine Auskunft, kein Werbebanner: es steht nur auf /wand und nur, solange
       die Anwendung NICHT im Vollbild laeuft. Ist sie es, verschwindet es von
       selbst — dann ist die Frage beantwortet. */
    #wandBand {
      position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 901;
      display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
      padding: 12px 14px; border-radius: 12px;
      background: color-mix(in srgb, var(--surface) 96%, transparent);
      border: 1px solid var(--accent2);
      box-shadow: 0 8px 26px rgba(0, 0, 0, .32);
      font-size: 13px; color: var(--text2); line-height: 1.45;
    }
    #wandBand .wb-text { flex: 1 1 16em; min-width: 0; }
    #wandBand .wb-text b { color: var(--text); font-weight: 650; }
    #wandBand .wb-haupt {
      border: 0; border-radius: 999px; cursor: pointer; font: inherit;
      font-weight: 600; padding: 9px 16px;
      background: var(--accent); color: var(--bg);
    }
    #wandBand .wb-weg-text { color: var(--text3); flex: 0 1 auto; }
    #wandBand .wb-zu {
      border: 0; background: transparent; color: var(--text3);
      cursor: pointer; font: inherit; padding: 6px 8px; line-height: 1;
    }
    #wandBand .wb-zu:hover { color: var(--text); }
    /* Wie bei der Vollbild-Pille: unter der Anmeldemaske hat es zu warten. */
    html.anmeldung-offen #wandBand { display: none; }

    /* ── Nachtmodus ─────────────────────────────────────────────────────────
       Zwei Ebenen, weil eine nicht reicht.

       (1) Die Token drehen die Flaeche: Hintergrund, Karten, Schrift, Akzent —
           das ist der weitaus groesste Teil des abgestrahlten Lichts. Statt
           Cyan (#06b6d4, fast im Empfindlichkeitsmaximum der Staebchen und
           damit das Schlechteste fuer die Dunkeladaption) steht hier Bernstein.

       (2) Der Filter ueber der ganzen Seite faengt, was die Token nicht
           erreichen: 62 fest kodierte Farben im Stylesheet und 141 in den
           Skripten — Graphenlinien, Balken, Statuspunkte. Kein reines Rot:
           gruen/gelb/rot muessen auf einem Alarmbildschirm unterscheidbar
           bleiben. Der Filter drueckt den Blauanteil und waermt alles an,
           statt die Bedeutung einzuebnen.

       Der Filter steht bewusst am WURZELELEMENT. Auf jedem anderen Element
       wuerde er einen Bezugsrahmen fuer fest positionierte Kinder aufspannen —
       Kopfzeile und Kiosk-Leiste wuerden mitscrollen. Fuer die Wurzel nimmt
       die Spezifikation das ausdruecklich aus. */
    html.nachtmodus {
      --bg:       #0b0704;
      --surface:  #18100a;
      --surface2: #24170e;
      --border:   #4f2a15;
      --text:     #ffcfa8;
      --text2:    #cf9463;
      --text3:    #96603c;
      --accent:   #ff9248;
      --accent2:  #c9591f;
      filter: brightness(.8) sepia(.55) saturate(1.6) hue-rotate(-16deg);
    }

    /* Graphen bekommen eine staerkere Dosis.
       Der Unterschied ist inhaltlich: In einem Graphen sagt die Farbe, WELCHE
       Linie das ist — Violett, Cyan, Blau sind Namen, keine Bedeutung. Bei
       gruen/gelb/rot sagt die Farbe, WIE ES STEHT, und dieser Unterschied darf
       nachts nicht verschwinden. Deshalb bleibt der Seitenfilter mild und die
       Leinwaende bekommen obendrauf, was die Skala kalt macht.
       Gemessen: der Seitenfilter allein senkt den Blauanteil der Seite von 61
       auf 11 (Blaukanal im Mittel ueber die ganze Seite) und laesst
       gruen/gelb/rot trotzdem unterscheidbar. */
    html.nachtmodus canvas { filter: sepia(.55) saturate(1.2); }

    /* ── Burger-Menü (nur Mobile) ── */
    /* Immer da. Vorher tauchte der Burger erst unter 900 px auf und die
       Kopfzeile trug daneben bis zu zehn einzelne Knoepfe. Jetzt gibt es genau
       ein Menue — auf jedem Bildschirm dasselbe. */
    .burger-wrap { position: relative; display: block; }
    /* Kante auf Kante mit der Kopfzeile. Vorher hing es am Knopf
       (top: 100% + 8px) — und weil der Knopf innerhalb der Kopfzeilenpolsterung
       sitzt, begann das Feld noch AUF der Kopfzeile und lag halb darüber.
       Jetzt haengt es an der gemessenen Kopfzeilenhoehe; liegt darunter das
       Kopie-Band, rutscht es mit (--header-h enthaelt es).
       Das eine Pixel obendrauf: sonst liegt der obere Rand des Feldes genau
       auf der Trennlinie der Kopfzeile, und beide verschmelzen zu einem
       dickeren Strich. */
    .burger-menu { position: fixed; top: calc(var(--header-h) + 1px); right: 2px; z-index: 200;
      background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
      padding: 6px; min-width: 160px; display: flex; flex-direction: column; gap: 2px;
      box-shadow: 0 8px 24px rgba(0,0,0,.4); }
    .burger-menu.hidden { display: none; }
    .burger-item { background: none; border: none; color: var(--text); cursor: pointer;
      padding: 9px 12px; border-radius: 8px; font-size: 14px; text-align: left;
      display: flex; align-items: center; gap: 10px; transition: background .12s; }
    .burger-item:hover { background: var(--surface2); }
    .burger-alarm-count { background: var(--red); color: #fff; border-radius: 999px;
      font-size: 10px; font-weight: 700; padding: 1px 6px; margin-left: 4px; }
    .burger-alarm-count.hidden { display: none; }
    /* Roter Punkt auf dem Burger-Button wenn Alarme aktiv */
    #burgerBtn.has-alarm::after { content: ''; position: absolute; top: 4px; right: 4px;
      width: 7px; height: 7px; background: var(--red); border-radius: 50%; border: 1.5px solid var(--surface); }
    #burgerBtn { position: relative; }
    /* Ab hier traegt das Burger-Menue die Werkzeugknoepfe.
       Die Schwelle lag bei 600 px — und genau darueber erschienen ALLE acht
       Icon-Knoepfe auf einmal. Am Geraet gemessen: .header-right springt damit
       von 213 auf 501 px, zusammen mit dem Logo passt das nicht in eine Zeile,
       und die Kopfzeile bricht auf 96 px um (bei 640 px Fensterbreite). Weil
       --header-h eine feste Zahl war, verschwanden dann 23 px der Statusleiste
       dahinter, und die Detailseiten begannen ebenfalls zu hoch.
       Erst ab rund 830 px passt die volle Knopfreihe neben Logo und Uhr. */
    @media (max-width: 900px) {
      .burger-hide { display: none !important; }
      .header-right { justify-content: flex-end; margin-left: auto; gap: 6px; }

    }
    /* ── Kiosk-Chrome (fester Display): linke Sidebar + Slide-down Topbar ──
       Im Kiosk-Modus werden Header (oben) und alte Bottom-Nav entfernt. */
    :root { --kiosk-side-w: 84px; --kiosk-handle-h: 22px; }
    .kiosk-nav { display: none; }                 /* alte Bottom-Nav: aus */

    .kiosk-mode header { display: none; }

    /* Linke Sidebar */
    .kiosk-sidebar { display: none; }
    .kiosk-mode .kiosk-sidebar {
      display: flex; flex-direction: column; gap: 6px;
      position: fixed; top: 0; left: 0; bottom: 0; width: var(--kiosk-side-w);
      background: var(--surface); border-right: 1px solid var(--border);
      padding: 12px 8px; z-index: 60;
    }
    .kiosk-side-btn {
      display: flex; flex-direction: column; align-items: center; gap: 6px;
      padding: 14px 4px; border: none; background: none; color: var(--text3);
      border-radius: 14px; cursor: pointer; font-size: 11px; font-weight: 600;
      transition: background .15s, color .15s; -webkit-tap-highlight-color: transparent;
    }
    .kiosk-side-btn:hover  { background: var(--surface2); color: var(--accent); }
    .kiosk-side-btn.active { background: var(--surface2); color: var(--accent); }
    .kiosk-side-btn.active svg { filter: drop-shadow(0 0 4px var(--accent)); }

    .kiosk-mode main {
      padding-left: calc(var(--kiosk-side-w) + var(--gap));
      padding-top: calc(var(--gap) + var(--kiosk-handle-h));
      padding-bottom: var(--gap);
    }
    .kiosk-mode .overlay { padding-left: var(--kiosk-side-w); padding-bottom: 0; }

    /* Slide-down Topbar */
    .kiosk-top { display: none; }
    .kiosk-mode .kiosk-top {
      display: block; position: fixed; top: 0; left: var(--kiosk-side-w); right: 0;
      z-index: 65; pointer-events: none;
    }
    .kiosk-top-panel {
      pointer-events: auto; background: var(--surface);
      border-bottom: 1px solid var(--border);
      border-bottom-left-radius: 18px; border-bottom-right-radius: 18px;
      padding: 16px 22px 18px; box-shadow: 0 10px 30px rgba(0,0,0,.4);
      transform: translateY(-100%); transition: transform .32s cubic-bezier(.4,0,.2,1);
    }
    .kiosk-top.open .kiosk-top-panel { transform: translateY(0); }
    .kiosk-top-handle {
      pointer-events: auto; position: absolute; top: 0; left: 50%;
      transform: translateX(-50%); width: 72px; height: var(--kiosk-handle-h);
      background: var(--surface); border: 1px solid var(--border); border-top: none;
      border-bottom-left-radius: 12px; border-bottom-right-radius: 12px;
      color: var(--text3); cursor: pointer; display: flex; align-items: center;
      justify-content: center; transition: color .15s;
    }
    .kiosk-top-handle:hover { color: var(--accent); }
    .kiosk-top-handle svg { transition: transform .32s; }
    .kiosk-top.open .kiosk-top-handle svg { transform: rotate(180deg); }

    .ktp-status { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
    .ktp-clock  { font-size: 28px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
    .ktp-batt   { display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 600; color: var(--text3); }
    .ktp-quick  { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; }
    .ktp-tile   { background: var(--surface2); border: 1px solid var(--border); border-radius: 14px;
      padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; min-height: 78px; justify-content: space-between; }
    .ktp-tile.disabled { opacity: .45; }
    .ktp-tile-lbl { font-size: 11px; color: var(--text3); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
    .ktp-toggle { border: 1px solid var(--border); background: var(--surface); color: var(--text2);
      border-radius: 10px; padding: 9px; font-size: 14px; font-weight: 700; cursor: pointer;
      font-family: inherit; transition: all .15s; }
    .ktp-toggle:hover:not(:disabled) { border-color: var(--accent2); }
    .ktp-toggle:disabled { cursor: not-allowed; }
    .ktp-toggle.on  { background: #22c55e22; border-color: #22c55e; color: #22c55e; }
    .ktp-range { width: 100%; accent-color: var(--accent2); cursor: pointer; }

    /* Mini-Toast */
    .mini-toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(20px);
      background: var(--surface); border: 1px solid var(--border); color: var(--text);
      padding: 10px 18px; border-radius: 10px; font-size: 13px; z-index: 9998;
      box-shadow: 0 8px 24px rgba(0,0,0,.4); opacity: 0; transition: opacity .2s, transform .2s; pointer-events: none; }
    .mini-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

    /* ── Kachel-Engine (Grid) ───────────────────────────────────────────────
       Eine Basis-Einheit: normale Kachel = Quadrat (Breite == Höhe).
       half = halbe Höhe · wide = doppelte Breite (gleiche Höhe).
       Spaltenzahl + Zeilenhöhe setzt JS (_applyGrid in display.js);
       grid-auto-flow:dense packt automatisch — keine Lücken oben. */
    main { display: grid; gap: var(--gap); padding: var(--gap);
      padding-top: calc(var(--header-h) + var(--gap));
      grid-template-columns: 1fr;          /* ab 640px von JS gesetzt */
      grid-auto-flow: row dense; }
    @media (min-width: 1024px) { main { max-width: 1240px; margin: 0 auto; } }
    @media (min-width: 1600px) { main { max-width: 1660px; } }

    /* Heizung: CSS beim Plugin (plugins/heizung/oberflaeche/heizung.css). */
    /* ── Stromverlauf (eigene Seite) ──────────────────────────────────────
       Nach Cerbo-Vorbild: Erzeugung als gestapelte Flaeche, Verbrauch als
       Linie darueber, darunter die Energiesummen des Fensters. */
    .vl-karte { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 16px 18px;
      max-width: 1500px; margin: 0 auto; }
    .vl-kopf  { display: flex; align-items: center; gap: 10px;
      flex-wrap: wrap; margin-bottom: 14px; }
    .vl-bereiche { display: flex; gap: 6px; flex-wrap: wrap; }
    .vl-btn   { font-family: inherit; font-size: 12px; font-weight: 600;
      padding: 6px 12px; border-radius: 9px; cursor: pointer;
      border: 1px solid var(--border); background: var(--surface2); color: var(--text2); }
    .vl-btn:hover { border-color: var(--accent2); }
    .vl-btn.an { border-color: var(--accent); color: var(--accent); }
    .vl-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    .vl-chart { width: 100%; height: 300px; display: block; }
    /* Wochentrend: fuellt die Kachel aus.
       Vorher stand er auf festen 210 px, waehrend die Kachel im Raster auf die
       Zeilenhoehe gestreckt wird — darunter blieb sichtbar Luft stehen. Jetzt
       waechst das Diagramm mit; 210 px bleiben die Untergrenze, damit die
       sieben Balkenpaare auch in einer flachen Zeile lesbar sind. */
    .vl-week-chart { width: 100%; height: 210px; min-height: 210px;
      flex: 1; display: block; }
    .vl-titel { font-size: 11px; font-weight: 700; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text3); }
    .vl-legende { display: flex; align-items: center; gap: 12px; margin-left: auto;
      font-size: 10px; color: var(--text3); flex-wrap: wrap; }
    .vl-legende i { display: inline-block; width: 8px; height: 8px; border-radius: 2px;
      margin-right: 5px; vertical-align: -1px; }
    /* Leerzustand: KEIN gezeichnetes Diagramm mit erfundener Achse. */
    .vl-leer { display: flex; align-items: center; justify-content: center;
      min-height: 120px; padding: 22px 16px; text-align: center;
      font-size: 13px; color: var(--text3); line-height: 1.6; }
    @media (max-width: 639px) { .vl-chart { height: 220px; } }
    .vl-summen { display: grid; gap: 10px 22px; margin-top: 14px;
      padding-top: 14px; border-top: 1px solid var(--border);
      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
    .vl-summe-zeile { display: flex; align-items: center; gap: 9px; font-size: 13px; min-width: 0; }
    .vl-punkt { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
    .vl-name  { color: var(--text2); overflow: hidden;
      text-overflow: ellipsis; white-space: nowrap; }
    .vl-wh    { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
    .vl-hinweis { font-size: 12px; color: var(--text3); margin-top: 10px; }

    /* ── Batterie: die Antwort zuerst ─────────────────────────────────────
       Die Seite beantwortete bisher nirgends die Frage, mit der man sie
       oeffnet: reicht der Strom? Der Shunt liefert dafuer kein ttg, aus
       Restenergie und Verbrauch laesst es sich aber rechnen. */
    .ba-antwort { display: grid; gap: 22px 28px; align-items: center;
      grid-template-columns: 200px minmax(0, 1fr); }
    @media (max-width: 700px) { .ba-antwort { grid-template-columns: 1fr; gap: 16px; } }
    .ba-ring     { width: 100%; max-width: 200px; height: auto; display: block; margin: 0 auto; }
    .ba-ring-num { font-size: 40px; font-weight: 700; font-family: inherit; }
    .ba-ring-lbl { font-size: 11px; font-weight: 600; fill: var(--text3); font-family: inherit; }
    .ba-kopf     { font-size: clamp(20px, 3.4vw, 27px); font-weight: 700;
      line-height: 1.2; letter-spacing: -.01em; text-wrap: balance; }
    .ba-kopf small { display: block; font-size: 13px; font-weight: 500;
      color: var(--text3); margin-top: 6px; letter-spacing: 0; }
    .ba-kette { display: flex; flex-wrap: wrap; gap: 6px 20px; margin-top: 14px;
      font-size: 13px; color: var(--text3); font-variant-numeric: tabular-nums; }
    .ba-kette b { color: var(--text2); font-weight: 600; }

    /* ── Batterie: gerichtete Bilanz ── */
    .ba-fluss { display: grid; gap: 18px; align-items: center;
      grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
    @media (max-width: 760px) { .ba-fluss { grid-template-columns: 1fr; gap: 14px; } }
    .ba-seite { display: flex; flex-direction: column; gap: 9px; min-width: 0; }
    .ba-zeile { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto;
      gap: 9px; align-items: center; font-size: 13px; }
    .ba-punkt { width: 9px; height: 9px; border-radius: 3px; }
    .ba-name  { color: var(--text2); overflow: hidden;
      text-overflow: ellipsis; white-space: nowrap; }
    .ba-watt  { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
    .ba-bahn  { grid-column: 2 / 4; height: 5px; border-radius: 3px;
      background: var(--surface2); overflow: hidden; margin-top: -3px; }
    .ba-bahn div { height: 100%; border-radius: 3px; transition: width .4s ease; }
    .ba-mitte { display: flex; flex-direction: column; align-items: center;
      gap: 3px; padding: 0 8px; white-space: nowrap; }
    .ba-mitte b { font-size: 25px; font-weight: 700; line-height: 1;
      font-variant-numeric: tabular-nums; }
    .ba-mitte span { font-size: 10px; font-weight: 700; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text3); }
    .ba-pfeil { color: var(--text3); font-size: 17px; line-height: 1; }
    @media (max-width: 760px) { .ba-pfeil { transform: rotate(90deg); } }

    /* ── Batterie: Zellen als Abweichung vom Mittel ───────────────────────
       Absolute 3.335 gegen 3.340 sagt beim Draufschauen nichts. Die
       Abweichung zeigt sofort, welche Zelle ausreisst. */
    .ba-zellen { display: flex; flex-direction: column; gap: 8px; }
    /* Fuenf Spalten: Nummer, Spannung, Abweichungsbahn, Millivolt, Temperatur.
       Die Temperaturspalte traegt die zweite Farbe der Karte und wird nur
       gefuellt, wenn ueberhaupt eine Zelle eine Temperatur meldet — das
       Element bleibt aber erhalten, sonst verrutscht das Raster der Zeile. */
    .ba-zeile-z { display: grid;
      grid-template-columns: 24px 62px minmax(0, 1fr) 58px auto;
      gap: 9px; align-items: center; font-size: 12px; }
    .ba-znr   { color: var(--text3); font-weight: 700; }
    /* Absolute Zellspannung — ersetzt die frueher nur mobil gezeigte Kachel. */
    .ba-zv    { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
    .ba-zv small { color: var(--text3); font-weight: 600; font-size: 10px; }
    .ba-bahn-z{ position: relative; height: 16px; background: var(--surface2); border-radius: 4px; }
    .ba-null  { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--border); }
    .ba-bar-z { position: absolute; top: 3px; bottom: 3px; border-radius: 2px; transition: all .4s ease; }
    /* Ueber der Skala: der Balken ist geklemmt. Ohne Markierung wuerde eine
       Zelle mit 200 mV Abweichung genauso aussehen wie eine mit 76 mV. */
    .ba-bar-ueber { border-radius: 2px 0 0 2px;
      background-image: linear-gradient(135deg, rgba(255,255,255,.45) 25%, transparent 25%,
        transparent 50%, rgba(255,255,255,.45) 50%, rgba(255,255,255,.45) 75%, transparent 75%);
      background-size: 6px 6px; }
    .ba-mv    { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
    .ba-zt    { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums;
      min-width: 30px; font-size: 11px; }
    @media (max-width: 420px) {
      /* Auf sehr schmalen Geraeten hat die Bahn sonst weniger Platz als die
         Zahlen daneben — dann lieber die Bahn schmaler als die Werte kuerzen. */
      .ba-zeile-z { grid-template-columns: 20px 54px minmax(0, 1fr) 48px auto;
        gap: 6px; font-size: 11px; }
      .ba-zt { min-width: 26px; font-size: 10px; }
    }

    /* ── Batterie-Detail: Servicebatterie als EINE Karte ───────────────────
       Vorher war die Bank auf zwei Kacheln zerlegt (Shunt-Werte hier,
       BMS-Werte dort) und die BMS-Zellen standen neben der Starterbatterie,
       mit der sie nichts zu tun haben. Shunt und BMS sind zwei Messquellen
       DERSELBEN Batterie und gehoeren deshalb zusammen.
       Die Energieringe zeigen die Quellen als wachsende Kreise um den SOC. */
    .sb-card { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 20px; margin-bottom: var(--gap); }
    .sb-hd { display: flex; align-items: center; gap: 8px; margin-bottom: 16px;
      font-size: 12px; font-weight: 700; letter-spacing: .07em;
      text-transform: uppercase; color: var(--text2); }
    .sb-hd .chip { margin-left: auto; }
    /* Die Kopfzeile setzt Grossbuchstaben — in den Chips stehen aber Einheiten,
       und aus "19 mV" wurde damit "19 MV", also Megavolt. */
    .sb-hd .chip { text-transform: none; letter-spacing: .02em; }
    /* Nur der ERSTE Chip wird nach rechts geschoben — die folgenden reihen sich
       daneben ein, statt auseinandergerissen zu werden. */
    .sb-hd .chip ~ .chip { margin-left: 0; }
    .sb-grid { display: grid; gap: 24px; align-items: center;
      grid-template-columns: 230px 190px minmax(0, 1fr); }
    @media (max-width: 1050px) { .sb-grid { grid-template-columns: 230px minmax(0, 1fr); } }
    @media (max-width: 700px)  { .sb-grid { grid-template-columns: 1fr; } }


    /* Kennzahlen — Spalten breit genug, dass kein Label abgeschnitten wird */
    .sb-stats { display: grid; gap: 16px 18px;
      grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }
    .st   { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
    .st-l { font-size: 10px; font-weight: 700; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text3);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .st-v { font-size: 20px; font-weight: 700; line-height: 1.15;
      font-variant-numeric: tabular-nums; white-space: nowrap; }
    .st-v small { font-size: 11px; font-weight: 600; color: var(--text2); margin-left: 3px; }

    /* Zellen gehoeren zur Servicebatterie und stehen deshalb IN deren Karte */
    .sb-cells    { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
    .sb-cells-hd { display: flex; align-items: center; gap: 10px; margin-bottom: 10px;
      font-size: 10px; font-weight: 700; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text3); }
    /* 62px: bei 320px Geraetebreite bleiben nach Kartenpolster und Luecken
       rund 68px je Spalte — mit 74px waere die vierte Zelle allein in eine
       zweite Reihe gerutscht. */
    .cellrow { display: grid; gap: 8px;
      grid-template-columns: repeat(auto-fit, minmax(62px, 1fr)); }
    .cell    { background: var(--surface2); border-radius: 9px; padding: 8px 6px; text-align: center; }
    .cell-nr { font-size: 10px; font-weight: 700; color: var(--text3); }
    .cell-v  { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
    .cell-t  { font-size: 10px; color: var(--text3); font-variant-numeric: tabular-nums; }
    .cell.lo .cell-v { color: var(--yellow); }   /* niedrigste Zelle */
    .cell.hi .cell-v { color: var(--accent); }   /* hoechste Zelle */
    .chip    { font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 6px;
      background: var(--surface2); color: var(--text3); white-space: nowrap; }
    .chip.on   { background: #22c55e1a; color: var(--green); }
    .chip.warn { background: #eab3081a; color: var(--yellow); }
    .chip.err  { background: #ef44441a; color: var(--red); }

    /* Starterbatterie: eigene, bewusst kleinere Karte — hat mit der Bank nichts zu tun */
    .starter { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 20px; margin-bottom: var(--gap);
      display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }

    /* Widerspruch zwischen eingestellter Bankkapazitaet und BMS-Restenergie.
       Bewusst auffaellig: die Autonomie-Aussage darueber haengt daran. */
    .ba-streit { display: flex; align-items: flex-start; gap: 8px; margin-top: 12px;
      padding: 9px 12px; border-radius: 8px; font-size: 12px; line-height: 1.5;
      color: var(--yellow); background: rgba(234,179,8,.10);
      border: 1px solid rgba(234,179,8,.35); }
    .ba-streit svg { flex-shrink: 0; margin-top: 2px; }
    .ba-streit b { color: var(--text); }

    /* Geraete-Kacheln unter dem Verlauf: gleich hoch, kein Treppeneffekt */
    .bd-flow { display: grid; gap: var(--gap); margin-bottom: var(--gap);
      grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); align-items: stretch; }
    .bd-src  { background: var(--surface); border: 1px solid var(--border);
      border-left: 3px solid var(--border); border-radius: var(--radius);
      padding: 16px; display: flex; flex-direction: column; gap: 10px; min-width: 0;
      /* Die Kacheln fuellen die Rasterzeile. Ohne space-between klebt alles
         oben und unten bleibt ein Streifen Luft — die Kachel sieht dann aus,
         als waere sie zu gross geraten, statt bewusst so hoch zu sein. */
      justify-content: space-between; }
    .bd-src-ok { border-left-color: var(--green); }
    .bd-src-warn { border-left-color: var(--yellow); }
    .bd-src-err { border-left-color: var(--red); }
    .bd-src-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
    .bd-src-name { font-size: 11px; font-weight: 700; letter-spacing: .06em;
      text-transform: uppercase; color: var(--text2); min-width: 0;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .bd-src-head .chip { margin-left: auto; }
    .bd-src-main { display: flex; align-items: baseline; gap: 4px;
      font-variant-numeric: tabular-nums; }
    .bd-src-main b { font-size: 26px; font-weight: 700; line-height: 1; }
    .bd-src-main span { font-size: 12px; font-weight: 600; color: var(--text2); }
    .bd-src-sub { font-size: 12px; color: var(--text3); margin-top: auto;
      font-variant-numeric: tabular-nums;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Die drei Sollwerte des Laders, nebeneinander mit dem, was er zurueckmeldet.
       Drei Spalten und keine Tabelle: es sind immer genau drei Zeilen, und die
       Zahlen sollen untereinander stehen (tabular-nums), damit ein Unterschied
       an der Stelle auffaellt und nicht erst beim Lesen. */
    /* „Gelernt: … · Verwerfen" — eine Zeile ueber den Spannungen. */
    .ld-kennlinie { display: flex; align-items: center; gap: 10px;
      margin-top: 8px; flex-wrap: wrap; }
    .ld-kenn-text { font-size: 12px; color: var(--text3); flex: 1; min-width: 0; }

    .ld-spannungen { margin-top: 10px; border-top: 1px solid var(--border);
      padding-top: 8px; display: flex; flex-direction: column; gap: 3px; }
    .ld-sp-zeile { display: grid; grid-template-columns: 1fr auto auto;
      gap: 10px; align-items: baseline; font-size: 12px; }
    .ld-sp-kopf { color: var(--text3); font-size: 10px; letter-spacing: .06em;
      text-transform: uppercase; }
    .ld-sp-kopf .ld-sp-name { text-transform: none; letter-spacing: 0;
      font-size: 12px; color: var(--text2); font-weight: 600; }
    .ld-sp-name { color: var(--text3); }
    .ld-sp-wert { color: var(--text2); font-variant-numeric: tabular-nums;
      min-width: 62px; text-align: right; }
    /* Weicht das Geraet vom Sollwert ab, ist genau das die Auskunft. */
    .ld-sp-wert.ab { color: var(--yellow); font-weight: 600; }
    .ld-sp-wert i { font-style: normal; color: var(--text3); font-size: 11px; }
    .ld-sp-kopf .ld-sp-name i { font-style: normal; font-weight: 400; color: var(--text3);
      font-size: 11px; margin-left: 4px; }
    /* Die Zeile „jetzt": nimmt beide Wertspalten, Phase · Spannung · Strom. */
    .ld-sp-jetzt { grid-template-columns: 1fr auto; margin-top: 2px; }
    .ld-sp-live { color: var(--text2); font-variant-numeric: tabular-nums; text-align: right; }
    .ld-sp-live i { font-style: normal; color: var(--text3); font-size: 11px; }
    /* ── Gemeinsamer Start ────────────────────────────────────────────────
       Die Kacheln haengen an verschiedenen Quellen (/api/status, waterlevel,
       weather, wartung, Heizung) mit sehr verschiedenen Antwortzeiten. Ohne
       diese Sperre baut sich die Seite beim Neuladen stueckweise auf. Mit
       opacity statt display bleibt das Layout gerechnet — Canvas-Breiten
       stimmen also von Anfang an, was bei display:none nicht der Fall waere. */
    /* Waehrend des Starts liegt die Oberflaeche unscharf darunter. Das bleibt
       so — es gefaellt (Eignerwort: „fand das verwischte aber sehr chick") und
       zeigt, dass gleich etwas da ist, ohne dass man halbfertige Zahlen
       ablesen kann.
       Was RAUS ist, ist das Weganimieren. Einen Weichzeichner ueber die ganze
       Seite Bild fuer Bild aufzuloesen ist die teuerste Bewegung, die diese
       Oberflaeche kennt: gemessen bei vierfacher Drosselung 45 ms im
       schlimmsten Bild, also drei ausgelassene. Genau das war das Ruckeln beim
       Uebergang („er springt einen kleinen Moment zur Seite"). Ein STEHENDER
       Weichzeichner wird einmal gerechnet und kostet danach nichts.
       Beim Freigeben faellt er in einem Schritt weg, waehrend der Schirm noch
       davorliegt — bewegt wird nur dessen Deckkraft, und das ist billig. */
    html.startet main,
    html.startet .statusbar {
      /* Kraeftiger als die frueheren 7 px (Eignerwunsch): dahinter sollen
         keine Formen mehr zu erkennen sein, die man fuer eine Aussage halten
         koennte. Er steht STILL und wird deshalb nur einmal gerechnet — die
         Staerke kostet nichts, das Weganimieren haette gekostet. */
      filter: blur(14px);
      opacity: .35;
      pointer-events: none;
      user-select: none;
    }

    .ladeschirm {
      position: fixed; inset: 0; z-index: 250;
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: 16px; pointer-events: none;
      /* Halbdeckend, damit die unscharfe Oberflaeche darunter zu sehen ist.
         Etwas kraeftiger als frueher (45 %): die Kacheln packen sich beim Start
         zweimal um, waehrend ihre Quellen eintreffen (gemessen: bei 165 und
         216 ms wandert die Wechselrichterkachel von x=90 nach 500 und wieder
         zurueck). Bei 45 % war dieses Umspringen zu sehen; bei 82 % ahnt man
         nur noch Flaechen — der Weichzeichner bleibt sichtbar, das Ruecken
         nicht. */
      background: color-mix(in srgb, var(--bg) 82%, transparent);
      transition: opacity .3s ease;
    }
    /* Sobald der Start freigegeben ist, ist die Klasse weg — dann auch der
       Schirm. Kein eigener Zeitgeber: er haengt an derselben Entscheidung wie
       die Kacheln, sonst laufen beide auseinander. */
    html:not(.startet) .ladeschirm { opacity: 0; visibility: hidden; }
    /* Steht die Anmeldung an, hat sie Vorrang — zwei uebereinanderliegende
       Schirme waeren nur verwirrend. */
    html.anmeldung-offen .ladeschirm { display: none; }

    /* Die Marke, gross und atmend. Sie erbt ihre Form von `.marke-mave`
       (Maske ueber das Zeichen), hier bekommt sie nur Groesse und Farbe. */
    .lade-marke {
      font-size: 34px; color: var(--accent);
      animation: lade-atmen 2.2s ease-in-out infinite;
    }
    @keyframes lade-atmen { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

    /* Ein Strich, der hin und her laeuft. Kein Fortschrittsbalken: wir wissen
       nicht, wie weit es ist — er sagt nur, dass gearbeitet wird. */
    .lade-balken {
      width: 128px; height: 3px; border-radius: 2px; overflow: hidden;
      background: color-mix(in srgb, var(--accent) 14%, transparent);
    }
    .lade-balken i {
      display: block; width: 40%; height: 100%; border-radius: 2px;
      background: var(--accent);
      animation: lade-lauf 1.5s ease-in-out infinite;
    }
    @keyframes lade-lauf {
      0%   { transform: translateX(-100%); }
      100% { transform: translateX(250%); }
    }
    @media (prefers-reduced-motion: reduce) {
      /* Wer Bewegung abbestellt hat, bekommt Ruhe: die Marke bleibt stehen,
         der Strich pulsiert nur. */
      .lade-marke { animation: none; opacity: .9; }
      .lade-balken i { width: 100%; animation: lade-puls 1.6s ease-in-out infinite; }
      @keyframes lade-puls { 50% { opacity: .3; } }
    }
    .lade-text {
      font-size: 11px; font-weight: 600; letter-spacing: .05em;
      color: var(--text3); text-align: center; max-width: 260px; line-height: 1.4;
    }
    .lade-text[hidden] { display: none; }

    /* ── Kacheln anordnen ─────────────────────────────────────────────────
       Eigener Modus statt dauerhaftem Ziehen: am Kartentisch haengt ein
       Touchscreen, und ein versehentlich verschobenes Dashboard waere
       aergerlicher als ein Klick mehr zum Einschalten. */
    .ordnen-leiste { position: fixed; left: 50%; transform: translateX(-50%);
      bottom: calc(14px + env(safe-area-inset-bottom, 0px)); z-index: 300;
      display: flex; align-items: center; gap: 12px;
      background: var(--surface); border: 1px solid var(--accent);
      border-radius: 999px; padding: 9px 10px 9px 18px;
      box-shadow: 0 6px 24px rgba(0,0,0,.45); }
    .ordnen-leiste.hidden { display: none; }
    .ordnen-text { font-size: 13px; color: var(--text2); white-space: nowrap; }
    .ordnen-btn { background: var(--surface2); border: 1px solid var(--border);
      color: var(--text); border-radius: 999px; padding: 7px 14px;
      font-size: 13px; font-family: inherit; cursor: pointer; white-space: nowrap; }
    .ordnen-btn:hover { background: var(--border); }
    .ordnen-fertig { background: var(--accent); border-color: var(--accent); color: #06202b; font-weight: 600; }
    @media (max-width: 420px) {
      .ordnen-text { display: none; }
      .ordnen-leiste { padding: 9px 10px; }
    }
    /* Im Ordnen-Modus: Kachel als greifbar markieren, Auswahl unterdruecken. */
    /* Beim Anordnen bekommt jede Kachel ein Werkzeug statt einer Ziehgeste.
       Gezogen wurde bis zum 08.09.2026; das ist raus (Eignerwunsch). Ziehen
       auf einem Touchscreen an Bord ist eine Geste, die man treffen muss, und
       sie stritt mit dem Scrollen. Vier Knoepfe trifft man auch bei Seegang. */
    body.kacheln-ordnen main > .card {
      /* Ohne dieses `relative` haengt das Werkzeug am naechsten positionierten
         Vorfahren — also irgendwo auf der Seite, nicht auf der Kachel. */
      position: relative;
      outline: 1px dashed var(--accent); outline-offset: -3px;
      user-select: none; -webkit-user-select: none; }
    /* Abgeschaltete Kacheln stehen beim Anordnen mit da, sonst kaeme man an sie
       nie wieder heran — aber nur als EINE ZEILE (Eignerwunsch): der Name, der
       Schalter, die Pfeile. Mehr braucht es nicht, um sie an ihren Platz zu
       stellen und wieder anzuschalten, und in voller Hoehe verstellten sie das
       Bild von dem, was wirklich zu sehen sein wird.
       `align-self: start` ist dabei das Entscheidende: ohne das zieht das
       Raster die Kachel auf die volle Zeilenhoehe, und aus der einen Zeile
       wuerde wieder ein Kasten. */
    body.kacheln-ordnen main > .card.tile-aus {
      align-self: start;
      /* EINE Zeile: Name links, Werkzeug rechts, nebeneinander statt
         uebereinander. Die Karte ist sonst eine Spalte (flex column); im
         Ausgeschalteten wird sie zur Zeile, und das Werkzeug steht dann IM
         Fluss statt darueber — nur so ueberdeckt es den Namen nicht. */
      flex-direction: row; align-items: center; justify-content: space-between;
      min-height: 52px; padding: 8px 10px 8px 14px; gap: 10px;
      opacity: .5; outline-style: dotted;
    }
    body.kacheln-ordnen main > .card.tile-aus .kachel-werkzeug {
      position: static; box-shadow: none; background: none; border: none;
      padding: 0; flex: none;
    }
    /* Alles weg AUSSER Titel und Werkzeug.
       Nicht ueber `.tile-content`: den Halter haben nur drei der acht Kacheln
       (Batterie, Licht, Heizung) — die anderen haengen ihren Inhalt direkt in
       die Karte. Ein Ausschluss trifft alle, eine Aufzaehlung nur die, an die
       man gerade denkt. `:not()` und nicht `display:none` mit Rueckausnahme:
       so behalten die beiden ihre eigene Anzeigeart. */
    body.kacheln-ordnen main > .card.tile-aus > *:not(.card-title):not(.kachel-werkzeug) {
      display: none !important; }
    body.kacheln-ordnen main > .card.tile-aus .card-title { margin: 0; }
    /* Der Name soll lesbar bleiben, auch wenn die Kachel zurueckgenommen ist —
       er ist ja das Einzige, woran man sie erkennt. */
    body.kacheln-ordnen main > .card.tile-aus .card-title,
    body.kacheln-ordnen main > .card.tile-aus .kachel-werkzeug { opacity: 1; }
    /* Im Ausgeschalteten stoert die Detailseiten-Verknuepfung nur. */
    body.kacheln-ordnen main > .card.tile-aus .card-link { display: none; }

    /* Das Werkzeug schwebt oben rechts IN der Kachel — dort, wo bei keiner
       Kachel ein Messwert steht. Ueber allem, was die Kachel selbst zeichnet. */
    /* „Details →" hilft beim Anordnen nicht und braucht den Platz, den der
       Kachelname braucht. */
    body.kacheln-ordnen main > .card .card-link { display: none; }
    /* Damit der Name nicht unter das schwebende Werkzeug laeuft. */
    body.kacheln-ordnen main > .card > .card-title { padding-right: 200px; }
    body.kacheln-ordnen main > .card.tile-aus > .card-title { padding-right: 0; }
    /* Der NAME der Kachel darf nicht schrumpfen — er ist das Einzige, woran
       man sie erkennt. Beim Wasserstand stand sonst „WASSE" da, waehrend der
       Ortsname daneben in voller Laenge blieb. Was zu viel ist, wird hinten
       abgeschnitten, und hinten steht das Entbehrliche. */
    body.kacheln-ordnen main > .card > .card-title > * { flex-shrink: 0; }
    body.kacheln-ordnen main > .card.tile-aus > .card-title {
      /* Auch die dreigeteilte Kopfzeile (Wasserstand, Wetter) wird hier zur
         einfachen Zeile. Sie ist sonst ein GRID mit `minmax(0,1fr)` aussen —
         darin greift kein `flex-shrink`, und die Gattung wurde zu „WASSE"
         gequetscht, waehrend der Ortsname daneben in voller Laenge stand. */
      display: flex; gap: 8px;
      flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; }

    .kachel-werkzeug {
      position: absolute; top: 6px; right: 6px; z-index: 40;
      display: flex; align-items: center; gap: 4px;
      padding: 4px 5px; border-radius: 10px;
      background: color-mix(in srgb, var(--surface2) 92%, transparent);
      border: 1px solid var(--border);
      box-shadow: 0 4px 14px rgba(0,0,0,.45);
    }
    .kw-name {
      font-size: 10px; font-weight: 700; letter-spacing: .06em;
      text-transform: uppercase; color: var(--text3);
      padding: 0 4px 0 2px;
    }
    /* Das Wort zur Groesse faellt weg, wenn es eng wird: der Name der Kachel
       ist wichtiger als die Wiederholung dessen, was man ohnehin sieht.
       Gemessen bei drei Spalten (380 px Kachel) lief „BELEUCHTUNG" sonst unter
       das Werkzeug. */
    @media (max-width: 1400px) { .kw-name { display: none; } }
    .kw-knopf {
      display: inline-flex; align-items: center; justify-content: center;
      /* 34 px: Fingermass. Kleiner trifft man auf einem schwankenden Boot nicht. */
      width: 34px; height: 34px; padding: 0;
      border: 1px solid var(--border); border-radius: 8px;
      background: var(--surface); color: var(--text); cursor: pointer;
    }
    .kw-knopf:disabled { opacity: .3; cursor: default; }
    /* Das Feld fuer an/aus. Es traegt sein Wort selbst, statt sich auf ein
       Sinnbild zu verlassen: „An" und „Aus" sind zwei Zustaende, und ein Auge
       mit Strich sagt nicht, welcher gerade gilt. */
    .kw-schalter {
      min-width: 46px; height: 34px; padding: 0 10px;
      border: 1px solid var(--border); border-radius: 8px;
      background: var(--surface); color: var(--text3);
      font-size: 12px; font-weight: 700; letter-spacing: .04em; cursor: pointer;
    }
    .kw-schalter.an { background: var(--accent); border-color: var(--accent);
      color: #062c33; }
    .kw-knopf:not(:disabled):active { background: var(--accent); color: #fff;
      border-color: var(--accent); }

    /* ── Statusleiste ─────────────────────────────────────────────────────
       Alle Kernwerte in einer dichten Zeile ueber den Kacheln. Jedes Feld
       fuehrt per Tap in die zugehoerige Detailansicht. Steht bewusst
       AUSSERHALB des Kachel-Grids: main setzt grid-auto-rows per JS auf
       Kachelhoehe, das wuerde die Leiste sonst auf Kachelgroesse aufblasen. */
    /* Die Statusleiste bleibt beim Scrollen stehen. Sie sitzt dafuer in einem
       eigenen Halter statt selbst sticky zu sein: die Leiste ist abgerundet
       und seitlich eingerueckt, der durchlaufende Inhalt waere sonst an den
       Ecken und neben ihr zu sehen. Der Halter traegt den Seitenhintergrund
       und die Abstaende, die vorher an der Leiste hingen. */
    .statusbar-halter {
      position: sticky; top: var(--header-h); z-index: 60;
      padding: var(--gap) var(--gap);
      background: var(--bg);
      transition: padding .18s ease;
    }
    /* Traegt den Abstand zur festen Kopfzeile und dient zugleich als Fuehler:
       sobald er unter die Kopfzeile rutscht, schaltet die Leiste auf kompakt
       (siehe _leisteKompaktFuehren in core.js). Ein eigenes Element statt
       margin am Halter, weil ein Beobachter etwas braucht, das NICHT
       mitwandert. */
    .statusbar-fuehler { height: var(--header-h); }
    /* Hat kein einziges Feld eine Quelle, nimmt der Server die ganze Leiste
       weg. Dann muss auch ihr Halter gehen — sonst bliebe sein Abstand als
       leerer Streifen unter der Kopfzeile stehen. Der Fuehler bleibt: an ihm
       haengt der Abstand zur festen Kopfzeile, ohne ihn rutscht der Inhalt
       darunter. */
    .statusbar-halter:has(> .statusbar[hidden]) { display: none; }
    .statusbar {
      margin: 0;
      /* Feste Spaltenzahl statt auto-fit: auto-fit hat zwischen 641 und
         ~690 px genau FUENF Spalten gebildet, das sechste Feld stand dann
         allein in einer zweiten Zeile neben vier leeren Zellen. */
      /* --sb-n ist die Zahl der Felder, die an diesem Boot eine Quelle
         haben; der Server setzt sie als Stilangabe an die Leiste (siehe
         bosun/konfig/oberflaeche.py). Feste sechs Spalten liessen fuer jedes
         weggenommene Feld eine leere Zelle stehen — und weil der Spalt
         zwischen den Zellen die Randfarbe durchscheinen laesst, waere das ein
         grauer Block neben der Leiste gewesen, kein leerer Platz. */
      display: grid;
      grid-template-columns: repeat(var(--sb-n, 6), minmax(0, 1fr));
      gap: 1px;                                  /* 1px Spalt = Haarlinie */
      background: var(--border);                 /* scheint durch den Spalt */
      border: 1px solid var(--border);
      border-radius: var(--radius); overflow: hidden;
      /* Seiten und Oberkante gehen MIT der Bewegung weg, nicht auf einen
         Schlag am Ende. Auf ganze Pixel gerundet, weil eine halbe Randlinie
         als hellerer Streifen erscheint. */
      border-top-width:   round(calc(1px * (1 - var(--leiste-eng))), 1px);
      border-left-width:  round(calc(1px * (1 - var(--leiste-eng))), 1px);
      border-right-width: round(calc(1px * (1 - var(--leiste-eng))), 1px);
    }
    main { padding-top: 0;     /* Kopf- und Leistenabstand traegt der Halter */
      /* Beim Umschalten auf die kompakte Leiste wird der Streifen um rund
         35 px flacher. Ohne diese Zeile verankert der Browser die Ansicht an
         einer Kachel und korrigiert dafuer den Scrollstand — dadurch rutscht
         der Fuehler wieder ins Bild, die Leiste klappt auf, der Scrollstand
         wird erneut korrigiert, und das Ganze flackert genau an der Schwelle.
         Nur hier abgeschaltet, nicht global: an anderer Stelle ist die
         Verankerung nuetzlich. */
      overflow-anchor: none; }

    /* ── Die Leiste dockt beim Scrollen an die Kopfzeile ──────────────────
       Sie schrumpft dabei nicht auf einen Schlag, sondern haengt am
       Scrollstand: --leiste-eng laeuft von 0 (oben, volle Leiste) bis 1
       (angedockt, flacher Streifen), und alle Groessen werden daraus
       gerechnet. Dadurch wird die Leiste von der obersten Kachel nach oben
       geschoben, statt an einer Schwelle umzuklappen.

       --leiste-eng ist ueber @property als Zahl angemeldet; nur dann laesst
       sich eine eigene Eigenschaft ueberhaupt animieren und weitervererben. */
    @property --leiste-eng {
      syntax: '<number>'; inherits: true; initial-value: 0;
    }
    @keyframes leiste-andocken { to { --leiste-eng: 1; } }

    /* Der bevorzugte Weg: die Animation laeuft am Scrollstand des Dokuments
       entlang, nicht an einem scroll-Handler. Sie ist genau ueber die Strecke
       gespannt, die die Leiste bis zum Andocken zuruecklegt. */
    @supports (animation-timeline: scroll()) {
      body {
        animation: leiste-andocken linear both;
        animation-timeline: scroll(root block);
        animation-range: 0 var(--header-h);
      }
    }
    /* Rueckfall fuer Browser ohne scroll-gesteuerte Animation (aeltere
       Chromium-Fassungen, Safari): dort schaltet der Beobachter aus core.js
       die Klasse, und der Uebergang laeuft ueber eine Transition. */
    @supports not (animation-timeline: scroll()) {
      body { transition: --leiste-eng .2s linear; }
      body.leiste-kompakt { --leiste-eng: 1; }
    }
    @media (prefers-reduced-motion: reduce) {
      body { transition: none; }
    }

    /* Alle Groessen aus dem Fortschritt gerechnet. */
    .statusbar-halter { padding: calc(var(--gap) * (1 - var(--leiste-eng))); }
    .statusbar        { border-radius: calc(var(--radius) * (1 - var(--leiste-eng))); }
    /* Groessen und Abstaende sind unten bei den Grunddefinitionen aus dem
       Fortschritt gerechnet — dort, wo sie je Bildbreite ohnehin stehen.
       Hier oben stuenden sie VOR ihnen und waeren wirkungslos. */

    /* Spaltenzahl und Randlinien lassen sich nicht stufenlos rechnen — die
       schaltet weiterhin der Beobachter, und zwar erst am Ende der Bewegung,
       wenn die Felder ohnehin schon flach sind. */
    /* Frueher schaltete hier die Klasse .leiste-kompakt Schriftgroessen,
       Randlinien und Breite auf einen Schlag um. Am Ende der Bewegung sprang
       die Leiste dadurch um 9 px flacher und 72 px breiter, und weil die
       Klasse an einem Beobachter haengt, kam der Sprung beim schnellen
       Scrollen auch noch verspaetet. Alles, was sich rechnen laesst, haengt
       jetzt am Fortschritt --leiste-eng und laeuft mit dem Finger mit. */


    .sb-item {
      background: var(--surface); border: 0; margin: 0;
      /* Halten heisst hier "Detailseite oeffnen". Ohne diese beiden Zeilen
         faengt der Browser waehrenddessen an, Text zu markieren, und auf dem
         Telefon springt zusaetzlich das Auswahlmenue auf — man haelt den Finger
         drauf und bekommt blaue Bloecke statt einer Seite. */
      user-select: none; -webkit-user-select: none;
      -webkit-touch-callout: none;
      /* Aus dem Andock-Fortschritt gerechnet (--leiste-eng, siehe oben):
         beim Scrollen wird das Feld flacher, statt an einer Schwelle
         umzuklappen. */
      padding: calc(10px - 5px * var(--leiste-eng))
               calc(12px - 4px * var(--leiste-eng))
               calc(11px - 5px * var(--leiste-eng));
      /* Auf GANZE Pixel gerundet: bei gebrochenen Werten faellt die
         Reihenhoehe zwischen zwei Pixel, und der 1-px-Spalt zwischen den
         Reihen rastert mal als ein, mal als zwei Pixel — die mittlere
         Trennlinie wurde dabei sichtbar dicker und wieder duenner. Die Zeile
         darueber bleibt als Rueckfall fuer Browser ohne round() stehen.

         Nur noch am Telefon (weiter unten): dort stehen zwei Reihen
         uebereinander, und der Spalt dazwischen ist die Trennlinie, um die es
         geht. In der breiten Ansicht gibt es nur EINE Reihe und damit keine
         mittlere Linie — dort wird ungerundet gerechnet, sonst kippen fuenf
         gerundete Groessen gleichzeitig und die Leiste ruckt in 5-px-Stufen
         durch die Bewegung, statt zu gleiten. */
      min-width: 0;
      display: flex; flex-direction: column;
      gap: calc(2px * (1 - var(--leiste-eng)));
      font-family: inherit; color: inherit; text-align: left;
      cursor: pointer; transition: background .15s;
      position: relative; overflow: hidden;   /* traegt den Hintergrundgraphen */
      /* Beim Andocken aendern sich Polster und Schriftgroessen dieses Feldes
         in jedem Bild. `contain` sagt dem Browser, dass davon nichts nach
         aussen wirkt — er muss dann nicht das ganze Dokument nachrechnen.
         Gemessen (vierfach gedrosselt, Schwung von unten nach oben): das
         Andocken kostete p95 24 ms je Bild gegenueber 17 ms ohne. */
      contain: layout style;
    }
    /* Verlauf der letzten 24 Stunden als Hintergrund. Er liegt hinter dem
       Text, nimmt keine Klicks an und faerbt sich mit dem Zustand des Feldes
       (siehe .sb-ok/.sb-low/.sb-warn weiter unten) — die Flaeche wird nach
       unten hin durchsichtig, damit die Zeile darunter lesbar bleibt. */
    .sb-spark {
      /* Volle Feldhoehe, damit der Hoechstwert der Skala (bei Prozentwerten
         100 %) wirklich an der OBERKANTE des Feldes liegt und die Hoehe der
         Flaeche sich ablesen laesst. */
      position: absolute; inset: 0;
      pointer-events: none; z-index: 0;
      color: var(--text3);                    /* Vorgabe, bis ein Zustand greift */
    }
    .sb-spark svg { display: block; width: 100%; height: 100%; }
    /* Waagerechter Balken: fuellt das Feld von links nach rechts. Anders als
       der Verlauf zeigt er keinen Weg, sondern den Stand — deshalb eine
       gleichmaessige Flaeche mit klarer Kante statt eines Verlaufs. */
    /* Ein Streifen fuers Halten stand hier. Er ist weg (Eignerwunsch): bei
       einer Drittelsekunde ist er ohnehin kaum zu sehen, und ein Balken, der
       bei jedem Tippen kurz aufblitzt, ist mehr Unruhe als Auskunft. */
    .sb-item[data-detail] { cursor: pointer; }

    .sb-balken {
      position: absolute; inset: 0 auto 0 0; width: 0;
      /* Ohne eigene Tankfarbe: der Zustandsfarbton, dezent im Hintergrund.
         MIT Farbverlauf (siehe _sbRenderTank) setzt JS ein eigenes Bild und
         hebt die Deckkraft an — ein Verlauf bei 18 % waere keiner. */
      /* Deckkraft in den FARBEN und nicht am Element.
         Am Element multiplizierte sie sich mit der Kante darin — und die soll
         ja gerade KRAEFTIGER sein als die Flaeche, was ueber eine gemeinsame
         Deckkraft nicht geht. */
      --balken-alpha: 18%;
      --kante-alpha: 34%;
      opacity: 1;
      background: color-mix(in srgb, currentColor var(--balken-alpha), transparent);
      /* Die Kante sitzt IM Balken, als Innenschatten an seiner rechten Seite.
         Vorher war sie ein eigenes Element mit eigener Position — und das
         musste jemand mit der Balkenbreite gleichhalten. Beim Andocken der
         Leiste aendert sich die Feldbreite in jedem Bild; der Balken folgte
         sofort, die Kante hing hinterher. Als Teil des Balkens kann sie das
         nicht mehr. */
      box-shadow: inset -1px 0 0 color-mix(in srgb, currentColor var(--kante-alpha), transparent);
      pointer-events: none; z-index: 0;
      color: var(--text3);
      transition: width .5s ease;
    }
    /* Wasser ist blau — Zahl und Balken. Nur im normalen Zustand: faellt der
       Stand unter die Schwellen, gewinnen weiter Gelb und Rot, sonst ginge
       genau die Warnung verloren, fuer die die Farben da sind. */
    .sb-item.sb-wasser.sb-ok .sb-val b,
    .sb-item.sb-wasser.sb-ok .sb-balken { color: var(--accent); }

    .sb-item.sb-ok   .sb-balken { color: var(--green); }
    .sb-item.sb-low  .sb-balken { color: var(--yellow); }
    .sb-item.sb-warn .sb-balken { color: var(--red); }
    .sb-item.sb-idle .sb-balken { color: var(--text3); }
    /* Der Inhalt gehoert ueber den Graphen. */
    .sb-lbl, .sb-val, .sb-sub { position: relative; z-index: 1; }
    /* NUR mit einem echten Zeiger, nicht beim Anfassen — und die Frage, was
       gerade benutzt wird, beantwortet `_zeigerartMerken()` in display.js am
       tatsaechlichen Eingabegeraet, nicht die Medienabfrage.

       Denn `:hover` bleibt auf Beruehrgeraeten am zuletzt angetippten Feld
       haengen, bis man woanders hintippt: das Feld leuchtete noch, als die
       Detailseite schon darueber lag. `@media (hover: hover)` fing das nicht
       ab — iPadOS meldet dort `hover: hover`, obwohl kein Zeiger da ist, und
       Tablets mit Stift oder angesteckter Tastatur ebenso.

       Darunter zeichnet der Browser zusaetzlich eine eigene Hervorhebung auf
       das angetippte Element (`-webkit-tap-highlight-color`). Die steht
       ausserhalb dieser Regeln und wird deshalb getrennt abgeschaltet. */
    html[data-zeiger="fein"] .sb-item:hover { background: var(--surface2); }
    /* Und beim Antippen kurz aufleuchten. Das ist NICHT dasselbe wie Hover:
       es kommt mit dem Finger und geht mit ihm wieder. `:active` taugt dafuer
       nicht — auf iOS greift es nur, wenn am Element selbst ein Beruehr-
       Horcher haengt, und hier horcht die Leiste stellvertretend fuer alle
       Felder. Deshalb eine Klasse, gesetzt vom Zeigerereignis. */
    .sb-item.sb-tipp { background: var(--surface2); transition: background .04s; }

    .sb-item, .card[onclick], .ch-bar-wrap, button {
      -webkit-tap-highlight-color: transparent;
    }
    .sb-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
    /* Zeilenhoehen bewusst in ganzen Pixeln: mit "normal" ist die Zeile
       gebrochen hoch, damit auch die Reihe — und der 1-px-Spalt zwischen den
       beiden Reihen liegt dann zwischen zwei Bildpunkten und wirkt mal
       dicker, mal duenner. */
    /* Zeilenhoehe und Buchstabenabstand liefen frueher mit. Sie sind der
       teuerste Teil am Text — jede Aenderung setzt die Zeile neu — und der am
       wenigsten sichtbare. Die Schriftgroesse traegt den Effekt allein. */
    .sb-lbl { font-size: calc(10px - 1px * var(--leiste-eng));
      line-height: 12px;
      font-weight: 700; letter-spacing: .07em;
      text-transform: uppercase; color: var(--text3);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .sb-val { display: flex; align-items: baseline; gap: 3px;
      line-height: 20px;
      color: var(--text); font-variant-numeric: tabular-nums; }
    .sb-val b { font-size: calc(21px - 6px * var(--leiste-eng)); font-weight: 700; }
    .sb-val i { font-size: calc(11px - 2px * var(--leiste-eng)); font-style: normal;
      font-weight: 600; color: var(--text2); }
    /* Die Unterzeile geht als Erste: bei 40 % des Weges ist sie schon
       unsichtbar, damit sie nicht bis zuletzt gequetscht mitlaeuft. */
    .sb-sub { font-size: 11px; line-height: 13px; color: var(--text3);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      max-height: calc(15px * (1 - var(--leiste-eng)));
      opacity: calc(1 - 2.5 * var(--leiste-eng)); }
    /* Zustandsfarben: nur der Zahlenwert faerbt sich, nie die ganze Flaeche */
    .sb-item.sb-ok   .sb-val b { color: var(--green); }
    .sb-item.sb-low  .sb-val b { color: var(--yellow); }
    .sb-item.sb-warn .sb-val b { color: var(--red); }
    .sb-item.sb-idle .sb-val b { color: var(--text2); }
    /* Der Graph traegt dieselbe Zustandsfarbe wie die Zahl darueber. */
    .sb-item.sb-ok   .sb-spark { color: var(--green); }
    .sb-item.sb-low  .sb-spark { color: var(--yellow); }
    .sb-item.sb-warn .sb-spark { color: var(--red); }
    .sb-item.sb-idle .sb-spark { color: var(--text3); }
    .sb-item.sb-stale .sb-val b,
    .sb-item.sb-stale .sb-sub { opacity: .45; }  /* Wert veraltet, Sensor stumm */
    /* Ruhiger im Hintergrund, je flacher die Leiste wird: auf 40 px Hoehe
       arbeitet die volle Deckkraft gegen die kleine Schrift. */
    .sb-spark  { opacity: calc(.9 - .25 * var(--leiste-eng)); }
    /* Ueber die Farbanteile und nicht ueber die Deckkraft des Elements —
       sonst waere die Kante darin gleich mit erledigt. Beide werden im selben
       Verhaeltnis leiser. */
    .sb-balken { --balken-alpha: calc(18% - 5% * var(--leiste-eng));
                 --kante-alpha:  calc(34% - 9% * var(--leiste-eng)); }

    /* Bis 700 px zwei Zeilen a drei Feldern — darunter reicht die Breite fuer
       sechs nebeneinander nicht, ohne dass die Unterzeilen abschneiden.
       Genau deshalb sind es SECHS Felder: bei fuenf haette die zweite Zeile
       eine Luecke. */
    @media (max-width: 700px) {
      .statusbar { grid-template-columns: repeat(var(--sb-n-eng, 3), minmax(0, 1fr)); }

      /* Und sie BLEIBEN zwei Zeilen, auch angedockt. Aus zwei Zeilen zu je
         drei Feldern eine Zeile mit sechs zu machen war verwirrend: die
         Felder wechselten mitten in der Bewegung den Platz, und drei davon
         landeten woanders. Ohne Umbruch ist der ganze Weg stufenlos.
         Muss NACH der 6-Spalten-Regel weiter oben stehen — gleiche
         Spezifitaet, es entscheidet die Reihenfolge. */
      body.leiste-kompakt .statusbar { grid-template-columns: repeat(var(--sb-n-eng, 3), minmax(0, 1fr)); }

      /* Die Kopfzeile hat sich hier zeitweise nach oben aus dem Bild
         geschoben, um Platz fuer die zweite Reihe zu machen. Auf Wunsch des
         Eigners wieder raus: ohne sie wirkte die Seite fremd, und Menue und
         Alarmglocke waren nicht mehr erreichbar.

         Angedockt dafuer so flach wie moeglich — und der Weg dorthin ist auch
         hier gerechnet statt geschaltet, damit die Schrift mitlaeuft, statt in
         einem Schritt zu springen. Zeilenhoehen bleiben ganzzahlig. */
      .sb-lbl   { letter-spacing: .06em; line-height: 12px; }
      .sb-val   { line-height: 20px; }
      .sb-sub   { max-height: round(calc(15px * (1 - var(--leiste-eng))), 1px); }
      .sb-item  { gap: round(calc(2px * (1 - var(--leiste-eng))), 1px); }
    }
    @media (max-width: 640px) {
      .sb-item { padding: calc(9px - 4px * var(--leiste-eng))
                          calc(10px - 5px * var(--leiste-eng))
                          calc(10px - 4px * var(--leiste-eng));
                 padding: round(calc(9px - 4px * var(--leiste-eng)), 1px)
                          round(calc(10px - 5px * var(--leiste-eng)), 1px)
                          round(calc(10px - 4px * var(--leiste-eng)), 1px); }
      .sb-val b { font-size: 18px; }
    }
    /* Sehr schmal (bis 380 px): dichter setzen. Sonst schnitt die Unterzeile
       der Batterie ("13.38 V . -12.7 A") in der 320-px-Spalte ab. */
    @media (max-width: 380px) {
      .sb-item { padding: calc(8px - 3px * var(--leiste-eng))
                          calc(8px - 4px * var(--leiste-eng))
                          calc(9px - 3px * var(--leiste-eng));
                 padding: round(calc(8px - 3px * var(--leiste-eng)), 1px)
                          round(calc(8px - 4px * var(--leiste-eng)), 1px)
                          round(calc(9px - 3px * var(--leiste-eng)), 1px); }
      .sb-lbl  { font-size: 9px; letter-spacing: .05em; }
      .sb-val b { font-size: 17px; }
      .sb-val i { font-size: 10px; }
      .sb-sub  { font-size: 10px; }
    }
    /* Breite Schirme: Leiste exakt so breit wie das Kachelraster darunter */
    @media (min-width: 1024px) {
      /* Angedockt geht die Leiste ueber die volle Breite wie die Kopfzeile,
         sonst zeigten die Luecken links und rechts sie als eigenen Streifen.
         Der Weg dorthin ist gerechnet, nicht geschaltet; max(0px, …) haelt die
         Leiste in schmalen Fenstern davon ab, schmaler zu werden statt breiter. */
      .statusbar { --sb-breit: calc(1240px - 2 * var(--gap));
        max-width: calc(var(--sb-breit) + max(0px, 100vw - var(--sb-breit)) * var(--leiste-eng));
        margin-left: auto; margin-right: auto; }
    }
    @media (min-width: 1600px) {
      .statusbar { --sb-breit: calc(1660px - 2 * var(--gap)); }
    }
    /* Kiosk: kein Header, dafuer Sidebar links — Leiste zieht mit */
    .kiosk-mode .statusbar {
      margin-top: calc(var(--gap) + var(--kiosk-handle-h));
      margin-left: calc(var(--kiosk-side-w) + var(--gap));
    }
    .kiosk-mode main { padding-top: var(--gap); }

    /* Innenaufbau: Titel immer oben, Inhalt füllt den Rest der Kachel.
       Bei wide wird .tile-content zur Zeile: links normal, rechts Extra. */
    .tile-content { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 14px; }
    .tile-main { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 14px; }
    /* min-height:0 laesst .tile-main unter seine Inhaltshoehe schrumpfen —
       noetig, weil es sonst ueber die Kachel hinauswaechst (gemessen 426 px
       Inhalt in einer 392 px hohen Kachel) und die Fusszeile hinausschiebt.
       NUR im mehrspaltigen Raster: dort haben die Kacheln eine feste
       Zeilenhoehe. Einspaltig sind sie inhaltsgross, und dieselbe Regel liesse
       sie auf null zusammenfallen. */
    body.raster-mehrspaltig .tile-main { min-height: 0; }
    /* Bei schmalen Spalten sind die Kacheln flach (die Zeilenhoehe haengt an
       der Spaltenbreite). Dort kosten 14 px zwischen fuenf Bloecken 56 px —
       ein Viertel der Kachel. */
    @media (min-width: 601px) and (max-width: 860px) {
    }
    .tile-wide-side { display: none; }
    .tile--wide .tile-content { flex-direction: row; align-items: stretch; gap: 22px; }
    .tile--wide .tile-main { flex: 1 1 0; }
    .tile--wide .tile-wide-side { display: flex; flex: 1 1 0; min-width: 0; flex-direction: column;
      gap: 10px; justify-content: center; border-left: 1px solid var(--surface2); padding-left: 22px; }
    /* Halbe Kacheln: wenig Inhalt -> vertikal zentrieren */
    .tile--half .tile-main { justify-content: center; }

    /* ── Signal K in den Einstellungen ───────────────────────────────────── */
    .sk-zeile { display: flex; align-items: flex-start; gap: 10px; padding: 7px 0;
      font-size: 14px; cursor: pointer; }
    .sk-zeile input { margin-top: 2px; flex-shrink: 0; }
    .sk-zeile .hinweis { display: block; margin-top: 2px; }
    .sk-adressen { display: flex; flex-direction: column; gap: 8px; }
    .sk-adr { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
    .sk-adr-n { flex: 0 0 90px; font-size: 11px; font-weight: 700;
      letter-spacing: .08em; text-transform: uppercase; color: var(--text3); }
    /* Die Adresse ist zum Abtippen da — sie muss ganz dastehen und darf
       umbrechen, statt am Rand abgeschnitten zu werden. */
    .sk-adr-v { font-size: 13px; color: var(--text); background: var(--surface2);
      border: 1px solid var(--border); border-radius: 6px; padding: 3px 7px;
      word-break: break-all; user-select: all; }

    /* Ein Geraet, an dem noch nichts eingetragen ist, hat keine Kachel. */
    .nichts-eingerichtet { margin: 0; padding: 48px var(--gap);
      text-align: center; color: var(--text3); font-size: 14px; }

    /* Größen-Sichtbarkeit */
    .tile-hidden { display: none !important; }   /* schlägt inline display aus Daten-Updates */
    /* Kachel ist eingeschaltet, hat aber keine Daten (Tanks/Batterie).
       _applyGrid() rechnet sie aus dem Raster heraus, statt sie wieder
       aufzureißen. */
    .tile-nodata { display: none !important; }
    .tile-show-half, .tile-show-wide { display: none; }
    .tile--half .tile-show-half { display: block; }
    .tile--wide .tile-show-wide { display: block; }
    .tile--half .tile-hide-half { display: none !important; }

    /* ── Batterie ─────────────────────────────────────────────────────────── */
    /* Gauge nimmt den vertikalen Slack (zentriert), Wert-Zellen bleiben flach
       (TODO #5: wenig Leerraum über/unter der Zahl). */
    .card-battery .gauge-wrap { flex: 1; justify-content: center; margin: 0; min-height: 132px; }
    .card-battery .gauge-svg  { width: 184px; height: 129px; }
    .card-battery .batt-grid .batt-item { padding: 7px 10px; }
    .card-battery .batt-sub { margin-top: 2px; }
    /* half: kompakte Schlüsselwerte (SOC · Spannung · Strom · Restkap.) */
    .tile--half.card-battery .gauge-wrap,
    .tile--half.card-battery .batt-grid,
    .tile--half.card-battery .batt-sub,
    .tile--half.card-battery .src-row { display: none; }
    /* Das Modus-Etikett in der Kopfzeile ist nur noch fuer die HALBE Kachel
       da: dort gibt es keinen Ring, in dem der Modus stehen koennte. Ueberall
       sonst stuende er zweimal. */
    .card-battery #chgModeBadge { display: none !important; }
    .tile--half.card-battery #chgModeBadge { display: inline !important; }

    .batt-half { display: none; }
    .tile--half.card-battery .batt-half { display: flex; align-items: center; gap: 26px; flex-wrap: wrap; }
    .batt-half-soc  { font-size: 46px; font-weight: 800; line-height: 1; }
    .batt-half-stat { font-size: 11px; color: var(--text3); text-transform: uppercase; letter-spacing: .05em; }
    .batt-half-stat b { display: block; color: var(--text); font-size: 19px; font-weight: 700; margin-top: 3px; text-transform: none; }
    /* wide: rechts SOC-Verlauf (Graph) + Kennzahlen */
    .tile--wide.card-battery .tile-wide-side { justify-content: flex-start; gap: 12px; }
    .batt-wide-hd { font-size: 11px; font-weight: 700; text-transform: uppercase;
      letter-spacing: .08em; color: var(--text3); margin: 0; }
    .batt-wide-chart { flex: 1; width: 100%; min-height: 80px; display: block; }
    .batt-wide-foot { display: flex; justify-content: space-between; gap: 16px; }
    .batt-wide-stat { display: flex; flex-direction: column; gap: 2px; }
    .batt-wide-stat b { font-size: 20px; font-weight: 700; color: var(--text); }
    .batt-wide-lbl { font-size: 11px; color: var(--text3); text-transform: uppercase; letter-spacing: .04em; }

    /* ── Tanks ────────────────────────────────────────────────────────────── */
    .tile--half.card-tanks .tank-bar-wrap { min-height: 0; }
    .tile--half.card-tanks .tank-pct-below { display: none; }
    .tile--half.card-tanks .tank-name      { font-size: 11px; margin: 0; }

    /* ── Beleuchtung ──────────────────────────────────────────────────────── */
    .tile--half.card-lights .channels-block,
    .tile--half.card-lights .divider { display: none; }
    /* Kanal-Balken füllen den oberen Bereich, Preset-Buttons bleiben normal groß */
    .card-lights .channels-block { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
    .card-lights .channels-row { flex: 1; min-height: 36px; }
    .card-lights .presets-grid { flex: 0 0 auto; }
    .preset-btn { justify-content: center; }
    /* half: kompakte Buttons, die in die halbe Höhe passen (nicht abschneiden) */
    .tile--half.card-lights .presets-grid { gap: 6px; min-height: 0; grid-auto-rows: minmax(0, 1fr); }
    .tile--half.card-lights .preset-btn { padding: 6px; gap: 3px; min-height: 0; overflow: hidden; }
    .tile--half.card-lights .preset-emoji { font-size: 18px; }
    .tile--half.card-lights .preset-name  { font-size: 10px; }
    /* wide: rechte Spalte = Zonen-Slider, füllt das Panel */
    .lights-wide { display: flex; flex-direction: column; height: 100%; gap: 10px; }
    .lights-wide-hd { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--text3); }
    .lights-wide-sliders { display: flex; justify-content: space-around; align-items: stretch;
      flex: 1; min-height: 0; gap: 6px; }
    .lights-slider-item { display: flex; flex-direction: column; align-items: center; gap: 8px; flex: 1; min-width: 0; }
    .lights-vslider { writing-mode: vertical-lr; direction: rtl; width: 30px; flex: 1; min-height: 90px;
      cursor: pointer; accent-color: var(--accent2); }
    .lights-relay-btn { width: 44px; height: 44px; border-radius: 10px; border: 1.5px solid var(--border);
      background: var(--surface2); color: var(--text2); cursor: pointer; font-size: 18px; transition: background .15s; }
    .lights-relay-btn.active { background: var(--green); color: #fff; border-color: var(--green); }
    .lights-slider-lbl { font-size: 10px; color: var(--text3); font-weight: 600; text-align: center;
      line-height: 1.1; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    /* ── 230V ─────────────────────────────────────────────────────────────── */
    /* Inhalt gleichmäßig verteilen statt großer Lücken; 2×2-Grid füllt unten. */
    #inverterCard:not(.tile--half) { justify-content: space-between; }
    #inverterCard .gauge-svg { width: 168px; height: 118px; }
    #inverterCard #invIndicatorRow { display: none !important; } /* Status steht im Grid */
    #inverterCard .batt-grid { gap: 8px; }
    .tile--half#inverterCard .gauge-wrap,
    .tile--half#inverterCard .batt-grid { display: none; }
    /* ── 230-V-Kachel: Punkte und Schalter ────────────────────────────────
       Stand bis zum 16.09.2026 im Wartungs-Plugin. Beim Aufteilen von
       style.css am 13.09. ist es dorthin gerutscht, und solange alle Plugins
       geladen wurden, fiel es nicht auf. Auf einem Geraet ohne das
       Wartungs-Plugin war der Inverter-Schalter danach blanker Text —
       „Inverter Aus Inverter An" in einer Zeile — und die Punkte auf der
       Batteriekachel waren weg. Beides gehoert dem Kern: `.shore-dot` steht
       auch am BMS-Relais und an der Zellgesundheit. */
/* Inverter-Button-Gruppe */
.shore-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); flex-shrink: 0; }
.shore-dot.on { background: var(--green); box-shadow: 0 0 4px var(--green); }

.inv-btn { flex: 1; padding: 10px; border-radius: 10px; font-size: 14px; font-weight: 700;
  cursor: pointer; border: 1px solid var(--border); background: var(--surface2); color: var(--text2);
  transition: all .15s; }
.inv-btn:hover { background: var(--surface); }
.inv-btn.active-on  { background: #22c55e22; border-color: #22c55e; color: #22c55e; }
.inv-btn.active-eco { background: #eab30822; border-color: #eab308; color: #eab308; }
.inv-btn.active-off { background: #ef444422; border-color: #ef4444; color: #ef4444; }

.inv-pill { position: relative; display: flex; align-items: center;
  height: 42px; border-radius: 21px; border: 1.5px solid var(--border);
  background: var(--surface2); cursor: pointer; user-select: none;
  overflow: hidden; transition: border-color .25s; }
.inv-pill.on { border-color: var(--green); }
.inv-pill-thumb { position: absolute; top: 3px; left: 3px;
  width: calc(50% - 3px); height: calc(100% - 6px);
  border-radius: 18px; background: var(--border);
  transition: transform .28s cubic-bezier(.4,0,.2,1), background .25s;
  z-index: 0; }
.inv-pill.on .inv-pill-thumb { transform: translateX(calc(100% + 0px)); background: var(--green); }
.inv-pill-label { position: relative; z-index: 1; flex: 1; text-align: center;
  font-size: 12px; font-weight: 700; color: var(--text3);
  transition: color .25s; pointer-events: none; }
.inv-pill.on  .inv-pill-label.right { color: var(--text); }
.inv-pill:not(.on) .inv-pill-label.left  { color: var(--text); }

    .inv-half-summary { padding: 4px 0; }
    .tile--half#inverterCard .inv-half-summary { flex: 1; display: flex; align-items: center; }
    .inv-half-pct     { font-size: 32px; font-weight: 700; color: var(--text); }
    .inv-half-sep     { color: var(--text3); margin: 0 4px; }

    /* Wartung: CSS beim Plugin. */
    /* ── Cards ── */
    /* KEIN Fokusrahmen an der Kachel. Er war der Versuch, ein abgeschnittenes
       Rechteck zu retten — aber eine Kachel ist kein Bedienelement, und der
       Rahmen brachte nichts ausser dem Problem: er wurde oben von der
       klebenden Statusleiste ueberdeckt, egal wo man ihn hinlegte. Knoepfe und
       Felder INNERHALB der Kachel haben weiterhin ihren eigenen, und dort
       gehoert er auch hin.
       Das scroll-margin bleibt: eine angesprungene Kachel soll unter der
       Leiste landen und nicht dahinter. */
    .card { scroll-margin-top: calc(var(--header-h) + 62px);
      background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 20px;
      display: flex; flex-direction: column; gap: 16px; overflow: hidden; }
    /* Zwei Fehler auf einmal: der Ring lag aussen (siehe oben), UND
       `var(--red)33` ist kein gueltiger Farbwert — so haengt man keine
       Deckkraft an eine Variable. Der Browser hat die ganze Zeile verworfen,
       der Alarmring war also nie zu sehen. */
    /* Ein Ring, zwei Farben.
       Erst lagen beide auf box-shadow — dieselbe Eigenschaft, also gewann die
       spaetere Regel und der Alarm verschwand beim Anfassen. Dann lag der rote
       Ring vier Pixel weiter innen: sichtbar blieben beide, aber der blaue war
       vom roten fast verdeckt, und zwei ineinandergeschachtelte Ringe sahen
       nach Fehler aus.
       Jetzt teilen sie sich GENAU dieselbe Flaeche — Rahmen und ein Pixel
       Ring nach innen. Beim Anfassen wechselt nur die Farbe von Rot auf Blau,
       und wenn der Finger weg ist, ist der Alarm wieder da. Nichts springt,
       nichts wird breiter.
       Beim Kacheln-Ordnen gewinnt die gestrichelte Greifkante — das ist ein
       gewollter Ausnahmezustand und dauert, solange man ordnet. */
    .card--alarm {
      border-color: var(--red) !important;
      box-shadow: inset 0 0 0 1px var(--red);
      transition: border-color .3s, box-shadow .3s;
    }
    /* Der Alarm tritt beim Anfassen hinter die Hervorhebung zurueck — er ist
       eine halbe Sekunde spaeter wieder da, und in dieser halben Sekunde
       schaut jemand ohnehin genau auf diese Kachel. */
    html[data-zeiger="fein"] .card--alarm[onclick]:hover {
      border-color: var(--accent2) !important;
      box-shadow: inset 0 0 0 1px var(--accent2);
    }
    /* Auch hier stand `var(--red)55` — kein gueltiger Farbwert, so haengt man
       keine Deckkraft an eine Variable. Der Browser hat die Zeile verworfen,
       den Ring gab es nie. */
    .tank-bar-wrap--alarm { border-color: var(--red) !important;
      box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--red) 55%, transparent); }

    /* Kacheln, auf denen gewischt wird (Wetter, Pegel): senkrecht soll die
       Seite weiter scrollen, waagerecht behandeln wir selbst. */

    /* Wetter, Wasserstand: CSS bei den Plugins. */
    /* ── Einstellungen: Wetterorte ── */
    .set-card-zahl { font-size: 12px; color: var(--text3); font-weight: 600; }
    .set-ort { display: flex; align-items: center; gap: 6px;
      padding: 8px 0; border-bottom: 1px solid var(--border); }
    .set-ort:last-child { border-bottom: 0; }
    .set-ort-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 600;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .set-ort-koord { font-size: 12px; color: var(--text3); font-weight: 400;
      margin-left: 6px; font-variant-numeric: tabular-nums; }
    .set-ort-btn { background: var(--surface2); border: 1px solid var(--border);
      color: var(--text2); border-radius: 8px; width: 30px; height: 30px; flex: none;
      display: inline-flex; align-items: center; justify-content: center;
      cursor: pointer; -webkit-tap-highlight-color: transparent; }
    .set-ort-btn:disabled { opacity: .3; cursor: default; }
    html[data-zeiger="fein"] .set-ort-btn:not(:disabled):hover { color: var(--text); border-color: var(--accent); }
    html[data-zeiger="fein"] .set-ort-weg:not(:disabled):hover { color: var(--red); border-color: var(--red); }
    .set-ort-leer { font-size: 13px; color: var(--text3); padding: 6px 0; line-height: 1.5; }
    .set-suche { position: relative; margin-top: 10px; }
    /* .settings-input ist auf die schmalen Zahlenfelder der uebrigen
       Bereiche eingestellt. Ein Ortsname braucht die ganze Zeile. */
    .set-suche .settings-input, #sWetterModell { width: 100%; max-width: none; }
    .set-treffer { margin-top: 6px; border: 1px solid var(--border);
      border-radius: 10px; overflow: hidden; background: var(--surface2); }
    .set-treffer-zeile { display: block; width: 100%; text-align: left;
      background: none; border: 0; border-bottom: 1px solid var(--border);
      color: var(--text); font: inherit; font-size: 13px; padding: 8px 10px;
      cursor: pointer; -webkit-tap-highlight-color: transparent; }
    .set-treffer-zeile:last-child { border-bottom: 0; }
    .set-treffer-zeile span { color: var(--text3); font-size: 12px; }
    html[data-zeiger="fein"] .set-treffer-zeile:hover { background: var(--surface); }

    /* Wartungsplan: CSS beim Plugin (plugins/wartung/oberflaeche/wartung.css).
       Die Kachel-Kopfzeile mit Ortsnamen (card-title-ort, ct-ort, ort-punkte)
       ist Kern: mehrere Plugins (Wetter, Pegel) teilen sie sich. */
    .card-title { display: flex; align-items: center; gap: 8px; font-size: 11px;
      font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--text3); }
    .card-title svg { flex-shrink: 0; }
    .card-link { margin-left: auto; font-size: 10px; color: var(--text3); font-weight: 400;
      letter-spacing: .04em; text-transform: none; }

    /* Kopfzeile mit Ortsnamen: drei Spalten, damit der Name WIRKLICH in der
       Mitte steht und nicht dort, wo die linke Seite gerade aufhoert. Die
       aeusseren Spalten sind gleich breit; was nicht passt, wird abgekuerzt.

       Vorher sass der Ort rechts oben — an der Stelle, an der auf jeder
       anderen Kachel „Details" steht. Zwei Kacheln hatten damit kein Details
       mehr, und man musste raten, dass sie eine Seite haben. */
    /* minmax(0, 1fr) und nicht 1fr: eine 1fr-Spalte darf nicht unter ihren
       Inhalt schrumpfen, also wuchs sie bei „WASSERSTAND" ueber ihr Drittel
       hinaus und schob die Mitte nach rechts. Mit der Null als Untergrenze
       sind die aeusseren Spalten wirklich gleich breit; wird es eng, kuerzt
       die Gattung links ab — das Sinnbild daneben sagt ohnehin, welche
       Kachel das ist. */
    .card-title-ort { display: grid; align-items: center;
      grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
    /* Enger als in der normalen Kopfzeile: bei zwei Spalten (Fenster um die
       700 px) fehlten der Gattung sonst drei Pixel, und sie endete mit einem
       Auslassungszeichen. Die sechs Pixel hier und am Ortsnamen reichen. */
    .card-title-ort .ct-links { display: inline-flex; align-items: center;
      gap: 6px; min-width: 0; overflow: hidden; text-overflow: ellipsis;
      white-space: nowrap; }
    .card-title-ort .card-link { margin-left: 0; justify-self: end;
      white-space: nowrap; }
    /* Der Ort ist ein Name und kein Bedienelement mit Rahmen. Dass es weitere
       gibt, sagen die Punkte unten auf der Kachel — dafuer braucht es hier
       weder Kasten noch Pfeil. Antippbar bleibt er. */
    .ct-ort { justify-self: center; background: none; border: 0; padding: 0 4px;
      font: inherit; text-transform: none; letter-spacing: .02em;
      font-size: 12px; font-weight: 600; color: var(--text2);
      cursor: pointer; max-width: 100%; overflow: hidden;
      text-overflow: ellipsis; white-space: nowrap;
      -webkit-tap-highlight-color: transparent; }
    html[data-zeiger="fein"] .ct-ort:hover { color: var(--text); }

    /* Die Punkte unten: dieselbe Sprache wie beim Blaettern am Telefon —
       wie viele Orte gepflegt sind und auf welchem man gerade steht. Sie
       ersetzen den Pfeil am Namen: ein Pfeil sagt „hier geht es weiter", die
       Punkte sagen zusaetzlich, wie weit. */
    .ort-punkte { display: flex; justify-content: center; gap: 6px;
      padding-top: 1px; flex: none; }
    .ort-punkte i { width: 5px; height: 5px; border-radius: 50%;
      background: var(--text3); opacity: .3;
      transition: opacity .2s, background .2s; }
    .ort-punkte i.an { background: var(--accent); opacity: .95; }

    /* ── Battery card — clickable ── */
    .card-battery {
      cursor: pointer; transition: border-color .2s, box-shadow .2s;
      -webkit-tap-highlight-color: transparent; user-select: none;
    }
    /* Ring nach INNEN. Aussen liegt er ausserhalb der Kachel und wird vom
       Nachbarn ueberdeckt — in der obersten Reihe vom Halter der Statusleiste,
       der direkt darueber sitzt. Deshalb sah er dort schmaler aus als
       ringsherum, und nur dort. Innen kann ihm das nicht passieren. */
    /* Hover NUR mit echtem Zeiger — siehe `_zeigerartMerken` in display.js.
       Auf dem Touchscreen bleibt `:hover` am zuletzt Angetippten haengen, bis
       man woanders hintippt. Die Lichtkachel und der Wasserstand hatten es
       sogar als Inline-Handler (`onmouseenter` setzt `style.borderColor`,
       `onmouseleave` raeumt auf) — und `mouseleave` kommt auf einem
       Touchgeraet oft gar nicht. Der Rahmen blieb dann dauerhaft hell
       (Eignermeldung 08.09.2026: „immer die Lichtkachel gehighlightet").
       Ein Inline-Stil ist dabei das Schlimmere von beidem: den raeumt auch
       kein Browser von selbst wieder ab. */
    html[data-zeiger="fein"] .card-battery:hover { border-color: var(--accent2); box-shadow: inset 0 0 0 1px var(--accent2); }



    /* ── SOC Gauge ── */
    .gauge-wrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }
    .gauge-svg { width: 160px; height: 112px; overflow: visible; }
    .gauge-track { fill: none; stroke: var(--border); stroke-width: 10; stroke-linecap: round; }
    .gauge-value { fill: none; stroke-width: 10; stroke-linecap: round;
      transition: stroke-dasharray .7s ease, stroke .5s; }
    .gauge-center { text-anchor: middle; dominant-baseline: middle; }
    .gauge-pct   { font-size: 28px; font-weight: 700; fill: var(--text); }
    .gauge-label { font-size: 11px; fill: var(--text3); letter-spacing: .08em; }
    /* Der Lademodus im Ring — zurueckhaltend (Eignerwunsch).
       Erst stand er kraeftiger da als das „SOC", das er ersetzt hat: groesser,
       fetter, heller. Das war zu viel fuer eine Zeile, die man im
       Vorbeigehen mitnimmt und nicht liest. Jetzt liegt er auf demselben Ton
       wie die Beschriftung davor — die Prozentzahl darueber hat den Blick, er
       beantwortet nur die Rueckfrage. */
    .gauge-modus { font-size: 11px; font-weight: 500; fill: var(--text3);
      letter-spacing: .04em; }

    .batt-unit-switch { cursor:pointer; margin-left:4px; display:inline-flex; align-items:center; gap:1px; }
    .batt-unit-sw { font-size:9px; font-weight:700; padding:1px 4px; border-radius:3px;
      color:var(--text3); text-transform:none; letter-spacing:0; transition:all .15s; }
    .batt-unit-sw.active { color:var(--text); background:var(--surface2); }

    /* ── Battery grid ── */
    .batt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .batt-center-btn {
      position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
      height: 26px; padding: 0 10px; border-radius: 13px;
      background: var(--accent); border: none;
      color: var(--bg); font-size: 10px; font-weight: 700;
      cursor: pointer; z-index: 2; white-space: nowrap;
      display: flex; align-items: center; gap: 4px;
      box-shadow: 0 0 0 3px var(--surface), 0 2px 6px rgba(0,0,0,0.4);
      transition: filter .1s;
    }
    .batt-center-btn:active  { filter: brightness(.85); }
    .batt-center-btn span    { pointer-events: none; }
    .btu-sep  { opacity: .35; margin: 0 2px; font-weight: 400; }
    .btu-active { opacity: 1; }
    .batt-center-btn span:not(.btu-active):not(.btu-sep) { opacity: .35; }
    .batt-item { background: var(--surface2); border-radius: 10px; padding: 7px 10px; text-align: center; }
    .batt-grid .batt-item:nth-child(2) { border-bottom-right-radius: 16px; }
    .batt-grid .batt-item:nth-child(3) { border-bottom-left-radius:  16px; }
    .batt-grid .batt-item:nth-child(4) { border-top-right-radius:    16px; }
    .batt-grid .batt-item:nth-child(5) { border-top-left-radius:     16px; }
    .batt-item .label { font-size: 9px; color: var(--text3); margin-bottom: 2px; letter-spacing: .06em; text-transform: uppercase; }
    .batt-item .value { font-size: 18px; font-weight: 700; line-height: 1; }
    .batt-item .unit  { font-size: 10px; color: var(--text2); margin-left: 2px; }
    .batt-sub, .hz-sub { display: flex; justify-content: space-between; padding-top: 4px;
      border-top: 1px solid var(--border); flex-wrap: wrap; gap: 4px;
      margin-top: -8px; }
    .batt-sub-item, .hz-sub-item { font-size: 12px; color: var(--text2); }
    .batt-sub-item b, .hz-sub-item b { color: var(--text); font-weight: 600; }
    /* Die Fusszeile steht immer unten, die Raumliste davor gibt nach. */
    .hz-sub { margin-top: auto; gap: 10px; flex-wrap: wrap; }

    /* ── Source Progress Bars (rechts neben Gauge) ── */
    .src-bar-hd { font-size: 8px; font-weight: 700; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      border-bottom: 1px solid var(--border); padding-bottom: 3px;
      width: 90px; text-align: right; display: block; line-height: 1;
      /* Linke BMS-Rows auf 18px anheben um mit Bars gleich zu sein */ }
    .src-bar { position: relative; width: 90px; height: 15px;
      background: var(--surface2); border-radius: 999px; overflow: hidden;
      border: 1px solid var(--border); }
    .src-bar-fill { position: absolute; left: 0; top: 0; height: 100%;
      background: var(--green); border-radius: 999px; width: 0%;
      transition: width .6s cubic-bezier(.4,0,.2,1); }
    .src-bar-text, .src-bar-text-dark {
      position: absolute; top: 0; left: 0; right: 0;
      display: flex; align-items: center; justify-content: flex-end; height: 100%;
      font-size: 11px; font-weight: 400;
      padding: 0 8px; white-space: nowrap; box-sizing: border-box; }
    .src-bar-text      { color: var(--text3); z-index: 1; }
    .src-bar-text-dark { color: #1a2f10; z-index: 2; clip-path: inset(0 100% 0 0); }

    /* ── Power sources (Solar / Alternator) ── */
    .src-row { display: flex; gap: 8px; flex-wrap: wrap; }
    .src-row.hidden { display: none; }
    .src-item { display: none; flex: 1; min-width: 110px; align-items: center; gap: 6px;
      background: var(--surface2); border-radius: 8px; padding: 7px 11px; font-size: 12px; color: var(--text2); }
    .src-item.visible { display: flex; }
    .src-icon { font-size: 14px; line-height: 1; }
    .src-val  { font-size: 15px; font-weight: 700; }
    .src-solar .src-val { color: var(--yellow); }
    .src-alt   .src-val { color: var(--accent); }

    .val-green  { color: var(--green)  !important; }
    .val-yellow { color: var(--yellow) !important; }
    .val-red    { color: var(--red)    !important; }
    .val-orange { color: var(--orange) !important; }
    .val-accent { color: var(--accent) !important; }

    /* ── Tanks ── */
    .card-tanks { cursor: pointer; -webkit-tap-highlight-color: transparent;
      transition: border-color .2s; }
    html[data-zeiger="fein"] .card-tanks:hover { border-color: var(--accent2); }

    /* Jede anklickbare Kachel hebt sich beim Ueberfahren ab — und zwar gleich.
       Vorher war das je Klasse einzeln gepflegt und existierte nur fuer
       Batterie und Tanks; Beleuchtung, Wasserstand, Wartungsplan und Heizung
       fielen durch, obwohl sie genauso klickbar sind. Der Selektor haengt am
       onclick statt an einer Klassenliste, damit die naechste neue Kachel die
       Hervorhebung automatisch mitbringt. */
    .card[onclick] { cursor: pointer; }
    /* NUR mit echtem Zeiger.
       Hier lag der eigentliche Fehler: die Regel galt fuer jede anklickbare
       Kachel und war nicht abgesichert. Auf dem Touchscreen bleibt `:hover` am
       zuletzt Angetippten haengen — die Kachel blieb also hell stehen, bis man
       woanders hintippte (Eignermeldung 08.09.2026: „immer die Lichtkachel
       gehighlightet").
       Die Absicherung stand vorher als `@media (hover: none)` darunter und
       nahm nur den Schatten weg, nicht die Rahmenfarbe — und die Medienabfrage
       luegt ohnehin: iPadOS meldet `hover: hover` ohne Zeiger. Deshalb
       `data-zeiger`, das aus dem echten Eingabeereignis kommt (display.js). */
    html[data-zeiger="fein"] .card[onclick]:hover {
      border-color: var(--accent2);
      /* Nach innen — siehe .card-battery:hover. */
      box-shadow: inset 0 0 0 1px var(--accent2);
    }
    .tanks-row { display: flex; gap: 16px; flex: 1; }
    .tank { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 10px; }
    .tank-name { font-size: 12px; color: var(--text2); }
    .tank-bar-wrap { flex: 1; width: 100%; min-height: 120px; background: var(--surface2);
      border-radius: 10px; position: relative; overflow: hidden; border: 1px solid var(--border); }
    /* KEIN Gruen als Ausgangsfarbe. Bei Hoehe 0 sieht man es zwar nicht —
       aber der Uebergang blendet beim ersten Fuellen VON dieser Farbe auf die
       eingestellte, und genau das sah man: der Balken lud gruen und sprang
       dann um. Die echte Farbe ist eine Einstellung vom Boot (presets.json)
       und steht hier grundsaetzlich nicht. */
    .tank-fill { position: absolute; bottom: 0; left: 0; right: 0;
      border-radius: 0 0 10px 10px; transition: height .8s ease, background .5s;
      background: var(--border); }
    .tank-pct-label { position: absolute; inset: 0; display: flex; flex-direction: column;
      align-items: center; justify-content: center; gap: 0; }
    .tank-val-big  { font-size: 28px; font-weight: 700; color: var(--text);
      text-shadow: 0 1px 6px rgba(0,0,0,.7); line-height: 1; }
    .tank-val-unit { font-size: 15px; font-weight: 600; color: var(--text);
      text-shadow: 0 1px 4px rgba(0,0,0,.7); opacity: .75; margin-top: 2px; }
    .tank-pct-below { font-size: 13px; color: var(--text2); }

    /* ── Lights ── */
    .presets-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; }
    @media (max-width: 400px) { .presets-grid { grid-template-columns: repeat(2,1fr); } }
    .preset-btn { background: var(--surface2); border: 1px solid var(--border);
      border-radius: 12px; padding: 14px 10px; cursor: pointer;
      display: flex; flex-direction: column; align-items: center; gap: 6px;
      transition: all .15s; color: var(--text);
      user-select: none; -webkit-tap-highlight-color: transparent; }
    .preset-btn:hover:not(.disabled) { border-color: var(--accent2); background: #1a3244; }
    .preset-btn:active:not(.disabled) { transform: scale(.96); }
    /* Der Ring lag NACH AUSSEN (box-shadow ohne inset). Aussen wird er vom
       Nachbarn ueberdeckt und am Kartenrand beschnitten — oben sah er deshalb
       schmaler aus als an den anderen Seiten, und kein Nachziehen der Abstaende
       hat das je ganz behoben. Nach innen gelegt kann ihm beides nicht mehr
       passieren: er liegt vollstaendig im Knopf.
       Zusammen mit dem Rahmen ergibt das gleichmaessige 3 px ringsum. */
    .preset-btn.active { border-color: var(--accent); background: rgba(6,182,212,.12);
      box-shadow: inset 0 0 0 2px var(--accent); }
    .preset-btn.disabled { opacity: .35; cursor: not-allowed; }
    .preset-emoji { font-size: 22px; line-height: 1; }
    .preset-name  { font-size: 12px; font-weight: 500; text-align: center; line-height: 1.2; }
    .channels-row { display: flex; gap: 5px; align-items: flex-end; height: 32px;
      /* Der Finger regelt hier senkrecht — ohne das scrollt die Seite mit. */
      touch-action: none; }
    .ch-bar-wrap { flex: 1; height: 100%; background: var(--surface2); border-radius: 4px;
      position: relative; overflow: hidden; cursor: ns-resize;
      -webkit-tap-highlight-color: transparent;
      /* Dasselbe wie bei den Feldern der Statusleiste: Ziehen und Halten
         duerfen nichts markieren. */
      user-select: none; -webkit-user-select: none;
      -webkit-touch-callout: none; }
    .ch-bar { position: absolute; bottom: 0; left: 0; right: 0; background: var(--accent);
      border-radius: 4px; transition: height .5s ease; opacity: .85; }
    /* Waehrend gezogen wird, darf die Fuellung dem Finger nicht hinterherlaufen —
       eine halbe Sekunde Nachlauf fuehlt sich an wie ein Wackelkontakt. */
    .channels-row.zieht .ch-bar { transition: none; }
    .ch-bar.relay { background: var(--orange); }

    /* Der Name IM Balken, von unten nach oben gelesen. Er liegt ueber der
       Fuellung und bleibt damit bei jedem Stand lesbar; der Schatten traegt
       ihn auch dort, wo die Fuellung genau hinter ihm endet. */
    .ch-name {
      position: absolute; inset: 0; z-index: 2;
      display: flex; align-items: center; justify-content: center;
      writing-mode: vertical-rl; transform: rotate(180deg);
      font-size: 11px; font-weight: 600; letter-spacing: .04em;
      color: var(--text); opacity: .85;
      text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
      pointer-events: none; user-select: none;
      white-space: nowrap; overflow: hidden;
    }

    /* Unter den Balken, wenn diese zu schmal fuer senkrechte Schrift sind
       (siehe _CH_NAME_INNEN_AB_PX in lights.js). Waagerecht liest sich der
       Name normal, auch wenn weniger davon zu sehen ist. */
    .channels-label { display: flex; gap: 5px; margin-top: 5px; }
    .channels-row.namen-innen + .channels-label { display: none; }
    .ch-name-unten {
      flex: 1; min-width: 0; text-align: center;
      font-size: 10px; font-weight: 600; color: var(--text2);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }

    /* Die Nummernzeile unter den Balken ist entfallen: "1 2 3 4 R" sagte
       ohnehin niemandem etwas. An ihrer Stelle stehen dort jetzt die Namen —
       aber nur auf schmalen Balken, siehe oben. */
    .divider { height: 1px; background: var(--border); margin: 0 -4px; }

    /* ── Full-screen overlay (shared base) ── */
    /* Overlay startet UNTER der Haupt-Topbar — diese bleibt sichtbar */
    .overlay { position: fixed; top: var(--header-h); left: 0; right: 0; bottom: 0;
      background: var(--bg); z-index: 100; display: flex; flex-direction: column; }
    .overlay.hidden { display: none; }
    /* Schlanke, randlose Kopfzeile — kein zweiter Balken */
    .ov-header { display: flex; align-items: center;
      padding: 12px 16px 4px; background: transparent; flex-shrink: 0; gap: 8px; }
    .ov-title { flex: 1; text-align: left; font-size: 15px; font-weight: 700;
      letter-spacing: .02em; text-transform: none; color: var(--text);
      display: flex; align-items: center; gap: 8px; }
    .ov-header-spacer { width: 0; flex-shrink: 0; }
    /* Zwei Knoepfe im Overlay-Kopf (Stromverlauf + Energiefluss). Auf schmalen
       Geraeten duerfen sie umbrechen, statt den Titel zu zerquetschen. */
    .ov-head-btns { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
      justify-content: flex-end; }
    @media (max-width: 560px) {
      /* Mit zwei beschrifteten Knoepfen bleibt fuer den Titel nichts uebrig —
         bei 320 px zerbrach "Batterie — Details" mitten im Gedankenstrich.
         Unter 560 px zeigen die Knoepfe nur ihr Symbol; die Beschriftung
         steht weiterhin im title-/aria-label-Attribut. */
      .ov-head-btns .monday-refresh { padding: 6px 9px; gap: 0; }
      .ov-head-btns .monday-refresh .btn-text { display: none; }
    }
    .ov-body { flex: 1; overflow-y: auto; padding: 12px 16px 16px; }

    /* ── Zentrierte Modals (statt Bottom-Sheets) ── */
    .center-modal-bg { display: none; position: fixed; inset: 0; z-index: 199;
      background: rgba(0,0,0,.55); backdrop-filter: blur(2px); }
    .center-modal { display: none; position: fixed; top: 50%; left: 50%;
      transform: translate(-50%, -50%); z-index: 200;
      width: calc(100% - 32px); max-width: 560px; max-height: 88vh; overflow-y: auto;
      background: var(--surface); border: 1px solid var(--border);
      border-radius: 16px; padding: 20px;
      box-shadow: 0 24px 64px rgba(0,0,0,.55); }
    .center-modal-hd { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
    .center-modal-close { margin-left: auto; background: var(--surface2); border: 1px solid var(--border);
      color: var(--text2); width: 32px; height: 32px; border-radius: 8px; cursor: pointer;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
    .center-modal-close:hover { background: var(--border); color: var(--text); }

    /* ── Zahleneingaben: Spinner-Pfeile ausblenden ── */
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
    input[type=number] { -moz-appearance: textfield; appearance: textfield; }

    /* ── Battery detail — 3-column page grid ── */
    /* ── Neue Batterie-Detail-Seite (2-spaltig) ── */
    .bd2-layout { display: grid; grid-template-columns: 300px 1fr; gap: 16px; align-items: stretch; }
    @media (max-width: 860px) { .bd2-layout { grid-template-columns: 1fr; } }
    .bd2-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
      padding: 18px 20px; display: flex; flex-direction: column; gap: 14px; }
    .bd2-chart-card { flex: 1; }
    .bd2-canvas { flex: 1; min-height: 0; width: 100% !important; cursor: crosshair; }
    .bd2-section-hd { font-size: 10px; font-weight: 700; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3); }
    .bd2-kv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .bd2-kv { background: var(--surface2); border-radius: 8px; padding: 9px 11px; }
    .bd2-kv-label { font-size: 10px; color: var(--text3); text-transform: uppercase;
      letter-spacing: .06em; margin-bottom: 4px; }
    .bd2-kv-val { font-size: 20px; font-weight: 700; line-height: 1; display: flex;
      align-items: baseline; gap: 3px; }
    .bd2-kv-unit { font-size: 12px; color: var(--text2); font-weight: 400; }
    .bd2-stat-row { display: flex; gap: 10px; flex-wrap: wrap; }
    .bd2-stat { font-size: 13px; color: var(--text2); display: flex; gap: 5px; align-items: baseline; }
    .bd2-stat-l { font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing:.04em; }

    /* ── Batterie-Detailseite: Raster ─────────────────────────────────────
       Vorher lagen fuenf Karten in voller Breite untereinander (Desktop
       1485 px hoch). Die Kennzahlenzeile endete bei 40 % der Breite, ein
       78-W-Balken war 1300 px lang, und man musste dreimal scrollen, um die
       Geraete zu sehen. Zwei Spalten nutzen die Breite; unter 1100 px faellt
       das Raster auf eine Spalte zurueck, die Reihenfolge bleibt dieselbe. */
    .bd-grid {
      display: grid; gap: var(--gap);
      max-width: 1500px; margin: 0 auto; padding: 16px; box-sizing: border-box;
      grid-template-columns: 1fr;
      grid-template-areas: "antwort" "bilanz" "zellen" "geraete" "verlauf"
                           "energie" "woche" "starter";
      /* Die Rasterflaeche ist so hoch wie das Fenster. Ohne align-content
         verteilt der Browser die Restzhoehe auf die Zeilen: die Zeilen werden
         hoeher als ihr Inhalt, und mit align-items:start klebten die Karten
         oben darin. Am Geraet gemessen ergab das 53 px Luft zwischen
         Geraetekacheln und Starterkarte, waehrend ueberall sonst 16 px stehen.
         Zeilen also nach Inhalt, ueberschuessige Hoehe bleibt unten. */
      align-content: start;
      /* Und innerhalb einer Zeile fuellen die Karten die volle Zeilenhoehe —
         sonst standen Bilanz (168 px) und Zellen (185 px) nebeneinander
         unterschiedlich hoch. */
      align-items: stretch;
    }
    /* Die Karte selbst muss die Zelle auch ausfuellen, nicht nur das Rasterfeld. */
    .bd-grid > div > .sb-card,
    .bd-grid > .bd-flow,
    .bd-grid > div > .starter,
    .bd-grid > div > .bd-card { height: 100%; box-sizing: border-box; }
    @media (min-width: 1100px) {
      .bd-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        /* Links die Energie (was fliesst jetzt, was floss vorher), rechts der
           Zustand der Hardware (Zellen, Geraete). Die beiden Spalten sind so
           auch ungefaehr gleich hoch — bei "Verlauf ueber die volle Breite"
           stand rechts eine halbe Bildschirmhoehe leer. */
        grid-template-areas:
          "antwort antwort"
          "bilanz  zellen"
          "verlauf geraete"
          "verlauf starter"
          "energie woche";
      }
    }
    .bd-a-antwort { grid-area: antwort; }
    .bd-a-bilanz  { grid-area: bilanz; }
    .bd-a-zellen  { grid-area: zellen; }
    .bd-a-geraete { grid-area: geraete; }
    .bd-a-verlauf { grid-area: verlauf; }
    .bd-a-starter { grid-area: starter; }
    /* Stromverlauf und 7-Tage-Trend, von der frueheren Unterseite hierher.
       Sie behalten ihre .vl-karte-Optik, muessen sich im Raster aber wie die
       uebrigen Karten verhalten: kein eigener Aussenabstand, volle Zeilenhoehe. */
    .bd-a-energie { grid-area: energie; }
    .bd-a-woche   { grid-area: woche; }
    .bd-grid > .vl-karte { margin: 0; height: 100%; box-sizing: border-box; }
    /* Nur die Wochenkachel wird zur Spalte: dann kann das Canvas darin die
       Resthoehe uebernehmen. Beim Feinverlauf ist das nicht gewollt — der hat
       unter dem Diagramm noch Summen und Hinweiszeile. */
    .bd-grid > .bd-a-woche { display: flex; flex-direction: column; }
    /* Im Raster erzeugt jede Karte ihren eigenen Abstand ueber gap — die alten
       Einzel-Abstaende wuerden sich addieren. */
    .bd-grid .sb-card,
    .bd-grid .starter,
    .bd-grid .bd-flow { margin-bottom: 0; }
    /* Die Geraetekacheln stehen jetzt in einer halben Spalte: zwei nebeneinander
       statt vier, damit die Wattzahl gross bleibt. */
    @media (min-width: 1100px) {
      .bd-a-geraete { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    /* Der Verlauf spannt links zwei Rasterzeilen, damit rechts unter den
       Geraeten kein toter Raum bleibt. Er darf die Hoehe ausfuellen. */
    @media (min-width: 1100px) { .bd-a-verlauf { align-self: stretch; } }
    .bd-a-verlauf { display: flex; }
    .bd-a-verlauf > .bd-pg-chart { grid-area: auto; flex: 1; min-width: 0; }

    /* Altes Grid (nicht mehr für battOverlay genutzt, kann bleiben) */
    .bd-pg {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      grid-template-areas:
        "batt   cells   sources"
        "chart  chart   starter";
      gap: 14px; max-width: 1500px; margin: 0 auto; align-items: start;
    }
    /* flex:1 ohne Deckel liess den Verlauf auf 647 px anwachsen — mehr Hoehe
       macht eine Kurve nicht lesbarer, sie schiebt nur alles Weitere nach
       unten aus dem Blick. */
    /* Im Raster liegt der Verlauf ueber die volle Breite: flacher als frueher,
       sonst nimmt eine meist ruhige Kurve wieder das halbe Bild. */
    .bd-pg-chart canvas.chart { flex: 1; min-height: 200px; max-height: 260px; }
    .bd-pg-batt    { grid-area: batt; }
    .bd-pg-chart   { grid-area: chart; }
    .bd-pg-cells   { grid-area: cells; }
    .bd-pg-sources { grid-area: sources; }
    .bd-pg-starter { grid-area: starter; }
    @media (max-width: 1023px) {
      .bd-pg {
        grid-template-columns: 1fr 1fr;
        grid-template-areas:
          "batt   cells"
          "sources starter"
          "chart  chart";
      }
    }
    @media (max-width: 639px) {
      .bd-pg {
        grid-template-columns: 1fr;
        grid-template-areas: "batt" "chart" "cells" "sources" "starter";
      }
    }

    /* ── Battery detail — card layout ── */
    .bd-page { max-width: 900px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px; }
    .bd-card {
      background: var(--surface); border: 1px solid var(--border);
      /* Ein Innenabstand fuer alle Karten (20 px), einer fuer die kleineren
         Geraetekacheln (16 px). Vorher waren es vier verschiedene:
         20 / 14+16 / 14+18 / 18+20. */
      border-radius: var(--radius); padding: 20px;
      display: flex; flex-direction: column; gap: 14px;
    }
    .bd-card-hd {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      padding-bottom: 10px; border-bottom: 1px solid var(--border);
    }
    .bd-card-hd-row {
      display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px;
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      padding-bottom: 10px; border-bottom: 1px solid var(--border);
    }
    .bd-ov-row { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }
    .bd-soc-block { display: flex; flex-direction: column; gap: 8px; min-width: 130px; flex-shrink: 0; }
    .bd-soc-head  { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
    .bd-soc-num   { font-size: 58px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
    .bd-soc-pct-unit { font-size: 22px; color: var(--text2); font-weight: 400; }
    .bd-soc-dir   { font-size: 14px; color: var(--text2); align-self: center; }
    .bd-soc-sec   { font-size: 12px; color: var(--text3); }
    .bd-kv-grid   { flex: 1; min-width: 200px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
    .bd-kv-item   { background: var(--surface2); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; }
    .bd-kv-label  { font-size: 10px; color: var(--text3); letter-spacing: .06em; text-transform: uppercase; margin-bottom: 4px; }
    .bd-kv-line   { display: flex; align-items: baseline; gap: 3px; }
    .bd-kv-val    { font-size: 22px; font-weight: 700; line-height: 1; }
    .bd-kv-unit   { font-size: 12px; color: var(--text2); font-weight: 400; }
    .bd-kv-sec    { font-size: 11px; color: var(--text3); margin-top: 4px; }
    .bd-stat-row  { display: flex; flex-wrap: wrap; gap: 8px; }
    .bd-stat      { flex: 1; min-width: 100px; background: var(--surface2); border-radius: 8px; padding: 10px 12px; }
    .bd-stat-label { font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 4px; }
    .bd-stat-val  { font-size: 15px; font-weight: 600; }
    .bd-stat-unit { font-size: 11px; color: var(--text2); margin-left: 2px; }
    .bd-3col      { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
    .bd-3col-item { background: var(--surface2); border-radius: 10px; padding: 14px; text-align: center; display: flex; flex-direction: column; align-items: center; }
    .bd-3col-label { font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px; }
    .bd-3col-val  { font-size: 26px; font-weight: 700; display: flex; align-items: baseline; gap: 3px; }

    /* ── Cell mini grid (inside service battery card) ── */
    .bd-cell-mini-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
    .bd-cell-mini-item { background: var(--surface); border: 2px solid var(--border);
      border-radius: 9px; padding: 8px 10px; transition: border-color .4s; }
    .bd-cell-mini-nr { font-size: 9px; color: var(--text3); letter-spacing:.06em;
      text-transform: uppercase; margin-bottom: 4px; }
    .bd-cell-mini-v  { font-size: 17px; font-weight: 700; line-height: 1; }
    .bd-cell-mini-t  { font-size: 11px; color: var(--text2); margin-top: 3px; }

    /* ── Mini stats row (restkapazität, zyklen, letzte Ladung) ── */
    .bd-mini-row { display: flex; gap: 6px; flex-wrap: wrap; }
    .bd-mini-item { flex: 1; min-width: 68px; background: var(--surface2);
      border-radius: 8px; padding: 8px 10px; }
    .bd-mini-val  { font-size: 14px; font-weight: 600; margin-top: 2px; }

    /* ── Min/Max footer row in battery card ── */
    .bd-minmax-row { display: flex; align-items: center; gap: 8px; font-size: 12px;
      color: var(--text3); padding-top: 10px; border-top: 1px solid var(--surface2);
      margin-top: auto; flex-wrap: wrap; }

    /* ── Solar column ── */
    .bd-solar-list { display: flex; flex-direction: column; gap: 7px; }
    .bd-solar-item { display: flex; align-items: center; justify-content: space-between;
      background: var(--surface2); border-radius: 8px; padding: 9px 12px; }
    .bd-solar-name { font-size: 13px; color: var(--text2); }
    .bd-solar-vals { display: flex; align-items: baseline; gap: 8px; }
    .bd-solar-w    { font-size: 16px; font-weight: 700; color: var(--yellow); }
    .bd-solar-v    { font-size: 12px; color: var(--text3); }
    .bd-solar-total { background: var(--surface2); border-radius: 8px; padding: 10px 12px; }
    .bd-solar-total-val { font-size: 22px; font-weight: 700; color: var(--yellow); margin-top: 2px; }

    /* ── Placeholder card (dashed border) ── */
    .bd-card-ph { border-style: dashed; opacity: .55; }
    .bd-ph-body { flex: 1; display: flex; flex-direction: column;
      align-items: center; justify-content: center; gap: 8px;
      padding: 28px 0; color: var(--text3); }
    .bd-ph-icon { font-size: 26px; }
    .bd-ph-text { font-size: 13px; }

    /* ── Battery detail layout (legacy — kept for ov-body compat) ── */
    .bd-label { font-size: 10px; color: var(--text3); letter-spacing: .06em;
      text-transform: uppercase; margin-bottom: 4px; }
    .bd-unit { font-size: 12px; color: var(--text2); margin-left: 2px; font-weight: 400; }

    /* ── bd-sec (connectivity detail grid) ── */
    .bd-sec-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .bd-sec-item { background: var(--surface2); border-radius: 8px; padding: 9px 11px; }
    .bd-sec-val  { font-size: 15px; font-weight: 600; margin-top: 2px; }

    /* ── Charts ── */
    .chart-section { display: flex; flex-direction: column; gap: 14px; }
    .chart-card { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 14px 16px; }
    .chart-header { display: flex; justify-content: space-between; align-items: baseline;
      margin-bottom: 10px; }
    .chart-title { font-size: 11px; font-weight: 600; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text3); }
    .chart-current { font-size: 18px; font-weight: 700; }
    .chart-unit { font-size: 11px; color: var(--text2); margin-left: 2px; }
    canvas.chart { width: 100%; height: 80px; display: block; border-radius: 6px; }

    /* ── Alarm badge ── */
    .alarm-btn { position: relative; }
    .alarm-badge {
      position: absolute; top: -5px; right: -5px;
      background: var(--red); color: #fff; border-radius: 50%;
      min-width: 16px; height: 16px; padding: 0 3px;
      font-size: 10px; font-weight: 700;
      display: flex; align-items: center; justify-content: center;
      pointer-events: none;
    }
    .alarm-badge.hidden { display: none; }

    /* ── Alarm overlay tabs ── */
    .tabs { display: flex; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
    .tab-btn {
      padding: 10px 18px; font-size: 13px; font-weight: 500;
      border: none; background: none; color: var(--text2); cursor: pointer;
      border-bottom: 2px solid transparent; margin-bottom: -1px;
      transition: all .15s; font-family: inherit;
    }
    .tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
    .tab-pane { display: none; }
    .tab-pane.active { display: block; }

    /* ── Alarm cards ── */
    .alarm-list { display: flex; flex-direction: column; gap: 10px; }
    .alarm-empty { color: var(--text3); text-align: center; padding: 50px 20px; font-size: 14px; }
    .alarm-card {
      background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 14px 16px;
      display: flex; flex-direction: column; gap: 8px;
      transition: opacity .3s;
    }
    .alarm-card.warning  { border-left: 3px solid var(--yellow); }
    .alarm-card.critical { border-left: 3px solid var(--red); }
    .alarm-card.acknowledged { opacity: .55; }
    .alarm-card.resolved { border-left-color: var(--border); }
    .alarm-header { display: flex; align-items: center; gap: 8px; }
    .alarm-severity-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    .warning  .alarm-severity-dot { background: var(--yellow); }
    .critical .alarm-severity-dot { background: var(--red); }
    .resolved .alarm-severity-dot { background: var(--border); }
    .alarm-name { font-size: 14px; font-weight: 600; flex: 1; }
    .alarm-time { font-size: 11px; color: var(--text3); }
    .alarm-detail { font-size: 12px; color: var(--text2); }
    .alarm-detail b { color: var(--text); }
    .alarm-resolved-badge {
      font-size: 11px; color: var(--green); font-weight: 600;
      display: flex; align-items: center; gap: 4px;
    }
    .alarm-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 2px; }
    .alarm-ack-btn, .alarm-del-btn {
      border: 1px solid var(--border); border-radius: 6px;
      padding: 5px 12px; font-size: 12px; cursor: pointer;
      font-family: inherit; transition: all .15s; background: none; color: var(--text2);
    }
    .alarm-ack-btn:hover { background: var(--surface2); color: var(--accent); border-color: var(--accent2); }
    .alarm-del-btn:hover { background: rgba(239,68,68,.1); color: var(--red); border-color: var(--red); }
    .ack-all-row { display: flex; justify-content: flex-end; margin-bottom: 12px; }

    /* ── Alarm rules ── */
    .rule-cat-nav { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 16px; }
    .rule-cat-btn { background: var(--surface2); border: 1px solid var(--border); color: var(--text2);
      padding: 7px 14px; border-radius: 20px; font-size: 13px; cursor: pointer; font-weight: 500; }
    .rule-cat-btn:hover { background: var(--border); }
    .rule-cat-btn.active { background: var(--accent2, #3b82f6); color: #fff; border-color: transparent; }
    .rule-cat-btn .rc-count { font-size: 11px; opacity: .7; margin-left: 4px; }
    .rule-list { display: flex; flex-direction: column; gap: 2px; margin-bottom: 20px; }
    .rule-row {
      display: flex; flex-direction: column; gap: 6px;
      padding: 12px 0; border-bottom: 1px solid var(--surface2);
    }
    .rule-row:last-child { border-bottom: none; }
    .rule-row.no-data { opacity: .45; }
    .rule-header { display: flex; align-items: center; gap: 10px; }
    .rule-toggle { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
    .rule-toggle input { opacity: 0; width: 0; height: 0; position: absolute; }
    .rule-slider {
      position: absolute; inset: 0; background: var(--border);
      border-radius: 20px; cursor: pointer; transition: background .2s;
    }
    .rule-slider::before {
      content: ''; position: absolute; width: 14px; height: 14px;
      left: 3px; top: 3px; background: #fff; border-radius: 50%;
      transition: transform .2s;
    }
    .rule-toggle input:checked + .rule-slider { background: var(--accent); }
    .rule-toggle input:checked + .rule-slider::before { transform: translateX(16px); }
    .rule-name { flex: 1; font-size: 13px; color: var(--text); }
    .rule-threshold-wrap { display: flex; align-items: center; gap: 5px; }
    .rule-op   { font-size: 12px; color: var(--text3); white-space: nowrap; }
    .rule-unit { font-size: 12px; color: var(--text3); }
    .rule-input {
      width: 72px; background: var(--surface2); border: 1px solid var(--border);
      border-radius: 6px; padding: 5px 8px; color: var(--text); font-size: 13px;
      outline: none; text-align: right; font-family: inherit;
    }
    .rule-input:focus { border-color: var(--accent); }
    .rule-severity { font-size: 10px; font-weight: 600; padding: 2px 6px;
      border-radius: 4px; white-space: nowrap; border: none; cursor: pointer; }
    .rule-severity.warning  { background: rgba(234,179,8,.15);  color: var(--yellow); }
    .rule-severity.critical { background: rgba(239,68,68,.15); color: var(--red); }
    .rule-no-data { font-size: 11px; color: var(--text3); font-style: italic; padding-left: 46px; }

    /* ── Dual-range slider ── */
    .dr-wrap { padding: 4px 0 2px; }
    .dr-vals { display: flex; justify-content: space-between; font-size: 12px;
               color: var(--accent); font-variant-numeric: tabular-nums; margin-bottom: 4px; }
    .dr-track { position: relative; height: 44px; display: flex; align-items: center; }
    .dr-track-bg { position: absolute; left: 22px; right: 22px; height: 4px;
                   top: 50%; transform: translateY(-50%);
                   background: var(--surface2); border-radius: 2px; }
    .dr-fill { position: absolute; height: 4px; top: 50%; transform: translateY(-50%);
               background: var(--accent); border-radius: 2px; pointer-events: none; }
    .dr-thumb {
      position: absolute; width: 44px; height: 44px;
      display: flex; align-items: center; justify-content: center;
      cursor: grab; touch-action: none; transform: translateX(-50%);
      z-index: 2;
    }
    .dr-thumb::after {
      content: ''; width: 18px; height: 18px; border-radius: 50%;
      background: var(--accent); border: 2px solid #fff;
      box-shadow: 0 1px 4px rgba(0,0,0,.5);
    }
    .dr-thumb:active { cursor: grabbing; }
    .dr-bounds { display: flex; justify-content: space-between; font-size: 10px;
                 color: var(--text3); padding: 0 0; margin-top: 2px; }

    /* ── Settings ── */
    .settings-section { margin-bottom: 28px; }
    .settings-section-title {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3); margin-bottom: 4px;
      padding-bottom: 8px; border-bottom: 1px solid var(--border);
    }
    .settings-row {
      display: flex; align-items: center; gap: 12px;
      padding: 10px 0; border-bottom: 1px solid var(--surface2);
    }
    .settings-row:last-child { border-bottom: none; }
    .settings-label { font-size: 13px; color: var(--text2); min-width: 120px; flex-shrink: 0; }
    .settings-input {
      flex: 1; background: var(--surface2); border: 1px solid var(--border);
      border-radius: 8px; padding: 9px 12px; color: var(--text); font-size: 14px;
      outline: none; transition: border-color .15s; font-family: inherit;
    }
    .settings-input:focus { border-color: var(--accent); }
    .settings-input.narrow { max-width: 100px; }
    .settings-color-wrap {
      display: flex; align-items: center; gap: 8px;
    }
    .settings-color {
      width: 44px; height: 38px; padding: 3px; border-radius: 8px;
      border: 1px solid var(--border); background: var(--surface2);
      cursor: pointer; flex-shrink: 0;
    }
    .settings-actions {
      display: flex; gap: 10px; justify-content: flex-end; margin-top: 24px;
    }
    .btn-primary {
      background: var(--accent); color: #0f172a; border: none;
      border-radius: 8px; padding: 10px 20px; font-size: 14px; font-weight: 600;
      cursor: pointer; transition: background .15s; font-family: inherit;
    }
    /* Nur mit einem echten Zeiger — sonst bleibt der zuletzt angetippte Knopf
       hell stehen, bis man woanders hintippt (siehe `_zeigerartMerken`).
       Dieselbe Regel gilt fuer die uebrigen Schalter dieser Oberflaeche; hier
       stehen erst die beiden allgemeinen. */
    html[data-zeiger="fein"] .btn-primary:hover { background: var(--accent2); }
    .btn-primary:disabled { opacity: .5; cursor: not-allowed; }
    .btn-secondary {
      background: var(--surface2); color: var(--text); border: 1px solid var(--border);
      border-radius: 8px; padding: 7px 14px; font-size: 13px; font-weight: 600;
      cursor: pointer; transition: background .15s, border-color .15s; font-family: inherit;
    }
    html[data-zeiger="fein"] .btn-secondary:hover { background: var(--surface); border-color: var(--accent2); }
    .settings-feedback {
      font-size: 13px; color: var(--green); margin-right: auto;
      align-self: center; opacity: 0; transition: opacity .3s;
    }
    .settings-feedback.show { opacity: 1; }
    .settings-feedback.error { color: var(--red); }

    /* ── Network overlay — device cards ── */
    .net-grid { display: grid; gap: 12px;
      grid-template-columns: 1fr; max-width: 1100px; margin: 0 auto; }
    @media (min-width: 550px)  { .net-grid { grid-template-columns: 1fr 1fr; } }
    @media (min-width: 900px)  { .net-grid { grid-template-columns: 1fr 1fr 1fr; } }

    .net-device-card { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); overflow: hidden; }
    .net-device-header { display: flex; align-items: center; gap: 8px;
      padding: 10px 12px; border-bottom: 1px solid var(--border);
      background: var(--surface2); }
    .net-device-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    .net-device-dot.ok   { background: var(--green); box-shadow: 0 0 4px var(--green); }
    .net-device-dot.warn { background: var(--yellow); animation: pulse 1.5s infinite; }
    .net-device-dot.old  { background: var(--border); }
    .net-device-name { font-size: 13px; font-weight: 600; color: var(--text); flex: 1;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .net-device-src  { font-size: 11px; color: var(--text3); font-family: monospace;
      background: var(--surface); border: 1px solid var(--border); border-radius: 4px;
      padding: 1px 5px; flex-shrink: 0; }

    .net-pgn-list { padding: 0; }
    .net-pgn-row { display: flex; align-items: center; gap: 8px;
      padding: 5px 12px; border-bottom: 1px solid var(--surface2); }
    .net-pgn-row:last-child { border-bottom: none; }
    /* Direkte Kinder (Router-Kachel): desc nimmt Restbreite, iv rechts */
    .net-pgn-row > .net-pgn-desc { flex: 1; font-size: 12px; color: var(--text2); }
    .net-pgn-iv { font-size: 12px; color: var(--text); white-space: nowrap; font-weight: 500; }
    /* CAN-Kacheln: dot + info-Block + iv-badge */
    .net-pgn-dot-wrap { flex-shrink: 0; display: flex; align-items: center; padding-right: 2px; }
    .net-pgn-dot { width: 5px; height: 5px; border-radius: 50%; }
    .net-pgn-dot.ok   { background: var(--green); }
    .net-pgn-dot.warn { background: var(--yellow); }
    .net-pgn-dot.old  { background: var(--border); }
    .net-pgn-info { flex: 1; min-width: 0; }
    .net-pgn-desc { font-size: 12px; color: var(--text); }
    .net-pgn-num  { font-size: 10px; color: var(--text3); font-family: monospace; margin-top: 1px; }
    .net-inst-badge { display: inline-block; font-size: 9px; background: var(--accent);
      color: #fff; border-radius: 3px; padding: 0 4px; margin-left: 4px;
      vertical-align: middle; line-height: 16px; }
    .net-iv-badge { font-size: 10px; color: var(--text3); white-space: nowrap;
      flex-shrink: 0; font-family: monospace; }
    .net-pgn-row:hover { background: var(--surface2); border-radius: 4px; }

    .net-empty { color: var(--text3); text-align: center; padding: 60px 20px; font-size: 14px; }

    /* ── PGN-Detail Modal ── */
    .pgn-nav-btn { background: var(--surface2); border: 1px solid var(--border); color: var(--text);
      border-radius: 6px; padding: 3px 10px; cursor: pointer; font-size: 14px; line-height: 1.4; }
    .pgn-nav-btn:hover { background: var(--border); }
    .pgn-field-row { display: flex; justify-content: space-between; align-items: baseline;
      padding: 7px 16px; border-bottom: 1px solid var(--surface2); }
    .pgn-field-row.alarm { background: rgba(239,68,68,.08); }
    .pgn-field-row:last-child { border-bottom: none; }
    .pgn-field-name { font-size: 12px; color: var(--text2); flex-shrink: 0; margin-right: 12px; }
    .pgn-field-val  { font-size: 13px; font-weight: 600; color: var(--text); text-align: right; }
    .pgn-field-empty { padding: 24px 16px; color: var(--text3); font-size: 13px; text-align: center; }

    /* ── Light detail — channel cards ── */
    #chSlidersWrap {
      display: grid; grid-template-columns: 1fr; gap: 10px; margin-bottom: 10px;
    }
    @media (min-width: 540px) {
      #chSlidersWrap { grid-template-columns: 1fr 1fr; }
    }
    .ch-card {
      background: var(--surface2); border-radius: 14px; padding: 16px 18px;
    }
    .ch-card-header {
      display: flex; align-items: center; gap: 10px; margin-bottom: 14px;
    }
    .ch-card-num {
      font-size: 10px; font-weight: 700; color: var(--text3);
      background: var(--border); border-radius: 4px; padding: 2px 7px; flex-shrink: 0;
    }
    .ch-card-name { flex: 1; font-size: 15px; font-weight: 600; color: var(--text); }
    .ch-card-val {
      font-size: 22px; font-weight: 700; color: var(--accent);
      font-variant-numeric: tabular-nums; min-width: 48px; text-align: right;
    }
    .ch-slider-big {
      width: 100%; -webkit-appearance: none; appearance: none;
      height: 10px; border-radius: 5px; outline: none; cursor: pointer;
      background: linear-gradient(to right, var(--accent) 0%, var(--border) 0%);
    }
    .ch-slider-big::-webkit-slider-thumb {
      -webkit-appearance: none; width: 34px; height: 34px; border-radius: 50%;
      background: var(--accent); border: 3px solid #fff;
      box-shadow: 0 2px 8px rgba(0,0,0,.5); cursor: pointer;
    }
    .ch-slider-big::-moz-range-thumb {
      width: 28px; height: 28px; border-radius: 50%;
      background: var(--accent); border: 3px solid #fff; cursor: pointer;
    }
    .relay-card {
      display: flex; align-items: center; gap: 16px;
      background: var(--surface2); border-radius: 14px; padding: 18px;
    }
    .relay-card-info { flex: 1; }
    .relay-card-name { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 3px; }
    .relay-status { font-size: 12px; color: var(--text3); }
    .relay-btn {
      padding: 12px 32px; border-radius: 10px; font-size: 15px; font-weight: 700;
      cursor: pointer; font-family: inherit; border: 1px solid var(--border);
      transition: all .15s; letter-spacing: .04em; flex-shrink: 0;
    }
    .relay-btn.on  { background: var(--orange); border-color: var(--orange); color: #fff; box-shadow: 0 0 0 3px rgba(249,115,22,.2); }
    .relay-btn.off { background: var(--surface); color: var(--text3); }

    /* ── Preset save sheet ── */
    .preset-sheet-bg {
      position: fixed; inset: 0; z-index: 199; background: rgba(0,0,0,.45);
      display: none;
    }
    .preset-sheet {
      position: fixed; left: 0; right: 0; bottom: 0; z-index: 200;
      background: var(--surface); border-top: 1px solid var(--border);
      border-radius: 18px 18px 0 0; padding: 20px;
      max-height: 75vh; overflow-y: auto; display: none;
    }
    .preset-sheet-handle {
      width: 36px; height: 4px; background: var(--border);
      border-radius: 2px; margin: 0 auto 16px;
    }
    .preset-sheet-title {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3); margin-bottom: 16px;
    }
    .preset-save-grid {
      display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    }
    @media (max-width: 380px) { .preset-save-grid { grid-template-columns: 1fr; } }
    .preset-save-card {
      background: var(--surface2); border: 1px solid var(--border);
      border-radius: 10px; padding: 10px 12px;
      display: flex; flex-direction: column; gap: 8px;
    }
    .preset-save-card-top { display: flex; align-items: center; gap: 6px; }
    .preset-save-card-emoji { font-size: 16px; }
    .preset-edit-name {
      flex: 1; min-width: 0; background: var(--surface); border: 1px solid var(--border);
      border-radius: 6px; padding: 6px 8px; color: var(--text); font-size: 13px;
      outline: none; font-family: inherit; transition: border-color .15s;
    }
    .preset-edit-name:focus { border-color: var(--accent); }
    .preset-save-card-btn {
      width: 100%; background: var(--surface); border: 1px solid var(--border);
      border-radius: 7px; padding: 8px; font-size: 12px; font-weight: 600;
      color: var(--text2); cursor: pointer; font-family: inherit;
      transition: all .15s; display: flex; align-items: center; justify-content: center; gap: 5px;
    }
    .preset-save-card-btn:hover { background: var(--accent); border-color: var(--accent); color: #0f172a; }
    .preset-save-card-btn.saved { background: rgba(34,197,94,.15); border-color: var(--green); color: var(--green); }
    .light-section-title {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      padding-bottom: 8px; margin-bottom: 4px;
      border-bottom: 1px solid var(--border);
    }

    /* ── Chart controls ── */
    .chart-controls {
      display: flex; justify-content: space-between; align-items: center;
      flex-wrap: wrap; gap: 8px; margin-bottom: 10px;
    }
    .chart-tog-group, .chart-range-group { display: flex; gap: 4px; flex-wrap: wrap; }
    .chart-tog {
      background: var(--surface2); border: 1px solid var(--border);
      border-radius: 6px; padding: 4px 10px; font-size: 11px; font-weight: 600;
      cursor: pointer; color: var(--text3); transition: all .15s; font-family: inherit;
    }
    .chart-tog.active { color: var(--text); border-color: var(--accent2); background: rgba(6,182,212,.1); }
    .chart-range {
      background: var(--surface2); border: 1px solid var(--border);
      border-radius: 6px; padding: 4px 8px; font-size: 11px;
      cursor: pointer; color: var(--text3); transition: all .15s; font-family: inherit;
    }
    .chart-range.active { color: var(--accent); border-color: var(--accent); background: rgba(6,182,212,.08); }
    .chart-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 8px; }
    .chart-legend-item { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text2); }
    .chart-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    .chart-legend-val { font-size: 14px; font-weight: 700; }


    /* ── BMS section ── */
    .bms-section-title {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      padding-bottom: 8px; border-bottom: 1px solid var(--border);
      margin-bottom: 12px;
    }
    .bms-flags-row { display: flex; gap: 6px; flex-wrap: wrap; margin: 12px 0; }
    .bms-flag {
      display: flex; align-items: center; gap: 5px; padding: 4px 10px;
      border-radius: 20px; font-size: 11px; font-weight: 600; border: 1px solid;
    }
    .bms-flag.ok   { background: rgba(34,197,94,.1);  border-color: rgba(34,197,94,.4);  color: var(--green); }
    .bms-flag.warn { background: rgba(234,179,8,.1);  border-color: rgba(234,179,8,.4);  color: var(--yellow); }
    .bms-flag.err  { background: rgba(239,68,68,.1);  border-color: rgba(239,68,68,.4);  color: var(--red); }
    .bms-flag.off  { background: var(--surface2); border-color: var(--border); color: var(--text3); }
    .bms-cell-grid {
      display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
      gap: 8px; margin-top: 12px;
    }
    .bms-cell {
      background: var(--surface); border: 2px solid var(--border);
      border-radius: 10px; padding: 12px; text-align: center;
      transition: border-color .4s;
    }
    .bms-cell .cell-num  { font-size: 10px; color: var(--text3); margin-bottom: 6px; letter-spacing: .06em; text-transform: uppercase; }
    .bms-cell .cell-volt { font-size: 22px; font-weight: 700; line-height: 1; }
    .bms-cell .cell-temp { font-size: 13px; color: var(--text2); margin-top: 6px; }

    /* ── Battery detail layout ── */
    .bd-layout { display: grid; grid-template-columns: 1fr; gap: 14px;
      max-width: 1200px; margin: 0 auto; }
    @media (min-width: 860px) {
      .bd-layout { grid-template-columns: 340px 1fr; align-items: start; }
    }
    .bd-label { font-size: 10px; color: var(--text3); letter-spacing: .06em;
      text-transform: uppercase; margin-bottom: 4px; }
    .bd-unit { font-size: 12px; color: var(--text2); margin-left: 2px; font-weight: 400; }

    /* ── Charge source donut ── */
    .charge-src-wrap {
      display: flex; align-items: center; gap: 14px;
      background: var(--surface2); border-radius: 10px; padding: 12px 14px;
      margin-top: 12px;
    }
    .charge-src-legend { flex: 1; display: flex; flex-direction: column; gap: 7px; }
    .charge-src-row { display: flex; align-items: center; gap: 7px; font-size: 12px; }
    .charge-src-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    .charge-src-label { flex: 1; color: var(--text2); }
    .charge-src-val { font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
    .charge-src-pct { font-size: 10px; color: var(--text3); margin-left: 3px; }

    /* BMS pack row */
    .bms-pack-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
    .bms-pack-item {
      flex: 1; min-width: 90px; background: var(--surface2);
      border-radius: 8px; padding: 10px 12px;
    }
    .bms-pack-val { font-size: 17px; font-weight: 600; margin-top: 3px; }

    /* ── Connectivity icon dot ── */
    .conn-inet-wrap { position: relative; display: flex; align-items: center; justify-content: center; }
    .conn-inet-dot {
      position: absolute; bottom: -1px; right: -1px;
      width: 8px; height: 8px; border-radius: 50%;
      background: var(--text3); border: 1.5px solid var(--surface);
      transition: background .4s;
    }

    /* ── Connectivity overlay ── */
    .conn-section-title {
      font-size: 11px; font-weight: 600; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3);
      padding-bottom: 8px; border-bottom: 1px solid var(--border);
      margin-bottom: 12px;
    }
    .conn-active-banner {
      background: var(--surface2); border-radius: var(--radius);
      padding: 16px 18px; margin-bottom: 16px;
      display: flex; flex-direction: column; gap: 6px;
    }
    .conn-active-type {
      display: flex; align-items: center; gap: 10px;
    }
    .conn-active-icon { font-size: 22px; line-height: 1; }
    .conn-active-label { font-size: 20px; font-weight: 700; }
    .conn-fallback { font-size: 13px; color: var(--text2); }
    .conn-signal-bar-wrap {
      height: 6px; background: var(--surface2); border-radius: 3px;
      overflow: hidden; margin-bottom: 3px;
    }
    .conn-signal-bar-fill {
      height: 100%; border-radius: 3px;
      transition: width .6s ease, background .5s;
    }

    /* ── WiFi clients list ── */
    .wifi-client-row { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--surface2); font-size: 13px; }
    .wifi-client-row:last-child { border-bottom: none; }
    .wifi-client-name { flex: 1; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .wifi-client-ip   { font-size: 11px; color: var(--text3); font-variant-numeric: tabular-nums; white-space: nowrap; }
    .wifi-client-sig  { font-size: 11px; color: var(--text3); min-width: 55px; text-align: right; }
    .wifi-client-mac  { font-size: 10px; color: var(--text3); opacity: .6; white-space: nowrap; }
    /* ── Connectivity card grid ── */
    .conn-cards-grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
    @media (min-width: 620px) { .conn-cards-grid { grid-template-columns: 1fr 1fr; } }
    .conn-card-body { padding: 12px 14px; }

    /* SOC progress bar */
    .soc-bar-wrap {
      height: 7px; background: var(--surface2); border-radius: 4px;
      overflow: hidden; margin-bottom: 12px;
    }
    .soc-bar-fill {
      height: 100%; border-radius: 4px; background: var(--green);
      transition: width .7s ease, background .5s;
    }

    /* Mobile: compact topbar */
    @media (max-width: 500px) {
      :root { --header-basis: 51px; }
      .logo-sub, .logo-ver { display: none; }
      #topbarClock { display: none !important; }
      header { padding: 10px 12px 9px; }
      .header-right { gap: 6px; }
      .burger-menu, .quelle-pop { right: 2px; }
    }

    /* Back-arrow close button */
    .ov-close-arrow {
      background: none; border: none; color: var(--text2);
      font-size: 22px; cursor: pointer; padding: 4px 10px 4px 4px;
      line-height: 1; display: flex; align-items: center; gap: 6px;
      transition: color .15s;
    }
    .ov-close-arrow:hover { color: var(--text); }
    .ov-close-arrow svg { flex-shrink: 0; }
    /* Stauplan, Monday: CSS bei den Plugins (plugins/<id>/oberflaeche/). */
    /* ── Energiefluss (Schema im Victron-Stil) ── */
    .flow-card { max-width: 1700px; margin: 0 auto; padding: 20px 28px;
      background: radial-gradient(120% 120% at 50% 0%, #16263f 0%, #0e1a2e 100%);
      border: 1px solid var(--border); border-radius: 18px; }
    /* Fuellt die Flaeche: vorher deckelte max-width:800px das Schema, in einem
       1400px breiten Fenster stand es klein in der Mitte mit breiten Raendern. */
    .flow-schema { width: 100%; height: 100%; display: block; }
    .flow-edge { fill: none; stroke: #3c5269; stroke-width: 1.6; }
    /* animierter Fluss (Menge bekannt): laufende Punkte */
    .flow-edge-dot { fill: none; stroke-width: 4.5; stroke-linecap: round;
      stroke-dasharray: 0.1 13; opacity: 0; transition: opacity .3s; }
    .flow-edge-dot.on { opacity: 1; animation: flowdots 1s linear infinite; }
    .flow-edge-dot.flow-rev { animation-direction: reverse; }
    /* Strom fließt, Menge unbekannt: farbige Strich-Punkt-Linie, kein Lauf */
    .flow-edge-dot.static { opacity: 1; animation: none; stroke-dasharray: 7 7; stroke-width: 3.5; }
    /* Ruhende Leitung: durchgezogen und ausgegraut. Sie zeigt die Verkabelung,
       ohne zu behaupten, dass dort gerade Strom fliesst. */
    .flow-edge-dot.idle { opacity: .5; animation: none; stroke-dasharray: none;
      stroke-width: 2; stroke: #35485f; }
    @keyframes flowdots { to { stroke-dashoffset: -26; } }
    .flow-box { fill: #162438; stroke: #283d5a; stroke-width: 1.3; }
    .flow-box-main { fill: #1a3050; stroke: var(--accent); stroke-width: 2;
      filter: drop-shadow(0 0 10px rgba(6,182,212,.45)); }
    .flow-g.dim { opacity: .5; }
    .flow-g.dim .flow-box { fill: #111e30; stroke: #223347; }
    .flow-name { fill: #5a7a9c; font-size: 12px; font-weight: 600; letter-spacing: .06em;
      text-anchor: middle; text-transform: uppercase; dominant-baseline: middle; }
    .flow-val  { fill: #ddeeff; font-size: 22px; font-weight: 800; text-anchor: middle; }
    .flow-sub  { fill: #7a9ab8; font-size: 11px; text-anchor: middle; }
    .flow-icon { fill: #3d6080; stroke: #3d6080; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.3; }

    /* ── Settings: Kategorie-Navigation + Unterseiten ── */
    .set-nav { display: flex; gap: 6px; flex-wrap: wrap; padding: 14px 16px;
      position: sticky; top: 0; z-index: 5; background: var(--bg);
      border-bottom: 1px solid var(--border); }
    .set-nav-btn { background: var(--surface); border: 1px solid var(--border); color: var(--text2);
      padding: 8px 14px; border-radius: 999px; font-size: 13px; cursor: pointer; font-weight: 600;
      display: inline-flex; align-items: center; gap: 6px; transition: background .15s, color .15s, border-color .15s; }
    /* `display: inline-flex` oben schlaegt das display:none, das der Browser
       einem [hidden] gibt — ein Klassenselektor gewinnt gegen das
       Standard-Stylesheet. Der Reiter „Licht" stand deshalb weiter da, obwohl
       das Boot keine Lichtanlage hat. Muss NACH der Grunddefinition stehen. */
    .set-nav-btn[hidden] { display: none; }
    .set-nav-btn:hover { background: var(--surface2); color: var(--text); }
    .set-nav-btn.active { background: var(--accent2); color: #fff; border-color: transparent; }
    .set-pane { display: none; padding: 22px 16px 28px; max-width: 660px; margin: 0 auto; }
    .set-pane.active { display: block; }
    .set-pane-net { max-width: 100%; }
    .set-card { background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--radius); padding: 16px 18px; margin-bottom: 16px; }
    .set-card-hd { font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
      color: var(--text3); margin-bottom: 12px; }


    /* ── Datenquelle (Kopfzeile) ─────────────────────────────────────────── */
    /* Sagt, WOHER die Daten kommen — der Punkt daneben nur, OB etwas kommt. */
    .quelle-chip {
      display: flex; align-items: center; gap: 5px;
      background: none; border: 1px solid var(--border); border-radius: 999px;
      padding: 4px 9px 4px 7px; cursor: pointer;
      font-size: 11px; font-weight: 600; letter-spacing: .04em;
      color: var(--text2); transition: all .2s;
    }
    .quelle-chip:hover { border-color: var(--text3); }
    .quelle-chip.ok    { color: var(--green);  border-color: color-mix(in srgb, var(--green) 40%, transparent); }
    .quelle-chip.warn  { color: var(--yellow); border-color: color-mix(in srgb, var(--yellow) 55%, transparent);
                         background: color-mix(in srgb, var(--yellow) 12%, transparent); }
    .quelle-chip svg { flex: 0 0 auto; }
    /* Auf schmalen Geraeten bleibt nur das Symbol — die Farbe sagt ohnehin das
       Wichtigste, und die volle Aussage steht im Fenster darunter. */
    @media (max-width: 620px) { .quelle-txt { display: none; } .quelle-chip { padding: 4px 6px; } }

    .quelle-pop {
      position: fixed; top: calc(var(--header-h) + 1px); right: 2px; z-index: 130;
      width: min(320px, calc(100vw - 24px));
      background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
      box-shadow: 0 12px 32px rgba(0,0,0,.38); padding: 14px 15px;
    }
    .quelle-pop.hidden { display: none; }
    .qp-kopf { font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 11px; }
    .qp-weg  { display: flex; align-items: center; margin-bottom: 11px; }
    .qw-knoten {
      flex: 1 1 0; text-align: center; font-size: 10px; font-weight: 600;
      padding: 6px 3px; border-radius: 7px; line-height: 1.25;
      background: var(--bg); color: var(--text3); border: 1px solid var(--border);
    }
    .qw-knoten.an  { color: var(--text); border-color: var(--text3); }
    .qw-knoten.aus { color: var(--yellow); border-color: color-mix(in srgb, var(--yellow) 45%, transparent);
                     border-style: dashed; }
    .qw-strich { flex: 0 0 14px; height: 1px; background: var(--border); }
    .qp-text  { font-size: 12px; line-height: 1.5; color: var(--text2); }
    .qp-alter { font-size: 12px; color: var(--text2); margin-top: 9px;
                padding-top: 9px; border-top: 1px solid var(--border); }
    .qp-alter b { color: var(--text); }

    /* ── Kopie-Modus ─────────────────────────────────────────────────────── */
    /* Liegt nur die gespeicherte Kopie vor, muss das unuebersehbar sein und
       kein Schalter darf mehr so aussehen, als wuerde er etwas bewirken. */
    /* Der Stapel fuer alle Meldungen. Er faengt keine Klicks ab — nur die
       Karten darin tun das —, sonst laege eine unsichtbare Flaeche ueber dem
       unteren Rand der Seite. */
    .meldungen {
      position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 300;
      display: flex; flex-direction: column; gap: 8px; pointer-events: none;
    }
    .meldungen > * { pointer-events: auto; }
    .meldungen:empty { display: none; }
    /* Waehrend des Starts nicht. Sie lagen ueber dem Ladeschirm und waren die
       einzige Unruhe auf einer sonst stillen Flaeche — und was sie zu sagen
       haben, gilt ohnehin erst, wenn etwas angekommen ist. */
    html.startet .meldungen { display: none; }

    .kopie-banner {
      display: flex; align-items: center; gap: 9px;
      padding: 12px 14px; border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0,0,0,.4);
      background: color-mix(in srgb, var(--yellow) 17%, var(--surface));
      /* Rundum und nicht nur unten: als Streifen unter der Kopfzeile war der
         untere Rand die Trennlinie zur Seite, als schwebende Karte fehlte
         drumherum alles. */
      border: 1px solid color-mix(in srgb, var(--yellow) 45%, transparent);
      font-size: 12px; color: var(--text);
    }
    .kopie-banner.hidden { display: none; }
    .kb-mark {
      flex: 0 0 auto; font-size: 10px; font-weight: 800; letter-spacing: .08em;
      text-transform: uppercase; color: var(--bg); background: var(--yellow);
      padding: 3px 8px; border-radius: 5px;
    }
    .kb-txt { flex: 1 1 auto; line-height: 1.3; }
    .kb-txt b { font-weight: 700; }
    @media (max-width: 560px) {
      .kopie-banner { padding: 10px 11px; gap: 7px; font-size: 11px; align-items: center; }
      .kb-mark { font-size: 9px; padding: 2px 6px; }
    }

    /* Alles, was ans Boot schreibt, wird sichtbar stillgelegt.

       Die Liste ist aus dem laufenden DOM erhoben, nicht geraten: jeder
       Klick-Handler der Oberflaeche wurde einmal aufgelistet und danach
       einzeln einsortiert. Bewusst NICHT gesperrt ist alles, was nur die
       Ansicht aendert (Overlays oeffnen, Reiter, Zeitbereiche, Einheiten,
       Filter) — im Kopie-Modus darf man weiter alles ansehen, nur nichts
       bewirken.

       Ein Muster wie [onclick^="save"] waere kuerzer, wuerde aber irgendwann
       einen Ansichts-Handler mitnehmen, der zufaellig so heisst. Deshalb
       ausgeschriebene Namen.

       Kommt spaeter ein Schalter dazu und wird hier vergessen, bleibt er
       sichtbar bedienbar — greifen tut er trotzdem nicht: der Waechter an
       fetch() (quelle.js) laesst keine schreibende Anfrage durch. Diese
       Liste ist die Hoeflichkeit, der Waechter die Sicherung. */

    /* Schalter mit Ereignis-Empfaenger statt onclick */
    html.nur-kopie .lights-vslider,
    html.nur-kopie .lights-relay-btn,
    html.nur-kopie .preset-btn,
    html.nur-kopie .ch-slider-big,
    html.nur-kopie .hz-preset,
    html.nur-kopie .hz-mini,
    html.nur-kopie .hz-rund,
    /* Strom und Anlage */
    html.nur-kopie [onclick*="toggleRelay"],
    html.nur-kopie [onclick*="_toggleRelayFromWide"],
    html.nur-kopie [onclick*="toggleInverter"],
    html.nur-kopie [onclick*="setChargerMode"],
    html.nur-kopie [onclick*="saveChargerSettings"],
    /* Heizung */
    html.nur-kopie [onclick*="hzPreset"],
    html.nur-kopie [onclick*="hzHand"],
    html.nur-kopie [onclick*="hzModus"],
    html.nur-kopie [onclick*="hzSoll"],
    html.nur-kopie [onclick*="hzLuefter"],
    html.nur-kopie [onclick*="hzPruefen"],
    html.nur-kopie [onclick*="hzAbbrechen"],
    html.nur-kopie [onclick*="hzEinstellungenSpeichern"],
    /* System */
    html.nur-kopie [onclick*="syncTime"],
    html.nur-kopie [onclick*="runUpdate"],
    html.nur-kopie [onclick*="saveSettings"],
    html.nur-kopie [onclick*="saveRules"],
    html.nur-kopie [onclick*="ackAllAlarms"],
    /* Wartung, Stauplan, Aufgaben */
    html.nur-kopie [onclick*="saveWartungTask"],
    html.nur-kopie [onclick*="saveWartungDone"],
    html.nur-kopie [onclick*="saveWartungSettings"],
    html.nur-kopie [onclick*="addWartungCat"],
    html.nur-kopie [onclick*="deleteWartungCat"],
    html.nur-kopie [onclick*="deleteWartungTask"],
    html.nur-kopie [onclick*="saveStauEdit"],
    html.nur-kopie [onclick*="deleteStauItem"],
    html.nur-kopie [onclick*="selectFach"],
    html.nur-kopie [onclick*="createMondayItem"] {
      opacity: .34 !important; filter: grayscale(1);
      pointer-events: none !important; cursor: not-allowed !important;
    }

    /* ── Anmeldung ───────────────────────────────────────────────────────── */
    /* Legt sich ueber die Oberflaeche, statt sie zu ersetzen: der Verlauf des
       Ladens bleibt sichtbar, und nach dem Anmelden ist man dort, wo man war. */
    .anmeldung {
      position: fixed; inset: 0; z-index: 400;
      display: flex; align-items: center; justify-content: center; padding: 20px;
      background: color-mix(in srgb, var(--bg) 88%, transparent);
      backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
    }
    .anmeldung.hidden { display: none; }
    .anm-karte {
      width: min(360px, 100%); box-sizing: border-box;
      background: var(--surface); border: 1px solid var(--border);
      border-radius: 16px; padding: 26px 24px 22px;
      box-shadow: 0 20px 60px rgba(0,0,0,.45);
      display: flex; flex-direction: column; gap: 14px;
    }
    .anm-marke {
      font-size: 19px; font-weight: 700; letter-spacing: .18em;
      color: var(--accent); text-transform: uppercase; text-align: center;
    }
    .anm-marke span {
      display: block; font-size: 10px; font-weight: 500; letter-spacing: .16em;
      color: var(--text3); margin-top: 4px;
    }
    .anm-wohin {
      text-align: center; font-size: 12px; color: var(--text2);
      margin: -6px 0 4px; padding-bottom: 12px; border-bottom: 1px solid var(--border);
    }
    .anm-feld { display: flex; flex-direction: column; gap: 5px; }
    .anm-feld span {
      font-size: 10px; font-weight: 700; letter-spacing: .09em;
      text-transform: uppercase; color: var(--text3);
    }
    .anm-feld input {
      background: var(--bg); border: 1px solid var(--border); border-radius: 9px;
      padding: 11px 12px; color: var(--text); font-size: 15px; font-family: inherit;
      /* 15px und nicht kleiner: darunter zoomt iOS beim Antippen in das Feld
         hinein, und die Maske sitzt danach schief. */
      transition: border-color .15s;
    }
    .anm-feld input:focus { outline: none; border-color: var(--accent); }
    .anm-fehler {
      font-size: 12px; line-height: 1.4; color: var(--red);
      background: color-mix(in srgb, var(--red) 12%, transparent);
      border: 1px solid color-mix(in srgb, var(--red) 35%, transparent);
      border-radius: 8px; padding: 8px 10px;
    }
    .anm-fehler.hidden { display: none; }
    .anm-knopf {
      margin-top: 4px; padding: 12px; border: none; border-radius: 9px;
      background: var(--accent); color: var(--bg);
      font-size: 14px; font-weight: 700; font-family: inherit; letter-spacing: .03em;
      cursor: pointer; transition: opacity .15s;
    }
    .anm-knopf:hover { opacity: .9; }
    .anm-knopf:disabled { opacity: .55; cursor: default; }

    /* Solange die Maske steht, soll dahinter nichts scrollen oder blinken. */
    html.anmeldung-offen body { overflow: hidden; }

    /* Der Hinweis, dass noch gar kein Konto besteht — dieselbe Leiste wie beim
       Kopie-Modus, aber in ruhigerem Ton: es ist kein Fehler, sondern der
       Zustand vor der Einrichtung. */
    .kopie-banner.offen-hinweis {
      background: color-mix(in srgb, var(--accent) 13%, var(--surface));
      border-color: color-mix(in srgb, var(--accent) 40%, transparent);
    }
    .kopie-banner.offen-hinweis .kb-mark { background: var(--accent); }

    /* ── Was jemand nicht darf, steht ihm nicht im Weg ────────────────────── */
    /* Dieselbe Mechanik wie im Kopie-Modus, aus demselben Grund: ein Schalter,
       der nur abweist, ist schlimmer als keiner. Die Entscheidung faellt am
       Endpunkt — das hier ist Hoeflichkeit, kein Schutz.
       `kein-konto` nimmt die Schonfrist aus: solange es keine Konten gibt,
       ist absichtlich alles offen. */
    html:not(.darf-schalten):not(.kein-konto) .lights-vslider,
    html:not(.darf-schalten):not(.kein-konto) .lights-relay-btn,
    html:not(.darf-schalten):not(.kein-konto) .preset-btn,
    html:not(.darf-schalten):not(.kein-konto) .ch-slider-big,
    html:not(.darf-schalten):not(.kein-konto) .hz-preset,
    html:not(.darf-schalten):not(.kein-konto) .hz-rund,
    html:not(.darf-schalten):not(.kein-konto) [onclick*="toggleRelay"],
    html:not(.darf-schalten):not(.kein-konto) [onclick*="toggleInverter"],
    html:not(.darf-schalten):not(.kein-konto) [onclick*="setChargerMode"],
    html:not(.darf-schalten):not(.kein-konto) [onclick*="hzPreset"],
    html:not(.darf-schalten):not(.kein-konto) [onclick*="hzModus"],
    html:not(.darf-schalten):not(.kein-konto) [onclick*="hzSoll"] {
      opacity: .34 !important; filter: grayscale(1);
      pointer-events: none !important; cursor: not-allowed !important;
    }

    .qp-wegtitel {
      font-size: 9px; font-weight: 700; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3); margin-bottom: 6px;
    }

    /* Hinweis auf eine veraltete Seite. Unten statt oben: er soll auffallen,
       aber nicht die Kopfzeile verdecken, während man noch arbeitet. */
    .veraltet {
      display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
      padding: 12px 14px; border-radius: 12px;
      background: color-mix(in srgb, var(--yellow) 17%, var(--surface));
      border: 1px solid color-mix(in srgb, var(--yellow) 45%, transparent);
      box-shadow: 0 10px 30px rgba(0,0,0,.4);
      font-size: 12px; color: var(--text);
    }
    .veraltet .kb-txt { flex: 1 1 220px; line-height: 1.4; }
    .veraltet-knopf {
      background: var(--yellow); border: none; border-radius: 8px; color: var(--bg);
      padding: 8px 14px; font-size: 12px; font-weight: 700; font-family: inherit;
      cursor: pointer; white-space: nowrap;
      -webkit-tap-highlight-color: transparent;
      transition: filter .12s, transform .06s, opacity .12s;
    }
    /* Die Klasse setzt JS beim Druecken. `:active` waere das Naheliegende,
       wird aber auf dem Anzeigegeraet (iPad) nicht zuverlaessig angewandt. */
    .veraltet-knopf.tippt { filter: brightness(.8); transform: scale(.97); }
    html[data-zeiger="fein"] .veraltet-knopf:hover { filter: brightness(1.1); }
    /* Waehrend geraeumt und neu geladen wird. */
    .veraltet-knopf:disabled { opacity: .65; cursor: default; transform: none; }
    .veraltet-knopf:focus-visible { outline: 2px solid var(--bg); outline-offset: -4px; }
    /* Auf dem Telefon hochkant reicht die Breite fuer Marke, Text UND Knopf
       nicht. Der Knopf rutschte dann als drittes Element in eine eigene Zeile
       und stand dort linksbuendig unter dem Text — als waere er verrutscht.
       Untereinander ist es kein Unfall, sondern Absicht, und der Knopf laesst
       sich mit dem Daumen treffen. */
    @media (max-width: 560px) {
      .veraltet { flex-direction: column; align-items: stretch; gap: 9px; }
      .veraltet .kb-mark { align-self: flex-start; }
      .veraltet .kb-txt { flex: none; }
      .veraltet-knopf { width: 100%; padding: 11px 14px; font-size: 13px; }
    }

    /* ── Gäste-WLAN: frei schwebendes Popup ──────────────────────────────
       Keine eigene Seite (Eignerwunsch). Der abgedunkelte Grund faengt den
       Tipp zum Schliessen ab; die Karte selbst nicht, sonst geht das Popup zu,
       waehrend jemand scannt und dabei das Tablet anfasst. */
    .wlan-pop {
      position: fixed; inset: 0; z-index: 200;
      display: flex; align-items: center; justify-content: center;
      padding: 20px; background: rgba(4, 10, 20, .72);
      -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    }
    .wlan-pop.hidden { display: none; }
    .wlan-karte {
      position: relative; background: var(--surface);
      border: 1px solid var(--border); border-radius: 18px;
      padding: 22px 24px 20px; width: min(360px, 100%);
      box-shadow: 0 24px 60px rgba(0, 0, 0, .5); text-align: center;
    }
    .wlan-zu {
      position: absolute; top: 10px; right: 10px; width: 34px; height: 34px;
      display: inline-flex; align-items: center; justify-content: center;
      background: none; border: 0; color: var(--text3); cursor: pointer;
      border-radius: 9px; -webkit-tap-highlight-color: transparent;
    }
    html[data-zeiger="fein"] .wlan-zu:hover { color: var(--text); background: var(--surface2); }
    .wlan-titel { font-size: 12px; font-weight: 700; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text3); margin-bottom: 14px; }
    /* Weiss und mit Rand: der Code ist dunkel auf hell, und ein Teil der
       Telefone liest umgekehrte Codes nicht. Huebscher waere durchsichtig —
       aber wenn es dann nicht klappt, sucht niemand die Ursache im Farbton. */
    .wlan-qr { background: #fff; border-radius: 12px; padding: 8px;
      display: flex; justify-content: center; }
    .wlan-qr img { width: 100%; max-width: 260px; display: block; }
    .wlan-qr:has(img:not([src])) { display: none; }
    .wlan-leer { font-size: 13px; color: var(--text2); line-height: 1.5;
      padding: 24px 6px; }
    .wlan-zeilen { margin-top: 14px; display: grid; gap: 5px; }
    .wlan-zeile { display: flex; justify-content: space-between; gap: 12px;
      font-size: 14px; }
    .wlan-zeile i { font-style: normal; color: var(--text3); }
    /* Das Passwort muss man abtippen koennen, wenn das Scannen nicht klappt —
       also mit fester Schrittweite, damit l und 1 sich unterscheiden. */
    .wlan-zeile b { color: var(--text); font-weight: 600; text-align: right;
      font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
      overflow-wrap: anywhere; }
    .wlan-hinweis { margin-top: 12px; font-size: 12px; color: var(--text3);
      line-height: 1.45; }

    /* Die Eingabefelder in den Einstellungen. */
    .set-wlan-form { display: grid; gap: 10px;
      grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
    .set-wlan-form label { display: flex; flex-direction: column; gap: 4px;
      font-size: 12px; color: var(--text3); }
    .set-wlan-form .settings-input { width: 100%; max-width: none; }
    .set-wlan-rand { font-size: 11px; color: var(--yellow); }
    .set-wlan-haken { flex-direction: row !important; align-items: center;
      gap: 8px !important; color: var(--text2) !important; }

    /* ── Kontomenü ───────────────────────────────────────────────────────── */
    .konto-pop {
      position: fixed; top: calc(var(--header-basis) - 4px); right: 12px; z-index: 130;
      width: min(260px, calc(100vw - 24px));
      background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
      box-shadow: 0 12px 32px rgba(0,0,0,.38); padding: 15px 16px;
    }
    .konto-pop.hidden { display: none; }
    .kp-kopf { font-size: 15px; font-weight: 700; color: var(--text); }
    .kp-rolle { font-size: 12px; color: var(--text2); margin-top: 2px; }
    .kp-darf { font-size: 10px; color: var(--text3); margin-top: 6px; line-height: 1.5; }
    .kp-text { font-size: 12px; color: var(--text2); margin-top: 6px; line-height: 1.5; }
    .kp-tat {
      display: flex; flex-direction: column; gap: 6px;
      margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--border);
    }
    .kp-knopf {
      background: none; border: 1px solid var(--border); border-radius: 8px;
      color: var(--text2); padding: 8px 11px; font-size: 12px; font-family: inherit;
      cursor: pointer; transition: all .15s; text-align: left;
    }
    .kp-knopf:hover { border-color: var(--text3); color: var(--text); }
    .kp-knopf.warn { color: var(--red); border-color: color-mix(in srgb, var(--red) 35%, transparent); }

    .pw-regeln { list-style: none; margin: -6px 0 10px; padding: 0; }
    .pw-regeln li {
      display: flex; align-items: flex-start; gap: 8px;
      font-size: 11.5px; line-height: 1.5; color: var(--text3);
      padding: 2px 0; transition: color .2s;
    }
    .pw-regeln li.ok { color: var(--green); }
    .pw-regeln li.hinweis { opacity: .75; }
    .pw-regeln .regel-punkt { flex: 0 0 14px; text-align: center; font-weight: 700; }

    .kp-person { font-size: 11px; color: var(--text2); margin-top: 3px; line-height: 1.4; }
    a.kp-knopf { text-decoration: none; display: block; }

    /* Was jemand nicht darf, steht ihm nicht im Weg. Einstellungen und
       Geräteübersicht setzen das Recht `einstellen` voraus — die Übersicht
       nennt jedes Gerät im Bord-WLAN mit Namen, und das ist eine Aussage über
       die Anwesenheit von Menschen. `kein-konto` nimmt die Schonfrist aus:
       solange keine Konten bestehen, ist absichtlich alles offen. */
    html:not(.darf-einstellen):not(.kein-konto) #settingsBtn,
    html:not(.darf-einstellen):not(.kein-konto) #geraeteBtn,
    html:not(.darf-einstellen):not(.kein-konto) [onclick*="openGeraete"],
    html:not(.darf-einstellen):not(.kein-konto) [onclick*="openNetwork"],
    html:not(.darf-einstellen):not(.kein-konto) [onclick*="openSettings"] {
      display: none !important;
    }

    /* Hinweis waehrend eines Neustarts. Unten, ruhig, ohne Rot: es ist kein
       Fehler, sondern ein Zustand, der von selbst vorbeigeht. */
    .neustart-hinweis {
      display: flex; align-items: center; gap: 12px;
      padding: 13px 15px; border-radius: 12px;
      background: var(--surface2); border: 1px solid var(--border);
      box-shadow: 0 10px 30px rgba(0,0,0,.4);
      font-size: 12px; color: var(--text2); line-height: 1.4;
    }
    .neustart-hinweis.fertig { border-color: color-mix(in srgb, var(--green) 45%, transparent); }
    .neustart-hinweis.fertig .nh-kreis { border-top-color: var(--green); animation: none; }
    .nh-kreis {
      flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%;
      border: 2px solid var(--border); border-top-color: var(--accent);
      animation: lade-dreh .8s linear infinite;
    }
    .nh-txt { flex: 1 1 auto; }

    /* ── Vollbild-Wunsch nach einem Neuladen ──────────────────────────────── */
    /* Ein Neuladen verlaesst den Vollbild, und keine Seite darf ihn von selbst
       zurueckholen — das muss ein Griff sein. Frueher nahm sich die Seite dafuer
       den ersten Griff, der kam, egal worauf er zielte. Jetzt fragt sie. */
    #vollbildPille {
      position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
      z-index: 900; display: flex; gap: 6px; align-items: center;
      padding: 5px; border-radius: 999px;
      background: color-mix(in srgb, var(--surface) 92%, transparent);
      border: 1px solid var(--border);
      box-shadow: 0 6px 22px rgba(0, 0, 0, .28);
      backdrop-filter: blur(6px);
      font-size: 13px;
    }
    #vollbildPille button {
      border: 0; border-radius: 999px; cursor: pointer;
      font: inherit; padding: 7px 14px;
    }
    #vollbildPille .vp-haupt {
      background: var(--accent); color: var(--bg); font-weight: 600;
    }
    #vollbildPille .vp-weg {
      background: transparent; color: var(--text2); padding: 7px 10px;
    }
    #vollbildPille .vp-weg:hover { color: var(--text); }
    /* Solange die Anmeldemaske steht, hat der Vollbild zu warten: sie liegt
       ueber der Seite, und eine Schaltflaeche darunter waere nur im Weg. */
    html.anmeldung-offen #vollbildPille { display: none; }

    /* ── Der Schriftzug "Mave" ────────────────────────────────────────────── */
    /* Der Bootsname steht in "Fall in love" — der Schrift, die auch am Rumpf
       klebt. Geladen wird dafuer KEINE Schriftdatei: der Zug ist ein einziger
       Pfad, der sich nie aendert. Als Maske geladen nimmt er die Farbe seiner
       Umgebung an (background: currentColor), bleibt bei jeder Groesse scharf,
       blitzt beim Laden nicht als Ersatzschrift auf — und die Schriftdatei
       selbst muss nicht mit ausgeliefert werden (sie ist "nur privat"
       lizenziert). Der Text bleibt im Element stehen: Vorleser und die Suche
       finden ihn, er steht nur ausserhalb des sichtbaren Bereichs. */
    .marke-mave {
      /* Ohne Maskenunterstuetzung bleibt schlichter Text stehen — kein
         leeres Rechteck. Die Maskenregeln stehen deshalb im @supports. */
      font-style: italic; text-transform: none; letter-spacing: .02em;
    }
    .logo .marke-mave { color: var(--accent); }

    /* ── Bosun Reach ─────────────────────────────────────────────────────
       Die Marke des Produkts, solange kein Boot benannt ist. Kein Schriftzug
       als Maske: Buchstaben von Hand als Pfade zu zeichnen sieht aus wie von
       Hand gezeichnet. Stattdessen ordentlich gesetzter Text und ein Zeichen
       davor — das haelt sich an das SVG-Icon-System und bleibt lesbar, wenn
       jemand den Namen aendert.

       Das Zeichen ist ein Punkt mit zwei Bogen: Reichweite. Fuer ein Produkt,
       dessen Kern der Zugriff aus der Ferne ist, sagt es genau das. */
    html[data-marke="bosun"] .marke-mave {
      font-style: normal; font-weight: 600; letter-spacing: .015em;
      display: inline-flex; align-items: center; gap: .42em;
    }
    html[data-marke="bosun"] .marke-mave::before {
      content: ''; flex: none;
      width: .92em; height: .85em;
      background: currentColor;
      /* Die Daten-URI steht HIER und nicht als Datei daneben — dieselbe
         Ueberlegung wie beim Mave-Schriftzug: ein maskiertes Element ist
         unsichtbar, bis die zweite Anfrage da ist.
         Einfache Anfuehrungszeichen im SVG, `<`, `>` und `#` kodiert. Mit
         doppelten beendet das SVG die CSS-Zeichenkette, die Maske laedt nicht
         — und `background: currentColor` fuellt dann den ganzen Kasten als
         Block. Genau so sah es am 16.09.2026 aus. */
      -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 24'%3E%3Ccircle cx='5.2' cy='12' r='2.7'/%3E%3Cpath d='M11 6.6a8 8 0 0 1 0 10.8' fill='none' stroke='%23000' stroke-width='2.3' stroke-linecap='round'/%3E%3Cpath d='M16.4 3.2a13.2 13.2 0 0 1 0 17.6' fill='none' stroke='%23000' stroke-width='2.3' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / contain;
      mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 24'%3E%3Ccircle cx='5.2' cy='12' r='2.7'/%3E%3Cpath d='M11 6.6a8 8 0 0 1 0 10.8' fill='none' stroke='%23000' stroke-width='2.3' stroke-linecap='round'/%3E%3Cpath d='M16.4 3.2a13.2 13.2 0 0 1 0 17.6' fill='none' stroke='%23000' stroke-width='2.3' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / contain;
    }
    /* Auf dem Ladeschirm steht die Marke gross und allein — dort darf das
       Zeichen etwas mehr Luft haben. */
    html[data-marke="bosun"] .lade-marke { gap: .5em; }
    /* Nur fuer die Marke, zu der diese Maske gehoert (data-marke am
       Wurzelelement, aus dem Bootsprofil). Ein anderes Boot zeigt seinen
       Namen als Text — bis es eine eigene Maske mitbringt. */
    @supports ((-webkit-mask-image: url(#a)) or (mask-image: url(#a))) {
      html[data-marke="mave"] .marke-mave {
        display: inline-block; vertical-align: -.52em;
        height: 1.95em; aspect-ratio: 2.469 / 1;
        background: currentColor;
        /* Die Maske steht als Daten-URI HIER und nicht als Datei daneben.
           Sonst haengt das Zeichen an einer zweiten Anfrage — und bis die da
           ist, ist ein maskiertes Element unsichtbar. Auf dem Ladeschirm sah
           man deshalb manchmal nur den Strich ohne Schriftzug (Eignermeldung);
           der Service Worker haelt die Datei zwar vor, aber eben erst ab dem
           zweiten Besuch. Im Stylesheet ist sie da, sobald das Stylesheet da
           ist — und ohne das gaebe es ohnehin keinen Ladeschirm. */
        -webkit-mask: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 2666.7 1080.0%22><g transform=%22translate(0.1 867.0) scale(1 -1)%22><path fill=%22%23000%22 d=%22M1439.0 738.0Q1403.0 663.0 1365.0 574.5Q1327.0 486.0 1295.0 393.0Q1263.0 300.0 1242.5 207.0Q1222.0 114.0 1222.0 30.0Q1223.0 26.0 1223.0 18.0Q1223.0 16.0 1224.0 12.5Q1225.0 9.0 1224.0 7.0Q1224.0 9.0 1223.5 10.5Q1223.0 12.0 1224.0 9.0Q1228.0 -25.0 1240.0 -59.0Q1244.0 -61.0 1243.0 -61.0Q1242.0 -61.0 1242.0 -60.5Q1242.0 -60.0 1241.0 -60.0Q1242.0 -60.0 1242.5 -60.5Q1243.0 -61.0 1244.0 -61.0Q1264.0 -69.0 1279.0 -82.5Q1294.0 -96.0 1305.0 -113.0Q1307.0 -117.0 1311.5 -124.5Q1316.0 -132.0 1314.0 -137.0Q1313.0 -143.0 1306.0 -143.0Q1302.0 -143.0 1300.0 -142.0Q1269.0 -131.0 1243.0 -111.0Q1217.0 -91.0 1196.5 -65.0Q1176.0 -39.0 1163.0 -8.5Q1150.0 22.0 1146.0 54.0Q1138.0 108.0 1144.0 161.0Q1150.0 214.0 1161.0 266.0Q1180.0 357.0 1209.5 443.5Q1239.0 530.0 1274.0 615.0Q1225.0 569.0 1176.0 503.5Q1127.0 438.0 1082.0 367.0Q1037.0 296.0 998.5 226.5Q960.0 157.0 930.5 101.0Q901.0 45.0 883.5 9.5Q866.0 -26.0 863.0 -27.0Q856.0 -31.0 847.0 -31.0Q829.0 -31.0 811.5 -19.5Q794.0 -8.0 779.0 9.0Q764.0 26.0 754.0 45.0Q744.0 64.0 741.0 79.0Q733.0 119.0 738.0 160.5Q743.0 202.0 751.0 241.0Q766.0 329.0 789.0 415.0Q812.0 501.0 838.0 586.0Q813.0 543.0 777.5 481.0Q742.0 419.0 704.0 348.0Q666.0 277.0 629.0 201.5Q592.0 126.0 563.5 55.5Q535.0 -15.0 518.5 -76.0Q502.0 -137.0 505.0 -179.0Q506.0 -185.0 502.0 -190.5Q498.0 -196.0 495.0 -202.0Q493.0 -208.0 490.0 -210.5Q487.0 -213.0 479.0 -213.0Q466.0 -213.0 451.0 -203.5Q436.0 -194.0 423.5 -180.0Q411.0 -166.0 402.0 -150.5Q393.0 -135.0 391.0 -123.0Q388.0 -97.0 393.0 -71.0Q398.0 -45.0 404.0 -20.0Q413.0 19.0 424.5 57.0Q436.0 95.0 448.0 133.0Q462.0 178.0 476.5 223.5Q491.0 269.0 505.0 314.0Q519.0 360.0 533.0 405.0Q547.0 450.0 560.0 496.0Q575.0 553.0 587.5 609.5Q600.0 666.0 600.0 725.0Q598.0 736.0 596.5 745.5Q595.0 755.0 592.0 764.0Q590.0 766.0 589.5 768.0Q589.0 770.0 588.0 772.0Q587.0 772.0 587.0 772.5Q587.0 773.0 586.0 773.0Q572.0 779.0 558.0 782.0Q549.0 783.0 540.0 784.0Q531.0 785.0 522.0 785.0Q499.0 785.0 477.5 781.0Q456.0 777.0 434.0 770.0Q368.0 749.0 305.0 708.0Q242.0 667.0 193.0 611.5Q144.0 556.0 113.5 489.5Q83.0 423.0 81.0 351.0V330.0Q81.0 323.0 82.0 320.0V316.0Q87.0 271.0 101.0 232.0Q105.0 231.0 114.0 231.0Q135.0 231.0 149.5 218.0Q164.0 205.0 178.0 191.0Q180.0 189.0 184.5 182.5Q189.0 176.0 192.0 169.0Q195.0 162.0 195.0 156.0Q195.0 150.0 187.0 150.0Q185.0 149.0 179.0 149.0Q143.0 149.0 115.5 164.5Q88.0 180.0 67.5 204.5Q47.0 229.0 33.5 259.5Q20.0 290.0 12.0 321.0Q4.0 353.0 1.0 387.0Q-2.0 421.0 3.0 454.0Q11.0 516.0 38.0 573.0Q65.0 630.0 106.0 678.0Q136.0 713.0 176.0 747.0Q216.0 781.0 262.5 807.5Q309.0 834.0 358.0 850.5Q407.0 867.0 455.0 867.0Q493.0 867.0 528.0 854.0Q563.0 841.0 592.0 818.0Q621.0 795.0 642.5 764.0Q664.0 733.0 674.0 697.0Q686.0 655.0 680.0 612.0Q674.0 569.0 666.0 527.0Q653.0 468.0 636.5 411.0Q620.0 354.0 602.0 297.0Q595.0 274.0 588.0 250.5Q581.0 227.0 573.0 204.0Q637.0 331.0 705.5 454.5Q774.0 578.0 855.0 695.0Q858.0 700.0 861.0 705.5Q864.0 711.0 869.0 714.0Q873.0 716.0 875.0 716.0Q884.0 716.0 894.5 709.0Q905.0 702.0 915.5 692.5Q926.0 683.0 934.0 672.5Q942.0 662.0 945.0 655.0Q950.0 643.0 949.0 634.0Q948.0 626.0 946.5 619.0Q945.0 612.0 943.0 604.0Q935.0 574.0 926.5 544.0Q918.0 514.0 909.0 485.0Q898.0 443.0 886.5 403.0Q875.0 363.0 864.0 321.0Q850.0 262.0 837.0 202.5Q824.0 143.0 819.0 83.0Q821.0 85.0 822.0 87.0Q836.0 103.0 848.0 119.0Q860.0 135.0 872.0 152.0Q905.0 199.0 936.5 245.5Q968.0 292.0 1000.0 340.0Q1036.0 394.0 1071.5 448.0Q1107.0 502.0 1144.0 556.0Q1175.0 602.0 1207.0 646.5Q1239.0 691.0 1274.0 735.0Q1286.0 749.0 1298.0 763.0Q1310.0 777.0 1324.0 790.0Q1333.0 798.0 1343.0 805.0Q1353.0 812.0 1365.0 814.0Q1371.0 815.0 1379.0 810.0Q1387.0 805.0 1391.0 802.0Q1403.0 793.0 1413.5 782.0Q1424.0 771.0 1432.0 757.0Q1437.0 751.0 1438.0 744.0ZM103.0 227.0Q102.0 228.0 102.0 228.0ZM79.0 238.0Q79.0 237.0 80.0 237.0Q79.0 238.0 79.0 238.0ZM82.0 236.0Q81.0 237.0 80.5 237.0Q80.0 237.0 79.0 238.0Q78.0 239.0 79.0 238.5Q80.0 238.0 82.0 236.0ZM1236.0 -48.0Q1235.0 -48.0 1235.0 -46.0Q1234.0 -45.0 1234.5 -46.0Q1235.0 -47.0 1236.0 -48.0ZM1245.0 -62.0Q1244.0 -61.0 1243.0 -61.0Q1244.0 -61.0 1245.0 -62.0Z M1753.0 80.0Q1728.0 44.0 1701.0 20.5Q1674.0 -3.0 1645.0 -3.0Q1628.0 -3.0 1613.5 4.5Q1599.0 12.0 1587.5 24.0Q1576.0 36.0 1568.0 51.0Q1560.0 66.0 1556.0 81.0Q1551.0 99.0 1552.5 114.5Q1554.0 130.0 1552.0 142.0Q1546.0 134.0 1532.5 110.5Q1519.0 87.0 1503.0 62.5Q1487.0 38.0 1470.5 18.0Q1454.0 -2.0 1442.0 -2.0Q1427.0 -2.0 1409.0 8.5Q1391.0 19.0 1375.0 34.0Q1359.0 49.0 1346.5 66.5Q1334.0 84.0 1330.0 98.0Q1324.0 118.0 1325.5 138.5Q1327.0 159.0 1330.0 179.0Q1334.0 201.0 1342.5 230.0Q1351.0 259.0 1364.0 291.0Q1377.0 323.0 1394.5 353.5Q1412.0 384.0 1433.0 408.5Q1454.0 433.0 1478.5 447.5Q1503.0 462.0 1531.0 462.0Q1557.0 462.0 1580.0 447.5Q1603.0 433.0 1621.0 416.0Q1623.0 420.0 1625.5 428.5Q1628.0 437.0 1630.5 445.0Q1633.0 453.0 1635.0 459.5Q1637.0 466.0 1638.0 466.0H1640.0Q1645.0 466.0 1660.5 461.5Q1676.0 457.0 1692.5 448.5Q1709.0 440.0 1721.0 428.0Q1733.0 416.0 1731.0 401.0Q1731.0 400.0 1723.5 381.0Q1716.0 362.0 1705.5 332.5Q1695.0 303.0 1684.0 267.0Q1673.0 231.0 1665.5 196.5Q1658.0 162.0 1656.0 132.5Q1654.0 103.0 1662.0 87.0Q1668.0 78.0 1674.0 78.0Q1687.0 78.0 1705.0 102.0Q1723.0 126.0 1744.0 163.0Q1765.0 200.0 1787.0 245.0Q1809.0 290.0 1829.0 332.0Q1832.0 339.0 1837.5 341.5Q1843.0 344.0 1848.0 344.0Q1858.0 344.0 1865.5 338.5Q1873.0 333.0 1871.0 328.0Q1870.0 325.0 1860.5 299.0Q1851.0 273.0 1835.5 236.5Q1820.0 200.0 1799.0 158.0Q1778.0 116.0 1753.0 80.0ZM1439.0 123.0Q1459.0 135.0 1488.0 165.5Q1517.0 196.0 1549.5 248.0Q1582.0 300.0 1608.0 382.0Q1581.0 381.0 1557.5 366.0Q1534.0 351.0 1514.0 327.5Q1494.0 304.0 1477.5 274.5Q1461.0 245.0 1449.0 215.0Q1437.0 185.0 1428.0 156.5Q1419.0 128.0 1415.0 107.0Q1418.0 110.0 1439.0 123.0Z M2223.0 459.0 2238.0 443.0Q2240.0 441.0 2244.5 435.0Q2249.0 429.0 2253.0 422.0Q2257.0 415.0 2258.0 409.5Q2259.0 404.0 2253.0 404.0Q2251.0 403.0 2248.0 403.0Q2228.0 396.0 2211.0 379.0Q2194.0 362.0 2181.0 347.0Q2164.0 327.0 2149.0 305.5Q2134.0 284.0 2119.0 262.0Q2087.0 214.0 2055.0 166.5Q2023.0 119.0 1987.0 74.0Q1981.0 66.0 1969.5 52.5Q1958.0 39.0 1944.5 26.5Q1931.0 14.0 1917.5 5.0Q1904.0 -4.0 1892.0 -4.0Q1876.0 -4.0 1861.0 6.0Q1846.0 16.0 1835.0 25.0Q1806.0 50.0 1790.5 75.5Q1775.0 101.0 1773.0 140.0Q1771.0 167.0 1775.5 194.5Q1780.0 222.0 1786.0 248.0Q1794.0 280.0 1804.0 311.0Q1814.0 342.0 1825.0 372.0Q1827.0 377.0 1834.5 395.0Q1842.0 413.0 1851.0 432.0Q1860.0 451.0 1868.5 466.0Q1877.0 481.0 1880.0 481.0Q1888.0 481.0 1899.0 473.5Q1910.0 466.0 1921.0 456.0Q1932.0 446.0 1940.5 436.0Q1949.0 426.0 1952.0 420.0L1957.0 411.0Q1959.0 406.0 1956.0 401.0Q1938.0 371.0 1921.0 332.5Q1904.0 294.0 1890.0 253.0Q1876.0 212.0 1866.5 171.0Q1857.0 130.0 1855.0 95.0Q1867.0 105.0 1877.5 116.0Q1888.0 127.0 1897.0 138.0Q1939.0 189.0 1974.5 243.0Q2010.0 297.0 2047.0 351.0Q2064.0 375.0 2081.0 398.5Q2098.0 422.0 2118.0 443.0Q2130.0 457.0 2146.0 469.5Q2162.0 482.0 2182.0 484.0Q2188.0 485.0 2194.5 480.0Q2201.0 475.0 2206.0 472.0Q2215.0 466.0 2223.0 459.0Z M2632.0 347.0Q2637.0 349.0 2642.0 349.0Q2649.0 349.0 2654.5 344.5Q2660.0 340.0 2663.0 334.0Q2666.0 328.0 2666.5 322.0Q2667.0 316.0 2664.0 312.0Q2661.0 308.0 2641.0 282.5Q2621.0 257.0 2590.0 222.0Q2559.0 187.0 2520.0 147.5Q2481.0 108.0 2440.5 75.0Q2400.0 42.0 2361.5 20.5Q2323.0 -1.0 2292.0 0.0Q2255.0 1.0 2231.0 16.0Q2207.0 31.0 2194.0 52.0Q2180.0 72.0 2174.5 95.0Q2169.0 118.0 2170.0 135.0Q2173.0 183.0 2193.5 242.5Q2214.0 302.0 2248.5 354.0Q2283.0 406.0 2328.5 441.5Q2374.0 477.0 2426.0 477.0Q2440.0 477.0 2458.5 468.5Q2477.0 460.0 2494.5 447.0Q2512.0 434.0 2526.5 419.0Q2541.0 404.0 2547.0 392.0Q2554.0 379.0 2553.5 364.5Q2553.0 350.0 2548.0 336.0Q2541.0 312.0 2526.0 288.0Q2511.0 264.0 2491.0 244.5Q2471.0 225.0 2446.0 213.0Q2421.0 201.0 2394.0 201.0Q2370.0 201.0 2347.0 215.0Q2324.0 229.0 2306.0 244.0Q2288.0 209.0 2274.5 172.0Q2261.0 135.0 2256.0 96.0Q2254.0 80.0 2264.0 72.0Q2274.0 64.0 2286.0 64.0Q2309.0 64.0 2342.0 84.0Q2375.0 104.0 2411.5 134.0Q2448.0 164.0 2484.5 199.0Q2521.0 234.0 2550.5 265.0Q2580.0 296.0 2599.5 317.0Q2619.0 338.0 2621.0 340.0Q2626.0 345.0 2632.0 347.0ZM2320.0 268.0Q2344.0 268.0 2368.0 281.0Q2391.0 294.0 2410.5 313.5Q2430.0 333.0 2444.5 357.0Q2459.0 381.0 2465.0 402.0Q2417.0 385.0 2381.0 347.5Q2345.0 310.0 2320.0 268.0Z%22/></g></svg>") no-repeat center / contain;
                mask: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 2666.7 1080.0%22><g transform=%22translate(0.1 867.0) scale(1 -1)%22><path fill=%22%23000%22 d=%22M1439.0 738.0Q1403.0 663.0 1365.0 574.5Q1327.0 486.0 1295.0 393.0Q1263.0 300.0 1242.5 207.0Q1222.0 114.0 1222.0 30.0Q1223.0 26.0 1223.0 18.0Q1223.0 16.0 1224.0 12.5Q1225.0 9.0 1224.0 7.0Q1224.0 9.0 1223.5 10.5Q1223.0 12.0 1224.0 9.0Q1228.0 -25.0 1240.0 -59.0Q1244.0 -61.0 1243.0 -61.0Q1242.0 -61.0 1242.0 -60.5Q1242.0 -60.0 1241.0 -60.0Q1242.0 -60.0 1242.5 -60.5Q1243.0 -61.0 1244.0 -61.0Q1264.0 -69.0 1279.0 -82.5Q1294.0 -96.0 1305.0 -113.0Q1307.0 -117.0 1311.5 -124.5Q1316.0 -132.0 1314.0 -137.0Q1313.0 -143.0 1306.0 -143.0Q1302.0 -143.0 1300.0 -142.0Q1269.0 -131.0 1243.0 -111.0Q1217.0 -91.0 1196.5 -65.0Q1176.0 -39.0 1163.0 -8.5Q1150.0 22.0 1146.0 54.0Q1138.0 108.0 1144.0 161.0Q1150.0 214.0 1161.0 266.0Q1180.0 357.0 1209.5 443.5Q1239.0 530.0 1274.0 615.0Q1225.0 569.0 1176.0 503.5Q1127.0 438.0 1082.0 367.0Q1037.0 296.0 998.5 226.5Q960.0 157.0 930.5 101.0Q901.0 45.0 883.5 9.5Q866.0 -26.0 863.0 -27.0Q856.0 -31.0 847.0 -31.0Q829.0 -31.0 811.5 -19.5Q794.0 -8.0 779.0 9.0Q764.0 26.0 754.0 45.0Q744.0 64.0 741.0 79.0Q733.0 119.0 738.0 160.5Q743.0 202.0 751.0 241.0Q766.0 329.0 789.0 415.0Q812.0 501.0 838.0 586.0Q813.0 543.0 777.5 481.0Q742.0 419.0 704.0 348.0Q666.0 277.0 629.0 201.5Q592.0 126.0 563.5 55.5Q535.0 -15.0 518.5 -76.0Q502.0 -137.0 505.0 -179.0Q506.0 -185.0 502.0 -190.5Q498.0 -196.0 495.0 -202.0Q493.0 -208.0 490.0 -210.5Q487.0 -213.0 479.0 -213.0Q466.0 -213.0 451.0 -203.5Q436.0 -194.0 423.5 -180.0Q411.0 -166.0 402.0 -150.5Q393.0 -135.0 391.0 -123.0Q388.0 -97.0 393.0 -71.0Q398.0 -45.0 404.0 -20.0Q413.0 19.0 424.5 57.0Q436.0 95.0 448.0 133.0Q462.0 178.0 476.5 223.5Q491.0 269.0 505.0 314.0Q519.0 360.0 533.0 405.0Q547.0 450.0 560.0 496.0Q575.0 553.0 587.5 609.5Q600.0 666.0 600.0 725.0Q598.0 736.0 596.5 745.5Q595.0 755.0 592.0 764.0Q590.0 766.0 589.5 768.0Q589.0 770.0 588.0 772.0Q587.0 772.0 587.0 772.5Q587.0 773.0 586.0 773.0Q572.0 779.0 558.0 782.0Q549.0 783.0 540.0 784.0Q531.0 785.0 522.0 785.0Q499.0 785.0 477.5 781.0Q456.0 777.0 434.0 770.0Q368.0 749.0 305.0 708.0Q242.0 667.0 193.0 611.5Q144.0 556.0 113.5 489.5Q83.0 423.0 81.0 351.0V330.0Q81.0 323.0 82.0 320.0V316.0Q87.0 271.0 101.0 232.0Q105.0 231.0 114.0 231.0Q135.0 231.0 149.5 218.0Q164.0 205.0 178.0 191.0Q180.0 189.0 184.5 182.5Q189.0 176.0 192.0 169.0Q195.0 162.0 195.0 156.0Q195.0 150.0 187.0 150.0Q185.0 149.0 179.0 149.0Q143.0 149.0 115.5 164.5Q88.0 180.0 67.5 204.5Q47.0 229.0 33.5 259.5Q20.0 290.0 12.0 321.0Q4.0 353.0 1.0 387.0Q-2.0 421.0 3.0 454.0Q11.0 516.0 38.0 573.0Q65.0 630.0 106.0 678.0Q136.0 713.0 176.0 747.0Q216.0 781.0 262.5 807.5Q309.0 834.0 358.0 850.5Q407.0 867.0 455.0 867.0Q493.0 867.0 528.0 854.0Q563.0 841.0 592.0 818.0Q621.0 795.0 642.5 764.0Q664.0 733.0 674.0 697.0Q686.0 655.0 680.0 612.0Q674.0 569.0 666.0 527.0Q653.0 468.0 636.5 411.0Q620.0 354.0 602.0 297.0Q595.0 274.0 588.0 250.5Q581.0 227.0 573.0 204.0Q637.0 331.0 705.5 454.5Q774.0 578.0 855.0 695.0Q858.0 700.0 861.0 705.5Q864.0 711.0 869.0 714.0Q873.0 716.0 875.0 716.0Q884.0 716.0 894.5 709.0Q905.0 702.0 915.5 692.5Q926.0 683.0 934.0 672.5Q942.0 662.0 945.0 655.0Q950.0 643.0 949.0 634.0Q948.0 626.0 946.5 619.0Q945.0 612.0 943.0 604.0Q935.0 574.0 926.5 544.0Q918.0 514.0 909.0 485.0Q898.0 443.0 886.5 403.0Q875.0 363.0 864.0 321.0Q850.0 262.0 837.0 202.5Q824.0 143.0 819.0 83.0Q821.0 85.0 822.0 87.0Q836.0 103.0 848.0 119.0Q860.0 135.0 872.0 152.0Q905.0 199.0 936.5 245.5Q968.0 292.0 1000.0 340.0Q1036.0 394.0 1071.5 448.0Q1107.0 502.0 1144.0 556.0Q1175.0 602.0 1207.0 646.5Q1239.0 691.0 1274.0 735.0Q1286.0 749.0 1298.0 763.0Q1310.0 777.0 1324.0 790.0Q1333.0 798.0 1343.0 805.0Q1353.0 812.0 1365.0 814.0Q1371.0 815.0 1379.0 810.0Q1387.0 805.0 1391.0 802.0Q1403.0 793.0 1413.5 782.0Q1424.0 771.0 1432.0 757.0Q1437.0 751.0 1438.0 744.0ZM103.0 227.0Q102.0 228.0 102.0 228.0ZM79.0 238.0Q79.0 237.0 80.0 237.0Q79.0 238.0 79.0 238.0ZM82.0 236.0Q81.0 237.0 80.5 237.0Q80.0 237.0 79.0 238.0Q78.0 239.0 79.0 238.5Q80.0 238.0 82.0 236.0ZM1236.0 -48.0Q1235.0 -48.0 1235.0 -46.0Q1234.0 -45.0 1234.5 -46.0Q1235.0 -47.0 1236.0 -48.0ZM1245.0 -62.0Q1244.0 -61.0 1243.0 -61.0Q1244.0 -61.0 1245.0 -62.0Z M1753.0 80.0Q1728.0 44.0 1701.0 20.5Q1674.0 -3.0 1645.0 -3.0Q1628.0 -3.0 1613.5 4.5Q1599.0 12.0 1587.5 24.0Q1576.0 36.0 1568.0 51.0Q1560.0 66.0 1556.0 81.0Q1551.0 99.0 1552.5 114.5Q1554.0 130.0 1552.0 142.0Q1546.0 134.0 1532.5 110.5Q1519.0 87.0 1503.0 62.5Q1487.0 38.0 1470.5 18.0Q1454.0 -2.0 1442.0 -2.0Q1427.0 -2.0 1409.0 8.5Q1391.0 19.0 1375.0 34.0Q1359.0 49.0 1346.5 66.5Q1334.0 84.0 1330.0 98.0Q1324.0 118.0 1325.5 138.5Q1327.0 159.0 1330.0 179.0Q1334.0 201.0 1342.5 230.0Q1351.0 259.0 1364.0 291.0Q1377.0 323.0 1394.5 353.5Q1412.0 384.0 1433.0 408.5Q1454.0 433.0 1478.5 447.5Q1503.0 462.0 1531.0 462.0Q1557.0 462.0 1580.0 447.5Q1603.0 433.0 1621.0 416.0Q1623.0 420.0 1625.5 428.5Q1628.0 437.0 1630.5 445.0Q1633.0 453.0 1635.0 459.5Q1637.0 466.0 1638.0 466.0H1640.0Q1645.0 466.0 1660.5 461.5Q1676.0 457.0 1692.5 448.5Q1709.0 440.0 1721.0 428.0Q1733.0 416.0 1731.0 401.0Q1731.0 400.0 1723.5 381.0Q1716.0 362.0 1705.5 332.5Q1695.0 303.0 1684.0 267.0Q1673.0 231.0 1665.5 196.5Q1658.0 162.0 1656.0 132.5Q1654.0 103.0 1662.0 87.0Q1668.0 78.0 1674.0 78.0Q1687.0 78.0 1705.0 102.0Q1723.0 126.0 1744.0 163.0Q1765.0 200.0 1787.0 245.0Q1809.0 290.0 1829.0 332.0Q1832.0 339.0 1837.5 341.5Q1843.0 344.0 1848.0 344.0Q1858.0 344.0 1865.5 338.5Q1873.0 333.0 1871.0 328.0Q1870.0 325.0 1860.5 299.0Q1851.0 273.0 1835.5 236.5Q1820.0 200.0 1799.0 158.0Q1778.0 116.0 1753.0 80.0ZM1439.0 123.0Q1459.0 135.0 1488.0 165.5Q1517.0 196.0 1549.5 248.0Q1582.0 300.0 1608.0 382.0Q1581.0 381.0 1557.5 366.0Q1534.0 351.0 1514.0 327.5Q1494.0 304.0 1477.5 274.5Q1461.0 245.0 1449.0 215.0Q1437.0 185.0 1428.0 156.5Q1419.0 128.0 1415.0 107.0Q1418.0 110.0 1439.0 123.0Z M2223.0 459.0 2238.0 443.0Q2240.0 441.0 2244.5 435.0Q2249.0 429.0 2253.0 422.0Q2257.0 415.0 2258.0 409.5Q2259.0 404.0 2253.0 404.0Q2251.0 403.0 2248.0 403.0Q2228.0 396.0 2211.0 379.0Q2194.0 362.0 2181.0 347.0Q2164.0 327.0 2149.0 305.5Q2134.0 284.0 2119.0 262.0Q2087.0 214.0 2055.0 166.5Q2023.0 119.0 1987.0 74.0Q1981.0 66.0 1969.5 52.5Q1958.0 39.0 1944.5 26.5Q1931.0 14.0 1917.5 5.0Q1904.0 -4.0 1892.0 -4.0Q1876.0 -4.0 1861.0 6.0Q1846.0 16.0 1835.0 25.0Q1806.0 50.0 1790.5 75.5Q1775.0 101.0 1773.0 140.0Q1771.0 167.0 1775.5 194.5Q1780.0 222.0 1786.0 248.0Q1794.0 280.0 1804.0 311.0Q1814.0 342.0 1825.0 372.0Q1827.0 377.0 1834.5 395.0Q1842.0 413.0 1851.0 432.0Q1860.0 451.0 1868.5 466.0Q1877.0 481.0 1880.0 481.0Q1888.0 481.0 1899.0 473.5Q1910.0 466.0 1921.0 456.0Q1932.0 446.0 1940.5 436.0Q1949.0 426.0 1952.0 420.0L1957.0 411.0Q1959.0 406.0 1956.0 401.0Q1938.0 371.0 1921.0 332.5Q1904.0 294.0 1890.0 253.0Q1876.0 212.0 1866.5 171.0Q1857.0 130.0 1855.0 95.0Q1867.0 105.0 1877.5 116.0Q1888.0 127.0 1897.0 138.0Q1939.0 189.0 1974.5 243.0Q2010.0 297.0 2047.0 351.0Q2064.0 375.0 2081.0 398.5Q2098.0 422.0 2118.0 443.0Q2130.0 457.0 2146.0 469.5Q2162.0 482.0 2182.0 484.0Q2188.0 485.0 2194.5 480.0Q2201.0 475.0 2206.0 472.0Q2215.0 466.0 2223.0 459.0Z M2632.0 347.0Q2637.0 349.0 2642.0 349.0Q2649.0 349.0 2654.5 344.5Q2660.0 340.0 2663.0 334.0Q2666.0 328.0 2666.5 322.0Q2667.0 316.0 2664.0 312.0Q2661.0 308.0 2641.0 282.5Q2621.0 257.0 2590.0 222.0Q2559.0 187.0 2520.0 147.5Q2481.0 108.0 2440.5 75.0Q2400.0 42.0 2361.5 20.5Q2323.0 -1.0 2292.0 0.0Q2255.0 1.0 2231.0 16.0Q2207.0 31.0 2194.0 52.0Q2180.0 72.0 2174.5 95.0Q2169.0 118.0 2170.0 135.0Q2173.0 183.0 2193.5 242.5Q2214.0 302.0 2248.5 354.0Q2283.0 406.0 2328.5 441.5Q2374.0 477.0 2426.0 477.0Q2440.0 477.0 2458.5 468.5Q2477.0 460.0 2494.5 447.0Q2512.0 434.0 2526.5 419.0Q2541.0 404.0 2547.0 392.0Q2554.0 379.0 2553.5 364.5Q2553.0 350.0 2548.0 336.0Q2541.0 312.0 2526.0 288.0Q2511.0 264.0 2491.0 244.5Q2471.0 225.0 2446.0 213.0Q2421.0 201.0 2394.0 201.0Q2370.0 201.0 2347.0 215.0Q2324.0 229.0 2306.0 244.0Q2288.0 209.0 2274.5 172.0Q2261.0 135.0 2256.0 96.0Q2254.0 80.0 2264.0 72.0Q2274.0 64.0 2286.0 64.0Q2309.0 64.0 2342.0 84.0Q2375.0 104.0 2411.5 134.0Q2448.0 164.0 2484.5 199.0Q2521.0 234.0 2550.5 265.0Q2580.0 296.0 2599.5 317.0Q2619.0 338.0 2621.0 340.0Q2626.0 345.0 2632.0 347.0ZM2320.0 268.0Q2344.0 268.0 2368.0 281.0Q2391.0 294.0 2410.5 313.5Q2430.0 333.0 2444.5 357.0Q2459.0 381.0 2465.0 402.0Q2417.0 385.0 2381.0 347.5Q2345.0 310.0 2320.0 268.0Z%22/></g></svg>") no-repeat center / contain;
        /* Der Text raus aus dem Bild, aber im Dokument. */
        text-indent: -9999px; overflow: hidden; white-space: nowrap;
      }
    }

    /* ── Das eine Menü ────────────────────────────────────────────────────── */
    /* Oben steht in einer Zeile, wer angemeldet ist; darunter führt ein Knopf
       in die Kontoansicht DESSELBEN Menüs. Vorher war das ein zweites
       Klappfeld daneben, und beide konnten gleichzeitig offen sein — sie lagen
       dann übereinander. */
    .burger-menu { min-width: 216px; }
    .bm-wer {
      display: flex; flex-direction: column; gap: 1px;
      padding: 9px 11px 8px; line-height: 1.3;
    }
    .bm-wer b { font-size: 13.5px; font-weight: 650; color: var(--text); }
    .bm-wer span { font-size: 11px; color: var(--text3); }
    .bm-wer-leer { font-size: 12.5px; color: var(--text3); }
    .bm-konto .bm-pfeil { margin-left: auto; display: flex; color: var(--text3); }
    .bm-zurueck { color: var(--text3) !important; }

    /* Der Trennstrich zwischen Konto und den übrigen Seiten. */
    .burger-trenner {
      height: 1px; background: var(--border); margin: 6px 8px;
    }

    .bm-konto-kopf  { padding: 4px 11px 0; font-size: 15px; font-weight: 700; }
    .bm-konto-neben { padding: 1px 11px 0; font-size: 11px; color: var(--text3); }
    .bm-konto-rolle { padding: 3px 11px 0; font-size: 12px; color: var(--accent); font-weight: 600; }
    .bm-konto-darf  { padding: 2px 11px 6px; font-size: 10.5px; color: var(--text3); line-height: 1.5; }
    .bm-warn { color: var(--red) !important; }

    /* Steht Wartung an, sieht man das am Burger — ohne ihn zu öffnen. */
    .burger-punkt {
      position: absolute; top: 5px; right: 5px;
      width: 7px; height: 7px; border-radius: 50%;
      background: var(--yellow); pointer-events: none;
    }
    .bm-punkt {
      margin-left: auto; width: 7px; height: 7px; border-radius: 50%;
      background: var(--yellow); flex: 0 0 auto;
    }

    /* ── Verbindung: ein Zeichen, zwei Aussagen ───────────────────────────── */
    /* Das Zeichen sagt WOHER die Daten kommen, der Punkt WIE GUT die Leitung
       dafür ist. Vorher waren das drei Anzeigen nebeneinander. */
    .quelle-guete {
      width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
      margin-left: 1px; box-shadow: 0 0 0 2px var(--surface);
    }
    .qp-guete {
      display: flex; align-items: center; gap: 8px;
      margin: 10px 0 2px; font-size: 12px; color: var(--text2);
    }
    .qp-guete i { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
    .qp-mehr {
      margin-left: auto; background: none; border: 1px solid var(--border);
      border-radius: 7px; color: var(--text2); padding: 4px 9px;
      font-size: 11px; font-family: inherit; cursor: pointer;
    }
    .qp-mehr:hover { border-color: var(--text3); color: var(--text); }

    /* ── Fußzeile ─────────────────────────────────────────────────────────── */
    /* Die Fassungsnummer stand in der Kopfzeile neben dem Bootsnamen und nahm
       dort Platz weg. Sie wird selten gelesen — hier steht sie, wenn man sie
       sucht, und sonst niemandem im Weg. */
    .seitenfuss {
      padding: 4px 20px calc(18px + env(safe-area-inset-bottom));
      text-align: center; font-size: 10.5px; color: var(--text3);
      letter-spacing: .04em;
    }

    /* ── Reiter auf zusammengehörenden Seiten ─────────────────────────────── */
    /* "Wartung" und "Netzwerk" waren vier Einträge im Menü für zwei Fragen.
       Jetzt sind es zwei Seiten mit Reitern — der Inhalt blieb, wo er war. */
    .ov-reiter {
      display: flex; gap: 4px; padding: 8px 16px 0;
      border-bottom: 1px solid var(--border);
      background: var(--surface); flex: 0 0 auto;
      overflow-x: auto; scrollbar-width: none;
    }
    .ov-reiter::-webkit-scrollbar { display: none; }
    .ov-reiter-knopf {
      background: none; border: none; border-bottom: 2px solid transparent;
      color: var(--text3); font-family: inherit; font-size: 13px; font-weight: 600;
      padding: 8px 12px 9px; cursor: pointer; white-space: nowrap;
      transition: color .15s, border-color .15s;
    }
    .ov-reiter-knopf:hover { color: var(--text2); }
    .ov-reiter-knopf.an { color: var(--accent); border-bottom-color: var(--accent); }

    /* ── Das Kontofeld klappt nach links auf ──────────────────────────────── */
    /* Das Menü steht am rechten Rand — ein Feld, das sich von dort nach rechts
       öffnet, hätte keinen Platz. Feste Breite fürs Menü, damit die Kante des
       Kontofeldes daneben ohne Messen stimmt. */
    .burger-menu { width: 232px; min-width: 0; }
    /* Bündig ans Menü: dessen linke Kante liegt bei 2 px Abstand plus 232 px
       Breite, also 234 px vom rechten Rand. Kein Spalt dazwischen — die beiden
       Felder gehören zusammen und sollen auch so aussehen. */
    .burger-konto {
      position: fixed; top: calc(var(--header-h) + 1px); right: 234px; z-index: 200;
      width: 232px;
      background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
      padding: 6px; display: flex; flex-direction: column; gap: 2px;
      box-shadow: 0 8px 24px rgba(0,0,0,.4);
    }
    .burger-konto.hidden { display: none; }
    .burger-item.bm-konto.an { background: var(--surface2); color: var(--text); }

    /* Schmal ist für zwei Felder nebeneinander kein Platz. Dann tritt die
       Hauptliste zurück und das Konto nimmt ihren Platz ein — mit dem
       Zurück-Pfeil oben bleibt der Weg derselbe. */
    @media (max-width: 620px) {
      .burger-konto { right: 2px; }
      html.bm-konto-auf .burger-menu { display: none; }
    }

    /* ── Alarm wartet auf Ton ─────────────────────────────────────────────── */
    /* Browser lassen Ton erst zu, nachdem jemand die Seite berührt hat. Kommt
       davor ein Alarm, verschwindet er nicht still — er wartet sichtbar und
       geht beim ersten Antippen los. */
    .ton-hinweis {
      position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
      z-index: 950; display: flex; align-items: center; gap: 11px;
      max-width: min(520px, calc(100vw - 24px));
      padding: 11px 15px; border-radius: 12px; cursor: pointer;
      background: color-mix(in srgb, var(--red) 16%, var(--surface));
      border: 1px solid color-mix(in srgb, var(--red) 45%, transparent);
      box-shadow: 0 8px 26px rgba(0, 0, 0, .45);
      font-size: 13px; color: var(--text); line-height: 1.4;
    }
    .ton-hinweis .th-mark {
      font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
      background: var(--red); color: #240b0b; border-radius: 5px;
      padding: 3px 8px; flex: 0 0 auto;
    }

    /* ── Meldeweg wählen ──────────────────────────────────────────────────── */
    /* Vier Möglichkeiten mit je einem Satz Erklärung — ein Auswahlfeld mit vier
       Wörtern hätte den Unterschied verschwiegen, und genau der ist hier das
       Entscheidende (welcher Lautstärkeregler gilt). */
    .al-weg {
      display: flex; align-items: flex-start; gap: 11px;
      padding: 11px 12px; border-radius: 10px; cursor: pointer;
      border: 1px solid var(--border); margin-bottom: 8px;
      transition: border-color .15s, background .15s;
    }
    .al-weg:hover { border-color: var(--text3); }
    .al-weg.an { border-color: var(--accent); background: rgba(6,182,212,.08); }
    .al-weg input { margin-top: 3px; accent-color: var(--accent); flex: 0 0 auto; }
    .al-weg-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
    .al-weg-text b { font-size: 13.5px; font-weight: 650; }
    .al-weg-text span { font-size: 12px; color: var(--text2); line-height: 1.5; }

    /* ── Geräteseite ──────────────────────────────────────────────────────── */
    /* Neu gebaut. Vorher erfand die Seite ein Dutzend eigener Bausteine
       (ger-summary, ger-stat, ger-quelle, ger-toolbar, ger-seg, ger-tile …) und
       sah dadurch aus wie aus einer anderen Anwendung. Jetzt trägt sie
       .set-card wie die Einstellungen und die Farbtoken wie alles andere;
       eigen ist nur, was es sonst nirgends gibt. */
    #gerInhalt { max-width: 860px; margin: 0 auto; padding: 18px 16px 60px; }

    /* Die Antwort zuerst. Zahlen sagen nicht, ob etwas in Ordnung ist. */
    .ger-antwort {
      padding: 16px 18px; border-radius: var(--radius);
      background: var(--surface); border: 1px solid var(--border);
      border-left: 3px solid var(--text3); margin-bottom: 14px;
    }
    .ger-antwort.gut      { border-left-color: var(--green); }
    .ger-antwort.mau      { border-left-color: var(--yellow); }
    .ger-antwort.schlecht { border-left-color: var(--red); }
    .ger-antwort-satz { font-size: 17px; font-weight: 650; }
    .ger-antwort.gut      .ger-antwort-satz { color: var(--green); }
    .ger-antwort.mau      .ger-antwort-satz { color: var(--yellow); }
    .ger-antwort.schlecht .ger-antwort-satz { color: var(--red); }
    .ger-antwort-neben { font-size: 12.5px; color: var(--text2); margin-top: 3px; }

    .ger-sorgen { border-left: 3px solid var(--red); }

    /* Eine Zeile, überall dieselbe: Punkt, Name mit Nebenzeile, Wert, Marke. */
    .ger-liste { display: flex; flex-direction: column; }
    .ger-zeile {
      display: flex; align-items: center; gap: 11px; width: 100%;
      background: none; border: none; border-top: 1px solid var(--border);
      padding: 10px 2px; text-align: left; color: var(--text);
      font-family: inherit; font-size: 13.5px; cursor: pointer;
    }
    .ger-zeile:first-child { border-top: none; }
    .ger-zeile:hover { background: var(--surface2); }
    .ger-zeile-still { cursor: default; }
    .ger-zeile-still:hover { background: none; }
    .ger-punkt {
      width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
      background: var(--text3);
    }
    .ger-punkt.s-online { background: var(--green); }
    .ger-punkt.s-traege { background: var(--yellow); }
    .ger-punkt.s-offline, .ger-punkt.s-unbekannt { background: var(--red); }
    .ger-zeile-mitte { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
    .ger-zeile-name { font-weight: 600; }
    .ger-zeile-sub  { font-size: 11.5px; color: var(--text3); }
    .ger-zeile-wert {
      font-size: 11.5px; color: var(--text3); white-space: nowrap;
      font-variant-numeric: tabular-nums;
    }
    .ger-zeile-wert b { color: var(--text2); font-weight: 600; }
    .ger-marke {
      font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
      padding: 2px 8px; border-radius: 20px; white-space: nowrap;
      color: var(--text3); border: 1px solid var(--border);
    }
    .ger-marke.s-online { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, transparent); }
    .ger-marke.s-traege { color: var(--yellow); border-color: color-mix(in srgb, var(--yellow) 45%, transparent); }
    .ger-marke.s-offline, .ger-marke.s-unbekannt {
      color: var(--red); border-color: color-mix(in srgb, var(--red) 45%, transparent); }
    .ger-neu {
      font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
      color: var(--accent); margin-left: 6px;
    }
    /* Zwischenüberschrift in der Liste — dieselbe Gestalt wie überall sonst. */
    .ger-gruppe {
      display: flex; align-items: baseline; gap: 8px;
      font-size: 9.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
      color: var(--text3); margin: 16px 0 2px; padding-top: 12px;
      border-top: 1px solid var(--border);
    }
    .ger-gruppe:first-child { margin-top: 0; padding-top: 0; border-top: none; }
    .ger-gruppe span { margin-left: auto; letter-spacing: 0; font-weight: 600; }
    .ger-leer { padding: 22px 4px; text-align: center; font-size: 13px; color: var(--text3); }

    /* Suche und Ansichtswahl */
    .ger-werkzeug { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 16px 0 12px; }
    .ger-suche {
      flex: 1; min-width: 180px; display: flex; align-items: center; gap: 8px;
      background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
      padding: 8px 12px; color: var(--text3);
    }
    .ger-suche input {
      flex: 1; min-width: 0; background: none; border: none; outline: none;
      color: var(--text); font-family: inherit; font-size: 13.5px;
    }
    .ger-wahl { display: flex; background: var(--surface); border: 1px solid var(--border);
      border-radius: 10px; overflow: hidden; }
    .ger-wahl button {
      background: none; border: none; color: var(--text3); font-family: inherit;
      font-size: 12.5px; padding: 8px 12px; cursor: pointer;
    }
    .ger-wahl button.an { background: var(--surface2); color: var(--accent); font-weight: 600; }
    .ger-nur {
      background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
      color: var(--text3); font-family: inherit; font-size: 12.5px; padding: 8px 12px;
      cursor: pointer;
    }
    .ger-nur.an { border-color: var(--red); color: var(--red); }
