/* ══ Abschlussprojekt — eigenes Stylesheet ═════════════════════════════════
   @onur, 2026-09-12: Der Neubau des Portfolios ist hell („Schnee & Kobalt"),
   diese Projektseite hing noch am alten dunklen Stand.

   WARUM eine eigene Datei und nicht die alte weiterbenutzt:
   Die Seite lag auf `/style.css` + `/fallstudie.css` + Tailwind vom CDN.
   Drei Quellen für eine Seite, von denen zwei zum alten, dunklen Portfolio
   gehören und ersatzlos verschwinden sollen. Solange diese Seite daran
   hängt, kann keine der beiden gelöscht werden. Jetzt steht alles, was
   diese Seite braucht, hier daneben — löschen der alten Dateien ändert an
   dieser Seite nichts mehr.

   Verworfen: die beiden alten Dateien hell umfärben. Das hätte die
   Abhängigkeit behalten und zusätzlich ein zweites, konkurrierendes
   Farbsystem neben `app/globals.css` geschaffen.

   Verworfen: Tailwind hell konfigurieren. Im Neubau gibt es kein Tailwind;
   ein CDN-Skript für Klassen, die nur noch an drei Stellen standen, ist
   200 kB Laufzeit für nichts.

   WARUM die Farben hier noch einmal stehen:
   Eine Datei in `public/` ist eine Datei, die Caddy ausliefert — sie kann
   `app/globals.css` nicht importieren (das existiert nach dem Bauen nur
   noch unter einem gehashten Namen). Die Regler sind deshalb eine bewusste
   KOPIE, Zeile für Zeile aus `app/globals.css`. Wer die Palette dreht,
   dreht sie dort und hier. Die Alternative — die Seite in eine React-Route
   umbauen — wäre die saubere, aber sie hätte aus 500 Zeilen fertigem,
   geprüftem HTML/SVG ein Portierungsprojekt gemacht.

   Die Regler heissen wie im Neubau nach ihrer ROLLE, nicht nach dem
   Farbton: `--c-ink` ist der Grund, `--c-paper` die Schrift. Dreht die
   Palette wieder auf dunkel, dreht diese Seite mit.
   ========================================================================= */

/* Bricolage Grotesque, variabel, mit Breiten- (wdth) und Größenachse (opsz).
   Die Dateien liegen NEBEN dieser Seite und kommen nicht von Google: Der
   Neubau lädt sie über `next/font` von der eigenen Adresse, und ein
   Besucher dieser Unterseite soll nicht plötzlich eine Anfrage an einen
   Dritten schicken, nur weil hier statisches HTML liegt. Es sind dieselben
   Unterschnitte, die `next/font` erzeugt (latin und latin-ext), kopiert aus
   dem Build. */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url("bricolage-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url("bricolage-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

:root {
  /* ── Kopie aus app/globals.css, als Kanaltripel ─────────────────────── */
  --c-ink: 240, 242, 245;          /* der Grund: kühles Fastweiss */
  --c-ink-2: 255, 255, 255;        /* die Flächen: reines Weiss */
  --c-ink-3: 220, 225, 231;
  --c-paper: 18, 24, 33;           /* die Schrift: tiefes Blauschwarz */
  --c-accent: 30, 72, 190;         /* Kobalt */
  --c-accent-deep: 18, 48, 132;
  --c-second: 120, 132, 148;       /* Stahlgrau */
  --c-signal: 212, 88, 44;         /* Signal: was ein Mensch entscheiden muss */

  --c-feld-werdegang: 30, 72, 190;    /* Kobalt */
  --c-feld-projekte: 13, 112, 104;    /* Petrol */
  --c-feld-nachweise: 166, 96, 20;    /* Bernstein */
  --c-feld-schwerpunkte: 158, 44, 62; /* Ochsenblut */

  --ink: rgb(var(--c-ink));
  --paper: rgb(var(--c-paper));
  --paper-dim: #444e5c;
  --accent: rgb(var(--c-accent));
  --signal: rgb(var(--c-signal));
  --mist: #78818f;

  --sans: "Bricolage Grotesque", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "JetBrains Mono", Consolas, monospace;

  /* ── Die Kurven ──────────────────────────────────────────────────────────
     Die Bewegungsregel des Hauses verbietet `linear` und die `ease`-Familie,
     und `node scripts/check-motion.mjs` prüft das (der Pfad dieser Seite
     steht jetzt mit in seinen ROOTS).

     Die alte Fassung setzte an vierzig Stellen `linear`. Sachlich war das
     harmlos — die Keyframes dort halten einen Wert und springen innerhalb
     von einem Prozent der Laufzeit um, die Kurve ist also fast wirkungslos.
     Genau deshalb ist der Austausch auch kostenlos: `--k-halt` sieht
     identisch aus und die Prüfung bleibt grün, ohne eine Ausnahme
     einzubauen. Eine Ausnahmeliste im Lint wäre die schlechtere Lösung
     gewesen: Sie hätte die Regel für ALLE Dateien weicher gemacht, um
     vierzig Zeilen zu retten, die niemand braucht.

     --k-halt   Halten und Umschlagen (Sichtbarkeiten, Farbwechsel)
     --k-fahrt  Der Weg des Briefumschlags: anfahren, ankommen
     --k-weich  Übergänge an Bedienelementen */
  --k-halt: cubic-bezier(0.4, 0, 0.6, 1);
  --k-fahrt: cubic-bezier(0.4, 0, 0.5, 1);
  --k-weich: cubic-bezier(0.3, 0.7, 0.2, 1);

  /* Derselbe Zeiger wie im Neubau, aus demselben Grund: Als `cursor`-Bild
     zeichnet ihn der Fensterverwalter selbst, er klebt ohne Verzögerung am
     Gerät. Ein nachgezogenes DIV hinkt immer ein Bild hinterher. */
  --zeiger: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'%3E%3Cpath d='M4 2.4 L4 19.2 L8.3 15.2 L11 21.6 L14.2 20.2 L11.6 14 L17.4 13.8 Z' fill='%23000' stroke='%23fff' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E") 4 3, auto;
  --zeiger-hand: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'%3E%3Cpath d='M4 2.4 L4 19.2 L8.3 15.2 L11 21.6 L14.2 20.2 L11.6 14 L17.4 13.8 Z' fill='%23000' stroke='%23fff' stroke-width='1.4' stroke-linejoin='round'/%3E%3Ccircle cx='20.5' cy='5.5' r='3' fill='none' stroke='%23fff' stroke-width='3.6'/%3E%3Ccircle cx='20.5' cy='5.5' r='3' fill='none' stroke='%23000' stroke-width='1.6'/%3E%3C/svg%3E") 4 3, pointer;
}

* { box-sizing: border-box; }

/* Kein Scrollen — dieselbe Bedingung wie auf der Startseite, und auf dieser
   Seite steht sie sogar schon im alten Prüfblatt-Kommentar („Recruiter lesen
   nicht alles"). `overflow: hidden` ist dabei die Zusage, nicht die Lösung:
   Was nicht passt, wird still abgeschnitten. Deshalb misst
   `node scripts/umbruch.mjs <url>` nach. */
html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }
html { background: var(--ink); cursor: var(--zeiger); }
body {
  margin: 0;
  background: transparent;
  color: var(--paper);
  font-family: var(--sans);
  font-variation-settings: "wdth" 100, "opsz" 14;
  -webkit-font-smoothing: antialiased;
  cursor: var(--zeiger);
}
a, button, [role="button"] { cursor: var(--zeiger-hand); }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, p { margin: 0; }
button { font: inherit; color: inherit; }

