/* ============================================================
   Occulis AI · REIFF Medien
   ------------------------------------------------------------
   Aufbau: Tokens → Grundlagen → Bausteine → Gerüst → Bereiche →
           Aufnehmer → Barrierefreiheit → Größenstufen.

   Grundsätze:
   - Komponenten kennen keine Rohwerte, nur Tokens. Farbe, Abstand,
     Schriftgrad, Rundung und Höhe kommen aus je EINER Skala.
   - Mobile first: die Regeln gelten ab Handygröße, die Stufen bauen
     nach oben aus.
   - Touch-Ziele: die Größe hängt am ZEIGEGERÄT (pointer: coarse),
     nicht an der Fensterbreite. Ein Touch-Notebook ist breit UND
     wird mit dem Finger bedient; die Breite sagt darüber nichts.
   ============================================================ */

/* ============================================================
   1. Design-Tokens
   ============================================================ */

/* ---------- Farbe ----------
   --brand ist der aus dem Logo ausgelesene Hausfarbton (#293484) und in BEIDEN
   Themes identisch: er gehört der Marke. --accent ist die davon abgeleitete
   BEDIENFARBE und wird im dunklen Theme aufgehellt, sonst läge sie unter 4,5:1.

   Statusfarben (--ok, --info) kommen hinzu, weil Zustände sich nicht allein
   über den Akzent unterscheiden lassen: "indexiert", "freigegeben" und "fehlt"
   müssen auf einen Blick auseinandergehen. Alle Paare sind gegen WCAG AA
   geprüft, einschließlich der weichen Chip-Hintergründe. */
:root {
  color-scheme: light;
  --brand: #293484;
  /* Runde 56: neutrale, leicht kühle Graustufen statt blaustichiger Flächen.
     Farbe trägt nur noch, was Bedeutung hat: die Bedienfarbe und die Zustände.
     Flächen unterscheiden sich über Helligkeit und Schatten, nicht über Tönung.
     Runde 64: die Inhaltsfläche ist weiß und EINE Ebene. Bereiche trennen sich
     über Überschrift, Abstand und Haarlinie - nicht mehr als weiße Karten auf
     grauem Grund, von denen jede gleich laut war. Grau trägt nur noch die
     Seitenleiste (Navigation) und eingelassene Nebenflächen. */
  --bg: #ffffff;
  --bg-sidebar: #f3f4f7;
  --flaeche-abschnitt: #f6f7f9;
  --kante-fein: #e6e8ee;
  --bg-panel: #ffffff;
  --bg-feld: #ffffff;
  --bg-hover: #eceef3;
  --bg-active: #e3e6ed;
  --bg-blase: #eceef4;
  --text: #15171c;
  --text-dim: #585e6b;
  --border: #dadde5;
  --border-stark: #c3c9d4;
  --accent: #293484;
  --accent-hover: #1f2868;
  --accent-soft: rgba(41, 52, 132, 0.07);
  --accent-soft-stark: rgba(41, 52, 132, 0.15);
  --ok: #116149;
  --ok-soft: rgba(17, 97, 73, 0.11);
  --info: #1a5f7a;
  --info-soft: rgba(26, 95, 122, 0.11);
  /* #9a5a06 kam auf dem weichen Chip-Grund auf 4,44:1 und verfehlte AA für
     kleinen Text knapp; #8f5305 liegt bei 4,97:1 (und 5,80:1 auf --bg). */
  --warn: #8f5305;
  --warn-soft: rgba(143, 83, 5, 0.11);
  --danger: #b3261e;
  --danger-soft: rgba(179, 38, 30, 0.1);
  --schleier: rgba(15, 17, 22, 0.45);
  /* Knopf, der AUF einem Bild liegt - in jedem Thema gleich, siehe Aufnehmer. */
  --auf-bild: rgba(12, 14, 22, 0.62);
  --auf-bild-stark: rgba(12, 14, 22, 0.82);
  --auf-bild-text: #ffffff;
  /* Drei Höhen statt zwei: Karte, schwebendes Bedienteil, Ebene. */
  --shadow: 0 1px 2px rgba(16, 20, 32, 0.05), 0 1px 1px rgba(16, 20, 32, 0.03);
  --shadow-mittel: 0 2px 4px -2px rgba(16, 20, 32, 0.06), 0 8px 20px -6px rgba(16, 20, 32, 0.12);
  --shadow-stark: 0 18px 44px -12px rgba(16, 20, 32, 0.30), 0 4px 10px -4px rgba(16, 20, 32, 0.10);
  --logo: var(--brand);
  /* Schrift auf einer FARBIGEN Flaeche (Akzent, Gefahr). */
  --auf-akzent: #ffffff;
  --flaeche-klar: rgba(255, 255, 255, 0);
  --kante-schatten: rgba(15, 23, 42, 0.16);
  --kante-schatten-klar: rgba(15, 23, 42, 0);
  /* Meldungen stehen invertiert - sie liegen über allem und müssen sich von
     jeder Fläche darunter abheben. */
  --toast-grund: #1c1f26;
  --toast-text: #f4f5f8;
  --toast-akzent: #b3bcf2;
  --toast-hover: rgba(255, 255, 255, 0.12);
  --toast-fehler: #ff8a80;
}

[data-theme="dark"] {
  color-scheme: dark;
  --flaeche-klar: rgba(24, 27, 33, 0);
  /* Die Inhaltsfläche hat im Dunkeln den Ton der früheren Karten; die
     Seitenleiste liegt eine Stufe tiefer - wie im Hellen ist die Navigation
     die gedämpfte Ebene und der Inhalt die ruhige helle. */
  --bg: #181b21;
  --bg-sidebar: #0e1014;
  --flaeche-abschnitt: #1e2127;
  --kante-fein: #272b33;
  --bg-panel: #181b21;
  --bg-feld: #111318;
  --bg-hover: #21252c;
  --bg-active: #2a2f37;
  --bg-blase: #232831;
  --text: #e9ebf0;
  --text-dim: #9ba2ae;
  --border: #2c313a;
  --border-stark: #414854;
  --accent: #8f9cea;
  --accent-hover: #a8b3f2;
  --accent-soft: rgba(143, 156, 234, 0.13);
  --accent-soft-stark: rgba(143, 156, 234, 0.24);
  --ok: #5fc9a3;
  --ok-soft: rgba(95, 201, 163, 0.15);
  --info: #6fbcd8;
  --info-soft: rgba(111, 188, 216, 0.15);
  --warn: #d99a4e;
  --warn-soft: rgba(217, 154, 78, 0.15);
  --danger: #e5695f;
  --danger-soft: rgba(229, 105, 95, 0.14);
  --schleier: rgba(0, 0, 0, 0.6);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-mittel: 0 2px 4px -2px rgba(0, 0, 0, 0.4), 0 8px 20px -6px rgba(0, 0, 0, 0.55);
  --shadow-stark: 0 18px 44px -12px rgba(0, 0, 0, 0.75), 0 4px 10px -4px rgba(0, 0, 0, 0.4);
  --auf-akzent: #0e1014;
  --kante-schatten: rgba(0, 0, 0, 0.55);
  --kante-schatten-klar: rgba(0, 0, 0, 0);
  --toast-grund: #eceef3;
  --toast-text: #15171c;
  --toast-akzent: #293484;
  --toast-hover: rgba(0, 0, 0, 0.08);
  --toast-fehler: #b3261e;
  /* Auf dunklem Grund wäre das Marken-Blau fast unsichtbar - hier steht das
     Logo in der aufgehellten Variante, wie bei Wort-Bild-Marken üblich. */
  --logo: #aab4ee;
}

/* ---------- Farben der Auswertung (Prüfstand, Runde 65) ----------
   Vier Ergebnisklassen als Teile einer Leiste und eine zweipolige Skala für
   die Kreuztabelle Szenario × Stufe. Beide am 29.09.2026 mit dem
   Palettenprüfer (dataviz) gegen Rot-Grün- und Blau-Gelb-Schwäche geprüft,
   je Thema gegen seine Fläche. Die Statusfarben taugten dafür nicht: --warn
   und --danger lagen für eine Grünschwäche fast aufeinander (ΔE 0,8), und als
   Flächen nebeneinander hätte man „gefallen" und „technisch" nicht getrennt.
   Farbe trägt trotzdem nie allein - jedes Segment steht mit Wort und Zahl in
   der Legende, jede Zelle mit Quote und Nenner.
   Die Mitte der Skala ist grau, nicht farbig: 50 % ist weder gut noch
   schlecht, sondern unentschieden. Text in den Zellen bleibt --text (≥ 5:1
   auf jeder Stufe). */
:root {
  --bm-bestanden: #3a9a74;
  --bm-gefallen: #b3261e;
  --bm-technisch: #d49334;
  --bm-ohne-urteil: #8a909c;
  --bm-rest: var(--bg-active);
  --bm-hm-0: #e8958a;
  --bm-hm-1: #f3c2bb;
  --bm-hm-2: #eceef3;
  --bm-hm-3: #cfd5f2;
  --bm-hm-4: #9ea9e4;
}
[data-theme="dark"] {
  --bm-bestanden: #3ea389;
  --bm-gefallen: #e76455;
  --bm-technisch: #9a6118;
  --bm-ohne-urteil: #8b93a1;
  --bm-hm-0: #8c3a31;
  --bm-hm-1: #5c302c;
  --bm-hm-2: #2a2f37;
  --bm-hm-3: #35407a;
  --bm-hm-4: #4a5ab8;
}

/* ---------- Abstand ----------
   Eine Skala, 4-px-Raster. Vorher standen hier 2, 3, 5, 7, 9, 11, 13, 18, 22,
   26 und 30 px nebeneinander - Werte, die sich um einen Pixel unterscheiden,
   wirken nicht feiner, sondern unaufgeräumt. */
:root {
  /* --s0 nimmt die Feinabstände auf, die vorher als 2 und 3 px roh im Text
     standen (Chips, Zellen, Symbolreihen) - eine halbe Stufe, keine neue Zahl. */
  --s0: 2px;
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 32px;
  --s8: 40px;
  --s9: 56px;

  /* ---------- Schriftgrade ----------
     Acht Stufen statt dreizehn. Halbe Pixel (13,5 / 12,5 / 11,5) sind ersatzlos
     weg: sie runden je nach Zoomstufe unterschiedlich und erzeugen genau die
     unruhigen Grundlinien, die sie vermeiden sollten. */
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-md: 13px;
  --fs-bd: 14px;   /* Fließtext in dichten Bereichen (Tabellen, Listen) */
  --fs-lg: 15px;   /* Grundschrift */
  --fs-xl: 18px;
  --fs-2xl: 22px;
  --fs-3xl: 28px;
  --fs-4xl: 34px;  /* nur die EINE Hauptkennzahl einer Ansicht */

  --lh-eng: 1.35;
  --lh: 1.55;

  /* Kennungen, Prüfsummen, Fehlercodes: Zeichen, die man vergleicht statt
     liest. Aus der Systemschrift - eine weitere Datei wäre Ladezeit für ein
     paar Zeichen, und die CSP erlaubt ohnehin nur eigene Schriften. */
  --mono: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /* ---------- Rundung ----------
     --radius war vorhanden und wurde an KEINER Stelle benutzt; daneben standen
     siebzehn verschiedene Rohwerte. Jetzt fünf Stufen, und sie gelten. */
  --r-xs: 6px;
  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* ---------- Bedienhöhen ----------
     Am Zeigegerät ausgerichtet, siehe Kopfkommentar. 44 px ist das Maß, das
     die WCAG-Empfehlung 2.5.8 und die Plattform-Leitfäden gemeinsam tragen. */
  --h-ziel: 40px;        /* Mindesthöhe eines Bedienteils */
  --h-ziel-klein: 34px;  /* nur dort, wo Dichte den Ausschlag gibt */
  --h-feld: 40px;
  /* Schriftgrad in Eingabefeldern. Am Finger 16 px: darunter zoomt iOS beim
     Antippen in das Feld hinein und die Seite verrutscht. */
  --fs-feld: 14px;

  /* ---------- Ebenen ----------
     Eine Leiter statt gewürfelter Zahlen: wer etwas Neues einhängt, sieht
     sofort, wohin es gehört. */
  --z-basis: 1;
  --z-haftend: 10;
  --z-schwebend: 50;
  --z-schleier: 190;
  --z-schublade: 200;
  --z-menue: 260;
  --z-vollbild: 300;
  --z-dialog: 400;
  --z-toast: 500;

  --sidebar-breite: 264px;
  --sidebar-schmal: 60px;
  --lesebreite: 760px;      /* Chat: angenehme Zeilenlänge */
  --formbreite: 720px;      /* Einstellungen: Formularspalte */

  --tempo: 0.16s;
  --tempo-lang: 0.24s;
  --tempo-dreh: 0.7s;
  --tempo-puls: 1.4s;
  /* Eine Kurve für alles, was erscheint, eine für alles, was geht. */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --ease-raus: cubic-bezier(0.4, 0, 1, 1);
  --fokus: 0 0 0 3px var(--accent-soft-stark);
}

/* Grobzeiger (Finger, Stift): alles, was bedient wird, wächst auf 44 px.
   Das ist der Grund, warum die Werte hier und nicht in den Media-Queries
   stehen - ein Touch-Notebook ist 1440 px breit und braucht sie trotzdem. */
@media (pointer: coarse) {
  :root {
    --h-ziel: 44px;
    --h-ziel-klein: 40px;
    --h-feld: 46px;
    --fs-feld: 16px;
  }
}

/* Inter (SIL Open Font License, siehe fonts/Inter-LICENSE.txt), selbst
   ausgeliefert - die CSP erlaubt Schriften nur aus der eigenen Quelle. Eine
   variable Datei für alle Stärken. Bis sie geladen ist, steht die Systemschrift
   da (swap), nichts bleibt unsichtbar. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/InterVariable.woff2") format("woff2");
}

/* ============================================================
   2. Grundlagen
   ============================================================ */
* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: var(--fs-lg) / var(--lh) "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-feature-settings: "cv11", "calt";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
}
/* Die Seite selbst rollt nie waagerecht. Einzelne Bereiche dürfen es (eine
   breite Tabelle etwa), aber sie tun es dann in ihrem EIGENEN Kasten. */
body { overflow-x: hidden; }

button, input, textarea, select { font: inherit; color: inherit; }
button { -webkit-tap-highlight-color: transparent; }
::selection { background: var(--accent-soft-stark); }

/* Überschriften: h2 war exakt so groß wie der Fließtext und las sich deshalb
   nicht als Überschrift. Jetzt trägt jede Stufe einen erkennbaren Sprung. */
/* Runde 64: der Seitentitel ist eine Ortsangabe, keine Schlagzeile - 28 px
   fett standen über jeder Ansicht wie eine Überschrift auf einer Werbeseite.
   22 px tragen den Ort; die Zahlen darunter sind lauter als er. */
h1 { font-size: var(--fs-2xl); line-height: 1.25; margin: 0; letter-spacing: -0.018em; font-weight: 650; }
h2 { font-size: var(--fs-xl); line-height: 1.3; margin: 0 0 var(--s2); letter-spacing: -0.012em; font-weight: 620; }
h3 { font-size: var(--fs-bd); margin: 0 0 var(--s2); letter-spacing: -0.005em;
     color: var(--text); font-weight: 600; }

.hint { color: var(--text-dim); font-size: var(--fs-md); margin: 0 0 var(--s3);
        line-height: var(--lh); max-width: 68ch; }
.hint-inline { color: var(--text-dim); font-size: var(--fs-sm); font-weight: 400;
               text-transform: none; letter-spacing: 0; }
.hint-warn { color: var(--danger); }
.warnung { color: var(--warn); }
.spacer { flex: 1; }

/* Nur für Screenreader - trägt jetzt auch den Sprunglink, siehe .sprunglink. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Sprunglink: die Seitenleiste kostet je nach Zahl der Chats dutzende
   Tab-Schritte, bevor der Inhalt erreicht ist. Gemessen waren es 169 Stationen
   bis zur Dokumentenliste. Der Link ist unsichtbar, bis er den Fokus bekommt. */
.sprunglink {
  position: fixed; top: var(--s2); left: var(--s2); z-index: var(--z-toast);
  padding: var(--s2) var(--s4); border-radius: var(--r-sm);
  background: var(--accent); color: var(--auf-akzent); text-decoration: none;
  font-size: var(--fs-bd); font-weight: 600; box-shadow: var(--shadow-stark);
  transform: translateY(-200%);
}
.sprunglink:focus { transform: translateY(0); }

/* ---------- Marke ---------- */
.brand { display: flex; align-items: center; gap: var(--s3); padding: 0 var(--s2) var(--s3);
         font-size: var(--fs-lg); font-weight: 600; }
/* Das Logo liegt als PNG mit Transparenz vor und wird per Maske eingefärbt: so
   trägt es im hellen Theme den Markenton und im dunklen die aufgehellte
   Variante, ohne dass zwei Dateien zu pflegen wären. */
.brand-logo {
  display: inline-block;
  flex-shrink: 0;
  width: 30px; height: 28px;
  background-color: var(--logo);
  -webkit-mask: url("img/reiff-logo.png") no-repeat center / contain;
  mask: url("img/reiff-logo.png") no-repeat center / contain;
}
.brand-logo-gross { display: block; margin: 0 auto; width: 56px; height: 52px; opacity: 0.9; }
.brand-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.brand-text small { color: var(--text-dim); font-size: var(--fs-xs); font-weight: 600;
                    letter-spacing: 0.09em; text-transform: uppercase; }
.brand-gross { gap: var(--s4); font-size: var(--fs-xl); }
.brand-gross .brand-logo { width: 44px; height: 41px; }

/* ============================================================
   3. Bausteine
   ============================================================ */

/* ---------- Schaltflächen ----------
   EIN Grundbaustein, davon alle Varianten. Vorher gab es zwölf Knopfarten mit
   je eigener Höhe (30/32/34/36/38/40/46/58 px) und eigenem Fokusverhalten;
   dieselbe Handlung sah an zwei Stellen verschieden aus. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: var(--h-ziel); padding: var(--s2) var(--s4);
  border: 1px solid var(--border-stark); border-radius: var(--r-sm);
  background: var(--bg-panel); color: var(--text);
  font-size: var(--fs-bd); font-weight: 550; line-height: 1.2; letter-spacing: -0.005em;
  text-decoration: none; cursor: pointer; box-shadow: var(--shadow);
  transition: background var(--tempo) var(--ease), border-color var(--tempo) var(--ease),
              color var(--tempo) var(--ease), box-shadow var(--tempo) var(--ease);
}
.btn:hover { background: var(--bg-hover); border-color: var(--border-stark); }
.btn:active { background: var(--bg-active); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.btn:disabled:hover { background: var(--bg-panel); border-color: var(--border-stark); }

.btn-primary { background: var(--accent); border-color: var(--accent);
               color: var(--auf-akzent); font-weight: 600; box-shadow: var(--shadow); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-primary:disabled:hover { background: var(--accent); border-color: var(--accent); }

.btn-danger { background: var(--danger); border-color: var(--danger);
              color: var(--auf-akzent); font-weight: 600; }
.btn-danger:hover { background: var(--danger); border-color: var(--danger); filter: brightness(1.1); }
.btn-danger:disabled:hover { background: var(--danger); border-color: var(--danger); filter: none; }
.btn-danger-ghost { color: var(--danger); }
/* Dritte Stufe: eine Handlung, die da sein soll, aber nicht ruft - „Alle Läufe",
   „Aufklappen", „Mehr laden". Ohne Rahmen und Schatten; erst der Zeiger zeigt
   die Fläche. Damit bleibt pro Bereich EIN Knopf, der wie ein Knopf aussieht. */
.btn-leise { border-color: transparent; background: none; box-shadow: none; color: var(--text-dim); }
.btn-leise:hover { background: var(--bg-hover); border-color: transparent; color: var(--text); }
.btn-leise:disabled:hover { background: none; border-color: transparent; }
.btn-danger-ghost:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

/* Kleine Variante: nur dort, wo Dichte wirklich zählt - und selbst dort nicht
   unter das Fingermaß, sobald mit dem Finger bedient wird. */
.btn-sm { min-height: var(--h-ziel-klein); padding: var(--s1) var(--s3); font-size: var(--fs-md); }

/* Symbolknopf. Der Klickbereich ist IMMER quadratisch und mindestens so groß
   wie --h-ziel; das Symbol darin bleibt klein. Vorher waren .btn-icon (34) und
   .tool-icon (30) zwei Bauteile für dieselbe Sache. */
.btn-icon, .tool-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--h-ziel); height: var(--h-ziel); flex-shrink: 0; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-sm); background: none;
  color: var(--text-dim); cursor: pointer;
  transition: background var(--tempo), color var(--tempo);
}
.btn-icon:hover, .tool-icon:hover { background: var(--bg-hover); color: var(--text); }
.btn-icon:active, .tool-icon:active { background: var(--bg-active); }
.btn-icon:disabled, .tool-icon:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-icon:disabled:hover, .tool-icon:disabled:hover { background: none; }
.btn-icon.aktiv { background: var(--accent-soft); color: var(--accent); }
.tool-icon.gefahr:hover { color: var(--danger); background: var(--danger-soft); }
/* Dichte Variante für Tabellenzeilen - nur bei feinem Zeiger. */
@media (pointer: fine) {
  .doc-action .tool-icon, .msg-tools .tool-icon { width: 32px; height: 32px; }
}

.linklike {
  display: inline-flex; align-items: center; gap: var(--s1);
  min-height: var(--h-ziel-klein); padding: 0 var(--s2); margin: 0;
  border: none; border-radius: var(--r-xs); background: none;
  color: var(--accent); font-size: var(--fs-md); font-weight: 500;
  cursor: pointer; text-align: left;
}
.linklike:hover { background: var(--accent-soft); color: var(--accent-hover); }

/* Ladezustand. Die Beschriftung bleibt in der Breite stehen, sonst springt die
   ganze Leiste, sobald ein Knopf zu arbeiten anfängt. */
.btn.busy { position: relative; color: transparent !important; pointer-events: none; }
.btn.busy::after {
  content: ""; position: absolute; width: 16px; height: 16px;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: var(--r-pill);
  color: var(--text); animation: dreh var(--tempo-dreh) linear infinite;
}
.btn-primary.busy::after, .btn-danger.busy::after { color: var(--auf-akzent); }
@keyframes dreh { to { transform: rotate(360deg); } }
.btn-gross { min-height: var(--h-feld); font-size: var(--fs-lg); }

/* ---------- Eingabefelder ----------
   Eine Regel für alle Feldarten statt sechs beinahe gleicher Blöcke. */
/* `.edit-box textarea` gehoert NICHT in diese Liste: es ueberschrieb sechs der
   Eigenschaften weiter unten sofort wieder (Breite, Innenabstand, Rahmen,
   Rundung, Grund) und sah damit nie aus wie die uebrigen Felder. In der Liste
   zu stehen und dann doch anders auszusehen ist die schlechteste Kombination -
   der eigene Block unten sagt es jetzt vollstaendig. */
.feld, .field input, .feld-form input, .freigabe-form input, .freigabe-form select,
.filterleiste input[type="search"], .filterleiste select, .ws-box textarea,
.filterzeile input[type="search"], .filterzeile input[type="text"], .filterzeile select,
.bm-filter select, .betrieb-zeitraum select,
.prompt-text, .regler select.breit {
  width: 100%; min-height: var(--h-feld); padding: var(--s2) var(--s3);
  border: 1px solid var(--border-stark); border-radius: var(--r-sm);
  background: var(--bg-feld); color: var(--text);
  /* Durchsichtig statt `none`: im Kontrastmodus von Windows fallen Schatten
     weg, ein Umriss nicht - dort bliebe sonst gar keine Fokusmarke. */
  outline: 2px solid transparent; outline-offset: 0;
  font-size: var(--fs-feld); font-weight: 400;
  transition: border-color var(--tempo) var(--ease), box-shadow var(--tempo) var(--ease);
}
.feld:focus, .field input:focus, .feld-form input:focus, .freigabe-form input:focus,
.freigabe-form select:focus, .filterleiste input[type="search"]:focus,
.filterleiste select:focus, .ws-box textarea:focus, .prompt-text:focus,
.filterzeile select:focus, .filterzeile input[type="search"]:focus,
.bm-filter select:focus, .betrieb-zeitraum select:focus,
.filterzeile input[type="text"]:focus,
.edit-box textarea:focus, .regler select.breit:focus {
  border-color: var(--accent); box-shadow: var(--fokus);
}
textarea { resize: vertical; }

/* ---------- Abschnitte ----------
   Runde 64: `.panel` ist kein Kasten mehr, sondern ein ABSCHNITT der weißen
   Inhaltsfläche. Vorher war jeder Bereich eine Karte mit Rand und Schatten,
   und in den Karten standen weitere Karten (Kennzahlen, Prüfsätze, Messwerte):
   alles war gleich laut, und der Rahmen war das Erste, was man sah. Jetzt
   gliedern Überschrift, Abstand und Haarlinie; einen Rahmen bekommt nur noch,
   was ein eigenes Ding ist - ein Datenbereich (`.tabellen-rahmen`) oder ein
   Objekt unter gleichartigen (ein Prüfsatz, eine Quelle: `.bm-karte`,
   `.bm-quelle`). Klasse und IDs bleiben, damit Skripte und Prüfungen weiter
   treffen. */
.panel {
  margin: 0 0 var(--s8); padding: 0;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
.panel-flush { padding: 0; }
.panel-flush > h2 { padding: 0; }
.panel-fuss {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2);
  margin-top: var(--s4); padding: var(--s3) 0 0;
  border-top: 1px solid var(--kante-fein);
}
.panel-fuss .hint { margin: 0; }

/* Der Rahmen eines Datenbereichs - und sein Rollkasten. Breite Tabellen
   wurden vorher am Rand der Ansicht ABGESCHNITTEN, weil `.view` waagerecht
   nicht rollt (Laufdetail, „Aufgegliedert", unter ~1000 px). Hier rollen sie
   in ihrem eigenen Kasten, und ein Schatten an der Kante zeigt, dass noch
   etwas kommt (dieselbe Technik wie beim senkrechten Kasten der Dokumente). */
.tabellen-rahmen {
  overflow-x: auto; overscroll-behavior-x: contain;
  margin-bottom: var(--s4);
  border: 1px solid var(--kante-fein); border-radius: var(--r-md);
  background:
    linear-gradient(to right, var(--bg) 30%, var(--flaeche-klar)) left center,
    linear-gradient(to left, var(--bg) 30%, var(--flaeche-klar)) right center,
    radial-gradient(farthest-side at 0 50%, var(--kante-schatten), var(--kante-schatten-klar)) left center,
    radial-gradient(farthest-side at 100% 50%, var(--kante-schatten), var(--kante-schatten-klar)) right center;
  background-repeat: no-repeat;
  background-size: 28px 100%, 28px 100%, 10px 100%, 10px 100%;
  background-attachment: local, local, scroll, scroll;
}
.tabellen-rahmen > .doc-table { margin: 0; }
.tabellen-rahmen > .doc-table thead th { background: var(--flaeche-abschnitt); }
.tabellen-rahmen > .doc-table th:first-child,
.tabellen-rahmen > .doc-table td:first-child { padding-left: var(--s4); }
.tabellen-rahmen > .doc-table th:last-child,
.tabellen-rahmen > .doc-table td:last-child { padding-right: var(--s4); }

/* ---------- Aufklappbares ----------
   EIN Zeichen für "hier geht etwas auf": ein Winkel, der sich dreht. Vorher
   waren es vier Handschriften - ein CSS-Dreieck bei den Panels, die
   Vollbreiten-Zeichen ＋/－ bei den Unterpanels (die in der ausgelieferten
   Schrift als leeres Kästchen ankamen), ▶/▼ im Ordnerbaum und ein Textknopf
   "Register (12) / schließen" in der Tabelle. */
.winkel {
  display: inline-block; flex-shrink: 0; width: 9px; height: 9px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform var(--tempo);
  opacity: 0.75;
}
.winkel-auf { transform: rotate(45deg); }

details.panel > summary, .unterpanel > summary {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--h-ziel); padding: 0; cursor: pointer; list-style: none;
  border-radius: var(--r-sm);
}
details.panel > summary::-webkit-details-marker,
.unterpanel > summary::-webkit-details-marker { display: none; }
details.panel > summary::before, .unterpanel > summary::before {
  content: ""; flex-shrink: 0; width: 9px; height: 9px;
  border-right: 2px solid var(--text-dim); border-bottom: 2px solid var(--text-dim);
  transform: rotate(-45deg); transition: transform var(--tempo);
  margin-left: calc(var(--s0) + 1px);
}
details.panel[open] > summary::before, .unterpanel[open] > summary::before {
  transform: rotate(45deg);
}
details.panel > summary h2 { margin: 0; }
details.panel[open] > summary { margin-bottom: var(--s4); }
details.panel > summary:hover, .unterpanel > summary:hover { color: var(--accent); }
details.panel > summary:hover::before, .unterpanel > summary:hover::before {
  border-color: var(--accent);
}

.unterpanel { margin-top: var(--s4); border-top: 1px solid var(--border); padding-top: var(--s2); }
.unterpanel > summary { font-size: var(--fs-bd); color: var(--text-dim); font-weight: 500; }

/* ---------- Chips: Etiketten ----------
   Ein Chip benennt eine Eigenschaft (Herkunft, Merkmal, Testprobe). Ein
   Zustand steht seit Runde 64 mit .status da (unten); `.chip-ok` für „aktuell"
   im Bestand ist deshalb entfallen. */
.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chip {
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: var(--s0) var(--s2); border-radius: var(--r-pill);
  background: var(--bg-hover); color: var(--text-dim);
  font-size: var(--fs-sm); font-weight: 550; white-space: nowrap; line-height: 1.5;
}
.chip-warn { background: var(--warn-soft); color: var(--warn); }
.chip-info { background: var(--info-soft); color: var(--info); }

/* ---------- Zustände (bausteine.status) ----------
   Runde 64: EIN Statusbaustein statt vier Schreibweisen. Das Symbol trägt den
   Ton in Farbe UND Form, das Wort steht immer daneben - in Textfarbe, damit es
   auf jeder Fläche lesbar bleibt. `.marke` legt eine Fläche darunter, wo der
   Zustand die Hauptsache einer Zelle ist. */
/* Grundlinie = die des Wortes: das Symbol ist mittig gesetzt und nimmt an der
   Grundlinie nicht teil. Sonst meldete der Baustein die Unterkante des
   Symbols als Grundlinie und stand neben Fließtext ein paar Pixel zu hoch. */
.status {
  display: inline-flex; align-items: baseline; gap: var(--s1);
  white-space: nowrap; color: var(--text); line-height: 1.35;
}
.status > svg { flex: none; align-self: center; }
.status-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.status[data-ton="ok"] > svg, .status[data-ton="aktiv"] > svg { color: var(--ok); }
.status[data-ton="info"] > svg { color: var(--info); }
.status[data-ton="warn"] > svg { color: var(--warn); }
.status[data-ton="fehler"] > svg, .status[data-ton="kritisch"] > svg { color: var(--danger); }
.status[data-ton="laeuft"] > svg { color: var(--accent); animation: dreh var(--tempo-puls) linear infinite; }
.status[data-ton="aus"], .status[data-ton="gesperrt"] { color: var(--text-dim); }
.status.marke {
  padding: var(--s0) var(--s2) var(--s0) var(--s1); border-radius: var(--r-pill);
  background: var(--bg-hover); font-size: var(--fs-sm); font-weight: 550;
}
.status.marke[data-ton="ok"], .status.marke[data-ton="aktiv"] { background: var(--ok-soft); color: var(--ok); }
.status.marke[data-ton="info"] { background: var(--info-soft); color: var(--info); }
.status.marke[data-ton="warn"] { background: var(--warn-soft); color: var(--warn); }
.status.marke[data-ton="fehler"] { background: var(--danger-soft); color: var(--danger); }
.status.marke[data-ton="laeuft"] { background: var(--accent-soft); color: var(--accent); }
/* Kritisch ist Fehler PLUS Rahmen und Gewicht - die eine Stufe, die auch aus
   dem Augenwinkel auffallen muss. */
.status[data-ton="kritisch"] {
  padding: var(--s0) var(--s2) var(--s0) var(--s1); border: 1px solid var(--danger);
  border-radius: var(--r-pill); background: var(--danger-soft); color: var(--danger); font-weight: 650;
}
@media (prefers-reduced-motion: reduce) {
  .status[data-ton="laeuft"] > svg { animation: none; }
}

