/* ══════════════════════════════════════════════════════════════════════════
   QS-ONE INVESTORENHUB — KOMPONENTEN                                15.09.2026
   software-designer · setzt auf tokens.css auf, ohne diese Datei ist alles
   hier ungestylt (keine Farben/Größen doppelt definiert).

   AUFBAU DIESER DATEI:
     1. Grundschicht (Reset, Body, Überschriften, Wrap/Spalten)
     2. Stufen-Modus (.stufe1 / .stufe2) — schaltet Dichte-Variablen um
     3. Eine Klasse pro Bauteil aus dem Auftrag, in der Reihenfolge des Auftrags
     4. Druckregeln

   ZWEI GESTEN (Florian, 15.09., wörtlich: „Stufe 1 = Pitch, Stufe 2 =
   Erklärung wie bei FinPrep"):
     .stufe1  — bühnenhaft: große Leitsätze, viel Luft, kurze Kapitel.
                Dunkler Bühnengrund für den Titelbereich, helle Kapitel danach.
     .stufe2  — ruhiges, dichtes Lesedokument im Kommentarsatz-Stil:
                Randziffern, längere Fließtexte, Tabellen, „Klartext" je Kapitel.
   Beide benutzen DIESELBEN Bauteile (Kapitelkopf, Leitsatz, Kennzahl, …) —
   der Unterschied liegt in Abstand/Maß/Größe, nicht in neuen Farben oder
   einem zweiten Komponenten-Satz. Das ist die sichtbare Zusammengehörigkeit,
   um die Florian gebeten hat.
   ══════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────── 1 · Grundschicht ─────────────────────────── */
*{box-sizing:border-box}
/* `overflow-x:hidden` hier (29.09.2026, Netzkarte-Umbau): Sicherheitsnetz
   gegen den bekannten `vw`-Bug (auf Desktop-Browsern mit sichtbarer
   Scrollleiste misst `vw` die Leiste MIT, ein vollbreites Element kann
   dadurch um deren Breite über den echten Dokumentrand hinausragen) - die
   vollbreite Netzkarten-Bühne (Kap. 08) ist das erste Element hier, das
   bewusst bis an den Viewport-Rand reicht. Betrifft nur die X-Achse,
   `position:sticky` (Y-Achse) bleibt davon unberührt. */
html{scroll-behavior:smooth; overflow-x:hidden; overflow-x:clip} /* clip (30.09.): hidden liess scrollIntoView die Seite seitlich verschieben; clip schneidet ohne Scroll-Container, hidden bleibt Rueckfall fuer alte Browser */
/* 16.09. abends, Florian am Bildschirm: „Schrift verbreitern … also den
   Text" — am Live-Hub gemessen 14px/23,8px Zeilenhöhe, 342px/601px/601px
   Spaltenbreite bei 390/1440/2560px (~41/71/71 Zeichen). QUELLE hier stand
   bereits auf --f-body:17px (siehe tokens.css) — das Live-Bild lag also
   HINTER diesem Stand (kein neuer Bau seit der letzten Anhebung, siehe
   Übergabe an den Entwickler). `line-height` bleibt bewusst RELATIV (1.65
   default, 1.7/1.75 je Stufe in Abschnitt 2 unten) statt eines festen
   Pixelwerts — sie zieht dadurch automatisch mit jeder künftigen Änderung
   von --f-body mit, ohne dass diese Regel angefasst werden muss.
   Zeilenlänge (Zeichen/Zeile): `--mass-lese` ist bewusst in `ch` notiert
   (Abschnitt 1 unten, `.lese-spalte`) — ch skaliert nativ mit der
   Schriftgröße, die ZEICHENZAHL bleibt also beim Anheben von --f-body
   praktisch UNVERÄNDERT (68ch bleiben ~68 Zeichen, ob bei 14 oder 17px),
   nur die Pixelbreite der Spalte wächst mit. Gerechnet mit dem aus Florians
   eigener Messung abgeleiteten Verhältnis 1ch ≈ 0,63 × Schriftgröße
   (601px ÷ 68ch ÷ 14px), NICHT geschätzt: bei 17px und 24px Seitenrand
   (`.seite{padding:0 24px}`, macht 48px beidseitig) ergibt das
     390px  → Spalte 342px (390−48, deckt sich exakt mit Florians Messwert) → ~32 Zeichen
              (unter 60–75: unvermeidlich bei 390px Breite UND ≥16px Schrift,
              kein Fehler — eine 60-Zeichen-Spalte bräuchte hier ~540px, mehr
              als der Bildschirm hat)
     768px  → Spalte 720px (768−48, noch unter dem ch-Deckel) → ~67 Zeichen ✓
     1440px → Spalte ~729px (68ch-Deckel greift, wächst nicht weiter) → ~68 Zeichen ✓
     2560px → wie 1440px, derselbe Deckel → ~68 Zeichen ✓ (bleibt bewusst so
              schmal wie bei 1440px, kein Auseinanderziehen auf großen
              Monitoren — das war schon vor dieser Änderung der Sinn von
              `--mass-lese` in ch statt %/vw). */
body{
  margin:0; background:var(--flaeche-tief); color:var(--ink);
  font-family:var(--font-text); font-size:var(--f-body); line-height:1.65;
  -webkit-font-smoothing:antialiased; overflow-wrap:break-word;
}
img,svg{max-width:100%}
h1,h2,h3{font-family:var(--font-anzeige); line-height:1.15; letter-spacing:-.015em; margin:0}
/* h3 (Markdown „###" im Kapiteltext) hatte bisher KEINE explizite Größe -
   nur h1/h2 wurden anderswo mit --f-h1/--f-h2 belegt, h3 fiel auf die
   Browser-Vorgabe zurück (zufällig nahe --f-h3, aber ungenau/instabil).
   16.09. abends nachgetragen, damit der Token wirklich greift und mit
   --f-body mitgezogen werden kann, nicht nur im Kommentar existiert. */
h3{font-size:var(--f-h3)}
p{margin:0}
a{color:var(--tiefgruen)}
a:focus-visible,button:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:3px; border-radius:6px}
.dunkel a:focus-visible,.dunkel button:focus-visible{outline-color:var(--frischgruen)}
::selection{background:var(--frischgruen); color:var(--navy)}

.seite{max-width:var(--breite-inhalt); margin:0 auto; padding:0 24px}
.lese-spalte{max-width:var(--mass-lese, 66ch); margin:0 auto}

/* 16.09., Korrektur nach Live-Skalierungsmessung: `.sprung` (Sprungmarke
   „Zum Inhalt springen" o. ä.) fehlte hier bisher als eigene Regel — sie
   war offenbar mit der veralteten `left:-9999px`-Technik eingebaut, die
   auf dem Handy zur horizontalen Scrollbarkeit der ganzen Seite beitrug
   (eine weit im Negativen positionierte Box zählt in manchen Browsern
   trotzdem zur `scrollWidth` des Dokuments). Jetzt die übliche „visuell
   verborgen bis Fokus"-Technik: die Box ist im Ruhezustand nur 1×1px groß
   und per `clip-path` zugeschnitten (bleibt also IM normalen Fluss, kein
   Offset ins Negative), erst beim Fokus wird sie sichtbar groß. */
.sprung{
  position:absolute; top:0; left:0; z-index:80;
  width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap;
  background:var(--flaeche); color:var(--tiefgruen); text-decoration:none;
  font-family:var(--font-anzeige); font-weight:700; font-size:15px;
}
.sprung:focus{
  width:auto; height:auto; overflow:visible; clip-path:none; white-space:normal;
  padding:12px 20px; border-radius:var(--r-sm); box-shadow:var(--schatten-karte);
}

/* Ein Kapitel ist die wiederkehrende Grundeinheit beider Stufen. Der Abstand
   kommt aus der Dichte-Variable, damit Stufe 1 „viel Luft" bekommt und
   Stufe 2 dicht bleibt, ohne zwei Klassensätze zu brauchen. */
.kapitel{padding:var(--kapitel-abstand) 0}
.kapitel[id]{scroll-margin-top:96px}
.kapitel + .kapitel{border-top:1px solid var(--line)}

.eyebrow{
  display:inline-block; font-family:var(--font-mono); font-size:var(--f-micro);
  font-weight:600; letter-spacing:.16em; text-transform:uppercase;
  color:var(--tiefgruen); margin-bottom:var(--sp-3);
}

/* ─────────────────────── 2 · Stufen-Modus (Dichte) ─────────────────────── */
.stufe1{
  --kapitel-abstand:132px;
  --mass-lese:60ch;
  --leitsatz-groesse:clamp(28px,4.4vw,46px);
  /* 29.09.2026, Komplettabnahme-Befund: bei GENAU 768px unterschritt
     `--mass-lese` (60ch ≈ 643px) die verfügbare Breite (768−48 = 720px)
     spürbar früher als `--breite-daten` (960px) - `.lese-spalte` blieb
     dadurch ~38px schmäler/weiter rechts eingerückt als die Datenbausteine
     daneben, die bei derselben Breite bereits voll ausfüllten. Diese
     Variable macht den LINKEN Einzug der Lesespalte für Datenbausteine
     NACHRECHENBAR (statt eigener, unabhängiger Zentrierung) - siehe
     `--daten-versatz`-Verwendung unten bei `.branchenexpansion` &co: die
     linke Kante liegt dadurch AUF JEDER Breite exakt auf der von
     Überschrift/Fließtext, nach rechts darf der Baustein trotzdem bis
     `--breite-daten` breiter sein. `max(0px, …)`, weil das Ergebnis sonst
     am Handy negativ würde (Lesespalte dort selbst schon randvoll). */
  --daten-versatz:max(0px, calc((100% - var(--mass-lese)) / 2));
}
/* :where() haelt die Spezifitaet bei (0,1,0) — sonst schluege dieses
   Kontext-Kompositum jede Utility-Klasse wie `.lead`/`.muted`, die zusammen
   MIT `.text` auf demselben Absatz steht (z. B. class="text lead"). */
:where(.stufe1) .text{font-size:calc(var(--f-body) + 1px); line-height:1.75}
.stufe1 .kapitel-kopf{margin-bottom:var(--sp-8)}

.stufe2{
  --kapitel-abstand:80px;
  --mass-lese:68ch;
  --leitsatz-groesse:clamp(20px,2.6vw,26px);
  --daten-versatz:max(0px, calc((100% - var(--mass-lese)) / 2));
}
:where(.stufe2) .text{font-size:var(--f-body); line-height:1.7}
.stufe2 .kapitel-kopf{margin-bottom:var(--sp-6)}