/* ── Der Grund ─────────────────────────────────────────────────────────────
   Die Startseite hat eine bewegte Atmosphäre (Nebel, Korn, Falter) aus
   React-Komponenten. Die ist hier NICHT nachgebaut: Sie hängt an einem
   Zeiger-Signal und einer Schleife, also an Laufzeit, die diese statische
   Seite nicht hat. Ein Nachbau in reinem CSS wäre eine zweite, leicht
   andere Atmosphäre geworden — und zwei Fassungen derselben Stimmung sind
   schlechter als eine ruhige. Geblieben ist der leise Lichtkegel, damit die
   Fläche nicht als Pappe liest. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% -10%, rgba(var(--c-accent), 0.07), transparent 60%),
    radial-gradient(90% 70% at 85% 110%, rgba(var(--c-feld-nachweise), 0.05), transparent 62%);
}

/* ══ Die Seite ═════════════════════════════════════════════════════════════
   Eine Spalte aus vier Bändern, das mittlere nimmt den Rest. So kann kein
   Band das nächste verdrängen: Kopf, Messwerte und Fuss sind inhaltsgross,
   das Raster bekommt, was übrig ist — und gibt es an die Pläne weiter, die
   sich als SVG von selbst einpassen. */
.seite {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  gap: clamp(8px, 1.4vh, 16px);
  padding: clamp(12px, 2.2vh, 26px) clamp(16px, 2.4vw, 44px) clamp(8px, 1.2vh, 14px);
}

/* ── Kopf ──────────────────────────────────────────────────────────────────
   @onur, 2026-09-12: „Statt pfSense-Cluster → Abschlussprojekt."

   Dieselbe Vertauschung wie in der Übersicht (`lib/content.ts`): Die
   Überschrift sagt, WAS es ist, der Kicker darüber, WORUM es ging. Ein
   Recruiter sucht „Abschlussprojekt" — „Layer-4 Load Balancing" ist die
   Antwort auf eine Frage, die er noch nicht gestellt hat.

   Der Kopf liegt in EINER Zeile, Titel links, Einordnung rechts: Titel und
   Untertitel übereinander hätten zwei Zeilen Höhe gekostet, und Höhe ist
   auf dieser Seite das knappe Gut. */
.kopf {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(12px, 2vw, 32px);
  flex-wrap: wrap;
  border-bottom: 1px solid rgba(var(--c-paper), 0.12);
  padding-bottom: clamp(6px, 1vh, 12px);
}
.kopf-titel { min-width: 0; }
.kicker {
  font-family: var(--mono);
  font-size: clamp(9px, 1.2vh, 11px);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 2px;
}
/* Plakatstimme wie `.plakat` im Neubau: eng, schwer, versal — aber über die
   BREITENACHSE der Schrift geschmälert, nicht über `transform`. Gestaucht
   wären die Buchstaben verzogen; auf `wdth 75` sind sie gezeichnet. */
.titel {
  font-variation-settings: "wdth" 75, "opsz" 96, "wght" 800;
  font-weight: 800;
  font-size: clamp(26px, 5vh, 52px);
  text-transform: uppercase;
  letter-spacing: -0.035em;
  line-height: 0.88;
}
.unter {
  font-size: clamp(11px, 1.5vh, 13.5px);
  line-height: 1.35;
  color: var(--paper-dim);
  max-width: 56ch;
  text-align: right;
}
.unter b { font-variation-settings: "wght" 700; color: var(--paper); font-weight: 400; }

/* ── Das Raster ────────────────────────────────────────────────────────────
   Links die Fakten, rechts daneben die beiden Pläne.

   Verworfen: vier gleich breite Spalten (Fakten, Vorher, Nachher,
   Messwerte). Gemessen auf 1280 blieben den Plänen dann 335 px — die
   Beschriftung im Plan (17 px in einem 620 px breiten Koordinatenfeld)
   wäre auf 9 px Bildschirmgrösse geschrumpft und unlesbar geworden. Die
   Messwerte liegen deshalb als Band UNTER dem Raster: Sie sind vier kurze
   Zahlen und lesen in einer Reihe sogar besser. */
.raster {
  flex: 1;
  min-height: 0;
  display: grid;
  /* Gleich breite Planspalten — und das ist eine Entscheidung gegen die
     naheliegendere.

     Verworfen: die Spalten im Verhaeltnis der beiden Zeichnungen (1,69 zu 1,
     aus 620:356 gegen 620:600). Rechnerisch fuellen dann BEIDE Plaene ihr
     Blatt genau auf dieselbe Hoehe — gebaut, gemessen, und im Bild war es
     falsch: Beide Zeichnungen sind 620 Einheiten breit, also skaliert die
     breitere Spalte auch die SCHRIFT mit. Der Vorher-Plan stand auf 1920 in
     1,56-facher Groesse neben einem Nachher-Plan in 0,92-facher. Zwei
     Plaene, die man vergleichen soll, muessen dieselbe Schriftgroesse
     haben; gleiche Hoehe ist dagegen nur huebsch.

     Gleiche Breite heisst gleicher Maszstab. Die leere Flaeche, die der
     kurze Vorher-Plan dadurch in seinem Blatt liess, ist nicht mit Luft
     gefuellt, sondern weg: Sein Blatt hoert am Ende der Zeichnung auf
     (`align-self: start` weiter unten). Zwei Blaetter unterschiedlicher
     Laenge sind ein Stapel Papier — ein halb leeres Blatt ist ein Fehler. */
  grid-template-columns: clamp(190px, 16.5vw, 260px) minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(8px, 1.2vw, 18px);
  align-items: stretch;
}
.spalte {
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 1.2vh, 16px);
  min-height: 0;
}

/* ══ Das Beiblatt ══════════════════════════════════════════════════════════
   Übernommen aus `app/styles/blatt.css`, auf die Form reduziert, die diese
   Seite braucht: Papier, 1px-Kante, weicher Schatten OHNE eigene Kante,
   Kopf mit Titel in Versalien.

   Beim Zeigen passiert genau das, was im Neubau passiert: Kante und Titel
   nehmen die Feldfarbe an, der Titel wird grösser und nutzt die
   BREITENACHSE der Schrift. Nichts kippt, nichts hebt sich — die
   Papierphysik ist im Neubau bewusst ausgebaut worden, und diese Seite holt
   sie nicht zurück. */