/* Fehler eines Bereichs (bausteine.fehlerZustand): bleibt stehen, bis der
   Grund behoben ist, und bietet den Weg heraus an. */
.fehler-zustand {
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: center;
  gap: var(--s2) var(--s3); margin: 0 0 var(--s5); padding: var(--s3) var(--s4);
  border: 1px solid var(--danger); border-left-width: 3px; border-radius: var(--r-md);
  background: var(--danger-soft); font-size: var(--fs-bd); text-align: left;
}
.fehler-zustand .status { font-weight: 650; }
/* Keine Flex-BASIS: stünde der Kasten je in Spaltenrichtung, würde aus ihr eine
   Höhe (im Bild des Reiters „Anlage" war er so 330 px hoch). */
.fehler-zustand-text { flex: 1 1 auto; min-width: 12em; color: var(--text); }
.fehler-zustand .btn { margin-left: auto; }

/* Herkunftsmarke "aus der Bestandsliste". Bei einer Bestandsfrage steht sie in
   jeder Zeile - als Klammertext "[Bestandsliste]" ist das eine Wand aus
   Wiederholungen, die den Satz zerreisst. Klein, gedaempft und ohne Klammern
   traegt sie dieselbe Auskunft und tritt zurueck. Der volle Satz steht im
   title. */
.bestandsmarke {
  display: inline-block; margin-left: var(--s1); padding: 0 calc(var(--s1) + var(--s0));
  border-radius: var(--r-pill); background: var(--bg-hover);
  color: var(--text-dim); font-size: var(--fs-xs); font-weight: 500;
  vertical-align: 1px; white-space: nowrap; cursor: help;
}

/* ---------- Überlaufmenü ----------
   Neu. Vier bis fünf Symbolknöpfe je Tabellenzeile passten auf breiten Schirmen
   gerade so und lagen zwischen 830 und 1400 px vollständig außerhalb des
   sichtbaren Bereichs - gemessen ragte die Tabelle bis 1618 px bei 1194 px
   Fensterbreite. Ein Menü nimmt immer genau eine Knopfbreite ein, egal wie
   viele Handlungen es trägt, und trägt sie beschriftet statt nur als Symbol. */
.menu {
  position: fixed; z-index: var(--z-menue);
  min-width: 216px; max-width: min(320px, calc(100vw - var(--s7)));
  /* Ein langes Menü darf nicht über den Fensterrand hinaus hängen. */
  max-height: calc(100dvh - var(--s4)); overflow-y: auto;
  padding: var(--s1);
  background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-stark);
}
.menu-item {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; min-height: var(--h-ziel); padding: var(--s2) var(--s3);
  border: none; border-radius: var(--r-sm); background: none;
  color: var(--text); font-size: var(--fs-bd); text-align: left; cursor: pointer;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--bg-hover); }
.menu-item svg { color: var(--text-dim); flex-shrink: 0; }
.menu-item[role="menuitemradio"][aria-checked="true"] svg,
.menu-item[role="menuitemcheckbox"][aria-checked="true"] svg { color: var(--accent); }
.menu-item-text { display: flex; flex-direction: column; min-width: 0; }
.menu-hinweis { color: var(--text-dim); font-size: var(--fs-sm); line-height: var(--lh-eng); }
/* Gesperrt, aber erreichbar: der Grund steht als zweite Zeile darunter. */
.menu-item[aria-disabled="true"] { cursor: not-allowed; color: var(--text-dim); }
.menu-item[aria-disabled="true"]:hover { background: none; }
.menu-item.gefahr { color: var(--danger); }
.menu-item.gefahr svg { color: var(--danger); }
.menu-item.gefahr:hover { background: var(--danger-soft); }
.menu-trenner { height: 1px; margin: var(--s1) var(--s2); background: var(--border); }
/* Die Kopfzeile eines Menues traegt keinen Rubriknamen, sondern einen NAMEN:
   den Eigentuemer und den Ordnerpfad. Grossbuchstaben waren hier deshalb keine
   Auszeichnung, sondern eine Faelschung - aus „Wohnung/Vertraege" wurde
   „WOHNUNG/VERTRAEGE", und das ist ein anderer Pfad als der, der im Baum steht.
   Klein bleibt sie trotzdem: sie beschriftet, sie handelt nicht. */
.menu-titel {
  padding: var(--s2) var(--s3) var(--s1); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: 0.01em; color: var(--text-dim); word-break: break-word;
}
/* Auf schmalen Displays wird aus dem Menü eine Blattschublade am unteren Rand -
   dieselbe Form wie beim Dialog, und dort ist der Daumen. */
.menu-schleier { position: fixed; inset: 0; z-index: calc(var(--z-menue) - 1);
                 background: var(--schleier); }
.menu-blatt {
  top: auto !important; left: 0 !important; bottom: 0;
  width: 100%; max-width: 100%; min-width: 0;
  padding: var(--s2) var(--s2) max(var(--s3), env(safe-area-inset-bottom));
  border-radius: var(--r-xl) var(--r-xl) 0 0; border-bottom: none;
  max-height: 80dvh; overflow-y: auto;
}
.menu-blatt .menu-item { font-size: var(--fs-lg); }

/* ---------- Skelette ----------
   Vor dem ersten Datensatz stand bisher der Leertext "Noch keine Dokumente" -
   die Anlage behauptete also, der Bestand sei leer, während er noch geladen
   wurde. Ein Skelett sagt "gleich", ein Leerzustand sagt "nichts". Das ist
   nicht dasselbe. */
.skelett { display: flex; flex-direction: column; gap: var(--s1); padding: var(--s3) var(--s4); }
.skelett-zeile {
  height: 44px; border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--bg-hover) 25%, var(--bg-active) 37%, var(--bg-hover) 63%);
  background-size: 400% 100%;
  animation: schimmer var(--tempo-puls) ease-in-out infinite;
}
@keyframes schimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
/* Wer weniger Bewegung eingestellt hat, sieht ein ruhiges Skelett. Vorher
   schimmerten Dokumentliste, Bildanhänge und Betrieb trotzdem endlos. */
@media (prefers-reduced-motion: reduce) {
  .skelett-zeile, .kennzahl-skelett, .anhang-chip.laedt { animation: none; }
}

/* ---------- Fortschritt ---------- */
.bar { height: 6px; border-radius: var(--r-pill); background: var(--bg-hover); overflow: hidden; }
.bar-fill { height: 100%; border-radius: var(--r-pill); background: var(--accent);
            transition: width var(--tempo-lang) var(--ease); }
/* Wo niemand sagen kann, wie weit es ist, wandert ein Band statt einer Zahl.
   Ein Balken, der bei null steht und sich nicht rührt, sieht aus wie ein
   hängendes Programm - und genau das soll er nicht behaupten. */
.bar-unbestimmt { position: relative; }
.bar-unbestimmt .bar-fill {
  position: absolute; left: 0; top: 0; width: 40%;
  transition: none; animation: bar-wandern var(--tempo-puls) ease-in-out infinite;
}
@keyframes bar-wandern {
  from { transform: translateX(-100%); }
  to { transform: translateX(250%); }
}
/* Ohne Bewegung bleibt die Aussage "es läuft, der Stand ist offen" - dann
   eben als ruhiges, gedämpftes Band über die ganze Breite. */
@media (prefers-reduced-motion: reduce) {
  .bar-unbestimmt .bar-fill { animation: none; width: 100%; opacity: 0.45; }
}

/* ---------- Leer- und Fehlerzustände ---------- */
.leer-zustand {
  margin: 0; padding: var(--s7) var(--s5); text-align: center;
  color: var(--text-dim); font-size: var(--fs-bd); line-height: var(--lh);
}
.leer-zustand strong { display: block; color: var(--text); font-size: var(--fs-lg);
                       margin-bottom: var(--s1); }
/* Der Knopf ist ein eigener Block, kein Wort im Fliesstext. Vorher lief er
   als Inline-Element in der letzten Zeile mit und stand mitten im Satz
   ("... daraus belegen. [Dateien auswaehlen]"). */
.leer-zustand .btn { display: inline-flex; margin-top: var(--s4); }
.leer-zustand span { display: block; max-width: 52ch; margin: 0 auto; }

/* ============================================================
   4. Gerüst: Bänder, Kopfleiste, Seitenleiste, Hauptbereich
   ============================================================ */

/* ---------- Hinweisbänder (oberster Rand) ----------
   Sie liegen jetzt IM Flussmodell des Seitengerüsts. Vorher wurde die
   Layouthöhe mit calc(100vh - 39px) korrigiert - eine feste Zahl für ein Band,
   dessen Text auf schmalen Displays über zwei bis drei Zeilen läuft. Damit
   stimmte die Rechnung genau dort nicht, wo sie gebraucht wurde. */
.hinweisband {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2) var(--s3);
  padding: var(--s2) var(--s4);
  padding-top: max(var(--s2), env(safe-area-inset-top));
  font-size: var(--fs-md);
  border-bottom: 1px solid;
}
.hinweisband .btn { margin-left: auto; flex-shrink: 0; }
.hinweisband code { font-size: var(--fs-sm); }
.hinweisband.warn  { background: var(--warn-soft);  border-color: var(--warn);  color: var(--warn); }
.hinweisband.info  { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.hinweisband.fehler { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.hinweisband.ok    { background: var(--ok-soft); border-color: var(--ok); color: var(--ok); }
/* In einer Ansicht ist ein Band kein Rand der Anwendung, sondern ein Hinweis
   zu DIESEM Inhalt: eingerückt, mit Kante links, Text in Textfarbe. */
.view .hinweisband {
  margin: 0 0 var(--s5); padding: var(--s3) var(--s4);
  border: 1px solid; border-left-width: 3px; border-radius: var(--r-md);
  color: var(--text); font-size: var(--fs-bd);
}
.view .hinweisband.warn { border-color: var(--warn); }
.view .hinweisband.info { border-color: var(--accent); }

/* ---------- Kopfleiste (nur bei eingeklappter Seitenleiste) ---------- */
.topbar {
  display: none;
  align-items: center;
  gap: var(--s2);
  flex: 0 0 auto;
  padding: var(--s2) var(--s3);
  padding-top: max(var(--s2), env(safe-area-inset-top));
  background: var(--bg-sidebar);
  border-bottom: 1px solid var(--border);
}
.topbar strong { flex: 1; font-size: var(--fs-lg); overflow: hidden;
                 text-overflow: ellipsis; white-space: nowrap; }
.topbar .brand-logo { width: 24px; height: 22px; }

/* ---------- Seitengerüst ----------
   Eine Flex-Spalte über die volle Höhe: Bänder oben, Layout füllt den Rest.
   Kein calc, keine Magie - was dazukommt, verschiebt den Rest von selbst. */
body {
  display: flex; flex-direction: column;
  height: 100vh; height: 100dvh; height: var(--vvh, 100dvh);
}
.layout { display: flex; flex: 1 1 auto; min-height: 0; }

.sidebar {
  width: var(--sidebar-breite);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s0);
  padding: var(--s4) var(--s3);
  padding-bottom: 0;
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  transition: width var(--tempo-lang) ease;
  /* Reicht die Hoehe nicht einmal fuer die festen Teile, rollt die Leiste
     SELBST - sie darf nicht die ganze Seite schieben. Gemessen am 22.09.2026:
     bei 500 px Fensterhoehe standen Marke, Knopf, fuenf Navigationseintraege,
     Abschaltkasten und Fusszeile zusammen 527 px hoch, und die Seite rollte um
     die fehlenden 27 px. Die Chatliste hat ihren eigenen Rollbereich und ist
     bis dahin laengst auf null geschrumpft; danach gibt nichts mehr nach.
     Aufgefallen ist es erst, als die Leiste in Runde 60 einen fuenften Eintrag
     bekam - der letzte vollstaendige Browserlauf lag davor. */
  overflow-y: auto;
  overscroll-behavior: contain;
}
.sidebar-backdrop { display: none; }

/* Die Symbolsammlung liegt einmalig im Dokument und wird per <use> geholt.
   Sie nimmt keinen Platz ein, muss aber aus dem Fluss - sonst schoebe sie das
   Layout um ihre Zeilenhoehe nach unten. */
.icon-sprite { position: absolute; }

/* Jeder Rollbereich ist Bezugsrahmen seiner absolut gesetzten Kinder. Ohne das
   richten sich z. B. die `.sr-only`-Beschriftungen in Tabellenköpfen am Dokument
   aus: sie lagen dann dort, wo die Tabelle im Inhalt steht (weit unter dem
   Fenster), und liessen die SEITE um bis zu 1150 px weiter rollen als ihr Inhalt. */
.sidebar, main, .view { position: relative; }
main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.view { flex: 1; overflow-y: auto; overflow-x: hidden; }
.view-chat { display: flex; flex-direction: column; overflow: hidden; position: relative; }
.view-inner { max-width: var(--formbreite); margin: 0 auto;
              padding: var(--s6) var(--s5) var(--s9); }
/* Die Dokumentenliste ist eine Tabelle, kein Fließtext: 720 px sind die richtige
   Breite für eine Textspalte, aber sechs Spalten plus Ordnerbaum passen darin
   nicht. Sie bekommt den Platz, den der Schirm hergibt. */
#view-documents .view-inner { max-width: min(1560px, 100%); }

.view-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3) var(--s4);
  margin-bottom: var(--s5);
}
.view-head h1 { margin-right: var(--s1); }

/* ---------- Navigation ----------
   Auf die Seitenleiste eingegrenzt. Als blosses `nav { flex-direction: column }`
   traf die Regel JEDES <nav> der Seite - auch den Ordnerbaum und die
   Bereichsleiste der Einstellungen, die dadurch untereinander statt
   nebeneinander standen. */
.sidebar nav { display: flex; flex-direction: column; gap: var(--s0); margin-top: var(--s2); }
.nav-item {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; min-height: var(--h-ziel); padding: var(--s2) var(--s3);
  border: none; border-radius: var(--r-sm); background: transparent;
  color: var(--text); font-size: var(--fs-bd); font-weight: 500;
  text-align: left; cursor: pointer;
  transition: background var(--tempo);
}
.nav-item:hover { background: var(--bg-hover); }
/* Der aktive Bereich trägt die Hausfarbe statt eines neutralen Grautons - das
   ist der eine Ort, an dem Farbe echte Orientierung gibt. */
.nav-item.active { background: var(--bg-panel); color: var(--text); font-weight: 600;
                   box-shadow: var(--shadow); }
.nav-item svg { color: var(--text-dim); flex-shrink: 0; }
.nav-item.active svg { color: var(--accent); }

.sidebar-section {
  display: flex; align-items: center; gap: var(--s2);
  margin: var(--s5) var(--s3) var(--s1); font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-dim);
}
/* Die Rubrik IN der Navigation steht enger am Eintrag darüber als die
   Überschrift der Chatliste - sie gliedert eine Liste, sie beginnt keine neue. */
.sidebar nav .nav-rubrik-leiste { margin: var(--s4) var(--s3) var(--s1); }
.chat-list { flex: 1; overflow-y: auto; overflow-x: hidden;
             display: flex; flex-direction: column; gap: 1px;
             margin: 0 calc(var(--s1) * -1); padding: 0 var(--s1); }
.chat-list .empty { padding: var(--s2) var(--s3); color: var(--text-dim); font-size: var(--fs-md); }

.chat-item { display: flex; align-items: center; border-radius: var(--r-sm); }
.chat-item:hover { background: var(--bg-hover); }
.chat-item.active { background: var(--bg-panel); box-shadow: var(--shadow); }
.chat-item.active .chat-item-title { color: var(--text); font-weight: 600; }
.chat-item-title {
  /* Volles Zielmass: einen Chat zu öffnen ist die häufigste Handlung in der
     Leiste, nicht eine Nebensache. */
  flex: 1; min-width: 0; min-height: var(--h-ziel); padding: var(--s2) var(--s3);
  border: none; background: none; color: inherit;
  text-align: left; font-size: var(--fs-bd); cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Der Löschknopf war 30 × 30 px und erschien nur beim Überfahren. Jetzt trägt
   er das volle Zielmaß und ist bei Tastaturfokus ebenso da. */
.chat-item-delete {
  display: none; align-items: center; justify-content: center;
  width: var(--h-ziel-klein); height: var(--h-ziel-klein); flex-shrink: 0;
  margin-right: var(--s1);
  border: none; border-radius: var(--r-xs); background: none;
  color: var(--text-dim); cursor: pointer;
}
.chat-item:hover .chat-item-delete, .chat-item:focus-within .chat-item-delete { display: inline-flex; }
.chat-item-delete:hover { color: var(--danger); background: var(--danger-soft); }
@media (pointer: coarse) { .chat-item-delete { display: inline-flex; } }

/* ---------- Auto-Stopp ----------
   Der Kasten erklärte sich bisher ausschließlich über title= - also nur beim
   Überfahren mit der Maus. Auf dem Telefon war die wichtigste Betriebsangabe
   der Anlage damit gar nicht zu bekommen. Jetzt steht die Erklärung als Text
   im Kasten, aufklappbar. */
.shutdown-box {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1) var(--s2);
  margin-top: var(--s2); padding: var(--s2);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  color: var(--text-dim); font-size: var(--fs-sm);
}
/* Der Melder ist die Zeile selbst: Restzeit lesen und Erklärung aufklappen in
   EINEM Bedienteil. Er nimmt den freien Platz und darf im Notfall kürzen -
   lieber ein abgeschnittenes Wort als ein Ausschalter in der zweiten Zeile.
   Der volle Wortlaut steht dann immer noch in der Erklärung darunter. */
.shutdown-melder {
  display: flex; align-items: center; gap: var(--s2);
  flex: 1 1 auto; min-width: 0;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: inherit; font: inherit; text-align: left;
  border-radius: var(--r-xs);
}
.shutdown-melder .shutdown-text {
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Die Zeile klappt die Erklärung auf - am Finger war sie 19 px hoch und damit
   unter dem Mindestmass von 24 px (WCAG 2.5.8). Sie wächst auf die Höhe der
   Knöpfe daneben, die Zeile bleibt einzeilig. */
@media (pointer: coarse) {
  .shutdown-melder { min-height: var(--h-ziel-klein); }
}
.shutdown-melder:hover .shutdown-text { text-decoration: underline; }
/* Nicht jeder Zustand hat etwas zu erklären ("Fährt herunter …"). Dann bleibt
   die Zeile stehen - versteckte man sie, wäre die Restzeit mit weg -, sie
   verliert nur ihre Rolle als Aufklapper. */
.shutdown-melder.ohne-erklaerung { cursor: default; }
.shutdown-melder.ohne-erklaerung:hover .shutdown-text { text-decoration: none; }
/* Breit sagt der Text, worum es geht; das Symbol wäre eine Wiederholung. In
   der Schiene ist es umgekehrt: dort steht nur "25m", und die Uhr sagt, wovon. */
.shutdown-uhr { display: none; }
.shutdown-box .btn-icon { width: var(--h-ziel-klein); height: var(--h-ziel-klein); }
.shutdown-box.warn { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }
.shutdown-box.error { color: var(--danger); border-color: var(--danger); background: var(--danger-soft); }
.shutdown-erklaerung {
  margin: var(--s1) 0 0; padding: var(--s2) var(--s3);
  border-radius: var(--r-xs); background: var(--bg-panel);
  color: var(--text-dim); font-size: var(--fs-sm); line-height: var(--lh);
}

.shutdown-overlay {
  position: fixed; inset: 0; z-index: var(--z-dialog);
  display: flex; align-items: center; justify-content: center;
  padding: var(--s6); text-align: center;
  background: var(--bg);
}
.shutdown-overlay h1 { margin-bottom: var(--s3); }
.shutdown-overlay p { color: var(--text-dim); margin: var(--s2) 0; }
.shutdown-overlay .offline-retry { font-size: var(--fs-md); }

.sidebar-footer {
  display: flex; align-items: center; gap: var(--s0);
  flex-wrap: wrap;
  margin-top: var(--s2); padding: var(--s2) 0;
  padding-bottom: max(var(--s2), env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
}
.sidebar-footer .user {
  min-width: 0; font-size: var(--fs-md); font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Runde 64: Konto, Benutzeransicht und Darstellung hinter EINEM beschrifteten
   Knopf (app.js). Initialen als Zeichen, darunter die Rolle - in der Schiene
   bleibt nur das Zeichen. */
.konto-knopf {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  min-height: var(--h-ziel); padding: var(--s2);
  border: 0; border-radius: var(--r-sm); background: none; color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
  transition: background var(--tempo) var(--ease);
}
.konto-knopf:hover, .konto-knopf[aria-expanded="true"] { background: var(--bg-hover); }
.konto-knopf:disabled { opacity: 0.6; cursor: wait; }
.konto-zeichen {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: var(--h-ziel-klein); height: var(--h-ziel-klein); border-radius: var(--r-pill);
  background: var(--accent-soft-stark); color: var(--accent);
  font-size: var(--fs-sm); font-weight: 650; letter-spacing: 0.02em;
}
.konto-text { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; line-height: var(--lh-eng); }
.konto-rolle { color: var(--text-dim); font-size: var(--fs-xs); font-weight: 500; }
.konto-rolle:empty { display: none; }
.konto-winkel { flex: none; color: var(--text-dim); }
/* Läuft die Benutzeransicht, zeigt es das Zeichen - auch in der Schiene, wo
   kein Wort Platz hat. */
.konto-knopf.vorschau .konto-zeichen {
  background: var(--warn-soft); color: var(--warn); box-shadow: 0 0 0 var(--s0) var(--warn);
}
body.leiste-schmal .sidebar .konto-text,
body.leiste-schmal .sidebar .konto-winkel { display: none; }
body.leiste-schmal .sidebar .konto-knopf { justify-content: center; padding-left: 0; padding-right: 0; }

/* ---------- Seitenleiste einklappen (breite Schirme) ----------
   Auf einem 1366er Notebook nahm die Leiste dauerhaft ein Fünftel der Breite.
   Eingeklappt bleibt eine Schiene mit denselben Zielen - keine Funktion geht
   verloren, die Chatliste wandert in ein Menü. */
.sidebar-toggle { display: none; }
/* Ausgeklappt sitzt der Umschalter rechts in der Markenzeile. Das stand vorher
   als `style="margin-left:auto"` im Markup - und ein Inline-Stil laesst sich
   von keiner Regel mehr zuruecknehmen, also blieb er auch in der Schiene
   stehen und schob den Knopf aus ihr heraus. */
.brand .sidebar-toggle { margin-left: auto; }
body.leiste-schmal .sidebar { width: var(--sidebar-schmal); padding-left: var(--s1); padding-right: var(--s1); }
body.leiste-schmal .sidebar .brand-text,
body.leiste-schmal .sidebar .sidebar-section,
body.leiste-schmal .sidebar .chat-list,
body.leiste-schmal .sidebar .shutdown-text,
body.leiste-schmal .sidebar .user,
body.leiste-schmal .sidebar #new-chat span,
body.leiste-schmal .sidebar .nav-item span { display: none; }
/* In der Schiene stehen Logo und Umschalter UNTEREINANDER. Nebeneinander
   brauchten sie 30 + 12 + 40 = 82 px, die Schiene bietet innen 52: gemessen
   ragte das Logo 11 px nach links aus der Leiste heraus (abgeschnitten) und
   der Knopf 11 px nach rechts darueber hinaus, mitten auf den Inhalt - dazu
   liess sich die Leiste seitlich verschieben (scrollWidth 71 zu clientWidth
   59). Der Umschalter sah damit aus wie ein Fehler und lag halb ausserhalb
   der Flaeche, auf die man zielt. */
body.leiste-schmal .sidebar .brand {
  flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s1); padding: 0 0 var(--s2);
}
body.leiste-schmal .sidebar .brand .sidebar-toggle { margin-left: 0; }
body.leiste-schmal .sidebar .nav-item,
body.leiste-schmal .sidebar #new-chat { justify-content: center; padding-left: 0; padding-right: 0; }
/* In der Schiene wird aus der Zeile eine schmale Saeule: Symbol, Restzeit in
   Kurzform, und der Verlaengern-Knopf. Der lange Text und die Erklaerung
   bleiben der ausgeklappten Fassung vorbehalten - die Restzeit selbst darf
   aber nicht verschwinden, nur weil die Leiste schmal ist. */
body.leiste-schmal .sidebar .shutdown-box {
  flex-direction: column; justify-content: center; gap: var(--s0); padding: var(--s1);
}
body.leiste-schmal .sidebar .shutdown-box .btn-icon:not(#extend-btn) { display: none; }
body.leiste-schmal .sidebar .shutdown-kurz { display: block; }
body.leiste-schmal .sidebar .shutdown-uhr { display: block; }
body.leiste-schmal .sidebar .shutdown-melder {
  flex-direction: column; align-items: center; gap: var(--s0); flex: 0 0 auto;
}
.shutdown-kurz { display: none; font-size: var(--fs-xs); font-weight: 700;
                 font-variant-numeric: tabular-nums; line-height: 1; }
body.leiste-schmal .sidebar-footer { flex-direction: column; gap: var(--s1); }
body.leiste-schmal .chatliste-knopf { display: inline-flex; }
.chatliste-knopf { display: none; }

/* ============================================================
   5. Chat
   ============================================================ */
.chat-scroll { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
/* margin-top: auto verankert den Verlauf UNTEN. Vorher klebte ein kurzer Chat
   oben und darunter standen mehrere hundert Pixel Leere bis zur Eingabezeile. */
.chat-messages {
  max-width: var(--lesebreite); width: 100%; margin: auto auto 0;
  padding: var(--s5) var(--s5) var(--s2);
  display: flex; flex-direction: column; gap: var(--s7);
}
.chat-empty {
  max-width: 560px; margin: auto; padding: var(--s7) var(--s5); text-align: center;
}
.chat-empty-titel { margin: var(--s4) 0 var(--s2); font-size: var(--fs-3xl); letter-spacing: -0.022em; }
.chat-empty p { color: var(--text-dim); margin: 0 auto var(--s5); max-width: 46ch; }

.msg { display: flex; flex-direction: column; gap: var(--s2); }
.msg-user { align-items: flex-end; }
.msg-user .bubble {
  max-width: min(82%, 60ch); padding: var(--s3) var(--s4);
  border-radius: var(--r-xl) var(--r-xl) var(--r-xs) var(--r-xl);
  background: var(--bg-blase); white-space: pre-wrap; word-break: break-word;
}
.msg-assistant { align-items: stretch; }
/* Die Antwort trug bisher keinerlei Rahmen: zwei aufeinanderfolgende Antworten
   waren als ein Block zu lesen. Eine ruhige Kante links ordnet sie zu, ohne
   eine zweite Sprechblase zu bauen. */
/* Die Antwort steht frei auf dem Grund, mit Absenderzeile darüber - zwei
   Antworten trennt der grössere Abstand im Verlauf. */
.msg-assistant .md { line-height: 1.65; }
.msg-absender {
  display: flex; align-items: center; gap: var(--s2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim);
  letter-spacing: 0.03em;
}
.msg-absender .brand-logo { width: 17px; height: 16px; }
/* Werkzeuge waren mit opacity:0 unsichtbar, blieben aber anklickbar - ein
   unsichtbares Ziel unter dem Mauszeiger. Jetzt gedämpft statt unsichtbar und
   bei Fokus oder Berührung voll da. */
.msg-tools { display: flex; gap: var(--s1); opacity: 0.45; transition: opacity var(--tempo); }
.msg-user .msg-tools { justify-content: flex-end; }
.msg:hover .msg-tools, .msg:focus-within .msg-tools { opacity: 1; }
@media (pointer: coarse) { .msg-tools { opacity: 1; } }
.msg-status {
  display: flex; align-items: center; gap: var(--s2);
  color: var(--text-dim); font-size: var(--fs-md);
}
.msg-status::before {
  content: ""; width: 13px; height: 13px; flex-shrink: 0;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: var(--r-pill);
  animation: dreh var(--tempo-dreh) linear infinite;
}

/* Die Bearbeitungsflaeche einer eigenen Nachricht. Sie sieht bewusst anders
   aus als ein Formularfeld: sie ist der Ort, an dem gerade gearbeitet wird,
   und traegt den Fokusring dauerhaft. Vollstaendig hier - die drei Zeilen aus
   der Sammelregel oben (Mindesthoehe, Textfarbe, Uebergang) stehen mit. */
.edit-box textarea {
  width: min(560px, 84vw); min-height: var(--h-feld); padding: var(--s3);
  border: 1px solid var(--accent); border-radius: var(--r-md);
  background: var(--bg-panel); color: var(--text);
  resize: vertical; outline: none; box-shadow: var(--fokus);
  transition: border-color var(--tempo), box-shadow var(--tempo);
}
.edit-actions { display: flex; gap: var(--s2); justify-content: flex-end; margin-top: var(--s2); }

.cite {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 var(--s1); margin: 0 var(--s0);
  border-radius: var(--r-xs); background: var(--accent-soft); color: var(--accent);
  font-size: var(--fs-xs); font-weight: 700; text-decoration: none; vertical-align: 1px;
}
.cite:hover { background: var(--accent); color: var(--auf-akzent); }
@media (pointer: coarse) {
  /* Am Finger ist eine 18-px-Marke im Fliesstext kaum zu treffen. */
  .cite { min-width: var(--s6); height: var(--s6); }
}

.sources { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
           margin-top: var(--s3); font-size: var(--fs-md); }
.sources-label { color: var(--text-dim); font-weight: 500; }
.sources a {
  display: inline-flex; align-items: center; min-height: var(--h-ziel-klein);
  color: var(--accent); text-decoration: none; padding: var(--s1) var(--s3);
  border: 1px solid var(--border); border-radius: var(--r-pill);
}
.sources a:hover { background: var(--accent-soft); border-color: var(--accent); }

.md { word-break: break-word; }
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md p, .md ul, .md ol { margin: 0 0 var(--s3); }
.md ul, .md ol { padding-left: var(--s5); }
.md li { margin-bottom: var(--s1); }
.md h1, .md h2, .md h3 { font-size: var(--fs-xl); margin: var(--s5) 0 var(--s2); }
.md code { padding: 1px var(--s1); border-radius: var(--r-xs); background: var(--bg-hover);
           font-size: var(--fs-md); }
.md pre { padding: var(--s3); border-radius: var(--r-sm); background: var(--bg-hover);
          overflow-x: auto; }
.md pre code { padding: 0; background: none; }
/* Eine breite Tabelle rollt in ihrem EIGENEN Kasten - sonst schiebt sie die
   ganze Antwortspalte auseinander. */
.md table { border-collapse: collapse; width: 100%; margin: var(--s3) 0;
            font-size: var(--fs-bd); }
/* JEDE Tabelle rollt in sich - auch eine in einer Liste oder einem
   aufgeklappten Block. Vorher nur die auf oberster Ebene. */
.md table { display: block; overflow-x: auto; max-width: 100%; }
.md .katex-display { overflow-x: auto; overflow-y: hidden; }
.md th, .md td { padding: var(--s2) var(--s3); border: 1px solid var(--border);
                 text-align: left; white-space: nowrap; }
.md th { background: var(--bg-hover); font-weight: 600; }
.md a { color: var(--accent); }
.md blockquote { margin: 0 0 var(--s3); padding-left: var(--s3);
                 border-left: 3px solid var(--border); color: var(--text-dim); }
.md details { margin-top: var(--s3); }
.md summary { cursor: pointer; color: var(--text-dim); font-size: var(--fs-md);
              min-height: var(--h-ziel-klein); display: flex; align-items: center; }
.md details table { margin-top: var(--s2); }

/* ---------- Chat: Eingabe ---------- */
.chat-inputbar {
  max-width: var(--lesebreite); width: 100%; margin: 0 auto;
  padding: var(--s2) var(--s5) var(--s4);
  padding-bottom: max(var(--s4), env(safe-area-inset-bottom));
}
.model-banner {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s2); padding: var(--s2) var(--s3); border-radius: var(--r-sm);
  background: var(--warn-soft); color: var(--warn); font-size: var(--fs-md);
}
.model-banner.error { background: var(--danger-soft); color: var(--danger); }

/* ---------- Wartung ----------
   Dieselbe Bauform an drei Stellen: Banner im Chat, Hinweis ueber der
   Ablageflaeche, Vorschau in den Einstellungen. Ein Zustand, ein Bild - wer
   ihn einmal gesehen hat, erkennt ihn ueberall wieder. Getragen wird er von
   der Warnfarbe, die es schon gibt: eine eigene Farbe fuer eine Lage, die es
   ein paar Mal im Jahr gibt, waere eine Farbe zu viel.
   Die Kante links macht den Unterschied zum gewoehnlichen Modellbanner - die
   Wartung ist keine Zwischenmeldung, sie bleibt stehen, bis jemand sie
   abschaltet. */
.model-banner.wartung, .wartung-hinweis, .wartung-vorschau {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s1) var(--s2);
  padding: var(--s3); border-radius: var(--r-sm);
  border-left: 3px solid var(--warn);
  background: var(--warn-soft); color: var(--warn); font-size: var(--fs-md);
}
.model-banner.wartung { margin-bottom: var(--s2); }
.wartung-hinweis { margin-bottom: var(--s4); }
.wartung-vorschau { margin-top: var(--s3); }
.model-banner.wartung strong, .wartung-hinweis strong, .wartung-vorschau strong {
  font-weight: 600;
}
/* Der Text steht in der Farbe des Fliesstextes, nicht in der Warnfarbe: die
   Warnung ist der Rahmen, die Auskunft darin will gelesen werden. */
.model-banner.wartung span:not(.wartung-icon),
.wartung-hinweis span:not(.wartung-icon),
.wartung-vorschau span:not(.wartung-icon) { color: var(--text); flex: 1 1 18rem; }
.wartung-icon { flex-shrink: 0; font-size: var(--fs-lg); line-height: 1; }

/* Gesperrte Ablageflaeche: sichtbar unbenutzbar, aber nicht ausgeblendet -
   sie zeigt weiter, WO hochgeladen wird, wenn die Wartung vorbei ist. */
.upload-zone.gesperrt {
  cursor: not-allowed; opacity: 0.55; border-style: solid;
}
.upload-zone.gesperrt:hover { border-color: var(--border-stark); background: none; }

/* Eingabefeld und Werkzeuge in EINER Karte: sonst wirkt die Werkzeugleiste
   wie ein eigener Bereich. */
.inputbox {
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background: var(--bg-panel); box-shadow: var(--shadow-mittel);
  transition: border-color var(--tempo) var(--ease), box-shadow var(--tempo) var(--ease);
}
/* Der Ring liegt AUSSEN und folgt der Rundung der Karte - ein rechteckiger
   Umriss quer durch die abgerundete Ecke sah nach Fehler aus. */
.inputbox:focus-within { border-color: var(--accent); box-shadow: var(--fokus); }
.inputbox textarea {
  display: block; width: 100%; max-height: 40vh; padding: var(--s3) var(--s4) var(--s1);
  border: none; background: none; resize: none; outline: none; line-height: var(--lh);
  font-size: var(--fs-feld);
}
.input-tools { display: flex; align-items: center; gap: var(--s2);
               padding: var(--s1) var(--s2) var(--s2); }
.tool-btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: var(--h-ziel-klein); padding: var(--s1) var(--s3);
  border: 1px solid transparent; border-radius: var(--r-sm); background: none;
  color: var(--text-dim); font-size: var(--fs-md); font-weight: 500; cursor: pointer;
}
.tool-btn:hover { background: var(--bg-hover); color: var(--text); }
.tool-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.tool-btn:disabled:hover { background: none; color: var(--text-dim); }
.tool-btn.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.tool-btn.busy { opacity: 0.6; }

/* ---------- Bilder an der Frage ----------
   Sie liegen UEBER der Werkzeugleiste und innerhalb des Eingabekastens: das
   Bild gehoert zur Nachricht, nicht zu den Schaltern. Ein Streifen und keine
   Liste - vier Bilder sind das Hoechste, das passt nebeneinander. */
.anhang-leiste {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  padding: var(--s2) var(--s3) 0;
}
.anhang-chip {
  position: relative; width: 56px; height: 56px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  overflow: hidden; background: var(--bg-hover);
}
.anhang-chip img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Der Wegnehmen-Knopf sitzt AUF dem Bild und ist dauerhaft da, nicht erst beim
   Ueberfahren: auf dem Telefon gibt es kein Ueberfahren, und ein versehentlich
   angehaengtes Foto muss man wieder loswerden koennen. */
.anhang-weg {
  position: absolute; top: 2px; right: 2px;
  width: 20px; height: 20px; display: flex; align-items: center;
  justify-content: center; padding: 0;
  border: none; border-radius: var(--r-pill); cursor: pointer;
  background: var(--auf-bild); color: var(--auf-bild-text);
}
.anhang-weg:hover { background: var(--auf-bild-stark); }
.anhang-chip.laedt { opacity: 0.5; }

/* Angehaengte Bilder in der bereits gesendeten Nachricht. Groesser als im
   Streifen: hier geht es ums Wiedererkennen, nicht ums Wegnehmen. */
.msg-anhaenge { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s2); }
.msg-anhaenge img {
  max-width: 190px; max-height: 190px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  display: block; cursor: zoom-in;
}

