/* ============================================================================
 * PWA Toolpoint — geteilte Stile (alle Seiten).
 *
 * HERKUNFT (Klaus 2026-08-09): Vorlage ist der Marktplatz aus family-project —
 * technisch die ausgereifteste Fassung im Netz. Von dort kommen die
 * Farb-Marken, die Glas-Knopf-Konstruktion (.btn mit ::before/::after) und die
 * Listing-Karten. Die nüchterne, erwachsene Haltung kommt von
 * SB·KIMTool·Point: Mono-Akzente, sachliche Abschnitts-Marken, keine Analogien.
 * Die Ähnlichkeit ist gewollt und wird nicht geleugnet — es ist dieselbe
 * Familie, und der offene Markt soll man ihr ansehen.
 *
 * WAS BEWUSST FEHLT — und warum (jedes gemessen, nicht gemeint):
 *
 *  - KEIN WebGL-Hintergrund. Auf einem Gerät ohne Grafikchip — und JEDES
 *    Prüfgerät bei PageSpeed ist eins — kostet die Dauerschleife Sekunden
 *    Blockierzeit. Gemessen (family-project 2026-08-08): mit Hintergrund
 *    65 · 56, ohne 89 · 94; Blockierzeit 8,9 s → 0,09 s. Klaus' Entscheid vom
 *    selben Tag: auf einem Gerät ohne Chip GAR KEIN Hintergrund, nicht einmal
 *    ein stehendes Bild. Hier gibt es ihn deshalb überhaupt nicht — der
 *    Farbschleier unten ist ein reiner CSS-Verlauf und kostet nichts.
 *
 *  - KEINE geladene Schrift. Systemschriften sparen einen Netzweg auf dem
 *    kritischen Pfad. Ein Markt, der mit gemessenen Ladezeiten wirbt, sollte
 *    selbst schnell sein.
 *
 *  - KEIN Themen-Umschalter (noch nicht). Ein Thema, dessen Kontraste
 *    ausgerechnet sind, ist mehr wert als drei geschätzte. Kontrast gilt PRO
 *    Thema (Bauregel Layout 2.3) — jedes weitere ist eine eigene Rechnung.
 *
 * KONTRAST — ausgerechnet am 2026-08-09, nicht geschätzt:
 *   Text  #eef2f8 auf #0b0d14 …… 17,28 : 1
 *   Leise #9aa7b6 auf #0b0d14 ……  7,93 : 1   · auf der Karte 7,40 : 1
 *   Akzent #6ee7d3 auf #0b0d14 … 12,97 : 1
 *   Knopfschrift #08121a auf dem DUNKELSTEN Punkt des Verlaufs … 6,94 : 1
 *   Fokusring #ffd166 auf #0b0d14 … 13,46 : 1
 * Wer eine Farbe ändert, rechnet nach (Bauregel Layout 2.1/2.2) — auch die
 * Deckkraft gehört in die Rechnung.
 * ========================================================================== */

:root {
  /* ---- Nacht (Standard) --------------------------------------------------
   * Warmer Bernstein auf kühlem Graphit. Family Projekt ist Minze auf
   * Blauschwarz — dieselbe Bauart, anderer Ton. Man sieht die Verwandtschaft
   * und verwechselt die beiden trotzdem nicht. */
  --bg:      #0c1016;
  --bg2:     #151b24;
  --card:    rgba(27, 35, 48, .55);
  --line:    rgba(255, 255, 255, .10);
  --text:    #e9eff5;
  --muted:   #9aa8b6;
  --accent:  #f2b544;
  --accent2: #7fb2e8;
  --accent3: #b98ce0;
  --knopftext: #1a1204;
  --aus:     #7c8794;
  --ok:      #46d27f;

  --header-bg: rgba(12, 16, 22, .58);
  --glow:   0 0 26px rgba(242, 181, 68, .26), 0 0 60px rgba(185, 140, 224, .14);
  --shadow: 0 12px 34px rgba(0, 0, 0, .40), 0 4px 10px rgba(0, 0, 0, .25);
  --schleier1: rgba(127, 178, 232, .13);
  --schleier2: rgba(242, 181, 68, .09);

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --focus: #ffd166;
  --breite: 1060px;
}