.blatt {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  color: var(--paper);
  background: rgb(var(--c-ink-2));
  border: 1px solid rgba(var(--c-paper), 0.1);
  border-radius: 3px;
  --feld: var(--c-accent);
  transition: border-color 420ms var(--k-weich);
}
[data-feld="werdegang"] { --feld: var(--c-feld-werdegang); }
[data-feld="projekte"] { --feld: var(--c-feld-projekte); }
[data-feld="nachweise"] { --feld: var(--c-feld-nachweise); }
[data-feld="schwerpunkte"] { --feld: var(--c-feld-schwerpunkte); }
.blatt:hover { border-color: rgba(var(--feld), 0.5); }

.blatt-schatten {
  position: absolute;
  inset: 6% -3% -7% -3%;
  z-index: -1;
  background: radial-gradient(62% 52% at 50% 62%, rgba(var(--c-paper), 0.13), rgba(var(--c-paper), 0.04) 48%, transparent 78%);
  pointer-events: none;
}

.blatt-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: clamp(6px, 1.1vh, 11px) 13px clamp(5px, 0.9vh, 9px);
  border-bottom: 1px solid rgba(var(--c-paper), 0.12);
  /* Der Kopf bekommt die Höhe des GROSSEN Titels, damit beim Zeigen nichts
     springt — sonst schiebt das Wachsen des Titels den Inhalt nach unten. */
  min-height: clamp(30px, 4.4vh, 44px);
}
.blatt-titel {
  font-family: var(--sans);
  font-variation-settings: "wdth" 78, "opsz" 32, "wght" 800;
  font-size: clamp(12px, 1.85vh, 17px);
  letter-spacing: 0.01em;
  text-transform: uppercase;
  line-height: 1;
  transition:
    font-variation-settings 420ms cubic-bezier(0.25, 0.9, 0.3, 1.05),
    font-size 420ms cubic-bezier(0.25, 0.9, 0.3, 1.05),
    color 320ms var(--k-weich);
}
/* Der Zusatz sagt in Alltagssprache, was der Plan gleich zeigt. Er läuft in
   em mit, wenn der Titel beim Zeigen wächst, bleibt aber klein und in
   Gemischtschreibung — so liest man ihn als Satz und nicht als Marke. Unter
   900 px teilen sich Titel und Knopf die Zeile zu knapp; dort fällt er weg,
   die Schritt-Sätze im Plan sagen dasselbe. */
.titel-klar {
  font-variation-settings: "wdth" 92, "opsz" 32, "wght" 500;
  font-size: 0.78em;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--mist);
}
@media (max-width: 900px) { .titel-klar { display: none; } }

.blatt:hover .blatt-titel {
  font-variation-settings: "wdth" 100, "opsz" 32, "wght" 800;
  font-size: clamp(14px, 2.25vh, 21px);
  color: rgb(var(--feld));
}
/* Die Nebenauskunft im Kopf (Laufzeit eines Plans, Zahl der Tests). Sie
   steht in Mono, weil sie Zahlen trägt — dieselbe Rollenteilung wie im
   Neubau: Grotesk liest man, Mono vergleicht man. */
.blatt-note {
  font-family: var(--mono);
  font-size: clamp(8.5px, 1.15vh, 10px);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mist);
  white-space: nowrap;
  flex-shrink: 0;
}
.blatt-leib {
  flex: 1;
  min-height: 0;
  padding: clamp(7px, 1.2vh, 13px) 13px clamp(8px, 1.3vh, 14px);
}

/* ── Aufgabe: ein Satz ─────────────────────────────────────────────────── */
.satz {
  font-size: clamp(12.5px, 1.75vh, 15px);
  line-height: 1.4;
}
.satz b { font-variation-settings: "wght" 700; font-weight: 400; color: rgb(var(--c-feld-schwerpunkte)); }

/* ── Ergebnis: vier Zahlen ─────────────────────────────────────────────────
   Der Dreiklang der Zeilen aus dem Neubau, hier auf zwei Glieder gekürzt:
   die Zahl gross in Mono, darunter ein Satz in der Grotesk. Eine dritte
   Zeile hätte die Spalte auf 1280 über ihre Höhe getrieben. */
.zahlen {
  display: flex;
  flex-direction: column;
  gap: clamp(5px, 0.95vh, 11px);
}
.zahl { display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); align-items: baseline; gap: 0 9px; }
.zahl b {
  font-family: var(--mono);
  font-size: clamp(16px, 2.5vh, 24px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: rgb(var(--feld));
  font-variant-numeric: tabular-nums;
}
/* Die Einheit ist kein Teil der Zahl, sondern ihre Fussnote. In Mono ist
   jedes Zeichen gleich breit, „3 s“ bekam damit eine Luecke von der Breite
   einer Ziffer und las sich wie zwei Angaben. Als eigenes, kleineres
   Zeichen haengt sie an der Zahl, wo sie hingehoert. */
.zahl i {
  font-style: normal;
  font-size: 0.58em;
  font-weight: 600;
  margin-left: 0.18em;
  letter-spacing: 0;
}
.zahl span {
  font-size: clamp(10.5px, 1.4vh, 12.5px);
  line-height: 1.25;
  color: var(--paper-dim);
}

/* ── Gebaut mit: Marken und Wortmarken ────────────────────────────────────
   „Marken statt Wörter, wo es geht" — für pfSense und Cisco gibt es ein
   Zeichen im Haus (`/img/marken/`), für HAProxy, CARP, pfsync und ZFS
   nicht. Erfundene Symbole dafür bezeichnen nichts (genau der Grund, aus
   dem die Leitmarke aus der Projektliste geflogen ist), also stehen sie als
   Wortmarke da. */
.stack { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(5px, 0.8vh, 8px); }
.stack-marke {
  display: inline-flex;
  align-items: center;
  height: clamp(20px, 2.8vh, 26px);
}
.stack-marke img {
  width: auto;
  height: 100%;
  max-width: 62px;
  object-fit: contain;
  opacity: 0.92;
}
/* Das pfSense-Zeichen ist als WEISSE Zeichnung für dunklen Grund gebaut und
   verschwände auf Papier. `brightness(0)` macht dieselbe Zeichnung in
   Schwarz daraus, ohne die Datei anzufassen — dieselbe Lösung wie in
   blatt.css. */
.stack-marke img[src$="pfsense.svg"],
.stack-marke img[src$="cisco.svg"] { filter: brightness(0); opacity: 0.8; }
.wortmarke {
  font-family: var(--mono);
  font-size: clamp(9px, 1.25vh, 11px);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 7px;
  border: 1px solid rgba(var(--c-paper), 0.16);
  border-radius: 2px;
  color: var(--paper);
  white-space: nowrap;
}
/* Die ausgemusterte Hardware ist kein Werkzeug, sondern der Fundort. Sie
   steht deshalb leiser und ohne Kante. */
.wortmarke.leise { border-style: dashed; color: var(--mist); }

/* ── Die Messwerte als Band ────────────────────────────────────────────────
   Vier Zellen in einer Reihe, jede mit demselben Aufbau: Kürzel, was
   gemessen wurde, das Ergebnis, das Soll. Die Reihe ist ein Raster und kein
   Flex-Band: Bei Flex bekämen die vier Zellen unterschiedliche Breiten nach
   Textlänge, und die Zahlen stünden nicht auf einer Flucht — die vergleicht
   man aber. */
.mess-reihe {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 22px);
}
.mess { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0 8px; align-items: baseline; }
.mess-nr {
  grid-row: span 2;
  font-family: var(--mono);
  font-size: clamp(9px, 1.2vh, 10.5px);
  font-weight: 700;
  letter-spacing: 0.1em;
  color: rgb(var(--feld));
  padding-top: 1px;
}
.mess-was { font-size: clamp(11px, 1.45vh, 13px); font-variation-settings: "wght" 650; line-height: 1.2; }
.mess-wert {
  font-family: var(--mono);
  font-size: clamp(11px, 1.45vh, 13px);
  font-weight: 700;
  color: rgb(var(--c-feld-projekte));
  white-space: nowrap;
}
.mess-soll { font-family: var(--mono); font-size: clamp(8.5px, 1.15vh, 10px); color: var(--mist); line-height: 1.35; }
.mess-zeile { display: flex; align-items: baseline; gap: 8px; min-width: 0; }