/* ─────────────────────── 3.1 · Stufen-Kennzeichnung ─────────────────────── */
.stufenmarke{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  font-family:var(--font-mono); font-size:var(--f-micro); font-weight:700;
  letter-spacing:.16em; text-transform:uppercase; padding:7px 16px;
  border-radius:var(--r-btn); line-height:1;
}
.stufenmarke .punkt{width:7px; height:7px; border-radius:50%; flex:none}
.stufenmarke.s1{background:var(--frischgruen); color:var(--navy)}    /* 14,2:1 */
.stufenmarke.s1 .punkt{background:var(--navy)}
.stufenmarke.s2{background:#fff; color:var(--tiefgruen); border:1.5px solid var(--tiefgruen)}
.stufenmarke.s2 .punkt{background:var(--tiefgruen)}
.dunkel .stufenmarke.s2{background:transparent; color:var(--frischgruen); border-color:var(--frischgruen)}
.dunkel .stufenmarke.s2 .punkt{background:var(--frischgruen)}
/* 05.10.2026 (Stufe 3 "Das Angebot", Pruefer-Auflage): dieselbe gruene
   Kapsel wie Stufe 2 - exakt dieselben zwei Kontexte (Zwischenschild auf
   hellem Grund vor Bereich 1, Hero-Schild in der dunklen Buehne), ohne
   eigene Regel waere ".s3" bisher auf die unstyled Basisregel oben
   zurueckgefallen (kein Hintergrund/keine Umrandung). */
.stufenmarke.s3{background:#fff; color:var(--tiefgruen); border:1.5px solid var(--tiefgruen)}
.stufenmarke.s3 .punkt{background:var(--tiefgruen)}
.dunkel .stufenmarke.s3{background:transparent; color:var(--frischgruen); border-color:var(--frischgruen)}
.dunkel .stufenmarke.s3 .punkt{background:var(--frischgruen)}

/* ───────────────────── 3.2 · Titelbereich Stufe 1 („der Traum") ─────────────────────
   Bühnenhaft: volle Breite, Navy-Grund, ein einziger großer Satz, viel Luft.
   Die Geisterziffer im Hintergrund zitiert die Kapitelmarken (siehe 3.3) —
   der Hub liest sich von der ersten Sekunde an wie ein nummeriertes Dokument,
   nicht wie eine Werbefläche. */
.traum-titel{
  position:relative; overflow:hidden; background:var(--navy); color:#fff;
  padding:var(--sp-9) 0; text-align:center;
}
.traum-titel::before{
  /* sehr zurückhaltendes Bühnenlicht — reine Fläche, kein Foto, kein Icon */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(720px 420px at 50% -10%, rgba(179,255,181,.14), transparent 62%);
}
.traum-titel .innen{position:relative; max-width:var(--breite-buehne); margin:0 auto; padding:0 24px}
.traum-titel .stufenmarke{margin-bottom:var(--sp-6)}
.traum-titel .satz{
  font-family:var(--font-anzeige); font-weight:800; font-size:var(--f-traum);
  line-height:1.12; letter-spacing:-.02em; margin:0;
}
.traum-titel .satz em{font-style:normal; color:var(--frischgruen)}
.traum-titel .unter{
  margin-top:var(--sp-6); font-size:var(--f-lead); color:rgba(255,255,255,.82);
  max-width:52ch; margin-inline:auto;
}
@media(max-width:640px){ .traum-titel{padding:var(--sp-8) 0} }

/* ───────────────────── 3.2f · Titelbühne Stufe 2 (Umbau 30.09.2026, zweite Runde) ─────────────────────
   Florian: "Das Hauptproblem bleibt der ERSTE Bildschirm von Stufe 2 ...
   baue eine Stufe-2-Titelbühne im Stil der Stufe-1-Titelbühne". EIGENE
   Klasse, bewusst NICHT `.traum-titel` wiederverwendet - Stufe 1 bleibt
   dadurch in jedem Fall unverändert, auch wenn hier später etwas geändert
   wird. Gegenüber 3.2 zwei Unterschiede: kleinere Schrift (Stufe 2 ist
   überall "leiser" als Stufe 1, vgl. `--leitsatz-groesse`/`--kapitel-
   abstand`) und KEIN Besen/Staub-Canvas - reines CSS, keine Laufzeit-
   Erzeugung, kein `<img class="besen-quelle">`. `.dunkel` ist ein bereits
   vorbereiteter, bis jetzt ungenutzter Zustand (siehe `.dunkel
   .stufenmarke.s2` weiter oben) - hier zum ersten Mal eingesetzt. */
.stufe2-buehne{
  position:relative; overflow:hidden; background:var(--navy); color:#fff;
  padding:var(--sp-8) 0; text-align:center;
}
.stufe2-buehne::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(640px 360px at 50% -10%, rgba(179,255,181,.1), transparent 62%);
}
.stufe2-buehne .innen{position:relative; max-width:var(--breite-buehne); margin:0 auto; padding:0 24px}
.stufe2-buehne .stufenmarke{margin-bottom:var(--sp-5)}
.stufe2-buehne .satz{
  font-family:var(--font-anzeige); font-weight:800; font-size:clamp(28px,4.2vw,44px);
  line-height:1.16; letter-spacing:-.015em; margin:0; color:#fff;
}
.stufe2-buehne .unter{
  margin-top:var(--sp-4); font-size:var(--f-lead); color:rgba(255,255,255,.82);
  max-width:60ch; margin-inline:auto;
}
@media(max-width:640px){ .stufe2-buehne{padding:var(--sp-6) 0} }
/* Dezente Einblendung beim Laden - reines CSS, kein JS, kein Scroll-
   Beobachter noetig, weil die Buehne ohnehin das Erste ist, was der
   Nutzer sieht. Bei reduzierter Bewegung/im Druck sofort im Endzustand. */
@media(prefers-reduced-motion:no-preference){
  .stufe2-buehne .stufenmarke,.stufe2-buehne .satz,.stufe2-buehne .unter{
    animation:stufe2-buehne-ein .6s ease-out both;
  }
  .stufe2-buehne .satz{animation-delay:.08s}
  .stufe2-buehne .unter{animation-delay:.16s}
}
@keyframes stufe2-buehne-ein{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
@media print{
  .stufe2-buehne{background:#fff !important; color:#000 !important; padding:24px 0}
  .stufe2-buehne::before{display:none}
  .stufe2-buehne .satz,.stufe2-buehne .unter{color:#000 !important}
  .stufe2-buehne .stufenmarke,.stufe2-buehne .satz,.stufe2-buehne .unter{
    animation:none !important; opacity:1 !important; transform:none !important;
  }
}

/* ───────────────────────── 3.3 · Kapitelkopf mit Nummer ─────────────────────────
   Die „Kommentarsatz"-Anmutung, die Florian an der FinPrep-Hülle gefallen
   hat — hier mit QS-One-Farben statt Navy/Messing: eine große Geisterziffer
   links, Kicker + Titel rechts, eine dünne Linie darunter. */
.kapitel-kopf{
  display:grid; grid-template-columns:auto 1fr; gap:var(--sp-4) var(--sp-6);
  align-items:end; padding-bottom:var(--sp-5); border-bottom:1.5px solid var(--line);
}
.kapitel-kopf .nr{
  font-family:var(--font-anzeige); font-weight:800; font-variant-numeric:tabular-nums;
  font-size:var(--f-nr-geist); line-height:.82;
  color:var(--frischgruen); -webkit-text-stroke:1.5px var(--tiefgruen);
}
/* 3.3b · Parallax (Der Wisch, Fortsetzung 29.09.2026): hub.html verschiebt
   die Geisterziffer per Scroll/rAF leicht langsamer als der Kapiteltext -
   nur `transform`, hier nur der Rendering-Hinweis. Nur unter "js-wisch"
   (Stufe 1, kein JS-Fehlen/keine reduzierte Bewegung) - ohne diese Klasse
   setzt hub.html gar keinen `style.transform`, die Ziffer steht ruhig. */
.js-wisch .stufe1 .kapitel-kopf .nr{will-change:transform}
@supports not (-webkit-text-stroke:1px black){
  .kapitel-kopf .nr{color:var(--tiefgruen)}
}
.kapitel-kopf .titel-block h2{font-size:var(--f-h2); color:var(--navy)}
.kapitel-kopf .titel-block .eyebrow{margin-bottom:var(--sp-2)}
@media(max-width:520px){
  .kapitel-kopf{grid-template-columns:1fr; gap:var(--sp-2)}
  .kapitel-kopf .nr{font-size:clamp(30px,10vw,44px)}
}

/* ───────────────────────────── 3.4 · Fließtext ───────────────────────────── */
.text{font-family:var(--font-text); color:var(--ink); max-width:var(--mass-lese)}
.text.muted{color:var(--muted)}
.text + .text{margin-top:var(--sp-4)}
/* 16.09.: der Lead klebte am ersten Fließtext-Absatz. Ursache: er steht im
   Markup als letztes Kind der EINLEITENDEN `.lese-spalte` (mit Kapitelkopf),
   der erste `.text`-Absatz aber als erstes Kind der NÄCHSTEN `.lese-spalte`
   — beide sind keine CSS-Geschwister, `.text + .text` griff also nie. Fix:
   `margin-bottom` direkt am Lead, escaped durch die randlose `.lese-spalte`
   nach außen (keine Border/Padding dort, die das verhindern würde). */
.lead{font-size:var(--f-lead); color:var(--muted); max-width:56ch; margin-bottom:1em}

/* ─────────────────────────── 3.5 · Zitat / Leitsatz ─────────────────────────── */
.leitsatz{
  font-family:var(--font-anzeige); font-weight:700; font-size:var(--leitsatz-groesse);
  line-height:1.28; letter-spacing:-.012em; color:var(--navy); max-width:28ch;
  border-left:3px solid var(--orange); padding-left:var(--sp-5); margin:var(--sp-7) 0;
}
.leitsatz cite{
  display:block; margin-top:var(--sp-3); font-style:normal;
  font-family:var(--font-text); font-weight:600; font-size:var(--f-small); color:var(--muted);
}
.dunkel .leitsatz{color:#fff}

/* 3.5b · Leitsaetze wort fuer wort (Der Wisch, Fortsetzung 29.09.2026):
   hub.html zerlegt NUR `.stufe1 .leitsatz p` in `<span class="wort">` - und
   nur unter derselben "js-wisch"-Bedingung wie das ganze Kapitel-Wischen
   oben (3.2c). Ohne JS/bei reduzierter Bewegung bleibt der Satz ein
   normaler, unzerlegter Textknoten - sofort vollstaendig sichtbar. `--i`
   (je Wort von hub.html gesetzt) staffelt die Verzoegerung, nur
   opacity/transform animieren. */
.js-wisch .stufe1 .leitsatz .wort{
  display:inline-block; opacity:0; transform:translateY(8px);
  transition:opacity .4s ease, transform .4s ease;
  transition-delay:calc(var(--i,0) * 45ms);
}
.js-wisch .stufe1 .leitsatz.leitsatz-sichtbar .wort{opacity:1; transform:translateY(0)}

/* ─────────── 3.5c · Dieselben zwei Effekte, DEZENT, für Stufe 2 (Umbau 30.09.2026) ───────────
   Florian, wörtlich: "ist gut aber zu trocken, du musst dir denken die
   kommen von geil auf hm" - Stufe 2 soll die Energie von Stufe 1 halten,
   nur ruhiger. Eigene Klasse "js-stufe2" (hub.html setzt sie NUR wenn
   body.stufe2 vorhanden ist), komplett getrennt von "js-wisch"/".stufe1" -
   Stufe 1 bleibt dadurch in JEDEM Fall unveraendert, auch wenn hier ein
   Fehler stecken sollte. `:not(.pitch-inhalt *)` nimmt das eingeklappte
   Stufe-1-Pitch-Zitat aus - das traegt ohnehin schon die Klasse ".stufe1"
   und bekommt seine Effekte bereits über die Regeln oben (3.2c/3.5b).
   Kleinere Werte als Stufe 1 (12px Weg statt 14px, 6px statt 8px,
   0,45s statt 0,6s) - "spürbar, aber dezent" laut Auftrag. Ohne JS/bei
   reduzierter Bewegung ist jedes Kapitel/jeder Leitsatz sofort vollständig
   sichtbar, exakt wie in Stufe 1. */
.js-stufe2 .stufe2 .kapitel:not(.pitch-inhalt *){
  opacity:0; transform:translateY(12px);
  transition:opacity .45s ease, transform .45s ease;
}
.js-stufe2 .stufe2 .kapitel.stufe2-sichtbar:not(.pitch-inhalt *){opacity:1; transform:translateY(0)}
.js-stufe2 .stufe2 .leitsatz:not(.pitch-inhalt *) .wort{
  display:inline-block; opacity:0; transform:translateY(6px);
  transition:opacity .35s ease, transform .35s ease;
  transition-delay:calc(var(--i,0) * 35ms);
}
.js-stufe2 .stufe2 .leitsatz.leitsatz-sichtbar:not(.pitch-inhalt *) .wort{opacity:1; transform:translateY(0)}
.stufe2 .leitsatz p{hyphens:auto; -webkit-hyphens:auto; overflow-wrap:break-word}
.js-stufe2 .stufe2 .leitsatz:not(.pitch-inhalt *) .wort{max-width:100%}
@media(prefers-reduced-motion:reduce){
  .js-stufe2 .stufe2 .kapitel:not(.pitch-inhalt *){opacity:1 !important; transform:none !important; transition:none !important}
  .js-stufe2 .stufe2 .leitsatz:not(.pitch-inhalt *) .wort{opacity:1 !important; transform:none !important; transition:none !important}
}
@media print{
  .js-stufe2 .stufe2 .kapitel:not(.pitch-inhalt *){opacity:1 !important; transform:none !important}
  .js-stufe2 .stufe2 .leitsatz:not(.pitch-inhalt *) .wort{opacity:1 !important; transform:none !important; transition:none !important}
}

/* ─────────────────────── 3.6 · Kennzahl-Kachel (Stufe 2) ─────────────────────── */
/* 16.09., Korrektur nach Screenshot-Prüfung: die Einheit brach mitten im Wort
   um („00,0 Mi / o €"). Grund: Einheit lag INLINE hinter der Zahl in derselben
   Zeile. Jetzt zwingend zweizeilig — die Einheit ist ein eigener Block unter
   der Zahl, kann also nie mehr innerhalb eines Wortes umbrechen. Zusätzlich
   `minmax` von 180px auf 220px angehoben, damit eine Kachel nie schmaler wird,
   als eine lange Einheit („Betriebe") in einer Zeile braucht. */
.kennzahlen{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:var(--sp-4); margin:var(--sp-6) auto;
  max-width:var(--breite-daten);
}
.kennzahl{
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-5) var(--sp-5); box-shadow:var(--schatten-karte); min-width:0;
}
.kennzahl .zahl{
  display:block; font-family:var(--font-anzeige); font-weight:800; color:var(--tiefgruen);
  font-size:var(--f-zahl); line-height:1; font-variant-numeric:tabular-nums lining-nums;
  white-space:nowrap;
}
.kennzahl .zahl .einheit{
  display:block; white-space:nowrap; font-size:.34em; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; margin-top:8px; color:var(--muted);
}
.kennzahl .label{display:block; margin-top:var(--sp-2); font-size:var(--f-small); font-weight:700; color:var(--ink)}
.kennzahl .kontext{display:block; margin-top:var(--sp-1); font-size:13px; color:var(--muted)}
.kennzahl .delta{
  display:inline-flex; align-items:center; gap:4px; margin-top:var(--sp-2);
  font-size:12.5px; font-weight:700; padding:3px 9px; border-radius:var(--r-btn);
}
.kennzahl .delta.auf{background:var(--hellorange); color:#7A4B00}
.kennzahl .delta.ab{background:#F3D9D6; color:#7A2A20}

/* ─────────────────── 3.7 · Jahrestabelle 2026–2031 ───────────────────
   16.09., Korrektur: die Spalte 2031 wirkte am Laptop abgeschnitten, weil der
   Tisch bis dahin in `.lese-spalte` (~66ch ≈ 700px) eingesperrt war und die
   Scrollbarkeit dort nicht auffiel. Jetzt `max-width:var(--breite-daten)`
   (960px) UND außerhalb von `.lese-spalte` platziert (Markup-Pflicht beim
   Einbau, siehe DESIGN.md) — bei 960px passen alle sieben Spalten ohne
   Scrollen; `.tabelle-scroll` bleibt als Sicherheitsnetz für schmalere
   Bildschirme (`min-width:640px` auf der Tabelle erzwingt dort das Scrollen
   statt eines Zusammenquetschens). */
.tabelle-scroll{
  overflow-x:auto; -webkit-overflow-scrolling:touch; margin:var(--sp-6) auto;
  border:1px solid var(--line); border-radius:var(--r-table); max-width:var(--breite-daten);
}
/* `width:auto` statt `100%`: die Tabelle darf schmaler sein als ihr
   Rahmen (z. B. am großen Monitor) — `min-width:640px` bleibt als FLOOR,
   nicht als Deckel, damit sie am Handy weiterhin überläuft und dort
   `.tabelle-scroll`/`.tabelle-rahmen` zum Scrollen zwingt, statt die
   Spalten zusammenzuquetschen. KEIN `max-width` hier — der würde das
   Überlaufen genau verhindern, das der Scroll-Rahmen braucht. */
table.jahre{width:auto; min-width:640px; border-collapse:collapse; font-variant-numeric:tabular-nums lining-nums}
table.jahre caption{text-align:left; padding:var(--sp-4) var(--sp-5) 0; font-size:var(--f-small); color:var(--muted)}
table.jahre th,table.jahre td{padding:12px 18px; font-size:15px; white-space:nowrap}
table.jahre thead th{
  text-align:right; font-family:var(--font-anzeige); font-weight:700; color:#fff;
  background:var(--tiefgruen); font-size:13.5px;
}
/* Pruefer-Befund 05.10.2026: `table.jahre td:first-child,table.jahre
   th:first-child{background:var(--flaeche)}` (frueher hier als EINE Regel
   fuer Kopf- UND Koerperzellen) hat die eigene Kopfzellen-Regel oben
   (thead th{background:tiefgruen; color:#fff}) ueberdeckt - nicht per
   Reihenfolge (die Kopfzellen-Regel steht ohnehin DAVOR), sondern per
   Spezifitaet: "table.jahre th:first-child" (0,2,2) schlaegt "table.jahre
   thead th" (0,1,3). Ergebnis: weisse Schrift auf weissem Grund in JEDER
   `table.jahre`-Kopfzeile mit beschrifteter erster Spalte (z. B. "Gesell-
   schafter" in :::captable) - unsichtbar, nicht nur unauffaellig. Fix:
   die Hintergrund/Sticky-Regel gilt jetzt nur noch fuer `tbody`-Zellen
   (Koerperzeilen, inkl. `<th scope="row">`), die Kopfzeile bekommt ihre
   eigene sticky-Regel direkt bei den anderen Kopfzellen-Regeln - bleibt
   dadurch tiefgruen/weiss wie jede andere Kopfzelle. Jahrestabellen mit
   LEERER erster Kopfzelle (z. B. die Planrechnungstabelle) sind davon
   nicht betroffen: eine leere Zelle sieht mit tiefgruen/weiss genauso
   leer aus wie vorher mit weiss/weiss. */
table.jahre thead th:first-child{
  text-align:left; border-radius:var(--r-table) 0 0 0; position:sticky; left:0; z-index:1;
}
table.jahre thead th:last-child{border-radius:0 var(--r-table) 0 0}
table.jahre td{text-align:right; border-top:1px solid var(--line); color:var(--ink)}
table.jahre tbody td:first-child,table.jahre tbody th:first-child{
  text-align:left; font-weight:700; position:sticky; left:0; background:var(--flaeche);
}
table.jahre tbody tr:nth-child(even) td{background:var(--flaeche-tief)}
table.jahre tbody tr:nth-child(even) td:first-child{background:var(--flaeche-tief)}
table.jahre tfoot td{border-top:1.5px solid var(--line-stark); font-weight:800; color:var(--tiefgruen)}

/* ─────────────── 3.7b · Tabelle-Rahmen (generischer Scroll-Rahmen) ───────────────
   16.09., Befund aus der Live-Skalierungsmessung: Markdown-Tabellen
   (`table.tabelle`) UND — je nach Einbau — auch `table.jahre` standen ohne
   eigenen Scroll-Rahmen im Fließtext und machten dadurch die GANZE Seite
   horizontal scrollbar, nicht nur die Tabelle. `.tabelle-rahmen` ist die
   generische Antwort darauf: um JEDE Tabelle, deren Spalten in der Breite
   nicht garantiert hineinpassen, wickelt der Entwickler dieses Element.

   Anders als `.tabelle-scroll` (3.7, extra für die Jahrestabelle: eigene
   Bühnenbreite 960px, eigener Rahmen/Radius, sticky erste Spalte) ist
   `.tabelle-rahmen` bewusst UNAUFWÄNDIG und ohne Bühnen-Breite — für ganz
   normale Kommentarsatz-Tabellen mitten im Lesefluss (`.mass-lese`-Breite).
   Beide Klassen dürfen nebeneinander bestehen; für `table.jahre` selbst
   reicht auch `.tabelle-scroll` weiterhin aus (sie hat `overflow-x:auto`
   bereits eingebaut) — `.tabelle-rahmen` ist für alle ANDEREN Tabellen da.

   Rand-Hinweis „weitere Spalten" ist ein durchgehendes, sehr dezentes
   Schlagschatten-Inset am rechten Innenrand (KEIN Farbverlauf, der auf
   die Tabellen-Hintergrundfarbe abgestimmt werden müsste — ein
   `box-shadow:inset` funktioniert unabhängig davon, was hinter ihm liegt).
   Bewusst vereinfacht: er bleibt sichtbar, auch wenn schon ganz nach
   rechts gescrollt ist — ein wirklich scrollstand-genauer Hinweis bräuchte
   JavaScript (`scrollLeft`/`scrollWidth` abfragen), das ist hier bewusst
   nicht gebaut. */
.tabelle-rahmen{
  position:relative; max-width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch;
  margin:var(--sp-5) 0; border-radius:var(--r-sm);
  box-shadow:inset -24px 0 16px -16px rgba(11,31,51,.14);
}
/* Tabellen darin dürfen ihre natürliche (ggf. schmalere) Breite behalten —
   kein erzwungenes `width:100%`, das sie unnötig aufblähen würde. */
.tabelle-rahmen table{width:auto; max-width:none}

/* Kleine, generische Basisoptik für gewöhnliche Markdown-Tabellen
   (`table.tabelle`) — keine eigene Farbwelt wie die Jahrestabelle (3.7),
   nur genug, damit sie nicht wie unformatiertes Browser-Standard-HTML
   mitten im sonst gestalteten Fließtext steht. Wer eine Tabelle braucht,
   die wie die Jahrestabelle aussehen soll, verwendet `table.jahre`. */
.tabelle-rahmen table{border-collapse:collapse; font-size:15px}
.tabelle-rahmen th,.tabelle-rahmen td{padding:10px 16px; text-align:left; border-bottom:1px solid var(--line); white-space:nowrap}
.tabelle-rahmen thead th{font-family:var(--font-anzeige); font-weight:700; color:var(--navy); border-bottom:1.5px solid var(--line-stark)}
.tabelle-rahmen tbody tr:nth-child(even) td{background:var(--flaeche-tief)}

/* ────────────── 3.8 · Drei-Töpfe-Darstellung Mittelverwendung ────────────── */
.toepfe{
  display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-5); margin:var(--sp-6) auto;
  align-items:end; max-width:var(--breite-daten);
}
.topf{text-align:center}
.topf .gefaess{
  --anteil:50%; height:180px; border-radius:20px; border:1.5px solid var(--line);
  background:
    linear-gradient(to top, var(--tiefgruen) var(--anteil), transparent var(--anteil)),
    var(--flaeche-tief);
  position:relative; overflow:hidden; display:flex; align-items:flex-start; justify-content:center;
}
.topf .gefaess .prozent{
  margin-top:var(--sp-3); font-family:var(--font-anzeige); font-weight:800; font-size:22px;
  color:#fff; mix-blend-mode:difference;
}
.topf .titel{display:block; margin-top:var(--sp-3); font-weight:700; font-size:15px}
.topf .beschreibung{display:block; margin-top:2px; font-size:13px; color:var(--muted)}
@media(max-width:520px){ .toepfe{gap:var(--sp-3)} .topf .gefaess{height:140px} }

/* ───────────── 3.9 · Phasen-Leiste (Regionalpartner Phase 1→2→3; auch als Zeitstrahl) ─────────────
   16.09., erweitert für den Zeitstrahl in Stufe 2 (`:::zeitstrahl`, sechs Stationen
   05/2026–2028–2031, gebaut auf genau diesem Bauteil). Drei Entscheidungen dazu:

   1. ZUSTANDSKLASSEN, verbindlich für das Bauskript, das sie aus dem heutigen
      Datum setzt: `.erreicht` (Vergangenheit/abgeschlossen) · `.aktiv` (laufend)
      · `.offen` (Zukunft). Alle drei sind jetzt EXPLIZIT ausprogrammiert — `.offen`
      sah vorher genau wie der unklassifizierte Grundzustand aus (keine eigene
      Regel), das war für ein Skript, das verlässlich eine von drei Klassen
      setzen soll, kein stabiler Vertrag. Jetzt hat jede der drei einen Namen
      UND eine eigene (auch wenn `.offen` bewusst unverändert aussieht) Regel.
   2. DRITTES FELD `.beschreibung` (z. B. „Prototyp, Netzwerkaufbau") ist jetzt
      ein regulärer, OPTIONALER dritter Bestandteil von `.phase` — kein Fork der
      Komponente. Löst das Provisorium `.zeitraum-beschreibung` in `app/hub.html`
      ab; der Entwickler benennt beim Einbau in `.phase > .beschreibung` um.
      Gleicher Klassenname wie bei den Drei-Töpfen (`.topf .beschreibung`,
      Abschnitt 3.8) — bewusst dieselbe Konvention: Klassen sind kontextuell
      unter ihrem Elternbauteil eindeutig, nicht global.
   3. SECHS STATIONEN AUF 390px: die schmalste Schrift bleibt bei 12,5px (nie
      unter 11px, wie vorgegeben). Statt die Schrift weiter zu verkleinern,
      bekommt die Variante `.phasenleiste.zeitstrahl` eine EIGENE, frühere
      Umbruchschwelle (900px statt 480px) — sechs Spalten samt Beschreibung
      brauchen mehr Platz pro Station als drei kurze Phasen-Label. Die
      ursprüngliche Drei-Phasen-Nutzung (Stufe 1, bereits von Florian
      abgenommen: „skaliert sauber") bleibt UNVERÄNDERT bei 480px — die neue
      Schwelle gilt nur mit der Zusatzklasse `.zeitstrahl`, kein Risiko einer
      Regression am bestehenden Bauteil. */
.phasenleiste{display:flex; align-items:flex-start; margin:var(--sp-6) auto; max-width:var(--breite-daten)}
.phase{flex:1; position:relative; text-align:center; padding:0 var(--sp-2)}
.phase:not(:last-child)::after{
  content:""; position:absolute; top:15px; left:50%; width:100%; height:2px;
  background:var(--line); z-index:0;
}
.phase.erreicht:not(:last-child)::after{background:var(--tiefgruen)}
.phase .punkt{
  position:relative; z-index:1; width:32px; height:32px; margin:0 auto var(--sp-2);
  border-radius:50%; background:#fff; border:2px solid var(--line);
  display:grid; place-items:center; font-family:var(--font-anzeige); font-weight:800; font-size:14px;
  color:var(--muted);
}
.phase.erreicht .punkt{background:var(--tiefgruen); border-color:var(--tiefgruen); color:#fff}
.phase.aktiv .punkt{border-color:var(--orange); color:var(--orange); background:#fff}
/* `.offen` sieht bewusst wie der frühere Grundzustand aus (Zukunft = neutral,
   keine Aktions-/Erfolgsfarbe) — jetzt aber als eigene, benannte Regel, kein
   impliziter „hat keine der anderen beiden Klassen"-Zustand mehr. */
.phase.offen .punkt{background:#fff; border-color:var(--line); color:var(--muted)}
.phase .name{display:block; font-weight:700; font-size:14.5px}
.phase .zeitraum{display:block; margin-top:2px; font-size:12.5px; color:var(--muted)}
.phase .beschreibung{
  display:block; margin-top:4px; font-size:12.5px; line-height:1.4; color:var(--muted);
  max-width:42ch; margin-inline:auto;
}
/* Unter 480px wird aus der Zeile eine Spalte — sonst quetschen sich drei
   Phasenlabels auf ~360px Breite unlesbar zusammen. Gilt für die einfache
   Phasen-Leiste (Stufe 1, unverändert). */
@media(max-width:480px){
  .phasenleiste{flex-direction:column; gap:var(--sp-5)}
  .phase{text-align:left; padding-left:44px}
  .phase .punkt{position:absolute; left:0; top:0; margin:0}
  .phase:not(:last-child)::after{
    top:32px; left:15px; width:2px; height:calc(100% + var(--sp-5) - 32px);
  }
  .phase .beschreibung{margin-inline:0}
}

/* ── Variante `.zeitstrahl`: mehr Stationen + Beschreibung (Stufe 2) ──
   Mobile-first gestapelt (wie oben, aber ab 390px aktiv, nicht erst ab
   480px) — erst ab 900px wird daraus eine Reihe. Dieselben Zustands- und
   Feld-Klassen (`.erreicht`/`.aktiv`/`.offen`, `.name`/`.zeitraum`/
   `.beschreibung`), nur der Container trägt zusätzlich `.zeitstrahl`. */
.phasenleiste.zeitstrahl{
  flex-direction:column; gap:var(--sp-5); max-width:var(--breite-lesen);
}
/* 16.09., Korrektur nach Live-Messung bei 1024px: die Reihe (ab 900px, siehe
   Media Query unten) lief bei 1024px 18px aus dem Bild — die Seite wurde
   dadurch horizontal scrollbar. Ursache war NICHT die Umbruchschwelle
   selbst, sondern derselbe Flex-Grundfehler wie schon bei `.branchenkarte`
   (Abschnitt 3.11, dort korrigiert): ein Flex-Kind darf laut Spec nie unter
   seine eigene Inhalts-Mindestbreite schrumpfen. Bei sechs `flex:1`-Stationen
   und einem einzelnen langen Wort in Name/Zeitraum/Beschreibung reichte der
   gleichmäßig verteilte Platz je Station bei 1024px nicht aus — die eine
   Station mit dem längsten Wort blieb breiter als ihr Anteil, alle sechs
   zusammen sprengten die 960px-Bühne. `min-width:0` hebt die Sperre auf,
   `overflow-wrap:anywhere` + `hyphens:auto` lassen das Wort im Notfall
   brechen/trennen statt die Station aufzublasen — bewusst NUR unter
   `.zeitstrahl` (nicht am `.phase`-Grundbauteil), damit die bereits
   abgenommene Drei-Phasen-Leiste in Stufe 1 unverändert bleibt. Geprüft
   gegen 900/1024/1100/1200/1440px: bei keiner Breite mehr Scrollbreite über
   der Fensterbreite. */
.phasenleiste.zeitstrahl .phase{min-width:0}
.phasenleiste.zeitstrahl .phase .name,
.phasenleiste.zeitstrahl .phase .zeitraum,
.phasenleiste.zeitstrahl .phase .beschreibung{overflow-wrap:anywhere; hyphens:auto}
.phasenleiste.zeitstrahl .phase{text-align:left; padding-left:44px}
.phasenleiste.zeitstrahl .phase .punkt{position:absolute; left:0; top:0; margin:0}
.phasenleiste.zeitstrahl .phase:not(:last-child)::after{
  top:32px; left:15px; width:2px; height:calc(100% + var(--sp-5) - 32px);
}
.phasenleiste.zeitstrahl .phase .beschreibung{margin-inline:0}
@media(min-width:900px){
  .phasenleiste.zeitstrahl{flex-direction:row; gap:0; max-width:var(--breite-daten)}
  .phasenleiste.zeitstrahl .phase{text-align:center; padding:0 var(--sp-2)}
  .phasenleiste.zeitstrahl .phase .punkt{position:relative; left:auto; top:auto; margin:0 auto var(--sp-2)}
  .phasenleiste.zeitstrahl .phase:not(:last-child)::after{top:15px; left:50%; width:100%; height:2px}
  .phasenleiste.zeitstrahl .phase .beschreibung{margin-inline:auto}
}

/* ─────────────── 3.10 · Netzwerkeffekt-Kreislauf (reines CSS/SVG) ─────────────── */
.kreislauf{margin:var(--sp-6) 0; display:flex; flex-direction:column; align-items:center; gap:var(--sp-4)}
.kreislauf svg{width:100%; max-width:360px; height:auto}
.kreislauf .kn-flaeche{fill:#fff; stroke:var(--tiefgruen); stroke-width:1.5}
.kreislauf .kn-text{font-family:var(--font-text); font-size:12.5px; fill:var(--ink); text-anchor:middle}
.kreislauf .pfeil{fill:none; stroke:var(--orange); stroke-width:2; stroke-linecap:round}
.kreislauf figcaption{font-size:var(--f-small); color:var(--muted); max-width:44ch; text-align:center}

/* ─────────────── 3.10b · Netzkarte — wachsende DACH-Karte (Kap. 08) ───────────────
   Florian, 29.09.2026, wörtlich: „eine wachsende Karte. Betriebe tauchen als
   Punkte auf einer DACH-Karte ... auf und verbinden sich zu einem Netz. Das
   zeigt, dass jeder Neue das Netz stärker macht." EIGENER Renderer
   (bauen.py render_netzkarte) — NICHT über :::netzwerk/.kreislauf oben, das
   Stufe 2 evtl. weiter nutzt. Länderumrisse: selbst gezeichnete, vereinfachte
   Polygone (kein Kartenserver, keine externe Datei — reines Inline-SVG).
   Punkte/Kanten sind FEST im Code (siehe bauen.py, _NETZKARTE_*), rein
   geometrisch verbunden — kein Zufall, keine erfundene Zahl/Stadt.

   Groß und mittig (Florians Vorgabe): eigene, großzügige Bühnenbreite
   innerhalb `--breite-daten`, deutlich größer als der kleine Kreislauf
   oben (der bewusst als ruhiges Diagramm gedacht war, das hier ist der
   Blickfang). */
.netzkarte{
  margin:var(--sp-7) auto; max-width:var(--breite-daten);
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-4);
}
.netzkarte svg{width:100%; max-width:820px; height:auto}
/* Fill kommt aus dem SVG selbst (`fill="url(#nk-verlauf)"`, bauen.py) - hier
   NUR Kontur, damit die CSS-Kaskade (Praesentationsattribute liegen unter
   jeder Stylesheet-Regel) den Verlauf nicht überschreibt. Der leichte
   Schatten auf der Gruppe darunter gibt zusätzlich Tiefe. */
.netzkarte .nk-laender{filter:drop-shadow(0 8px 18px rgba(11,31,51,.16))}
.netzkarte .nk-land{stroke:var(--line-stark); stroke-width:1.2}
.netzkarte .nk-linie{
  stroke:var(--frischgruen); stroke-width:1.5; stroke-linecap:round; stroke-opacity:.85;
}
.netzkarte .nk-punkt{
  fill:var(--tiefgruen); stroke:#fff; stroke-width:1;
  transform-box:fill-box; transform-origin:center;
}
.netzkarte .nk-punkt-puls{fill:var(--orange)}

/* Drei "Start"-Orte (Linz/Landshut/Kempten, Florian 29.09.2026, sechster
   Auftrag: "Das Netzwerk geht von Linz, Landshut und Kempten aus.") -
   groesser, orange, mit weissem Beschriftungs-Etikett (Textschrift,
   `filter:drop-shadow` statt eines SVG-`<filter>` - guenstiger, dieselbe
   Technik wie bei `.nk-laender` oben). Gilt fuer BEIDE Darstellungen: die
   statische SVG (bauen.py `_netzkarte_start_marken_svg`) UND das Canvas
   (hub.html zeichnet dieselben drei Koordinaten/Namen eigenstaendig,
   siehe dort) - hier nur die SVG-Fassung. */
.netzkarte .nk-start-punkt{fill:var(--orange); stroke:#fff; stroke-width:1.5}
.netzkarte .nk-start-schild{fill:#fff; filter:drop-shadow(0 2px 3px rgba(11,31,51,.28))}
.netzkarte .nk-start-label{
  font-family:var(--font-text); font-weight:700; font-size:11px; fill:var(--navy);
  text-anchor:middle; dominant-baseline:middle;
}
.netzkarte figcaption{
  margin:0; font-size:var(--f-small); color:var(--muted); max-width:52ch; text-align:center;
}
.netzkarte .nk-legende{
  display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-1) var(--sp-2);
  margin:0; padding:0; list-style:none; max-width:60ch;
  font-family:var(--font-mono); font-size:12.5px; letter-spacing:.04em; color:var(--muted-stark);
}
.netzkarte .nk-legende li{white-space:nowrap}
.netzkarte .nk-legende li:not(:last-child)::after{content:"→"; margin-left:var(--sp-2); color:var(--muted)}

/* Ein paar Punkte pulsieren (Florian, wörtlich: „Ein paar Punkte
   pulsieren") — reines CSS, unabhängig vom Scroll-Reveal unten, respektiert
   reduzierte Bewegung wie der Kreislauf-Wanderpunkt oben (3.10). */
@keyframes netzkarte-puls{
  0%,100%{opacity:1; transform:scale(1)}
  50%{opacity:.55; transform:scale(1.35)}
}
.netzkarte .nk-punkt-puls{animation:netzkarte-puls 2.4s ease-in-out infinite}
@media(prefers-reduced-motion:reduce){ .netzkarte .nk-punkt-puls{animation:none} }

/* Beim Hereinscrollen wachsendes Netz — hub.html setzt (eigenständig von der
   "Wisch"-Logik) die Klasse "netzkarte-js" auf das `.netzkarte`-Element
   SELBST, nicht auf <html>: die Karte bleibt dadurch unabhängig davon
   wiederverwendbar, auf welcher Stufe/Seite sie steht. WICHTIG — ohne diese
   Klasse (kein JS, kein IntersectionObserver, oder prefers-reduced-motion)
   gilt AUSSCHLIESSLICH die Basisregel oben: volle Deckkraft, fertig
   verbundene Linien. Hier wird nur ein vorheriges, unsichtbares
   Zwischenstadium ERGÄNZT — nie der Normalzustand versteckt, „ohne JS
   ebenfalls das fertige Netz sichtbar" bleibt dadurch strukturell wahr,
   nicht nur zufällig. */
.netzkarte.netzkarte-js .nk-punkt{
  opacity:0; transform:scale(.35);
  transition:opacity .45s ease, transform .45s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--i,0) * 65ms);
}
.netzkarte.netzkarte-js.netzkarte-sichtbar .nk-punkt{opacity:1; transform:scale(1)}
.netzkarte.netzkarte-js .nk-linie{
  stroke-dasharray:var(--len,1); stroke-dashoffset:var(--len,1);
  transition:stroke-dashoffset .55s ease;
  transition-delay:calc(var(--i,0) * 65ms + 200ms);
}
.netzkarte.netzkarte-js.netzkarte-sichtbar .nk-linie{stroke-dashoffset:0}
@media(prefers-reduced-motion:reduce){
  /* Zusätzliche, eigenständige Absicherung (die JS-Bedingung in hub.html
     prüft dasselbe bereits VOR dem Setzen der Klasse — diese Regel greift
     nur, falls die Klasse trotzdem irgendwie gesetzt würde): sofort das
     fertige Netz, keine Übergänge. */
  .netzkarte.netzkarte-js .nk-punkt,.netzkarte.netzkarte-js .nk-linie{transition:none}
  .netzkarte.netzkarte-js .nk-punkt{opacity:1; transform:scale(1)}
  .netzkarte.netzkarte-js .nk-linie{stroke-dashoffset:0}
}

/* ─────────────── 3.10c · Netzkarte, vollbreit (Kap. 08, fünfter Auftrag 29.09.2026) ───────────────
   Florian, wörtlich zuletzt: "es soll nur veranschaulichen, dass der
   Netzwerkeffekt vollumfänglich gezeigt wird" - GANZ OHNE ZAHLEN. Akt 1
   "Das Netz wächst" ist jetzt eine VOLLBREITE, gepinnte Bühne (bricht
   bewusst aus `--breite-daten`/`.seite` aus, siehe `.netzkarte-szene`
   unten) - hub.html erzeugt darin ein Canvas mit einer viel größeren,
   deterministisch gestreuten Punktwolke (bauen.py liefert die
   Länderumrisse + 16 Städte-Zentren dafür als JSON mit, `#nk-daten`).
   NUR EIN Satz + ein kleiner Akt-Indikator liegen als Overlay darauf -
   keine Zähler, keine Zahl mehr irgendwo im Bild.

   `.netzkarte-szene` ist die (hohe) Scroll-Strecke, `.netzkarte-sticky`
   bleibt während dieser Strecke am Bildschirm hängen (reines CSS
   `position:sticky`, kein JS nötig für das Anheften selbst). Vollbreite
   über die klassische "Breakout"-Technik (negative Margins aus
   `calc(50% - 50vw)` statt `width:100vw` direkt - letzteres überstünde
   auf Desktop-Browsern mit sichtbarer Scrollleiste den echten
   Dokumentrand um deren Breite; `html{overflow-x:hidden}` (Abschnitt 1)
   fängt einen letzten Rest zusätzlich ab). Die Formel wirkt unabhängig
   von `.seite`s eigenem `padding:0 24px`, siehe Herleitung im Bau-Bericht.

   Akt 2 "Der Wert steigt" ist jetzt ein SEPARATER, normal fließender
   Block NACH der Szene (nicht mehr Teil derselben Sticky-Bühne - vorher
   teilte er sich die Bühne mit den jetzt entfallenen Zählern; ohne die
   ist das unnötig). Reveal beim Hereinscrollen wie jeder andere
   Datenbaustein hier.

   Canvas-Sichtbarkeit: hub.html setzt "netzkarte-canvas-js" auf
   `.netzkarte` NUR bei echter Canvas-Unterstützung + `!reduzierte
   Bewegung` - blendet dann die SVG-Punkte/-Kanten aus (das Canvas
   übernimmt), die Länder-Silhouette bleibt in JEDEM Zustand sichtbar
   (gemeinsamer Hintergrund). OHNE diese Klasse (kein JS/reduzierte
   Bewegung/kein Canvas) bleibt die VORHERIGE, vollständige 40-Punkte-
   SVG-Karte stehen - strukturell wahr, nicht nur zufällig. */
.netzkarte-szene{
  position:relative; margin:var(--sp-8) 0;
  width:auto; max-width:none;
  margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw);
}
.netzkarte-sticky{position:sticky; top:0; height:min(90vh,860px); min-height:520px}
.netzkarte-sticky .netzkarte{
  position:relative; width:100%; height:100%; margin:0; max-width:none;
  overflow:hidden; border-radius:0;
  display:block;
}
.netzkarte-sticky .netzkarte svg{position:absolute; inset:0; width:100%; height:100%; max-width:none}
.nk-canvas{position:absolute; inset:0; width:100%; height:100%; pointer-events:none}
@media(min-width:701px){ .netzkarte-szene{height:240vh} }
@media(max-width:700px){
  .netzkarte-szene{height:auto}
  .netzkarte-sticky{position:static; height:min(78vh,620px); min-height:420px}
}

/* Overlay: EIN großer Satz + kleiner Akt-Indikator - sonst NICHTS (keine
   Zahl). Komplettabnahme-Korrektur (Florian): der Satz saß zu groß/mittig
   und deckte sich inhaltlich mit der figcaption ("Jeder neue Betrieb macht
   das Netz stärker") - jetzt eine ruhige Karte unten links auf
   halbtransparentem Hintergrund (statt Textschatten), die das Netz nicht
   verdeckt; figcaption + Stationen-Legende sind NUR in der Canvas-Fassung
   ausgeblendet (weiter unten `.netzkarte-canvas-js`) - ohne JS/Canvas
   (die vorherige SVG-Karte) bleiben sie stehen, da ist der Leitsatz-Satz
   gar nicht redundant zu sehen (kein Overlay ohne JS/Canvas). */
.netzkarte-overlay{
  position:absolute; inset:0; z-index:3;
  display:flex; flex-direction:column; justify-content:space-between;
  padding:var(--sp-6) var(--sp-6);
}
.nk-akt-indikator{margin:0; align-self:flex-end}
.nk-akt-punkt{
  display:inline-flex; font-size:12.5px; font-family:var(--font-mono); font-weight:700;
  letter-spacing:.04em; color:var(--navy); background:rgba(255,255,255,.82);
  padding:5px 12px; border-radius:var(--r-btn); box-shadow:var(--schatten-karte);
}
/* Bündelt Leitsatz + Bildunterschrift + optionale Stationen-Legende unten
   LINKS im Overlay (bewusst NICHT figcaption lose im normalen Fluss von
   `<figure>` - dort würde es mit der absolut positionierten Punktwolke/
   dem Rest des Overlays überlappen). */
.netzkarte-overlay-unten{
  display:flex; flex-direction:column; gap:var(--sp-2); align-self:flex-start; max-width:60ch;
}
.netzkarte-leitsatz{
  margin:0; max-width:26ch; font-family:var(--font-anzeige); font-weight:800;
  font-size:clamp(18px,2.3vw,27px); line-height:1.3; color:var(--navy);
  background:rgba(255,255,255,.88); padding:14px 18px; border-radius:var(--r-card);
  box-shadow:var(--schatten-karte); display:inline-block; width:fit-content;
}
.netzkarte.netzkarte-canvas-js .netzkarte-overlay-unten figcaption,
.netzkarte.netzkarte-canvas-js .netzkarte-overlay-unten .nk-legende{display:none}
.netzkarte-overlay-unten figcaption{
  margin:0; font-size:var(--f-small); color:var(--muted); text-align:left; max-width:56ch;
}
.netzkarte-overlay-unten .nk-legende{margin:0; justify-content:flex-start}
@media(max-width:700px){
  .netzkarte-overlay{padding:var(--sp-4)}
  .netzkarte-leitsatz{font-size:clamp(17px,5vw,21px); max-width:20ch; padding:12px 14px}
}

/* SVG-Punkte/-Kanten: Basiszustand (3.10b oben) bleibt IMMER voll sichtbar -
   erst "netzkarte-canvas-js" blendet sie zugunsten des Canvas aus. Die
   Länder-Silhouette (`.nk-laender`) ist davon nie betroffen. */
.netzkarte.netzkarte-canvas-js .nk-kanten,
.netzkarte.netzkarte-canvas-js .nk-punkte{display:none}

/* ─────────────── 3.10d · Kurve "Der Wert steigt" (Akt 2, :::netzkarte) ───────────────
   OHNE JEDE ZAHL (Florian, dritter Korrekturdurchgang): die quadratische
   Linie ("Verbindungen") in Frischgrün und dick, die lineare Linie
   ("Betriebe") gedämpft/dünner daneben - der Formunterschied (flach vs.
   steil) ist die ganze Aussage, jede Linie trägt ihr WORT statt einer
   Zahl (bauen.py `_netzkarte_kurve_svg`). Reveal beim Hereinscrollen -
   EIGENSTÄNDIGER Beobachter (hub.html), setzt "nk-akt-sichtbar" auf den
   Block; Einzeichnen über dieselbe stroke-dasharray/-dashoffset-Technik
   wie die Kartenkanten (`--laenge` kommt je Pfad aus bauen.py). OHNE
   diese Klasse (kein JS/reduzierte Bewegung) ist die Kurve sofort
   vollständig gezeichnet sichtbar - kein versteckter Vorher-Zustand. */
.nk-akt-block.nk-akt-2{
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.nk-akt-block .nk-akt-indikator{margin-bottom:var(--sp-4)}
.nk-akt-block .nk-akt-punkt{
  background:var(--flaeche); border:1px solid var(--line); box-shadow:none; color:var(--muted-stark);
}
/* Komplettabnahme-Korrektur: die Kurve füllte am Laptop mehr als einen
   Bildschirm - `max-height:60vh` + `object-fit:contain` deckeln die
   sichtbare Höhe (moderne Browser behandeln `<svg>` mit fester
   `viewBox` als ersetztes Element, `object-fit` greift dort genauso wie
   bei `<img>`), die Breite bleibt `--breite-daten` (Block oben).
   Beschriftung jetzt in der Textschrift statt Mono ("wirkt technisch"). */
.nk-kurve{width:100%}
.nk-kurve-svg{width:100%; height:auto; max-height:60vh; object-fit:contain; display:block}
.nk-kurve-achse{stroke:var(--line-stark); stroke-width:1.5}
.nk-kurve-linie{fill:none; stroke-linecap:round; stroke-linejoin:round}
.nk-kurve-betriebe{stroke:var(--muted-stark); stroke-width:2.5}
.nk-kurve-verbindungen{stroke:var(--frischgruen); stroke-width:4.5}
.nk-kurve-punkt{stroke:#fff; stroke-width:1.5}
.nk-kurve-punkt-betriebe{fill:var(--muted-stark)}
.nk-kurve-punkt-verbindungen{fill:var(--frischgruen)}
.nk-kurve-wortlabel{font-family:var(--font-text); font-weight:700; letter-spacing:.01em}
.nk-kurve-wortlabel.klein{font-size:11px; fill:var(--muted-stark)}
.nk-kurve-wortlabel.gross{font-size:13px; fill:var(--tiefgruen)}
.nk-kurve-legende{display:flex; flex-wrap:wrap; gap:var(--sp-3); margin:var(--sp-2) 0 0; font-size:12.5px; color:var(--muted)}
.nk-kurve-legende .chip{display:inline-flex; align-items:center; gap:6px}
.nk-kurve-legende .chip::before{content:""; width:14px; height:3px; border-radius:2px; display:inline-block}
.nk-kurve-legende .chip.betriebe::before{background:var(--muted-stark)}
.nk-kurve-legende .chip.verbindungen::before{background:var(--frischgruen)}
.netzkarte-hinweis{margin:var(--sp-2) 0 0; font-size:12.5px; color:var(--muted); font-style:italic}
.nk-akt-block.nk-akt-2.nk-akt-sichtbar-js .nk-kurve-linie{
  stroke-dasharray:var(--laenge,1); stroke-dashoffset:var(--laenge,1);
  transition:stroke-dashoffset .9s ease;
}
.nk-akt-block.nk-akt-2.nk-akt-sichtbar-js.nk-akt-sichtbar .nk-kurve-linie{stroke-dashoffset:0}
@media(prefers-reduced-motion:reduce){
  .nk-akt-block.nk-akt-2.nk-akt-sichtbar-js .nk-kurve-linie{stroke-dashoffset:0; transition:none}
}

/* ─────────────── 3.11 · Branchen-Karten (Reinigung → weitere Felder) ─────────────── */
/* 16.09., zwei Korrekturen nach Prüfung bei 1440px:
   1) TREPPENSTUFEN: `align-items:center` ließ Karten unterschiedlicher
      Texthöhe an ihrer MITTE ausrichten statt an der Oberkante — dadurch
      standen die Oberkanten einer Reihe versetzt (Kap. 03/05/06, überall
      dieselbe Klasse). Jetzt `stretch`: alle Karten einer Zeile gleich hoch,
      bündig oben. `.pfeil-weiter` behält sein eigenes `align-self:center`,
      bleibt also als schmales Glyphen-Element vertikal mittig neben den nun
      gestreckten Karten.
   2) FÜNF KARTEN IN KAP. 06: bei 960px Bühnenbreite brach die fünfte Karte
      um, der letzte Pfeil hing am Zeilenende. Ursache war NICHT zu wenig
      Platz im Mittel, sondern der Flex-Default: ein Flex-Kind darf laut
      Spec nie unter seine eigene Inhalts-Mindestbreite schrumpfen, und ein
      einzelnes unteilbares Wort wie „Sicherheitsdienste" ist bei 16,5px
      selbst breiter als 150px. `min-width:0` hebt diese Sperre auf,
      `hyphens:auto` + `overflow-wrap:anywhere` erlauben dem Wort im
      Notfall einen Umbruch/Trennstrich statt die Karte aufzublasen. Damit
      passen jetzt alle fünf Karten + vier Pfeile in eine Reihe (kleinere
      Karten statt 3+2-Umbruch) — geprüft für alle drei Kapitel mit dieser
      Klasse, nicht nur für Kap. 06. */
.branchenexpansion{
  display:flex; align-items:stretch; gap:var(--sp-2); flex-wrap:wrap;
  margin-top:var(--sp-6); margin-bottom:var(--sp-6); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.branchenkarte{
  flex:1 1 150px; background:var(--flaeche); border:1.5px solid var(--line);
  border-radius:var(--r-card); padding:var(--sp-4) var(--sp-4); min-width:0;
  hyphens:auto; overflow-wrap:anywhere;
  display:flex; flex-direction:column;
}
/* Florian, 29.09.2026 (Komplettabnahme): karten-3/karten-6 sollen die
   automatische Trennung/Umbruch-Notbremse aus obigem Kommentar NIE
   bekommen - auch nicht unter 760px (das griff vorher nur ab 760px, siehe
   die aelteren, breiten-gebundenen Regeln weiter unten). UNBEDINGT, damit
   es auf jeder Breite gilt, nicht nur ab Laptop. */
.branchenexpansion.karten-3 .branchenkarte,
.branchenexpansion.karten-6 .branchenkarte{hyphens:manual; overflow-wrap:normal}
.branchenkarte.heute{border-color:var(--tiefgruen); background:var(--flaeche)}
.branchenkarte .status{
  display:inline-block; font-family:var(--font-mono); font-size:12.5px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; padding:3px 9px; border-radius:var(--r-btn);
  margin-bottom:var(--sp-2); align-self:flex-start;
}
.branchenkarte.heute .status{background:var(--frischgruen); color:var(--navy)}
.branchenkarte.morgen .status{background:var(--hellorange); color:var(--muted)}
.branchenkarte h3{font-size:16.5px; margin-bottom:2px}
.branchenkarte p{font-size:13.5px; color:var(--muted)}
.pfeil-weiter{flex:0 0 18px; text-align:center; color:var(--muted); font-size:20px; align-self:center}
.pfeil-weiter::before{content:"→"}

/* 16.09., zweite Korrektur (nur die Reihe mit fünf Karten, Kap. 06 „Die
   nächsten Branchen"): bei gleichmäßig kleinen Karten brachen Titel wie
   „Sicherheitsdienste" jetzt zwar nicht mehr über den Kartenrand, aber
   MITTEN IM WORT ab — genau das automatische Verhalten aus der Korrektur
   oben, das hier eigentlich nur ein Sicherheitsnetz sein sollte, ist auf
   dieser schmalen Kartenbreite ständig gezogen worden. Florians Vorgabe:
   3+2-Raster, breitere Karten, keine automatische Trennung.

   Die Partnerfeld-Reihe (Kap. 03, 4 Karten) und die Baustein-Reihe
   (Kap. 05, 3 Karten) bleiben UNVERÄNDERT — sie benutzen dieselben Basis-
   klassen oben, aber keine davon trägt `.branchenkarte.heute` (die gibt es
   nur in Kap. 06). Deshalb ist alles Folgende über
   `.branchenexpansion:has(.branchenkarte.heute)` auf genau diese eine Reihe
   begrenzt, nicht generell auf `.branchenexpansion`/`.branchenkarte`.

   TECHNIK für das 3+2: reiner CSS/Flexbox-Trick, kein Markup-Eingriff.
     · Die drei Karten bekommen eine feste, größere Breite (rund ein Drittel
       der Bühne minus Pfeile/Lücken) statt frei zu wachsen/schrumpfen.
     · Der DRITTE Pfeil (zwischen Karte 3 und Karte 4 — im Markup immer an
       genau dieser Stelle, siehe Kommentar unten) wird zum unsichtbaren
       Zeilenumbruch: `flex-basis:100%` zwingt ihn auf eine eigene, aber
       0px hohe Zeile — alles danach (Karte 4, Pfeil 4, Karte 5) rutscht in
       die zweite Zeile. Der Pfeil selbst wird dabei entfernt (kein Inhalt,
       keine Höhe), NICHT nur versteckt — er stünde sonst als Geisterlinie
       zwischen den Zeilen.
     · `justify-content:center` zentriert JEDE Flex-Zeile für sich – Zeile 2
       (2 Karten + 1 Pfeil) bekommt dadurch automatisch den „2+3 zentriert"-
       Look, ohne dass die beiden Karten breiter werden als die drei in
       Zeile 1.
     · `hyphens:manual` + `overflow-wrap:normal` heben das Sicherheitsnetz
       von oben für DIESE Karten wieder auf — bei der neuen Breite nicht
       mehr nötig, und genau das war der Auslöser für die Wort-Trennung.
   16.09. abends, Breitenprüfung über Florians volle Liste (360·390·430·
   768·1024·1280·1440·1920·2560, siehe DESIGN.md): die Schwelle ist dafür
   von 900px auf 760px gesenkt, DAMIT AUCH 768px (Tablet hoch) das 3+2-
   Raster bekommt, nicht nur Laptop/Monitor. Die Kartenbreite ist eine
   Prozentformel (`calc(100% - …)`), keine feste Zahl — sie wächst mit dem
   Bildschirm mit (bei 2560px deckelt `max-width:340px` sie trotzdem, damit
   Karten nie „riesig" wirken; bei 1280–1920 dazwischen fließend). Karten-
   Innenpolster hier auf 12px (statt der allgemeinen 16px) gesenkt, NUR in
   diesem Ausschnitt — das schafft bei 768px zusätzliche ~8px Wortbreite
   Reserve. `min-width:0` statt einer festen Zahl, sonst würde ein starrer
   Mindestwert exakt bei 760px wieder mit der Prozentformel kollidieren.
   Gerechnet, nicht mit Screenshot gemessen (siehe DESIGN.md „Breiten-
   prüfung"): bei 768px bleiben rechnerisch rund 13–20px Luft für das
   längste Wort „Sicherheitsdienste"; das ist eine Schätzung anhand
   Zeichenbreite, kein Bildschirmtest.
   OFFENE LÜCKE, unverändert benannt: 701–759px (schmales Desktop-Fenster,
   NICHT in Florians Liste) fällt weiter auf das allgemeine, engere Fünf-
   Karten-Layout mit Sicherheitsnetz (`hyphens:auto`/`overflow-wrap:
   anywhere`) zurück — nie kaputt, nur nicht im 3+2-Look.
   ⚠️ Nutzt `:has()` (Chrome/Edge/Safari aktuell, Firefox ab 121) — ohne
   Unterstützung greift ebenfalls das allgemeine Layout, nicht kaputt,
   nur enger. */
@media(min-width:760px){
  .branchenexpansion:has(.branchenkarte.heute){
    justify-content:center;
  }
  .branchenexpansion:has(.branchenkarte.heute) .branchenkarte{
    flex:0 1 calc((100% - 2*18px - 4*var(--sp-2)) / 3);
    max-width:340px; min-width:0;
    padding:var(--sp-4) 12px;
    hyphens:manual; overflow-wrap:normal;
  }
  /* Der dritte Pfeil im Markup steht immer zwischen Karte 3 und Karte 4
     (Reihenfolge: Karte,Pfeil,Karte,Pfeil,Karte,PFEIL,Karte,Pfeil,Karte —
     `:nth-of-type(3)` zählt nur unter den <span class="pfeil-weiter">-
     Geschwistern, trifft also exakt diesen einen). */
  .branchenexpansion:has(.branchenkarte.heute) .pfeil-weiter:nth-of-type(3){
    flex:0 0 100%; height:0; margin:0; padding:0; border:0; overflow:hidden;
  }
  .branchenexpansion:has(.branchenkarte.heute) .pfeil-weiter:nth-of-type(3)::before{
    content:"";
  }
}

@media(max-width:700px){
  .branchenexpansion{flex-direction:column; align-items:stretch}
  .branchenkarte{flex:1 1 auto}
  .pfeil-weiter{align-self:center; transform:rotate(0)}
  .pfeil-weiter::before{content:"↓"}
}

/* ─────────────────── 3.11b · Team-Karte mit Foto (.team-karte, 05.10.2026) ───────────────────
   Variante von `.branchenkarte` (3.11) fuer das Gruenderteam/Beirat: "Wer
   wir sind" (Stufe 1 Kap. 09) und "Das Team" (Stufe 3) - render_kartenreihe()
   in bauen.py (Direktiven :::kompetenzen/:::partnerfelder) setzt die
   Zusatzklasse automatisch, sobald eine Zeile ein `bild: ...`-Feld traegt
   (siehe dortigen Kommentarkopf); Karten ohne Bild (Regionalpartner)
   bleiben unveraendert `.branchenkarte` ohne jede Aenderung hier.

   Das Foto (`.team-karte-bild`, Quelle IMMER 480×600px/4:5 aus
   medien/team/, siehe team_bild_data_uri()) steht im Markup als <img> VOR
   Status/Titel/Text, innerhalb derselben gepolsterten Karte wie die
   uebrigen Branchenkarten. Statt eines zweiten, eigenen Rahmens wird es
   per Minus-Aussenabstand exakt um das Kartenpolster (`--sp-4`) bis an den
   Kartenrand gezogen und bekommt oben dieselbe Rundung wie die Karte
   selbst (`--r-card`), unten eckig (Uebergang zu Status/Titel/Text) -
   wirkt dadurch "eingebaut" statt freischwebend, ohne dass das Markup ein
   zusaetzliches Rahmen-Element braucht. `aspect-ratio` haelt das
   Seitenverhaeltnis exakt wie die Quelle (keine Verzerrung bei
   wachsender/schrumpfender Kartenbreite), `object-fit:cover` faengt knapp
   abweichende Zuschnitte ab. Die Karte selbst waechst/schrumpft/umbricht
   wie jede andere `.branchenkarte` (3.11 oben) - am Laptop nebeneinander,
   ab 700px untereinander (Regel direkt darueber) - hier also KEINE
   eigene Breiten-/Umbruchregel noetig. */
.team-karte-bild{
  display:block; width:calc(100% + 2*var(--sp-4)); max-width:none;
  margin:calc(-1*var(--sp-4)) calc(-1*var(--sp-4)) var(--sp-3);
  aspect-ratio:4/5; object-fit:cover; border-radius:var(--r-card) var(--r-card) 0 0;
}
@media print{
  .team-karte-bild{border-bottom:1px solid #000 !important}
}

/* ─────────────────── 3.12 · Randziffer (nur Stufe 2, Kommentarsatz) ───────────────────
   Florian, 15.09., wörtlich: „Absätze beginnen mit Rz 1, Rz 2 … am Laptop im
   linken Rand, am Handy inline". Bewusst als eigenes <span class="rz"> im
   Markup (nicht als reiner CSS-Counter über ::before) — das macht die
   Randziffer robust gegenüber der Markdown→HTML-Pipeline des Entwicklers:
   sie kann sie einfach beim Rendern jedes Absatzes voranstellen, ohne dass
   eine Zählregel exakt sitzen muss. Mobile-first: ohne Media Query steht
   „Rz 1" schlicht als erstes Wort im Fließtext (inline). Erst ab 721px wird
   sie in den linken Rand gezogen — dafür braucht `.kommentarsatz` dort Platz. */
/* 16.09., Korrektur: „Rz 1" wirkte zu klein/blass. Kontrast war rechnerisch
   nie das Problem (--muted auf Weiß misst 7,08:1, siehe tokens.css) — aber
   12px + Gewicht 600 in einer System-Mono-Schrift liest sich dünn. Jetzt
   13,5px/700 und die dunklere `--muted-stark` (8,3:1) statt `--muted`:
   weiterhin dezent (kleiner als Fließtext, kein Fließtext-Gewicht), aber auf
   den ersten Blick lesbar statt nur ahnbar. */
.kommentarsatz .absatz{position:relative; margin-bottom:var(--sp-4)}
.kommentarsatz .absatz .rz{
  font-family:var(--font-mono); font-size:13.5px; font-weight:700;
  letter-spacing:.01em; color:var(--muted-stark); font-variant-numeric:tabular-nums;
  white-space:nowrap; margin-right:var(--sp-2);
}
@media(min-width:721px){
  .kommentarsatz{padding-left:64px}
  .kommentarsatz .absatz .rz{
    position:absolute; left:-64px; top:.1em; width:52px; text-align:right;
    margin-right:0; font-size:14px;
  }
}

/* ─────────── 3.13 · „Klartext"-Absatz am Kapitelende (Stufe 2, dezent) ───────────
   Bewusst KEIN Warnkasten: keine Hintergrundfarbe, kein Icon, kein größerer
   Schriftgrad als der Fließtext daneben — nur eine dünne Trennlinie und ein
   kleiner Kicker. Ein Vorbehalt, der optisch lauter ist als die Substanz,
   wirkt wie eine Selbstanzeige statt wie ein geprüfter Punkt (dieselbe
   Lehre, die in der FinPrep-Hülle bereits gezogen wurde). */
.klartext{margin-top:var(--sp-7); padding-top:var(--sp-4); border-top:1px solid var(--line); max-width:var(--mass-lese)}
.klartext .kicker{
  display:block; font-family:var(--font-mono); font-size:var(--f-micro); font-weight:600;
  letter-spacing:.16em; text-transform:uppercase; color:var(--muted); margin-bottom:var(--sp-2);
}
.klartext p{font-size:1em; line-height:1.65; color:var(--muted)}
.klartext p + p{margin-top:var(--sp-3)}

/* ─────────── 3.13b · Aufklapp-Details für dichte Randziffer-Blöcke (Umbau 30.09.2026) ───────────
   Florian: "lange Randziffer-Blöcke kürzen oder in Aufklapp-Details
   verschieben". Echtes natives `<details>` (wie `.bereich`/`.pitch-
   eingeklappt` schon anderswo im Hub) - kein eigener JS-Code nötig,
   funktioniert ohne Skript, ist von Haus aus per Tastatur bedienbar. Steht
   direkt im Markdown als rohes HTML (bauen.py reicht Absätze, die mit "<"
   beginnen, unverändert durch - siehe Kommentar über `absatz_leeren` in
   bauen.py). Die Randziffern DARIN bleiben normale `.kommentarsatz`-Blöcke,
   nur das äußere `<details>` ist neu. */
.mehr-aufklappen{
  margin:var(--sp-5) 0; border:1.5px solid var(--line); border-radius:var(--r-sm);
  padding:var(--sp-4) var(--sp-5); background:var(--flaeche-tief); max-width:var(--mass-lese);
}
.mehr-aufklappen summary{
  cursor:pointer; list-style:none; font-family:var(--font-mono); font-size:13.5px; font-weight:700;
  letter-spacing:.06em; color:var(--tiefgruen); display:flex; align-items:center; gap:8px;
}
.mehr-aufklappen summary::-webkit-details-marker{display:none}
.mehr-aufklappen summary::before{
  content:"+"; display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px;
  border:1.5px solid var(--tiefgruen); border-radius:50%; font-weight:700; flex:none;
}
.mehr-aufklappen[open] summary::before{content:"–"}
.mehr-aufklappen summary:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:3px}
.mehr-aufklappen[open] summary{margin-bottom:var(--sp-3)}
.mehr-aufklappen .kommentarsatz:last-child,.mehr-aufklappen > p:last-child{margin-bottom:0}
@media print{
  /* Browser unterschiedlich: manche drucken geschlossene <details> nicht
     mit. Diese Regel zwingt den Inhalt sichtbar - Entwickler bitte einmal
     an einem echten Ausdruck gegenprüfen (siehe Übergabenotiz). */
  .mehr-aufklappen{border:1px solid #000 !important; background:#fff !important}
  .mehr-aufklappen:not([open]) > :not(summary){display:block !important}
  .mehr-aufklappen summary::before{border-color:#000 !important; color:#000 !important}
}

/* ───────────────────────────── 3.14 · Kontaktblock ───────────────────────────── */
.kontakt{
  display:flex; gap:var(--sp-5); align-items:center; flex-wrap:wrap;
  padding:var(--sp-5) var(--sp-6); border-radius:var(--r-card);
  background:var(--warmweiss); border:1px solid var(--line); margin:var(--sp-6) 0;
}
.kontakt .avatar{
  flex:none; width:52px; height:52px; border-radius:50%; background:var(--tiefgruen); color:#fff;
  display:grid; place-items:center; font-family:var(--font-anzeige); font-weight:800; font-size:16px;
}
.kontakt .info{min-width:0}
.kontakt .info b{display:block; font-size:16px}
.kontakt .info span{display:block; font-size:13.5px; color:var(--muted); margin-top:1px}
.kontakt .info a{font-weight:700; margin-top:4px; display:inline-block}

/* ─────────────────── 3.15 · Navleiste (Stufe 2, „mehr Übersicht") ───────────────────
   Florian, 16.09.: „mehr Übersicht in Stufe 2" — eine immer sichtbare Kapitel-
   navigation. Am Laptop feste linke Seitenleiste (sticky), am Handy ein
   Menü-Knopf mit ausklappbarer Liste darunter — EIN Markup, zwei Zustände
   per Media Query, kein zweiter Komponentensatz.

   ERWARTETES MARKUP (Entwickler baut ein, hier nur die Vorgabe; Stand
   02.10.2026 nach dem Pruefer-Befund unten — Gruppenkopf aus Eyebrow +
   eigener Namenszeile, siehe app/bauen.py `baue_navleiste_bereiche`):
     <div class="mit-navleiste">
       <button class="navleiste-knopf" aria-expanded="false" aria-controls="navleiste">Kapitel</button>
       <nav class="navleiste" id="navleiste" aria-label="Kapitel Stufe 2" hidden>
         <span class="navleiste-gruppe" data-bereich="1">
           <span class="navleiste-gruppe-kopf"><span class="punkt"></span>Bereich 1</span>
           <span class="navleiste-gruppe-name">Reinheitsbewegung und Academy</span>
         </span>
         <ol><li><a href="#kap-2-11">11 · …</a></li> … </ol>
         <span class="navleiste-gruppe" data-bereich="2"> … </span>
         <ol><li><a href="#kap-2-18">18 · …</a></li> … </ol>
       </nav>
       <div class="navleiste-inhalt"> … alle Kapitel 11–23 … </div>
     </div>
   `hidden` ist der Ausgangszustand für die MOBILE Variante (Liste zu). Ab
   900px hebt die Media Query unten `hidden` wieder auf — die Seitenleiste
   ist am Laptop NIE einklappbar, das `hidden`-Attribut bleibt nur ein
   Mobil-Zustand. `.aktiv` markiert das gerade gelesene Kapitel bzw. den
   gerade gelesenen Bereich (hub.html setzt/verschiebt die Klasse per
   IntersectionObserver beim Scrollen — KEIN Kapitel/Bereich ist beim
   ersten Rendern vorab als aktiv markiert, siehe Pruefer-Befund unten;
   reine CSS-Aufgabe ist nur das Aussehen von `.aktiv`).

   BREITE: 900px als Schwelle für den Wechsel Menü-Knopf → Seitenleiste,
   NICHT die sonst übliche 700/760px-Handygrenze. Grund: bei 768px (Tablet
   hoch, in Florians Prüfliste) ließe eine dauerhafte 252px-Leiste nur noch
   ~470px für Bühne/Fließtext — eng, aber die Leiste selbst wäre technisch
   nutzbar; ich habe mich für den Knopf entschieden, weil ein Investor am
   Tablet hochkant eher überblättert als eine schmale Randspalte mitliest.
   Bei 1024px (Tablet quer, ebenfalls in der Liste) UND darüber greift die
   Seitenleiste (1024−252=772px Bühne, ausreichend).

   PRÜFER-BEFUND 02.10.2026 (Florian: „Sidebar ist gefährlich – sie ist
   falsch angeordnet"), BEHOBEN: `top:0`/`height:100vh` ignorierten die
   ECHTE Kopfleiste (`.kapitelnav` in app/hub.html, selbst `position:sticky;
   top:0`, aber mit höherem `z-index:40` – sie liegt also ÜBER der
   Navleiste). Beide stickten auf dieselbe Viewport-Kante: beim Scrollen
   rutschte der obere Teil der Navleiste UNTER die Kopfleiste (abgeschnittene
   erste Bereichsüberschrift), und `height:100vh` ab Viewport-Oberkante
   schnitt gleichzeitig das letzte Kapitel am unteren Rand ab. Fix: eigene
   Variable `--h-kapitelnav` (app/hub.html, dort gesetzt, weil die
   Kopfleiste selbst Bedienlogik-HTML ist, kein Designsystem-Bauteil) –
   `top`/`height` der Navleiste ziehen davon ab, die Leiste bekommt ihr
   EIGENES `overflow-y:auto` unterhalb der Kopfleiste statt eines zu hohen,
   teils verdeckten 100vh-Blocks. */
.navleiste-knopf{
  display:flex; align-items:center; gap:8px; width:100%; max-width:var(--breite-daten);
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-sm);
  padding:12px 16px; font-family:var(--font-anzeige); font-weight:700; font-size:15px;
  color:var(--ink); cursor:pointer; margin:0 auto var(--sp-4);
}
.navleiste-knopf::after{content:"▾"; margin-left:auto; color:var(--muted); transition:transform .15s ease}
.navleiste-knopf[aria-expanded="true"]::after{transform:rotate(180deg)}
.navleiste-knopf:hover{border-color:var(--line-stark)}
.navleiste-knopf:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}

.navleiste{
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-4) var(--sp-3); margin:0 auto var(--sp-6); max-width:var(--breite-daten);
  max-height:min(70vh,520px); overflow-y:auto;
}
.navleiste[hidden]{display:none}
/* Pruefer-Befund 02.10.2026: "1 ·" stand bei schmaler Spalte (252px) allein
   in einer Zeile, der Bereichsname zerfiel danach auf mehrere Zeilen -
   gesperrte Mono-Grossbuchstaben brechen an JEDEM Leerzeichen gleich
   schlecht. Jetzt zwei Zeilen MIT Bedeutung statt einer verunglueckt
   umbrechenden: oben ein kurzes, nie umbrechendes Eyebrow-Label
   ("Bereich 1"), darunter der volle Name in normaler Schreibung (keine
   Grossbuchstaben-Sperrung mehr) - der darf frei und lesbar umbrechen,
   weil er nicht mehr mit der Nummer in einem Textfluss steht. Gleiche
   Hierarchie-Sprache wie die Bereichs-Kacheln/-Koepfe weiter oben auf
   derselben Seite (3.28: Eyebrow tiefgruen + fette Anzeigeschrift fuer den
   Namen) - Stufe-1/Stufe-2-Formensprache bleibt dieselbe. */
.navleiste-gruppe{
  display:block; padding:14px 12px 6px; color:var(--muted);
}
.navleiste-gruppe:first-child{padding-top:4px}
.navleiste-gruppe-kopf{
  display:flex; align-items:center; gap:8px; font-family:var(--font-mono); font-size:11.5px;
  letter-spacing:.14em; text-transform:uppercase; color:inherit; white-space:nowrap;
}
.navleiste-gruppe-name{
  display:block; margin-top:3px; font-family:var(--font-anzeige); font-weight:700; font-size:14px;
  line-height:1.3; color:var(--ink);
}
.navleiste-gruppe.aktiv .navleiste-gruppe-name{color:var(--tiefgruen)}
.navleiste ol{list-style:none; margin:0; padding:0}
.navleiste li + li{margin-top:1px}
/* Kapitel sichtbar UNTER ihrem Bereich eingerueckt (Pruefer-Befund
   02.10.2026, "Kapitel eingerueckt unter ihrem Bereich") - 6px mehr
   Innenabstand links als der Gruppenkopf, ohne eigene Einzugsspalte (die
   waere bei 252px Breite zu teuer). */
.navleiste a{
  display:block; padding:9px 12px 9px 18px; border-radius:8px; font-size:14.5px; line-height:1.35;
  color:var(--ink); text-decoration:none; border-left:2.5px solid transparent;
}
.navleiste a:hover{background:var(--flaeche-tief)}
.navleiste a:focus-visible{outline:2px solid var(--tiefgruen); outline-offset:1px}
.navleiste a.aktiv{
  background:var(--flaeche-tief); border-left-color:var(--tiefgruen); color:var(--tiefgruen); font-weight:700;
}

@media(min-width:900px){
  .navleiste-knopf{display:none}
  /* 02.10.2026, Pruefer-Befund/Jens: „Sidebar klebt am linken Rand" — die
     Leiste sass bisher als direktes Kind von `<main id="feld">` OHNE jedes
     Aussenpolster, waehrend ALLES andere auf der Seite `.seite{padding:0
     24px}` traegt. Deshalb zwei Ergaenzungen, NICHT die Leistenbreite
     selbst: 1) dasselbe 24px-Polster wie `.seite`, damit die Leiste nie am
     physischen Fensterrand klebt; 2) eine Obergrenze + Zentrierung fuer den
     GESAMTEN Block (Leiste + Inhalt zusammen), damit auf grossen Monitoren
     (1920/2560) nicht nur die Kacheln/Tabellen in ihrer eigenen Spur
     zentriert sind, sondern Leiste und Inhalt als EINE Einheit in der
     Fenstermitte stehen — exakt Florians Vorgabe „mit dem Inhalt zusammen
     zentriert". Die Obergrenze ist bewusst DIESELBE --breite-inhalt wie bei
     `.seite` und der Kopfleiste (app/hub.html `.kapitelnav-zeile`) — damit
     Stufe-1-Inhalt, Kopfleiste und die Stufe-2-Leiste+Inhalt-Einheit auf
     JEDER Breite denselben Außenrand teilen, keine drei verschiedenen
     Zentrierungen auf derselben Seite. Dass die Innenspalte dadurch an den
     beiden obersten Stufen ein paar Pixel schmaler bleibt als ihr eigenes
     --breite-daten-Maximum (Grid teilt sich --breite-inhalt minus feste
     Leistenbreite), ist kein Fehler — die Kacheln/Tabellen füllen dann eben
     ihre tatsächlich verfügbare Spur, nie mehr. */
  .mit-navleiste{
    display:grid; grid-template-columns:var(--breite-navleiste) minmax(0,1fr); gap:0; align-items:start;
    max-width:var(--breite-inhalt); margin:0 auto; padding:0 24px;
  }
  .navleiste{
    position:sticky; top:var(--h-kapitelnav,56px); align-self:start;
    height:calc(100vh - var(--h-kapitelnav,56px)); max-height:none; max-width:none; overflow-y:auto;
    border:0; border-right:1px solid var(--line); border-radius:0; margin:0;
    padding:var(--sp-6) var(--sp-4);
  }
  /* Am Laptop nie einklappbar — `hidden` ist ausschließlich ein Mobil-
     Zustand, siehe Markup-Hinweis oben. */
  .navleiste[hidden]{display:block}
  .navleiste-inhalt{min-width:0; padding-left:var(--sp-6)}
}
@media(min-width:1600px){
  /* 1920/2560: die Leiste bleibt in fester Pixelbreite (--breite-navleiste
     ist px, kein vw) — sie wächst NICHT mit, sonst nimmt sie der Bühne auf
     großen Monitoren unnötig Platz weg. Nur das Innenpolster bekommt hier
     etwas mehr Luft, weil auf so einem Monitor ohnehin alles großzügiger
     wirken darf. */
  .navleiste{padding-left:var(--sp-5)}
}
@media(max-width:479px){
  /* 360/390/430: Leiste und Knopf teilen sich die volle Breite mit dem
     Rest der Seite (kein eigenes `--breite-daten`-Polster nötig, das wäre
     hier ohnehin größer als der Bildschirm). */
  .navleiste-knopf, .navleiste{max-width:none}
}

/* ─────────────── 3.16 · „Auf einen Blick" (Kopf von Stufe 2) ───────────────
   Florian, 16.09., wörtlich zur Übersicht: sechs Eckzahlen + 5–6 Kernsätze,
   die zum jeweiligen Kapitel springen. Sitzt ganz oben in `.navleiste-inhalt`,
   VOR dem ersten Kapitel. Eckzahlen sind bewusst KLEINER als die großen
   `.kennzahl`-Kacheln aus 3.6 (das hier ist eine Kurzfassung, keine
   Wiederholung) — eigene, kompaktere Klasse `.blick-kachel`, kein Reuse von
   `.kennzahl`, damit eine spätere Änderung an den großen Kacheln nicht
   versehentlich die Übersicht mitverändert. */
.aufeinenblick{
  background:var(--flaeche); border:1.5px solid var(--tiefgruen); border-radius:var(--r-card);
  padding:var(--sp-6); margin:0 auto var(--sp-7); max-width:var(--breite-daten);
}
.aufeinenblick .titel{
  font-family:var(--font-anzeige); font-weight:800; font-size:20px; color:var(--navy); margin:0 0 4px;
}
.aufeinenblick .untertitel{font-size:14px; color:var(--muted); margin:0 0 var(--sp-5); max-width:60ch}

/* 16.09., Korrektur nach Prüfung bei 1440px: `auto-fit` mit sechs Kacheln
   passte je nach verfügbarer Breite mal 5, mal 6 pro Reihe hinein — bei
   1440px genau 5, die sechste fiel allein in eine zweite Reihe. Jetzt ein
   FESTES Raster statt einer variablen Anzahl: 2 Spalten mobil (passte
   bereits), ab 900px genau 3×2. Grid-Zeilen sind ohnehin gleich hoch (Grid-
   Kinder strecken sich per Default auf die höchste Kachel ihrer Reihe —
   kein zusätzliches `align-items` nötig). */
.blick-kacheln{
  display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-3);
  margin-bottom:var(--sp-5);
}
@media(min-width:900px){
  .blick-kacheln{grid-template-columns:repeat(3,1fr)}
}
.blick-kachel{
  background:var(--flaeche-tief); border:1px solid var(--line); border-radius:var(--r-sm);
  padding:var(--sp-3) var(--sp-4); min-width:0;
}
.blick-kachel .zahl{
  display:block; font-family:var(--font-anzeige); font-weight:800; color:var(--tiefgruen);
  font-size:22px; line-height:1.2; font-variant-numeric:tabular-nums lining-nums;
  /* Pruefer-Befund 02.10.2026, 375/390px: `white-space:nowrap` stand hier
     fest - bei mehrteiligen Werten ("400 · 350 T€", der Mittelverwendungs-
     Zahl) oder schlicht einer langen Zahl ("750.000 €", Ask) lief die
     Kachel ueber ihre eigene Breite hinaus (die Kachel selbst durfte dank
     `min-width:0` oben schmaler werden als ihr Inhalt - das Zahl-Element
     folgte dem nicht, weil nowrap ihm das verbot). Jetzt darf die Zahl
     ZEILENUMBRUCH an einer Leerstelle (`· `-Trenner bei mehreren Toepfen);
     `overflow-wrap`/`word-break` fangen zusaetzlich den Fall ab, dass eine
     einzelne Zahl ohne Leerstelle (z. B. "750.000") immer noch breiter als
     die Kachel waere. */
  white-space:normal; overflow-wrap:break-word; word-break:break-word;
}
@media(max-width:420px){
  /* Am schmalsten gemessenen Rahmen (375px) bleibt die Zahl zusaetzlich
     kleiner - weniger Umbruch noetig, weniger "zerrissene" Kacheln. */
  .blick-kachel .zahl{font-size:19px}
  /* "Ask" und "Mittelverwendung" (die ersten beiden Kacheln, siehe
     baue_blick_kacheln - feste Reihenfolge) tragen die laengsten Werte
     ("750.000 €" bzw. "400 · 350 T€") - selbst bei 19px und erlaubtem
     Umbruch brach "750.000" noch MITTEN in der Zahl um (gemessen:
     73,5px verfuegbare Breite in der 2-spaltigen Halb-Kachel reichten
     nicht fuer 7 Ziffern). Diese zwei spannen am schmalsten Rahmen die
     volle Breite - dort reicht der Platz, keine Zahl muss mehr brechen. */
  .blick-kachel:nth-child(1),.blick-kachel:nth-child(2){grid-column:1 / -1}
}
/* Die EINHEIT neben der Kachelzahl ("€", "T€", "Mio €", "%", "Jahr",
   "Mio € (4×)") soll ihre Groesse an die Zahl binden (.55em) - deshalb
   `max()` statt einer festen Groesse: die Bindung bleibt, sobald die Zahl
   ueber 22,7px waechst, und darunter greift die Untergrenze.
   Vorgeschichte (16.09.): Hier stand eine bewusste AUSNAHME von der
   12,5px-Untergrenze, gemessen wurden 12,1px. Ein Pruefer hat zwei Dinge
   dagegengehalten, beide richtig: Erstens deckte die Begruendung "ein
   Waehrungszeichen ist kein Lesetext" die Faelle "Jahr" und "Mio € (4×)"
   nicht ab - das sind Woerter. Zweitens kauft die Ausnahme nichts: 12,1 auf
   12,5 sind +3,3%, das sieht niemand, aber die Regel bekommt ein Loch, das
   nach unten offen ist (Kachelzahl auf 20px gezogen = 11,0px, ohne dass
   etwas rot wird). Optisch identisch, Regel ohne Ausnahme. */
.blick-kachel .zahl .einheit{font-size:max(12.5px,.55em); font-weight:700; color:var(--muted); margin-left:3px}
.blick-kachel .label{display:block; margin-top:4px; font-size:12.5px; color:var(--muted); line-height:1.3}

.blick-zeilen{display:grid; border:1.5px solid var(--line); border-radius:var(--r-sm); overflow:hidden}
.blick-zeile{
  display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:4px 12px;
  padding:13px var(--sp-4); background:var(--flaeche); text-decoration:none; color:var(--ink);
  font-size:15px; border-top:1px solid var(--line);
}
.blick-zeile:first-child{border-top:0}
.blick-zeile:is(:hover,:focus-visible){background:var(--flaeche-tief)}
.blick-zeile:focus-visible{outline:2px solid var(--tiefgruen); outline-offset:-2px}
.blick-zeile .satz{min-width:0}
.blick-zeile .ziel{
  flex:none; font-family:var(--font-mono); font-size:12.5px; color:var(--muted);
  white-space:nowrap; display:inline-flex; align-items:center; gap:6px;
}
.blick-zeile .ziel::after{content:"→"; color:var(--muted)}

/* ─────────────────── 3.17 · Frageassistent (Stufe 1 UND Stufe 2) ───────────────────
   Florian, 16.09., wörtlich: „den Frageassistenten wo Firmen/Vertrieb/etc
   Jens beantwortet und Technik/KI und Zahlen beantworte ich". Schwebender
   Knopf unten rechts, öffnet ein Panel; am Handy Vollbild-Blatt statt einer
   schwebenden Karte (auf 380px Panelbreite wäre am Handy kein Rand mehr
   übrig). Kein eigener Nachtmodus-Zweig hier — folgt automatisch den
   Tokens, funktioniert also auch unter `[data-theme="dunkel"]`.

   ERWARTETES MARKUP (Entwickler baut Logik/Fetch/Fokus-Trap ein):
     <button class="frage-knopf" aria-haspopup="dialog" aria-expanded="false"
             aria-controls="frage-panel">Frage stellen</button>
     <div class="frage-panel" id="frage-panel" role="dialog" aria-modal="true"
          aria-labelledby="frage-panel-titel" hidden>
       <div class="frage-panel-kopf">
         <h2 id="frage-panel-titel">Frage stellen</h2>
         <button class="frage-schliessen" aria-label="Schließen">×</button>
       </div>
       <p class="frage-hinweis">Antworten erzeugt eine KI aus den Inhalten
         dieses Hubs; verbindlich ist das Gespräch.</p>
       <div class="frage-verlauf" aria-live="polite">
         <p class="frage-frage">… Nutzerfrage …</p>
         <div class="frage-antwort">
           <span class="antwort-person jens"><span class="punkt"></span>Jens Windel</span>
           <p>… Antworttext …</p>
           <span class="antwort-fundstelle">Rz 3 · Kapitel 20</span>
         </div>
         <p class="frage-laedt" aria-hidden="true">… tippt <span class="punkte"><span>.</span><span>.</span><span>.</span></span></p>
         <p class="frage-fehler" role="alert">… Fehlertext …</p>
       </div>
       <form class="frage-formular">
         <textarea class="frage-eingabe" maxlength="500" aria-describedby="frage-zaehler"></textarea>
         <div class="frage-formular-fuss">
           <span class="frage-zaehler" id="frage-zaehler">0/500</span>
           <button class="frage-absenden" type="submit">Senden</button>
         </div>
       </form>
     </div>
   Fokus-Trap, Escape-zu-Schließen, Rückgabe des Fokus an `.frage-knopf`
   beim Schließen: JS-Aufgabe des Entwicklers, hier nur die Optik/ARIA-Rollen
   vorbereitet. */
.frage-knopf{
  position:fixed; right:24px; bottom:24px; z-index:70;
  display:inline-flex; align-items:center; gap:8px;
  background:var(--tiefgruen); color:#fff; border:none; border-radius:var(--r-btn);
  padding:14px 22px; font-family:var(--font-anzeige); font-weight:700; font-size:15px;
  box-shadow:var(--schatten-karte); cursor:pointer;
}
.frage-knopf .punkt-live{width:8px; height:8px; border-radius:50%; background:var(--frischgruen); flex:none}
.frage-knopf:hover{background:#0d4a3b}
.frage-knopf:focus-visible{outline:3px solid var(--frischgruen); outline-offset:2px}
.frage-knopf[aria-expanded="true"]{background:var(--navy)}

.frage-panel{
  position:fixed; right:24px; bottom:88px; z-index:70; width:var(--breite-frage-panel);
  max-width:min(var(--breite-frage-panel),calc(100vw - 32px));
  max-height:min(640px,80vh);
  background:var(--flaeche); border:1px solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--schatten-karte); display:flex; flex-direction:column; overflow:hidden;
}
.frage-panel[hidden]{display:none}
.frage-panel-kopf{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  padding:var(--sp-4) var(--sp-5); border-bottom:1px solid var(--line); flex:none;
}
.frage-panel-kopf h2{font-size:16px; color:var(--navy)}
.frage-schliessen{
  background:none; border:none; font-size:20px; line-height:1; cursor:pointer; color:var(--muted);
  width:32px; height:32px; border-radius:8px; flex:none;
}
.frage-schliessen:hover{background:var(--flaeche-tief)}
.frage-schliessen:focus-visible{outline:2px solid var(--tiefgruen); outline-offset:1px}

.frage-hinweis{
  font-size:12.5px; line-height:1.5; color:var(--muted); margin:0; flex:none;
  padding:var(--sp-3) var(--sp-5); border-bottom:1px solid var(--line); background:var(--flaeche-tief);
}

.frage-verlauf{flex:1 1 auto; overflow-y:auto; padding:var(--sp-4) var(--sp-5); display:flex; flex-direction:column; gap:var(--sp-4)}

.frage-frage{
  align-self:flex-end; background:var(--warmweiss); border:1px solid var(--line);
  border-radius:14px 14px 4px 14px; padding:10px 14px; font-size:14.5px; max-width:88%; margin:0;
}
.frage-antwort{
  background:var(--flaeche-tief); border:1px solid var(--line); border-radius:14px 14px 14px 4px;
  padding:12px 16px; font-size:14.5px; line-height:1.55; max-width:92%;
}
.antwort-person{display:flex; align-items:center; gap:7px; font-weight:700; font-size:13px; margin-bottom:6px}
.antwort-person .punkt{width:8px; height:8px; border-radius:50%; flex:none}
.antwort-person.jens .punkt{background:var(--tiefgruen)}
.antwort-person.jens{color:var(--tiefgruen)}
.antwort-person.florian .punkt{background:var(--orange)}
.antwort-person.florian{color:#A04A16} /* dunkler als --orange: 5,68:1 auf --flaeche-tief statt 2,3:1 bei reinem Orange-Text (erste Fassung #B85A1E maß nur 4,39:1 — knapp unter AA, nachgebessert) */
.frage-antwort p{margin:0; color:var(--ink)}
.antwort-fundstelle{
  display:block; margin-top:8px; font-family:var(--font-mono); font-size:12.5px; color:var(--muted);
}

.frage-laedt{display:flex; align-items:center; gap:6px; font-size:13.5px; color:var(--muted); margin:0}
.frage-laedt .punkte span{animation:frage-blinken 1.2s infinite; opacity:.2}
.frage-laedt .punkte span:nth-child(2){animation-delay:.2s}
.frage-laedt .punkte span:nth-child(3){animation-delay:.4s}
@keyframes frage-blinken{0%,80%,100%{opacity:.2} 40%{opacity:1}}
@media(prefers-reduced-motion:reduce){.frage-laedt .punkte span{animation:none; opacity:1}}

.frage-fehler{
  background:#FBEAE8; border:1px solid #E3A79E; color:#7A2A20; border-radius:10px;
  padding:10px 14px; font-size:13.5px; margin:0;
}

.frage-formular{border-top:1px solid var(--line); padding:var(--sp-4) var(--sp-5); display:flex; flex-direction:column; gap:8px; flex:none}
.frage-eingabe{
  width:100%; resize:none; min-height:64px; border:1.5px solid var(--line); border-radius:12px;
  padding:10px 12px; font-family:var(--font-text); font-size:14.5px; color:var(--ink);
}
.frage-eingabe:focus-visible{outline:2px solid var(--tiefgruen); outline-offset:2px}
.frage-formular-fuss{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3)}
.frage-zaehler{font-size:12.5px; color:var(--muted); font-variant-numeric:tabular-nums}
.frage-zaehler.nah-am-limit{color:var(--orange); font-weight:700}
.frage-absenden{
  background:var(--tiefgruen); color:#fff; border:none; border-radius:var(--r-btn);
  padding:10px 20px; font-weight:700; font-size:14px; cursor:pointer;
}
.frage-absenden:hover{background:#0d4a3b}
.frage-absenden:disabled{background:var(--line); color:var(--muted); cursor:not-allowed}
.frage-absenden:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}

@media(max-width:639px){
  /* 360/390/430: Vollbild-Blatt statt schwebender Karte — bei 380px fester
     Panelbreite bliebe am Handy praktisch kein Rand mehr übrig. */
  .frage-panel{
    right:0; bottom:0; left:0; top:0; width:auto; max-width:none; max-height:none;
    border-radius:0; border:0;
  }
  .frage-knopf{right:16px; bottom:16px; padding:13px 18px; font-size:14.5px}
}
@media(min-width:640px) and (max-width:900px){
  /* schmalere Fenster/Tablet hoch: Panel darf nicht an den Bühnenrand
     stoßen — Breite weicht der tatsächlichen Fensterbreite, siehe
     `max-width:min(…, calc(100vw - 32px))` oben, hier nur die Position
     etwas näher an den Rand gezogen. */
  .frage-panel{right:16px; bottom:80px}
}

/* ─────────── 3.2b · „Der Wisch" — Bildschirmstaub + echter Besen ───────────
   Florian, 28.09.2026, wörtlich: „sowas wie einen Besen der immer weiterwischt".
   DRITTER Durchgang 29.09.2026, wörtlich: „Staub über den Banner, wo man sich
   denkt: jetzt wische ich den Bildschirm — und dann kommt ein Besen, der es
   wegwischt, ins Bild haha" — „es soll ECHT wirken". hub.html baut zur
   LAUFZEIT ZWEI übereinanderliegende `<canvas>` in `.traum-titel`:
     `.wisch-canvas` (unten) trägt den STAUB (Staubkörner/Fussel/
       Fingerabdruck-Schlieren, wirkt wie Staub AUF DEM BILDSCHIRM, nicht wie
       ein Filter) — wird NUR per `destination-out` an der Besen-Position
       angeknabbert, nie komplett neu gezeichnet (der Staub muss zwischen den
       Frames liegen bleiben, nur die Bahn des Kopfes wird sauber).
     `.wisch-besen-canvas` (oben) trägt NUR den beweglichen Besen selbst
       (`ctx.drawImage` mit `.besen-quelle` als Quelle) — wird JEDEN Frame
       komplett geleert und neu an der aktuellen Position gezeichnet, sonst
       bliebe eine Spur alter Besen-Abdrücke stehen. Dieselbe
       Koordinatenrechnung treibt BEIDE Canvas, die Putz-Bahn stimmt dadurch
       exakt mit der sichtbaren Besen-Position überein.
   `overflow:hidden` steht bereits auf `.traum-titel` selbst (3.2 oben) —
   auch während der Besen links/rechts außerhalb der Bühne steht, kein
   horizontales Scrollen möglich. `.besen-quelle` (das unsichtbare Quellbild
   aus bauen.py, nur als Bilddaten-Lieferant für `drawImage` gedacht) bleibt
   IMMER `display:none`. Ohne JS/bei reduzierter Bewegung/ohne Canvas-
   Unterstützung erzeugt hub.html gar kein Canvas — der Satz steht dann von
   Anfang an klar da, ganz ohne Regel hier. */
.traum-titel .wisch-canvas,.traum-titel .wisch-besen-canvas{position:absolute; inset:0; pointer-events:none}
.traum-titel .wisch-canvas{z-index:2}
.traum-titel .wisch-besen-canvas{z-index:3}
.traum-titel .besen-quelle{display:none}

/* ─────────── 3.2c · Kapitel werden beim Hereinscrollen einmalig freigewischt ───────────
   NUR aktiv, wenn hub.html die Klasse "js-wisch" auf <html> gesetzt hat — und
   das Skript setzt sie wiederum NUR, wenn IntersectionObserver existiert UND
   der Nutzer keine reduzierte Bewegung verlangt (siehe hub.html). Ohne JS
   oder bei reduzierter Bewegung greift diese Regel nie: jedes Kapitel ist von
   Anfang an voll sichtbar (Auftrag: „Ohne JS muss ALLER Text sichtbar sein"),
   das gilt auch fürs eingeklappte Stufe-1-Pitch-Zitat in Stufe 2 — der
   Selektor bleibt deshalb auf `.stufe1 .kapitel` beschränkt, echte
   Stufe-2-Kapitel (11–23) sind nie betroffen ("Effekte dort harmlos"). */
.js-wisch .stufe1 .kapitel{
  opacity:0; clip-path:inset(0 0 0 6%); transform:translateY(14px);
  transition:opacity .6s ease, clip-path .6s cubic-bezier(.22,.61,.36,1), transform .6s ease;
}
.js-wisch .stufe1 .kapitel.wisch-sichtbar{
  opacity:1; clip-path:inset(0 0 0 0); transform:translateY(0);
}

/* ─────────── 3.2d · Wisch-Leiste — Lesefortschritt am Rand ───────────
   „Ein Besen, der immer weiterwischt": eine schmale Leiste am rechten Rand
   füllt sich mit der Scrollposition, wie eine saubergewischte Spur. Rein
   dekorativ (kein Text, `aria-hidden`) und existiert nur, wenn hub.html sie
   per JS anlegt — ohne JS gibt es das Element schlicht nicht (kein
   Default-Versteck, das nur JS wieder zeigen müsste). */
.wisch-leiste{
  position:fixed; top:0; right:0; width:6px; height:100vh; z-index:35;
  background:var(--line); pointer-events:none;
}
.wisch-leiste::after{
  content:""; position:absolute; top:0; left:0; right:0; height:var(--anteil,0%);
  background:linear-gradient(var(--tiefgruen), var(--frischgruen));
}
@media(max-width:640px){ .wisch-leiste{display:none} }

/* ─────────── 3.2e · Hintergrund wird beim Scrollen "sauber" (Der Wisch, Fortsetzung) ───────────
   Florian, 29.09.2026, wörtlich: der Hintergrund soll von "schmutzig" zu
   "sauber" wechseln. Nutzt DIESELBE Fortschritts-Variable wie die
   Wisch-Leiste direkt oberhalb (`--anteil`, 0%–100%, per Scroll/rAF auf
   <html> gesetzt) - kein zweiter Scroll-Handler. `color-mix()` ohne
   Browserunterstützung ergibt eine UNGÜLTIGE Deklaration; die Kaskade
   fällt dann automatisch auf `body{background:var(--flaeche-tief)}`
   (Abschnitt 1, weiter oben in dieser Datei) zurück - kein Fehler, kein
   grauer Bildschirm, nur ein Verlauf weniger. Kontrast siehe tokens.css
   (`--stufe1-schmutzig`-Kommentar) - beide Enden bleiben AA-sicher. */
.js-wisch body.stufe1{
  background:color-mix(in srgb, var(--stufe1-sauber) var(--anteil,0%), var(--stufe1-schmutzig));
}

/* ─────────────────── 3.17 · Bilder ("Entwurf der Oberfläche") ───────────────────
   Florian, 28.09.2026, wörtlich: „Echte Bilder und Grafiken". Fertige,
   verkleinerte WebP-Mockups aus design/bilder/ (bauen.py bettet sie als
   data-URI ein) — Handy-Mockups (`.standard`) und Desktop-Cockpits
   (`.gross`), sowie Reihe/Band für mehrere Bilder nebeneinander. */
.bild-block{
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten)); text-align:center;
}
.bild-block img{
  max-width:100%; height:auto; border-radius:var(--r-card);
  border:1.5px solid var(--line); box-shadow:var(--schatten-karte); background:#fff;
}
.bild-block.standard img{max-width:min(340px,100%)}
.bild-block.gross img{max-width:min(640px,100%)}
.bild-block figcaption{
  margin-top:var(--sp-3); font-family:var(--font-mono); font-size:12.5px;
  letter-spacing:.06em; color:var(--muted); text-transform:uppercase;
}

/* ─────────── 3.17b · Bild-Scan-Effekt (:::bild effekt: scan, 29.09.2026) ───────────
   Florian, wörtlich: eine grüne Scan-Linie fährt einmal über das Bild und
   hinterlässt kurz einen Rahmen mit Etikett "erkannt" - reines CSS-Overlay,
   das <img> selbst bleibt unverändert (bauen.py `render_bild`). Grundzustand
   (keine Klasse) ist komplett unsichtbar (`opacity:0`) - ohne JS/bei
   reduzierter Bewegung bleibt nur das Bild da, kein hängendes Overlay.
   Die Linie bewegt sich per `transform:translateY()` INNERHALB von
   `.scan-spur` (per `inset:0` exakt auf Bildgröße gezogen) - `100%` ist
   damit relativ zur EIGENEN Höhe dieser Hülle (= Bildhöhe), nicht der
   Seite; bleibt dadurch eine reine transform/opacity-Animation. */
.bild-block.scan .scan-rahmen{position:relative; display:block}
.bild-block.scan .scan-rahmen img{display:block}
.bild-block.scan .scan-spur{position:absolute; inset:0; opacity:0; pointer-events:none}
.bild-block.scan .scan-linie{
  position:absolute; left:0; right:0; top:0; height:3px;
  background:linear-gradient(90deg, transparent, #29D97A, transparent);
  box-shadow:0 0 14px 2px rgba(41,217,122,.75);
}
.bild-block.scan .scan-rand{
  position:absolute; inset:0; border:2px solid #29D97A; border-radius:var(--r-card);
  box-shadow:0 0 0 3px rgba(41,217,122,.22) inset;
  opacity:0; display:flex; align-items:flex-end; justify-content:flex-end; padding:var(--sp-2);
  pointer-events:none;
}
.bild-block.scan .scan-etikett{
  font-family:var(--font-mono); font-size:12px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:#fff; background:#178A52; padding:3px 10px; border-radius:var(--r-btn);
  opacity:0; transform:translateY(4px);
}
.bild-block.scan.bild-scan-js .scan-spur{
  animation:scan-fahrt 1.3s cubic-bezier(.65,0,.2,1) both; animation-play-state:paused;
}
.bild-block.scan.bild-scan-js .scan-rand,
.bild-block.scan.bild-scan-js .scan-etikett{transition:opacity .4s ease, transform .4s ease}
.bild-block.scan.bild-scan-js.bild-scan-sichtbar .scan-spur{animation-play-state:running}
.bild-block.scan.bild-scan-js.bild-scan-sichtbar .scan-rand{opacity:1; transition-delay:1.05s}
.bild-block.scan.bild-scan-js.bild-scan-sichtbar .scan-etikett{opacity:1; transform:translateY(0); transition-delay:1.15s}
@keyframes scan-fahrt{
  0%{opacity:0; transform:translateY(0)}
  8%{opacity:1}
  90%{opacity:1}
  100%{opacity:0; transform:translateY(100%)}
}
@media(prefers-reduced-motion:reduce){
  .bild-block.scan .scan-spur,.bild-block.scan .scan-rand,.bild-block.scan .scan-etikett{
    animation:none !important; transition:none !important; opacity:0 !important;
  }
}

.bild-reihe{
  display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-6);
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.bild-reihe figure{margin:0; flex:1 1 320px; max-width:440px; text-align:center}
.bild-reihe img{
  width:100%; height:auto; border-radius:var(--r-card);
  border:1.5px solid var(--line); box-shadow:var(--schatten-karte); background:#fff;
}
.bild-reihe figcaption{
  margin-top:var(--sp-3); font-family:var(--font-mono); font-size:12.5px;
  letter-spacing:.06em; color:var(--muted); text-transform:uppercase;
}

/* Laufband — endlos scrollende Bilder-/Chip-Reihe. Florian, 28.09.2026,
   wörtlich: „überlaufende Grafiken … sowas wie einen Besen der immer
   weiterwischt". `.laufband-gruppe` steht zweimal im Markup (bauen.py
   render_bildband/render_branchen) — die Spur bewegt sich per Animation um
   exakt 50 % ihrer eigenen Breite (= eine Gruppenbreite), dadurch wirkt der
   Loop nahtlos. Pausiert bei Hover/Fokus, damit ein Bild bei Bedarf in Ruhe
   angesehen werden kann. */
.laufband{
  position:relative; margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten)); overflow:hidden;
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
  mask-image:linear-gradient(to right, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
}
.laufband-spur{display:flex; width:max-content; animation:laufband-zug 32s linear infinite}
.laufband:hover .laufband-spur,.laufband:focus-within .laufband-spur{animation-play-state:paused}
.laufband-gruppe{display:flex; align-items:flex-start; gap:var(--sp-6); padding:0 var(--sp-3)}
.laufband figure{margin:0; flex:0 0 auto; width:280px; text-align:center}
.laufband img{
  width:100%; height:auto; border-radius:var(--r-card);
  border:1.5px solid var(--line); box-shadow:var(--schatten-karte); background:#fff;
}
.laufband figcaption{
  margin-top:var(--sp-3); font-family:var(--font-mono); font-size:12.5px;
  letter-spacing:.06em; color:var(--muted); text-transform:uppercase;
}
@keyframes laufband-zug{ from{transform:translateX(0)} to{transform:translateX(-50%)} }
@media(max-width:640px){ .laufband figure{width:200px} }

/* Chip-Variante (Branchennamen Kap. 06, bauen.py render_branchen) — dieselbe
   Mechanik, kleinere Bausteine, komplett dekorativ (`aria-hidden` auf dem
   ganzen Band): die Namen stehen bereits lesbar in den Karten darüber, ein
   Screenreader soll sie nicht doppelt hören. */
.laufband-chips .laufband-spur{gap:0; animation-duration:22s}
.laufband-chips .laufband-gruppe{align-items:center; padding:0; gap:0}
.laufband-chips .chip{
  flex:0 0 auto; display:inline-block; padding:8px 18px; margin-right:var(--sp-3);
  border:1.5px solid var(--line); border-radius:var(--r-btn); background:var(--flaeche);
  font-family:var(--font-mono); font-size:13px; color:var(--tiefgruen); white-space:nowrap;
}
.laufband-chips .chip-trenn{margin-right:var(--sp-3); color:var(--muted)}

@media(prefers-reduced-motion:reduce){
  .laufband{overflow-x:auto; -webkit-overflow-scrolling:touch; -webkit-mask-image:none; mask-image:none}
  .laufband-spur{animation:none}
  .laufband-gruppe:nth-child(2){display:none}
}

/* Kreislauf-Punkte wandern (Kap. 08, bauen.py render_kreislauf) — reines
   CSS/SVG über `offset-path`, kein JS. Florian, 28.09.2026: „Im Kreislauf
   … wandern Punkte". */
.kreislauf .bahn{fill:none; stroke:none}
.kreislauf .wanderpunkt{fill:var(--orange); animation:kreislauf-wandern 10s linear infinite}
@keyframes kreislauf-wandern{ from{offset-distance:0%} to{offset-distance:100%} }
@media(prefers-reduced-motion:reduce){ .kreislauf .wanderpunkt{display:none} }

/* Zahlen, die hochzählen (bauen.py render_kartenreihe `_hebe_zahlen_hervor`,
   hub.html) — `tabular-nums` verhindert Zeilenzittern, während sich die
   Ziffern beim Hochzählen ändern. */
.zahl-lauf{font-variant-numeric:tabular-nums}

/* ─────────────────── 3.18 · Chaos-Feld (:::chaos, 29.09.2026) ───────────────────
   Florian, wörtlich: Zettel/WhatsApp/Excel/Telefon/Papier/Zuruf liegen wild
   verstreut und ordnen sich beim Hereinscrollen zu einer sauberen Reihe.
   GRUNDZUSTAND (keine Klasse) ist bereits die geordnete Reihe - normaler
   Flex-Fluss, kein Versatz. Erst `chaos-js` (hub.html, eigenständiger
   IntersectionObserver wie die Netzkarte) schaltet ein VORHERIGES,
   gestreutes Zwischenstadium dazu; `chaos-sichtbar` löst es wieder auf.
   `overflow:hidden` ist ein zusätzliches Sicherheitsnetz gegen horizontales
   Scrollen (die Streuwerte aus bauen.py sind klein genug, das sollte nie
   greifen müssen - schadet aber nicht, wenn doch). */
.chaos-feld{
  display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-3);
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten)); padding:var(--sp-5) var(--sp-4);
  overflow:hidden;
}
.chaos-chip{
  display:inline-flex; align-items:center; padding:9px 18px; border-radius:var(--r-btn);
  border:1.5px solid var(--line); background:var(--flaeche); font-family:var(--font-mono);
  font-size:14px; color:var(--muted-stark); white-space:nowrap;
}
.chaos-feld.chaos-js .chaos-chip{
  transition:transform .6s cubic-bezier(.22,.61,.36,1);
  transform:translate(var(--dx,0),var(--dy,0)) rotate(var(--rot,0deg));
}
.chaos-feld.chaos-js.chaos-sichtbar .chaos-chip{transform:none}
@media(prefers-reduced-motion:reduce){
  .chaos-feld.chaos-js .chaos-chip{transition:none; transform:none}
}

/* ─────────────────── 3.19 · Prozesskette (:::prozesskette, 29.09.2026) ───────────────────
   Florian, wörtlich: Stationen auf einer Linie (am Handy senkrecht), ein
   Leuchtpunkt läuft die Kette entlang, jede Station leuchtet beim
   Vorbeikommen auf, als Schleife. Reines CSS, KEIN Scroll-Bezug - die
   Schleife läuft unabhängig vom Scrollen, respektiert nur
   `prefers-reduced-motion` direkt hier (kein JS nötig). Der Punkt bewegt
   sich per `translateX` innerhalb von `.kette-bahn` (per `inset:0` exakt
   auf die Linienbreite gezogen) - `100%` ist damit relativ zur EIGENEN
   Breite dieser Hülle, nicht der Seite: bleibt eine reine
   transform-Animation, unabhängig von der tatsächlichen (responsiven)
   Linienbreite. Der laufende Punkt ist eine Desktop-Zugabe (ausgeblendet
   unter 700px) - die sequenziell aufblitzenden Stationsmarken tragen die
   Aussage "leuchtet beim Vorbeikommen auf" auch gestapelt am Handy. */
.prozesskette{
  position:relative; overflow:clip;
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.kette-spur{position:relative; height:3px; margin:0 15px var(--sp-6); background:var(--line); border-radius:2px}
.kette-bahn{position:absolute; inset:0; animation:kette-lauf-x var(--dauer,8s) linear infinite}
.kette-punkt{
  position:absolute; left:0; top:50%; width:13px; height:13px; margin-left:-6.5px;
  transform:translateY(-50%); border-radius:50%; background:var(--orange);
  box-shadow:0 0 0 5px rgba(255,127,50,.22);
}
@keyframes kette-lauf-x{ from{transform:translateX(0)} to{transform:translateX(100%)} }
@media(max-width:700px){ .kette-spur{display:none} }

.kette-stationen{list-style:none; display:flex; margin:0; padding:0; gap:0}
.kette-station{flex:1; min-width:0; text-align:center; padding:0 var(--sp-2)}
.kette-station .marke{
  position:relative; width:30px; height:30px; margin:0 auto var(--sp-2);
  border-radius:50%; background:var(--flaeche); border:2px solid var(--line);
}
.kette-station .glanz{
  position:absolute; inset:-6px; border-radius:50%; background:var(--orange); opacity:0;
  box-shadow:0 0 0 6px rgba(255,127,50,.22);
  animation:kette-blitz var(--dauer,8s) linear infinite; animation-delay:var(--verzoegerung,0s);
}
.kette-station .name{
  display:block; font-family:var(--font-mono); font-size:13px; color:var(--muted-stark);
  overflow-wrap:anywhere; hyphens:auto;
}
@keyframes kette-blitz{ 0%,4%{opacity:0} 7%{opacity:.85} 18%,100%{opacity:0} }
@media(max-width:700px){
  .kette-stationen{flex-direction:column; align-items:flex-start; gap:var(--sp-4)}
  .kette-station{display:flex; align-items:center; gap:var(--sp-3); text-align:left; padding:0; width:100%}
  .kette-station .marke{margin:0; flex:none}
}
@media(prefers-reduced-motion:reduce){
  .kette-bahn{animation:none}
  .kette-station .glanz{animation:none}
}

/* ─────────────── 3.19b · Geschichte (:::geschichte, Kap. 04, 29.09.2026) ───────────────
   Florian, wörtlich: "das ganze Kapitel als eine Geschichte vom Auftrag zur
   Rechnung, bei der die Kette die Bilder trägt" - ersetzt die vorige
   Kombination aus dünner Prozesskette + losem Fotoerkennungs-Satz +
   unverbundenem Cockpit-Laufband in Kapitel 04 durch EINE senkrechte
   Zeitleiste: nummerierte Knoten, Stationsname + Satz daneben, das
   passende Cockpit-Bild direkt bei der Station, die es zeigt.

   Linie: `::before` (statische Spur) + `::after` (Füllung, grün) auf dem
   `<ol>` selbst - EIN gemeinsamer Versatz `--gk-groesse` (Knotendurch-
   messer, auf `.geschichte-linie` gesetzt, vererbt an Kinder) trägt Spur
   UND Knotenmitte, ohne dass ein Wert doppelt gepflegt werden muss. Die
   Füllung ist eine reine `transform:scaleY()` (transform-origin:top) -
   hub.html setzt nur die Zahl `--fortschritt` (0..1), kein Layout-Wert
   wird animiert.

   Grundzustand (kein JS/reduzierte Bewegung) - KEINE Versteck-Regel:
   Füllung steht auf scaleY(1) ("Linie voll"), jede Station inkl. Bild ist
   normal sichtbar. Erst die Klasse "geschichte-js" (hub.html, EIGEN-
   STÄNDIGER Beobachter wie Netzkarte/Chaos - :::geschichte ist nicht an
   "js-wisch"/Stufe 1 gebunden) schaltet das Vorher-Stadium + die live
   berechnete Füllung dazu; je Station schaltet zusätzlich ein eigener
   IntersectionObserver-Eintrag "geschichte-erreicht" (Knoten leuchtet,
   Bild blendet ein). */
.geschichte{
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.geschichte-linie{
  --gk-groesse:48px;
  position:relative; list-style:none; margin:0; padding:0;
  display:flex; flex-direction:column; gap:var(--sp-7);
}
.geschichte-linie::before,.geschichte-linie::after{
  content:""; position:absolute; top:2px; bottom:2px;
  left:calc(var(--gk-groesse) / 2 - 1.5px); width:3px; border-radius:2px; z-index:0;
}
.geschichte-linie::before{background:var(--line-stark)}
.geschichte-linie::after{background:var(--frischgruen); transform-origin:top; transform:scaleY(1)}
.geschichte.geschichte-js .geschichte-linie::after{
  transform:scaleY(var(--fortschritt,0)); transition:transform .12s linear;
}
.geschichte-station{position:relative; z-index:1; display:flex; align-items:flex-start; gap:var(--sp-5)}
.geschichte-knoten{
  position:relative; flex:none; width:var(--gk-groesse); height:var(--gk-groesse);
  border-radius:50%; background:var(--flaeche); border:2px solid var(--line-stark);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-mono); font-weight:700; font-size:14px; color:var(--muted);
}
.geschichte-knoten::before{
  content:""; position:absolute; inset:-7px; border-radius:50%; background:var(--frischgruen);
  opacity:0; transform:scale(.55);
  transition:opacity .45s ease, transform .45s cubic-bezier(.22,.61,.36,1);
}
.geschichte-knoten .geschichte-nr{position:relative; z-index:1}
.geschichte-station.geschichte-erreicht .geschichte-knoten{
  background:var(--frischgruen); border-color:var(--frischgruen); color:var(--navy);
}
.geschichte-station.geschichte-erreicht .geschichte-knoten::before{opacity:.4; transform:scale(1)}
.geschichte-rahmen{flex:1; min-width:0; display:flex; align-items:center; gap:var(--sp-5); flex-wrap:wrap; padding-top:4px}
.geschichte-text{flex:1 1 260px; min-width:0}
.geschichte-text h3{font-family:var(--font-anzeige); font-size:20px; margin-bottom:4px}
.geschichte-text p{margin:0}
.geschichte-station.kompakt .geschichte-text{max-width:62ch}
.geschichte-bild{margin:0; flex:1 1 340px; max-width:55%}
.geschichte-bild img{width:100%; height:auto; display:block; border-radius:var(--r-card); box-shadow:var(--schatten-karte)}
.geschichte-bild figcaption{margin-top:var(--sp-2); font-size:13px; color:var(--muted); text-align:center}
.geschichte.geschichte-js .geschichte-station .geschichte-bild{
  opacity:0; transform:translateY(22px) scale(.96);
  transition:opacity .55s ease, transform .55s cubic-bezier(.22,.61,.36,1);
}
.geschichte.geschichte-js .geschichte-station.geschichte-erreicht .geschichte-bild{opacity:1; transform:translateY(0) scale(1)}
@media(max-width:700px){
  .geschichte-linie{--gk-groesse:34px; gap:var(--sp-6)}
  .geschichte-knoten{font-size:11.5px}
  .geschichte-rahmen{flex-direction:column; align-items:stretch}
  .geschichte-bild{max-width:none}
}
@media(prefers-reduced-motion:reduce){
  /* Eigenständige Absicherung, wie bei Netzkarte/Chaos (die JS-Bedingung
     prüft dasselbe bereits VOR dem Setzen der Klasse). */
  .geschichte-linie::after{transform:scaleY(1) !important}
  .geschichte-knoten::before{display:none}
  .geschichte.geschichte-js .geschichte-station .geschichte-bild{opacity:1 !important; transform:none !important}
}

/* ─────────────────── 3.20 · Fundament (:::fundament, 29.09.2026, ersetzt :::branchen in Kap. 06) ───────────────────
   Florian, wörtlich: unten ein breites Fundament (Core), darauf baut sich
   Clean als großer Block auf, daneben ploppen die Vorhaben gestaffelt auf.
   Das gestaffelte Aufploppen nutzt DENSELBEN Kapitel-weiten "Wisch"-
   Beobachter wie der Rest von Stufe 1 (`.kapitel.wisch-sichtbar`, 3.2c) -
   kein zweiter Observer, nur eine `--i`-gestaffelte Verzögerung je Karte. */
.fundament{
  margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.fundament-baukasten{
  display:flex; align-items:flex-end; gap:var(--sp-4); flex-wrap:wrap;
  padding:var(--sp-5) var(--sp-5) 0;
}
.fundament-heute{
  flex:1 1 260px; max-width:320px; background:var(--navy); color:#fff;
  border-radius:var(--r-card) var(--r-card) 0 0; padding:var(--sp-5);
  min-height:200px; display:flex; flex-direction:column; justify-content:flex-end;
}
.fundament-heute .status{
  display:inline-block; align-self:flex-start; font-family:var(--font-mono); font-size:12.5px;
  font-weight:700; letter-spacing:.08em; text-transform:uppercase; padding:3px 9px;
  border-radius:var(--r-btn); background:var(--frischgruen); color:var(--navy); margin-bottom:var(--sp-3);
}
.fundament-heute h3{font-size:19px; margin-bottom:6px}
.fundament-heute p{font-size:14px; color:rgba(255,255,255,.85); margin:0}
.fundament-morgen-reihe{flex:2 1 320px; display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--sp-3)}
.fundament-morgen{
  flex:1 1 150px; min-width:0; background:var(--flaeche); border:1.5px solid var(--line);
  border-radius:var(--r-card); padding:var(--sp-4);
}
/* Leichtes, deterministisches Staffeln der Standhöhe - jede zweite Karte
   sitzt etwas höher, wie "aufploppende" Vorhaben. Keine Zufallszahl. */
.fundament-morgen:nth-child(odd){margin-bottom:var(--sp-4)}
.fundament-morgen .status{
  display:inline-block; font-family:var(--font-mono); font-size:12.5px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; padding:3px 9px; border-radius:var(--r-btn);
  background:var(--hellorange); color:var(--muted); margin-bottom:var(--sp-2);
}
.fundament-morgen h3{font-size:15.5px; margin-bottom:2px}
.fundament-morgen p{font-size:13px; color:var(--muted); margin:0}
.fundament-basis{
  background:var(--tiefgruen); color:#fff; border-radius:var(--r-card); padding:var(--sp-5); text-align:center;
}
.fundament-basis-label{
  display:block; font-family:var(--font-anzeige); font-weight:800; font-size:17px; margin-bottom:4px;
}
.fundament-basis p{font-size:13.5px; color:rgba(255,255,255,.85); max-width:60ch; margin:0 auto}
@media(max-width:700px){
  .fundament-baukasten{flex-direction:column; align-items:stretch; padding:var(--sp-4) var(--sp-4) 0}
  .fundament-heute{max-width:none; border-radius:var(--r-card)}
  .fundament-morgen:nth-child(odd){margin-bottom:0}
}
.js-wisch .stufe1 .kapitel .fundament-morgen{
  opacity:0; transform:translateY(18px) scale(.94);
  transition:opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--i,0) * 120ms + .15s);
}
.js-wisch .stufe1 .kapitel.wisch-sichtbar .fundament-morgen{opacity:1; transform:translateY(0) scale(1)}

/* 29.09.2026, "mehr Symbolik" (Florian): jede Fundament-Karte bekommt ein
   Icon (bauen.py `_fundament_symbol_markup`, ueber das erste Wort des
   Titels). Aufploppen haengt an DEMSELBEN Kapitel-Beobachter wie die
   Karten selbst (`.kapitel.wisch-sichtbar`) - kein neuer JS-Code, nur
   eine zusaetzliche Regel hier. `stroke:currentColor` uebernimmt die
   Textfarbe der jeweiligen Karte (dunkel auf den hellen Vorhaben-Karten,
   weiss auf Heute/Basis). */
.fundament-symbol-huelle{display:inline-flex; margin-bottom:var(--sp-2)}
.fundament-symbol{width:38px; height:38px; fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round}
.fundament-heute .fundament-symbol,.fundament-basis .fundament-symbol{width:46px; height:46px}
.fundament-morgen .fundament-symbol-huelle{color:var(--tiefgruen)}
.fundament-heute .fundament-symbol-huelle,.fundament-basis .fundament-symbol-huelle{color:#fff}
.js-wisch .stufe1 .kapitel .fundament-symbol-huelle{
  opacity:0; transform:scale(.55);
  transition:opacity .4s ease, transform .4s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--i,0) * 120ms + .05s);
}
.js-wisch .stufe1 .kapitel.wisch-sichtbar .fundament-symbol-huelle{opacity:1; transform:scale(1)}
.fundament-module-chips{display:flex; gap:var(--sp-2); margin-top:var(--sp-3)}
.modul-symbol{width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; color:rgba(255,255,255,.85)}