/* ---- Signal — Werkstatt-Kontrast, Orange auf fast Schwarz ---------------- */
html[data-thema="signal"] {
  --bg:      #07090c;
  --bg2:     #0e1319;
  --card:    rgba(19, 26, 34, .60);
  --line:    rgba(255, 255, 255, .12);
  --text:    #f2f6fa;
  --muted:   #a3b1bf;
  --accent:  #ff8a3d;
  --accent2: #38d6d6;
  --accent3: #c58cff;
  --knopftext: #180a02;
  --aus:     #87929e;
  --header-bg: rgba(7, 9, 12, .62);
  --glow:   0 0 26px rgba(255, 138, 61, .30), 0 0 60px rgba(56, 214, 214, .16);
  --schleier1: rgba(56, 214, 214, .12);
  --schleier2: rgba(255, 138, 61, .10);
  --focus: #ffe14d;
}

/* ---- Tag — hell ---------------------------------------------------------
 * Bernstein verschwindet auf Weiß. Hier markiert ein kräftiges Kupferbraun;
 * der Fokusring wird Blau, weil Gold auf Hell nicht mehr zu sehen wäre. */
html[data-thema="tag"] {
  --bg:      #f5f6f8;
  --bg2:     #e9ecf1;
  --card:    rgba(255, 255, 255, .72);
  --line:    rgba(20, 30, 45, .14);
  --text:    #141b24;
  --muted:   #4f5d6e;
  --accent:  #8a5a12;
  --accent2: #1f5fb0;
  --accent3: #6b3fa8;
  --knopftext: #ffffff;
  --aus:     #5d6b7c;
  --header-bg: rgba(245, 246, 248, .82);
  --glow:   0 8px 26px rgba(31, 95, 176, .16);
  --shadow: 0 10px 28px rgba(20, 30, 45, .10), 0 3px 8px rgba(20, 30, 45, .07);
  --schleier1: rgba(31, 95, 176, .09);
  --schleier2: rgba(138, 90, 18, .07);
  --focus: #0f3ec4;
}

/* KONTRAST — ausgerechnet am 2026-08-09, JE THEMA, nicht geschätzt.
 * Kontrast gilt pro Thema (Bauregel Layout 2.3): eine Farbe, die im Dunkeln
 * trägt, kann im Hellen durchfallen. Alle 36 geprüften Paare bestehen; die
 * schwächste Stelle ist die ausgeschaltete Relais-Pille im Tag-Thema mit
 * 4,59 : 1 (gefordert 4,5). Wer eine Farbe ändert, rechnet ALLE DREI nach —
 * das Skript dafür steht im Kopf von tests/kontrast.mjs. */

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

/* ── Tastatur-Fokus sichtbar machen ──────────────────────────────────────────
 * `:focus-visible` statt `:focus`: der Ring erscheint bei Tastatur- und
 * Stift-Bedienung, nicht beim Mausklick auf einen Knopf. Textfelder zählen laut
 * Norm immer als focus-visible — dort ist er also auch mit der Maus zu sehen,
 * und das ist richtig so.
 *
 * `outline` und nicht `box-shadow`: ein Schatten würde die Glas-Knopf-Schatten
 * überschreiben und die Optik zerlegen. Ein Outline liegt außerhalb, klemmt
 * kein Layout und überschreibt nichts.
 *
 * `outline:none` ohne Ersatz ist hier verboten (Bauregel Layout 3.4). */
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  overflow-x: hidden;
  min-height: 100vh;
}

/* Farbschleier statt Grafik-Schleife: zwei Radial-Verläufe, fest positioniert,
   keine Rechenzeit je Bild. Das ist der ganze „Hintergrund". */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(60% 50% at 78% 0%,   var(--schleier1), transparent 60%),
    radial-gradient(55% 45% at 5% 100%,  var(--schleier2), transparent 60%);
}