/* ---------- Denkteil ----------
   Standardmaessig ZU. Der Denkteil ist Arbeit, nicht Ergebnis; wer ihn sehen
   will, klappt ihn auf. Offen stehend draengt er die eigentliche Antwort nach
   unten aus dem Bild. */
.denk-block {
  margin-bottom: var(--s2); border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--bg-hover);
  font-size: var(--fs-sm);
}
.denk-block > summary {
  padding: var(--s2) var(--s3); cursor: pointer; color: var(--text-dim);
  list-style: none;
}
.denk-block > summary::-webkit-details-marker { display: none; }
.denk-block > summary::before { content: "▸ "; }
.denk-block[open] > summary::before { content: "▾ "; }
.denk-text {
  padding: 0 var(--s3) var(--s3); margin: 0; color: var(--text-dim);
  white-space: pre-wrap; word-break: break-word;
  max-height: 260px; overflow: auto;
}
/* Der Absendeknopf ist die Haupthandlung der Anwendung und war auf JEDER
   Größe 36 × 36 px - am Telefon das kleinste Ziel im Bild. */
.send-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--h-ziel); height: var(--h-ziel); margin-left: auto; flex-shrink: 0;
  border: none; border-radius: var(--r-pill); background: var(--accent);
  color: var(--auf-akzent); cursor: pointer; transition: background var(--tempo) var(--ease);
}
.send-btn:hover { background: var(--accent-hover); }
/* Solange eine Antwort läuft, ist der Knopf „Stopp" - und sieht auch so aus. */
.send-btn.stopp { background: var(--text); color: var(--bg); }
.send-btn:disabled { opacity: 0.35; cursor: not-allowed; }

.index-progress {
  margin-bottom: var(--s2); padding: var(--s3);
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-panel);
}
.index-progress-head { display: flex; gap: var(--s3); font-size: var(--fs-sm);
                       color: var(--text-dim); margin-bottom: var(--s2); }
.index-progress-head span:first-child { flex: 1; overflow: hidden;
                                        text-overflow: ellipsis; white-space: nowrap; }
/* Fuss der Fortschrittsanzeige im Bestandsabschnitt: erklaerender Satz links,
   Abbruch rechts. Der Abbruch steht bei dem Lauf, den er abbricht - und nicht
   in einer anderen Ansicht, in die man erst wechseln muesste. */
.bestand-lauf-fuss {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); margin-top: var(--s2);
}
.bestand-lauf-fuss .hint { margin: 0; min-width: 0; }
.bestand-lauf-fuss .btn { flex-shrink: 0; }
/* Abkuerzungen in Spaltenkoepfen. Der gepunktete Unterstrich ist die einzige
   Andeutung, dass es dort etwas zu lesen gibt; ohne ihn faende die Erklaerung
   niemand. `text-decoration` statt `border-bottom`, weil der Rahmen bei
   `text-transform: uppercase` unter der ganzen Zellbreite laege. */
.doc-table th abbr {
  text-decoration: underline dotted; text-underline-offset: 3px;
  cursor: help;
}
/* Auf der Karte gibt es keinen Spaltenkopf mehr - dort steht die Beschriftung
   vor dem Wert, und die Erklaerung waere ohnehin nicht erreichbar. */
/* Die Knoepfe darunter stellen sich schon ab 559 px untereinander (siehe
   `.bestand-knoepfe`) - hier NICHT wiederholen. Nur der Fuss der
   Fortschrittsanzeige braucht eine eigene Grenze: Satz und Abbruch
   nebeneinander werden darunter zu eng. */
@media (max-width: 559px) {
  .bestand-lauf-fuss { flex-wrap: wrap; }
  .bestand-lauf-fuss .btn { width: 100%; }
}

.scroll-down {
  position: absolute; right: var(--s5); z-index: var(--z-schwebend);
  bottom: calc(var(--eingabe-hoehe, 120px) + var(--s3));
  display: flex; align-items: center; justify-content: center;
  width: var(--h-ziel); height: var(--h-ziel);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--bg-panel); color: var(--text-dim);
  box-shadow: var(--shadow-mittel); cursor: pointer;
}
.scroll-down:hover { color: var(--text); background: var(--bg-hover); }

.ws-box {
  margin-bottom: var(--s2); padding: var(--s4);
  border: 1px solid var(--accent); border-radius: var(--r-md); background: var(--bg-panel);
}
.ws-box p { margin: 0 0 var(--s2); font-size: var(--fs-bd); }
.ws-box textarea { margin-bottom: var(--s3); }
.confirm-actions { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ============================================================
   6. Dokumente
   ============================================================ */
.upload-zone {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--h-ziel); padding: var(--s4); margin-bottom: var(--s4);
  border: 1.5px dashed var(--border-stark); border-radius: var(--r-lg);
  color: var(--text-dim); font-size: var(--fs-bd); cursor: pointer;
  transition: border-color var(--tempo), background var(--tempo);
}
.upload-zone { flex-wrap: wrap; }
.upload-zone:hover, .upload-zone.drag { border-color: var(--accent); background: var(--accent-soft); }
/* Beim Ziehen deutlicher als beim bloßen Überfahren: sonst ist der einzige
   Unterschied zwischen "hier könnte etwas hin" und "hier landet es jetzt"
   eine Randfarbe, die man mit dem Ordner unter dem Zeiger halb verdeckt. */
.upload-zone.drag { border-style: solid; box-shadow: var(--fokus); }
/* Ein `hidden`-Dateifeld ist display:none und kann den Fokus gar nicht
   bekommen - die Fläche selbst trägt deshalb tabindex und einen Fokusring. */
.upload-zone:focus-visible { border-color: var(--accent); box-shadow: var(--fokus); outline: none; }
.upload-text { flex: 1 1 16rem; min-width: 0; }
.upload-zone svg { color: var(--accent); flex-shrink: 0; }
.upload-zone strong { color: var(--text); display: block; font-size: var(--fs-lg); }
.upload-zone small {
  display: block; margin-top: var(--s0); font-size: var(--fs-sm); color: var(--text-dim);
  font-weight: 400;
}
/* Auf schmalen Schirmen unter den Text statt daneben - nebeneinander bliebe
   für den Dateinamen nichts übrig. */
@media (max-width: 559px) {
  /* Enger gefasst: die Dokumentenseite soll kurz bleiben - die Freigaben
     darunter muessen im zweiten Bildschirm noch erreichbar sein. */
  .upload-zone { padding: var(--s3); gap: var(--s2); }
}

/* Erscheint nur nach einem Fehlversuch und verschwindet beim nächsten Upload. */
.upload-fehler {
  margin: var(--s2) 0 var(--s4); padding: var(--s3); border-radius: var(--r-sm);
  border: 1px solid var(--danger); background: var(--danger-soft);
  color: var(--danger); font-size: var(--fs-md); line-height: var(--lh);
}
.upload-fehler strong { display: block; margin-bottom: var(--s0); }
.upload-fehler .formate { color: var(--text-dim); font-size: var(--fs-sm); }

.confirm-bar {
  padding: var(--s3) var(--s4); margin-bottom: var(--s4);
  border: 1px solid var(--warn); border-radius: var(--r-md); background: var(--warn-soft);
}
.confirm-bar p { margin: 0 0 var(--s3); font-size: var(--fs-bd); }
/* Die Gruende eines Gruppierungsvorschlags. Sie stehen da, damit die
   Entscheidung nachvollziehbar ist - eine blosse Prozentzahl waere eine
   Behauptung, der man glauben muss. */
.gruppe-gruende {
  margin: 0 0 var(--s3);
  padding-left: 1.1em;
  color: var(--text-dim);
  font-size: var(--fs-sm);
  line-height: 1.5;
}
.gruppe-gruende li { margin: 0; }

/* ---------- Filter ----------
   Als Raster, nicht als Flexbox mit Richtungswechsel. Vorher stand hier
   `flex-direction: column` mit `flex: 2 1 190px` auf den Feldern - in einer
   Spalte gilt die Basis für die HÖHE, also wurden Suchfeld und beide
   Auswahlfelder je rund 200 px hoch und füllten auf dem Telefon den ganzen
   Schirm. Ein Raster kennt das Problem nicht. */
/* Flex statt Raster: die Zahl der Filter ist nicht mehr fest. Der
   Herkunftsfilter erscheint erst mit der ersten Freigabe, und ein Raster mit
   fester Spaltenzahl liesse dann entweder eine leere Spalte stehen oder
   schoebe den Knopf in eine zweite Zeile. */
.filterleiste {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--border);
}
.filterleiste input[type="search"] { flex: 3 1 100%; }
.filterleiste select { flex: 1 1 100%; }
.filterleiste .btn { flex: 0 0 auto; align-self: center; }
@media (min-width: 560px) {
  .filterleiste input[type="search"] { flex: 3 1 200px; }
  .filterleiste select { flex: 1 1 148px; }
}

/* ---------- Listenleiste ----------
   Sortierung und "alle auswählen" saßen im <thead>. Der wird auf schmalen
   Displays ausgeblendet (Kartenansicht) - damit gab es auf dem Telefon KEINE
   Möglichkeit zu sortieren oder alles auszuwählen, obwohl beides am Rechner
   ging. Beides steht jetzt hier und gilt auf jeder Größe. */
.listenleiste {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2) var(--s3);
  padding: var(--s2) var(--s4);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-md); color: var(--text-dim);
}
.listenleiste .wahl-alle { display: flex; align-items: center; gap: var(--s2);
                           min-height: var(--h-ziel-klein); cursor: pointer; }
.listenleiste .wahl-alle input { width: 18px; height: 18px; accent-color: var(--accent);
                                 cursor: pointer; }
.listenleiste .zaehler { font-variant-numeric: tabular-nums; }

.bulk-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2);
  padding: var(--s2) var(--s4); background: var(--accent-soft);
  border-bottom: 1px solid var(--border); font-size: var(--fs-bd);
}
.bulk-bar span { flex: 0 0 auto; font-weight: 600; color: var(--accent); }
/* Das Ziehen ist eine Mausgeste. Am Finger gibt es sie nicht - dort waere der
   Hinweis eine Anleitung fuer etwas Unmoegliches, also steht er da nicht.
   Die Handlung selbst bleibt ueber „In Ordner …“ auf jedem Geraet. */
/* Die Zahl der Ausgewaehlten ist zugleich der Griff. Die Riffelung links davon
   ist die uebliche Marke fuer "hier anfassen" und kostet 10 px - ein
   erklaerender Satz haette die Knopfreihe daneben auf zwei Zeilen gedrueckt.
   Gezeichnet als Punktraster, nicht als Zeichen: ein Braille-Glyph sieht in
   jeder Schrift anders aus. */
.bulk-bar .auswahl-griff {
  display: inline-flex; align-items: center; gap: var(--s2);
  margin-right: auto; padding: var(--s1) var(--s2);
  border-radius: var(--r-xs); cursor: grab;
}
.bulk-bar .auswahl-griff::before {
  content: ""; flex: 0 0 10px; width: 10px; height: 16px;
  background-image: radial-gradient(currentColor 1.1px, transparent 1.3px);
  background-size: 5px 5px; opacity: 0.55;
}
.bulk-bar .auswahl-griff:hover { background: var(--bg-panel); }
.bulk-bar .auswahl-griff:active { cursor: grabbing; }
/* Am Finger gibt es kein Ziehen - dort ist die Zahl nur eine Zahl, und der
   Weg in einen Ordner fuehrt ueber „In Ordner …“ daneben. */
@media (pointer: coarse) {
  .bulk-bar .auswahl-griff { cursor: default; padding-left: 0; }
  .bulk-bar .auswahl-griff::before { display: none; }
  .bulk-bar .auswahl-griff:hover { background: none; }
}

/* ---------- Tabelle ----------
   Die Liste bekommt wieder einen eigenen Rollbereich - diesmal mit den zwei
   Vorkehrungen, an denen der erste gescheitert ist.
   Damals: `max-height: 74vh`, keine Kante, kein Hinweis. Das Ende des Kastens
   sah aus wie das Ende der Liste, und dreizehn von zweiundzwanzig Dokumenten
   fand niemand.
   Jetzt: (1) der Kasten hat eine Kante und endet mitten in einer Zeile - eine
   angeschnittene Zeile ist der ehrlichste Hinweis, dass es weitergeht.
   (2) Ein Schatten an der oberen und unteren Kante zeigt, in welche Richtung
   noch etwas liegt; er verschwindet genau dann, wenn man dort angekommen ist
   (die Verläufe mit `local` rollen mit dem Inhalt und schieben die mit
   `scroll` zu).
   Das gilt nur noch am Telefon (Höhe im Abschnitt „Unter 760 px“). Am Rechner
   rollt die Liste seit dem 28.09.2026 mit der Seite („Die Liste rollt mit der
   Seite“). */
.doc-scroll {
  overflow: auto;
  overscroll-behavior-x: contain;
  /* Rollen bleibt an der Seite verkettet: wer unten ankommt, rollt weiter die
     Seite - sonst wäre der Kasten genau die Falle, die er vermeiden soll. */
  background:
    linear-gradient(var(--bg-panel) 30%, var(--flaeche-klar)) center top,
    linear-gradient(var(--flaeche-klar), var(--bg-panel) 70%) center bottom,
    radial-gradient(farthest-side at 50% 0,
                    var(--kante-schatten), var(--kante-schatten-klar)) center top,
    radial-gradient(farthest-side at 50% 100%,
                    var(--kante-schatten), var(--kante-schatten-klar)) center bottom;
  background-repeat: no-repeat;
  background-size: 100% 28px, 100% 28px, 100% 10px, 100% 10px;
  background-attachment: local, local, scroll, scroll;
  /* Runde 64: ohne die Karte drumherum trägt der Kasten selbst die Kante -
     ein Rollbereich muss als Kasten erkennbar sein (Lehre aus Runde 24). */
  border: 1px solid var(--kante-fein); border-radius: var(--r-md);
}
.doc-table { width: 100%; border-collapse: collapse; font-size: var(--fs-bd); }
/* Zahlen stehen rechtsbündig und in gleich breiten Ziffern - so stehen Einer
   unter Einern, und eine Spalte lässt sich überfliegen. Vorher galt das nur
   im Betrieb. */
.doc-table .zahl-zelle { text-align: right; font-variant-numeric: tabular-nums; }
/* Die Handlungsspalte der Nebentabellen nimmt nur, was ihre Knöpfe brauchen;
   die Knöpfe stehen in einem Behälter IN der Zelle (siehe settings.nuRender). */
.karten-tabelle td.col-aktion { width: 1%; white-space: nowrap; }
/* Zwei Knöpfe direkt in der Zelle („Ansehen", „Fortsetzen") standen Kante an
   Kante - aus JS gebaut, fehlt der Leerraum zwischen ihnen. */
.col-aktion > button + button { margin-left: var(--s2); }
/* `table-layout: fixed` ist hier der Kern der Sache.
   Im automatischen Layout bestimmt der INHALT die Spaltenbreite: ein langer
   Dateiname zog die Namensspalte auf, die Tabelle wurde breiter als ihr Kasten
   (gemessen 1582 px in einem 648 px breiten Behälter) und die Handlungsspalte
   lag ausserhalb des Bildes. Alle bisherigen Versuche, das über `width: 1%` und
   `min-width: max-content` zu steuern, verschoben das Problem nur zwischen den
   Spalten. Bei fester Aufteilung gibt der Spaltenkopf die Breite vor, der
   Inhalt kann sie nicht mehr sprengen - und der Name wird gekürzt statt zu
   drängeln. */
.doc-table-haupt { table-layout: fixed; }
.doc-table-haupt .col-check  { width: 44px; }
/* 132 -> 152 px: die haeufigen Bereiche ("versicherungsschein",
   "elektrizitätsrechnung") passen damit ohne Kuerzung; die seltenen langen
   werden gekuerzt und stehen vollstaendig im title. */
.doc-table-haupt .col-bereich { width: 152px; }
.doc-table-haupt .col-datum  { width: 116px; }
/* 184 -> 208 px: "durchsuchbar" und ein Zustands-Chip sollen nach Moeglichkeit
   nebeneinander passen, ohne dass die Namensspalte spuerbar leidet. */
.doc-table-haupt .col-status { width: 208px; }
.doc-table-haupt .col-aktion { width: 52px; }
/* Die Namensspalte nimmt auf, was übrig bleibt - `auto` ist hier die Aussage,
   nicht der Vorgabewert: sie ist die EINE Spalte ohne feste Breite. */
.doc-table-haupt .col-name { width: auto; }
.doc-table th {
  padding: var(--s3); text-align: left; font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.doc-table td { padding: var(--s2) var(--s3); border-bottom: 1px solid var(--border);
                vertical-align: middle; }
.doc-table tbody tr:last-child td { border-bottom: none; }
.doc-table tbody tr:hover { background: var(--bg-hover); }
/* Eine Auswahl muss man ueberfliegen koennen. Die Flaeche allein ist zart;
   die Kante links steht auch dann, wenn die Zeile gerade unter dem Zeiger
   liegt oder das Fenster schmal ist. */
.doc-table tr.selected { background: var(--accent-soft); }
.doc-table-haupt tbody tr.selected > td:first-child {
  box-shadow: inset 3px 0 0 var(--accent);
}
.doc-table a { color: var(--text); text-decoration: none; }
.doc-table a:hover { color: var(--accent); text-decoration: underline; }
.doc-table-haupt thead th {
  position: sticky; top: 0; z-index: var(--z-haftend);
  background: var(--bg-panel);
  box-shadow: inset 0 -1px 0 var(--border);
}

/* Eine Zeile bleibt EINE Zeile. Die Flex-Container sitzen INNERHALB der Zelle,
   nicht auf ihr: ein <td> mit display:flex fällt aus dem Tabellenfluss
   (siehe documents.js, flexZelle). */
.doc-name { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.doc-name > a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
                font-weight: 500; }
/* UMBRUCH ERLAUBT. Vorher `white-space: nowrap` in einer 184 px breiten
   Spalte: "durchsuchbar" plus ein Chip sind zusammen breiter, der Rest lief
   aus der Spalte heraus und wurde von der naechsten ueberdeckt (gemeldet am
   09.09.2026). Umbrechen laesst nur die AUSNAHME-Zeilen etwas hoeher werden -
   der Regelfall ist ein einzelnes Wort und bleibt einzeilig. */
.doc-index {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: calc(var(--s0) + 1px) var(--s2); white-space: nowrap;
}
.doc-action { display: flex; align-items: center; justify-content: flex-end; gap: var(--s0); }
/* Kein `min-width: max-content` mehr: das war der Notnagel für das
   automatische Tabellenlayout und liess die Zellen ihren Kasten sprengen.
   Bei fester Spaltenaufteilung steht die Breite ohnehin fest. */
.doc-action > * { flex-shrink: 0; }
.doc-action .hint { margin: 0; }

/* Die Nebenspalten führen keinen Umbruch - ihre Breite steht oben fest. */
.doc-table-haupt tbody tr:not(.register-row) > td:not(.zelle-name) { white-space: nowrap; }
.doc-table-haupt .zelle-name { overflow: hidden; }
.register-row > td { white-space: normal; width: auto; }
.col-check input { width: 18px; height: 18px; cursor: pointer; accent-color: var(--accent); }
.col-datum { white-space: nowrap; color: var(--text-dim); font-variant-numeric: tabular-nums; }
/* Der Bereich wird aus dem Dokument abgeleitet und kann lang werden. Ohne
   Begrenzung lief der Chip aus seiner Spalte und legte sich ueber das Datum -
   `table-layout: fixed` haelt die SPALTE fest, nicht ihren Inhalt.
   `display: inline-block` ist noetig, damit text-overflow greift: `.chip` ist
   sonst ein inline-flex, und dort wirkt es nicht. */
.col-bereich { white-space: nowrap; overflow: hidden; }
.col-bereich .chip {
  margin: 0; display: inline-block; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; vertical-align: middle;
}
.col-aktion { width: 1%; }
.register-row > td { padding: 0 var(--s3) var(--s3) var(--s9); background: var(--bg); }
.register-kopf { margin-bottom: var(--s2); color: var(--text-dim); font-size: var(--fs-sm); }
.register-liste {
  display: grid; grid-template-columns: auto 1fr; gap: var(--s1) var(--s4);
  margin: 0; font-size: var(--fs-md);
}
.register-liste dt { color: var(--text-dim); }
.register-liste dd { margin: 0; }
.register-liste dd a { color: var(--accent); text-decoration: none; }
.register-liste dd a:hover { text-decoration: underline; }

/* Sortierbare Spaltenköpfe (nur die Tabellenfassung; die Listenleiste trägt
   dieselbe Sortierung als Menü). */
.doc-table th:has(.sortier) { padding: 0; }
.sortier {
  display: flex; align-items: center; gap: var(--s1);
  width: 100%; min-height: var(--h-ziel-klein); padding: var(--s2) var(--s3);
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim);
}
.sortier:hover { color: var(--text); background: var(--bg-hover); }
.sortier.aktiv { color: var(--accent); }
/* Derselbe Winkel wie überall sonst, nur gedreht - vorher standen hier die
   Textzeichen ▲/▼ in eigener Größe. Ein Richtungszeiger ist dieselbe Aussage
   wie ein Aufklappzeiger; er soll auch gleich aussehen. */
.sortier.aktiv::after {
  content: ""; width: 6px; height: 6px; flex-shrink: 0;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-135deg); margin-top: calc(var(--s0) + 1px);
}
.sortier.aktiv[data-richtung="ab"]::after { transform: rotate(45deg); margin-top: -3px; }

/* Die Statuszeile steht seit dem 04.09.2026 DIREKT unter der Ablagefläche und
   nicht mehr unter der Liste - dort lag sie auf dem Telefon hinter einem
   eigenen Rollbereich mit zweiundzwanzig Zeilen und war nach einem Upload
   schlicht nicht im Bild. Sie ist deshalb jetzt ein eigener Kasten und nicht
   mehr die Fußzeile eines fremden. */
.job-status:not(:empty) {
  margin-bottom: var(--s4); padding: var(--s3) var(--s4);
  border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-panel);
}
.job-line { font-size: var(--fs-md); }
.job-head { display: flex; gap: var(--s3); align-items: baseline; margin-bottom: var(--s2);
            flex-wrap: wrap; }
.job-head strong { font-size: var(--fs-bd); }
/* Wo die Folge feststeht, steht sie dabei - klein, denn sie ordnet ein, sie
   ist nicht die Nachricht. */
.job-schritt { color: var(--text-dim); font-size: var(--fs-sm);
               font-variant-numeric: tabular-nums; }
/* Abbrechen und Wiederholen: die einzige Handlung an dieser Zeile, deshalb
   rechts abgesetzt und mit vollem Zielmaß. */
.job-tat {
  margin-left: auto; min-height: var(--h-ziel-klein); padding: 0 var(--s3);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--bg); color: var(--accent); cursor: pointer;
  font: inherit; font-size: var(--fs-sm); font-weight: 500;
}
.job-tat:hover { background: var(--bg-hover); border-color: var(--accent); }
.job-phase { color: var(--text-dim); }
.job-error { color: var(--danger); }
.job-warn { margin-top: var(--s2); color: var(--warn); font-size: var(--fs-sm); }
.job-hinweis { margin-top: var(--s1); color: var(--text-dim); font-size: var(--fs-sm); }

/* Statusspalte: der Regelfall leise, die Ausnahme laut. Vorher trug jede Zeile
   dieselbe gruene Plakette - eine Spalte, in der 22-mal dasselbe steht, kostet
   Aufmerksamkeit und gibt keine zurueck. */
.stand-still { color: var(--text-dim); font-size: var(--fs-sm); }
/* Der GRUND unter einem Warnhinweis - dieselbe Aussage wie im title, aber
   sichtbar. Ein title erscheint erst beim Verweilen mit der Maus und auf einem
   Tastgeraet gar nicht; ein Zustand, den man nur mit der Maus erklaert bekommt,
   ist fuer die Haelfte der Nutzung unerklaert. */
/* `.stand-grund` ist am 09.09.2026 entfallen: der Erklaersatz stand als
   dritte Angabe in einer 184-px-Spalte mit max-width 26em und lief heraus.
   Er steckt jetzt im `title` und im aria-label des Chips - sichtbar auf
   Nachfrage, nicht dauerhaft im Weg. */

/* ---------- Ordnerbaum ---------- */
.doc-layout { display: block; }
/* Der Ziehgriff existiert nur in der zweispaltigen Fassung. Unter 1200 px
   liegt der Baum ueber der Liste und ist so breit wie sie - da gibt es nichts
   zu ziehen, und ein unsichtbarer Griff im Tabulator-Lauf waere eine Falle. */
.baum-griff { display: none; }
.ordnerbaum {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--s2); border-bottom: 1px solid var(--border);
  max-height: 220px; overflow: auto; overscroll-behavior: contain;
}
/* Ein Knoten ist Filter UND Ablageziel: anklicken filtert, Zeilen darauf fallen
   lassen sortiert ein. Die Einrückung kommt aus der Tiefe, nicht aus
   verschachteltem Markup - eine flache Liste lässt sich in einem Zug neu
   zeichnen, ohne den Aufklappzustand zu verlieren. */
.baum-knoten {
  display: flex; align-items: center; gap: var(--s1);
  min-height: var(--h-ziel-klein); padding: var(--s1) var(--s2);
  border-radius: var(--r-xs); cursor: pointer;
  font-size: var(--fs-md); color: var(--text); white-space: nowrap;
}
.baum-knoten:hover { background: var(--bg-hover); }
.baum-knoten.aktiv { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
/* Der Pfeil war ein <span> mit Klickhandler: nicht fokussierbar, für die
   Tastatur also gar nicht vorhanden, und 16 px breit. Jetzt ein echter Knopf
   mit vollem Zielmaß. */
/* 30 px am Mauszeiger, volles Zielmass am Finger (siehe unten). Mit dem
   Zielmass auf JEDER Groesse blieben in der 220 px schmalen Baumspalte nur
   rund 110 px fuer den Ordnernamen uebrig - "Versicherungen" wurde zu
   "Versicherung...". Wo mit der Maus gezeigt wird, ist ein 30-px-Ziel
   vertretbar; wo mit dem Finger getippt wird, steht der Baum ohnehin ueber die
   volle Breite. */
.baum-knoten .pfeil {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex: 0 0 auto;
  margin: calc(var(--s1) * -1) 0;
  border: none; border-radius: var(--r-xs); background: none;
  color: var(--text-dim); cursor: pointer;
}
.baum-knoten .pfeil:hover { background: var(--bg-active); color: var(--text); }
.baum-knoten .pfeil.leer { visibility: hidden; }
/* `min-width: 0` ist hier kein Zierrat: ein Flex-Element schrumpft ohne das
   nicht unter seine Inhaltsbreite, und ein langer Ordnername ("Rechnungen
   Lieferanten 2025 Q3 Abschluss") schoebe dann Zahl und Menue aus der
   Seitenleiste. `overflow: hidden` allein deckt den Fall in aelteren Browsern
   nicht zuverlaessig ab. */
.baum-knoten .beschriftung {
  overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; min-width: 0;
}
/* Zahl und Pfeil duerfen NIE schrumpfen - sie sind die Auskunft, der Name ist
   der Teil, der gekuerzt werden kann. */
.baum-knoten .zahl {
  color: var(--text-dim); font-variant-numeric: tabular-nums; font-size: var(--fs-sm);
  flex-shrink: 0;
}
.baum-knoten .pfeil { flex-shrink: 0; }
.baum-knoten.aktiv .zahl { color: inherit; }
/* Aus dem einzelnen "x" ist ein Menue geworden - dieselbe Form wie an der
   Dokumentzeile. Umbenennen und Verschieben gab es vorher gar nicht. */
.baum-knoten .weg {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex: 0 0 auto;
  margin: calc(var(--s1) * -1) 0;
  border: none; border-radius: var(--r-xs); background: none;
  color: var(--text-dim); cursor: pointer; line-height: 1;
  opacity: 0;
}
.baum-knoten:hover .weg, .baum-knoten:focus-within .weg { opacity: 1; }
.baum-knoten .weg:hover { color: var(--text); background: var(--bg-active); }
@media (pointer: coarse) {
  .baum-knoten .weg { opacity: 1; }
  .baum-knoten .pfeil, .baum-knoten .weg {
    width: var(--h-ziel-klein); height: var(--h-ziel-klein);
  }
}
/* Dateien als Blätter - wie im Explorer. */
.baum-datei {
  display: flex; align-items: center; gap: var(--s2);
  min-height: var(--h-ziel-klein); padding: var(--s1) var(--s2);
  border-radius: var(--r-xs); text-decoration: none;
  font-size: var(--fs-md); color: var(--text-dim); white-space: nowrap;
}
.baum-datei:hover { background: var(--bg-hover); color: var(--text); }
.baum-datei .blatt-marke { width: 16px; flex: 0 0 16px; text-align: center; opacity: 0.6; }
.baum-datei .beschriftung { overflow: hidden; text-overflow: ellipsis; }
.baum-datei.offen-datei .beschriftung { font-style: italic; opacity: 0.75; }
.baum-neu { color: var(--text-dim); border: 1px dashed var(--border-stark); margin-top: var(--s2); }
/* Ueberschrift ueber dem, was ANDERE freigegeben haben. Es gibt sie nur, wenn
   es wirklich zwei Herkuenfte gibt - eine Ueberschrift ueber genau einem Ding
   beschriftet nichts. Ueber der eigenen Ablage steht bewusst keine: "Meine
   Dokumente" sagt sich selbst. */
.baum-abschnitt {
  margin: var(--s3) var(--s1) var(--s1);
  padding-top: var(--s2); border-top: 1px solid var(--border);
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-dim); white-space: normal;
}
/* Fremde Aeste tragen die Herkunft EINMAL - am Kopf des Astes, nicht an jeder
   Zeile. Der Strich links laeuft ueber alle Knoten des Astes und sagt bis in
   die Tiefe, dass man hier zu Gast ist. */