/* ══ Die Pläne ═════════════════════════════════════════════════════════════
   Jeder Plan ist ein eigenes Blatt mit eigener Feldfarbe: Vorher in
   Ochsenblut (der Zustand, der weg sollte), Nachher in Petrol (der, der
   blieb). Die Farbe ist damit kein Schmuck, sondern die Aussage.

   Das SVG füllt seinen Leib und passt sich mit `preserveAspectRatio`
   (Voreinstellung: einpassen) von selbst ein. Genau das ist die Zusage
   „kein Scrollen": Der Plan kann nicht über sein Blatt hinauswachsen, weil
   er sich am kleineren der beiden Masse ausrichtet. Die alte Fassung hatte
   `min-width: 620px` am SVG — das war die Stelle, an der die Seite auf
   schmalen Fenstern doch scrollte. */
.plan-leib { display: flex; min-height: 0; padding: clamp(5px, 0.9vh, 10px) clamp(6px, 1vh, 12px); }
.plan-leib svg { display: block; width: 100%; height: 100%; min-width: 0; overflow: visible; }

/* Der Vorher-Plan ist die flache Zeichnung (620 zu 356). Sein Blatt hoert
   deshalb dort auf, wo die Zeichnung aufhoert, statt die Zeilenhoehe
   mitzumachen: Das SVG bekommt sein Seitenverhaeltnis als Eigenschaft, die
   Hoehe folgt der Breite.

   `max-height: 100%` ist die Notbremse fuer den Fall, dass die Spalte
   einmal breiter wird als die Zeile hoch ist. Gemessen tritt er nicht ein
   (auf 1920 sind es 441 von 803 px), aber ohne die Grenze waere es die
   Stelle, an der die Seite doch scrollt. */
.plan-teil-v { align-self: start; max-height: 100%; }
.plan-teil-v .plan-leib svg { height: auto; aspect-ratio: 620 / 356; }

/* ── Der Knopf ─────────────────────────────────────────────────────────────
   Er sitzt IM Kopf des Blattes, rechtsbündig. Damit kostet er keine einzige
   Zeile Höhe — dieselbe Überlegung wie in der alten Fassung, und auf einer
   Seite ohne Scrollen ist sie nach wie vor die richtige.

   Jeder Plan hat seinen EIGENEN (@onur, 2026-08-24). Ein gemeinsamer
   Auslöser zwang beide Seiten in dieselbe Zeitachse, und man wusste nicht,
   wo hinsehen. */
.plan-knopf {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: clamp(8.5px, 1.15vh, 10px);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-dim);
  background: rgb(var(--c-ink-2));
  border: 1px solid rgba(var(--c-paper), 0.18);
  border-radius: 2px;
  padding: 4px 8px;
  line-height: 1;
  white-space: nowrap;
  transition: color 220ms var(--k-weich), border-color 220ms var(--k-weich), background-color 220ms var(--k-weich);
}
.plan-knopf:hover:not(:disabled), .plan-knopf:focus-visible {
  color: rgb(var(--feld));
  border-color: rgba(var(--feld), 0.5);
  background: rgba(var(--feld), 0.05);
}
.plan-knopf:disabled { cursor: default; color: var(--signal); border-color: rgba(var(--c-signal), 0.45); }
.plan-knopf-punkt { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: rgb(var(--feld)); }
.plan-knopf:disabled .plan-knopf-punkt { background: var(--signal); }

/* ── Die Zeichnung auf Papier ──────────────────────────────────────────────
   Die alte Fassung zeichnete Limette auf Schwarz: Auf Dunkel ADDIERT sich
   Licht, eine 1,5 px dünne Linie leuchtet dort. Auf Papier DECKT Farbe —
   dieselbe Linie wäre ein blasser Kratzer. Die Kästen stehen deshalb als
   weisse Flächen mit einer dunklen Haarlinie, und die Farbe trägt nur, was
   eine Aussage hat: Kobalt = aktiv, Signalrot = Problem, Petrol = geht gut.

   Verworfen: die Limette einfach dunkler ziehen. Ein Grünton, der auf
   Papier genug Kontrast hat, ist Olive — und Olive sagt nichts. Die
   Feldfarben des Hauses sagen etwas, weil sie überall dasselbe sagen. */
.plan-kasten { fill: rgb(var(--c-ink-2)); stroke: rgba(var(--c-paper), 0.28); stroke-width: 1.2; }
.plan-kasten-aktiv { fill: rgba(var(--c-accent), 0.05); stroke: var(--accent); stroke-width: 1.8; }
.plan-kasten-warn { fill: rgba(var(--c-signal), 0.05); stroke: var(--signal); stroke-width: 1.8; }
.plan-linie { stroke: rgba(var(--c-paper), 0.32); stroke-width: 1.3; fill: none; }
.plan-linie-weich { stroke: rgba(var(--c-accent), 0.45); stroke-width: 1.3; fill: none; stroke-dasharray: 5 5; }
.plan-text {
  fill: var(--paper);
  font-family: var(--sans);
  font-variation-settings: "wdth" 82, "wght" 750;
  font-size: 17px;
  letter-spacing: 0.04em;
  text-anchor: middle;
}
.plan-klein {
  fill: var(--mist);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-anchor: middle;
}
.plan-marke {
  fill: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-anchor: middle;
}
.plan-warn {
  fill: var(--signal);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-anchor: middle;
}
.plan-gut {
  fill: rgb(var(--c-feld-projekte));
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-anchor: middle;
}
.plan-led { fill: var(--accent); }
.plan-led-aus { fill: rgb(var(--c-ink-3)); }
.plan-led-warn { fill: var(--signal); }