/* ─────────────────── 3.21 · Treppe (:::treppe, 29.09.2026, ersetzt die Tabelle in Kap. 07) ───────────────────
   Florian, wörtlich: eine aufsteigende Treppe, jede Stufe eine Karte, die
   beim Scrollen gestaffelt einfährt; alle vier Spalteninhalte bleiben
   sichtbar. Karte UND Einzug schrumpfen ab 760px gemeinsam von der rechten
   Kante her (dieselbe Breite wird abgezogen) - dadurch kann bei keiner
   Fensterbreite etwas über die Bühne hinausragen. Vier Felder liegen in
   einem `auto-fit`-Grid, nie in festen Spalten - kein Feld wird per Media
   Query weggelassen, nur umgebrochen. */
.treppe{
  list-style:none; margin:var(--sp-7) auto; padding:0; max-width:var(--breite-daten);
  display:flex; flex-direction:column; gap:var(--sp-3);
}
.treppe-karte{
  background:var(--flaeche); border:1.5px solid var(--line); border-left:4px solid var(--tiefgruen);
  border-radius:var(--r-card); padding:var(--sp-4) var(--sp-5);
  display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--sp-3) var(--sp-5);
}
.treppe-feld{display:flex; flex-direction:column; gap:2px; min-width:0; overflow-wrap:anywhere}
.treppe-feld .label{
  font-family:var(--font-mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted);
}
.treppe-feld .wert{font-size:14.5px; color:var(--ink); font-weight:600}
@media(min-width:760px){
  .treppe-stufe{margin-left:calc(var(--i,0) * 40px); max-width:calc(100% - var(--i,0) * 40px)}
}
.js-wisch .stufe1 .kapitel .treppe-stufe{
  opacity:0; transform:translateX(-16px);
  transition:opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--i,0) * 110ms + .1s);
}
.js-wisch .stufe1 .kapitel.wisch-sichtbar .treppe-stufe{opacity:1; transform:translateX(0)}