.baum-knoten.fremd-knoten { border-left: 2px solid var(--accent-soft-stark); }
.baum-knoten.fremd-knoten .beschriftung { color: var(--text-dim); }
.baum-knoten.fremd-knoten.aktiv .beschriftung { color: inherit; }
.baum-marke {
  flex: 0 0 auto; padding: 0 var(--s1); border-radius: var(--r-xs);
  background: var(--bg-active); color: var(--text-dim); font-size: var(--fs-xs);
}

/* ---------- Ziehen ----------
   Das Zugbild haengt am Zeiger und sagt, WAS wandert. Es liegt ausserhalb des
   Bildes: der Browser fotografiert es beim dragstart, danach wird es entfernt.
   Ohne dieses Bild zeigte der Zeiger eine einzelne Zeile, auch wenn fuenfzehn
   Dokumente markiert waren. */
.zugbild {
  position: fixed; top: -1000px; left: -1000px; z-index: var(--z-toast);
  /* Durchsichtige Ecke oben links: dort liegt der Greifpunkt, der Mauszeiger
     steht also NEBEN der Marke statt auf ihr. Vorher verdeckte er die Zahl. */
  padding: var(--s5) 0 0 var(--s6); background: none;
}
.zugbild-marke {
  display: inline-block;
  padding: var(--s2) var(--s3); border-radius: var(--r-sm);
  background: var(--accent); color: var(--auf-akzent);
  font-size: var(--fs-md); font-weight: 600; white-space: nowrap;
  box-shadow: var(--shadow-stark);
}
.doc-table-haupt tbody tr[draggable="true"] { cursor: grab; }
.doc-table-haupt tbody tr[draggable="true"]:active { cursor: grabbing; }
.baum-knoten[draggable="true"] { cursor: grab; }
/* Solange etwas am Haken haengt, zeigen ALLE Ziele einen Rahmen. Vorher sah
   man erst beim Ueberfahren, dass ein Ordner ein Ziel ist - man musste raten,
   wohin man ueberhaupt ziehen darf. */
body.zieht-etwas .baum-knoten:not(.zieht):not(.baum-neu) {
  outline: 1px dashed var(--border-stark); outline-offset: -2px;
}
body.zieht-etwas .ordnerbaum { background: var(--accent-soft); border-radius: var(--r-xs); }
/* "Alle Dokumente" ist der Weg heraus - aus einem Ordner wie aus einem
   Unterordner. Der Baum hat einen eigenen Rollbereich; steht der Wurzelknoten
   gerade nicht im Bild, waere dieser Weg beim Ziehen unerreichbar. Waehrend
   eines Zugs klebt er deshalb oben. */
/* Wohin muss ein Ordner, damit er auf der obersten Ebene landet? Die Antwort
   steht waehrend des Zugs AM ZIEL - nicht erst im Streifen unten, den man erst
   liest, wenn man schon daraufsteht. */
.wurzel-zugziel { display: none; }
body.zieht-etwas .wurzel-zugziel {
  display: inline; flex: 0 0 auto; margin-left: auto;
  padding: 0 var(--s2); border-radius: var(--r-xs);
  background: var(--accent); color: var(--auf-akzent);
  font-size: var(--fs-xs); font-weight: 600; white-space: nowrap;
}
/* Am verbotenen Ziel waere die Einladung eine Luege. */
body.zieht-etwas .baum-knoten.kein-ziel .wurzel-zugziel { display: none; }

body.zieht-etwas .baum-knoten[data-schluessel="0:"] {
  position: sticky; top: 0; z-index: 1; background: var(--bg-panel);
  box-shadow: 0 1px 0 var(--border);
}
/* Waehrend eines Zugs steht unten im Baum in WORTEN, was passieren wuerde.
   Eine hervorgehobene Zeile sagt "hier" - sie sagt nicht, wie der Ordner
   danach heisst und auf welcher Ebene er liegt. Klebt unten, damit sie auch
   dann zu lesen ist, wenn man weit unten im Baum zielt. */
.baum-hinweis {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: var(--s5); z-index: var(--z-toast);
  max-width: min(92vw, 640px);
  padding: var(--s2) var(--s4); border-radius: var(--r-pill);
  border: 1px solid var(--accent);
  background: var(--bg-panel); color: var(--text-dim);
  font-size: var(--fs-md); line-height: 1.3; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  box-shadow: var(--shadow-stark); pointer-events: none;
}
.baum-hinweis strong { color: var(--accent); font-weight: 600; }
/* Ein verbotenes Ziel bekommt denselben Streifen - mit dem GRUND darin. Ein
   blosses Verbotszeichen am Zeiger beantwortet die falsche Frage: wer nicht
   ablegen kann, will wissen, woran es liegt, sonst probiert er dieselbe Stelle
   noch dreimal. */
.baum-hinweis.nein { border-color: var(--warn); color: var(--warn); }
/* Was den Gegenstand am Haken nicht annehmen kann, leuchtet auch nicht auf.
   Es bleibt sichtbar (man muss noch lesen koennen, woran man vorbeizielt),
   verliert aber den Rahmen, der ein Ziel verspricht. */
body.zieht-etwas .baum-knoten.kein-ziel {
  outline: none !important; opacity: 0.5; cursor: not-allowed;
}
/* Der ganze Ast wandert mit - nicht nur die angefasste Zeile. */
.baum-knoten.zieht-ast { opacity: 0.45; }
/* Der Ordner unter dem Zeiger ist nicht "auch ein Ziel", sondern DAS Ziel.
   Weiter oben stand einmal eine zweite, gestrichelte Fassung dieser Regel -
   sie war wirkungslos, weil diese hier spaeter kommt. Entfernt am 10.09.2026.
   Das `!important` bleibt und ist noetig: der Knoten traegt `tabindex="0"`,
   und die allgemeine Regel `[tabindex]:focus-visible` steht weiter unten in
   dieser Datei. Bei gleicher Spezifitaet gewaenne sonst der Fokusring, und
   ausgerechnet waehrend des Ziehens waere nicht mehr zu sehen, wohin es
   faellt. */
.baum-knoten.ziel { outline: 2px solid var(--accent) !important; outline-offset: -2px;
                    background: var(--accent-soft); color: var(--accent); font-weight: 600; }
/* Was gerade gezogen wird, tritt zurueck - Ordner wie Zeile. Die zweite,
   wortgleiche Zeile fuer die Tabellenzeile stand bis zum 10.09.2026 direkt
   darunter und tat nichts. */
.baum-knoten.zieht, .doc-table-haupt tbody tr.zieht { opacity: 0.45; }

/* ============================================================
   7. Freigaben, Formulare, Einstellungen
   ============================================================ */
/* Als Raster - aus demselben Grund wie die Filterleiste: die Flex-Fassung mit
   Richtungswechsel machte die Beschriftungsblöcke auf schmalen Displays
   150 px HOCH. */
.freigabe-form {
  display: grid; gap: var(--s3);
  grid-template-columns: 1fr;
  align-items: end;
  padding: var(--s4); margin-bottom: var(--s5);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg);
}
@media (min-width: 620px) {
  .freigabe-form { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
  .freigabe-form .btn { grid-column: auto; }
}
.freigabe-form label { display: flex; flex-direction: column; gap: var(--s1);
                       font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim);
                       min-width: 0; }
.freigabe-form .btn { min-height: var(--h-feld); }

/* Kontoliste und Zugriffsliste tragen freien NUTZERTEXT: ein Name darf 121
   Zeichen lang werden (Vor- und Nachname je 60), ein Benutzername 40, ein
   Bereichsname kommt aus dem Dokument. Diese beiden Tabellen laufen im
   automatischen Layout - anders als die Dokumententabelle, denn ihre
   Handlungsspalte traegt Textknoepfe ("Wiederherstellen"), die eine feste
   Breite abschneiden wuerde.
   Im automatischen Layout aber bestimmt der laengste Wert die Spaltenbreite:
   die Tabelle wuechse ueber ihren Kasten hinaus, und weil `.view` waagerecht
   ABSCHNEIDET statt zu rollen, waeren die Knoepfe am rechten Rand nicht mehr
   erreichbar - derselbe Fehler, den die Dokumententabelle schon hatte.
   Deshalb liegt die Grenze am Text selbst: ein Block mit Hoechstbreite kann die
   Spalte nicht mehr aufziehen. Unter 760 px wird die Zeile zur Karte, dort ist
   die volle Breite da und die Grenze faellt weg. */
/* Gleiches gilt fuer die Freigabelisten: dort steht der DATEINAME als Umfang,
   und der darf bis 251 Zeichen lang sein. */
.karten-tabelle .zellentext, .fg-block .zellentext { display: block; }
@media (min-width: 760px) {
  .karten-tabelle .zellentext, .fg-block .zellentext {
    max-width: 24ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* Die drei Laeufe nebeneinander, der teure ganz rechts: die Reihenfolge ist
   die Reihenfolge der Kosten. Auf schmalen Geraeten untereinander, damit kein
   Knopf halb aus dem Bild ragt - gerade dieser darf nicht versehentlich
   getroffen werden. */
.bestand-knoepfe { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.bestand-knoepfe .btn { flex: 0 1 auto; }
@media (max-width: 559px) {
  .bestand-knoepfe { flex-direction: column; }
  .bestand-knoepfe .btn { width: 100%; }
}

.fg-block { margin-top: var(--s5); }
.fg-block .doc-table td:first-child { padding-left: 0; }
.fg-block .leer-zustand { padding: var(--s3) 0; text-align: left; }

.info-list { display: grid; grid-template-columns: auto 1fr; gap: var(--s2) var(--s4);
             margin: 0 0 var(--s4); }
.info-list-eng { font-size: var(--fs-bd); gap: var(--s1) var(--s4); }
.info-list dt { color: var(--text-dim); }
.info-list dd { margin: 0; font-variant-numeric: tabular-nums; }

/* Ungelesene Antwort in der Chatliste. Ein Punkt, keine Zahl: es geht um
   "da ist etwas", nicht um wie viel. Der pulsierende Zustand zeigt, dass noch
   geschrieben wird - er hört von selbst auf, sobald die Antwort fertig ist. */
.chat-punkt { width: 8px; height: 8px; border-radius: var(--r-pill); flex: none;
              background: var(--accent); margin-right: var(--s2); }
.chat-punkt.schreibt { animation: chat-punkt-puls var(--tempo-puls) ease-in-out infinite; }
@keyframes chat-punkt-puls { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .chat-punkt.schreibt { animation: none; opacity: .6; }
}
/* Auf welchem Gerät eine Stufe rechnet. Gedämpft, weil es eine Randnotiz zum
   Modellnamen ist - aber sichtbar, weil es erklärt, was wie schnell ist. */
.geraet-marke { color: var(--text-dim); font-size: var(--fs-sm);
                white-space: nowrap; }

/* ---------- Einstellungsgruppen (Runde 64) ----------
   Links, WAS eine Einstellung regelt und was daraus folgt, rechts die
   Bedienung - ab 900 px nebeneinander, darunter untereinander. Vorher standen
   Formulare, Wertelisten und Hinweissätze gleichrangig in einer Spalte, und
   die Speicherknöpfe sahen überall anders aus. */
.einstellung {
  display: grid; gap: var(--s3) var(--s7); grid-template-columns: minmax(0, 1fr);
  padding: var(--s5) 0; border-top: 1px solid var(--kante-fein);
}
.einstellung:first-of-type { padding-top: var(--s2); border-top: 0; }
.einstellung-text h3 { margin: 0 0 var(--s1); font-size: var(--fs-lg); }
.einstellung-text .hint { margin: 0; }
/* Oben ausgerichtet: sonst zieht das Raster die Bedienung auf die Höhe des
   Erklärtexts daneben (die Wahlkarten der Darstellung standen 86 px hoch). */
.einstellung-feld { min-width: 0; align-self: start; }
@media (min-width: 900px) {
  .einstellung { grid-template-columns: minmax(12rem, 1fr) minmax(0, 2fr); }
}
/* Etwas NEU anlegen (Konto, Zugriff): abgesetzt unter der Liste, auf einer
   eingelassenen Fläche - es ist eine andere Handlung als das Lesen der Liste. */
.einstellung.einstellung-rahmen, .einstellung.einstellung-rahmen:first-of-type {
  margin-top: var(--s5); padding: var(--s5);
  border: 1px solid var(--kante-fein); border-radius: var(--r-lg);
  background: var(--flaeche-abschnitt);
}
.einstellung-feld.freigabe-form { margin: 0; padding: 0; border: 0; background: none; }
.einstellung-feld .freigabe-form { margin: 0 0 var(--s3); padding: 0; border: 0; background: none; }
.einstellung-feld .freigabe-form select { max-width: 24rem; }
/* Mehrere gleichrangige Knöpfe einer Gruppe: nebeneinander, oben bündig. */
.knopfreihe { display: flex; flex-wrap: wrap; gap: var(--s2); }
.einstellung-feld.unterpanel { margin: 0; padding: 0; border: 0; }
.einstellung-feld.unterpanel > summary { color: var(--accent); font-weight: 550; }
/* Eine Speicherleiste für jedes Formular: Hauptknopf, Verwerfen, Rückmeldung.
   Die Rückmeldung steht AM Formular, weil man nach dem Klick dorthin schaut. */
.speicherleiste { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); }
.speicher-meldung { color: var(--ok); font-size: var(--fs-md); font-weight: 550; }
.speicher-meldung:empty { display: none; }
/* Eine Wahl aus wenigen, sichtbar nebeneinander statt in einem Auswahlfeld. */
.wahlgruppe { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
.wahl-karte {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: var(--h-ziel); padding: var(--s2) var(--s4);
  border: 1px solid var(--border-stark); border-radius: var(--r-sm);
  background: var(--bg-panel); font-size: var(--fs-bd); cursor: pointer;
  transition: background var(--tempo) var(--ease), border-color var(--tempo) var(--ease);
}
.wahl-karte:hover { background: var(--bg-hover); }
.wahl-karte:has(input:checked) {
  border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600;
}
.wahl-karte:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.wahl-karte input { margin: 0; accent-color: var(--accent); }
/* Ein Reiter mit ungespeicherten Änderungen trägt einen Punkt davor. */
.abschnitt-nav a.ungesichert::before {
  content: ""; flex: none; width: var(--s2); height: var(--s2); margin-right: var(--s2);
  border-radius: var(--r-pill); background: var(--warn);
}

.feld-form { display: flex; flex-direction: column; gap: var(--s3); align-items: flex-start; }
.feld-form label { display: flex; flex-direction: column; gap: var(--s1);
                   font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim);
                   width: 100%; }
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
            gap: var(--s3); width: 100%; }
.form-row label { width: auto; }

.check { display: flex; align-items: flex-start; gap: var(--s3);
         min-height: var(--h-ziel); padding: var(--s1) 0;
         font-size: var(--fs-bd); line-height: var(--lh); cursor: pointer; }
.check input { margin-top: calc(var(--s0) + 1px); flex-shrink: 0; width: 18px; height: 18px;
               accent-color: var(--accent); cursor: pointer; }
.regler { margin: var(--s4) 0; }
.regler label { display: flex; gap: var(--s2); font-size: var(--fs-md); color: var(--text-dim);
                margin-bottom: var(--s2); }
.regler output { margin-left: auto; color: var(--accent); font-weight: 700;
                 font-variant-numeric: tabular-nums; }
/* Der Schieberegler-Griff war der Systemvorgabe überlassen (rund 16 px) und
   damit das kleinste Ziel der Einstellungsseite. */
.regler input[type="range"] {
  width: 100%; height: var(--h-ziel-klein); accent-color: var(--accent); cursor: pointer;
}

.prompt-item { padding-top: var(--s4); margin-top: var(--s4); border-top: 1px solid var(--border); }
.prompt-item:first-child { padding-top: 0; margin-top: 0; border-top: none; }
.prompt-head { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s2); }
.prompt-head strong { flex: 1; font-size: var(--fs-bd); }
.prompt-text { margin-bottom: var(--s3); font-size: var(--fs-md); line-height: var(--lh); }
.prompt-aktionen { display: flex; gap: var(--s2); }

/* Bereichsnavigation der Einstellungen. Acht Panels in einer Spalte hießen:
   scrollen, bis man findet, was man sucht. */
/* Runde 64: Reiter tragen ihre Marke als Strich - unten in der waagerechten
   Leiste, links in der Spalte. Die farbige Pille war eine zweite Knopfform
   neben den Knöpfen und zog den Blick vom Inhalt weg auf die Navigation. */
.abschnitt-nav {
  display: flex; flex-direction: row; gap: var(--s1); flex-wrap: wrap;
  margin-bottom: var(--s6); padding-bottom: 0;
  border-bottom: 1px solid var(--kante-fein);
}
.abschnitt-nav a {
  position: relative; display: inline-flex; align-items: center; min-height: var(--h-ziel);
  padding: var(--s1) var(--s3); border-radius: var(--r-sm) var(--r-sm) 0 0;
  color: var(--text-dim); text-decoration: none; font-size: var(--fs-bd); font-weight: 520;
  transition: color var(--tempo) var(--ease), background var(--tempo) var(--ease);
}
.abschnitt-nav a:hover { background: var(--bg-hover); color: var(--text); }
.abschnitt-nav a.aktiv { color: var(--text); font-weight: 620; }
.abschnitt-nav a.aktiv::after {
  content: ""; position: absolute; left: var(--s2); right: var(--s2); bottom: 0;
  height: var(--s0); border-radius: var(--r-pill); background: var(--accent);
}
/* Rubriken in der Leiste („Persönlich", „Verwaltung"): Beschriftung, kein
   Reiter - klein, gesperrt gesetzt, ohne Fläche. In der waagerechten Leiste
   entfallen sie, dort ordnet die Reihenfolge. Bis zum 23.09.2026 sahen die
   Zwischenzeilen des Prüfstands WIE Reiter aus und ließen sich nicht
   anklicken - deshalb hier bewusst keine Knopfform. */
.nav-rubrik { display: none; }
/* Nur ein Reiter sichtbar (Benutzeransicht der Einstellungen): eine Leiste mit
   einem einzigen Eintrag wäre eine Navigation ohne Wahl. */
.abschnitt-nav.einzeln { display: none; }
/* Ein Sprungziel darf nicht unter dem oberen Rand kleben. */
.panel[id] { scroll-margin-top: var(--s5); }

/* Ab 1200 px wird aus der Leiste eine mitlaufende Spalte links.
   Die Einstellungen waren eine einzelne 720-px-Spalte auf einem 1366er Schirm -
   rechts daneben lag die halbe Bildfläche brach, während man für den Weg von
   "Mein Konto" zu "Prompts" durch acht Bereiche scrollte. Jetzt trägt der freie
   Platz die Navigation, und sie bleibt beim Scrollen stehen. */
@media (min-width: 1200px) {
  /* Bis zum 22.09.2026 standen hier zwei Ansichts-Kennungen. Jede weitere
     Ansicht mit Reitern haette eine dritte gebraucht - und wer das vergisst,
     bekommt eine klebende Spalte UEBER dem Inhalt (am 21.09.2026 im
     Bildschirmfoto des ersten Prueflaufs gesehen; statisch war nichts zu
     bemerken). Jetzt traegt die Ansicht die Klasse, und das Gitter gilt fuer
     jede, die sie traegt. */
  /* Die klebende Spalte ist eine EIGENE Entscheidung, nicht die Folge der
     Reiter. Die Dokumente haben sie nicht: dort stehen Ordnerbaum, Liste und
     Handlungsleiste nebeneinander, und 200 px Leiste plus Spalte kosteten der
     Liste 228 px - die Handlungsleiste brach damit auf zwei Zeilen um
     (ui/ordner.py, 22.09.2026). Dort bleibt die Leiste waagerecht ueber dem
     Inhalt und der Bereich behaelt seine volle Breite. */
  .view-inner.reiter-spalte {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    column-gap: var(--s7);
    align-items: start;
  }
  /* Kopf und Einleitung laufen ueber beide Spalten; alles Weitere steht
     rechts neben der Leiste. Ohne die ausdrueckliche Zuweisung landet ein
     Absatz im Gitter automatisch in Spalte 1 - also unter der Leiste. */
  .view-inner.reiter-spalte > .view-head,
  .view-inner.reiter-spalte > .hint,
  .view-inner.reiter-spalte > .hinweisband { grid-column: 1 / -1; }
  /* KEIN festes grid-row: es ist genau ein Bereich offen, also liegen Leiste
     und Bereich ohnehin in derselben Zeile - und nur dann reicht die Zeile
     hoch genug, dass `sticky` ueberhaupt etwas zu kleben hat. Eine feste
     Zeilennummer kollidierte mit der Einleitung, die ueber beide Spalten
     laeuft und je nach Ansicht da ist oder nicht. */
  .view-inner.reiter-spalte > .abschnitt-nav {
    grid-column: 1;
    position: sticky; top: 0; align-self: start;
    flex-direction: column; align-items: stretch;
    margin-bottom: 0; padding-bottom: 0; border-bottom: none;
  }
  .view-inner.reiter-spalte .abschnitt-nav a,
  .ps-leiste > .abschnitt-nav a {
    min-height: var(--h-ziel-klein); padding-left: var(--s4); border-radius: var(--r-sm);
  }
  .view-inner.reiter-spalte .abschnitt-nav a.aktiv,
  .ps-leiste > .abschnitt-nav a.aktiv { background: var(--flaeche-abschnitt); }
  .view-inner.reiter-spalte .abschnitt-nav a.aktiv::after,
  .ps-leiste > .abschnitt-nav a.aktiv::after {
    left: 0; right: auto; top: var(--s2); bottom: var(--s2); width: 3px; height: auto;
  }
  .view-inner.reiter-spalte .nav-rubrik {
    display: block; margin: var(--s4) 0 var(--s1); padding: 0 var(--s4);
    color: var(--text-dim); font-size: var(--fs-xs); font-weight: 650;
    letter-spacing: 0.06em; text-transform: uppercase;
  }
  .view-inner.reiter-spalte .nav-rubrik:first-child { margin-top: 0; }
  .view-inner.reiter-spalte > .panel,
  .view-inner.reiter-spalte > .reiterfeld { grid-column: 2; }
  /* Die Einstellungen bleiben eine Lesespalte - dort stehen Formulare, keine
     Tabellen, und die laufen ueber die volle Breite schlecht. */
  #view-settings .view-inner { max-width: 1120px; }
}

/* .admin-only trägt keine Gestaltung - es wird per hidden-Attribut geschaltet
   (settings.js, setzeAdminRechte). Die Klasse ist reiner Selektor. */

/* ============================================================
   8. Anmeldeseite
   ============================================================ */
.login-wrap {
  display: flex; align-items: center; justify-content: center;
  flex: 1 1 auto; min-height: 100dvh; padding: var(--s6);
  padding-bottom: max(var(--s6), env(safe-area-inset-bottom));
  background: radial-gradient(1100px 520px at 50% -8%, var(--accent-soft), transparent 70%), var(--bg);
}
.login-card {
  width: 100%; max-width: 400px; padding: var(--s7) var(--s6) var(--s6);
  background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-stark);
}
.login-card .brand { justify-content: center; padding-bottom: var(--s2); }
.login-titel { margin: var(--s4) 0 var(--s1); text-align: center; font-size: var(--fs-2xl); }
.login-seite .form-error { margin: 0 0 var(--s4); }
.passwort-feld { position: relative; }
.passwort-feld input { padding-right: calc(var(--h-ziel) + var(--s2)); }
.passwort-zeigen {
  position: absolute; right: var(--s1); top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--h-ziel); height: var(--h-ziel); padding: 0;
  border: none; border-radius: var(--r-sm); background: none; color: var(--text-dim); cursor: pointer;
}
.passwort-zeigen:hover { background: var(--bg-hover); color: var(--text); }
.passwort-zeigen .durchgestrichen { stroke-width: 2.2; }
.login-card .subtitle { margin: 0 0 var(--s6); text-align: center; font-size: var(--fs-bd);
                        color: var(--text-dim); }
.login-card .btn-primary { width: 100%; margin-top: var(--s2); min-height: var(--h-feld); }
.field { margin-bottom: var(--s4); }
.field label { display: block; margin-bottom: var(--s1); font-size: var(--fs-md);
               font-weight: 600; color: var(--text-dim); }
.form-error {
  margin: var(--s4) 0 0; padding: var(--s3); border-radius: var(--r-sm);
  background: var(--danger-soft); color: var(--danger); font-size: var(--fs-bd);
}

/* ============================================================
   9. Dialoge und Toast
   ============================================================ */
.dialog-backdrop {
  position: fixed; inset: 0; z-index: var(--z-dialog);
  display: flex; align-items: center; justify-content: center; padding: var(--s5);
  background: var(--schleier);
}
.dialog {
  width: min(460px, 100%); max-height: calc(100dvh - var(--s8)); overflow-y: auto;
  padding: var(--s6);
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background: var(--bg-panel); box-shadow: var(--shadow-stark);
}
.dialog h2 { margin: 0 0 var(--s2); font-size: var(--fs-xl); }
/* `.dialog > p` statt `.dialog p`: sonst färbte die Regel auch die Fehlerzeile
   am Feld grau ein. Zeilenumbrüche im Text bleiben stehen. */
.dialog > p, .dialog-text { margin: 0; color: var(--text-dim); font-size: var(--fs-bd);
                             line-height: var(--lh); white-space: pre-line; }
.dialog-beschaeftigt { cursor: progress; }
.dialog .feld-form { margin-top: var(--s4); }
.dialog-actions { display: flex; justify-content: flex-end; gap: var(--s2); margin-top: var(--s6); }

/* Vorschlagsknöpfe im Eingabedialog (Dateiname umbenennen). Sie stehen unter
   dem Feld, nicht darüber: das Feld ist die Entscheidung, die Vorschläge sind
   das Angebot. */
/* Solange die Vorschläge unterwegs sind, steht hier ein Satz statt nichts. */
.dialog-warte { color: var(--text-dim); font-size: var(--fs-md); }
.dialog-vorschlaege { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s2); }
.dialog-vorschlaege .btn { font-size: var(--fs-sm); }

/* Auswahldialog (Namensstil). Die Erklärung steht AN der Möglichkeit, nicht
   darüber - sonst müsste man beim Lesen zwischen Text und Optionen springen. */
.wahl-liste { display: flex; flex-direction: column; gap: var(--s2); margin: var(--s4) 0 0; }
.wahl {
  display: flex; gap: var(--s3); align-items: flex-start;
  padding: var(--s3); border: 1px solid var(--border); border-radius: var(--r-sm);
  cursor: pointer;
}
.wahl:hover { border-color: var(--accent); }
.wahl.aktiv { border-color: var(--accent); background: var(--accent-soft); }
.wahl input { margin-top: var(--s0); width: 18px; height: 18px; accent-color: var(--accent); }
.wahl strong { display: block; font-size: var(--fs-bd); }
.wahl code {
  display: block; margin-top: var(--s0); font-size: var(--fs-sm); color: var(--text-dim);
  word-break: break-all;
}

/* Ein Dokument, das ich geteilt habe - Symbol plus Zahl, anklickbar. Es steht
   NEBEN dem Namen und nicht in einer eigenen Spalte: eine Spalte, die in den
   meisten Zeilen leer bleibt, kostet Breite in jeder. */
.geteilt-marke {
  display: inline-flex; align-items: center; gap: calc(var(--s0) + 1px); flex: 0 0 auto;
  padding: var(--s0) var(--s1); border: 1px solid var(--border);
  border-radius: var(--r-pill); background: none;
  color: var(--text-dim); font-size: var(--fs-xs); font-weight: 600;
  cursor: pointer; line-height: 1;
}
.geteilt-marke:hover { color: var(--accent); border-color: var(--accent); }
.geteilt-marke:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Noch nicht übernommen: der einzige Zustand, der eine Erwartung offenlässt. */
.geteilt-marke.geteilt-offen { color: var(--accent); border-color: var(--accent); }
/* Am Finger wächst sie auf dasselbe Maß wie jedes andere dichte Bedienteil.
   Der Wert kommt aus `--h-ziel-klein`, das unter `pointer: coarse` ohnehin auf
   40 px springt - so steht die Regel an EINER Stelle und nicht zweimal. */
.geteilt-marke { min-height: var(--h-ziel-klein); }
@media (pointer: fine) {
  /* Mit der Maus darf sie klein bleiben: sie steht neben einem Dateinamen und
     würde die Zeile sonst um ein Drittel höher machen. */
  .geteilt-marke { min-height: 0; }
}

/* ---------- Freigabe-Dialog: eine Zeile je Person ----------
   Kein Formular, sondern eine Uebersicht mit Schaltern: wer hat Zugriff,
   worueber, und hat er geantwortet. Jede Handlung wirkt sofort - deshalb gibt
   es unten nur „Fertig" und kein „Speichern". */
/* Offene Angebote an der zugeklappten Ueberschrift - sonst sieht sie niemand. */
.fg-offen-zahl {
  margin-left: var(--s2); padding: 1px var(--s2); border-radius: var(--r-pill);
  background: var(--accent); color: var(--auf-akzent);
  font-size: var(--fs-sm); font-weight: 700;
}
/* Dieselbe Form fuer den Papierkorb, aber ruhig: was darin liegt, verlangt
   keine Handlung - anders als ein offenes Angebot. */
.pk-zahl {
  margin-left: var(--s2); padding: 1px var(--s2); border-radius: var(--r-pill);
  background: var(--bg-hover); color: var(--text-dim);
  font-size: var(--fs-sm); font-weight: 700;
}
.pk-leiste { display: flex; justify-content: flex-end; }

.fg-ziel {
  margin: 0 0 var(--s3); padding: var(--s2) var(--s3);
  border-radius: var(--r-sm); background: var(--bg-hover);
  font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fg-personen { display: flex; flex-direction: column; gap: var(--s2); }
.fg-person {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--border); border-radius: var(--r-sm);
}
.fg-person-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.fg-person strong { font-size: var(--fs-bd); }
.fg-stand { font-size: var(--fs-sm); color: var(--text-dim); }
/* Ein offenes Angebot ist der einzige Zustand, der noch etwas erwartet. */
.fg-person.fg-offen { border-color: var(--accent); }
/* Wer noch keinen Zugriff hat, tritt zurueck - so sieht man auf einen Blick,
   wer ihn hat, statt jede Zeile lesen zu muessen. Nur ueber das Schriftgewicht:
   eine zweite Rahmenfarbe waere neben „offenes Angebot" und „ausgenommen" die
   dritte, und drei Randzustaende unterscheidet niemand mehr. */