/* ── Legende und Sammelbeschriftung ────────────────────────────────────────
   Beide erklären den Plan in Alltagssprache, ohne ihm eine Zeile Höhe zu
   kosten: die Legende sitzt in der freien Ecke links oben, die Gruppenzeile
   auf der leeren Hälfte der Abzweigschiene. Sie stehen links und mittig
   gesetzt, weil sie Beschriftung sind und nicht Teil des Flusses. */
.plan-legende text,
.plan-gruppe {
  fill: var(--mist);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-anchor: start;
}
.plan-legende-kreuz { stroke: var(--signal); stroke-width: 1.8; fill: none; stroke-linecap: round; }
/* Die Beisatz-Zeile zwischen den beiden Knoten. Sie muss in die Lücke von
   156 px passen, die die Kästen lassen — deshalb eine Stufe kleiner. */
.plan-mini {
  fill: var(--mist);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  text-anchor: middle;
}
.plan-kreuz { stroke: var(--signal); stroke-width: 2.4; fill: none; stroke-linecap: round; opacity: 0; }

/* Der Briefumschlag. `transform-box: view-box` ist Pflicht: ohne sie bezöge
   sich der `transform` auf den Rahmen des Elements selbst, und die Zahlen in
   den Keyframes wären keine Plankoordinaten mehr. Mit ihr ist
   `translate(310px, 44px)` genau der Punkt, der auch in den <rect>s steht. */
.plan-mail { transform-box: view-box; transform-origin: 0 0; opacity: 0; }
.plan-mail rect { fill: rgb(var(--c-ink-2)); stroke: var(--accent); stroke-width: 2; }
.plan-mail path { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; }

/* Alles, was erst im Lauf erscheint, ist über `opacity` unsichtbar und nicht
   über `display`: ein `display: none`-Element kann nicht einblenden. */
#v-s1, #v-s2, #v-s3,
#n-a-tot, #n-b-master, #n-s1, #n-s2, #n-s3, #n-s4, #n-s5 { opacity: 0; }

/* ══ LINKS: die Mail kommt nicht an ════════════════════════════════════════
   Weg: CLIENTS → PERIMETERSCHUTZ → DNS-A-RECORD → Abzweig → EX-3.
   Alle Punkte sind aus dem Plan abgelesen, nicht geschätzt.

   @onur, 2026-08-24: „Recruiter checken die Animation nicht. Mache von den
   Clients eine E-Mail, die man dann leicht nachverfolgen kann."

   Der erste Anlauf liess Zustände wechseln: Lampen aus, Kästen um, Texte
   ein. Präzise — aber es setzt voraus, dass man WEISS, wonach man schaut.
   Jetzt bewegt sich EIN Gegenstand, und das Auge folgt ihm von allein. */
.plan-teil-v { --lauf: 6s; }

@keyframes mv-weg {
  0%,  6%   { transform: translate(310px, 62px); }
  20%       { transform: translate(310px, 99px); }   /* Perimeterschutz */
  36%       { transform: translate(310px, 192px); }  /* DNS-A-Record    */
  46%       { transform: translate(310px, 252px); }  /* Abzweigschiene  */
  54%       { transform: translate(260px, 252px); }  /* über EX-3       */
  64%       { transform: translate(260px, 300px); }  /* EX-3: Aufschlag */
  /* Sie prallt ab und bleibt DARÜBER stehen. Mitten auf dem Kasten deckte
     sie genau das Kreuz zu, das sie beweisen soll. */
  72%       { transform: translate(260px, 274px); }
  78%, 100% { transform: translate(260px, 281px); }
}
@keyframes mv-sicht { 0% { opacity: 0; } 6%, 78% { opacity: 1; } 100% { opacity: 0; } }
/* Ab EX-3 wird der Umschlag rot: er ist nicht angekommen. */
@keyframes mv-farbe { 0%, 63% { stroke: var(--accent); } 64%, 100% { stroke: var(--signal); } }

.plan-teil-v.laeuft #v-mail {
  animation: mv-weg var(--lauf) var(--k-fahrt) both,
             mv-sicht var(--lauf) var(--k-halt) both;
}
.plan-teil-v.laeuft #v-mail rect,
.plan-teil-v.laeuft #v-mail path { animation: mv-farbe var(--lauf) var(--k-halt) both; }

/* Das Kreuz erscheint in dem Moment, in dem die Mail ankommt — nicht vorher.
   Wer den toten Knoten von Anfang an sieht, weiss das Ende schon. */
@keyframes mv-kreuz { 0%, 62% { opacity: 0; } 64%, 100% { opacity: 1; } }
.plan-teil-v.laeuft #v-ex3-kreuz { animation: mv-kreuz var(--lauf) var(--k-halt) both; }

@keyframes mv-kasten {
  0%, 62%   { stroke: rgba(var(--c-paper), 0.28); }
  64%, 100% { stroke: var(--signal); }
}
.plan-teil-v.laeuft #v-ex3 { animation: mv-kasten var(--lauf) var(--k-halt) both; }

/* Die Warnung im DNS-Kasten meldet sich, wenn die Mail dort verteilt wird. */
@keyframes mv-warn {
  0%, 30%   { opacity: 1; }
  36%       { opacity: 0.2; }
  42%       { opacity: 1; }
  48%       { opacity: 0.2; }
  54%, 100% { opacity: 1; }
}
.plan-teil-v.laeuft #v-warn { animation: mv-warn var(--lauf) var(--k-halt) both; }

/* Drei Sätze, die die Mail begleiten. Sie erklären nicht den Plan, sondern
   begleiten den Gegenstand. */
@keyframes mv-s1 { 0%, 5% { opacity: 0; } 6%, 33% { opacity: 1; } 36%, 100% { opacity: 0; } }
@keyframes mv-s2 { 0%, 33% { opacity: 0; } 36%, 61% { opacity: 1; } 64%, 100% { opacity: 0; } }
@keyframes mv-s3 { 0%, 62% { opacity: 0; } 64%, 100% { opacity: 1; } }
.plan-teil-v.laeuft #v-s1 { animation: mv-s1 var(--lauf) var(--k-halt) both; }
.plan-teil-v.laeuft #v-s2 { animation: mv-s2 var(--lauf) var(--k-halt) both; }
.plan-teil-v.laeuft #v-s3 { animation: mv-s3 var(--lauf) var(--k-halt) both; }