.wrap { max-width: var(--breite); margin: 0 auto; padding: 0 20px; }
.muted { color: var(--muted); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------------------------------------------------------------- Kopfleiste
 * `min-height` an der Leiste, nicht nur an ihrem Inhalt: eine Leiste mit
 * `flex-wrap` bricht um, sobald EIN Kind breiter wird, und schiebt dann alles
 * darunter (Bauregel Layout 1.2 — bei Point kostete genau das 50 px auf einen
 * Schlag). Die Höhe steht deshalb fest, bevor irgendetwas geladen ist. */
header {
  position: sticky; top: 0; z-index: 30;
  background: var(--header-bg);
  backdrop-filter: blur(16px) saturate(1.3);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  border-bottom: 1px solid var(--line);
}
.bar {
  display: flex; align-items: center; gap: 14px;
  min-height: 60px; flex-wrap: wrap; padding: 6px 0;
}
.brand {
  display: flex; align-items: center; gap: 11px;
  font-weight: 800; font-size: 1.14rem; color: var(--text);
}
.brand:hover { text-decoration: none; }
.brand .mark {
  width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0;
  background: linear-gradient(135deg, var(--accent), var(--accent3) 55%, var(--accent2));
  box-shadow: var(--glow);
}
/* ---- Status-Lampen + Siegel-Platz ------------------------------------------
 * `min-height: 34px` ist die wichtigste Zeile in dieser Datei.
 *
 * Modul 16 hängt sein Siegel-Abzeichen (34 × 34) NACH dem Laden in genau
 * diesen Container. Ohne die reservierte Höhe wächst die Leiste von 9 px auf
 * 34 px und schiebt die ganze Seite nach unten. Bei SB·KIMTool·Point gemessen:
 * CLS 0,103 → 0,052 durch diese eine Zeile.
 *
 * Die Lampen selbst sind Punkte ohne Aufregung: sie leuchten nur bei einem
 * echten Ereignis. Wo nichts passiert, leuchtet nichts — auch das ist eine
 * Aussage, und eine ehrlichere als eine Lampe, die immer grün ist. */
.lamps {
  display: flex; gap: 1rem; flex-wrap: wrap;
  min-height: 34px; align-items: center;
}
.lamp {
  display: inline-flex; align-items: center; gap: .35rem;
  font-family: var(--mono); font-size: .74rem; color: var(--muted);
}
.lamp::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--aus); box-shadow: none;
  transition: background .25s, box-shadow .25s;
}
.lamp.on::before   { background: var(--ok);    box-shadow: 0 0 8px var(--ok); }
.lamp.warn::before { background: var(--gold);  box-shadow: 0 0 8px var(--gold); }
.lamp.bad::before  { background: #ff6b6b;      box-shadow: 0 0 8px #ff6b6b; }
.lamp.traffic-pulse::before { animation: lampen-puls .9s ease-out; }
@keyframes lampen-puls {
  0%   { background: var(--accent); box-shadow: 0 0 12px var(--accent); }
  100% { background: var(--ok);     box-shadow: 0 0 8px var(--ok); }
}
/* Am schmalen Bildschirm nur die Punkte — die Beschriftung würde die Leiste
   umbrechen lassen, und eine umbrechende Kopfleiste ist eine Sprungfalle. */
@media (max-width: 700px) { .lamp .lamp-label { display: none; } }

nav.top { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
nav.top a {
  color: var(--muted); font-size: .9rem;
  /* 8px oben/unten + 1.6er Zeilenhöhe ≈ 37 px hoch — über den geforderten
     24 px Berührungsziel (Bauregel Layout 3.1). */
  padding: 8px 12px; border-radius: 10px;
  transition: color .15s, background .2s;
}
nav.top a:hover, nav.top a:focus-visible {
  color: var(--text); background: rgba(255, 255, 255, .06); text-decoration: none;
}
nav.top a[aria-current="page"] { color: var(--text); }

/* -------------------------------------------------------------------- Flächen */
section { padding: 34px 0; }
section.oben { padding-top: 44px; }

h1 { font-size: clamp(1.75rem, 4.4vw, 2.6rem); line-height: 1.18; margin: 0 0 14px; font-weight: 800; }
h2 { font-size: 1.4rem; margin: 0 0 8px; font-weight: 700; }
h3 { font-size: 1.05rem; margin: 0 0 6px; font-weight: 650; }

.lead { font-size: 1.08rem; color: var(--muted); margin: 0 0 22px; max-width: 62ch; }
.sub  { color: var(--muted); margin: 0 0 16px; max-width: 70ch; }
.hinweis { color: var(--muted); font-size: .88rem; white-space: pre-line; }
.klein { font-size: .84rem; color: var(--muted); }

/* Mono-Abschnittsmarke — die nüchterne Note von SB·KIMTool·Point. */
.marke-klein {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 6px;
}

.glass {
  background: var(--card); border: 1px solid var(--line); border-radius: 16px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow);
}

/* ------------------------------------------------------------ Glas-Knöpfe
 * Konstruktion 1:1 aus dem family-project-Marktplatz: geschliffene Kante über
 * inset-Schatten, darüber zwei Ebenen (::before Schimmer, ::after Kantenlicht),
 * die dem Zeiger folgen (--mx/--my aus app.js, mit rAF gedrosselt).
 *
 * Ohne JavaScript stehen die Voreinstellungen 50 %/24 % — der Knopf sieht dann
 * genauso aus, nur ohne Verfolgung. Fail-soft bis in die Optik. */
.btn {
  position: relative; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--sans); font-weight: 700; font-size: .96rem; line-height: 1.2;
  padding: 13px 22px; border-radius: 14px; border: 1px solid transparent;
  overflow: hidden; text-decoration: none; cursor: pointer;
  transform: perspective(640px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform .14s ease, box-shadow .2s ease;
  box-shadow:
    inset 0 2px 1px rgba(255, 255, 255, .70),
    inset 0 -5px 9px rgba(0, 0, 0, .52),
    inset 11px 0 17px rgba(255, 255, 255, .07),
    inset -11px 0 19px rgba(0, 0, 0, .42),
    inset 0 0 0 1px rgba(255, 255, 255, .12),
    0 14px 30px rgba(0, 0, 0, .48), 0 4px 8px rgba(0, 0, 0, .36);
}
.btn:hover { text-decoration: none; }
.btn::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background:
    radial-gradient(108px 76px at var(--mx, 50%) var(--my, 24%), rgba(255, 255, 255, .72), transparent 56%),
    linear-gradient(180deg, rgba(255, 255, 255, .36), rgba(255, 255, 255, 0) 46%),
    linear-gradient(115deg, transparent 26%,
      color-mix(in srgb, var(--accent3) 62%, transparent) 43%,
      color-mix(in srgb, var(--accent)  58%, transparent) 51%,
      color-mix(in srgb, var(--accent2) 62%, transparent) 60%, transparent 76%);
  background-size: auto, auto, 240% 100%;
  background-position: 0 0, 0 0, var(--mx, 50%) 0;
  mix-blend-mode: screen; opacity: .45; transition: opacity .22s;
}
.btn::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(60% 140% at var(--mx, 50%) -10%, rgba(255, 255, 255, .5), transparent 40%);
  mix-blend-mode: screen; opacity: 0; transition: opacity .22s;
}
.btn:hover::before, .btn:focus-visible::before { opacity: 1; }
.btn:hover::after,  .btn:focus-visible::after  { opacity: .85; }