.fg-person.fg-ohne strong { font-weight: 500; color: var(--text-dim); }
.fg-person.fg-ausgenommen { border-style: dashed; }
.fg-person .btn { flex: 0 0 auto; }

/* Meldungen stapeln sich unten mittig. Im Chat stehen sie ÜBER der Eingabe -
   vorher lagen sie auf dem Senden-Knopf. */
.toast-stapel {
  position: fixed; left: 50%; z-index: var(--z-toast);
  bottom: calc(var(--s6) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: var(--s2);
  width: max-content; max-width: calc(100vw - var(--s6));
  pointer-events: none;
}
body:has(#view-chat:not([hidden])) .toast-stapel {
  bottom: calc(var(--eingabe-hoehe, 120px) + var(--s3));
}
.toast-meldung {
  display: flex; align-items: center; gap: var(--s1);
  max-width: min(560px, calc(100vw - var(--s6)));
  padding: var(--s1) var(--s1) var(--s1) var(--s4); border-radius: var(--r-lg);
  background: var(--toast-grund); color: var(--toast-text);
  font-size: var(--fs-bd); line-height: var(--lh-eng); box-shadow: var(--shadow-stark);
  opacity: 0; transform: translateY(var(--s2));
  transition: opacity var(--tempo-lang) var(--ease), transform var(--tempo-lang) var(--ease);
  pointer-events: auto;
}
.toast-meldung.show { opacity: 1; transform: none; }
.toast-meldung.geht { opacity: 0; transform: translateY(var(--s1)); pointer-events: none;
                      transition-timing-function: var(--ease-raus); }
.toast-fehler { box-shadow: inset 3px 0 0 var(--toast-fehler), var(--shadow-stark); }
.toast-text { flex: 1 1 auto; min-width: 0; padding: var(--s2) var(--s2) var(--s2) 0; }
/* „Rückgängig" - der Weg zurück steht NEBEN der Meldung, nicht in einem
   Dialog davor. Deshalb braucht das Verschieben keine Rückfrage. */
.toast-tat {
  flex: 0 0 auto; min-height: var(--h-ziel-klein); padding: 0 var(--s3);
  border: none; border-radius: var(--r-md); background: none; cursor: pointer;
  color: var(--toast-akzent); font: inherit; font-weight: 600;
}
.toast-tat:hover { background: var(--toast-hover); }
.toast-tat:focus-visible, .toast-zu:focus-visible { outline: 2px solid var(--toast-akzent); outline-offset: 1px; }
.toast-zu {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: var(--h-ziel-klein); height: var(--h-ziel-klein); padding: 0;
  border: none; border-radius: var(--r-md); background: none; cursor: pointer;
  color: var(--toast-text); opacity: 0.7;
}
.toast-zu:hover { opacity: 1; background: var(--toast-hover); }

/* ============================================================
   10. Barrierefreiheit
   ============================================================ */

/* Überschriften bekommen den Fokus nur, damit die Sprachausgabe dort weiterliest
   (tabindex="-1", Laufdetail, Abschnittssprung) - bedienbar sind sie nicht. Ein
   Fokusrahmen darum sah aus wie ein Eingabefeld (Runde 64, im Bild gesehen). */
h1[tabindex="-1"]:focus, h2[tabindex="-1"]:focus, h3[tabindex="-1"]:focus { outline: none; }

/* Sichtbarer Tastatur-Fokus - nur bei Tastaturbedienung, nicht bei Mausklick. */
a:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, select:focus-visible, [tabindex]:focus-visible,
summary:focus-visible, label:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  /* Keine eigene Rundung: der Umriss folgt der des Elements. Vorher wurden
     Pillen und Knöpfe beim Tastaturfokus eckig. */
}

/* Eingabefelder markieren ihren Fokus SELBST - über den Rahmen und einen weichen
   Ring am Feld. Der allgemeine Umriss käme dort als zweiter, enger sitzender
   Ring obendrauf: zwei Rahmen um dasselbe Feld, einer davon eckig im runden. */
.inputbox textarea:focus-visible,
.ws-box textarea:focus-visible,
.field input:focus-visible,
.feld-form input:focus-visible,
.prompt-text:focus-visible,
.edit-box textarea:focus-visible,
.filterleiste input:focus-visible,
.filterleiste select:focus-visible,
.filterzeile input:focus-visible,
.filterzeile select:focus-visible,
.freigabe-form select:focus-visible,
.freigabe-form input:focus-visible {
  outline: none;
}

/* Wer Bewegung reduziert haben will, bekommt keine Dauer-Animationen. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   11. Größenstufen
   ============================================================ */

/* ---------- Ab 900 px: Seitenleiste steht fest ----------
   Darunter ist sie eine Schublade. Vorher lag sie als Block ÜBER dem Inhalt und
   nahm bis zu 45 % der Höhe - auf einem Telefon blieb für den Chat kaum etwas
   übrig. */
@media (max-width: 899px) {
  .topbar { display: flex; }

  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: var(--z-schublade);
    width: min(304px, 86vw); height: 100%;
    padding-top: max(var(--s4), env(safe-area-inset-top));
    transform: translateX(-100%);
    transition: transform var(--tempo-lang) ease;
    box-shadow: var(--shadow-stark);
  }
  body.menu-offen .sidebar { transform: translateX(0); }
  body.menu-offen .sidebar-backdrop {
    display: block; position: fixed; inset: 0; z-index: var(--z-schleier);
    background: var(--schleier);
  }
  /* In der Schublade ist die Marke doppelt - oben steht sie schon. */
  .sidebar .brand { display: none; }
  /* Eingeklappt gibt es die schmale Schiene nicht: die Schublade ist bereits
     die platzsparende Fassung. */
  body.leiste-schmal .sidebar { width: min(304px, 86vw); padding: var(--s4) var(--s3) 0; }
  body.leiste-schmal .sidebar .brand-text,
  body.leiste-schmal .sidebar .sidebar-section,
  body.leiste-schmal .sidebar .chat-list,
  body.leiste-schmal .sidebar .shutdown-text,
  body.leiste-schmal .sidebar .user,
  body.leiste-schmal .sidebar #new-chat span,
  body.leiste-schmal .sidebar .nav-item span { display: revert; }
  body.leiste-schmal .sidebar .shutdown-uhr { display: none; }
  body.leiste-schmal .sidebar .shutdown-melder {
    flex-direction: row; align-items: center; gap: var(--s2); flex: 1 1 auto;
  }
  body.leiste-schmal .sidebar .nav-item,
  body.leiste-schmal .sidebar #new-chat { justify-content: flex-start;
    padding-left: var(--s3); padding-right: var(--s3); }
  body.leiste-schmal .sidebar-footer { flex-direction: row; }
  body.leiste-schmal .sidebar .konto-text { display: flex; }
  body.leiste-schmal .sidebar .konto-winkel { display: block; }
  body.leiste-schmal .sidebar .konto-knopf { justify-content: flex-start; padding: var(--s2); }
  body.leiste-schmal .chatliste-knopf,
  body.leiste-schmal .sidebar-toggle { display: none; }

  .view-inner { padding: var(--s4) var(--s4) var(--s8); }
  #view-documents .view-inner { padding-left: var(--s3); padding-right: var(--s3); }
  .chat-messages { padding: var(--s4) var(--s4) var(--s2); gap: var(--s5); }
  .chat-inputbar { padding: var(--s2) var(--s3) var(--s3);
                   padding-bottom: max(var(--s3), env(safe-area-inset-bottom)); }
  .msg-user .bubble { max-width: 90%; }
  .scroll-down { right: var(--s4); }
  h1 { font-size: var(--fs-2xl); }
}

/* Ab 900 px steht der Umschalter für die schmale Schiene bereit. */
@media (min-width: 900px) {
  .sidebar-toggle { display: inline-flex; }
}

/* ---------- Unter 760 px: Tabellen werden zu Karten ----------
   Eine sechsspaltige Tabelle ist bei 375 px nicht lesbar. Jede Zeile wird
   deshalb zu einer Karte, in der die Spaltenüberschrift als Label vor dem Wert
   steht (data-label). Sortierung und Mehrfachauswahl gehen dabei NICHT
   verloren - sie stehen in der Listenleiste, die auf jeder Größe da ist. */
@media (max-width: 759px) {
  /* Gestapelt in der natürlichen Reihenfolge: Titel, dann die Zahlen, die ihn
     erläutern, dann die Handlungen. Der Platzhalter, der auf breiten Schirmen
     die Knöpfe nach rechts schiebt, hat in einer Spalte nichts zu suchen. */
  .view-head { align-items: stretch; flex-direction: column; gap: var(--s3); }
  .view-head .spacer { display: none; }
  .view-head .kopf-aktionen { display: flex; gap: var(--s2); }
  .view-head .kopf-aktionen .btn { flex: 1; }

  /* Auf dem Telefon ist der Ordnerbaum eine NAVIGATION, kein Dauerbegleiter. */
  .ordnerbaum { max-height: 34vh; }

  /* Auf der Karte ist eine Zeile mehr als doppelt so hoch - in Zeilen
     gerechnet waere der Kasten weit hoeher als der Schirm, und er haette
     wieder keinen Rand, den man sieht. Hier begrenzt deshalb die
     Bildschirmhoehe. */
  .doc-scroll { overflow-x: hidden; max-height: 66vh; }
  .doc-table-haupt thead { display: none; }
  .doc-table-haupt, .doc-table-haupt tbody, .doc-table-haupt tr, .doc-table-haupt td {
    display: block; width: 100%;
  }
  .doc-table-haupt tr {
    position: relative;
    /* Rechts bleibt Platz für den Aktionsknopf, der dort schwebt - ohne diese
       Reserve schoben sich die Etiketten des Dateinamens darunter. */
    padding: var(--s3) var(--s8) var(--s3) var(--s9);
    border-bottom: 1px solid var(--border);
  }
  .doc-table-haupt tr:last-child { border-bottom: none; }
  .doc-table-haupt td { padding: var(--s0) 0; border: none; width: auto !important; }
  .doc-table-haupt td.zelle-name { font-size: var(--fs-lg); }
  /* Auf der Karte bekommt der DATEINAME eine eigene Zeile; Eigentümer, Ordner
     und die Freigabe-Marke rutschen darunter.
     Vorher standen alle nebeneinander in EINER Flex-Zeile: der Name schrumpfte
     als einziges schrumpfbares Element zuerst und war bei 390 px auf „gew…"
     zusammengefallen, während drei Etiketten daneben in voller Breite standen.
     Das Wichtigste verlor gegen das Beiwerk. */
  .doc-name { flex-wrap: wrap; row-gap: var(--s1); }
  .doc-name > a { flex: 1 0 100%; }
  .doc-table-haupt td.col-check {
    position: absolute; left: var(--s3); top: var(--s3); width: auto !important; padding: 0;
  }
  .doc-table-haupt td[data-label]::before {
    content: attr(data-label) " ";
    color: var(--text-dim); font-size: var(--fs-sm);
  }
  /* Die Zeilen-Handlungen liegen in der Karte rechts oben, nicht unter dem
     Inhalt: dort sucht sie niemand, und vier Symbole in einer Reihe unter
     jeder Karte machten die Liste doppelt so lang. */
  .doc-table-haupt .doc-action { position: absolute; right: var(--s2); top: var(--s2);
                                 justify-content: flex-end; }
  .doc-table-haupt .register-row { padding-left: var(--s3); }
  .register-row > td { padding: var(--s2) 0 0; }

  /* Auch die Zugriffs- und Freigabetabellen: ohne die Etiketten stünden dort
     drei Namen nebeneinander, ohne dass erkennbar wäre, wer wessen Bestand
     liest. */
  /* Für JEDE Karten-Tabelle, nicht für eine Liste von IDs: der Bestand aller
     Konten stand darunter mit fünf Werten ohne ein einziges Etikett. */
  .fg-block .doc-table td, .karten-tabelle:not(.betrieb-tabelle) td {
    display: block; padding: var(--s0) 0; border: none;
  }
  .fg-block .doc-table thead, .karten-tabelle thead { display: none; }
  .fg-block .doc-table tr, .karten-tabelle:not(.betrieb-tabelle) tr {
    display: block; padding: var(--s3) 0; border-bottom: 1px solid var(--border);
  }
  .fg-block .doc-table td[data-label]::before,
  .karten-tabelle:not(.betrieb-tabelle) td[data-label]::before {
    content: attr(data-label) " "; color: var(--text-dim); font-size: var(--fs-sm);
  }

  .panel { margin-bottom: var(--s7); }
  /* Auf der Karte ist jede Zeile ihr eigener Block - ein Rahmen darum wäre ein
     Kasten um Kästen, und waagerecht rollen muss dort nichts mehr. */
  .tabellen-rahmen { overflow-x: visible; border: 0; border-radius: 0; background: none; }
  .tabellen-rahmen > .doc-table th:first-child,
  .tabellen-rahmen > .doc-table td:first-child { padding-left: 0; }
  .job-status:not(:empty) { padding: var(--s3) var(--s4); }
  .leer-zustand { padding: var(--s6) var(--s4); }
  .listenleiste, .filterleiste, .bulk-bar { padding-left: var(--s3); padding-right: var(--s3); }

  .freigabe-form .btn { width: 100%; }
  .panel-fuss .btn { flex: 1 1 auto; }

  /* Dialog als Blattschublade am unteren Rand - dort ist der Daumen. */
  .dialog-backdrop { align-items: flex-end; padding: 0; }
  .dialog {
    width: 100%; max-height: 88dvh; padding: var(--s5);
    border-radius: var(--r-xl) var(--r-xl) 0 0; border-bottom: none;
    padding-bottom: max(var(--s5), env(safe-area-inset-bottom));
  }
  .dialog-actions .btn { flex: 1; }

  .toast-stapel { bottom: calc(var(--s4) + env(safe-area-inset-bottom)); }
}

/* ---------- Ab 760 px: die Spalte "Bereich" darf mit ---------- */
@media (min-width: 760px) and (max-width: 1299px) {
  /* Zwischen Karte und voller Tabelle: die Datumsspalte ist das erste, was
     entfallen darf - das Datum steht ohnehin im Titel der Zeile. Vorher blieben
     alle sechs Spalten stehen, die Tabelle wurde breiter als ihr Kasten (bei
     1194 px Fensterbreite gemessene 1618 px) und die Handlungsspalte lag
     vollständig außerhalb des Bildes. */
  .doc-table-haupt .col-datum, .doc-table-haupt th.col-datum { display: none; }
}

/* ---------- Ab 1100 px: Ordnerbaum neben die Liste ---------- */
/* Erst ab 1200 px: darunter nähme der Baum der Tabelle den Platz, den sie für
   Name UND Handlungsspalte braucht. */
@media (min-width: 1200px) {
  /* Die Breite steht in einer Variablen, damit der Ziehgriff sie setzen kann,
     ohne dass JavaScript die Rasterdefinition kennen muss. Der Vorgabewert
     bleibt 220 px - wer nie zieht, sieht dieselbe Ansicht wie vorher. */
  .doc-layout {
    display: grid;
    grid-template-columns: var(--baum-breite, 220px) auto minmax(0, 1fr);
  }
  .baum-griff {
    display: block; width: 5px; cursor: col-resize;
    background: none; border: none; padding: 0;
    /* Die Trennlinie zeichnet der Griff (box-shadow, unten beim Baum). Seine
       Markierung bleibt unsichtbar, bis man ihn braucht. */
    position: relative;
  }
  /* Die Greiffläche ist breiter als der sichtbare Strich: 5 px trifft niemand
     zuverlaessig, 15 px schon. Das Feld liegt ueber der Trennlinie, nicht
     daneben, damit es keine tote Zone zwischen Baum und Liste gibt. */
  .baum-griff::before {
    content: ""; position: absolute; inset: 0 -5px; cursor: col-resize;
  }
  .baum-griff::after {
    content: ""; position: absolute; top: 50%; left: 1px;
    width: 3px; height: 32px; margin-top: -16px; border-radius: var(--r-pill);
    background: var(--border); opacity: 0; transition: opacity var(--tempo);
  }
  .baum-griff:hover::after, .baum-griff:focus-visible::after,
  .doc-layout.zieht .baum-griff::after { opacity: 1; background: var(--accent); }
  .baum-griff:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
  /* Waehrend des Ziehens darf nichts markiert werden - sonst faerbt sich die
     halbe Liste blau, sobald der Zeiger sie streift. */
  .doc-layout.zieht { user-select: none; cursor: col-resize; }
  /* Der Baum rollt nicht mit der Liste weg, er bleibt oben stehen (siehe „Die
     Liste rollt mit der Seite“). Hoeher als das Fenster wird er nie; hat er
     mehr Ordner, rollt er in sich - und reicht das Rollen am Ende an die
     Seite weiter, damit auch sein unteres Ende ins Bild kommt, solange er
     noch nicht oben angekommen ist.
     `align-self: start`, weil ein gestreckter Baum keinen Platz haette, in
     dem er kleben kann. Deshalb zieht jetzt der Griff die Trennlinie ueber
     die volle Hoehe - der Baum ist oft kuerzer als die Liste. */
  .ordnerbaum {
    border-bottom: none;
    position: sticky; top: 0; align-self: start;
    max-height: var(--vvh, 100dvh); overscroll-behavior: auto;
  }
  .baum-griff { box-shadow: inset 1px 0 0 var(--border); }
  .doc-haupt { min-width: 0; }
}

/* ---------- Ab 1500 px: Chat und Ordnerbaum duerfen atmen ---------- */
@media (min-width: 1500px) {
  :root { --lesebreite: 820px; }
  /* Nur der VORGABEWERT waechst mit. Eine selbst gezogene Breite steht als
     --baum-breite auf dem Element und gewinnt gegen diese Regel. */
  .doc-layout { grid-template-columns: var(--baum-breite, 260px) auto minmax(0, 1fr); }
}

/* ---------- Ab 760 px: die Liste rollt mit der Seite ----------
   Nutzermeldung 28.09.2026: unten abgeschnitten, man soll weiter nach unten
   rollen koennen. Die Liste stand in einem eigenen Kasten (15 Zeilen,
   hoechstens 74vh), und die Seite rollte zusaetzlich - zwei Rollbereiche
   ineinander, und auf einem kleinen Fenster blieben im Kasten drei Zeilen.
   Der Kasten war fuer den Weg an der Liste VORBEI gebaut: darunter standen die
   Freigaben. Die sind seit dem 22.09.2026 ein eigener Reiter; unter der Liste
   steht nichts mehr, an dem man vorbei muesste.
   Jetzt steht die ganze Liste untereinander, und es rollt nur die Seite. Was
   man beim Rollen braucht, bleibt stehen: der Spaltenkopf oben, ab 1200 px der
   Ordnerbaum links (Filter UND Ablageziel - er muss erreichbar bleiben, wenn
   man eine Zeile weit unten in einen Ordner zieht).
   Am Telefon bleibt der Kasten (Abschnitt „Unter 760 px“). */
@media (min-width: 760px) {
  /* `clip` statt `auto`: der Kasten schneidet an seiner runden Kante ab, ist
     aber kein Rollbereich mehr - sonst klebte der Spaltenkopf an IHM und nicht
     am oberen Rand der Ansicht. Die Schatten-Verlaeufe zeigen nur in einem
     rollenden Kasten etwas an. */
  .doc-scroll { overflow: clip; background: none; }
  /* Bis 1199 px klebt die Reiterleiste selbst oben (`.abschnitt-nav` in
     `max-width: 1199px`); der Spaltenkopf klebt darunter statt darueber. Ihre
     Hoehe: Innenabstand oben, ein Reiter, die Kante. */
  .doc-table-haupt thead th { top: calc(var(--s1) + var(--h-ziel) + 1px); }
}
@media (min-width: 1200px) {
  .doc-table-haupt thead th { top: 0; }
}

/* ============================================================
   11b. Betrieb (nur Administratoren)
   ------------------------------------------------------------
   Nutzung und GPU-Zustand auf einen Blick - nur Metadaten. EIN Zeitraum oben
   gilt fuer alles darunter, dann Kennzahlen, GPU, Nutzer, Aktivitaet. Ein
   Zustand traegt immer Punkt UND Text; "aus" und "inaktiv" sind zusaetzlich
   hohl gezeichnet, damit sie sich auch ohne Farbe unterscheiden.
   ============================================================ */
#view-betrieb .view-inner { max-width: min(1320px, 100%); }
.betrieb-kopf .hint { margin: 0; }
/* Der Datenschutzsatz ist eine Zusage, keine Nachricht: er steht als Fußzeile,
   nicht mehr über allem anderen (Runde 64). */
.betrieb-datenschutz {
  max-width: none; margin: var(--s7) 0 0; padding-top: var(--s3);
  border-top: 1px solid var(--kante-fein); font-size: var(--fs-sm);
}

/* ---------- Lagebild (Runde 64) ----------
   Über den Reitern, immer sichtbar: Zustand der GPU mit Symbol und Wort, wer
   gerade da ist, was läuft, was zu tun ist - und die passende Handlung. Ein
   eigener Kasten, weil es ein eigenes Ding ist: der Zustand der Anlage. */
.lagebild {
  margin: 0 0 var(--s5); padding: var(--s4) var(--s5);
  border: 1px solid var(--kante-fein); border-radius: var(--r-lg);
  background: var(--flaeche-abschnitt);
}
/* Die schwerste Meldung färbt die Kante: links breit, damit sie auch aus dem
   Augenwinkel auffällt - die Farbe ist dabei Zugabe, die Meldung selbst
   trägt Symbol und Wort. */
.lagebild.lage-warn { border-color: var(--warn); border-left-width: 4px; }
.lagebild.lage-fehler { border-color: var(--danger); border-left-width: 4px; }
.lage-kopf { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s5); }
.lage-kopf .gpu-zustand { flex: 1 1 28em; margin: 0; }
.gpu-zustand .lage-status { font-size: var(--fs-lg); font-weight: 650; }
.gpu-zustand .lage-status > svg { width: 1.15em; height: 1.15em; }
.lage-jetzt { flex-basis: 100%; color: var(--text-dim); font-size: var(--fs-md); }
.lage-aktionen { display: flex; flex-wrap: wrap; gap: var(--s2); }
.lage-aktionen:empty { display: none; }
.lage-meldungen {
  display: grid; gap: var(--s2); margin: var(--s3) 0 0; padding: var(--s3) 0 0;
  border-top: 1px solid var(--kante-fein); list-style: none;
}
.lage-meldung { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s3);
                font-size: var(--fs-bd); }
.lage-meldung > .status { font-weight: 600; }
.lage-ruhig > .status { font-weight: 500; color: var(--text-dim); }
.lage-text { color: var(--text-dim); }
.lage-bar { flex: 0 1 12em; }
.lage-hin { margin-left: auto; }

/* Reiter und Zeitraum in EINER Zeile: der Zeitraum gilt für die Reiter links
   von ihm, nicht für die Anlage (dort verschwindet er). */
.betrieb-leiste {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s2) var(--s4);
  margin-bottom: var(--s6); border-bottom: 1px solid var(--kante-fein);
}
.betrieb-leiste > .abschnitt-nav { flex: 1 1 auto; margin-bottom: 0; border-bottom: 0; }
.betrieb-zeitraum {
  display: flex; align-items: center; gap: var(--s2); padding-bottom: var(--s1);
  color: var(--text-dim); font-size: var(--fs-sm); font-weight: 600;
}
.betrieb-zeitraum select, .bm-filter select { width: auto; min-height: var(--h-ziel-klein); font-size: var(--fs-md); }
@media (max-width: 1199px) {
  .betrieb-leiste {
    position: sticky; top: 0; z-index: var(--z-haftend);
    margin: 0 calc(var(--s4) * -1) var(--s5); padding: 0 var(--s4); background: var(--bg);
  }
  .betrieb-leiste > .abschnitt-nav { position: static; margin: 0; padding: var(--s1) 0 0; background: none; }
}

@media (max-width: 759px) {
  /* Titel, Stand und EIN leiser Knopf passen am Telefon in eine Zeile - die
     allgemeine Regel stapelte sie in drei (gebaut für Köpfe mit mehreren
     Handlungen wie bei den Dokumenten). */
  .view-head.betrieb-kopf, #view-pruefstand .view-head {
    flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s3);
  }
  .view-head.betrieb-kopf .spacer, #view-pruefstand .view-head .spacer { display: block; }
}

.abschnitt-kopf {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--s2) var(--s4); margin: var(--s2) 0 var(--s2);
}
.abschnitt-kopf h3 { margin: 0; }
.zl-legende { display: flex; flex-wrap: wrap; gap: var(--s4); margin: 0; color: var(--text-dim); font-size: var(--fs-sm); }
.zl-legende-an::before, .zl-legende-fehl::before {
  content: ""; display: inline-block; width: var(--s3); height: var(--s2); margin-right: var(--s1);
  border-radius: var(--r-xs); background: var(--accent); vertical-align: middle;
}
.zl-legende-fehl::before { background: var(--warn); }
/* Beim Aktualisieren bleibt die Anzeige stehen, nur gedaempft - kein Leeren,
   kein Springen. */
#view-betrieb .kennzahlen, #view-betrieb .panel { transition: opacity var(--tempo); }
#view-betrieb.laedt .kennzahlen, #view-betrieb.laedt .panel { opacity: 0.65; }

.filterzeile {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--s3);
  margin-bottom: var(--s4);
}
.filterzeile label {
  display: flex; flex-direction: column; gap: var(--s1); min-width: 0;
  flex: 1 1 180px; max-width: 280px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim);
}

/* Runde 64: EINE Leiste statt vier bis sechs gleich großer Karten. Die Fugen
   zeichnet jede Zelle selbst (Schatten rechts und unten); der Rahmen der
   Leiste schneidet die äußeren ab. Mit einem grauen Gittergrund stünde in
   einer halb gefüllten letzten Reihe ein grauer Block. Die EINE Zahl, auf die
   es ankommt, trägt `.haupt` und steht größer als die übrigen. */
.kennzahlen {
  display: grid; gap: 0; margin-bottom: var(--s6);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  border: 1px solid var(--kante-fein); border-radius: var(--r-md); overflow: hidden;
}
.kennzahl {
  display: flex; flex-direction: column; gap: var(--s1); min-width: 0;
  padding: var(--s4) var(--s5); background: var(--bg);
  box-shadow: 1px 0 0 var(--kante-fein), 0 1px 0 var(--kante-fein);
}
.kennzahl-label { color: var(--text-dim); font-size: var(--fs-sm); font-weight: 600; }
.kennzahl-wert { color: var(--text); font-size: var(--fs-2xl); font-weight: 600; line-height: 1.2;
                 letter-spacing: -0.01em; }
.kennzahl.haupt .kennzahl-wert { font-size: var(--fs-4xl); letter-spacing: -0.02em; }
.kennzahl-zusatz { color: var(--text-dim); font-size: var(--fs-sm); }
/* Erstes Laden: Skelette statt leerer Tabellenköpfe und leerer Kacheln. Beim
   Nachladen bleibt dagegen die bisherige Anzeige stehen, nur gedämpft (.laedt). */
.betrieb-skelett { display: none; padding: var(--s2) 0; }
#view-betrieb.erst-laedt .betrieb-skelett { display: flex; }
#view-betrieb.erst-laedt .betrieb-tabelle,
#view-betrieb.erst-laedt .tabellen-rahmen,
#view-betrieb.erst-laedt .zeitleiste { display: none; }
#view-betrieb.erst-laedt .kennzahlen, #view-betrieb.erst-laedt .panel { opacity: 1; }
#view-betrieb.erst-laedt .lage-meldungen { display: none; }
.kennzahl-skelett {
  min-height: 5.5rem;
  background: linear-gradient(90deg, var(--bg-hover) 25%, var(--bg-active) 37%, var(--bg-hover) 63%);
  background-size: 400% 100%;
  animation: schimmer var(--tempo-puls) ease-in-out infinite;
}