/* ══ RECHTS: die Mail kommt an ═════════════════════════════════════════════
   Weg: CLIENTS → PERIMETERSCHUTZ → CARP-VIP → [3 s warten] → pfSense B →
   HAProxy → EX-4.

   Die drei Sekunden Stillstand bei der virtuellen Adresse sind 35,3 % von
   8,5 s. Genau das ist T-01. Es wäre ein Leichtes, sie auf eine halbe
   Sekunde zu kürzen und die Animation „flüssiger" zu machen — dann wäre sie
   eine Illustration und kein Beleg mehr. */
.plan-teil-n { --lauf: 8.5s; }

@keyframes mn-weg {
  0%,  5%   { transform: translate(310px, 62px); }
  15%       { transform: translate(310px, 99px); }   /* Perimeterschutz  */
  24%, 59%  { transform: translate(310px, 181px); }  /* CARP-VIP: WARTEN */
  66%       { transform: translate(470px, 232px); }  /* Schiene rechts   */
  72%       { transform: translate(470px, 304px); }  /* pfSense B        */
  78%       { transform: translate(470px, 374px); }  /* Sammelschiene    */
  84%       { transform: translate(310px, 428px); }  /* HAProxy          */
  90%       { transform: translate(360px, 490px); }  /* Abzweig EX-4     */
  /* 534 und nicht 547: mittig auf dem Kasten deckte der Umschlag die
     Beschriftung „EX-4" zu — und welcher Knoten die Mail bekommen hat, ist
     die Pointe. */
  95%, 100% { transform: translate(360px, 534px); }
}
@keyframes mn-sicht { 0% { opacity: 0; } 5%, 100% { opacity: 1; } }
/* Beim Warten pulst der Umschlag rot — er steht, aber er ist nicht weg. */
@keyframes mn-farbe {
  0%, 23%   { stroke: var(--accent); }
  26%       { stroke: var(--signal); }
  40%       { stroke: rgba(var(--c-signal), 0.4); }
  52%       { stroke: var(--signal); }
  59%, 100% { stroke: var(--accent); }
}
.plan-teil-n.laeuft #n-mail {
  animation: mn-weg var(--lauf) var(--k-fahrt) both,
             mn-sicht var(--lauf) var(--k-halt) both;
}
.plan-teil-n.laeuft #n-mail rect,
.plan-teil-n.laeuft #n-mail path { animation: mn-farbe var(--lauf) var(--k-halt) both; }

/* ── Die beiden Ausfälle, gleich zu Beginn ─────────────────────────────── */
@keyframes mn-led-a { 0%, 1% { fill: var(--accent); } 2%, 100% { fill: rgb(var(--c-ink-3)); } }
@keyframes mn-led-b { 0%, 58% { fill: rgb(var(--c-ink-3)); } 59%, 100% { fill: var(--accent); } }
@keyframes mn-kasten-aus {
  0%, 1%    { stroke: var(--accent); stroke-width: 1.8; }
  2%, 100%  { stroke: rgba(var(--c-paper), 0.18); stroke-width: 1.2; }
}
@keyframes mn-kasten-an {
  0%, 58%   { stroke: rgba(var(--c-paper), 0.28); stroke-width: 1.2; }
  59%, 100% { stroke: var(--accent); stroke-width: 1.8; }
}
@keyframes mn-weg-text { 0%, 1% { opacity: 1; } 2%, 100% { opacity: 0; } }
@keyframes mn-kommt    { 0%, 58% { opacity: 0; } 59%, 100% { opacity: 1; } }
@keyframes mn-sofort   { 0%, 1% { opacity: 0; } 2%, 100% { opacity: 1; } }

.plan-teil-n.laeuft #n-a-led    { animation: mn-led-a      var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-b-led    { animation: mn-led-b      var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-a        { animation: mn-kasten-aus var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-b        { animation: mn-kasten-an  var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-a-rolle  { animation: mn-weg-text   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-b-rolle  { animation: mn-weg-text   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-a-tot    { animation: mn-sofort     var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-b-master { animation: mn-kommt      var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-ex3-kreuz{ animation: mn-sofort     var(--lauf) var(--k-halt) both; }

@keyframes mn-ex3-kasten { 0%, 1% { stroke: rgba(var(--c-paper), 0.28); } 2%, 100% { stroke: var(--signal); } }
.plan-teil-n.laeuft #n-ex3 { animation: mn-ex3-kasten var(--lauf) var(--k-halt) both; }

/* Die tote Zuleitung erlischt, wenn HAProxy die Mail umleitet. */
@keyframes mn-abgeklemmt { 0%, 83% { opacity: 1; } 85%, 100% { opacity: 0.16; } }
.plan-teil-n.laeuft #n-ex3-linie { animation: mn-abgeklemmt var(--lauf) var(--k-halt) both; }

/* Der Weg über A ist tot, der über B trägt. */
@keyframes mn-weg-a { 0%, 1% { opacity: 1; } 2%, 100% { opacity: 0.18; } }
@keyframes mn-weg-b { 0%, 58% { opacity: 0.55; } 59%, 100% { opacity: 1; } }
.plan-teil-n.laeuft #n-weg-a, .plan-teil-n.laeuft #n-ab-a { animation: mn-weg-a var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-weg-b, .plan-teil-n.laeuft #n-ab-b { animation: mn-weg-b var(--lauf) var(--k-halt) both; }

/* Die virtuelle Adresse flackert genau so lange, wie die Mail wartet. */
@keyframes mn-carp {
  0%, 23%   { stroke: var(--accent); }
  26%       { stroke: var(--signal); }
  36%       { stroke: rgba(var(--c-signal), 0.25); }
  46%       { stroke: var(--signal); }
  56%       { stroke: rgba(var(--c-signal), 0.25); }
  59%, 100% { stroke: var(--accent); }
}
.plan-teil-n.laeuft #n-carp { animation: mn-carp var(--lauf) var(--k-halt) both; }

/* Fünf Sätze, die die Mail begleiten. Jeder trägt eine Zahl aus der Messung,
   keine erfundene. */
@keyframes mn-ruhe { 0%, 1% { opacity: 1; } 2%, 100% { opacity: 0; } }
@keyframes mn-s1 { 0%, 1% { opacity: 0; } 2%, 22% { opacity: 1; } 24%, 100% { opacity: 0; } }
@keyframes mn-s2 { 0%, 22% { opacity: 0; } 24%, 57% { opacity: 1; } 59%, 100% { opacity: 0; } }
@keyframes mn-s3 { 0%, 57% { opacity: 0; } 59%, 81% { opacity: 1; } 83%, 100% { opacity: 0; } }
@keyframes mn-s4 { 0%, 81% { opacity: 0; } 83%, 92% { opacity: 1; } 94%, 100% { opacity: 0; } }
@keyframes mn-s5 { 0%, 92% { opacity: 0; } 94%, 100% { opacity: 1; } }
.plan-teil-n.laeuft #n-ruhe { animation: mn-ruhe var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-s1   { animation: mn-s1   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-s2   { animation: mn-s2   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-s3   { animation: mn-s3   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-s4   { animation: mn-s4   var(--lauf) var(--k-halt) both; }
.plan-teil-n.laeuft #n-s5   { animation: mn-s5   var(--lauf) var(--k-halt) both; }