.btn.primary {
  background: linear-gradient(135deg, var(--accent), var(--accent3) 60%, var(--accent2));
  color: var(--knopftext);
}
.btn.primary:hover {
  box-shadow: inset 0 2px 1px rgba(255, 255, 255, .75), inset 0 -5px 9px rgba(0, 0, 0, .5),
              inset 0 0 0 1px rgba(255, 255, 255, .16), 0 16px 32px rgba(0, 0, 0, .5), var(--glow);
}
.btn.ghost {
  background: linear-gradient(180deg, rgba(140, 150, 170, .16), rgba(18, 23, 33, .24));
  border: 1px solid var(--line); color: var(--text);
}
.btn.ghost:hover {
  border-color: var(--accent);
  box-shadow: inset 0 2px 1px rgba(255, 255, 255, .5), inset 0 -5px 9px rgba(0, 0, 0, .5),
              0 16px 32px rgba(0, 0, 0, .5), var(--glow);
}
.btn.slim {
  padding: 7px 13px; font-size: .78rem; font-weight: 600; border-radius: 10px; gap: 5px;
  box-shadow: inset 0 1.5px .5px rgba(255, 255, 255, .5), inset 0 -2px 4px rgba(0, 0, 0, .40),
              inset 0 0 0 1px rgba(255, 255, 255, .08), 0 5px 14px rgba(0, 0, 0, .34);
}
.btn.slim:hover {
  box-shadow: inset 0 1.5px .5px rgba(255, 255, 255, .5), inset 0 -2px 4px rgba(0, 0, 0, .42),
              inset 0 0 0 1px color-mix(in srgb, var(--accent) 50%, transparent),
              0 6px 16px rgba(0, 0, 0, .4), var(--glow);
}
.btn[disabled] { opacity: .55; cursor: not-allowed; }