.gpu-zustand {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s3);
  margin-bottom: var(--s4); font-size: var(--fs-bd);
}
.gpu-zustand-text { color: var(--text-dim); font-size: var(--fs-bd); font-weight: 400; }
.gpu-raster { display: grid; gap: var(--s5); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) {
  .gpu-raster { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
}

.messwert { display: flex; flex-direction: column; gap: var(--s2); }
.messwert + .messwert { margin-top: var(--s4); }
.messwert-kopf { font-size: var(--fs-bd); font-weight: 600; }
.messwert-rest { color: var(--text-dim); font-size: var(--fs-md); }
.meter-zeile {
  display: grid; align-items: center; gap: var(--s2) var(--s3);
  grid-template-columns: 6.5em minmax(0, 1fr) auto; font-size: var(--fs-md);
}
.meter-label { color: var(--text-dim); }
.meter-wert { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Erlaeuterung unter Balken und Zahl - nicht daneben, sonst nimmt sie dem
   Balken die Breite (siehe bausteine.meter). */
.meter-zusatz {
  grid-column: 2 / -1; margin-top: calc(var(--s1) * -1);
  color: var(--text-dim); font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
/* Die Spur ist ein hellerer Schritt derselben Farbe - die Lage liest sich so
   ueber den ganzen Balken, nicht nur an der Fuellung. */
.meter { position: relative; height: 8px; border-radius: var(--r-pill); background: var(--accent-soft-stark); }
/* Das Soll als senkrechter Strich, der über den Balken hinausragt - er muss
   auch dann zu sehen sein, wenn die Füllung darüber hinweggeht. */
.meter-soll {
  position: absolute; top: calc(var(--s1) * -1); bottom: calc(var(--s1) * -1);
  width: var(--s0); margin-left: -1px; border-radius: var(--r-pill); background: var(--text);
}
.soll-verfehlt .meter-fill { background: var(--warn); }
.soll-verfehlt .meter-wert { color: var(--warn); font-weight: 600; }
.meter-fill {
  width: 0; height: 100%; border-radius: var(--r-pill);
  background: var(--accent); transition: width var(--tempo);
}
.meter-fill.knapp { background: var(--warn); }
.meter-fill.kritisch { background: var(--danger); }

.unter-titel { margin-top: var(--s5); }
.zeitleiste { position: relative; margin: var(--s2) 0 var(--s4); }
.zl-spur { position: relative; height: 32px; border-radius: var(--r-sm); background: var(--bg-hover); }
.zl-segment {
  position: absolute; top: 4px; bottom: 4px; min-width: 3px; padding: 0;
  border: none; border-radius: var(--r-xs); background: var(--accent); cursor: pointer;
}
.zl-segment:hover { background: var(--accent-hover); }
.zl-segment:focus-visible { outline: none; box-shadow: var(--fokus); }
/* Ein fehlgeschlagener Start hat keine Dauer - er waere unsichtbar. Er bekommt
   eine Mindestbreite und die Warnfarbe; was passiert ist, sagt der Tooltip und
   die Tabelle darunter. */
.zl-segment.fehlstart { min-width: 6px; background: var(--warn); }
.zl-achse { position: relative; height: 1.7em; margin-top: var(--s1); border-top: 1px solid var(--border); }
.zl-marke {
  position: absolute; top: var(--s1); transform: translateX(-50%); white-space: nowrap;
  color: var(--text-dim); font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
}
.zl-tooltip {
  position: absolute; bottom: 100%; z-index: var(--z-schwebend); max-width: min(340px, 90vw);
  padding: var(--s2) var(--s3); border-radius: var(--r-sm);
  background: var(--text); color: var(--bg-panel); box-shadow: var(--shadow-stark);
  font-size: var(--fs-md); pointer-events: none;
}

.betrieb-tabelle .col-aktion { width: 1%; white-space: nowrap; text-align: right; }
.betrieb-tabelle tbody tr.zeile-markiert td { background: var(--accent-soft); }

@media (max-width: 759px) {
  .kennzahlen { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kennzahl { padding: var(--s3); }
  .kennzahl-wert { font-size: var(--fs-xl); }
  .kennzahl.haupt { grid-column: 1 / -1; }
  .kennzahl.haupt .kennzahl-wert { font-size: var(--fs-3xl); }
  /* Bliebe die letzte Kennzahl allein in ihrer Reihe, stünde daneben eine
     leere, umrandete Zelle. Sie nimmt dann die ganze Reihe - mit Hauptzahl
     vorn bei gerader, ohne sie bei ungerader Gesamtzahl. */
  .kennzahl.haupt:first-child ~ .kennzahl:last-child:nth-child(even),
  .kennzahlen:not(:has(> .haupt)) > .kennzahl:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .filterzeile label { flex-basis: 100%; max-width: none; }
  .zl-marke:nth-child(even) { display: none; }
  /* Zeilen werden zu Karten: Beschriftung links, Wert rechts. */
  .betrieb-tabelle tbody tr { display: block; padding: var(--s3) 0; border-bottom: 1px solid var(--border); }
  .betrieb-tabelle tbody td {
    display: flex; justify-content: space-between; align-items: center; gap: var(--s3);
    padding: var(--s1) 0; border: none; text-align: right;
  }
  .betrieb-tabelle tbody td[data-label]::before {
    content: attr(data-label); color: var(--text-dim); font-size: var(--fs-sm); text-align: left;
  }
  .betrieb-tabelle .col-aktion { width: auto; justify-content: flex-end; }
}
/* ---------- Plus-Menue an der Eingabe ----------
   Bild und Websuche hinter EINEM Knopf; Nachdenken und Praezisieren bleiben
   daneben. Die gewaehlte Websuche steht als Chip UEBER der Leiste, wie die
   Bilder: sie gehoert zur Nachricht, und in der Leiste selbst schob sie auf
   360 px Praezisieren und Senden aus dem Bild. */
.inputbox > .modus-chip { margin: var(--s2) 0 0 var(--s3); }
/* Schon ohne Chip brauchte die Leiste auf 360 px 356 px bei 334 px Platz -
   Senden ragte hinaus. Unter 380 px ruecken die Knoepfe enger zusammen;
   Beschriftung, Reihenfolge und Funktion bleiben. */
@media (max-width: 379px) {
  .input-tools { gap: var(--s1); padding-left: var(--s1); padding-right: var(--s1); }
  .input-tools .tool-btn:not(.plus-btn) { padding-left: var(--s2); padding-right: var(--s2); }
}
.plus-btn { justify-content: center; min-width: var(--h-ziel-klein); padding: var(--s1); }
.plus-btn[aria-expanded="true"] { background: var(--accent-soft); color: var(--accent); }
.modus-chip {
  display: inline-flex; align-items: center; gap: var(--s1);
  min-height: var(--h-ziel-klein); padding: 0 var(--s1) 0 var(--s2);
  border: 1px solid var(--accent); border-radius: var(--r-pill);
  background: var(--accent-soft); color: var(--accent);
  font-size: var(--fs-md); font-weight: 500; white-space: nowrap;
}
.modus-weg {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: none; border-radius: var(--r-pill);
  background: none; color: inherit; cursor: pointer;
}
.modus-weg:hover { background: var(--accent-soft-stark); }
@media (pointer: coarse) {
  .modus-weg { width: var(--h-ziel-klein); height: var(--h-ziel-klein); }
}

/* ============================================================
   11c. Runde 56 - neue Bausteine und Feinschliff
   ------------------------------------------------------------
   Alles hier nutzt nur Tokens. Es steht VOR dem Aufnehmer, damit die
   statischen Prüfungen (keine Rohwerte) auch hier greifen.
   ============================================================ */

::placeholder { color: var(--text-dim); opacity: 1; }
.zaehler, .col-datum, .kennzahl-wert, .meter-wert, .zl-marke { font-variant-numeric: tabular-nums; }

/* Eingabewerte erbten das Schriftgewicht ihrer Beschriftung und standen fett
   im Feld - Beschriftung und Inhalt sahen gleich laut aus. */
.feld-form label input, .feld-form label select,
.freigabe-form label input, .freigabe-form label select,
.filterzeile label input, .filterzeile label select, .field input {
  font-weight: 400; color: var(--text); font-size: var(--fs-feld);
}
.feld-hinweis { margin: 0; color: var(--text-dim); font-size: var(--fs-sm); line-height: var(--lh-eng); }
.feld-fehler { margin: 0; color: var(--danger); font-size: var(--fs-sm); font-weight: 550; line-height: var(--lh-eng); }
[aria-invalid="true"] { border-color: var(--danger) !important; }

/* Die neue Seitenleiste: „Neuer Chat" ist dort nicht mehr der zweite
   Primärknopf neben dem der Ansicht - er bleibt prominent, trägt aber die
   Bedienfarbe nur im Symbol. */
.sidebar #new-chat { background: var(--bg-panel); color: var(--text);
                     border-color: var(--border); box-shadow: var(--shadow); font-weight: 600; }
.sidebar #new-chat svg { color: var(--accent); }
.sidebar #new-chat:hover { background: var(--bg-hover); border-color: var(--border-stark); }
.topbar { background: var(--bg-panel); }
.topbar-titel { font-weight: 600; letter-spacing: -0.01em; }

/* Wo bin ich? Der Titel des offenen Chats. Auf dem Telefon trägt ihn die
   Kopfzeile oben - dort bleibt er nur für Sprachausgaben. */
.chat-kopf {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  min-height: var(--h-ziel); padding: var(--s2) var(--s6);
}
.chat-titel {
  margin: 0; max-width: var(--lesebreite); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: var(--fs-bd); font-weight: 600; letter-spacing: -0.005em;
  color: var(--text-dim);
}
@media (max-width: 899px) {
  .chat-kopf { position: absolute; width: 1px; height: 1px; min-height: 0; padding: 0;
               overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
}
.msg-fehler .md { padding: var(--s3) var(--s4); border-radius: var(--r-md);
                  background: var(--danger-soft); color: var(--text); }
.edit-hinweis { margin: var(--s2) 0 0; color: var(--text-dim); font-size: var(--fs-sm); }
.chat-messages.laedt { opacity: 0.55; transition: opacity var(--tempo) var(--ease); }
.anhang-chip.laedt { background: linear-gradient(90deg, var(--bg-hover) 25%, var(--bg-active) 37%, var(--bg-hover) 63%);
                     background-size: 400% 100%; animation: schimmer var(--tempo-puls) ease-in-out infinite; opacity: 1; }
.msg-anhaenge a { display: block; border-radius: var(--r-sm); }

/* Dokumente */
.treffer-inhalt {
  flex: 0 0 auto; padding: 0 var(--s2); border-radius: var(--r-pill);
  background: var(--info-soft); color: var(--info);
  font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; line-height: 1.6;
}
@media (pointer: coarse) {
  /* Die Auswahl-Häkchen waren am Finger 18 px gross. */
  .col-check input, .listenleiste .wahl-alle input { width: var(--s6); height: var(--s6); }
}
.wahl-liste { max-height: min(52dvh, 440px); overflow-y: auto; padding: var(--s0); }
.wahl small { display: block; margin-top: var(--s0); color: var(--text-dim); font-size: var(--fs-sm); }

/* Freigaben */
.beschaeftigt { opacity: 0.7; pointer-events: none; }
.fg-person.fg-hervor { border-color: var(--accent); box-shadow: inset 3px 0 0 var(--accent); }
.fg-person-knoepfe { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s2); flex: 0 0 auto; }

/* Einstellungen */
.konto-loeschen { max-width: none; margin: var(--s2) 0 0; padding-top: var(--s4); border-top: 1px solid var(--kante-fein); }
.prompt-item.ungesichert .prompt-text { border-color: var(--warn); }
@media (max-width: 1199px) {
  /* Die Abschnitte als waagerecht rollende Leiste, die oben stehen bleibt.
     Vorher brach sie auf dem Telefon in zwei Zeilen um und rollte mit weg. */
  .abschnitt-nav {
    position: sticky; top: 0; z-index: var(--z-haftend);
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    margin: 0 calc(var(--s4) * -1) var(--s5); padding: var(--s1) var(--s4) 0;
    background: var(--bg);
  }
  .abschnitt-nav::-webkit-scrollbar { display: none; }
  .abschnitt-nav a { flex: 0 0 auto; white-space: nowrap; }
}

/* Ein Rahmen, dessen Tabelle leer ist, verschwindet mit ihr: die Skripte
   blenden bei leerer Liste die TABELLE aus (settings.leerZustand,
   betrieb.leerOderTabelle) - ein leerer Kasten mit Rand bliebe sonst stehen. */
.tabellen-rahmen:has(> table[hidden]) { display: none; }

/* ---------- Dokumente am Telefon ----------
   Suche und EIN Filterknopf in einer Zeile, der Ordnerbaum hinter einem
   Umschalter, der den gewählten Ordner nennt. Vorher standen Suche, drei
   Auswahlfelder und der ganze Baum über der Liste - das erste Dokument lag
   unter der ersten Bildschirmhöhe. */
.filter-umschalter, .ordner-umschalter { display: none; }
.filter-mehr { display: contents; }
.filter-zahl {
  min-width: var(--s5); padding: 0 var(--s1); border-radius: var(--r-pill);
  background: var(--accent); color: var(--auf-akzent);
  font-size: var(--fs-xs); font-weight: 700; line-height: var(--s5); text-align: center;
}
@media (max-width: 759px) {
  .filterleiste { flex-wrap: wrap; }
  .filterleiste input[type="search"] { flex: 1 1 0; min-width: 0; }
  .filter-umschalter { display: inline-flex; flex: 0 0 auto; min-height: var(--h-feld); }
  .filterleiste:not(.filter-offen) .filter-mehr { display: none; }
  .filterleiste.filter-offen .filter-mehr { display: flex; flex-direction: column; gap: var(--s2); flex: 1 1 100%; }
  .filter-umschalter[aria-expanded="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

  .ordner-umschalter {
    display: flex; align-items: center; gap: var(--s2); width: 100%;
    min-height: var(--h-ziel); padding: var(--s2) var(--s4);
    border: none; border-bottom: 1px solid var(--border); background: none;
    color: var(--text-dim); font: inherit; font-size: var(--fs-bd); text-align: left; cursor: pointer;
  }
  .ordner-umschalter svg { color: var(--accent); flex: 0 0 auto; }
  .ordner-umschalter-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ordner-umschalter strong { color: var(--text); font-weight: 600; }
  .ordner-umschalter .winkel { transform: rotate(45deg); margin-top: calc(var(--s1) * -1); }
  .ordner-umschalter[aria-expanded="true"] .winkel { transform: rotate(-135deg); margin-top: var(--s1); }
  .doc-layout:not(.ordner-offen) .ordnerbaum { display: none; }

  /* Kompakte Karte: Name, darunter EINE Zeile Bereich · Datum · Zustand.
     Vorher trug jede Angabe eine eigene Zeile samt Etikett - vier Dokumente
     passten auf den Schirm. */
  .doc-table-haupt tr { padding-top: var(--s3); padding-bottom: var(--s3); }
  .doc-table-haupt td.col-bereich, .doc-table-haupt td.col-datum, .doc-table-haupt td.col-status {
    display: inline-flex !important; align-items: center; width: auto !important;
    margin-right: var(--s2); vertical-align: middle; font-size: var(--fs-sm);
  }
  .doc-table-haupt td.col-bereich[data-label]::before { content: none; }
  /* Kein Trennpunkt: bricht die Zeile um, bliebe er am Ende hängen. Der
     Abstand trennt genauso. */
  .doc-table-haupt td.col-bereich, .doc-table-haupt td.col-datum { margin-right: var(--s3); }
  .doc-table-haupt td.zelle-name { font-size: var(--fs-lg); margin-bottom: var(--s1); }
  .doc-table-haupt .doc-name > a { white-space: normal; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
}

/* Kontrastmodus (Windows): Flächen aus reiner Hintergrundfarbe verschwinden
   dort - Balken, Punkte, die Zeitleiste. Sie bekommen Systemfarben. */
@media (forced-colors: active) {
  .bar-fill, .meter-fill, .zl-segment, .chat-punkt, .meter-soll, .sollskala-ist {
    forced-color-adjust: none; background: Highlight;
  }
  .bar, .meter, .zl-spur { border: 1px solid CanvasText; }
  .btn-primary, .send-btn { border: 1px solid ButtonText; }
  .nav-item.active, .chat-item.active, .baum-knoten.aktiv, .tool-btn.active {
    outline: 2px solid Highlight; outline-offset: -2px;
  }
  .toast-meldung, .menu, .dialog { border: 1px solid CanvasText; }
}
@media (prefers-contrast: more) {
  :root { --border: var(--border-stark); }
  .stand-still, .hint, .feld-hinweis { color: var(--text); }
}

/* ============================================================
   12. Aufnehmer (Fotos)
   ------------------------------------------------------------
   Ein Aufbau für beide Geräte, nur anders angeordnet: Bühne, Seitenspalte,
   Bedienleiste. Ab 900 px steht die Spalte rechts neben dem Bild - der Platz
   ist da, und man sieht alle Seiten gleichzeitig statt sie durchzuscrollen.

   Die BÜHNE bleibt bewusst schwarz und folgt nicht dem Farbschema: ein
   Kamerabild beurteilt man auf Schwarz, sonst färbt der Rahmen die Beurteilung
   ein. Die Bedienteile darum beziehen ihre Farben jetzt aus eigenen Tokens
   statt aus zwei Dutzend eingestreuter rgba()-Werte.
   ============================================================ */
.sc, .schau {
  --sc-grund: #0a0a0c;
  --sc-text: #f5f5f7;
  --sc-text-dim: rgba(245, 245, 247, 0.6);
  --sc-flaeche: rgba(255, 255, 255, 0.1);
  --sc-flaeche-hover: rgba(255, 255, 255, 0.18);
  --sc-flaeche-aktiv: rgba(255, 255, 255, 0.26);
  --sc-kante: rgba(255, 255, 255, 0.1);
  --sc-blau: #0a84ff;
  --sc-gruen: #30d158;
  --sc-rot: #ff6961;
}

/* `touch-action: manipulation` schaltet das Doppeltipp-Zoomen ab - und damit
   die 300 ms, die der Browser sonst wartet, ob ein zweiter Tipp kommt. Ohne das
   wirkt jeder Knopf träge. */
body.sc-offen { overflow: hidden; }
.sc button, .schau button, .fo button, .sc select {
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  user-select: none;
}
.sc, .schau {
  position: fixed; inset: 0; z-index: var(--z-vollbild);
  display: flex; flex-direction: column;
  background: var(--sc-grund); color: var(--sc-text);
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.schau { z-index: calc(var(--z-vollbild) + 20); }
/* Im Aufnehmer gilt derselbe Fokusring wie überall, nur in Weiß - vorher hatte
   dort KEIN Bedienteil außer der Bildkachel eine sichtbare Fokusmarke. */
.sc :focus-visible, .schau :focus-visible, .fo :focus-visible {
  outline: 2px solid var(--sc-blau); outline-offset: 2px;
}

.sc-kopf, .fo-kopf {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--sc-kante);
}
.sc-titel { flex: 1; min-width: 0; text-align: center; line-height: 1.25; }
.sc-titel strong { display: block; font-size: var(--fs-lg); font-weight: 600; }
.sc-titel span { font-size: var(--fs-sm); color: var(--sc-text-dim); }
.sc-platzhalter { width: var(--h-ziel); flex: 0 0 auto; }
.sc-rund {
  flex: 0 0 auto; width: var(--h-ziel); height: var(--h-ziel);
  display: grid; place-items: center;
  border: none; border-radius: 50%; cursor: pointer;
  background: var(--sc-flaeche); color: var(--sc-text);
}
.sc-rund:hover { background: var(--sc-flaeche-hover); }
.sc-rund:active { background: var(--sc-flaeche-aktiv); }

/* SPALTE auf schmalen Schirmen, Zeile auf breiten. `min-height: 0` ist hier
   nicht Kosmetik: ein Flex-Kind hat `min-height: auto` und schrumpft deshalb
   NICHT unter seinen Inhalt. Das Video ist hoch, die Bühne blieb hoch, und der
   Fotostreifen samt halber Bedienleiste wurde aus dem Bild geschoben. */
.sc-mitte { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.sc-buehne {
  position: relative; flex: 1 1 auto; min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.sc-buehne video { width: 100%; height: 100%; object-fit: contain; display: block; }
.sc-status {
  position: absolute; left: 50%; bottom: var(--s4); transform: translateX(-50%);
  margin: 0; padding: var(--s2) var(--s5); border-radius: var(--r-pill); white-space: nowrap;
  font-size: var(--fs-bd); font-weight: 500; background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(10px); border: 1px solid var(--sc-kante);
}
.sc-status.warnt { background: rgba(255, 159, 10, 0.92); color: #1a1a1a; border-color: transparent; }
.sc-leer { padding: var(--s7) var(--s6); text-align: center; font-size: var(--fs-lg);
           line-height: 1.6; color: var(--sc-text-dim); max-width: 32rem; }
/* Die Kamerawahl. Volles Zielmass, nicht das kleine: sie ist am Telefon ein
   Bedienteil wie jedes andere - und seit die Rueckkameras einzeln darin stehen,
   ist sie kein Notbehelf mehr, sondern der Weg zur richtigen Linse. Breiter,
   weil "Ultraweitwinkel" mehr Platz braucht als "Kamera 2". */
.sc-kamera {
  position: absolute; right: var(--s3); top: var(--s3);
  min-height: var(--h-ziel);
  background: rgba(0, 0, 0, 0.6); color: var(--sc-text); font-size: var(--fs-sm);
  border: 1px solid var(--sc-kante); border-radius: var(--r-sm); padding: var(--s1) var(--s2);
  max-width: min(62%, 16rem);
}
/* Die Klappliste selbst zeichnet das System - dort gilt die dunkle Flaeche des
   Aufnehmers nicht, also stehen Text und Grund hier ausdruecklich. */
.sc-kamera option, .sc-kamera optgroup { background: #1a1a1c; color: #f5f5f7; }
.sc-blitz {
  position: absolute; inset: 0; background: #fff; pointer-events: none;
  animation: sc-blitz 220ms ease-out forwards;
}
@keyframes sc-blitz { from { opacity: 0.9; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .sc-blitz { display: none; } }

/* ---- Fotos ----
   Auf dem Telefon ein eigener Schirm über allem, auf dem Rechner die rechte
   Spalte. Gleiche Kacheln, gleiche Knöpfe, gleicher Code - nur die Anordnung
   unterscheidet sich.

   Der z-index gilt INNERHALB von .sc: die Bühne bildet mit ihrem eigenen
   z-index einen Stapelzusammenhang, aus dem ein Kind nicht ausbricht. */
.fo {
  position: fixed; inset: 0; z-index: 5; display: none;
  flex-direction: column; background: var(--sc-grund); color: var(--sc-text);
  --sc-text: #f5f5f7;
  --sc-text-dim: rgba(245, 245, 247, 0.6);
  --sc-flaeche: rgba(255, 255, 255, 0.1);
  --sc-flaeche-hover: rgba(255, 255, 255, 0.18);
  --sc-flaeche-aktiv: rgba(255, 255, 255, 0.26);
  --sc-kante: rgba(255, 255, 255, 0.1);
  --sc-blau: #0a84ff;
  --sc-rot: #ff6961;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.fo.offen { display: flex; }
.fo-kopf strong { font-size: var(--fs-lg); font-weight: 600; }
.fo-raster {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s3);
  padding: var(--s3) var(--s4); align-content: start;
}
.fo-leer {
  flex: 1 1 auto; display: grid; place-content: center; text-align: center;
  margin: 0; padding: var(--s6); font-size: var(--fs-bd); line-height: 1.6;
  color: var(--sc-text-dim);
}
.fo-leiste {
  flex: 0 0 auto; display: flex; gap: var(--s3); padding: var(--s3) var(--s4) var(--s4);
  border-top: 1px solid var(--sc-kante);
}
/* Die Knöpfe gehören zur festen dunklen Palette des Aufnehmers, nicht zum
   Farbschema der Anwendung - sonst stünde hier je nach Einstellung ein weißer
   Knopf auf fast schwarzem Grund. */
.fo-leiste .btn {
  flex: 1; justify-content: center; min-height: var(--h-ziel);
  background: var(--sc-flaeche); color: var(--sc-text); border-color: var(--sc-kante);
}
.fo-leiste .btn:hover { background: var(--sc-flaeche-hover); border-color: var(--sc-kante); }
.fo-leiste .btn:active { background: var(--sc-flaeche-aktiv); }
.fo-leiste .btn-primary { background: var(--sc-blau); border-color: var(--sc-blau); color: #fff; }
.fo-leiste .btn-primary:hover { background: #339cff; border-color: #339cff; }

/* ---- Eine Kachel ---- */
.fo-kachel {
  display: flex; flex-direction: column; gap: var(--s2); border-radius: var(--r-lg);
  background: rgba(255, 255, 255, 0.06); padding: var(--s2);
}
.fo-kachel.zieht { opacity: 0.4; }
.fo-bild {
  position: relative; display: block; width: 100%; padding: 0; border: none;
  border-radius: var(--r-sm); overflow: hidden; background: #fff; cursor: pointer;
  aspect-ratio: 3 / 4; touch-action: manipulation;
}
.fo-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fo-bild .nr {
  position: absolute; left: var(--s2); top: var(--s2); min-width: 22px; padding: 2px var(--s2);
  border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.72); color: #fff;
  font-size: var(--fs-sm); font-weight: 700; font-variant-numeric: tabular-nums;
}
.fo-bild:active { opacity: 0.8; }
/* Zugeschnitten oder gedreht: an der Kachel muss zu sehen sein, dass hier
   nicht mehr das Bild der Kamera steht - sonst sucht man spaeter einen Rand,
   den man selbst weggenommen hat. */
.fo-marke {
  position: absolute; right: var(--s2); top: var(--s2);
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: rgba(0, 0, 0, 0.72); color: #fff; pointer-events: none;
}
/* Lupe: dass ein Bild antippbar ist, muss man sehen - ein Bild sieht sonst aus
   wie eine Anzeige, nicht wie ein Knopf. */
.fo-bild::after {
  content: ""; position: absolute; right: var(--s2); bottom: var(--s2);
  width: 26px; height: 26px; border-radius: 50%; pointer-events: none;
  background: rgba(0, 0, 0, 0.6) center/14px 14px no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
}
/* Vier Knöpfe unter jeder Kachel. Sie stehen HIER und nicht nur in der
   Großansicht, weil Umsortieren der häufigste Handgriff ist und niemand dafür
   erst ein Bild öffnen will. */
.fo-knoepfe { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; }
.fo-knopf {
  height: var(--h-ziel); display: grid; place-items: center; padding: 0; cursor: pointer;
  border: none; border-radius: var(--r-sm); background: none;
  color: rgba(245, 245, 247, 0.85); touch-action: manipulation;
}
.fo-knopf:hover { background: var(--sc-flaeche-hover); }
.fo-knopf:active { background: var(--sc-flaeche-aktiv); }
.fo-knopf:disabled { opacity: 0.25; cursor: default; background: none; }
.fo-knopf.gefahr { color: var(--sc-rot); }

/* ---- Bedienleiste ---- */
.sc-leiste, .schau-leiste {
  flex: 0 0 auto; display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: var(--s3); padding: var(--s4) var(--s5) var(--s5);
}
.schau-leiste { grid-template-columns: repeat(5, 1fr); }
.schnitt-leiste { grid-template-columns: repeat(4, 1fr); }
/* Fuenf Beschriftungen nebeneinander passen auf ein Telefon nicht - sie
   brechen sonst mitten im Wort um. Unter 560 px zwei Reihen zu dreien; die
   vier des Zuschnitts stehen dort zu zweit, sonst wird "Übernehmen" schmaler
   als das Wort. */
@media (max-width: 559px) {
  .schau-leiste { grid-template-columns: repeat(3, 1fr); gap: var(--s1);
                  padding-bottom: var(--s4); }
  .schnitt-leiste { grid-template-columns: repeat(2, 1fr); gap: var(--s1);
                    padding-bottom: var(--s4); }
}
.sc-neben {
  display: flex; flex-direction: column; align-items: center; gap: var(--s1);
  min-width: 68px; min-height: 58px; padding: var(--s2); cursor: pointer;
  border: none; border-radius: var(--r-lg); background: none;
  color: rgba(245, 245, 247, 0.85); font-size: var(--fs-sm);
}
.sc-neben:hover { background: var(--sc-flaeche); }
/* Am Telefon gibt es kein Überfahren - ohne :active-Zustand fühlt sich jeder
   Druck an, als wäre er nicht angekommen, und man tippt ein zweites Mal. */
.sc-neben:active { background: var(--sc-flaeche-aktiv); }
.sc-neben:disabled { opacity: 0.3; cursor: default; }
.sc-neben:disabled:hover { background: none; }
.sc-neben.gefahr { color: var(--sc-rot); }
/* Die eine Handlung, die den Zustand aendert - in einer Reihe gleich
   aussehender Knoepfe muss sie sich unterscheiden, sonst sucht man sie. */
.sc-neben.haupt { color: var(--sc-blau); }
.sc-neben:last-child { justify-self: end; }
.schau-leiste .sc-neben { justify-self: center; }
.sc-zaehler {
  min-width: 26px; height: 22px; line-height: 22px; padding: 0 var(--s2);
  border-radius: var(--r-pill);
  background: var(--sc-gruen); color: #08240f; font-weight: 700; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.sc-neben:disabled .sc-zaehler { background: rgba(255, 255, 255, 0.2); color: #fff; }
/* Der Auslöser ist groß und rund: er wird im Halbdunkel und in Bewegung
   getroffen, nicht in Ruhe gezielt. */
.sc-ausloeser {
  justify-self: center; width: 72px; height: 72px; padding: 0; cursor: pointer;
  display: grid; place-items: center; border-radius: 50%;
  border: 4px solid rgba(255, 255, 255, 0.9); background: transparent;
}
.sc-ausloeser .kern {
  width: 56px; height: 56px; border-radius: 50%; background: #fff;
  transition: transform 110ms ease;
}
.sc-ausloeser:active .kern { transform: scale(0.85); }
.sc-ausloeser:disabled { opacity: 0.4; cursor: default; }

/* ---- Einzelne Seite ansehen ---- */
.schau-buehne {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center; padding: var(--s3);
}
.schau-buehne img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  border-radius: var(--r-sm); background: #fff; box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5);
}
.schau-pfeil {
  position: absolute; top: 50%; left: var(--s2); transform: translateY(-50%);
  width: 48px; height: 64px; display: grid; place-items: center; cursor: pointer;
  border: none; border-radius: var(--r-lg); color: #fff;
  background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(8px);
}
.schau-pfeil.rechts { left: auto; right: var(--s2); }
.schau-pfeil:disabled { opacity: 0.2; cursor: default; }

/* ---- Zuschneiden ----
   Eine Ebene ueber der Grossansicht. Der Rahmen wird in JavaScript in Pixeln
   gesetzt (er haengt an der gemessenen Lage des Bildes, nicht an Prozenten der
   Buehne) - hier steht nur, wie er aussieht und wo man ihn anfassen kann. */
.schnitt { z-index: calc(var(--z-vollbild) + 25); }
.schnitt-buehne {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s4); overflow: hidden;
}
.schnitt-buehne img {
  position: relative; z-index: 1;
  max-width: 100%; max-height: 100%; object-fit: contain; display: block;
  background: #fff; user-select: none; -webkit-user-drag: none;
  /* Gedreht wird um die Bildmitte - dieselbe Mitte, um die auch das Ergebnis
     gerechnet wird. Ohne diese Festlegung waere es der Vorgabewert (ebenfalls
     die Mitte), aber hier haengt eine Rechnung daran, also steht sie da. */
  transform-origin: center center;
}
/* Der weisse Grund unter dem Ausschnitt: bei geneigtem Bild schaut er in den
   Ecken hervor und zeigt vorweg, was das Ergebnis dort haben wird. */
.schnitt-blatt { position: absolute; z-index: 0; background: #fff; }
.schnitt-rahmen {
  position: absolute; z-index: 2; left: 0; top: 0; width: 0; height: 0; box-sizing: border-box;
  border: 2px solid #fff; cursor: move; touch-action: none;
  /* EIN Schatten dunkelt alles ausserhalb ab - vier Kaesten muessten bei jeder
     Bewegung neu gerechnet werden, und der Rahmen soll dem Finger folgen. */
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.55);
  /* Drittellinien: sie helfen beim Ausrichten, ohne selbst etwas zu behaupten.
     Die Kachel ist genau ein Drittel breit und die Linie steht an ihrem Anfang -
     damit liegen sie bei 0, 1/3 und 2/3, und die erste verschwindet unter dem
     Rahmen. (Mit `background-position: 33.33%` waeren es 22 % gewesen: ein
     Prozentwert richtet die Kachel IM Kasten aus, er verschiebt sie nicht.) */
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.28) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.28) 1px, transparent 1px);
  background-size: calc(100% / 3) 100%, 100% calc(100% / 3);
  background-position: 0 0;
}
.schnitt-griff {
  position: absolute; width: 34px; height: 34px; touch-action: none;
}
/* Die Trefferflaeche ist gross, die Marke darin klein: am Finger wird nicht
   gezielt, aber ein 34-px-Klotz an jeder Ecke verdeckte das Bild. */
.schnitt-griff::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%); border-radius: 2px;
}
.g-ol::after, .g-or::after, .g-ul::after, .g-ur::after {
  width: 16px; height: 16px; border: 3px solid #fff; border-radius: 3px;
}
.g-ol::after { border-right: none; border-bottom: none; }
.g-or::after { border-left: none; border-bottom: none; }
.g-ul::after { border-right: none; border-top: none; }
.g-ur::after { border-left: none; border-top: none; }
.g-o::after, .g-u::after { width: 26px; height: 4px; background: #fff; }
.g-l::after, .g-r::after { width: 4px; height: 26px; background: #fff; }
.g-ol { left: -17px; top: -17px; cursor: nwse-resize; }
.g-or { right: -17px; top: -17px; cursor: nesw-resize; }
.g-ul { left: -17px; bottom: -17px; cursor: nesw-resize; }
.g-ur { right: -17px; bottom: -17px; cursor: nwse-resize; }
.g-o { left: 50%; top: -17px; margin-left: -17px; cursor: ns-resize; }
.g-u { left: 50%; bottom: -17px; margin-left: -17px; cursor: ns-resize; }
.g-l { top: 50%; left: -17px; margin-top: -17px; cursor: ew-resize; }
.g-r { top: 50%; right: -17px; margin-top: -17px; cursor: ew-resize; }

/* Neigen: der feine Winkel, mit dem ein aus der Hand aufgenommenes Blatt
   gerade gerueckt wird. Der Regler nimmt die Breite, die Gradzahl ist zugleich
   der Weg zurueck auf null. */
.schnitt-regler {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s5) 0;
}
.schnitt-regler label { flex: 0 0 auto; font-size: var(--fs-sm); color: var(--sc-text-dim); }
/* Die Spur wird selbst gezeichnet, und zwar VON DER MITTE aus. Der Regler geht
   in zwei Richtungen; die Systemvorgabe faerbt aber immer von links bis zum
   Griff, und dann sieht eine Neigung von 5 Grad nach rechts aus wie ein
   Ausschlag von 55 %. Die beiden Marken setzt das Skript (siehe winkelSetzen). */
.schnitt-regler input[type="range"] {
  flex: 1 1 auto; min-width: 0; height: var(--h-ziel);
  -webkit-appearance: none; appearance: none; background: none; cursor: pointer;
  --von: 50%; --bis: 50%;
}
.schnitt-regler input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--sc-kante) var(--von),
              var(--sc-blau) var(--von) var(--bis), var(--sc-kante) var(--bis));
}
.schnitt-regler input[type="range"]::-moz-range-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--sc-kante) var(--von),
              var(--sc-blau) var(--von) var(--bis), var(--sc-kante) var(--bis));
}
/* Sobald die Spur selbst gezeichnet wird, verschwindet auch der Griff der
   Systemvorgabe - er muss deshalb hier stehen. Gross genug fuer den Daumen. */
.schnitt-regler input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 22px; height: 22px; margin-top: -9px;
  border: none; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}