/* ══ OHNE BEWEGUNG ═════════════════════════════════════════════════════════
   Kein Film, sondern das ERGEBNIS: links liegt die Mail rot auf dem toten
   EX-3, rechts auf EX-4 angekommen. Dieselbe Aussage, sofort da. */
@media (prefers-reduced-motion: reduce) {
  .laeuft * { animation: none !important; }
  .blatt, .blatt-titel, .plan-knopf { transition-duration: 0.01ms !important; }
}

.ergebnis #v-mail { opacity: 1; transform: translate(260px, 281px); }
.ergebnis #v-mail rect, .ergebnis #v-mail path { stroke: var(--signal); }
.ergebnis #v-ex3-kreuz, .ergebnis #v-s3 { opacity: 1; }
.ergebnis #v-ex3 { stroke: var(--signal); }

.ergebnis #n-mail { opacity: 1; transform: translate(360px, 534px); }
.ergebnis #n-a-led { fill: rgb(var(--c-ink-3)); }
.ergebnis #n-b-led { fill: var(--accent); }
.ergebnis #n-a { stroke: rgba(var(--c-paper), 0.18); stroke-width: 1.2; }
.ergebnis #n-b { stroke: var(--accent); stroke-width: 1.8; }
.ergebnis #n-weg-a, .ergebnis #n-ab-a { opacity: 0.18; }
.ergebnis #n-a-rolle, .ergebnis #n-b-rolle, .ergebnis #n-ruhe { opacity: 0; }
.ergebnis #n-a-tot, .ergebnis #n-b-master, .ergebnis #n-s5, .ergebnis #n-ex3-kreuz { opacity: 1; }
.ergebnis #n-ex3 { stroke: var(--signal); }
.ergebnis #n-ex3-linie { opacity: 0.16; }

/* ══ Der Fuss ══════════════════════════════════════════════════════════════
   Der Laufschriftbalken der alten Fassung ist ersatzlos weg. Er wiederholte
   in Bewegung genau die Zahlen, die zwei Zentimeter darüber still im Blatt
   „Gemessen" stehen — und Bewegung, die nichts Neues sagt, zieht nur den
   Blick von dem weg, was zählt. Im Neubau gibt es sie ebenfalls nicht. */
.fuss {
  display: flex;
  align-items: center;
  gap: clamp(8px, 1.2vw, 18px);
  padding-top: clamp(4px, 0.7vh, 9px);
  border-top: 1px solid rgba(var(--c-paper), 0.1);
  font-family: var(--mono);
  font-size: clamp(9px, 1.2vh, 11px);
  letter-spacing: 0.06em;
}
.fuss-link { color: var(--mist); transition: color 220ms var(--k-weich); }
.fuss-link:hover, .fuss-link:focus-visible { color: var(--accent); }
.fuss-schub { margin-left: auto; }
.knopf {
  font-family: var(--mono);
  font-size: clamp(9px, 1.2vh, 11px);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 5px 11px;
  border-radius: 2px;
  border: 1px solid rgba(var(--c-paper), 0.2);
  background: rgb(var(--c-ink-2));
  color: var(--paper);
  white-space: nowrap;
  transition: color 220ms var(--k-weich), border-color 220ms var(--k-weich), background-color 220ms var(--k-weich);
}
.knopf:hover, .knopf:focus-visible { border-color: rgba(var(--c-accent), 0.5); color: var(--accent); }
.knopf-voll {
  background: var(--accent);
  border-color: var(--accent);
  color: rgb(var(--c-ink-2));
}
.knopf-voll:hover, .knopf-voll:focus-visible {
  background: rgb(var(--c-accent-deep));
  border-color: rgb(var(--c-accent-deep));
  color: rgb(var(--c-ink-2));
}

/* Der Schiebe-Hinweis am Plan. Auf dem Rechner gibt es nichts zu schieben,
   dort ist er weg. */
.wisch { display: none; }

/* ══ SCHMALER ALS 860 px ═══════════════════════════════════════════════════
   Hier gilt die Ein-Bildschirm-Regel NICHT mehr, und das ist keine Ausnahme
   aus Bequemlichkeit: Ein Plan mit zwölf Kästen und 620 Koordinateneinheiten
   Breite ist auf 390 px nicht lesbar zu machen. Bisher blieb die Regel auch
   dort stehen — mit `overflow: hidden` als Zusage. Die Folge war die
   schlimmste Sorte Fehler: Die Seite sah heil aus und war es nicht. Der Satz
   in „Aufgabe" endete bei „ohne Umschaltung bei", die vierte Zahl war halb
   abgeschnitten, und die Knöpfe lagen jenseits des rechten Randes — ohne
   Scrollbalken, der es verraten hätte.

   Also: Höhe freigeben, die drei Spalten zu einer Folge machen, und die
   EINZIGE Stelle, an der etwas breiter sein darf als das Gerät, ist der
   Rahmen um eine Zeichnung. Ein Diagramm darf über den Rand gehen, der
   Seitenkörper nicht.

   Die Schriftgrade hängen an dieser Seite überall an `vh`, weil die Höhe
   am Rechner das knappe Gut ist. Auf einer scrollenden Seite ist die
   Fensterhöhe kein Maß für Platz mehr — auf einem 844 px hohen Telefon
   wären 1,45vh gerade 12 px. Die Grade stehen deshalb hier fest. */