/* ─────────────────── 3.22 · Großzahlen (:::grosszahlen, 29.09.2026) ───────────────────
   Kennzahl-Kacheln, größer/lauter als die ruhigen `.kennzahl`-Kacheln aus
   3.6 (Stufe 2) - passend zur Pitch-Bühne. Zählt über DIESELBE Mechanik
   hoch wie hervorgehobene Zahlen im Fließtext (`.zahl-lauf`, siehe
   bauen.py `_hebe_zahlen_hervor` + hub.html `wischZaehleHoch`). */
.grosszahlen{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:var(--sp-4);
  margin-top:var(--sp-6); margin-bottom:var(--sp-6); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten));
}
.grosszahl-kachel{
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-6) var(--sp-5); text-align:center;
}
.grosszahl-kachel .zahl{
  display:block; font-family:var(--font-anzeige); font-weight:800; font-size:var(--f-zahl);
  color:var(--tiefgruen); font-variant-numeric:tabular-nums; line-height:1.05;
}
.grosszahl-kachel .label{display:block; margin-top:var(--sp-2); font-size:14.5px; color:var(--muted)}

/* ─────────────────── 3.23 · CTA-Knopf (:::cta, 29.09.2026) ───────────────────
   Großer, leuchtender, pulsierender Knopf, echtes `<a href>`. Der Puls ist
   ein `::before`-Ring dahinter (eigene Stapel-Ebene über `isolation:isolate`,
   damit `z-index:-1` nicht hinter FREMDE Elemente rutscht) - animiert wird
   ausschließlich `opacity`/`transform` (scale), nie Breite/Schatten. */