.schnitt-regler input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px; border: none; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}
.schnitt-null {
  flex: 0 0 auto; min-width: 66px; min-height: var(--h-ziel-klein); padding: 0 var(--s2);
  border: 1px solid var(--sc-kante); border-radius: var(--r-pill);
  background: var(--sc-flaeche); color: var(--sc-text); cursor: pointer;
  font: inherit; font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.schnitt-null:hover { background: var(--sc-flaeche-hover); }
.schnitt-null:disabled {
  background: none; border-color: transparent; color: var(--sc-text-dim); cursor: default;
}

/* ---- Abschluss ---- */
.schluss {
  position: fixed; inset: 0; z-index: calc(var(--z-vollbild) + 30); display: flex;
  align-items: flex-end; justify-content: center; background: rgba(0, 0, 0, 0.6);
}
.schluss-box {
  width: min(560px, 100%); display: flex; flex-direction: column; gap: var(--s1);
  background: var(--bg-panel); color: var(--text);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding: var(--s6) var(--s5) calc(var(--s5) + env(safe-area-inset-bottom));
}
.schluss-box h2 { margin: 0; font-size: var(--fs-2xl); }
.schluss-knoepfe { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s4); }
.schluss-knoepfe .btn { flex: 1 1 auto; min-height: var(--h-ziel); justify-content: center; }

/* ---- Rechner: Fotos nach rechts ---- */
@media (min-width: 900px) {
  .sc-mitte { flex-direction: row; }
  /* Auf dem Rechner ist Platz für beides nebeneinander - dort steht die
     Fotospalte dauerhaft offen und der Umweg über einen eigenen Schirm
     entfällt. Es sind dieselben Kacheln. */
  .fo {
    position: static; display: flex; width: 272px; flex: 0 0 272px;
    border-left: 1px solid var(--sc-kante); padding: 0;
  }
  .fo-zurueck { display: none; }
  .fo-raster { grid-template-columns: 1fr; }
  .schluss { align-items: center; }
  .schluss-box { border-radius: var(--r-xl); }
  .schau-buehne { padding: var(--s6) 72px; }
}

/* Fehlerzustand einer Liste. Er sieht aus wie ein Leerzustand - denn an genau
   dieser Stelle stand vorher fälschlich einer -, trägt aber die Warnfarbe und
   einen Weg zurück. */
.fehler-zustand { display: flex; flex-direction: column; align-items: center;
                  gap: var(--s1); }
.fehler-zustand strong { color: var(--danger); }

/* Ein Foto, das sich nicht anzeigen laesst, muss das SAGEN. Vorher blieb an
   dieser Stelle eine leere weisse Flaeche zurueck (Kachel) bzw. der alt-Text
   des Bildes auf weissem Grund (Grossansicht) - beides sah nach einem
   Darstellungsfehler aus, war aber eine kaputte Aufnahme. */
.fo-kachel.kaputt .fo-bild { background: var(--sc-flaeche); }
.fo-kachel.kaputt .fo-bild::before {
  content: "Bild defekt"; position: absolute; inset: 0;
  display: grid; place-content: center; text-align: center; padding: var(--s2);
  color: var(--sc-rot); font-size: var(--fs-sm); font-weight: 600;
}
.schau-buehne img.kaputt {
  width: min(280px, 80%); height: 120px; background: var(--sc-flaeche);
  border: 1px dashed var(--sc-rot);
}

/* „Erneut versuchen", wenn die Kamera nicht aufging. */
.sc-nochmal { margin-top: var(--s4); background: var(--sc-flaeche); color: var(--sc-text);
              border-color: var(--sc-kante); box-shadow: none; }
.sc-nochmal:hover { background: var(--sc-flaeche-hover); border-color: var(--sc-kante); }

/* ============================================================
   16. Benchmark (nur Administratoren)
   ------------------------------------------------------------
   Prueflaeufe gegen einen festen Prueffbestand. Dieselbe Bauweise wie der
   Bereich Betrieb: Kennzahlen oben, darunter Abschnitte, Diagramme von Hand
   aus DOM und CSS. Es gibt bewusst keine Diagrammbibliothek - ein Balken und
   eine Saeule sind zwei Elemente mit einer Breite bzw. Hoehe, und eine
   Bibliothek waere mehr Ladezeit als Erkenntnis.

   Ein Urteil traegt immer TEXT, nie nur Farbe: gefallene Zeilen sind
   zusaetzlich markiert, und in der Bewertungsliste steht das Wort daneben.
   ============================================================ */
#view-pruefstand .view-inner { max-width: min(1320px, 100%); }
#view-pruefstand .kennzahlen, #view-pruefstand .panel { transition: opacity var(--tempo); }
#view-pruefstand.laedt .kennzahlen, #view-pruefstand.laedt .panel { opacity: 0.65; }
#view-pruefstand h3 {
  margin: var(--s5) 0 var(--s2); font-size: var(--fs-lg); font-weight: 600;
}
#view-pruefstand .panel > h3:first-of-type { margin-top: var(--s3); }

/* Der laufende Lauf steht oben und faellt auf - er sperrt Einlesen und
   Loeschen, also muss man ihn sehen, ohne zu suchen. Runde 64: als Band, das
   beim Rollen oben haftet - die Frage „läuft da noch etwas?" stellt sich auf
   jeder Höhe der Seite. */
.panel.bm-laufend {
  position: sticky; top: 0; z-index: var(--z-haftend);
  margin-bottom: var(--s5); padding: var(--s3) var(--s4);
  border: 1px solid var(--accent); border-left-width: 4px; border-radius: var(--r-md);
  background: var(--bg); box-shadow: var(--shadow-mittel);
}
.panel.bm-laufend h2 { margin: 0 0 var(--s1); font-size: var(--fs-lg); }
.panel.bm-laufend .hint { margin-bottom: var(--s2); }
.panel.bm-laufend .panel-fuss { margin-top: var(--s2); padding-top: var(--s2); }

.bm-meter { display: flex; flex-direction: column; gap: var(--s2); }

/* Verlauf ueber die Laeufe: eine Saeule je Lauf. Die ganze Reihe ist EIN
   Bedienelement (roving tabindex) - sonst tabbt man sich durch dreissig
   Saeulen, um an die Tabelle darunter zu kommen. */
/* Runde 64: mit Achse (0/50/100 %), Hilfslinien, Wert über und Laufnummer
   unter jeder Säule, und höchstens 64 px breit. Vorher standen drei Läufe als
   drei bildschirmbreite Blöcke da, und den Wert gab es nur im Hinweisfenster. */
.bm-saeulen {
  display: flex; align-items: stretch; gap: var(--s3);
  height: 190px; padding: var(--s5) 0 0;
}
.verlauf-achse {
  display: flex; flex-direction: column; justify-content: space-between; flex: none;
  padding-bottom: calc(var(--s5) + var(--s1));
  color: var(--text-dim); font-size: var(--fs-xs); line-height: 1;
  font-variant-numeric: tabular-nums; text-align: right;
}
.verlauf-achse span:first-child { transform: translateY(-50%); }
.verlauf-achse span:last-child { transform: translateY(50%); }
.verlauf-saeule {
  flex: 0 1 64px; min-width: 28px; height: 100%; padding: 0;
  display: flex; flex-direction: column; align-items: stretch; gap: var(--s1);
  background: none; border: 0; border-radius: var(--r-xs);
  cursor: pointer;
}
.verlauf-spur {
  position: relative; flex: 1 1 auto; display: flex; align-items: flex-end;
  border-bottom: 1px solid var(--border-stark);
  background-image: linear-gradient(var(--kante-fein), var(--kante-fein)),
                    linear-gradient(var(--kante-fein), var(--kante-fein));
  background-size: 100% 1px; background-position: 0 0, 0 50%; background-repeat: no-repeat;
}
.verlauf-wert {
  position: absolute; left: 0; right: 0; margin-bottom: var(--s1);
  color: var(--text); font-size: var(--fs-xs); font-weight: 600; text-align: center;
  font-variant-numeric: tabular-nums;
}
.verlauf-lauf {
  flex: none; height: var(--s5); color: var(--text-dim); font-size: var(--fs-xs);
  text-align: center; font-variant-numeric: tabular-nums;
}
.verlauf-saeule:hover { background: var(--bg-hover); }
/* Kein eigener Fokusumriss: die allgemeine Regel in Abschnitt 10 zeichnet ihn.
   Hier stand bis zum 23.09.2026 `outline: var(--fokus)` - und --fokus ist ein
   SCHATTEN (`0 0 0 3px ...`), kein Umriss. Ein ungueltiger Wert macht die
   Eigenschaft zur Laufzeit ungueltig, sie faellt auf `none` zurueck, und weil
   die Regel spezifischer ist als die allgemeine, ueberstimmte sie diese: die
   Saeulenreihe hatte keinen sichtbaren Tastaturfokus. tests/t_frontend.py
   verbietet die Schreibweise seitdem. */
.verlauf-fuellung {
  display: block; width: 100%; min-height: 2px;
  background: var(--accent); border-radius: var(--r-xs) var(--r-xs) 0 0;
}
/* Ohne Urteil ist NICHT null: ein leerer Balken behauptete sonst eine
   Verschlechterung, wo gar nichts gemessen wurde. */
.verlauf-fuellung.verlauf-ohne { background: var(--border-stark); }
/* Nach aelteren Regeln bewertet: dieselbe Saeule, aber gestrichelt umrandet
   und heller - sichtbar anders, ohne wie "kein Wert" auszusehen. */
.verlauf-aelter .verlauf-fuellung {
  background: var(--accent-soft-stark);
  outline: 1px dashed var(--accent); outline-offset: -1px;
}

.bm-tabelle .zellentext { max-width: 30ch; }
/* Zweite Zeile einer Zelle: was zur ersten gehört, aber keine eigene Spalte
   braucht - Notiz, Fallzahl, Antwortmodell in der Liste der Läufe. */
.zelle-zusatz { display: block; margin-top: var(--s0); font-size: var(--fs-sm); color: var(--text-dim); }
@media (min-width: 760px) {
  .zelle-zusatz { max-width: 24ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Der Modus eines Vergleichslaufs ist die Auskunft der Zeile - er bricht um,
     statt abgeschnitten zu werden. */
  .zelle-umbruch .zellentext { white-space: normal; }
  /* Die Liste der Läufe passt so auch bei 1366 px neben die Reiterspalte:
     schmalere Textspalten, und zwei Handlungen stehen untereinander - die
     Spalte bleibt so breit wie ein Knopf. */
  /* Runde 65: 18 statt 22 Zeichen - die Spalte „Ergebnis" kam hinzu. */
  #bm-laeufe .zellentext, #bm-laeufe .zelle-zusatz { max-width: 18ch; }
  /* Notiz und Antwortmodell sind Beiwerk - gekürzt, ganz im Hinweis. */
  #bm-laeufe td[data-label="Prüfsatz"] .zelle-zusatz,
  #bm-laeufe td[data-label="Modus"] .zelle-zusatz { max-width: 15ch; }
  #bm-laeufe td.col-aktion > button { display: block; width: 100%; }
  #bm-laeufe td.col-aktion > button + button { margin: var(--s1) 0 0; }
}
/* Ein gefallener Fall trägt eine Kante links und sein Urteil als Zustand
   (Symbol und Wort) - vorher eine rosa Fläche über die ganze Zeile. */
.bm-tabelle tbody tr.bm-gefallen td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.zelle-kennung .zellentext { font-family: var(--mono); font-size: var(--fs-sm); }
/* Die Handlung einer Zeile bleibt beim waagerechten Rollen rechts stehen: in
   einem breiten Datenbereich lag „Ansehen" sonst hinter dem Rand (Runde 64). */
@media (min-width: 760px) {
  .tabellen-rahmen > .bm-tabelle td.col-aktion,
  .tabellen-rahmen > .bm-tabelle:has(td.col-aktion) th:last-child {
    position: sticky; right: 0; background: var(--bg);
    box-shadow: inset 1px 0 0 var(--kante-fein);
  }
  .tabellen-rahmen > .bm-tabelle:has(td.col-aktion) th:last-child { background: var(--flaeche-abschnitt); }
}
.bm-tabelle tbody tr.bm-geaendert td { background: var(--accent-soft); }

.bm-stand { column-count: 2; column-gap: var(--s6); }
.bm-stand dt { font-weight: 600; color: var(--text-dim); font-size: var(--fs-sm); }
.bm-stand dd { margin: 0 0 var(--s2); overflow-wrap: anywhere; }
/* Prüfsummen und Kennungen: gleich breite Zeichen auf eingelassener Fläche -
   man vergleicht sie Zeichen für Zeichen (benchmark.mitKennung). */
code.kennung {
  padding: 0 var(--s1); border-radius: var(--r-xs); background: var(--flaeche-abschnitt);
  font-family: var(--mono); font-size: var(--fs-sm); overflow-wrap: anywhere;
}

/* Der Einzelfall im Dialog: Soll und Ist nebeneinander, darunter Bewertung
   und Spur. Die Gegenueberstellung ist der Kern - ein Urteil ohne die beiden
   Seiten daneben laesst sich nicht nachvollziehen. */
.bm-zug { display: flex; flex-direction: column; gap: var(--s3); max-width: 78ch; }
.bm-block h3 { margin: 0 0 var(--s2); font-size: var(--fs-md); color: var(--text-dim); }
.bm-paar { display: grid; gap: var(--s3); grid-template-columns: 1fr 1fr; }
.bm-soll, .bm-ist {
  padding: var(--s3); border: 1px solid var(--border); border-radius: var(--r-sm);
  min-width: 0;
}
.bm-soll { background: var(--bg-feld); }
.bm-text {
  margin: 0; white-space: pre-wrap; overflow-wrap: anywhere;
  font-family: inherit; font-size: var(--fs-md); line-height: var(--lh);
  max-height: 22em; overflow-y: auto;
}

@media (max-width: 759px) {
  .bm-paar { grid-template-columns: 1fr; }
  .bm-stand { column-count: 1; }
  .bm-saeulen { height: 150px; gap: var(--s2); }
}

/* Die Dimensionsnamen sind Saetze, keine Woerter ("Alle noetigen Dokumente
   beruecksichtigt"). Die Spalte des Bereichs Betrieb ist 6,5 em breit - dort
   stehen "Auslastung" und "Speicher". Hier brachen die Namen dreizeilig um und
   machten jede Zeile dreimal so hoch wie noetig. `.meter-zeile` ist ein
   Gitter, die Breite steckt also in grid-template-columns. */
#view-pruefstand .meter-zeile { grid-template-columns: 17em minmax(0, 1fr) auto; }
@media (max-width: 899px) {
  #view-pruefstand .meter-zeile { grid-template-columns: minmax(0, 1fr) auto; }
  #view-pruefstand .meter-label { grid-column: 1 / -1; }
  #view-pruefstand .meter-zusatz { grid-column: 1 / -1; }
}

/* ---------- Die Leiste mit zwei Teilen (seit 23.09.2026) ----------
   Erst der Teil, dann der Bereich. Bis dahin standen zehn Reiter in einer
   Reihe, getrennt von zwei Zwischenzeilen, die wie Reiter aussahen. Die
   Leiste steckt dafuer in einem Umschlag - und die Regeln, die sonst an
   `.view-inner.reiter-spalte > .abschnitt-nav` haengen, gelten jetzt fuer den
   Umschlag: `sticky` klebt nur innerhalb des Elternteils, und der waere jetzt
   genau so hoch wie die Leiste selbst. */
.ps-leiste { display: flex; flex-direction: column; gap: var(--s3); }
.ps-leiste > .abschnitt-nav { margin-bottom: 0; }
.teilwahl {
  display: flex; gap: var(--s1); padding: var(--s1);
  background: var(--bg-feld); border: 1px solid var(--border); border-radius: var(--r-pill);
}
.teilwahl button {
  flex: 1 1 0; min-height: var(--h-ziel-klein); padding: var(--s1) var(--s3);
  border: 0; border-radius: var(--r-pill); background: none; cursor: pointer;
  color: var(--text-dim); font: inherit; font-size: var(--fs-md); font-weight: 500;
  transition: background var(--tempo), color var(--tempo);
}
.teilwahl button:hover { color: var(--text); }
.teilwahl button[aria-pressed="true"] {
  background: var(--bg-panel); color: var(--text); font-weight: 600;
  box-shadow: var(--shadow);
}
/* Die Gruppe verhaelt sich wie die Leiste, in der sie steht: senkrecht in der
   Spalte, waagerecht in der rollenden Leiste darueber. */
.nav-teil { display: flex; flex-direction: inherit; gap: inherit; align-items: inherit; }

@media (min-width: 1200px) {
  .view-inner.reiter-spalte > .ps-leiste {
    grid-column: 1; position: sticky; top: 0; align-self: start;
  }
  .ps-leiste > .abschnitt-nav {
    flex-direction: column; align-items: stretch;
    padding-bottom: 0; border-bottom: none;
  }
}
@media (max-width: 1199px) {
  .ps-leiste {
    position: sticky; top: 0; z-index: var(--z-haftend);
    margin: 0 calc(var(--s4) * -1) var(--s5); padding: var(--s2) var(--s4);
    background: var(--bg); border-bottom: 1px solid var(--border);
  }
  .teilwahl { align-self: flex-start; }
  .teilwahl button { flex: 0 0 auto; }
  /* Die Leiste klebt jetzt mit dem Umschlag; eine zweite klebende Ebene darin
     wuerde sich beim Rollen unter die erste schieben. */
  .ps-leiste > .abschnitt-nav {
    position: static; margin: 0; padding: 0; border-bottom: none; background: none;
  }
}

/* ---------- Ueberblick: eine Zeile je Pruefsatz ----------
   Runde 64: vorher Karten im Raster, alle so hoch wie die höchste - ein Satz
   ohne Lauf stand als großer leerer Kasten da. Jetzt eine Zeile je Satz:
   links Name, Quote und Umfang, rechts die fünf Bereiche nebeneinander; ein
   Satz ohne Lauf ist eine kurze Zeile. Die Spalten stehen über alle Sätze
   hinweg untereinander - so lassen sich die Sätze vergleichen. */
.bm-karten { display: grid; gap: var(--s3); grid-template-columns: minmax(0, 1fr); margin-bottom: var(--s5); }
.bm-karte, .bm-quelle {
  display: flex; flex-direction: column; gap: var(--s3); min-width: 0;
  padding: var(--s4) var(--s5); background: var(--bg-panel);
  border: 1px solid var(--kante-fein); border-radius: var(--r-lg);
}
@media (min-width: 1100px) {
  .bm-karte {
    display: grid; column-gap: var(--s7); row-gap: var(--s1);
    grid-template-columns: minmax(15rem, 1fr) minmax(0, 2fr) auto;
    /* Runde 65: Spanne und Trend, die Klassenleiste und die schwächste Gruppe
       stehen links unter der Quote - sie gehören zu ihr. Fehlt ein Teil
       (Lauf ohne Auswertung), bleibt seine Zeile leer und flach. */
    grid-template-areas: "kopf kopf aktionen" "quote bereiche bereiche"
                         "lage bereiche bereiche" "klassen bereiche bereiche"
                         "schwach bereiche bereiche"
                         "misst bereiche bereiche" "lauf bereiche bereiche";
    align-items: start;
  }
  .bm-karte > .bm-karte-kopf { grid-area: kopf; }
  .bm-karte > .bm-karte-aktionen { grid-area: aktionen; justify-self: end; margin-top: 0; }
  .bm-karte > .bm-karte-quote { grid-area: quote; }
  .bm-karte > .bm-karte-lage { grid-area: lage; }
  .bm-karte > .bm-klassen { grid-area: klassen; }
  .bm-karte > .bm-karte-schwach { grid-area: schwach; }
  .bm-karte > .bm-karte-misst { grid-area: misst; }
  .bm-karte > .hint { grid-area: lauf; }
  .bm-karte > .bm-karte-bereiche {
    grid-area: bereiche; display: grid; gap: var(--s2) var(--s5);
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  }
}
.bm-karte-kopf { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2) var(--s3); }
.bm-karte-kopf h3 { margin: 0; flex: 1 1 auto; font-size: var(--fs-lg); }
#view-pruefstand .bm-karte-kopf h3 { margin: 0; }
.bm-karte-quote { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s2); }
.bm-karte-quote strong {
  font-size: var(--fs-3xl); font-weight: 650; line-height: 1.1; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.bm-karte-quote span { color: var(--text-dim); font-size: var(--fs-md); }
/* Die zweite Zahl neben der Quote. Gleich nach ihr, nicht in einer Fussnote -
   ohne sie liest sich eine Quote wie eine Aussage ueber die ganze Anlage. */
.bm-karte-misst { margin: 0; color: var(--text-dim); font-weight: 550; font-size: var(--fs-md); }
.bm-karte-bereiche { display: flex; flex-direction: column; gap: var(--s2); }
#view-pruefstand .bm-karte-bereiche .meter-zeile { grid-template-columns: 9em minmax(0, 1fr) auto; }
.bm-karte .hint { margin: 0; }
.bm-karte-aktionen { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: auto; }

/* ---------- Quellen ---------- */
.bm-quellen { display: flex; flex-direction: column; gap: var(--s4); }
.bm-quelle-zweck { margin: 0; max-width: 78ch; }
.bm-quelle-angaben { margin: 0; }
.bm-quelle-angaben dd { overflow-wrap: anywhere; }
.bm-grenzen-liste { margin: var(--s2) 0 var(--s3); padding-left: var(--s5); max-width: 82ch; }
.bm-grenzen-liste li { margin-bottom: var(--s2); line-height: var(--lh); }
.bm-bereich-zeile { margin: var(--s2) 0; }

/* ---------- Ein Lauf ---------- */
.bm-detail-kopf { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3); }
.bm-detail-kopf h2 { margin: 0; }
#bm-detail-regelstand { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
#bm-detail-regelstand[hidden] { display: none; }

.bm-bereiche { display: grid; gap: var(--s4); }
.bm-bereich {
  padding: var(--s4) var(--s5); border: 1px solid var(--kante-fein); border-radius: var(--r-md);
  background: var(--bg-panel);
}
.bm-bereich-kopf { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s3); }
.bm-bereich-kopf h4 { margin: 0; font-size: var(--fs-bd); font-weight: 600; }
.bm-bereich-kopf .hint { margin: 0; }
/* "Ohne Urteil" steht als Wort da und nicht als leerer Balken - ein leerer
   Balken behauptete null, wo nichts entschieden wurde. */
.bm-ohne-urteil .bm-ohne-urteil-text { color: var(--text-dim); font-size: var(--fs-md); }
.bm-nicht-geprueft {
  margin: var(--s3) 0 0; padding-top: var(--s2); border-top: 1px dashed var(--border);
  color: var(--text-dim); font-size: var(--fs-sm);
}

/* Soll/Ist einer gemessenen Größe (benchmark.sollIst): das Mittel als Punkt,
   die Schwelle als Strich auf einer Skala von 0 bis 1. Verfehlt: Warnfarbe am
   Punkt - das Wort dazu steht in der Zeile daneben. */
.sollskala { display: inline-flex; align-items: center; margin-right: var(--s2); vertical-align: middle; }
.sollskala-spur {
  position: relative; display: inline-block; width: 7em; height: var(--s1);
  border-radius: var(--r-pill); background: var(--bg-active);
}
.sollskala-soll {
  position: absolute; top: calc(var(--s1) * -1); bottom: calc(var(--s1) * -1); width: var(--s0);
  margin-left: -1px; border-radius: var(--r-pill); background: var(--text);
}
.sollskala-ist {
  position: absolute; top: 50%; width: var(--s3); height: var(--s3); margin: calc(var(--s3) / -2) 0 0 calc(var(--s3) / -2);
  border: var(--s0) solid var(--bg); border-radius: var(--r-pill); background: var(--ok);
}
.sollskala-verfehlt .sollskala-ist { background: var(--warn); }

/* Fehlerklassen: Wort, Code, Zahl - neutral. Eine Fehlerklasse ist eine
   Einordnung, kein Alarm; rot stand dort jede, auch die harmloseste. */
.bm-klasse { gap: var(--s2); padding: var(--s1) var(--s1) var(--s1) var(--s3); color: var(--text); }
.bm-klasse-code {
  padding: 0 var(--s1); border-radius: var(--r-xs); background: var(--bg-panel);
  color: var(--text-dim); font-family: var(--mono); font-size: var(--fs-xs); font-weight: 500;
}
.bm-klasse-zahl {
  min-width: var(--s5); padding: 0 var(--s1); border-radius: var(--r-pill);
  background: var(--danger-soft); color: var(--danger); text-align: center; font-variant-numeric: tabular-nums;
}

/* Die Modusmatrix ist Nachschlagestoff und klappt auf (Runde 64). */
.bm-umfang { margin-top: var(--s2); }
.bm-umfang > .hint { margin-top: var(--s2); }

.bm-quer-tabelle td { vertical-align: middle; }
.bm-zelle-wert { display: block; font-variant-numeric: tabular-nums; font-weight: 600; }
.bm-zelle-balken {
  display: block; height: 4px; margin-top: var(--s1); max-width: 6em;
  background: var(--accent-soft-stark); border-radius: var(--r-pill); overflow: hidden;
}
.bm-zelle-fuellung { display: block; height: 100%; background: var(--accent); }

.bm-herkunft { margin-top: var(--s5); }
.bm-herkunft h4 { margin: var(--s3) 0 var(--s2); font-size: var(--fs-md); color: var(--text-dim); }
.bm-filter { display: flex; align-items: center; gap: var(--s2); font-size: var(--fs-md); color: var(--text-dim); }
#panel-bm-laeufe .panel-kopf { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3); padding: 0 0 var(--s3); }
#panel-bm-laeufe .panel-kopf h2 { margin: 0; }

@media (max-width: 759px) {
  .bm-karten { grid-template-columns: 1fr; }
  #view-pruefstand .bm-karte-bereiche .meter-zeile { grid-template-columns: minmax(0, 1fr) auto; }
  #view-pruefstand .bm-karte-bereiche .meter-label { grid-column: 1 / -1; }
}

/* ---------- Auswertung eines Laufs (Runde 65) ----------
   Die Leitfrage von oben nach unten: wie gut (Klassenleiste), wo es klemmt
   (schwächste Gruppen, Kreuztabelle, Aufgliederung), welche Fälle (Liste).
   Die Zeichner stehen in js/bm_auswertung.js, die Farben in Abschnitt 1. */

/* Die vier Klassen als Teile vom Ganzen. Zwischen den Teilen 2 px Fläche -
   gleich helle Nachbarn verschwämmen sonst an der Naht. „noch offen" und
   „übersprungen" sind kein Ergebnis und bilden den hellen Rest der Spur. */
.bm-klassen { display: flex; flex-direction: column; gap: var(--s2); margin-bottom: var(--s6); }
.bm-klassenleiste {
  display: flex; gap: var(--s0); height: var(--s3);
  border-radius: var(--r-xs); overflow: hidden;
}
.bm-klassenleiste:empty { background: var(--bm-rest); }
.bm-segment { flex: 1 1 0; min-width: 3px; }
.bm-segment-bestanden { background: var(--bm-bestanden); }
.bm-segment-gefallen { background: var(--bm-gefallen); }
.bm-segment-technisch { background: var(--bm-technisch); }
.bm-segment-ohne_urteil { background: var(--bm-ohne-urteil); }
.bm-segment-rest { background: var(--bm-rest); }
.bm-klassen-legende {
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s4);
  margin: 0; padding: 0; list-style: none; font-size: var(--fs-md);
}
.bm-klassen-legende li { display: inline-flex; align-items: center; gap: var(--s2); }
.bm-klassen-legende strong { font-variant-numeric: tabular-nums; }
/* Die Marke hat die Form des Teils, für das sie steht: eine kurze Pille. */
.bm-swatch { flex: none; width: 14px; height: 10px; border-radius: var(--r-pill); }
.bm-legende-knopf {
  padding: var(--s0) var(--s1); margin: calc(var(--s0) * -1) calc(var(--s1) * -1);
  border: 0; border-radius: var(--r-xs); background: none; cursor: pointer;
  color: var(--text); font: inherit;
  text-decoration: underline; text-decoration-color: var(--border-stark); text-underline-offset: 3px;
}
.bm-legende-knopf:hover { background: var(--bg-hover); text-decoration-color: currentColor; }
/* Klein: in einer Tabellenzeile und auf der Satzkarte - nur die Leiste. */
.bm-klassen.bm-klassen-klein { gap: var(--s1); margin: var(--s1) 0 0; }
.bm-klassen-klein .bm-klassenleiste { height: 6px; max-width: 12rem; border-radius: var(--r-pill); }
.bm-lauf-ergebnis { display: flex; align-items: baseline; gap: var(--s2); white-space: nowrap; }
.bm-lauf-quote { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.bm-lauf-nenner { color: var(--text-dim); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
#bm-laeufe .bm-klassen-klein .bm-klassenleiste { max-width: 7rem; }

/* Satzkarte im Überblick: Spanne und Trend unter der Quote, dann die Leiste. */
.bm-karte-lage { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s3); }
.bm-karte-lage .hint { margin: 0; }
.bm-karte-schwach { margin: 0; font-size: var(--fs-md); }
.bm-karte-schwach > span:first-child { color: var(--text-dim); }

/* Laufkopf: Ausfuhr und Löschen gehören zum Lauf, nicht zur Seite. */
.bm-detail-aktionen { display: flex; flex-wrap: wrap; gap: var(--s2); }
.bm-detail-klassen .bm-klassen { margin-top: calc(var(--s3) * -1); }

/* Wo es klemmt: die schwächsten Gruppen als Kacheln - jede ein Filter. */
.bm-schwaechen {
  display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  margin: 0 0 var(--s6); padding: 0; list-style: none;
}
.bm-schwaechen li { display: flex; min-width: 0; }
.bm-schwaeche {
  display: flex; flex-direction: column; gap: var(--s0); width: 100%; min-width: 0;
  padding: var(--s3) var(--s4); border: 1px solid var(--kante-fein); border-radius: var(--r-md);
  background: var(--bg-panel); color: var(--text); font: inherit; text-align: left;
}
button.bm-schwaeche { cursor: pointer; transition: background var(--tempo), border-color var(--tempo); }
button.bm-schwaeche:hover { background: var(--bg-hover); border-color: var(--border-stark); }
.bm-schwaeche-achse { color: var(--text-dim); font-size: var(--fs-sm); font-weight: 600; }
.bm-schwaeche-wert { font-size: var(--fs-bd); overflow-wrap: anywhere; }
.bm-schwaeche-quote { font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.bm-schwaeche-abstand { color: var(--text-dim); font-size: var(--fs-sm); }

/* Kreuztabelle Szenario × Stufe. Zellen mit 2 px Fuge (border-spacing);
   jede Zelle nennt Quote und Nenner. Unter drei entschiedenen Fällen keine
   Farbe, sondern eine Schraffur: 1 von 1 sind 100 % und sagen nichts. */
.bm-heatmap-rahmen { margin-bottom: var(--s2); border: 0; }
.bm-heatmap {
  width: 100%; min-width: 34rem; border-collapse: separate; border-spacing: var(--s0);
  table-layout: fixed; font-size: var(--fs-md);
}
.bm-heatmap th {
  padding: var(--s1) var(--s2); color: var(--text-dim); font-size: var(--fs-sm); font-weight: 600;
  text-align: center; vertical-align: bottom; line-height: var(--lh-eng);
}
.bm-heatmap thead th:first-child, .bm-heatmap tbody th { width: 11rem; text-align: left; }
.bm-heatmap tbody th { color: var(--text); font-size: var(--fs-md); font-weight: 550; vertical-align: middle; }
.bm-hm-kopfzusatz::before { content: " · "; }
.bm-heatmap td {
  height: 3.25rem; padding: 0; border-radius: var(--r-xs);
  background: var(--bg-hover); color: var(--text); text-align: center;
}
.bm-heatmap td[data-stufe="0"], .bm-hm-swatch[data-stufe="0"] { background: var(--bm-hm-0); }
.bm-heatmap td[data-stufe="1"], .bm-hm-swatch[data-stufe="1"] { background: var(--bm-hm-1); }
.bm-heatmap td[data-stufe="2"], .bm-hm-swatch[data-stufe="2"] { background: var(--bm-hm-2); }
.bm-heatmap td[data-stufe="3"], .bm-hm-swatch[data-stufe="3"] { background: var(--bm-hm-3); }
.bm-heatmap td[data-stufe="4"], .bm-hm-swatch[data-stufe="4"] { background: var(--bm-hm-4); }
.bm-heatmap td.bm-hm-wenig, .bm-hm-swatch.bm-hm-wenig {
  background: repeating-linear-gradient(135deg, var(--bg-hover) 0 5px, var(--bg) 5px 10px);
  box-shadow: inset 0 0 0 1px var(--kante-fein); color: var(--text-dim);
}
.bm-heatmap td.bm-hm-leer { background: none; box-shadow: inset 0 0 0 1px var(--kante-fein); color: var(--text-dim); }
/* Die Summenspalte trägt einen Rand - sie ist keine weitere Stufe. */
.bm-heatmap td.bm-hm-summe { box-shadow: inset 0 0 0 1px var(--border-stark); }
.bm-heatmap td.bm-hm-summe .bm-hm-quote { font-weight: 750; }
.bm-hm-knopf {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; height: 100%; min-height: 3.25rem; padding: var(--s1);
  border: 0; border-radius: inherit; background: none; color: inherit; font: inherit;
}
button.bm-hm-knopf { cursor: pointer; }
button.bm-hm-knopf:hover { box-shadow: inset 0 0 0 2px var(--text); }
.bm-hm-quote { font-weight: 650; font-variant-numeric: tabular-nums; }
.bm-hm-n { font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.bm-hm-strich { color: var(--text-dim); }
.bm-hm-legende {
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s4);
  margin: 0 0 var(--s6); padding: 0; list-style: none;
  color: var(--text-dim); font-size: var(--fs-sm);
}
.bm-hm-legende li { display: inline-flex; align-items: center; gap: var(--s2); }
.bm-hm-swatch { flex: none; width: 18px; height: 14px; border-radius: var(--r-xs); }

/* Aufgliederung: eine Zeile je Gruppe - Name, Balken mit Spanne, Quote,
   darunter die Zahlen. EINE Farbe für alle Balken; der senkrechte Strich
   ist der ganze Lauf. Die Enden der Spanne ragen über den Balken hinaus,
   damit man sie auch dort sieht, wo sie auf ihm liegen. */
.bm-achse { display: flex; flex-direction: column; gap: var(--s1); margin-bottom: var(--s6); }
.bm-achse-zeile {
  display: grid; align-items: center; column-gap: var(--s4); row-gap: var(--s0);
  grid-template-columns: minmax(8rem, 14rem) minmax(6rem, 1fr) 3.5rem;
  grid-template-areas: "name spur wert" "name zusatz zusatz";
  width: 100%; padding: var(--s2); border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text); font: inherit; text-align: left;
}
button.bm-achse-zeile { cursor: pointer; }
button.bm-achse-zeile:hover { background: var(--bg-hover); }
.bm-achse-name { grid-area: name; font-size: var(--fs-bd); font-weight: 550; overflow-wrap: anywhere; }
.bm-achse-spur { grid-area: spur; position: relative; height: 14px; }
.bm-achse-spur::before {
  content: ""; position: absolute; left: 0; right: 0; top: 3px; bottom: 3px;
  border-radius: var(--r-xs); background: var(--bg-active);
}
.bm-achse-fuellung {
  position: absolute; left: 0; top: 3px; bottom: 3px;
  border-radius: var(--r-xs); background: var(--accent);
}
.bm-achse-wenig .bm-achse-fuellung {
  background: repeating-linear-gradient(135deg, var(--accent) 0 3px, var(--accent-soft-stark) 3px 6px);
}
.bm-achse-spanne {
  position: absolute; top: 0; bottom: 0; min-width: 2px;
  border-left: 2px solid var(--text-dim); border-right: 2px solid var(--text-dim);
  background: linear-gradient(var(--text-dim), var(--text-dim)) center / 100% 2px no-repeat;
}
.bm-achse.mit-gesamt .bm-achse-spur::after {
  content: ""; position: absolute; left: var(--bm-gesamt); top: -3px; bottom: -3px;
  width: 2px; margin-left: -1px; background: var(--text);
}
.bm-achse-spur:has(> .bm-achse-leer)::before, .bm-achse-spur:has(> .bm-achse-leer)::after { content: none; }
.bm-achse-spur:has(> .bm-achse-leer) { height: auto; }
.bm-achse-leer { color: var(--text-dim); font-size: var(--fs-sm); }
.bm-achse-luecke .bm-achse-name { color: var(--text-dim); }
.bm-achse-wert { grid-area: wert; text-align: right; font-weight: 650; font-variant-numeric: tabular-nums; }
.bm-achse-zusatz { grid-area: zusatz; color: var(--text-dim); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.bm-achse-zusatz:empty { display: none; }

/* Fallliste: Zahl der Treffer und das Zurücksetzen über der Tabelle. */
.bm-fall-lage { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.bm-fall-lage .hint { margin: 0; }
.bm-fall-filter input[type="search"] { min-width: 14rem; }

/* Ein Fall als Gespräch (Dialog): ein Block je Zug, Soll neben Ist. */
.bm-fall-kopf { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); }
.bm-fall-kopf .hint { margin: 0; }
.bm-fall-einordnung { flex-basis: 100%; }
.bm-fall-zug {
  display: flex; flex-direction: column; gap: var(--s3);
  padding-top: var(--s4); border-top: 1px solid var(--kante-fein);
}
.bm-fall-zug h3 { margin: 0; font-size: var(--fs-bd); }
.bm-fall-zug > .hint { margin: 0; }
.bm-folge { display: inline-flex; flex-wrap: wrap; gap: var(--s1) var(--s2); }
.bm-folge-marke { font-variant-numeric: tabular-nums; }
.bm-gruende { display: flex; flex-wrap: wrap; gap: var(--s1); }
.bm-befunde { display: flex; flex-direction: column; gap: var(--s1); margin: 0; padding: 0; list-style: none; }
.bm-befunde li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s0) var(--s2); }
.bm-befunde li .hint { flex-basis: 100%; margin: 0; }
/* Die Gründe über der Problemliste sind Schalter (aria-pressed): gedrückt zeigt
   die Liste nur diese Fälle. Der gedrückte trägt einen Rand - nicht nur Farbe. */