/* ------------------------------------------------------------------- Suche */
.suchzeile { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; }
.suchzeile input[type="search"] {
  flex: 1 1 260px; min-width: 0;
  padding: 13px 15px; font: inherit; font-size: 1rem;
  color: var(--text); background: var(--bg2);
  border: 1px solid var(--line); border-radius: 14px;
}
.schalter {
  display: flex; align-items: flex-start; gap: 10px;
  margin-top: 12px; color: var(--muted); font-size: .89rem; max-width: 64ch;
  /* Das Kästchen selbst ist ~13 px. Padding macht das ANFASSBARE Ziel groß
     genug, ohne die Optik zu verändern (Bauregel Layout 3.1). */
  padding: 6px 0; cursor: pointer;
}
.schalter input { margin-top: 4px; width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--accent); }

/* Die Notiz-Zeile unter der Suche bekommt ihre Höhe VORHER.
   Sie ist beim ersten Bild leer und wird erst von app.js gefüllt — eine leere
   Zeile, die zu einer vollen wird, schiebt alles darunter (Lehre 1b). */
#suchNotiz { min-height: 1.4em; margin: 10px 0 0; }

/* ----------------------------------------------------------- Listing-Karten */
.listings {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px; margin-top: 8px;
}
/* HIER STAND EINE PLATZRESERVE — und sie war der Fehler. Nachtrag 2026-08-09.
 *
 * Die Vorlage (family-project) hält den Platz der Liste mit
 * `.listings:not(.gefuellt){min-height:70vh}` frei und gibt ihn nach dem
 * Zeichnen wieder ab. Wörtlich übernommen hat das hier CLS 0,105 auf 0,136
 * VERSCHLECHTERT: dort stehen vierzehn Einträge, hier steht keiner. Beim
 * Freigeben verschwand also ein halber Bildschirm, und alles darunter sprang
 * hoch.
 *
 * Eine Reserve ist richtig für Inhalt, der KOMMT. Kommt keiner, ist sie selbst
 * der Sprung. Die Einträge stehen deshalb jetzt als echtes HTML in der Seite
 * (`node tools/statische-listen.mjs`) — dann muss nichts reserviert und nichts
 * freigegeben werden, bei null Einträgen so wenig wie bei hundert.
 *
 * Die Lehre ist allgemeiner als dieser eine Fall: eine Regel, die anderswo
 * gemessen wurde, gilt unter den Bedingungen, unter denen sie gemessen wurde.
 * Hier war die Bedingung „die Liste ist voll" — und die galt nicht. */

/* Die Zählzeile über der Liste. Sie ist beim ersten Bild leer und bekommt
 * ihren Text erst vom Skript — genau der Sprung, den family-project am
 * 2026-08-05 mit 0 → 0,006 gemessen hat (`#mkCount`, Δy = +31 px).
 *
 * Diese Reserve wird NICHT wieder abgegeben: sie ist so hoch wie der Inhalt,
 * der hineinkommt, und stört deshalb auch dann nicht, wenn die Zeile leer
 * bleibt (null Einträge). */