@media (max-width: 860px) {
  html, body { height: auto; overflow: visible; overscroll-behavior: auto; }
  .seite {
    height: auto;
    min-height: 100dvh;
    gap: 14px;
    padding: 16px 16px 20px;
  }

  /* ── Kopf: Titel und Einordnung untereinander, beide linksbündig ─────── */
  .kopf { align-items: flex-start; gap: 8px; padding-bottom: 10px; }
  .titel { font-size: clamp(30px, 9vw, 44px); }
  .unter { text-align: left; max-width: none; font-size: 12.5px; }

  /* ── Aus drei Spalten wird eine Folge ────────────────────────────────── */
  .raster { display: flex; flex-direction: column; gap: 14px; }
  .spalte { gap: 14px; }

  /* Jede Karte bekommt ihre Höhe wieder vom Inhalt statt vom Fenster. */
  .blatt-leib { flex: none; padding: 12px 13px 14px; }
  .plan-teil-v { align-self: stretch; max-height: none; }

  /* Der Schatten greift am Rechner 3 % nach links und rechts aus dem Blatt
     heraus — dort deckt ihn `overflow: hidden` ab. Auf der scrollenden Seite
     wäre er ein 5 px breiter Streifen Querlauf, gemessen auf 768. Unten darf
     er bleiben, seitlich nicht. */
  .blatt-schatten { inset: 6% 0 -7% 0; }
  .blatt-kopf { min-height: 0; padding: 10px 13px 9px; flex-wrap: wrap; gap: 8px; }
  .blatt-titel, .blatt:hover .blatt-titel { font-size: 15px; }
  /* Der Klartext-Zusatz fällt hier NICHT weg, sondern rückt unter den
     Titel: Auf dem Telefon liest man ihn eher als am Rechner. */
  .titel-klar { display: block; font-size: 12.5px; margin-top: 3px; }
  .blatt-note { white-space: normal; }

  .satz { font-size: 15px; }
  .zahlen { gap: 10px; }
  .zahl b { font-size: 23px; }
  .zahl span { font-size: 12.5px; }
  .stack-marke { height: 24px; }
  .wortmarke { font-size: 11px; }

  /* ── Die Pläne: schieben statt verlieren ─────────────────────────────────
     `min-width` auf der Zeichnung ist die eigentliche Zusage — darunter
     wird die 12-px-Beschriftung im 620er Feld zu Grau. Der Rahmen darum
     scrollt, die Seite nicht. */
  .plan-leib { overflow-x: auto; overflow-y: hidden; padding: 9px 11px 11px; }
  .plan-leib svg { width: 100%; height: auto; min-width: 520px; }
  .plan-teil-n .plan-leib svg { aspect-ratio: 620 / 600; }
  /* ── Messwerte: eine Liste, keine vier Spalten ───────────────────────────
     Zu viert nebeneinander blieben je 80 px, und die Sätze standen Wort
     für Wort untereinander. */
  .mess-reihe { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .mess-was { font-size: 13.5px; }
  .mess-wert { font-size: 13.5px; }
  .mess-soll { font-size: 11px; }
  .mess-nr { font-size: 10.5px; }

  .fuss { flex-wrap: wrap; gap: 10px; padding-top: 10px; }
  .fuss-schub { margin-left: auto; }
  .knopf { font-size: 11px; }
}

/* Der Hinweis erscheint erst, wo es wirklich etwas zu schieben gibt: Der
   Rahmen ist so breit wie das Fenster minus 56 px Rändern, die Zeichnung
   mindestens 520 px. Unter 576 px Fensterbreite reicht es also nicht mehr —
   600 als runde Schwelle mit etwas Luft. Auf einem Tablet, wo der Plan ganz
   hineinpasst, wäre der Hinweis eine Aufforderung ins Leere. */
@media (max-width: 600px) {
  .wisch {
    display: inline-block;
    font-family: var(--mono);
    font-size: 9.5px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mist);
    white-space: nowrap;
  }
}

/* ══ AUF DEM BILDSCHIRM NICHT, AUF PAPIER SCHON ════════════════════════════
   Die vollständige Arbeit ist NICHT gelöscht, sie steht unter `nur-druck`.
   „Fallstudie drucken" liefert damit das Handout für das Gespräch — genau
   das, was man auf den Tisch legt, wenn doch jemand nachfragt. */
.nur-druck { display: none; }

@media print {
  /* Auf Papier gilt die Ein-Bildschirm-Regel nicht, sondern ihr Gegenteil:
     Hier darf und soll alles stehen. Also Höhe und Überlauf freigeben. */
  html, body { height: auto; overflow: visible; background: #fff; }
  body::before { display: none; }
  .seite { display: block; height: auto; padding: 0; }
  .fuss, .plan-knopf { display: none !important; }
  .blatt { border-color: #bbb; box-shadow: none; break-inside: avoid; }
  .blatt-schatten { display: none; }
  .raster { display: block; }
  /* Auf dem Bildschirm halten `gap`-Angaben die Baender auseinander; im
     Druckfluss gibt es kein Flex mehr, also muss der Abstand an die Kinder.
     Ohne das klebte die erste Druckueberschrift am Blatt „Gemessen“. */
  .seite > *, .raster > *, .spalte > * { margin-bottom: 5mm; }
  .plan-leib svg { max-height: none; }
  .plan-legende text, .plan-gruppe, .plan-mini { fill: #555; }
  .mess-reihe { grid-template-columns: 1fr 1fr; }

  /* Ein halb eingeblendeter Umschlag wäre ein Fehler im Handout: Die Pläne
     drucken im Ruhezustand. */
  .plan-mail,
  #v-s1, #v-s2, #v-s3,
  #n-a-tot, #n-b-master, #n-s1, #n-s2, #n-s3, #n-s4, #n-s5,
  #v-ex3-kreuz, #n-ex3-kreuz { display: none !important; }
  .laeuft *, .ergebnis * { animation: none !important; }

  .nur-druck { display: block; break-inside: avoid; margin: 6mm 0 7mm; }
  .druck-titel {
    font-variation-settings: "wdth" 82, "wght" 800;
    font-size: 13pt;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin-bottom: 2mm;
    padding-bottom: 1mm;
    border-bottom: 1px solid #bbb;
  }
  .druck-text { font-size: 10pt; line-height: 1.55; margin-bottom: 2.5mm; max-width: 68ch; }
  .druck-text code { font-family: var(--mono); font-size: 9pt; background: #eee; padding: 0 2px; }
  .druck-bu { font-size: 9pt; line-height: 1.5; color: #444; margin-top: 2mm; max-width: 68ch; }
  .druck-schritte { counter-reset: schritt; }
  .druck-schritte > li { counter-increment: schritt; margin-bottom: 3mm; break-inside: avoid; }
  .druck-schritte > li::before {
    content: counter(schritt, decimal-leading-zero);
    font-family: var(--mono);
    font-size: 8pt;
    color: #666;
    margin-right: 3mm;
    float: left;
  }
  .druck-schritt-titel { font-variation-settings: "wght" 700; font-size: 10.5pt; }
  .druck-tab { width: 100%; border-collapse: collapse; font-size: 9.5pt; margin-top: 2mm; }
  .druck-tab caption { text-align: left; font-size: 8.5pt; color: #555; padding-bottom: 1.5mm; }
  .druck-tab th, .druck-tab td { text-align: left; padding: 1.2mm 2mm; border-bottom: 1px solid #ddd; }
  .druck-tab th { font-size: 8.5pt; text-transform: uppercase; letter-spacing: 0.06em; color: #444; }
  .druck-tab .num { text-align: right; font-family: var(--mono); }
  .druck-tab .gut { font-weight: 700; }
  .druck-tab .hebt td { border-top: 1.5px solid #333; border-bottom: none; font-weight: 700; }
}