.bm-grund-knopf { padding: 0; border: 0; border-radius: var(--r-pill); background: none; cursor: pointer; font: inherit; }
.bm-grund-knopf:hover .status.marke { filter: brightness(0.96); }
.bm-grund-knopf[aria-pressed="true"] .status.marke { box-shadow: inset 0 0 0 2px currentColor; }

/* Live-Zwischenstand im Band „Lauf in Arbeit". */
.bm-live { display: flex; flex-direction: column; gap: var(--s2); margin-top: var(--s3); }
.bm-live-kennzahlen { margin-bottom: 0; }
.bm-live-kennzahlen .kennzahl { padding: var(--s2) var(--s4); }
.bm-live-kennzahlen .kennzahl-wert { font-size: var(--fs-xl); }
.bm-live-kennzahlen .kennzahl.haupt .kennzahl-wert { font-size: var(--fs-2xl); }
.bm-live .bm-klassen { margin-bottom: 0; }

/* Vergleich Fall für Fall. */
.bm-verg-fallsicht { display: flex; flex-direction: column; gap: var(--s3); margin: var(--s3) 0 var(--s5); }
.bm-verg-fallsicht .hint { margin: 0; }
.bm-vergleichbar { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.bm-verg-quote { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s5); margin: 0; font-variant-numeric: tabular-nums; }
.bm-tabelle tbody tr.bm-gestiegen td:first-child { box-shadow: inset 3px 0 0 var(--ok); }

/* Deckung: Fragen je Szenario und Prüfsatz. Eine Lücke ist ein Wort. */
.bm-deckung-abschnitt { margin: var(--s2) 0 var(--s5); }
.bm-deckung-abschnitt h3 { margin: 0 0 var(--s1); }
.bm-deckung { font-size: var(--fs-md); }
.bm-deckung tbody th { text-align: left; font-weight: 550; white-space: nowrap; }
.bm-deckung td.bm-luecke { color: var(--text-dim); background: var(--flaeche-abschnitt); }

@media (max-width: 759px) {
  /* Kreuztabelle und Deckung sind echte Tabellen, keine Karten: sie rollen in
     ihrem Rahmen, statt die Seite zu verbreitern. */
  .tabellen-rahmen.bm-heatmap-rahmen, .tabellen-rahmen.bm-deckung-rahmen { overflow-x: auto; }
  .bm-heatmap { min-width: 30rem; }
  .bm-heatmap thead th:first-child, .bm-heatmap tbody th { width: 8.5rem; }
  .bm-hm-kopfzusatz { display: block; font-weight: 500; }
  .bm-hm-kopfzusatz::before { content: none; }
  .bm-achse-zeile {
    grid-template-columns: minmax(0, 1fr) 3.5rem;
    grid-template-areas: "name wert" "spur spur" "zusatz zusatz";
  }
  .bm-fall-filter input[type="search"] { min-width: 0; }
  .bm-detail-aktionen { width: 100%; }
  .bm-detail-aktionen > .btn { flex: 1 1 auto; }
}

/* ============================================================
   17. Prüfstand - die vier Reiter der Verarbeitung
   ============================================================
   Der Bereich hiess bis zum 22.09.2026 "Benchmark" und bestand nur aus
   Abschnitt 16. Was hier dazukommt, ist die andere Haelfte derselben Frage:
   nicht "wie gut misst sich die Anlage", sondern "was hat sie bei DIESEM
   Dokument und DIESER Frage eigentlich getan". */

/* Der Umschlag um mehrere Panels, die zu EINEM Reiter gehoeren. Ohne ihn
   muesste jeder Reiter genau einem Panel entsprechen - und "Prueflaeufe"
   besteht nun einmal aus Uebersicht, Start, Liste und Detail. */
.reiterfeld { display: contents; }
/* Ein Element, das zu einem geschlossenen Reiter gehoert, aber ausserhalb von
   ihm liegt. Klasse statt `hidden`, weil diese Elemente ihre Sichtbarkeit
   selbst schalten - siehe bausteine.reiter(). Der Selektor ist absichtlich
   zweiteilig: er muss `display: flex` der Ablageflaeche schlagen. */
[data-reiter].reiter-zu { display: none; }
/* Sobald die Reiterleiste ein Gitter aufspannt, darf der Umschlag NICHT mehr
   durchsichtig sein: `display: contents` gaebe seine Kinder direkt ans Gitter
   weiter, und `hidden` an einem durchsichtigen Element blendet nichts aus. */
.view-inner.mit-reitern > .reiterfeld { display: block; }
.view-inner.mit-reitern > .reiterfeld > .panel:first-child { margin-top: 0; }

/* Die Rubriken IN der Reiterleiste (`.nav-gruppe`) sind am 23.09.2026
   entfallen: aus zwei Zwischenzeilen, die wie Reiter aussahen, wurden zwei
   Teile vor der Leiste (.teilwahl, Abschnitt 16). */

/* Ein Kasten je Verarbeitungsschritt im Überblick. */
.ps-karten {
  display: grid; gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
/* Vier Kaesten: zwei mal zwei liest sich besser als drei und einer allein.
   Erst ab genug Breite - darunter entscheidet auto-fit. */
@media (min-width: 900px) {
  .ps-karten { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.ps-karte {
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s4) var(--s5); border: 1px solid var(--kante-fein);
  border-radius: var(--r-lg); background: var(--bg-panel);
}
/* Mit der Kennung der Ansicht: `#view-pruefstand h3` gab jeder Überschrift
   oben 20 px Abstand - im Kasten stand sie dadurch tiefer als sein Inhalt. */
#view-pruefstand .ps-karte h3 { margin: 0; font-size: var(--fs-lg); }
.ps-karte-satz { margin: 0; color: var(--text-dim); font-size: var(--fs-md); }
.ps-karte .btn { align-self: flex-start; margin-top: auto; }

/* Der Schaukasten: Frage, Antwort, Zahlen, Zeiten. */
.ps-detail { display: flex; flex-direction: column; gap: var(--s3); }
.ps-detail h4 { margin: 0; font-size: var(--fs-md); }
.ps-detail-kopf { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; margin: 0; }
/* Eine Frage oder Antwort ist Fliesstext, kein Programmtext - aber sie kann
   lang sein und muss umbrechen duerfen. */
.ps-detail-text {
  margin: 0; padding: var(--s3); border-radius: var(--r-sm);
  background: var(--bg-hover); font-size: var(--fs-md); line-height: var(--lh);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.ps-schritte {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  margin: 0; padding: 0; list-style: none;
}
.ps-schritte li {
  padding: var(--s1) var(--s3); border-radius: var(--r-pill);
  background: var(--bg-hover); font-size: var(--fs-xs); color: var(--text-dim);
}

/* Eine Zeile aus einem FREMDEN Chat. Kein Warnton - es ist kein Fehler,
   sondern eine Grenze: hier steht die Verarbeitung und sonst nichts. */

/* Kopf eines Abschnitts mit Tabelle: Überschrift und Hinweis darüber. Er trug
   den Innenabstand, den `.panel-flush` der Tabelle wegen wegließ - seit die
   Abschnitte flach sind (Runde 64), rückte er damit 16 px aus der Flucht von
   Filter und Tabelle, und der Filter klebte am Hinweis. Jetzt bündig, und der
   Hinweis behält seinen Abstand nach unten. */
.panel-kopf { padding: 0; }
.panel-kopf h2 { margin-bottom: var(--s2); }

/* Ein Haken mit Beschriftung in einer Filterzeile - daneben stehen <label>
   mit <select>, und ohne diese Zeile saesse der Haken auf der Grundlinie. */
.feld-schalter {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: var(--h-feld); font-size: var(--fs-md);
}
.feld-schalter input { margin: 0; }

/* Erster Aufbau: ein Skelett statt zehn leerer Bereiche.
   Die Klasse stand seit dem 21.09.2026 im Markup und wurde von benchmark.js
   auch wieder entfernt - nur gab es keine einzige Regel dazu. Der erste
   Aufbau zeigte deshalb den leeren Endzustand, und das sah aus wie "es gibt
   nichts" statt wie "es laedt noch". */
#view-pruefstand.erst-laedt .ps-karten,
#view-pruefstand.erst-laedt .doc-table,
#view-pruefstand.erst-laedt .tabellen-rahmen,
#view-pruefstand.erst-laedt .leer-zustand { display: none; }
#view-pruefstand.erst-laedt #ps-ueberblick-skelett { display: flex; }
#view-pruefstand:not(.erst-laedt) #ps-ueberblick-skelett { display: none; }

/* Wie eine Antwort zustande kam - eine Zeile unter der Antwort, der Rest im
   Aufklapper. Die Antwort bleibt die Hauptsache: ein Kasten voller Zahlen
   unter jeder Nachricht waere genau die Ueberladung, gegen die der ganze
   Umbau gerichtet ist. */
.verarbeitung { display: flex; flex-direction: column; gap: var(--s2); margin-top: var(--s2); }
.verarbeitung-kopf { display: flex; flex-wrap: wrap; gap: var(--s1); align-items: center; }
.verarbeitung-mehr > summary {
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: var(--s1) 0; color: var(--text-dim);
  font-size: var(--fs-xs); cursor: pointer; list-style: none;
}
.verarbeitung-mehr > summary::-webkit-details-marker { display: none; }
.verarbeitung-mehr > summary::before {
  content: ""; width: 0; height: 0;
  border-left: 4px solid currentColor;
  border-top: 3px solid var(--flaeche-klar);
  border-bottom: 3px solid var(--flaeche-klar);
  transition: transform var(--tempo) var(--ease);
}
.verarbeitung-mehr[open] > summary::before { transform: rotate(90deg); }
.verarbeitung-mehr > summary:hover { color: var(--text); }
.verarbeitung-mehr .info-list { margin-top: var(--s2); }

/* Ein Produktname (Modell, Hersteller) in einer sonst deutschen Liste. Er
   bekommt die Ziffernschrift, damit lange Bezeichner wie „Qwen3.8-27B-Q4_K_M"
   nicht umbrechen wie Fliesstext - und er ist der Anker, an dem die
   Sprachprüfung ihn als Fremdnamen erkennt (e2e/ui/sprache.py). */
.fremder-name { font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ---------- Modi, Startkarte, Auswahl (seit 23.09.2026) ----------
   Klein, Mittel, Voll je Pruefsatz; vor dem Start steht, was GENAU laeuft,
   und die Vorabpruefung als Liste. Der Modusschalter ist dieselbe
   `.teilwahl` wie die Wahl zwischen Verarbeitung und Messung - ein
   Bedienmuster fuer "eins von wenigen". */
.bm-matrix-rahmen { overflow-x: auto; margin-bottom: var(--s5); }
.bm-matrix { font-size: var(--fs-sm); }
.bm-matrix td, .bm-matrix th { padding: var(--s2) var(--s2); font-variant-numeric: tabular-nums; }
/* Koepfe duerfen umbrechen: "Belegdokumente" und "Unbeantwortbar" setzten
   sonst allein die Spaltenbreite, und neun Spalten passten nicht ins Panel. */
.bm-matrix th { white-space: normal; vertical-align: bottom; }
.bm-matrix td[data-label="Fragen"], .bm-matrix td[data-label="Dokumente mit Beleg"] { white-space: nowrap; }
/* Die Sprachzelle bricht nur an ihren <wbr> hinter „→" und „/" (benchmark.mitUmbruch). */
.bm-matrix td[data-label="Sprache"] { min-width: 9ch; }
.bm-matrix tr.bm-matrix-schlank > td { border-top: 2px solid var(--border-stark); }
/* Der Name steht einmal ueber den drei Zeilen seines Satzes - und darf
   umbrechen, statt nach 24 Zeichen abgeschnitten zu werden. */
.bm-matrix td.bm-matrix-titel { vertical-align: top; font-weight: 600; min-width: 12ch; max-width: 16ch; }

.bm-modus-feld { display: flex; flex-direction: column; gap: var(--s1); }
/* Wie die Beschriftung jedes anderen Feldes der Zeile - und gleich hoch wie
   ein Auswahlfeld, damit die drei Beschriftungen auf einer Linie stehen. */
.bm-modus-label { font-size: var(--fs-sm); font-weight: 600; color: var(--text-dim); }
.bm-modus { align-self: flex-start; min-height: var(--h-feld); padding: var(--s0); }
.bm-modus button { flex: 0 0 auto; min-height: calc(var(--h-feld) - 6px); }

.bm-vorab {
  display: grid; gap: var(--s3); margin: var(--s4) 0; padding: var(--s4);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-feld);
}
.bm-vorab h3 { margin: var(--s2) 0 0; }
.bm-vorab-titel { margin: 0; font-size: var(--fs-lg); font-weight: 600; }
.bm-vorab .hint { margin: 0; }

.bm-verteilung { display: grid; gap: var(--s2); }
.bm-verteilung-zeile { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: baseline; }
.bm-verteilung-titel { min-width: 14ch; color: var(--text-dim); font-size: var(--fs-sm); }

.bm-checkliste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s1); }
.bm-checkliste li { display: flex; gap: var(--s2); align-items: baseline; }
.bm-pruef-zeichen { display: inline-flex; flex: 0 0 1.5em; justify-content: center; align-self: center; }
.bm-pruef-ja .bm-pruef-zeichen { color: var(--ok); }
.bm-pruef-nein { color: var(--danger); font-weight: 550; }
.bm-pruef-hinweis .bm-pruef-zeichen { color: var(--warn); }
.bm-pruef-laedt { color: var(--text-dim); padding-left: calc(1.5em + var(--s2)); }

.bm-varianten { display: grid; gap: var(--s1); margin: 0 0 var(--s3); padding: 0; border: 0; }
.bm-varianten legend { padding: 0; margin-bottom: var(--s1); font-weight: 600; }
.bm-schalter { display: flex; gap: var(--s2); align-items: center; }
.bm-mehr { margin-top: var(--s2); }

.bm-auswahl { margin: var(--s5) 0; }
.bm-auswahl .chips { margin: var(--s2) 0; }

@media (max-width: 759px) {
  /* Auf dem Telefon wird jede Moduszeile eine fliessende Zeile ("Klein ·
     Fragen 24 von 318 · ...") statt einer Karte mit neun Feldern - achtzehn
     solche Karten waeren ueber acht Bildschirmhoehen lang. Spezifischer als
     die allgemeine Kartenregel (.karten-tabelle:not(.betrieb-tabelle) td). */
  .bm-matrix-rahmen .karten-tabelle.bm-matrix tr {
    display: flex; flex-wrap: wrap; gap: var(--s0) var(--s3); padding: var(--s2) 0;
  }
  .bm-matrix-rahmen .karten-tabelle.bm-matrix td { display: inline; padding: 0; }
  .bm-matrix-rahmen .karten-tabelle.bm-matrix td.bm-matrix-titel {
    flex-basis: 100%; max-width: none; padding-top: var(--s3);
  }
  .bm-matrix-rahmen .karten-tabelle.bm-matrix td.bm-matrix-titel::before,
  .bm-matrix-rahmen .karten-tabelle.bm-matrix td[data-label="Modus"]::before { content: none; }
  .bm-matrix-rahmen .karten-tabelle.bm-matrix td[data-label="Modus"] { font-weight: 600; }
  .bm-matrix-rahmen .karten-tabelle.bm-matrix tr.bm-matrix-schlank > td { border-top: none; }
}
@media (max-width: 599px) {
  /* Bezeichnung und Wert untereinander: nebeneinander blieb dem Wert eine
     Spalte von neunzig Pixeln, und Woerter brachen mitten durch. */
  .bm-vorab .info-list, .bm-auswahl .info-list { grid-template-columns: 1fr; gap: 0; }
  .bm-vorab .info-list dd, .bm-auswahl .info-list dd { margin-bottom: var(--s2); }
}

/* ---------- Der einzelne Testfall (Runde 66, bm_fall.js) ----------
   Eine ganze Seite statt eines Dialogs: Soll und Ist brauchen Breite, ein
   Seitenbild braucht Höhe, und wer durch hundert Fälle blättert, braucht eine
   Leiste, die stehen bleibt. Solange sie offen ist, tritt die Ansicht an die
   Stelle der Bereiche; die Bereiche bleiben dahinter, wie sie waren (Filter,
   Rollstand). */
.view-inner.fall-offen > :not(#panel-bm-fall) { display: none !important; }
.view-inner.reiter-spalte > .bm-fall-seite { grid-column: 1 / -1; }
.bm-fall-seite { margin-bottom: var(--s9); }
.bm-fall { max-width: 1120px; }

/* Die Leiste: zurück, Testfall/Ergebnis, Lauf, Blättern. Klebt am oberen Rand. */
.bm-fall-leiste {
  position: sticky; top: 0; z-index: var(--z-haftend);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4);
  padding: var(--s2) 0; background: var(--bg); border-bottom: 1px solid var(--kante-fein);
}
.bm-fall-zurueck { display: inline-flex; align-items: center; gap: var(--s1); }
.bm-fall-leiste .teilwahl { flex: 0 0 auto; }
.bm-fall-leiste .teilwahl button { flex: 0 0 auto; padding-left: var(--s4); padding-right: var(--s4); }
.bm-fall-lauf { display: inline-flex; align-items: center; gap: var(--s2); min-width: 0; }
.bm-fall-lauf-text { color: var(--text-dim); font-size: var(--fs-md); }
.bm-fall-lauf select, .bm-fall-belegseiten select {
  min-height: var(--h-ziel-klein); padding: var(--s1) var(--s3);
  border: 1px solid var(--border-stark); border-radius: var(--r-sm);
  background: var(--bg-feld); color: var(--text); font: inherit; font-size: var(--fs-md);
}
.bm-fall-lauf select:focus-visible, .bm-fall-belegseiten select:focus-visible {
  border-color: var(--accent); box-shadow: var(--fokus); outline: none;
}
.bm-fall-lauf select { max-width: 26em; }
.bm-fall-ohne-lauf { margin: 0; }
.bm-fall-blaettern { display: inline-flex; align-items: center; gap: var(--s1); }
.bm-fall-zaehler { color: var(--text-dim); font-size: var(--fs-md); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Die Frage steht groß und allein - alles Weitere ordnet sich ihr unter. */
.bm-fall-kopf { max-width: 70ch; margin: var(--s6) 0 var(--s5); }
.bm-fall-vorzeile { margin: 0 0 var(--s2); color: var(--text-dim); font-size: var(--fs-md); }
.bm-fall-frage {
  margin: 0; font-size: var(--fs-2xl); font-weight: 600; line-height: 1.3;
  overflow-wrap: anywhere; white-space: pre-wrap;
}
.bm-fall-laden { margin: var(--s6) 0; }

/* Die Züge eines Gesprächs. */
.bm-fall-zuege { display: flex; gap: var(--s2); margin: 0 0 var(--s5); overflow-x: auto; padding-bottom: var(--s1); }
.bm-fall-zug-knopf {
  display: inline-flex; align-items: center; gap: var(--s2); flex: none;
  min-height: var(--h-ziel-klein); padding: 0 var(--s4);
  border: 1px solid var(--border); border-radius: var(--r-pill); background: none;
  color: var(--text-dim); font: inherit; font-size: var(--fs-md); cursor: pointer; white-space: nowrap;
}
.bm-fall-zug-knopf:hover { color: var(--text); }
.bm-fall-zug-knopf[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--text); }
.bm-fall-verlauf { margin: 0 0 var(--s5); }
.bm-fall-verlaufsliste { max-width: 70ch; }
.bm-fall-verlaufsliste { margin: var(--s3) 0 0; padding-left: var(--s5); }
.bm-fall-verlaufsliste li { margin: 0 0 var(--s3); }
.bm-fall-verlauf-frage { margin: 0; font-weight: 600; }
.bm-fall-verlauf-antwort { margin: var(--s1) 0 0; color: var(--text-dim); }

/* Die Abschnitte: eine Spalte, viel Luft, je eine Überschrift. */
.bm-fall-erwartet, .bm-fall-bewertung { min-width: 0; }
.bm-fall-quellen { scroll-margin-top: var(--s9); }
.bm-fall-zug-nr { font-weight: 500; }
.bm-fall-sicht { display: flex; flex-direction: column; gap: var(--s8); margin-bottom: var(--s8); }
.bm-fall-abschnitt-kopf { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s3); margin: 0 0 var(--s3); }
.bm-fall-abschnitt-kopf h3 { margin: 0; font-size: var(--fs-lg); font-weight: 600; }
.bm-fall-abschnitt-kopf .hint { margin: 0; }
.bm-fall-paar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s7); align-items: start; }
.bm-fall-spalte { min-width: 0; }

/* Erwartet: eine eingelassene Fläche für die Sollantwort, darunter Sätze. */
.bm-fall-flaeche { padding: var(--s4); border-radius: var(--r-md); background: var(--flaeche-abschnitt); }
.bm-fall-flaeche-titel {
  margin: 0 0 var(--s2); color: var(--text-dim); font-size: var(--fs-xs); font-weight: 650;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.bm-fall-text { margin: 0; max-width: 76ch; font-size: var(--fs-bd); line-height: var(--lh); white-space: pre-wrap; overflow-wrap: anywhere; }
.bm-fall-gross { margin: 0; font-size: var(--fs-3xl); font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.bm-fall-liste { margin-top: var(--s4); }
.bm-fall-liste-titel { margin: 0 0 var(--s1); color: var(--text-dim); font-size: var(--fs-md); font-weight: 600; }
.bm-fall-liste ul { margin: 0; padding-left: var(--s5); }
.bm-fall-liste li { margin: 0 0 var(--s1); overflow-wrap: anywhere; }

/* Tatsächlich: die Antwort, wie ein Mensch sie im Chat läse. */
.bm-fall-antwort { padding: var(--s4); border: 1px solid var(--kante-fein); border-radius: var(--r-md); background: var(--bg-panel); }
.bm-fall-md { max-width: 76ch; font-size: var(--fs-bd); line-height: var(--lh); }
mark.bm-treffer { padding: 0 var(--s0); border-radius: var(--r-xs); background: var(--accent-soft-stark); color: inherit; }
.bm-fall-ergebnis { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); }
.bm-fall-fehlerklasse { color: var(--text-dim); font-size: var(--fs-md); }
.bm-fall-technik { margin: 0; }
.bm-fall-leer { padding: var(--s7) var(--s4); }

/* Quellen: links die Dokumente, rechts der Betrachter. */
.bm-fall-belege { display: grid; grid-template-columns: minmax(14em, 20em) minmax(0, 1fr); gap: var(--s5); align-items: start; }
.bm-fall-belegliste { min-width: 0; }
.bm-fall-belegzeilen { display: flex; flex-direction: column; gap: var(--s2); margin: 0; padding: 0; list-style: none; }
.bm-fall-beleg {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s0); width: 100%;
  padding: var(--s3); border: 1px solid var(--kante-fein); border-radius: var(--r-md);
  background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.bm-fall-beleg:hover { background: var(--bg-hover); }
.bm-fall-beleg[aria-current="true"] { border-color: var(--accent); background: var(--accent-soft); }
.bm-fall-beleg-name { font-weight: 600; overflow-wrap: anywhere; }
.bm-fall-beleg-meta { color: var(--text-dim); font-size: var(--fs-sm); }
.bm-fall-beleg-zustand { margin-top: var(--s1); font-size: var(--fs-md); }
.bm-fall-betrachter { min-width: 0; padding: var(--s4); border: 1px solid var(--kante-fein); border-radius: var(--r-md); background: var(--bg-panel); }
.bm-fall-betrachter-kopf { margin: 0 0 var(--s3); overflow-wrap: anywhere; }
.bm-fall-seiten { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s5); margin: 0 0 var(--s3); }
.bm-fall-seitenreihe, .bm-fall-belegseiten { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); }
.bm-fall-seitenknopf {
  min-width: var(--h-ziel-klein); min-height: var(--h-ziel-klein); padding: 0 var(--s2);
  border: 1px solid var(--border); border-radius: var(--r-pill); background: none;
  color: var(--text); font: inherit; font-size: var(--fs-md); font-variant-numeric: tabular-nums; cursor: pointer;
}
.bm-fall-seitenknopf[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); font-weight: 600; }
.bm-fall-seitenknopf.genannt { border-color: var(--ok); }
.bm-fall-bild { display: flex; flex-direction: column; gap: var(--s2); }
.bm-seitenbild { display: block; width: 100%; height: auto; border: 1px solid var(--kante-fein); border-radius: var(--r-sm); background: var(--bg); }
.bm-fall-gross-link { align-self: flex-start; font-size: var(--fs-md); }
.bm-fall-ohne-bild, .bm-fall-keine-quelle { margin: 0; }
.bm-fall-lesen { max-width: 76ch; max-height: 34em; overflow-y: auto; padding-right: var(--s2); font-size: var(--fs-bd); line-height: var(--lh); }
.bm-fall-lesen p { margin: 0 0 var(--s3); overflow-wrap: anywhere; }
.bm-fall-lesetext .hint { margin: var(--s2) 0 0; }
.bm-fall-seitentext { margin-top: var(--s3); }

/* Bewertung: gefallene Prüfungen zuerst, jede mit ihrem Grund in einem Satz. */
.bm-fall-fazit { margin: 0 0 var(--s3); font-weight: 600; }
.bm-fall-pruefungen { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.bm-fall-pruefung { padding: var(--s3) 0; border-top: 1px solid var(--kante-fein); }
.bm-fall-pruefung:first-child { border-top: 0; }
.bm-fall-pruefung-kopf { font-weight: 600; }
.bm-fall-begruendung { margin: var(--s1) 0 0; padding-left: var(--s5); max-width: 76ch; color: var(--text-dim); overflow-wrap: anywhere; }

/* Ablauf und Herkunft: Beschriftung links, Wert rechts. */
.bm-fall-daten { display: grid; grid-template-columns: minmax(10em, max-content) minmax(0, 1fr); gap: var(--s2) var(--s5); margin: var(--s3) 0 0; }
.bm-fall-daten dt { color: var(--text-dim); }
.bm-fall-daten dd { margin: 0; overflow-wrap: anywhere; }
.bm-fall-ueber .bm-fall-daten, .bm-fall-ablauf .bm-fall-daten { max-width: 70ch; }

@media (max-width: 899px) {
  .bm-fall-paar, .bm-fall-belege { grid-template-columns: 1fr; gap: var(--s5); }
  /* Zehn Belege untereinander schöben den Betrachter weit nach unten: die Liste rollt in sich. */
  .bm-fall-belegzeilen { max-height: 19em; overflow-y: auto; }
  .bm-fall-frage { font-size: var(--fs-xl); }
  .bm-fall-lauf select { max-width: 100%; }
  .bm-fall-lauf { flex: 1 1 100%; }
  .bm-fall-lauf select { flex: 1; }
}
@media (max-width: 559px) {
  .bm-fall-leiste { gap: var(--s2); }
  .bm-fall-daten { grid-template-columns: 1fr; gap: var(--s0); }
  .bm-fall-daten dd { margin-bottom: var(--s2); }
  .bm-fall-flaeche, .bm-fall-antwort, .bm-fall-betrachter { padding: var(--s3); }
}