#anzahl { min-height: 1.5em; }

/* ---- Eintrags-Karte: offen bleibt nur, was zählt -------------------------
 * Klaus 2026-08-09: „nicht so viel Text auf einmal, der Text soll erscheinen,
 * wenn er relevant ist … außer die App-Beschreibung, die Messwerte und das
 * PWA-Symbol, die sollen immer zu sehen sein."
 *
 * Also drei Dinge dauerhaft — Symbol · Beschreibung · Messwerte — und alles
 * Weitere hinter einem Klick. Gebaut mit `<details>`/`<summary>`, NICHT mit
 * eigenem JavaScript: der Browser bringt Tastatur-Bedienung, die Vorlese-Ansage
 * („eingeklappt"/„ausgeklappt") und das Öffnen per Enter von selbst mit. Und es
 * funktioniert, wenn kein Skript läuft — ein Aufklapper, der ohne JavaScript
 * tot wäre, wäre genau der tote Knopf, den wir nicht bauen.
 *
 * Kein Sprung-Problem: das Aufklappen löst der Nutzer selbst aus, und was er
 * selbst anstößt, zählt Chrome nicht als Layout-Sprung. */
.listing {
  position: relative; padding: 0; overflow: hidden;
  display: flex; flex-direction: column;
  transform: translateY(var(--lift, 0px));
  transition: transform .18s ease, box-shadow .18s;
}
.listing:hover { --lift: -3px; box-shadow: var(--shadow), var(--glow); }

/* Das Symbol der App — quadratisch, nicht als Breitbild beschnitten. Ein
   PWA-Icon ist ein Zeichen, kein Foto. */
.listing .img {
  width: 64px; height: 64px; flex-shrink: 0;
  border-radius: 14px; overflow: hidden;
  background: linear-gradient(180deg, var(--bg2), var(--bg));
  border: 1px solid var(--line);
}
.listing .img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.listing summary {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 16px; cursor: pointer; list-style: none;
}
.listing summary::-webkit-details-marker { display: none; }
.listing summary:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.listing .kopf { min-width: 0; flex: 1 1 auto; }
.listing h3 { margin: 0 0 6px; font-size: 1.06rem; }
.listing .beschreibung { margin: 0 0 10px; color: var(--muted); font-size: .9rem; line-height: 1.45; }

/* Der Hinweis, dass es mehr gibt. Dreht sich beim Öffnen — mehr Anzeige
   braucht es nicht, und weniger wäre zu wenig. */
.listing .mehr {
  font-family: var(--mono); font-size: .72rem; color: var(--accent);
  display: inline-flex; align-items: center; gap: 6px; min-height: 24px;
}
.listing .mehr::before { content: "▸"; transition: transform .18s; }
.listing[open] .mehr::before { transform: rotate(90deg); }
.listing .mehr .wort-zu { display: none; }
.listing[open] .mehr .wort-zu { display: inline; }
.listing[open] .mehr .wort-auf { display: none; }

/* Messwerte — immer sichtbar, mit Datum. Vier kleine Felder, keine Ampel-Show:
   die Zahl steht da, auch wenn sie schlecht ist. */