.cta-block{text-align:center; margin:var(--sp-7) 0}
.cta-knopf{
  position:relative; isolation:isolate; display:inline-block;
  font-family:var(--font-anzeige); font-weight:800; font-size:17px; color:var(--navy);
  background:var(--frischgruen); padding:16px 40px; border-radius:var(--r-btn); text-decoration:none;
  transition:background .2s ease, transform .2s ease;
}
.cta-knopf:is(:hover,:focus-visible){background:#fff; transform:translateY(-2px)}
.cta-knopf::before{
  content:""; position:absolute; inset:0; z-index:-1; border-radius:inherit;
  background:var(--frischgruen); opacity:.5; transform:scale(1);
  animation:cta-puls 2.2s ease-out infinite;
}
@keyframes cta-puls{ 0%{opacity:.5; transform:scale(1)} 75%,100%{opacity:0; transform:scale(1.45)} }
@media(prefers-reduced-motion:reduce){ .cta-knopf::before{animation:none; opacity:0} }
/* :::cta in Schritte-Form (07.10.2026): Knopf klappt eine nummerierte
   Schrittliste auf, statt direkt zu waehlen/mailen. */
.cta-schritte > summary{list-style:none; cursor:pointer}
.cta-schritte > summary::-webkit-details-marker{display:none}
.cta-schritte > summary::after{content:" ↓"}
.cta-schritte[open] > summary::after{content:" ↑"}
.cta-schritte[open] > summary{background:#fff; box-shadow:inset 0 0 0 1.5px var(--tiefgruen)}
.cta-schritte[open] > summary::before{animation:none; opacity:0}
.cta-schritte-liste{
  text-align:left; max-width:620px; margin:var(--sp-5) auto 0; padding:var(--sp-5) var(--sp-5) var(--sp-5) calc(var(--sp-5) + 1.4em);
  background:#fff; border:1px solid var(--line); border-radius:16px; line-height:1.6;
}
.cta-schritte-liste li{margin:0 0 var(--sp-3)}
.cta-schritte-liste li:last-child{margin-bottom:0}
.cta-schritte-liste li::marker{font-weight:800; color:var(--tiefgruen)}

/* ─────────────────────────────── 4 · Druck ─────────────────────────────── */
@media print{
  .no-print,nav,.klapper{display:none !important}
  body{background:#fff !important; color:#000 !important; font-size:12.5pt}
  .seite,.lese-spalte{max-width:none}
  /* 02.10.2026, Breiten-Erweiterung: `.mit-navleiste` traegt jetzt ein
     eigenes max-width/padding fuer den Bildschirm (s. 3.15) — im Druck
     gilt wie bei `.seite`/`.lese-spalte` darueber: volle Papierbreite,
     kein Aussenrand-Rest. */
  .mit-navleiste{max-width:none; padding:0}
  .kapitel{break-inside:avoid-page; padding:24px 0}
  .kapitel + .kapitel{break-before:page; border-top:0}
  .traum-titel{background:#fff !important; color:#000 !important; padding:24px 0}
  .traum-titel::before{display:none}
  .traum-titel .satz em{color:#000}
  .traum-titel .unter{color:#000}
  .kapitel-kopf .nr{color:#000 !important; -webkit-text-stroke:0; opacity:.35}
  .kennzahl,.branchenkarte,.kontakt,.tabelle-scroll,.topf .gefaess{
    box-shadow:none !important; border:1px solid #000 !important;
  }
  table.jahre thead th{background:#eee !important; color:#000 !important}
  table.jahre tbody tr:nth-child(even) td{background:#f4f4f4 !important}
  .tabelle-scroll,.tabelle-rahmen{overflow:visible; box-shadow:none}
  .stufenmarke.s1{background:#fff !important; border:1px solid #000; color:#000 !important}
  .stufenmarke.s1 .punkt{background:#000}
  .phase .punkt{border:1.5px solid #000 !important; background:#fff !important; color:#000 !important}
  .phase.erreicht .punkt{background:#000 !important; color:#fff !important}
  /* `.aktiv` unterschied sich im Druck bisher NICHT von `.offen" (beide
     schwarze Kontur, weiß, schwarzer Text) — Orange trägt im Druck keine
     Information. Jetzt gestrichelt statt durchgezogen, damit alle drei
     Zustände auch in Schwarz-Weiß auseinanderzuhalten sind. */
  .phase.aktiv .punkt{border:1.5px dashed #000 !important; background:#fff !important; color:#000 !important}
  .kreislauf .pfeil,.kreislauf .kn-flaeche{stroke:#000 !important}
  .netzkarte .nk-laender{filter:none !important}
  .netzkarte .nk-land{fill:#fff !important; stroke:#000 !important}
  .netzkarte .nk-linie{stroke:#000 !important; stroke-dashoffset:0 !important; opacity:1 !important}
  .netzkarte .nk-punkt{fill:#000 !important; opacity:1 !important; transform:none !important}
  .netzkarte .nk-punkt-puls{animation:none !important}
  a{color:#000 !important; text-decoration:underline}
  /* 16.09.: die drei neuen Bauteile — Navleiste, Frageassistent-Knopf/
     Panel sind reine Bildschirm-Bedienelemente, kein Inhalt. „Auf einen
     Blick" bleibt gedruckt (echter Inhalt), nur die Sprung-Pfeile/Hover-
     Optik ergeben im Papier keinen Sinn mehr. */
  .navleiste-knopf,.navleiste,.frage-knopf,.frage-panel{display:none !important}
  .mit-navleiste{display:block !important}
  .navleiste-inhalt{padding-left:0 !important}
  .blick-zeile{border:1px solid #000; border-top:1px solid #000 !important}
  .blick-zeile .ziel::after{content:none}
  .blick-kachel{border:1px solid #000 !important}

  /* "Der Wisch" (28.09.) im Druck: alles sofort vollstaendig sichtbar, keine
     Bewegung, keine ungeoeffnete Flaeche - ein Ausdruck darf NIE zeigen,
     was gerade zufaellig noch nicht "freigewischt" wurde. */
  .traum-titel .wisch-canvas,.traum-titel .wisch-besen-canvas{display:none}
  .js-wisch .stufe1 .kapitel{opacity:1 !important; clip-path:none !important; transform:none !important}
  .wisch-leiste{display:none}
  .laufband{overflow:visible; mask-image:none; -webkit-mask-image:none}
  .laufband-spur{animation:none; flex-wrap:wrap; width:auto}
  .laufband-gruppe:nth-child(2){display:none}
  .kreislauf .wanderpunkt{display:none}
  .bild-block img,.bild-reihe img,.laufband img{box-shadow:none !important; border:1px solid #000 !important}

  /* 29.09. "Mehr pitchy": neue Bausteine im Druck immer im FERTIGEN,
     bewegungslosen Zustand - unabhaengig davon, ob vor dem Drucken schon
     gescrollt/gesehen wurde (ein Ausdruck darf nie einen Zwischenzustand
     zeigen, siehe "Der Wisch" oben). */
  .js-wisch .stufe1 .leitsatz .wort{opacity:1 !important; transform:none !important; transition:none !important}
  .js-wisch .stufe1 .kapitel-kopf .nr{transform:none !important}
  .chaos-feld.chaos-js .chaos-chip{transform:none !important; transition:none !important}
  .kette-spur{display:none}
  .kette-station .glanz{display:none}
  .js-wisch .stufe1 .kapitel .fundament-morgen,
  .js-wisch .stufe1 .kapitel .treppe-stufe{opacity:1 !important; transform:none !important; transition:none !important}
  .fundament-heute,.fundament-basis{background:#fff !important; color:#000 !important; border:1px solid #000 !important}
  .fundament-heute .status,.fundament-morgen .status{background:#fff !important; color:#000 !important; border:1px solid #000 !important}
  .fundament-morgen,.grosszahl-kachel,.treppe-karte{border:1px solid #000 !important; box-shadow:none !important}
  .bild-block.scan .scan-spur,.bild-block.scan .scan-rand{display:none !important}
  .cta-knopf::before{display:none !important}
  .cta-knopf{background:#fff !important; color:#000 !important; border:1.5px solid #000 !important}

  /* Kap. 04 Geschichte: Linie voll, jede Station/jedes Bild sofort fertig. */
  .geschichte-linie::after{transform:scaleY(1) !important}
  .geschichte-linie::before,.geschichte-linie::after{background:#000 !important}
  .geschichte-knoten{border:1.5px solid #000 !important; background:#fff !important; color:#000 !important}
  .geschichte-knoten::before{display:none !important}
  .geschichte.geschichte-js .geschichte-station .geschichte-bild{opacity:1 !important; transform:none !important}
  .geschichte-bild img{box-shadow:none !important; border:1px solid #000 !important}

  /* Fundament-Symbole: sofort sichtbar, Chips ohne Deckkraftreduzierung. */
  .fundament-symbol-huelle{opacity:1 !important; transform:none !important}
  .modul-symbol{color:#000 !important}

  /* Kap. 08 Netzkarte, vollbreit/ohne Zahlen: keine Sticky-Strecke, kein
     Ausbrechen aus dem Satzspiegel, die vollstaendige 40-Punkte-SVG (nie
     das Canvas - das existiert im Druck ohnehin nicht) + die fertig
     gezeichnete Kurve, dieselbe Schwarz-Weiss-Logik wie ueberall sonst. */
  .netzkarte-szene{
    height:auto !important; margin-left:0 !important; margin-right:0 !important; max-width:none !important;
  }
  .netzkarte-sticky{position:static !important; height:auto !important}
  .netzkarte-sticky .netzkarte{height:auto !important; aspect-ratio:600/725}
  .nk-canvas{display:none !important}
  .netzkarte-overlay{position:static !important}
  .netzkarte-leitsatz{
    color:#000 !important; background:#fff !important; box-shadow:none !important;
    border:1px solid #000 !important;
  }
  .nk-akt-punkt{background:#fff !important; color:#000 !important; border:1px solid #000 !important; box-shadow:none !important}
  .nk-kurve-betriebe{stroke:#666 !important}
  .nk-kurve-verbindungen{stroke:#000 !important}
  .nk-kurve-punkt-betriebe{fill:#666 !important}
  .nk-kurve-punkt-verbindungen{fill:#000 !important}
  .nk-kurve-wortlabel.gross,.nk-kurve-wortlabel.klein{fill:#000 !important}
  .nk-akt-block.nk-akt-2.nk-akt-sichtbar-js .nk-kurve-linie{stroke-dashoffset:0 !important}
}

/* 28.09. Narrative-Einbau: acht Vorteilskarten (Kap. 03) als 4+4-Raster,
   ohne Silbentrennung; Persona-Tabelle (Kap. 07) darf im Lesemaß umbrechen. */
.branchenexpansion.karten-8{display:grid; grid-template-columns:repeat(4,minmax(0,1fr))}
.branchenexpansion.karten-8 .branchenkarte{hyphens:manual; overflow-wrap:normal}
@media(max-width:900px){.branchenexpansion.karten-8{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.branchenexpansion.karten-8{grid-template-columns:1fr}}
.stufe1 .tabelle-rahmen th,.stufe1 .tabelle-rahmen td{white-space:normal; vertical-align:top}
.stufe1 .tabelle-rahmen table{width:100%; min-width:0}

/* 28.09. Florian: "Der Text ist zu schmal zu den Bildern, es ist nicht
   stimmig." Stufe 1: Lesespalte auf die Bühnenbreite der Bilder/Bänder
   (--breite-daten) ziehen, statt 60ch neben 960px-Bildern. Ab Laptop-
   breite; am Handy ändert sich nichts (dort ist beides randbündig). */
@media(min-width:900px){
  /* Florian-Befund 05.10.2026, 1024px: zwischen 900 und 1279px reicht
     --breite-daten (960px) bis knapp an den Seitenrand - `.seite` traegt
     ueberall nur die uebliche 24px-Polsterung, keine zusaetzliche. Bei
     1024px blieben dadurch links/rechts der Lesespalte nur ~8px Luft
     OBERHALB dieser Polsterung (~32px vom Fensterrand, exakt Florians
     Messwert); zwischen 900 und ~1007px gab es sogar GAR keine (reine
     24px) - die Lesespalte fuellte dort randlos die gesamte `.seite`. Die
     Buehne (`--breite-buehne`, bis 1279px konstant 820px) bleibt in
     derselben Spanne klar eingerueckt (40-230px je nach Breite) - ein
     sichtbarer Bruch genau am Uebergang Buehne→Lesetext.
     `min(var(--breite-daten), calc(100% - 32px))` haelt die bewusste
     28.09.-Kopplung an --breite-daten (die diese Regel ueberhaupt erst
     eingefuehrt hat: "Text zu schmal zu den Bildern") UNVERAENDERT bei,
     sobald wieder genug Platz da ist (ab ~1030px bindet weiterhin
     --breite-daten, keine Aenderung dort) - sorgt aber fuer MINDESTENS
     16px Luft je Seite oberhalb der Polsterung (40px vom Fensterrand) in
     der ganzen 900-1279px-Spanne, statt der bisherigen 0-8px. */
  /* auf .stufe1 selbst setzen - dort steht sonst --mass-lese:60ch und gewinnt per Vererbung */
  body.stufe1, body.stufe1 .stufe1{--mass-lese:min(var(--breite-daten), calc(100% - 32px))}
  body.stufe1 .lese-spalte{max-width:var(--mass-lese)}
  /* `.text`/`.klartext` bleiben bewusst auf --breite-daten (nicht --mass-
     lese): sie sitzen praktisch immer INNERHALB von `.lese-spalte` und
     koennen ohnehin nie breiter werden als deren eigener Inhaltsbereich -
     eine zweite, hier identische Deckelung wuerde nur unnoetig verschachtelt
     rechnen (ihr "100%" bezieht sich dann auf die schon engere Lesespalte,
     nicht mehr auf `.seite`). */
  body.stufe1 .text,body.stufe1 .klartext{max-width:var(--breite-daten)}
}

/* 29.09. gekürzte Fassung: Kap. 06 hat nur noch VIER Branchenkarten
   (Clean · Capital · Care · Courier) → eine Reihe statt 3+1; Kap. 03 zwei
   getrennte Vorteilsgruppen (3 + 5); Kap. 09 ein Team aus fünf Karten,
   Gründer zuerst und breiter. Nur Stufe 1, ab Laptopbreite. */
@media(min-width:760px){
  body.stufe1 .branchenexpansion:has(.branchenkarte.heute) .branchenkarte{
    flex:0 1 calc((100% - 3*18px - 6*var(--sp-2)) / 4); max-width:none;
  }
  body.stufe1 .branchenexpansion:has(.branchenkarte.heute) .pfeil-weiter:nth-of-type(3){
    flex:0 0 18px; height:auto; overflow:visible;
  }
  body.stufe1 .branchenexpansion:has(.branchenkarte.heute) .pfeil-weiter:nth-of-type(3)::before{content:"→"}
  body.stufe1 .branchenexpansion.karten-3,
  body.stufe1 .branchenexpansion.karten-5{display:grid; gap:var(--sp-3)}
  body.stufe1 .branchenexpansion.karten-3{grid-template-columns:repeat(3,minmax(0,1fr))}
  body.stufe1 #kap-1-3 .branchenexpansion.karten-5{grid-template-columns:repeat(3,minmax(0,1fr))}
  body.stufe1 #kap-1-9 .branchenexpansion.karten-5{grid-template-columns:repeat(6,minmax(0,1fr))}
  body.stufe1 #kap-1-9 .branchenexpansion.karten-5 .branchenkarte{grid-column:span 2}
  body.stufe1 #kap-1-9 .branchenexpansion.karten-5 .branchenkarte:nth-child(-n+2){grid-column:span 3}
  /* 05.10.2026: mit Joachim sechs Team-Karten → 3 + 3 */
  body.stufe1 #kap-1-9 .branchenexpansion.karten-6{display:grid; gap:var(--sp-3); grid-template-columns:repeat(3,minmax(0,1fr))}
  body.stufe1 #kap-1-9 .branchenexpansion.karten-6 .branchenkarte{hyphens:manual; overflow-wrap:normal; max-width:none}
  body.stufe1 .branchenexpansion.karten-3 .branchenkarte,
  body.stufe1 .branchenexpansion.karten-5 .branchenkarte{hyphens:manual; overflow-wrap:normal}
}

/* 29.09. Sichtprüfung: Scan-Rahmen hug das Bild (war volle Breite neben
   schmalem Handy); Treppe steigt nach oben (Horst unten, Alexander oben) –
   passend zu „Unten starten. Nach oben skalieren.“ DOM-Reihenfolge bleibt. */
.bild-block.scan .scan-rahmen{display:inline-block; max-width:100%; vertical-align:top}
@media(min-width:760px){
  .treppe{display:flex; flex-direction:column-reverse}
}

/* 29.09. Prüfer-Befund: Parallax-Kapitelnummer überlappt am Handy die
   Eyebrow-Zeile ("KAPITEL 02") – Parallax nur ab Laptopbreite. */
@media(max-width:1023px){
  .kapitel-kopf .nr{transform:none !important}
}

/* 29.09. Kap. 03 „Vieles mehr“ als sechste Soft-Karte → 3+3-Raster. */
@media(min-width:760px){
  body.stufe1 #kap-1-3 .branchenexpansion.karten-6{display:grid; gap:var(--sp-3); grid-template-columns:repeat(3,minmax(0,1fr))}
  body.stufe1 #kap-1-3 .branchenexpansion.karten-6 .branchenkarte{hyphens:manual; overflow-wrap:normal}
}

/* 29.09., fünfter Netzkarte-Durchgang: die frühere Wellen-Sichtbarkeit der
   SVG-Punkte ("netzkarte-wellen-js"/"nk-sichtbar") ist raus - die SVG ist
   jetzt IMMER der vollständige, statische No-JS-/Canvas-Zustand (siehe
   3.10c), die Basis-Puls-Animation aus 3.10b läuft deshalb ungegated. */
.netzkarte.netzkarte-canvas-js .nk-punkt-puls{animation:none}

/* 29.09. Kanten-Messung: ab 900px ist die Stufe-1-Lesespalte schon auf
   --breite-daten gezogen (Regel "Text zu schmal zu den Bildern") - dort
   darf der 768px-Versatz nicht mehr greifen, sonst stehen die Bausteine
   158px rechts der Textkante. 05.10.2026: ueber `var(--mass-lese)` statt
   `var(--breite-daten)` neu berechnet (`--mass-lese` traegt seit der
   1024px-Korrektur oben denselben `min(...)`-Rand-Schutz) - sonst wuerden
   die Datenbausteine (Bilder/Tabellen) in genau der 900-1279px-Spanne, in
   der die Lesespalte jetzt etwas eingerueckter steht, den linken Gleichlauf
   mit ihr verlieren. */
@media(min-width:900px){
  body.stufe1, body.stufe1 .stufe1{--daten-versatz:max(0px, calc((100% - var(--mass-lese)) / 2))}
}

/* 02.10.2026, Breiten-Erweiterung: --breite-daten wächst ab 1280px weiter
   (tokens.css) — für Kacheln/Tabellen/Grafiken genau richtig, für den
   FLIESSTEXT in Stufe 1 (an --breite-daten gekoppelt seit der Regel oben)
   wäre das auf 2560px über 130 Zeichen pro Zeile, deutlich über Florians
   Lesbarkeits-Vorgabe (~65–80 Zeichen). Die Lesespalte bleibt deshalb ab
   hier bei einer EIGENEN, nicht mitwachsenden Breite stehen (900px ≈ 79
   Zeichen bei der um 1px größeren Stufe-1-Schrift, siehe `:where(.stufe1)
   .text` oben) — Bilder/Kacheln/Tabellen dürfen über --breite-daten weiter
   wachsen. `--daten-versatz` wird hier bewusst MIT genau dieser festen
   Lesebreite neu berechnet (nicht --breite-daten) — sonst verliert die
   linke Kante der Datenbausteine den Gleichlauf mit der jetzt schmaleren
   Lesespalte, exakt das Problem, das der Block direkt darüber für 900px
   schon einmal gelöst hat. Rechts dürfen Bilder/Tabellen trotzdem breiter
   enden als der Text — ein übliches Magazin-Muster, kein Fehler. */
@media(min-width:1280px){
  body.stufe1{--mass-lese:900px}
  body.stufe1 .lese-spalte,body.stufe1 .text,body.stufe1 .klartext{max-width:900px}
  body.stufe1, body.stufe1 .stufe1{--daten-versatz:max(0px, calc((100% - 900px) / 2))}
}

/* 29.09. Sichtprüfung: Leitsatz-Kästchen verdeckte unten links die Schweiz -
   auf breiten Bildschirmen rechts in die freie Fläche neben Österreich. */
@media(min-width:1100px){
  .netzkarte-overlay-unten{align-self:flex-end; align-items:flex-end; text-align:right}
}

/* 29.09.: ohne Akt-Indikator rutschte der Leitsatz nach oben unter die
   Kopfleiste - wieder nach unten druecken. */
.netzkarte-overlay-unten{margin-top:auto}

/* 29.09. Kontaktkarten Kap. 10 (Florian: "schoen anordnen"). */
.kontaktkarten{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-3);
  margin:var(--sp-6) 0 var(--sp-6) var(--daten-versatz,0); width:min(calc(100% - var(--daten-versatz,0px)), var(--breite-daten))}
.kontaktkarte{background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-4) var(--sp-5); box-shadow:var(--schatten-karte); display:flex; flex-direction:column; gap:4px}
.kontaktkarte .kk-name{margin:0; font-family:var(--font-anzeige); font-weight:800; font-size:20px; color:var(--navy)}
.kontaktkarte .kk-rolle{margin:0 0 8px; font-size:var(--f-small); color:var(--muted)}
.kontaktkarte .kk-zeile{color:var(--tiefgruen); text-decoration:none; font-weight:600; width:fit-content}
.kontaktkarte .kk-zeile:hover{text-decoration:underline}
@media(max-width:700px){ .kontaktkarten{grid-template-columns:1fr} }
@media print{ .kontaktkarte{box-shadow:none !important; border:1px solid #000 !important} }

/* 29.09. Geraete-Test: auf sehr breiten Monitoren (Ultrawide) stand der
   Netz-Leitsatz am aeussersten Rand - Overlay auf die Inhaltsbreite begrenzen. */
@media(min-width:1500px){
  .netzkarte-overlay{left:max(0px, calc(50% - 680px)); right:max(0px, calc(50% - 680px))}
}

/* Safari/WebKit: Knoepfe erben die Schrift NICHT (zeigten Times) - 29.09. */
button, input, select, textarea { font-family: inherit; }

/* Kleine Handys (320px): ein langes Wort im Leitsatz ragte ueber den Rand - 29.09. */
.stufe1 .leitsatz p{hyphens:auto; -webkit-hyphens:auto; overflow-wrap:break-word}
.js-wisch .stufe1 .leitsatz .wort{max-width:100%}

/* ─────────────────── 3.24 · Balken (:::balken, Stufe-2-Umbau 30.09.2026) ───────────────────
   Ruhiges, waagerechtes Balkendiagramm für Stufe 2 (Florian 29.09.: gleiche
   Optik wie Stufe 1, aber sachlicher, mehr Zahlen). Statisch – keine
   Animation, kein Beobachter; steht ohne JS und im Druck vollständig da.
   Drei Spalten (Beschriftung · Spur · Wert), unter 560px bricht der Wert
   unter die Spur, damit bei 390px nichts seitlich übersteht. */
.balken{
  margin-top:var(--sp-6); margin-bottom:var(--sp-6); margin-inline:var(--daten-versatz,0px) 0;
  width:min(calc(100% - var(--daten-versatz,0px)), var(--breite-daten));
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-5); box-shadow:var(--schatten-karte); box-sizing:border-box;
}
.balken-titel{
  font-family:var(--font-mono); font-size:var(--f-micro); letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--sp-4);
}
.balken-liste{list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-3)}
.balken-zeile{
  display:grid; grid-template-columns:minmax(0,13em) minmax(0,1fr) minmax(6.5em,auto);
  align-items:center; gap:var(--sp-3); min-width:0;
}
.balken-label{font-size:14.5px; color:var(--ink); min-width:0; overflow-wrap:anywhere}
.balken-spur{display:block; height:14px; border-radius:var(--r-btn); background:var(--flaeche-tief); overflow:hidden; min-width:0}
.balken-fuell{display:block; height:100%; width:var(--anteil); border-radius:var(--r-btn); background:var(--tiefgruen); opacity:.55}
.balken-wert{font-family:var(--font-anzeige); font-weight:700; font-size:15px; color:var(--ink);
  font-variant-numeric:tabular-nums; text-align:right; white-space:nowrap}
.balken-zeile.hervor .balken-label{font-weight:700}
.balken-zeile.hervor .balken-fuell{opacity:1; background:var(--tiefgruen)}
.balken-zeile.hervor .balken-wert{color:var(--tiefgruen)}
@media(max-width:560px){
  .balken{padding:var(--sp-4)}
  .balken-zeile{grid-template-columns:minmax(0,1fr) auto; row-gap:6px}
  .balken-spur{grid-column:1 / -1; grid-row:2}
  .balken-wert{white-space:normal}
}
@media print{ .balken{box-shadow:none !important; border:1px solid #000 !important}
  .balken-fuell{background:#000 !important; opacity:1 !important; width:var(--anteil) !important; transition:none !important} }

/* ─────────── 3.24b · Balken wachsen beim Hereinscrollen (Umbau 30.09.2026) ───────────
   Florian: "ist gut aber zu trocken ... die Energie von Stufe 1 muss auch
   in Stufe 2 spürbar sein". Der Balken selbst bleibt bewusst wie er ist
   (ruhig, sachlich, siehe 3.24-Kommentar) - nur das FÜLLEN bekommt einen
   einmaligen Moment beim Erscheinen, wie die Kapitel-Kennzahlen in Stufe 1.
   NUR aktiv unter der Klasse "js-stufe2" (hub.html setzt sie, siehe dort -
   eigene, von "js-wisch"/Stufe 1 komplett unabhängige Klasse, damit Stufe 1
   in keinem Fall berührt wird). Ohne JS/bei reduzierter Bewegung bleibt die
   Grundregel aus 3.24 in Kraft: der Balken steht sofort in voller Länge da. */
.js-stufe2 .balken:not(.pitch-inhalt *) .balken-fuell{
  width:0; transition:width .9s cubic-bezier(.22,.61,.36,1);
}
.js-stufe2 .balken.balken-sichtbar:not(.pitch-inhalt *) .balken-fuell{width:var(--anteil)}
@media(prefers-reduced-motion:reduce){
  .js-stufe2 .balken:not(.pitch-inhalt *) .balken-fuell{width:var(--anteil) !important; transition:none !important}
}

/* ─────────── 3.25 · :::planchart / :::kassenkurve (02.10.2026, software-designer) ───────────
   Auftrag: "die Aufmerksamkeit von Stufe 1 in Stufe 2 halten" (Kap. 20
   Planrechnung, Kap. 21 Die Runde) - Saeulen Umsatz/Kosten + EBITDA-Linie
   bzw. die Liquiditaets-Linie mit Tiefpunkt/Break-even/Cashflow-Wende,
   direkt aus der Planrechnung gezeichnet (bauen.py render_planchart/
   render_kassenkurve - KEINE Zahl im Markdown). Dieselbe ruhige Karten-
   Optik wie .balken (3.24). Die SVG-Grafik selbst ist dekorativ (keine
   Textknoten drin - ein Diagramm, das mit der Containerbreite mitschrumpft,
   wuerde eingebetteten SVG-Text proportional mitschrumpfen lassen und waere
   auf dem Handy unleserlich, siehe Gedaechtnis "handybreite-ist-kein-
   handy") - die echten Zahlen stehen daneben als normaler HTML-Text
   (Jahrestabelle/Kennzahlen-Kacheln), immer lesbar, auch ohne JS/im Druck. */
.planchart,.kassenkurve{
  margin-top:var(--sp-6); margin-bottom:var(--sp-6); margin-inline:var(--daten-versatz,0px) 0;
  width:min(calc(100% - var(--daten-versatz,0px)), var(--breite-daten));
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-5); box-shadow:var(--schatten-karte); box-sizing:border-box;
}
.diagramm-titel{
  font-family:var(--font-mono); font-size:var(--f-micro); letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--sp-4);
}
.planchart-grafik,.kassenkurve-grafik{margin-bottom:var(--sp-4)}
.planchart-grafik svg,.kassenkurve-grafik svg{width:100%; height:auto; display:block}

/* Jahreszeile UNTER dem Planchart-SVG (02.10.2026, Pruefer-Befund Handybreite:
   ohne sie war am Handy unklar, welcher Balken zu welchem Jahr gehoert, bevor
   die Jahrestabelle weiter unten antippbar in Sicht kam). Reiner HTML-Text,
   `aria-hidden` (die Jahre stehen bereits im Tabellenkopf darunter) - das
   Padding kommt INLINE aus bauen.py (exakt aus den SVG-Raendern abgeleitet,
   siehe render_planchart), hier nur die Verteilung/Optik. */
.planchart-jahre{
  display:flex; justify-content:space-between; margin:-6px 0 var(--sp-4);
  font-family:var(--font-mono); font-size:11.5px; color:var(--muted);
  font-variant-numeric:tabular-nums lining-nums;
}

/* Saeulen Umsatz/Kosten + EBITDA-Linie (:::planchart). Kosten gedaempft in
   --muted (eine Kostenzeile ist keine Warnung), EBITDA-Linie in --orange -
   die Profitabilitaets-Geschichte ist der Akzent, nicht der Umsatz allein. */
.pc-saeule.pc-umsatz{fill:var(--tiefgruen); opacity:.85}
.pc-saeule.pc-kosten{fill:var(--muted); opacity:.4}
.pc-ebit-linie{fill:none; stroke:var(--orange); stroke-width:2.5px; stroke-linecap:round; stroke-linejoin:round}
.pc-ebit-punkt{fill:var(--orange); r:3.2}
.pc-ebit-punkt.pc-hervor{r:5}
.pc-nulllinie{stroke:var(--line-stark); stroke-width:1px; stroke-dasharray:4 4}

/* Legende (Farbpunkt/Linie + Wort) - reiner, immer lesbarer HTML-Text
   neben der dekorativen Grafik, keine zweite Bedeutung im SVG selbst.
   `.dl-eintrag` (02.10.2026, Pruefer-Befund Handybreite) haelt Symbol+Wort
   als EIN Flex-Kind von `.diagramm-legende` zusammen und bleibt selbst
   nowrap - vorher waren Symbol-Span und Text-Span zwei eigene Flex-Kinder
   und konnten am Handy getrennt umbrechen (Symbol Zeilenende, Wort Anfang
   der naechsten Zeile). */
.diagramm-legende{display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2) var(--sp-4);
  font-size:13.5px; color:var(--muted); margin-bottom:var(--sp-4)}
.dl-eintrag{display:inline-flex; align-items:center; white-space:nowrap}
.dl-punkt{display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:6px; vertical-align:-1px; flex-shrink:0}
.dl-punkt.pc-umsatz{background:var(--tiefgruen); opacity:.85}
.dl-punkt.pc-kosten{background:var(--muted); opacity:.4}
.dl-linie{display:inline-block; width:16px; height:2.5px; margin-right:6px; vertical-align:2px; border-radius:2px; flex-shrink:0}
.dl-linie.pc-ebit-linie{background:var(--orange)}

/* Liquiditaets-Linie + Markierungen (:::kassenkurve). Tiefpunkt/Break-even/
   Cashflow-Wende farblich unterschieden - orange = Wendepunkt (Tiefpunkt,
   Break-even), tiefgruen = der Punkt, ab dem es dauerhaft positiv bleibt. */
.kk-linie{fill:none; stroke:var(--tiefgruen); stroke-width:2.5px; stroke-linecap:round; stroke-linejoin:round}
.kk-punkt{fill:var(--flaeche); stroke:var(--tiefgruen); stroke-width:2px; r:3.4}
.kk-tiefpunkt{fill:var(--orange); r:5}
.kk-abweichung{stroke:var(--orange); stroke-width:1.5px; stroke-dasharray:3 3}
.kk-mindestkasse{stroke:var(--line-stark); stroke-width:1px; stroke-dasharray:4 4}
.kk-marke line{stroke:var(--muted); stroke-width:1px; stroke-dasharray:3 3}
.kk-marke circle{fill:var(--ink); r:3.6}
.kk-marke.kk-breakeven circle{fill:var(--orange)}
.kk-marke.kk-cashflow circle{fill:var(--tiefgruen)}

/* Kennzahlen-Kacheln unter der Kassenkurve - gleiche Sprache wie
   .blick-kachel (3.16: Zahl gross/fett, Label klein/gedaempft), nur ohne
   eigene Rahmenkarte (sitzen bereits INNERHALB der .kassenkurve-Karte). */
.kassenkurve-kennzahlen{display:flex; flex-wrap:wrap; gap:var(--sp-5); margin-bottom:var(--sp-4)}
.kk-kennzahl{display:flex; flex-direction:column; gap:2px; min-width:9em}
.kk-kennzahl .zahl{font-family:var(--font-anzeige); font-weight:800; font-size:clamp(18px,2.4vw,22px);
  color:var(--ink); font-variant-numeric:tabular-nums}
.kk-kennzahl .label{font-size:13px; color:var(--muted)}

/* Kassenkurve-Detailansicht (02.10.2026, Pruefer-Befund: der Tiefpunkt
   verschwindet auf der 0..10-Mio-Jahresskala fast) - sitzt INNERHALB der
   .kassenkurve-Karte, unter Kennzahlen/Tabelle, eigener kleiner Rahmen
   (keine zweite Schatten-Karte, nur eine Trennlinie). Die Bildunterschrift
   (`render_kassenkurve_detail`) nennt woertlich "eigene Skala" - deshalb
   hier KEINE eigene y-Achsen-Beschriftung, die mit der des Hauptcharts
   verwechselt werden koennte. Die kk-*-Klassen (Linie/Punkte/Marken) sind
   dieselben wie im Hauptchart - Farbgebung bleibt konsistent, nur kleiner
   (siehe render_kassenkurve_detail, geringere r-Werte). */
.kassenkurve-detail{
  margin-top:var(--sp-5); padding-top:var(--sp-4); border-top:1px dashed var(--line);
}
.kassenkurve-detail-titel{
  font-family:var(--font-mono); font-size:var(--f-micro); letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--sp-3);
}

@media(max-width:560px){
  .planchart,.kassenkurve{padding:var(--sp-4)}
  /* Handy: die klebende Beschriftungsspalte bricht um, damit neben ihr
     die Jahreszahlen sichtbar bleiben (sonst fuellt sie die ganze Karte). */
  .planchart table.jahre td:first-child,.planchart table.jahre th:first-child,
  .kassenkurve table.jahre td:first-child,.kassenkurve table.jahre th:first-child{
    white-space:normal; min-width:7.5em; max-width:7.5em; padding-left:12px; padding-right:10px; font-size:13px;
  }
  .planchart table.jahre caption,.kassenkurve table.jahre caption{padding-left:12px; padding-right:12px}
}
@media print{
  .planchart,.kassenkurve{box-shadow:none !important; border:1px solid #000 !important}
  .pc-saeule.pc-umsatz,.pc-saeule.pc-kosten{fill:#000 !important}
  .pc-ebit-linie,.pc-ebit-punkt,.kk-linie,.kk-punkt,.kk-tiefpunkt,.kk-abweichung,.kk-marke circle{
    stroke:#000 !important; fill:#000 !important;
  }
}

/* 3.25b · Saeulen wachsen/Linien zeichnen sich einmalig beim Hereinscrollen
   (hub.html .planchart-sichtbar/.kassenkurve-sichtbar) - exakt dieselbe
   Technik/Grundregel wie .balken-fuell (3.24b): NUR aktiv unter
   "js-stufe2", ohne JS/bei reduzierter Bewegung steht alles sofort fertig
   da (Stufe 1 bleibt dadurch in jedem Fall unberuehrt). */
.js-stufe2 .planchart:not(.pitch-inhalt *) .pc-saeule{
  transform-box:fill-box; transform-origin:center bottom; transform:scaleY(0);
  transition:transform .7s cubic-bezier(.22,.61,.36,1);
}
.js-stufe2 .planchart.planchart-sichtbar:not(.pitch-inhalt *) .pc-saeule{transform:scaleY(1)}
.js-stufe2 .planchart:not(.pitch-inhalt *) .pc-ebit-linie{
  stroke-dasharray:100; stroke-dashoffset:100; transition:stroke-dashoffset 1s cubic-bezier(.22,.61,.36,1) .35s;
}
.js-stufe2 .planchart.planchart-sichtbar:not(.pitch-inhalt *) .pc-ebit-linie{stroke-dashoffset:0}
.js-stufe2 .planchart:not(.pitch-inhalt *) .pc-ebit-punkt{opacity:0; transition:opacity .4s ease .9s}
.js-stufe2 .planchart.planchart-sichtbar:not(.pitch-inhalt *) .pc-ebit-punkt{opacity:1}
@media(prefers-reduced-motion:reduce){
  .js-stufe2 .planchart:not(.pitch-inhalt *) .pc-saeule{transform:scaleY(1) !important; transition:none !important}
  .js-stufe2 .planchart:not(.pitch-inhalt *) .pc-ebit-linie{stroke-dashoffset:0 !important; transition:none !important}
  .js-stufe2 .planchart:not(.pitch-inhalt *) .pc-ebit-punkt{opacity:1 !important; transition:none !important}
}
.js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-linie{
  stroke-dasharray:100; stroke-dashoffset:100; transition:stroke-dashoffset 1.1s cubic-bezier(.22,.61,.36,1);
}
.js-stufe2 .kassenkurve.kassenkurve-sichtbar:not(.pitch-inhalt *) .kk-linie{stroke-dashoffset:0}
.js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-punkt,
.js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-tiefpunkt,
.js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-abweichung,
.js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-marke{opacity:0; transition:opacity .5s ease .9s}
.js-stufe2 .kassenkurve.kassenkurve-sichtbar:not(.pitch-inhalt *) .kk-punkt,
.js-stufe2 .kassenkurve.kassenkurve-sichtbar:not(.pitch-inhalt *) .kk-tiefpunkt,
.js-stufe2 .kassenkurve.kassenkurve-sichtbar:not(.pitch-inhalt *) .kk-abweichung,
.js-stufe2 .kassenkurve.kassenkurve-sichtbar:not(.pitch-inhalt *) .kk-marke{opacity:1}
@media(prefers-reduced-motion:reduce){
  .js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-linie{stroke-dashoffset:0 !important; transition:none !important}
  .js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-punkt,
  .js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-tiefpunkt,
  .js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-abweichung,
  .js-stufe2 .kassenkurve:not(.pitch-inhalt *) .kk-marke{opacity:1 !important; transition:none !important}
}

/* Stufe-2-Umbau 30.09.2026: Texttabellen in Stufe 2 (Vorteile, Segmente,
   Personas) brechen um wie in Stufe 1 (siehe `.stufe1 .tabelle-rahmen` oben),
   statt als 1.600px breite Einzeiler seitlich zu scrollen. Zahlen ohne
   Leerzeichen bleiben dabei unzerteilt; reicht die Breite trotzdem nicht,
   scrollt weiterhin nur der Tabellenrahmen, nie die Seite. */
.stufe2 .tabelle-rahmen th,.stufe2 .tabelle-rahmen td{white-space:normal; vertical-align:top}
.stufe2 .tabelle-rahmen table{min-width:0}
/* 30.09. Pruefer: schmale Tabellen liessen rechts eine leere Flaeche im
   Rahmen stehen, breite schnitten ab - in Stufe 2 fuellen sie den Rahmen
   und lange Woerter trennen. */
.stufe2 .tabelle-rahmen:not(.pitch-inhalt *) table{width:100%}
.stufe2 .tabelle-rahmen:not(.pitch-inhalt *) th,.stufe2 .tabelle-rahmen:not(.pitch-inhalt *) td{hyphens:auto; -webkit-hyphens:auto; overflow-wrap:break-word; padding:10px 12px}
@media (min-width:560px){
  .stufe2 .tabelle-rahmen:not(.pitch-inhalt *) th:first-child,.stufe2 .tabelle-rahmen:not(.pitch-inhalt *) td:first-child{white-space:nowrap; hyphens:manual; -webkit-hyphens:manual}
}

/* Stufe-2-Umbau 30.09.2026: Kartenreihen (:::partnerfelder) in Stufe 2
   stehen in der schmaleren Spalte neben der Navleiste. Ein langes Wort wie
   „Verschmutzungserkennung" blies dort eine Karte auf und schob die ganze
   Seite um 40px zur Seite (gemessen bei 1024px). Deshalb in Stufe 2: Raster
   statt Flex und Silbentrennung erlaubt. Stufe 1 bleibt unberührt. */
.stufe2 .branchenexpansion:not(:has(.branchenkarte.heute)):not(.pitch-inhalt *){
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr)); gap:var(--sp-3)
}
.stufe2 .branchenexpansion:not(.pitch-inhalt *) .branchenkarte{hyphens:auto; -webkit-hyphens:auto; overflow-wrap:break-word}

/* ─────────────────── 3.25 · Preiswahl (:::preiswahl, Meeting 30.09.2026) ───────────────────
   Kap. 03: Klick auf „20 € Mitgliedschaft“ färbt alle enthaltenen Vorteile
   grün, „30 € Academy“ die Academy in Hellorange. Jede Vorteilskarte trägt
   ihre Farbmarke DAUERHAFT (statische Legende darunter) - ohne JS und bei
   reduzierter Bewegung bleibt die Zuordnung damit lesbar. Die Hervorhebung
   selbst hängt an `data-paket-aktiv` am Kapitel, gesetzt von hub.html. */
.paket-marke{display:inline-block; width:12px; height:12px; border-radius:50%; flex:none;
  border:2px solid var(--tiefgruen); background:var(--frischgruen)}
.paket-marke.paket-academy{border-color:#B85A1E; background:var(--hellorange)}
.branchenkarte.paket-karte{position:relative}
.branchenkarte.paket-karte > .paket-marke{position:absolute; top:14px; right:14px}
.paket-text{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap}
.paket-karte{transition:background-color .35s ease, border-color .35s ease, box-shadow .35s ease, transform .35s ease, opacity .35s ease}
/* 30.09. Pruefer: opacity .5 drueckte den Text auf 2,4:1 - jetzt nur Flaeche/Rand zuruecknehmen, Text bleibt lesbar */
[data-paket-aktiv] .paket-karte{background:var(--flaeche-tief); border-color:var(--line)}
[data-paket-aktiv="mitglied"] .paket-karte[data-paket="mitglied"],
[data-paket-aktiv="academy"] .paket-karte[data-paket="academy"]{opacity:1; transform:translateY(-3px)}
[data-paket-aktiv="mitglied"] .paket-karte[data-paket="mitglied"]{
  background:#E9FFE9; border-color:var(--tiefgruen); box-shadow:0 0 0 2px var(--frischgruen)}
[data-paket-aktiv="academy"] .paket-karte[data-paket="academy"]{
  background:var(--hellorange); border-color:#B85A1E; box-shadow:0 0 0 2px #FFD9BF}
.preiswahl{margin-inline:var(--daten-versatz) 0; width:min(calc(100% - var(--daten-versatz)), var(--breite-daten))}
.preiswahl .grosszahlen{margin-inline:0; width:100%; margin-bottom:var(--sp-3)}
.preiskachel{font:inherit; color:inherit; cursor:pointer; position:relative;
  transition:border-color .25s ease, box-shadow .25s ease, background-color .25s ease}
.preiskachel:hover{border-color:var(--line-stark)}
.preiskachel:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:3px}
.preiskachel-hinweis{display:block; margin-top:var(--sp-3); font-family:var(--font-mono); font-size:12.5px;
  letter-spacing:.08em; text-transform:uppercase; color:var(--muted)}
.preiskachel-hinweis::before{content:"○ "}
.preiskachel-hinweis{display:none}
.preiswahl-js .preiskachel-hinweis{display:block}
.preiskachel[aria-pressed="true"] .preiskachel-hinweis::before{content:"● "}
.preiskachel.paket-mitglied[aria-pressed="true"]{border-color:var(--tiefgruen); background:#E9FFE9; box-shadow:0 0 0 2px var(--frischgruen)}
.preiskachel.paket-academy[aria-pressed="true"]{border-color:#B85A1E; background:var(--hellorange); box-shadow:0 0 0 2px #FFD9BF}
.preiskachel.paket-academy[aria-pressed="true"] .zahl{color:var(--navy)}
.preiswahl-legende{display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-5); justify-content:center;
  font-size:14px; color:var(--muted); margin:0 0 var(--sp-6)}
.legende-eintrag{display:inline-flex; align-items:center; gap:8px}
@media (prefers-reduced-motion:reduce){
  .paket-karte,.preiskachel{transition:none}
  [data-paket-aktiv] .paket-karte{transform:none !important}
}
@media print{
  [data-paket-aktiv] .paket-karte{opacity:1 !important; background:#fff !important; box-shadow:none !important; transform:none !important}
  .preiskachel{background:#fff !important; box-shadow:none !important}
  .preiskachel-hinweis{display:none}
  .paket-text{position:static; width:auto; height:auto; clip:auto; clip-path:none; font-size:12px}
}

/* ─────────────────── 3.26 · Aufstieg (:::aufstieg, Meeting 30.09.2026, Kap. 06) ───────────────────
   Die Branchen hängen an einer Treppe „unten starten, nach oben skalieren“:
   jede Stufe ein Sockel (Höhe 16 + i·48 px, von bauen.py über --i gesetzt),
   darüber die Karte. Die Kurve (Inline-SVG, aria-hidden) läuft durch die
   Sockel-Oberkanten - dieselben Zahlen wie hier, deshalb ohne JS stimmig.
   Die C-Reihe trägt ihr „C“ als grüne Initiale. */
.aufstieg{margin-top:var(--sp-7); margin-bottom:var(--sp-7); margin-inline:var(--daten-versatz) 0;
  width:min(calc(100% - var(--daten-versatz)), var(--breite-daten))}
.aufstieg-kopf{display:flex; justify-content:space-between; flex-wrap:wrap; gap:var(--sp-2);
  font-family:var(--font-mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--sp-4)}
.aufstieg-reihe{color:var(--tiefgruen); font-weight:700}
.aufstieg-richtung::after{content:" ↗"}
.aufstieg-buehne{position:relative}
.aufstieg-stufen{list-style:none; margin:0; padding:0; position:relative; z-index:1;
  display:grid; grid-template-columns:repeat(var(--n,4),minmax(0,1fr)); gap:var(--sp-3); align-items:end}
.aufstieg-stufe{display:flex; flex-direction:column; min-width:0; position:relative; z-index:1}
.aufstieg-karte{background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-4); min-width:0; position:relative; z-index:2}
.aufstieg-stufe.jetzt .aufstieg-karte{background:var(--navy); color:#fff; border-color:var(--navy)}
.aufstieg-karte .status{display:inline-block; font-family:var(--font-mono); font-size:12.5px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; padding:3px 9px; border-radius:var(--r-btn);
  background:var(--hellorange); color:var(--muted); margin:0 0 var(--sp-2) var(--sp-2); vertical-align:middle}
.aufstieg-stufe.jetzt .status{background:var(--frischgruen); color:var(--navy)}
.aufstieg-karte h3{font-size:16.5px; margin:var(--sp-2) 0 4px; hyphens:manual}
.aufstieg-stufe.jetzt .aufstieg-karte h3{font-size:19px; color:#fff}
.aufstieg-karte p{font-size:13.5px; color:var(--muted); margin:0}
.aufstieg-stufe.jetzt .aufstieg-karte p{color:rgba(255,255,255,.85)}
.aufstieg-karte .fundament-symbol-huelle{color:var(--tiefgruen); vertical-align:middle; margin-bottom:0}
.aufstieg-stufe.jetzt .fundament-symbol-huelle{color:#fff}
.aufstieg-karte .fundament-symbol{width:34px; height:34px}
.c-initial{color:var(--tiefgruen); font-weight:800; font-size:1.18em; line-height:1;
  background:linear-gradient(transparent 58%, var(--frischgruen) 58%, var(--frischgruen) 92%, transparent 92%)}
.aufstieg-stufe.jetzt .c-initial{color:var(--frischgruen); background:none}
.aufstieg-sockel{display:block; height:calc(16px + var(--i,0) * 48px); margin-top:var(--sp-2);
  background:linear-gradient(rgba(16,90,72,.18), rgba(16,90,72,.05)); border-radius:10px 10px 0 0; position:relative}
.aufstieg-sockel::before{content:""; position:absolute; top:-7px; left:50%; width:14px; height:14px; margin-left:-7px;
  border-radius:50%; background:var(--flaeche); border:3px solid var(--tiefgruen); box-sizing:border-box; z-index:3}
.aufstieg-stufe.jetzt .aufstieg-sockel::before{background:var(--frischgruen)}
.aufstieg-kurve{position:absolute; left:0; bottom:0; width:100%; z-index:0; overflow:visible; pointer-events:none}
.aufstieg-kurve path{fill:none; stroke:var(--tiefgruen); stroke-width:3; stroke-dasharray:2 7; stroke-linecap:round; stroke-linejoin:round}
.aufstieg-basis{border-radius:0 0 var(--r-card) var(--r-card)}
.aufstieg-basis .fundament-symbol-huelle{color:#fff}
@media(max-width:759px){
  .aufstieg-stufen{display:flex; flex-direction:column-reverse; gap:var(--sp-3)}
  .aufstieg-stufe{margin-left:calc(var(--i,0) * 12px)}
  .aufstieg-sockel,.aufstieg-kurve{display:none}
  .aufstieg-basis{border-radius:var(--r-card); margin-top:var(--sp-3)}
}
.js-wisch .stufe1 .kapitel .aufstieg-stufe{opacity:0; transform:translateY(22px);
  transition:opacity .5s ease, transform .6s cubic-bezier(.22,.61,.36,1); transition-delay:calc(var(--i,0) * 140ms + .1s)}
.js-wisch .stufe1 .kapitel.wisch-sichtbar .aufstieg-stufe{opacity:1; transform:none}
@media print{
  .js-wisch .stufe1 .kapitel .aufstieg-stufe{opacity:1 !important; transform:none !important; transition:none !important}
  .aufstieg-stufe.jetzt .aufstieg-karte{background:#fff !important; color:#000 !important; border:1px solid #000 !important}
  .aufstieg-stufe.jetzt .aufstieg-karte h3,.aufstieg-stufe.jetzt .aufstieg-karte p{color:#000 !important}
  .aufstieg-karte{border:1px solid #000 !important}
  .aufstieg-sockel{background:#eee !important}
  .c-initial{background:none !important; color:#000 !important}
}

/* ─────────────────── 3.27 · Treppe mit Umschalter (Meeting 30.09.2026, Kap. 07) ───────────────────
   „nach Größe | nach Anzahl Betriebe“: bei „nach Anzahl“ steht das Segment
   mit den meisten Betrieben oben (--rang 0 = Horst), die Treppe wird zur
   Rangliste mit Anteilsbalken. Der Umschalter erscheint nur mit JS
   (hub.html entfernt `hidden`); die Zahl je Stufe steht immer da. */
.treppe-umschalter{display:flex; flex-wrap:wrap; gap:4px; padding:4px; margin:var(--sp-6) 0 0 var(--daten-versatz);
  width:max-content; max-width:100%; box-sizing:border-box; background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-btn)}
.treppe-umschalter[hidden]{display:none}
.treppe-knopf{font:inherit; font-size:14px; font-weight:600; color:var(--muted); background:none; border:0;
  border-radius:var(--r-btn); padding:8px 16px; cursor:pointer}
.treppe-knopf[aria-pressed="true"]{background:var(--navy); color:#fff}
.treppe-knopf:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}
.treppe-umschalter + .treppe{margin-top:var(--sp-4)}
.treppe.mit-anzahl .treppe-anzahl .wert{color:var(--tiefgruen)}
@media(min-width:760px){ .treppe.mit-anzahl .treppe-karte{grid-template-columns:minmax(0,.8fr) minmax(0,1fr) minmax(0,1.3fr) minmax(0,1.2fr) minmax(0,1fr)} }
.treppe-balken{display:none; grid-column:1 / -1; height:8px; border-radius:var(--r-btn); background:var(--line)}
.treppe-balken > span{display:block; height:100%; width:var(--anteil-betriebe); border-radius:inherit; background:var(--tiefgruen)}
.treppe.nach-anzahl{flex-direction:column !important}
.treppe.nach-anzahl .treppe-stufe{order:var(--rang); margin-left:0; max-width:100%}
.treppe.nach-anzahl .treppe-balken{display:block}
.treppe-stufe{transition:margin-left .45s cubic-bezier(.22,.61,.36,1), max-width .45s cubic-bezier(.22,.61,.36,1)}
.treppe-hinweis{margin:var(--sp-3) 0 0 var(--daten-versatz); font-size:13px; color:var(--muted); max-width:70ch}
@media (prefers-reduced-motion:reduce){ .treppe-stufe{transition:none} }
@media print{ .treppe-umschalter{display:none !important} .treppe-balken{display:none !important} }

/* ─────────── 3.27b · Schlanke Hinweis-Leiste (Umbau 30.09.2026, zweite Runde) ───────────
   Ersetzt den fruehen grauen Textblock GANZ OBEN in Stufe 2 (Florian:
   "genau da kippt geil auf hm"). Natives `<details open>` - Wortlaut
   unveraendert, nur die Huelle ist neu: eine duenne, ruhige Zeile mit
   Trennlinien statt eines vollen Absatz-Blocks. "open" haelt den Text
   sofort lesbar (Pflicht vor den Inhalten), der Zeiger zeigt, dass sich
   die Leiste einklappen laesst, wenn gelesen. Keine eigene .kapitel-
   Nummer, keine Eyebrow - bewusst zurueckhaltender als jedes andere
   Bauteil auf der Seite, damit sie nicht wie die Hauptsache wirkt. */
.hinweisleiste{
  max-width:var(--breite-daten); margin:var(--sp-5) auto; border-top:1px solid var(--line);
  border-bottom:1px solid var(--line); padding:var(--sp-3) 0;
}
.hinweisleiste summary{
  cursor:pointer; list-style:none; display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  font-family:var(--font-mono); font-size:12.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted);
}
.hinweisleiste summary::-webkit-details-marker{display:none}
.hinweisleiste summary:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:3px}
.hinweisleiste-zeiger{width:16px; height:16px; border-radius:50%; border:1.5px solid var(--line-stark); position:relative; flex:none}
.hinweisleiste-zeiger::before{
  content:""; position:absolute; left:50%; top:42%; width:6px; height:6px;
  border-right:1.5px solid var(--muted); border-bottom:1.5px solid var(--muted);
  transform:translate(-50%,-50%) rotate(45deg); transition:transform .2s ease;
}
.hinweisleiste[open] .hinweisleiste-zeiger::before{transform:translate(-50%,-20%) rotate(-135deg)}
.hinweisleiste-inhalt{margin-top:var(--sp-3); font-size:13.5px; color:var(--muted); max-width:80ch}
.hinweisleiste-inhalt p{margin:0}
.hinweisleiste-inhalt p + p{margin-top:var(--sp-2)}
/* Florian-Befund 05.10.2026: `markdown_zu_html` (bauen.py) verpackt normale
   Absaetze generisch in eine eigene `<div class="lese-spalte">` (gedacht
   fuer den Lesefluss der Kapitel) - das landet unveraendert auch im Rumpf
   des Hinweis-Kapitels, das `baue_hinweisleiste` hier einfach durchreicht.
   `.lese-spalte{max-width:var(--mass-lese,66-68ch); margin:0 auto}` hat den
   Text dadurch gegenueber der linksbuendigen Ueberschrift ~60px nach rechts
   zentriert UND zusaetzlich auf ~560-580px gedeckelt - unabhaengig von der
   Fensterbreite (ch-Mass), deshalb "auch bei 1920px zu schmal". Diese Box
   hat mit 80ch bereits ihre eigene, linksbuendige Spaltenbreite - die
   verschachtelte `.lese-spalte` braucht hier keine zweite, engere,
   zentrierte Spalte: Zentrierung aufheben, Deckel aufheben. */
.hinweisleiste-inhalt .lese-spalte{margin:0; max-width:none}
@media(prefers-reduced-motion:reduce){ .hinweisleiste-zeiger::before{transition:none} }
@media print{
  .hinweisleiste{border:none; margin:0 auto var(--sp-4)}
  .hinweisleiste-zeiger{display:none}
  .hinweisleiste-inhalt{display:block !important; color:#000 !important}
}

/* ─────────────────── 3.28 · Stufe 2 in fünf Bereichen (Meeting 30.09.2026) ───────────────────
   Oben der Überblick (fünf Karten), darunter jeder Bereich als <details>
   mit seinen Kapiteln. Stufe-1-Optik: große Nummer in Frischgrün-Kontur,
   Tiefgrün als Akzent, runde Karten. Scroll-Effekte bleiben dezent:
   Lesefortschritt am Rand (3.2d, von hub.html auch für Stufe 2 angelegt)
   und eine Punktleiste mit dem aktuellen Bereich.

   Umbau 30.09.2026 (Florian: "die kommen von geil auf hm" - zu trocken):
   die Karte ist jetzt ein Blickfang aus Symbol + kurzem Teaser-Satz statt
   einer Textkarte mit Kapitelliste - der lange Satz UND die Kapitelliste
   bleiben im aufgeklappten Bereich-Kopf (`.bereich-kopf .bereich-satz`
   weiter unten), dort ist mehr Text am Platz. */
.bereiche-ueberblick{margin:var(--sp-6) 0 var(--sp-5); padding:var(--sp-6); background:var(--flaeche);
  border:1.5px solid var(--tiefgruen); border-radius:var(--r-card)}
.bereiche-ueberblick .titel{font-family:var(--font-anzeige); font-weight:800; font-size:clamp(22px,2.6vw,30px);
  margin:0 0 6px; color:var(--ink)}
.bereiche-ueberblick .untertitel{font-size:15px; color:var(--muted); margin:0 0 var(--sp-5); max-width:60ch}
.bereich-karten{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr)); gap:var(--sp-3)}
/* Florian-Befund 05.10.2026 (Skalierungs-Durchgang): die vorige Fassung
   setzte ab 900px ein FESTES 6-Spalten-Raster mit Span 2/3 je Karte, nach
   Position gestaffelt (erste drei Karten Span 2, danach Span 3) - das
   schrieb implizit "genau 5 Karten" fest. Mit nur ZWEI Karten (Stufe 3,
   "Die zwei Bereiche") blieben beide unter dem nth-child(n+4)-Schwellwert,
   bekamen also beide Span 2 = 4 von 6 Spalten, ein Drittel der Buehne blieb
   rechts leer. `auto-fit` + `minmax(…,1fr)` loest das fuer JEDE Kartenzahl:
   leere Spalten werden auf 0 kollabiert, die vorhandenen Karten wachsen per
   `1fr` auf die volle Breite - bei 2 Karten eine Reihe zu zweit (voll),
   bei 5 Karten (Stufe 2) weiterhin 3+2 in zwei Reihen (270px Mindestbreite
   laesst bei --breite-daten/den ueblichen Spaltenbreiten genau 3 pro Reihe
   zu), bei jeder anderen Zahl ebenso ohne Lücke. */
@media(min-width:900px){
  .bereich-karten{grid-template-columns:repeat(auto-fit,minmax(270px,1fr))}
}
.bereich-karte{display:flex; flex-direction:column; gap:8px; text-decoration:none; color:var(--ink);
  background:var(--flaeche-tief); border:1.5px solid var(--line); border-radius:var(--r-sm);
  padding:var(--sp-4) var(--sp-4) var(--sp-3); position:relative;
  transition:border-color .2s ease, transform .2s ease, box-shadow .2s ease}
.bereich-karte:hover{border-color:var(--tiefgruen); transform:translateY(-4px); box-shadow:0 10px 24px rgba(11,31,51,.1)}
.bereich-karte:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}
/* Symbol + Geisterziffer zusammen als EIN Blickfang oben auf der Karte -
   das Symbol traegt die Bedeutung (Bewegung/Software/Markt/Zahlen/Struktur),
   die Ziffer bleibt als Orientierung ("das ist Bereich 3") daneben, kleiner
   als frueher (war 34px als einzelnes Element). */
.bereich-symbol-huelle{display:flex; align-items:center; gap:var(--sp-3); color:var(--tiefgruen)}
.bereich-symbol{width:40px; height:40px; flex:none; fill:none; stroke:currentColor; stroke-width:1.8;
  stroke-linecap:round; stroke-linejoin:round}
.bereich-symbol-huelle .bereich-nr{font-family:var(--font-anzeige); font-weight:800; font-size:26px; line-height:1;
  color:var(--frischgruen); -webkit-text-stroke:1.3px var(--tiefgruen)}
.bereich-karte .bereich-titel{font-family:var(--font-anzeige); font-weight:700; font-size:18px; line-height:1.25}
.bereich-karte .bereich-teaser{font-family:var(--font-anzeige); font-weight:600; font-size:15.5px;
  color:var(--ink); line-height:1.4}
.bereich-karte .bereich-kapitel{font-size:12px; color:var(--muted); margin-top:auto; padding-top:var(--sp-2);
  border-top:1px solid var(--line); line-height:1.45; letter-spacing:.02em; text-transform:uppercase;
  font-family:var(--font-mono)}
.bereich-los{font-family:var(--font-mono); font-size:12.5px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--tiefgruen); font-weight:700}
.bereich-los::after{content:" ↓"}
.bereiche-alle{margin-top:var(--sp-4); font:inherit; font-size:14px; font-weight:600; color:var(--ink);
  background:none; border:1.5px solid var(--line-stark); border-radius:var(--r-btn); padding:8px 18px; cursor:pointer}
.bereiche-alle[hidden]{display:none}
.bereiche-alle:hover{border-color:var(--tiefgruen)}
.bereiche-alle:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}

details.bereich{margin:var(--sp-4) 0; border:1.5px solid var(--line); border-radius:var(--r-card);
  background:var(--flaeche); scroll-margin-top:72px}
details.bereich[open]{border-color:var(--tiefgruen); background:transparent}
.bereich-kopf{list-style:none; cursor:pointer; display:grid; grid-template-columns:auto minmax(0,1fr) auto;
  gap:var(--sp-4); align-items:center; padding:var(--sp-5) var(--sp-5); border-radius:var(--r-card)}
.bereich-kopf::-webkit-details-marker{display:none}
.bereich-kopf:focus-visible{outline:3px solid var(--tiefgruen); outline-offset:2px}
.bereich-kopf .bereich-nr{font-size:clamp(40px,5vw,60px)}
.bereich-kopftext{display:flex; flex-direction:column; gap:4px; min-width:0}
.bereich-eyebrow{font-family:var(--font-mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase; color:var(--tiefgruen)}
.bereich-kopf .bereich-titel{font-family:var(--font-anzeige); font-weight:800; font-size:clamp(21px,2.4vw,28px); line-height:1.2; color:var(--ink)}
.bereich-kopf .bereich-satz{font-size:15px; color:var(--muted); max-width:70ch}
.bereich-zeiger{width:40px; height:40px; border-radius:50%; border:1.5px solid var(--line-stark); position:relative; flex:none}
.bereich-zeiger::before{content:""; position:absolute; left:50%; top:45%; width:10px; height:10px;
  border-right:2px solid var(--ink); border-bottom:2px solid var(--ink); transform:translate(-50%,-50%) rotate(45deg);
  transition:transform .25s ease}
details.bereich[open] > .bereich-kopf .bereich-zeiger::before{transform:translate(-50%,-20%) rotate(-135deg)}
details.bereich[open] > .bereich-kopf .bereich-zeiger{background:var(--frischgruen); border-color:var(--tiefgruen)}
.bereich-kopf:hover .bereich-zeiger{border-color:var(--tiefgruen)}
details.bereich[open] > .bereich-kopf{border-bottom:1px solid var(--line); border-radius:var(--r-card) var(--r-card) 0 0;
  position:sticky; top:52px; z-index:20; background:var(--flaeche); padding-top:var(--sp-3); padding-bottom:var(--sp-3)}
details.bereich[open] > .bereich-kopf .bereich-satz{display:none}
details.bereich[open] > .bereich-kopf .bereich-nr{font-size:36px}
details.bereich[open] > .bereich-kopf .bereich-titel{font-size:20px}
.bereich-inhalt{padding-bottom:var(--sp-5)}
.bereich-inhalt > .kapitel:first-child{padding-top:var(--sp-6)}
@media (prefers-reduced-motion:no-preference){
  details.bereich[open] > .bereich-inhalt{animation:bereich-auf .35s ease-out}
}
@keyframes bereich-auf{from{opacity:0; transform:translateY(-6px)} to{opacity:1; transform:none}}
@media(max-width:639px){
  .bereiche-ueberblick{padding:var(--sp-4)}
  .bereich-kopf{padding:var(--sp-4); gap:var(--sp-3); align-items:start}
  .bereich-kopf .bereich-nr{font-size:34px}
  .bereich-kopf .bereich-satz{font-size:14px}
  .bereich-zeiger{width:32px; height:32px}
  details.bereich[open] > .bereich-kopf{top:46px}
}

/* Bereich 4: Eckzahlen + Download. 02.10.2026 (Auftrag Florian): der Knopf
   ist jetzt ein ECHTER Link auf /api/download (web/api/download.ts liefert
   die Datei nur ab Stufe 2 - siehe bauen.py baue_bereich_zahlen) statt des
   gestrichelten, "cursor:not-allowed"-Platzhalters mit "folgt". Derselbe
   solide, gefuellte Knopf-Stil wie sonst im Hub (--tiefgruen, siehe
   .balken-fuell/.gefaess) - eine gestrichelte Kontur haette weiter
   "nicht klickbar" suggeriert. */
.bereich-zahlen{margin:var(--sp-6) 0 0; border-color:var(--line)}
.bereich-download{display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3); margin-top:var(--sp-5)}
.download-knopf{
  font:inherit; font-size:15px; font-weight:700; padding:12px 22px 12px 44px; border-radius:var(--r-btn);
  border:1.5px solid var(--tiefgruen); background:var(--tiefgruen); color:#fff; position:relative;
  display:inline-block; text-decoration:none; cursor:pointer;
  transition:background-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.download-knopf::before{content:""; position:absolute; left:20px; top:50%; width:12px; height:14px; margin-top:-8px;
  border-bottom:2px solid currentColor; background:linear-gradient(currentColor,currentColor) 50% 0/2px 10px no-repeat}
.download-knopf:is(:hover,:focus-visible){background-color:#0C4A3B; transform:translateY(-1px); box-shadow:var(--schatten-karte)}
.download-knopf:focus-visible{outline:2px solid var(--orange); outline-offset:2px}
@media(prefers-reduced-motion:reduce){ .download-knopf{transition:background-color .2s ease} }
.download-hinweis{font-family:var(--font-mono); font-size:12.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  padding:3px 10px; border-radius:var(--r-btn); background:var(--flaeche-tief); color:var(--muted)}

/* Fortschrittspunkt je Bereich in der Navleiste (Gruppenkopf): der
   Bereich, in dem man gerade liest, wird gefüllt (hub.html,
   IntersectionObserver). Ohne JS bleiben die Punkte leer. */
.navleiste-gruppe .punkt{display:inline-block; width:10px; height:10px; margin-right:8px; border-radius:50%;
  border:2px solid var(--tiefgruen); vertical-align:0; transition:background-color .2s ease, transform .2s ease}
.navleiste-gruppe.aktiv{color:var(--tiefgruen)}
.navleiste-gruppe.aktiv .punkt{background:var(--tiefgruen); transform:scale(1.2)}
@media (prefers-reduced-motion:reduce){ .bereich-karte,.navleiste-gruppe .punkt,.bereich-zeiger::before{transition:none} }
@media print{
  .bereiche-alle,.bereich-zeiger,.bereich-los{display:none !important}
  details.bereich{border:none !important}
  details.bereich > .bereich-kopf{position:static !important}
  .bereich-karte{border:1px solid #000 !important; transform:none !important}
  .bereich-symbol-huelle,.bereich-symbol,.bereich-symbol-huelle .bereich-nr{color:#000 !important; -webkit-text-stroke:0}
  .download-knopf{display:none}
}

/* 30.09. Pruefer: Ueberblick und Bereichs-Kaesten liefen bis an den rechten
   Fensterrand (Ecke abgeschnitten) - wie das alte "Auf einen Blick" auf die
   Datenbreite begrenzt und zentriert. */
.bereiche-ueberblick, details.bereich{max-width:var(--breite-daten); margin-inline:auto; box-sizing:border-box}

/* 30.09. Pruefer Runde 2: bei 1024 und 390 endeten Ueberblick, Hinweisleiste,
   Bereichs-Kaesten und eingeklappter Pitch genau am Fensterrand (Rahmen und
   Ecken abgeschnitten). Seitlicher Mindestabstand statt reiner Maximalbreite. */
@media screen{
  .bereiche-ueberblick, details.bereich, .hinweisleiste, .pitch-eingeklappt{
    width:min(var(--breite-daten), 100% - 2*var(--sp-4)); max-width:none;
    margin-inline:auto; box-sizing:border-box;
  }
}

/* 30.09. Pruefer: Druck von Stufe 2 war zu 41 von 47 Seiten leer - beforeprint
   oeffnet alle Bereiche, die Aufklapp-Animation startete bei Deckkraft 0 und
   wurde genau so gedruckt. Im Druck keine Animation, keine Uebergaenge. */
@media print{
  details.bereich[open] > .bereich-inhalt{animation:none !important}
  .stufe2 .kapitel{transition:none !important}
}

/* 30.09. Pruefer: im eingeklappten Stufe-1-Pitch INNERHALB von Stufe 2 ragte
   die vollbreite Netzkarte (calc(50% - 50vw)) ueber die linke Navleiste
   hinaus und wurde rechts abgeschnitten. Dort nur so breit wie die Spalte. */
.stufe2 .pitch-inhalt .netzkarte-szene{margin-left:0; margin-right:0}

/* ─────────────────── 3.29 · :::captable / :::mittelverwendung (05.10.2026, Folgeauftrag) ───────────────────
   Zwei neue Stufe-3-Bausteine (bauen.py render_captable/render_mittelverwendung)
   standen bisher ganz ohne eigenes CSS auf der Seite - die <figure> trug nur
   UA-Browserstandard (1em 40px Rand, alle <span> inline), darum lief der
   Cap-Table-Balken als Fliesstext zusammen ("Vor der RundeQS-One Holding ·
   100,00 %..."). BEIDE Tabellen darunter sind bereits fertig gestylt
   (`.tabelle-scroll`/`table.jahre`, 3.7) - hier NUR die Huelle und (fuer
   captable) der gestapelte Balken selbst.

   Huelle wie `.balken`/`.planchart` (3.24/3.25): dieselbe Karten-Optik,
   dieselbe Buehnenbreite (`--breite-daten`, ueber `--daten-versatz` auf die
   Lesespalte ausgerichtet, siehe dortiger Kommentar) - beide sitzen laut
   bauen.py/app/dist/stufe3.html als eigenstaendiges Element NEBEN (nicht
   IN) `.lese-spalte`, exakt wie `.balken`/`.planchart` auch. Der Investor
   soll diese drei Bausteine als EINE Familie wiedererkennen, nicht als
   drei neue Stile. */
figure.captable,figure.mittelverwendung{
  margin-top:var(--sp-6); margin-bottom:var(--sp-6); margin-inline:var(--daten-versatz,0px) 0;
  width:min(calc(100% - var(--daten-versatz,0px)), var(--breite-daten));
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-5); box-shadow:var(--schatten-karte); box-sizing:border-box;
}
/* Die Tabelle bringt ueber `.tabelle-scroll` (3.7) schon einen eigenen
   Rahmen/Radius mit - innerhalb der Karte hier reicht das Figure-Padding
   als Abstand, kein zweiter Aussenrand/-zentrierung noetig. */
figure.captable .tabelle-scroll,figure.mittelverwendung .tabelle-scroll{margin:0; max-width:none}
/* 390px-Screenshot 05.10.: die langen Gesellschafter-Bezeichnungen schoben
   beide Zahlenspalten aus dem Bild - am Handy darf die erste Spalte umbrechen. */
@media (max-width:640px){
  figure.captable table.jahre{min-width:0; width:100%}
  /* Pruefer-Befund 05.10.2026, 390px: mit 9em (126px) liess die erste Spalte
     den beiden Zahlenspalten ("Vor der Runde"/"Nach der Runde") zu wenig
     Rest-Breite - 4px Ueberlauf. 8em (112px) reicht für die Gesellschafter-
     Bezeichnungen beim Umbruch weiterhin aus und schafft den Zahlenspalten
     die 14px zurueck. */
  figure.captable table.jahre tr > :first-child{white-space:normal; min-width:8em}
  figure.captable table.jahre th,figure.captable table.jahre td{padding:10px 8px; font-size:14px}
  figure.captable table.jahre thead th{white-space:normal}
}

/* Meilenstein-Marke unter dem Quartalskopf (:::mittelverwendung) - sitzt in
   `table.jahre thead th`, die bereits auf --tiefgruen/#fff steht (3.7),
   deshalb helles, nicht navy/tiefgruen Textende. `white-space:normal`
   durchbricht bewusst das `nowrap` der Kopfzelle selbst (3.7) - sonst
   zwaenge "Vertriebsstart 04/2027" die Spalte unnoetig breit. */
.mv-meilenstein{
  display:block; margin-top:4px; font-family:var(--font-mono); font-weight:600;
  font-size:10.5px; letter-spacing:.04em; color:rgba(255,255,255,.78); white-space:normal;
}

/* ── Gestapelter Balken (:::captable) ──
   Zwei Zeilen ("Vor der Runde"/"Nach der Runde"), je Zeile Beschriftung +
   Spur - dieselbe Grundform wie `.balken-zeile` (3.24: Label|Spur), die
   Spur enthaelt hier aber MEHRERE farbige Segmente nebeneinander statt
   einer Fuellung, jedes mit `--anteil` (%) aus dem style-Attribut im
   Markup (bauen.py render_captable, balken_zeile()). */
.cap-balken{display:grid; gap:var(--sp-4); margin-bottom:var(--sp-5)}
.cap-balken-zeile{
  display:grid; grid-template-columns:minmax(0,9em) minmax(0,1fr);
  align-items:center; gap:var(--sp-3); min-width:0;
}
.cap-balken-label{font-size:14px; font-weight:700; color:var(--ink); min-width:0}
.cap-balken-spur{
  display:flex; align-items:stretch; min-width:0; height:52px;
  border:1px solid var(--line); border-radius:var(--r-sm); overflow:hidden;
  background:var(--flaeche-tief);
}
/* `flex:0 0 var(--anteil)` statt `width` - haelt die Breite exakt
   proportional, auch wenn `.cap-segment-text` (zwei Zeilen erlaubt) ein
   Segment hoeher macht als die Spur selbst; `min-width:0` hebt die
   Flex-Mindestbreiten-Sperre auf (dieselbe Falle wie bei
   `.phasenleiste.zeitstrahl`, 3.9 - ohne das wuerde ein einzelnes langes
   Wort sein Segment ueber den eigenen Anteil hinaus aufblasen). */
.cap-segment{
  flex:0 0 var(--anteil); min-width:0; display:flex; align-items:center;
  justify-content:center; padding:4px 6px; box-sizing:border-box;
  border-right:1px solid var(--line-stark);
}
.cap-segment:last-child{border-right:none}
.cap-segment-text{
  font-family:var(--font-anzeige); font-weight:700; font-size:11.5px; line-height:1.25;
  text-align:center; overflow-wrap:break-word; hyphens:auto;
}
/* Farben: ausschliesslich die vier in tokens.css bereits gegengerechneten
   Kontrastpaare (Kommentarkopf dort - 8,2:1 / >12:1 / 14,2:1 / 6,62:1),
   keine neue Farbe erfunden. Orange bewusst fuer "Investoren" (die einzige
   Aktionsfarbe des Systems) - hier der neue, aktive Teil der
   Kapitalerhoehung, nicht eine der bestehenden Gesellschafter-Zeilen. */
.cap-holding{background:var(--tiefgruen); color:#fff}
.cap-finprep{background:var(--navy); color:#fff}
.cap-brand{background:var(--frischgruen); color:var(--navy)}
.cap-investoren{background:var(--orange); color:var(--navy)}

/* Unter 640px waere ein 18-%-Segment (≈ 60px bei Handybreite) fuer seinen
   eigenen Text ("Investoren (6 Tickets) · 18,00 %") zu schmal - die Spur
   kippt deshalb von einer Reihe auf gestapelte, volle Zeilen je Segment
   (derselbe Gedanke wie `.balken-zeile` unter 560px, nur eine Stufe
   breiter, weil hier ganze Woerter statt nur ein Zahlenwert stehen
   muessen). Jedes Segment bleibt dadurch bei JEDER Breite vollstaendig
   lesbar, keine Kuerzung/Ellipse. */
@media(max-width:640px){
  .cap-balken-zeile{grid-template-columns:1fr; row-gap:6px}
  .cap-balken-spur{flex-direction:column; height:auto; border:none; background:none; gap:3px}
  .cap-segment{
    flex:none; width:100%; min-height:38px; padding:8px 12px;
    border-right:none; border-radius:var(--r-sm); box-sizing:border-box;
  }
  .cap-segment-text{font-size:13px; text-align:left}
}
@media print{
  figure.captable,figure.mittelverwendung{box-shadow:none !important; border:1px solid #000 !important}
  .mv-meilenstein{color:#000 !important}
  .cap-balken-spur{border:1px solid #000 !important; background:#fff !important}
  .cap-segment{background:#fff !important; color:#000 !important; border-right:1px solid #000 !important}
  .cap-segment:last-child{border-right:none !important}
}

/* ─────────────────── 3.30 · Ticketbekundung (:::ticketbekundung, 05.10.2026) ───────────────────
   Karte zur unverbindlichen, NICHT exklusiven Interessensbekundung fuer 1
   oder 2 Tickets (bauen.py render_ticketbekundung, Verhalten/fetch() in
   hub.html). Hiess zuerst ":::ticketreservierung" (exklusive Reservierung
   mit Kapazitaetsgrenze/Zaehler/Warteliste) - nach Kurswechsel (Florian,
   nach Gespraech mit Jens, 05.10.2026) umbenannt: KEIN Zaehler ("noch X
   frei") mehr, KEINE Warteliste, KEIN Verfall - beliebig viele Investoren
   koennen gleichzeitig Interesse an denselben Tickets bekunden, siehe
   Kommentarkopf render_ticketbekundung in bauen.py.

   Progressive Enhancement wie :::dokument/:::cta: OHNE JavaScript bleibt
   NUR die <noscript>-Nachricht + der Hinweistext stehen - das Formular ist
   dafuer per Default unsichtbar und wird erst mit der von hub.html
   gesetzten Klasse "js-aktiv" eingeblendet.

   Sitzt laut app/dist/stufe3.html INNERHALB von `.lese-spalte` (zwischen
   zwei Rz-Absaetzen) - anders als captable/mittelverwendung oben also KEIN
   Datenbaustein auf `--breite-daten`, sondern Teil des Lesetexts: Breite
   bleibt bei `--mass-lese`, dieselbe Karten-Optik wie `.frage-panel`/
   `.kontaktkarte` (flaeche/line/r-card/schatten-karte). */
.ticketbekundung{
  background:var(--flaeche); border:1.5px solid var(--line); border-radius:var(--r-card);
  padding:var(--sp-5); box-shadow:var(--schatten-karte); box-sizing:border-box;
  margin:var(--sp-6) 0; max-width:var(--mass-lese);
}
.ticketbekundung-titel{font-size:18px; color:var(--navy); margin:0 0 var(--sp-3)}

.ticketbekundung-label{
  display:flex; flex-direction:column; gap:6px; font-size:var(--f-small); font-weight:700;
  color:var(--ink); max-width:220px;
}
.ticketbekundung-label select{
  font:inherit; font-size:15px; font-weight:500; color:var(--ink); background:var(--flaeche);
  border:1.5px solid var(--line); border-radius:var(--r-sm); padding:9px 12px;
}
.ticketbekundung-label select:focus-visible{outline:2px solid var(--tiefgruen); outline-offset:2px}
.ticketbekundung-label select:disabled{color:var(--muted); background:var(--flaeche-tief); cursor:not-allowed}

/* Primär-Knopf wie `.download-knopf` (Bereich 4) - derselbe solide,
   gefuellte Stil, nur ohne dessen Download-Pfeil (hier kein Dateidownload). */
.ticketbekundung-knopf{
  font:inherit; font-size:15px; font-weight:700; padding:12px 22px; border-radius:var(--r-btn);
  border:1.5px solid var(--tiefgruen); background:var(--tiefgruen); color:#fff; cursor:pointer;
  transition:background-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.ticketbekundung-knopf:is(:hover,:focus-visible){background-color:#0C4A3B; transform:translateY(-1px); box-shadow:var(--schatten-karte)}
.ticketbekundung-knopf:focus-visible{outline:2px solid var(--orange); outline-offset:2px}
.ticketbekundung-knopf:disabled{
  background:var(--line); border-color:var(--line); color:var(--muted);
  cursor:not-allowed; transform:none; box-shadow:none;
}
.ticketbekundung-knopf[hidden]{display:none}
/* "Interesse zurückziehen" - zurueckhaltende Kontur statt Flaeche: die
   Aktion ist jederzeit rueckholbar (unverbindlich bis zum Vertrag), keine
   Alarmflaeche noetig. Dieselben Warnfarben wie `.frage-fehler`/
   `.kennzahl .delta.ab` - bereits zweimal im System im Einsatz, keine neue
   Farbe erfunden. */
.ticketbekundung-knopf.warnung{background:#fff; border-color:#E3A79E; color:#7A2A20}
.ticketbekundung-knopf.warnung:is(:hover,:focus-visible){background:#FBEAE8; color:#7A2A20; box-shadow:none}
.ticketbekundung-knopf.warnung:disabled{background:#fff; border-color:var(--line); color:var(--muted)}

/* Ohne "js-aktiv" (kein JS/noch nicht gewiert) bleibt das Formular
   unsichtbar - siehe Kommentarkopf oben. */
.ticketbekundung-formular{display:none}
.ticketbekundung.js-aktiv .ticketbekundung-formular{
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--sp-4); margin-bottom:var(--sp-4);
}

/* Statuszeile: eigene Bekundung (offen/im Gespraech/zugesagt/abgelehnt),
   Fehler. `:empty` haelt sie unauffaellig, solange nichts zu melden ist -
   sonst stuende vor dem ersten fetch()-Ergebnis eine leere graue Flaeche
   da. */
.ticketbekundung-status{
  font-size:14px; line-height:1.5; color:var(--ink); margin:0 0 var(--sp-3);
  padding:10px 14px; border-radius:var(--r-sm); background:var(--flaeche-tief);
}
.ticketbekundung-status:empty{display:none; padding:0; margin:0}
.ticketbekundung-status.fehler{background:#FBEAE8; border:1px solid #E3A79E; color:#7A2A20}
.ticketbekundung-hinweis{font-size:13px; color:var(--muted); margin:0}
.ticketbekundung-hinweis + .ticketbekundung-hinweis{margin-top:4px}

@media(max-width:480px){
  .ticketbekundung{padding:var(--sp-4)}
  .ticketbekundung.js-aktiv .ticketbekundung-formular{flex-direction:column; align-items:stretch}
  .ticketbekundung-label{max-width:none}
  .ticketbekundung-knopf{width:100%; text-align:center}
}
@media print{
  .ticketbekundung{box-shadow:none !important; border:1px solid #000 !important}
  .ticketbekundung-formular,.ticketbekundung-status{display:none !important}
}