.listing .messwerte { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; align-items: center; }
.mw {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: .72rem;
  padding: 3px 8px; border-radius: 7px;
  border: 1px solid var(--line); color: var(--muted); background: var(--bg2);
}
.mw b { font-weight: 700; color: var(--text); }
.mw.gut b     { color: var(--ok); }
.mw.mittel b  { color: var(--accent); }
.mw.schwach b { color: #ff7b7b; }
html[data-thema="tag"] .mw.schwach b { color: #b3261e; }
.listing .messdatum { font-family: var(--mono); font-size: .68rem; color: var(--muted); }

/* Der aufgeklappte Teil. */
.listing .mehrteil {
  padding: 14px 16px 16px; border-top: 1px solid var(--line); margin-top: 2px;
}
.listing .by { font-family: var(--mono); font-size: .74rem; color: var(--accent); margin: 0 0 8px; }
.listing .aktionen { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* Aufklapper auch für die Erklär-Karten — gleiche Bauart, gleiche Regel:
   die Überschrift steht, der Text kommt auf Wunsch. */
.karte > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  min-height: 28px; font-size: 1rem; font-weight: 650;
}
.karte > summary::-webkit-details-marker { display: none; }
.karte > summary::after { content: "▸"; color: var(--accent); transition: transform .18s; }
.karte[open] > summary::after { transform: rotate(90deg); }
.karte > summary:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.karte > p { margin: 10px 0 0; }

/* ---- Themen-Knopf --------------------------------------------------------
 * Ein echter <button>, kein <span>. Ein Element, das etwas auslöst, muss mit
 * der Tastatur erreichbar sein — als <span> ist es das nicht. */
.thema-knopf {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 32px; padding: 6px 12px;
  font-family: var(--mono); font-size: .76rem;
  color: var(--muted); background: var(--bg2);
  border: 1px solid var(--line); border-radius: 999px; cursor: pointer;
  transition: color .18s, border-color .18s;
}
.thema-knopf:hover { color: var(--text); border-color: var(--accent); }

/* ------------------------------------------------------- Knotenkarte (versteckt)
 * Die Zeichenfläche bekommt ihr Seitenverhältnis über `aspect-ratio` — damit
 * steht ihre Höhe fest, BEVOR das Skript zeichnet. Ein Bereich, den erst ein
 * Skript füllt, ist sonst beim ersten Bild leer und schiebt beim Füllen alles
 * darunter weg. */
.karten-flaeche { padding: 10px; }
.karten-flaeche svg { display: block; width: 100%; height: auto; aspect-ratio: 800 / 460; }

/* Relais-Pillen: klicken schaltet an und aus. `min-height` hält sie über den
   geforderten 24 px Berührungsziel. */
.relais-leiste { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
/* AUS-Zustand über die FARBE, nicht über die Deckkraft.
 *
 * Zuerst stand hier `opacity: .55`. Gemessen am 2026-08-09 (Lighthouse an der
 * Knotenkarte, Barrierefreiheit 96): der Text kam damit auf **3,06 : 1**,
 * gefordert sind 4,5. Die Deckkraft blasst eben nicht nur die Schrift ab,
 * sondern auch den Grund darunter — beide rücken zusammen, und der Abstand
 * schrumpft. Genau davor warnt die Bauregel „Deckkraft mitrechnen": wer den
 * Kontrast über die Farbe repariert, während ein `opacity` darüber liegt,
 * repariert nichts.
 *
 * `#7c8794` auf `#11151f` sind nachgerechnet **5,00 : 1** und trotzdem
 * deutlich matter als der An-Zustand. Der Unterschied wird zusätzlich vom
 * Punkt getragen (grau gegen grün leuchtend) — der Zustand hängt also nicht an
 * der Farbe allein. */
.relais-pille {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 32px; padding: 6px 12px;
  font-family: var(--mono); font-size: .78rem;
  color: var(--aus); background: var(--bg2);
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer;
  transition: border-color .18s, color .18s;
}
.relais-pille .punkt {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: var(--muted);
}
.relais-pille.an { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.relais-pille.an .punkt { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.relais-pille:hover { color: var(--text); border-color: var(--accent); }

/* ------------------------------------------------------------------ Kästen */
.note-box {
  padding: 18px 20px; border-left: 3px solid var(--accent3);
}
.note-box p { margin: 0 0 8px; }
.note-box p:last-child { margin-bottom: 0; }

.raster {
  display: grid; gap: 14px; margin: 6px 0 18px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.karte { padding: 16px; }
.karte p { margin: 0; color: var(--muted); font-size: .92rem; }

/* --------------------------------------------------------------- Formulare */
.form-grid { display: grid; gap: 14px; max-width: 580px; }
.field { display: grid; gap: 6px; }
.field > span { font-size: .92rem; }
.field > span em { color: var(--muted); font-style: normal; }
.field input, .field textarea {
  padding: 12px 14px; font: inherit; font-size: .98rem; width: 100%;
  color: var(--text); background: var(--bg2);
  border: 1px solid var(--line); border-radius: 12px; resize: vertical;
}
.form-grid button { justify-self: start; }
/* Auch diese Zeile bekommt ihre Höhe vorher — sie wird erst beim Absenden
   gefüllt und läge sonst als Sprung unter dem Knopf. */
#formNotiz { min-height: 1.4em; margin: 0; }

/* Feld-Hinweise: der kleine Satz unter einem Feld, der sagt, was erwartet
   wird. Er steht DA, bevor jemand etwas falsch macht — nicht als Fehler
   hinterher. */
.feldhinweis { font-size: .82rem; color: var(--muted); line-height: 1.45; }
.feldhinweis code {
  font-family: var(--mono); font-size: .95em;
  background: var(--bg2); padding: 1px 5px; border-radius: 5px;
}

/* Bild-Feld mit Vorschau. Die Vorschau hat ihre Maße VON ANFANG AN — sonst
   springt das Formular in dem Moment, in dem ein Bild geladen wird. */
.bildfeld { display: grid; grid-template-columns: 148px 1fr; gap: 14px; align-items: start; }
.bildvorschau {
  aspect-ratio: 16 / 9;
  border: 1px dashed var(--line); border-radius: 12px;
  background: var(--bg2);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; text-align: center; padding: 8px;
}
.bildvorschau-leer { font-size: .76rem; color: var(--muted); }
.bildvorschau-bild { width: 100%; height: 100%; object-fit: cover; display: block; }
.bildsteuer { display: grid; gap: 8px; min-width: 0; }
.bildsteuer input { width: 100%; }
@media (max-width: 560px) {
  .bildfeld { grid-template-columns: 1fr; }
  .bildvorschau { max-width: 220px; }
}

/* Der Aufklapper mit den Bedingungen sitzt im Formular-Raster und soll dort
   nicht wie ein Eingabefeld wirken. */
.form-grid > details.note-box { padding: 14px 18px; }
.form-grid > details.note-box > summary {
  cursor: pointer; list-style: none; font-weight: 650; font-size: .95rem;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  min-height: 26px;
}
.form-grid > details.note-box > summary::-webkit-details-marker { display: none; }
.form-grid > details.note-box > summary::after { content: "▸"; color: var(--accent); transition: transform .18s; }
.form-grid > details.note-box[open] > summary::after { transform: rotate(90deg); }
.form-grid > details.note-box > summary:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.form-grid > details.note-box p { margin: 10px 0 0; font-size: .9rem; color: var(--muted); }
.form-grid > details.note-box p strong { color: var(--text); }

/* Die Meldezeile unter dem Absenden-Knopf trägt im Fehlerfall den fertigen
   Eintrag zum Kopieren — sie muss also Zeilenumbrüche behalten. */
#ebNotiz { min-height: 1.4em; margin: 0; }

/* Bot-Falle: für Menschen unsichtbar, für Vorlese-Programme ausgeblendet.
   NICHT `display:none` — manche Bots erkennen das und lassen das Feld dann
   leer, womit die Falle nichts mehr fängt. */
.honig {
  position: absolute !important; left: -9999px !important; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

/* ------------------------------------------------------------------- Fuß */
footer {
  border-top: 1px solid var(--line); margin-top: 26px;
  padding: 24px 0 36px; color: var(--muted); font-size: .9rem;
}
footer a { color: var(--muted); }
footer p { margin: 0 0 8px; }
.fuss-links { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ---------------------------------------------------------------- Rücksicht
 * Bewegung abschaltbar (Bauregel Layout 3.5). Die Neigung der Knöpfe wird ganz
 * zurückgenommen; der Schimmer bleibt, weil er nicht animiert ist. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn, .listing, nav.top a { transition: none; }
  .btn { transform: none; }
  .listing { transform: translateY(var(--lift, 0px)); }
}
