/* ══════════════════════════════════════════════════════════════════
   SimDashboard — Schaufenster-Ebene
   Wird NUR auf /login, /standorte und / geladen. Nicht auf den
   Arbeitsflächen: dort liest man Termine in Tabellen, und bewegter
   Hintergrund unter einer Tabelle ist kein Effekt, sondern eine Zumutung.

   Zwei Dinge stecken hier drin:
     1. .luftig — die luftige Dichtestufe (große Zahlen, weite Abstände).
        Die darf man auch auf einer Arbeitsfläche einsetzen; sie schaltet
        keine Bewegung an.
     2. body.buehne — dekorative Bewegung. Parallax, driftendes Raster,
        Marken-Wasserzeichen, Enthüllen beim Scrollen.

   Bewegt wird ausschließlich per transform und opacity. Kein animiertes
   background-position, kein animiertes filter, kein box-shadow in
   Keyframes — das sind die drei Dinge, die auf Büro-Rechnern ohne
   dedizierte Grafik ruckeln.

   Scroll-Bewegung läuft über CSS-Scroll-Timelines (animation-timeline),
   nicht über IntersectionObserver. Kein JavaScript, und Browser ohne
   Unterstützung zeigen die Inhalte einfach fertig an — was der richtige
   Rückfall ist.
   ══════════════════════════════════════════════════════════════════ */

/* ══ 1. LUFTIGE DICHTESTUFE ════════════════════════════════════════ */

.luftig {
    padding: var(--r7) var(--r6);
    margin-bottom: var(--r6);
}
.luftig + .luftig { margin-top: calc(var(--r7) * -1 + var(--r6)); }

/* Sektion mit Nummer — das Muster, das neoconda (01–16), vibe3d (01–03)
   und terawulf (01–12) gemeinsam haben. Die Nummer zählt automatisch,
   damit beim Umsortieren nichts von Hand nachgezogen werden muss. */
.sf-sektion { counter-increment: sf-sektion; position: relative; }
body.buehne { counter-reset: sf-sektion; }

.sf-kopf {
    display: flex;
    align-items: baseline;
    gap: var(--r4);
    margin-bottom: var(--r5);
    border-top: 1px solid var(--line);
    padding-top: var(--r4);
}
.sf-kopf::before {
    content: counter(sf-sektion, decimal-leading-zero);
    font-family: var(--mono);
    font-size: var(--sf-nummer);
    font-weight: 600;
    letter-spacing: 0.14em;
    color: var(--marke-text);
    flex: 0 0 auto;
    padding-top: 0.35em;
}
.sf-kopf h2 {
    font-size: var(--sf-h2);
    font-weight: 600;
    letter-spacing: -0.01em;
}
.sf-kopf .sf-kopf-sub {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink3);
    margin-left: auto;
}

.sf-titel {
    font-size: var(--sf-h1);
    font-weight: 600;
    line-height: 1.06;
    letter-spacing: -0.02em;
    max-width: 22ch;
}
.sf-lead {
    font-size: var(--sf-lead);
    line-height: 1.55;
    color: var(--ink2);
    max-width: 62ch;
    margin-top: var(--r4);
}

/* Die große Kennzahl. Mono, damit sie nach Messwert aussieht und nicht
   nach Werbung — und tabular, damit sie beim Hochzählen nicht zappelt. */
.sf-kennzahl {
    font-family: var(--mono);
    font-size: var(--sf-display);
    font-weight: 600;
    line-height: 0.92;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    display: block;
}
.sf-kennzahl .einheit {
    font-size: 0.33em;
    font-weight: 400;
    letter-spacing: 0.04em;
    color: var(--ink2);
    margin-left: 0.25em;
    vertical-align: 0.55em;
}
.sf-kennzahl-label {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink3);
    margin-bottom: var(--r3);
    display: block;
}
.sf-kennzahl.ampel-ok { color: var(--ok); }
.sf-kennzahl.ampel-warn { color: var(--warn); }
.sf-kennzahl.ampel-crit { color: var(--crit); }

.sf-reihe {
    display: grid;
    gap: var(--r6);
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}


/* ══ 2. HINTERGRUND-EBENEN ═════════════════════════════════════════
   Drei feste Ebenen hinter dem Inhalt. Alle mit pointer-events:none,
   damit nichts davon Klicks abfängt. */

.buehne-hg {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}
/* Inhalt über die Hintergrundebenen heben.
   ACHTUNG: hier NICHT `position: relative` auf .side setzen — das
   überschreibt das `position: sticky` aus v2.css, die Seitenleiste scrollt
   dann mit und das Layout bricht auf. `sticky` ist selbst schon positioniert,
   z-index allein genügt. */
body.buehne .main { position: relative; z-index: 1; }
body.buehne .side { z-index: 1; }

/* Ebene A — technisches Raster, driftet langsam.
   Bewegt wird ein übergroßes Element per translate3d, nicht die
   background-position: Letzteres würde bei jedem Frame neu gerastert. */
.hg-raster {
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background-image:
        linear-gradient(var(--line) 1px, transparent 1px),
        linear-gradient(90deg, var(--line) 1px, transparent 1px);
    background-size: 64px 64px;
    opacity: 0.35;
    will-change: transform;
    animation: raster-drift 90s linear infinite;
}
@keyframes raster-drift {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-64px, -64px, 0); }
}

/* Ebene B — Markenschein. Ein roter Lichtkegel oben links, der sehr
   langsam atmet. Radialer Gradient auf transparentem Grund, kein Blur:
   ein animierter filter:blur() auf Vollbildgröße ist der teuerste Effekt,
   den man bauen kann. */
.hg-schein {
    position: absolute;
    top: -30vh;
    left: -18vw;
    width: 78vw;
    height: 96vh;
    background: radial-gradient(closest-side,
        rgba(255, 0, 0, 0.16), rgba(255, 0, 0, 0.05) 55%, transparent 72%);
    will-change: transform, opacity;
    animation: schein-atmen 22s ease-in-out infinite alternate;
}
@keyframes schein-atmen {
    from { transform: scale(1) translate3d(0, 0, 0); opacity: 0.75; }
    to { transform: scale(1.14) translate3d(3vw, 2vh, 0); opacity: 1; }
}

/* Ebene C — Marken-Wasserzeichen: die HENN-Bildmarke selbst, riesig und
   fast unsichtbar, mit Parallax. Kein generisches Deko-Muster, sondern
   die Geometrie der eigenen Marke. */
.hg-marke {
    position: absolute;
    right: -6vw;
    bottom: -12vh;
    width: min(62vw, 900px);
    aspect-ratio: 1;
    background: url('/static/img/henn-bildmarke.svg') center / contain no-repeat;
    opacity: 0.045;
    will-change: transform;
}

/* Parallax über die Scroll-Timeline des Dokuments: das Wasserzeichen
   wandert langsamer als der Inhalt. Browser ohne animation-timeline
   zeigen es einfach still — kein Bruch. */
@supports (animation-timeline: scroll()) {
    .hg-marke {
        animation: marke-parallax linear both;
        animation-timeline: scroll(root block);
    }
    .hg-schein {
        animation: schein-atmen 22s ease-in-out infinite alternate,
                   schein-parallax linear both;
        animation-timeline: auto, scroll(root block);
    }
}
@keyframes marke-parallax {
    from { transform: translate3d(0, 0, 0) rotate(0deg); }
    to { transform: translate3d(-4vw, -22vh, 0) rotate(-7deg); }
}
@keyframes schein-parallax {
    to { transform: translate3d(0, 14vh, 0); }
}


/* ══ 3. ENTHÜLLEN BEIM SCROLLEN ════════════════════════════════════
   Über view()-Timeline statt IntersectionObserver. animation-range
   sorgt dafür, dass der Block fertig eingeblendet ist, sobald er ein
   Drittel im Bild steht — nicht erst am Ende. */

@supports (animation-timeline: view()) {
    body.buehne .enthuellen {
        animation: enthuellen linear both;
        animation-timeline: view();
        animation-range: entry 5% cover 28%;
    }
}
@keyframes enthuellen {
    from { opacity: 0; transform: translateY(26px); }
    to { opacity: 1; transform: translateY(0); }
}


/* ══ 4. STANDORT-EBENE ═════════════════════════════════════════════ */

.standort-kopf {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--r5);
    flex-wrap: wrap;
    margin-bottom: var(--r6);
}

/* Weltkarte: eigenes SVG (keine Kartenlizenz, keine externe Anfrage).
   Die Pins sitzen prozentual auf einer Äquirektangular-Projektion —
   Umrechnung in standorte.js. */
.welt {
    position: relative;
    border: 1px solid var(--line);
    border-radius: var(--rad-l);
    background: var(--panel);
    overflow: hidden;
    margin-bottom: var(--r6);
}
.welt svg { display: block; width: 100%; height: auto; }
/* Landflächen (Natural Earth, s. templates/_weltland.svg). Der Ton liegt
   bewusst zwischen --panel2 und --line: dunkel genug, um dem Gradnetz und
   den Pins den Vortritt zu lassen, hell genug, dass die Küstenlinie auf den
   ersten Blick als Land lesbar ist. Reines --panel2 war gegen --panel zu
   knapp und sah aus wie ein Rendering-Fehler. */
.welt .land {
    fill: color-mix(in srgb, var(--panel2) 62%, var(--line) 38%);
    stroke: var(--line2);
    stroke-width: 0.45;
}

.pin {
    position: absolute;
    width: 12px;
    height: 12px;
    margin: -6px 0 0 -6px;
    border-radius: 50%;
    background: var(--ink3);
    border: 2px solid var(--panel);
    cursor: default;
}
.pin[data-angebunden="ja"] {
    background: var(--marke);
    cursor: pointer;
    width: 15px;
    height: 15px;
    margin: -7.5px 0 0 -7.5px;
}
/* Der angebundene Standort pulst — genau EIN Pin von neun, deshalb ist
   das Aufmerksamkeit und nicht Unruhe. */
.pin[data-angebunden="ja"]::after {
    content: "";
    position: absolute;
    inset: -5px;
    border-radius: 50%;
    border: 1px solid var(--marke);
    animation: pin-puls 2.6s ease-out infinite;
}
@keyframes pin-puls {
    from { transform: scale(0.7); opacity: 0.9; }
    to { transform: scale(2.1); opacity: 0; }
}
.pin-name {
    position: absolute;
    left: 50%;
    top: calc(100% + 6px);
    transform: translateX(-50%);
    font-family: var(--mono);
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--ink3);
    pointer-events: none;
}
/* Fünf der neun Standorte liegen innerhalb von vier Breitengraden in
   Mitteleuropa — ihre Namen lagen als Dauerbeschriftung übereinander und
   waren unlesbar. Darum: dauerhaft beschriftet wird nur der angebundene
   Standort, die übrigen zeigen ihren Namen beim Überfahren. Vollständig
   stehen alle Namen ohnehin in den Kacheln darunter. */
.pin[data-angebunden="nein"] .pin-name {
    opacity: 0;
    transition: opacity var(--dauer-flink) var(--kurve);
    background: var(--panel);
    border: 1px solid var(--line2);
    border-radius: var(--rad-s);
    padding: 1px 5px;
}
.pin[data-angebunden="nein"] { pointer-events: auto; }
.pin[data-angebunden="nein"]:hover { background: var(--ink2); z-index: 3; }
.pin[data-angebunden="nein"]:hover .pin-name { opacity: 1; color: var(--ink); }
.pin[data-angebunden="ja"] .pin-name {
    color: var(--ink);
    font-weight: 600;
    z-index: 4;
}

.standort-gitter {
    display: grid;
    gap: var(--r4);
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
}

.standort-karte {
    display: block;
    text-decoration: none;
    color: inherit;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--rad-l);
    padding: var(--r5);
    position: relative;
    overflow: hidden;
    transition: border-color var(--dauer-flink) var(--kurve),
                transform var(--dauer-normal) var(--kurve),
                box-shadow var(--dauer-normal) var(--kurve);
}
.standort-karte[data-angebunden="ja"] { border-color: var(--line2); }
.standort-karte[data-angebunden="ja"]::before {
    content: "";
    position: absolute;
    top: 0; left: 0; bottom: 0;
    width: 3px;
    background: var(--marke);
}
.standort-karte[data-angebunden="ja"]:hover {
    border-color: var(--line3);
    transform: translateY(-3px);
    box-shadow: var(--schatten-hoch);
}
.standort-karte[data-angebunden="ja"]:focus-visible {
    outline: none;
    box-shadow: var(--fokus-ring);
}
/* Nicht angebundene Standorte sind KEINE Links — sie sehen auch nicht
   wie welche aus. Kein Hover, kein Zeiger, gedämpfter Text. */
.standort-karte[data-angebunden="nein"] { cursor: default; opacity: 0.72; }

/* Die angebundene Kachel nimmt zwei Spalten. Neun gleich große Kacheln, von
   denen genau eine weiterführt, machen die Auswahl zu einem Suchspiel.

   `span 2` nur, wenn das Raster überhaupt zwei Spalten hat: auf einem
   einspaltigen Raster ist `span 2` kein Fehler, aber die Regel unten macht
   die Absicht sichtbar. */
.standort-karte.hervor { grid-column: span 2; }
@media (max-width: 700px) {
    .standort-karte.hervor { grid-column: span 1; }
}

.sk-kopfzeile {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--r3);
}
/* Segment (HENNconnectors / HENNgineered). Neutral gerahmt, NICHT in
   Markenrot: es ist eine Einordnung, keine Handlung — und zwei Segmente in
   Rot nebeneinander sagen nur, dass beide rot sind. */
.sk-segment {
    flex-shrink: 0;
    font-family: var(--mono);
    font-size: 0.62rem;
    letter-spacing: 0.1em;
    color: var(--ink2);
    border: 1px solid var(--line2);
    border-radius: var(--rad-rund);
    padding: 1px var(--r2);
    white-space: nowrap;
}

.sk-ort {
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.01em;
}
.sk-land {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink3);
}
.sk-firma { font-size: var(--fs-body); color: var(--ink2); margin-top: var(--r3); }
.sk-funktion { font-size: var(--fs-sub); color: var(--ink3); margin-top: var(--r1); }
.sk-fuss {
    display: flex;
    align-items: center;
    gap: var(--r2);
    margin-top: var(--r4);
    padding-top: var(--r3);
    border-top: 1px solid var(--line);
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.sk-fuss.live { color: var(--marke-text); }
.sk-fuss.aus { color: var(--ink3); }

/* Kennzahlenzeile auf der Karte des angebundenen Standorts */
.sk-kpis {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--r3);
    margin-top: var(--r4);
}
.sk-kpis div { display: flex; flex-direction: column; gap: 2px; }
.sk-kpis span {
    font-family: var(--mono);
    font-size: 0.58rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink3);
}
.sk-kpis b {
    font-family: var(--mono);
    font-size: 1.05rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}


/* Gradnetz-Linien der Weltkarte */
.welt .gitter { stroke: var(--line); stroke-width: 1; }
.welt .gitter.null { stroke: var(--line2); stroke-width: 1.4; }
.welt .welt-marke {
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: 0.16em;
    fill: var(--ink3);
}


/* ══ 4b. HERO ══════════════════════════════════════════════════════ */

.sf-hero { padding: var(--r7) 0 var(--r6); }
.sf-hero-eyebrow {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--marke-text);
    margin-bottom: var(--r4);
}
.sf-hero-zahlen {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r7);
    margin-top: var(--r6);
}
.sf-hero-zahlen .sf-kennzahl { font-size: clamp(2rem, 4.5vw, 3rem); }


/* ══ 4b2. VORHALLE ═════════════════════════════════════════════════
   Die zwei Auswahlstufen vor dem Leitstand (/standorte, /standort/…) haben
   KEIN Menüband — siehe base.html, Zone `vorhalle`. Statt der Seitenleiste
   steht oben eine schmale Kopfzeile.

   ACHTUNG: v2.css setzt `body { display: flex }` für das Nebeneinander von
   Seitenleiste und Inhalt. Ohne Seitenleiste müssen Kopfzeile und Inhalt
   ÜBEREINANDER liegen, also Spaltenrichtung — sonst stellt sich der Kopf
   neben den Inhalt und wird 200 px breit.                                */

body.vorhalle { flex-direction: column; }

.vh-kopf {
    position: sticky;
    top: 0;
    z-index: 2;                      /* über den Hintergrundebenen (z-index 0) */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--r5);
    flex-wrap: wrap;
    padding: var(--r3) var(--r6);
    border-bottom: 1px solid var(--line);
    /* Halbdurchsichtig, damit der bewegte Hintergrund darunter sichtbar
       bleibt — der Kopf soll die Bühne nicht abschneiden. */
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    backdrop-filter: blur(10px);
}
/* Markenkante wie an der Seitenleiste: 3 px HENN-Rot. Dasselbe Signal an
   derselben Stelle im Blickverlauf, nur waagerecht. */
.vh-kopf::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--marke);
}

.vh-marke {
    display: flex;
    align-items: baseline;
    gap: var(--r4);
    flex-wrap: wrap;
    text-decoration: none;
    color: inherit;
}
.vh-marke img { display: block; height: auto; }
.vh-marke-sub {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.12em;
    color: var(--ink3);
}
.vh-marke:focus-visible { outline: none; box-shadow: var(--fokus-ring); }

.vh-rechts {
    display: flex;
    align-items: center;
    gap: var(--r4);
    font-family: var(--mono);
    font-size: var(--fs-label);
}
.vh-benutzer { color: var(--marke-text); }
.vh-link {
    color: var(--ink2);
    text-decoration: none;
    padding: var(--r1) var(--r2);
    border-radius: var(--rad-s);
    border: 1px solid transparent;
}
.vh-link:hover { color: var(--ink); border-color: var(--line3); }
.vh-link:focus-visible { outline: none; box-shadow: var(--fokus-ring); }

/* Der Inhalt der Vorhalle ist zentriert statt linksbündig: ohne
   Seitenleiste gibt es keine linke Kante mehr, an der er sich ausrichten
   könnte, und angeklebt an den Rand sieht eine Auswahlseite unfertig aus. */
body.vorhalle .main {
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: var(--r5) var(--r6) var(--r7);
}


/* ══ 4b3. WERKSAUSWAHL ═════════════════════════════════════════════
   Zwei große Karten mit Anlagenbild, Prozesskette und der Spitzenlast des
   Werks. Bewusst nur zwei Spalten und keine dichte Kachelwand: es sind
   zwei Werke, und die Entscheidung zwischen zwei Dingen darf Platz haben. */

.werk-gitter {
    display: grid;
    gap: var(--r5);
    grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
}

.werk-karte {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    background: var(--panel);
    border: 1px solid var(--line2);
    border-radius: var(--rad-l);
    overflow: hidden;
    position: relative;
    transition: border-color var(--dauer-flink) var(--kurve),
                transform var(--dauer-normal) var(--kurve),
                box-shadow var(--dauer-normal) var(--kurve);
}
/* Rote Oberkante wie an den angebundenen Standortkacheln — dasselbe
   Zeichen für „hier geht es weiter". */
.werk-karte::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--marke);
    z-index: 1;
}
.werk-karte:hover {
    border-color: var(--line3);
    transform: translateY(-3px);
    box-shadow: var(--schatten-hoch);
}
.werk-karte:focus-visible { outline: none; box-shadow: var(--fokus-ring); }

/* Bildfläche: die Renderings sind freigestellte PNGs mit Alpha. Der
   Bodenschein darunter gibt ihnen einen Stand — ohne ihn schweben die
   Anlagen im Nichts. Gleiches Rezept wie .l3-halter auf /anlagen. */
/* Die HÖHE steckt an der Fläche, nicht am Bild. Damit reserviert der Browser
   den Platz, bevor das PNG da ist (kein Springen), und die Kartentexte
   stehen auf einer Linie, obwohl die Renderings unterschiedliche
   Seitenverhältnisse haben — ohne dass Pixelmaße in werke.py und im CSS
   doppelt gepflegt werden müssten. */
.wk-bild {
    position: relative;
    height: 250px;
    background:
        radial-gradient(ellipse at 50% 122%, var(--panel2) 0%, var(--bg) 74%);
    border-bottom: 1px solid var(--line);
    padding: var(--r4) var(--r4) var(--r5);
}
/* Das Bild füllt die Fläche und wird von object-fit eingepasst — NICHT über
   max-width/max-height auf ein `auto`-Bild: als Grid-Element behält es dann
   wegen `min-height: auto` seine Eigenhöhe und läuft unten aus der Karte
   heraus (genau das ist beim ersten Versuch passiert). */
.wk-bild img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.wk-bild-titel {
    position: absolute;
    left: var(--r4);
    bottom: var(--r2);
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.08em;
    color: var(--ink3);
}
/* Nur die Bildfläche bewegt sich beim Überfahren, nicht das Bild im Fluss:
   ein skalierter Text darunter wird unscharf. */
.werk-karte:hover .wk-bild img { transform: scale(1.03); }
.wk-bild img { transition: transform var(--dauer-ruhig) var(--kurve); }

.wk-inhalt {
    padding: var(--r5);
    display: flex;
    flex-direction: column;
    flex: 1;
}
.wk-nr {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--marke-text);
}
.wk-kurz {
    font-size: var(--sf-h2);
    font-weight: 600;
    margin-top: var(--r1);
}
.wk-text {
    color: var(--ink2);
    font-size: var(--fs-body);
    margin-top: var(--r2);
}

/* Prozesskette als Zeile kurzer Glieder. Sie sagt in einem Blick, was das
   Werk tut — genauer als jedes Bild und ohne eine Zahl zu behaupten. */
.wk-kette {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--r1) 6px;
    margin-top: var(--r4);
}
.wk-glied {
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink2);
    background: var(--panel2);
    border: 1px solid var(--line);
    border-radius: var(--rad-s);
    padding: 1px var(--r2);
}
.wk-pfeil { color: var(--ink3); font-size: var(--fs-label); }

.wk-kpis {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r5);
    margin-top: var(--r5);
    padding-top: var(--r4);
    border-top: 1px solid var(--line);
}
.wk-kpis div { display: flex; flex-direction: column; gap: 2px; }
.wk-kpis span {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink3);
}
.wk-kpis b {
    font-family: var(--mono);
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--accent);       /* Messwert = Bernstein, siehe tokens.css */
}
/* Der Engpass ist ein NAME, keine Messung — darum nicht bernstein. */
.wk-kpis .wk-engpass { color: var(--ink); font-size: 0.95rem; }

.wk-fuss {
    margin-top: auto;
    padding-top: var(--r4);
    font-family: var(--mono);
    font-size: var(--fs-sub);
    letter-spacing: 0.08em;
    color: var(--marke-text);
}

@media (max-width: 900px) {
    .vh-kopf { padding: var(--r2) var(--r4); }
    .vh-marke-sub { display: none; }   /* auf 375 px bricht die Zeile sonst um */
    body.vorhalle .main { padding: var(--r4) var(--r4) var(--r6); }
    .wk-bild { height: 170px; }
    .wk-inhalt { padding: var(--r4); }
}

@media (prefers-reduced-motion: reduce) {
    .werk-karte, .wk-bild img { transition: none; }
    .werk-karte:hover { transform: none; }
    .werk-karte:hover .wk-bild img { transform: none; }
}


/* ══ 4c. LINIE IN 3D (Seite /anlagen) ══════════════════════════════
   EINE Szene mit allen Stationen. Löst die alte Kachelzeile plus
   Einzelbühne ab (Entscheidung Luca, 31.07.: „ganz weg, nur 3D").

   Die Beschriftungen sind echte Knöpfe, die über der Szene schweben —
   dadurch ist die Linie mit Tastatur bedienbar und für Screenreader
   lesbar, ohne dass eine zweite Navigationsleiste sichtbar wird.        */

.anl-karte { padding: var(--r5); }

.l3-halter {
    position: relative;
    margin-top: var(--r3);
    border: 1px solid var(--line);
    border-radius: var(--rad-m);
    overflow: hidden;
    background:
        radial-gradient(ellipse at 50% 118%, var(--panel2) 0%, var(--bg) 72%);
}

.l3-buehne {
    position: relative;
    /* Sehr breit: die Linie ist lang und flach. Bei 16/9 stünde über und
       unter ihr mehr leere Fläche als Inhalt.

       KEIN min-height dazu. `aspect-ratio` rechnet in beide Richtungen:
       sobald eine Mindesthöhe gewinnt, leitet der Browser daraus die BREITE
       ab — bei 330 px wären das 843 px, und in einem schmaleren Kasten steht
       die Bühne dann über den Rand hinaus und wird abgeschnitten. Genau das
       ist mobil passiert (400 px Bühne in 347 px Kasten). Wer hier eine
       Mindesthöhe braucht, schaltet `aspect-ratio` ab — siehe Mobilteil. */
    aspect-ratio: 23 / 9;
    display: grid;
    place-items: center;
}
/* Verzweigte Strecke (Werk 2): drei Spuren in der Tiefe machen die
   Grundfläche annähernd quadratisch. In dem flachen 23/9-Streifen stand die
   Szene klein in der Mitte, weil die Kamera weit zurück muss, um eine tiefe
   Fläche vollständig zu zeigen — die Bühne war breit, die Szene nicht. */
.l3-buehne.tief { aspect-ratio: 16 / 10; }
.l3-buehne canvas { display: block; width: 100%; height: 100%; }
.l3-buehne:focus-visible { outline: none; box-shadow: inset var(--fokus-ring); }

/* ── Schwebende Stationsschilder ─────────────────────────────────── */

.l3-schilder {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;   /* nur die Schilder selbst fangen Klicks */
    overflow: hidden;
}
.l3-schild {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: auto;
    display: flex;
    align-items: baseline;
    gap: var(--r2);
    padding: var(--r1) var(--r3);
    background: color-mix(in srgb, var(--panel) 88%, transparent);
    border: 1px solid var(--line2);
    border-radius: var(--rad-rund);
    color: var(--ink);
    font-size: var(--fs-label);
    white-space: nowrap;
    cursor: pointer;
    backdrop-filter: blur(6px);
    /* Unsichtbar starten: bis das erste Bild gezeichnet ist, hat das Schild
       noch keine Position und säße sonst sichtbar in der linken oberen Ecke. */
    opacity: 0;
    transition: opacity var(--dauer-normal) var(--kurve),
                border-color var(--dauer-flink) var(--kurve),
                background var(--dauer-flink) var(--kurve);
}
.l3-schild:hover { border-color: var(--line3); }
.l3-schild:focus-visible { outline: none; box-shadow: var(--fokus-ring); }
.l3-schild .ls-nr {
    font-family: var(--mono);
    color: var(--ink3);
    letter-spacing: 0.12em;
}
.l3-schild .ls-wert {
    font-family: var(--mono);
    color: var(--accent);
}
.l3-schild.aktiv {
    border-color: var(--marke);
    background: color-mix(in srgb, var(--panel) 94%, var(--marke) 6%);
}
.l3-schild.aktiv .ls-nr { color: var(--marke-text); }

/* ── Leiste oben: Fortschritt und Rücksprung ─────────────────────── */

.l3-leiste {
    position: absolute;
    z-index: 3;
    top: var(--r3);
    left: var(--r3);
    right: var(--r3);
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--r3);
    pointer-events: none;
}
.l3-leiste > * { pointer-events: auto; }
.l3-status {
    font-family: var(--mono);
    font-size: var(--fs-readout);
    color: var(--ink2);
    background: color-mix(in srgb, var(--panel) 84%, transparent);
    border-radius: var(--rad-s);
    padding: var(--r1) var(--r2);
    min-height: 1.2em;
}
.l3-status:empty { display: none; }

/* ── Infotafel, blendet beim Reinzoomen ein ──────────────────────── */

.l3-info {
    position: absolute;
    z-index: 2;                     /* über den Schildern, nie darunter */
    right: var(--r3);
    bottom: var(--r3);
    width: min(340px, 42%);
    max-height: calc(100% - var(--r7));
    overflow-y: auto;
    background: color-mix(in srgb, var(--panel) 97%, transparent);
    border: 1px solid var(--line2);
    border-radius: var(--rad-m);
    padding: var(--r4);
    box-shadow: var(--schatten-karte);
    backdrop-filter: blur(10px);
    /* Immer im Layout, nur unsichtbar — nicht `hidden`. Ein Element, das
       erst eingehängt wird, braucht einen Bildlauf, bevor der Übergang
       greifen kann, und den gibt es in einem unsichtbaren Tab nicht. */
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transform: translateY(var(--r3));
    transition: opacity var(--dauer-normal) var(--kurve),
                transform var(--dauer-normal) var(--kurve),
                visibility 0s linear var(--dauer-normal);
}
.l3-info.an {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transform: none;
    transition-delay: 0s;
}
.l3-info h2 {
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 2px 0 var(--r2);
}
.l3-info .eyebrow { margin-bottom: 0; }
.li-was {
    font-size: var(--fs-sub);
    color: var(--ink2);
    margin-bottom: var(--r3);
}
.li-kpis { display: grid; gap: var(--r2); }
/* Kompakter als auf einer Fachseite: die Tafel schwebt über der Bühne und
   hat nur deren Höhe zur Verfügung. Mit der vollen KPI-Größe passt die
   dritte Kennzahl nicht mehr ins Bild und wird unten abgeschnitten. */
.li-kpis .kpi {
    background: var(--panel2);
    border-radius: var(--rad-m);
    padding: var(--r2) var(--r3);
}
.li-kpis .kpi .v { font-size: var(--fs-h2); margin: 0 0 1px; }
.li-kpis .kpi .s { font-size: var(--fs-label); }
.li-masse {
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink3);
    margin-top: var(--r3);
}
.li-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r2);
    margin-top: var(--r3);
}

/* ── Fußzeile: was der Browser wirklich zeichnet ─────────────────── */

.l3-fuss {
    position: absolute;
    left: var(--r3);
    bottom: var(--r3);
    display: flex;
    gap: var(--r3);
    flex-wrap: wrap;
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink3);
    pointer-events: none;
}
/* Namensnennung für fremde Modelle (CC-BY) — siehe models/LIZENZEN.md.
   Leer, solange keine Station mit Fremdmodell gewählt ist. */
.l3-lizenz:not(:empty)::before { content: "· "; }

/* ── Rückfalllinie ohne WebGL ────────────────────────────────────── */

.l3-ersatz {
    display: grid;
    gap: var(--r3);
    grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
    padding: var(--r4);
}
.l3-ersatz[hidden] { display: none; }
.le-karte {
    background: var(--panel2);
    border: 1px solid var(--line2);
    border-radius: var(--rad-m);
    padding: var(--r3);
}
.le-karte img {
    width: 100%;
    height: auto;
    display: block;
    margin-bottom: var(--r2);
}
.le-karte .le-name { font-size: var(--fs-body); font-weight: 600; }
.le-karte .le-wert {
    font-family: var(--mono);
    font-size: var(--fs-readout);
    color: var(--accent);
}

/* ── Schmale Bildschirme ─────────────────────────────────────────── */

@media (max-width: 900px) {
    /* Feste Höhe statt Seitenverhältnis: hochkant ist ein 23/9-Streifen
       120 px hoch und damit unbrauchbar. `aspect-ratio: auto` ist dabei
       zwingend — sonst rechnet der Browser aus der Höhe wieder eine Breite
       zurück und die Bühne wird breiter als der Bildschirm. */
    .l3-buehne {
        aspect-ratio: auto;
        height: min(56vh, 380px);
        min-height: 240px;
    }
    /* Die Infotafel deckt auf 375 px die halbe Szene zu. Darum steht sie
       hier unter der Bühne statt darüber — dafür ist sie dann immer da. */
    .l3-info {
        position: static;
        width: auto;
        max-height: none;
        border: 0;
        border-top: 1px solid var(--line);
        border-radius: 0;
        box-shadow: none;
        backdrop-filter: none;
        transform: none;
    }
    /* Im Fluss statt überlagert: eine unsichtbare, aber Platz belegende
       Tafel hinterließe sonst ein leeres Loch unter der Bühne. */
    .l3-info:not(.an) { display: none; }
    .l3-info.an { opacity: 1; visibility: visible; }
    .l3-fuss { position: static; padding: 0 var(--r3) var(--r3); }
    .l3-schild { font-size: var(--fs-label); padding: 2px var(--r2); }
    .l3-schild .ls-name { display: none; }
}

/* ══ 4d. STYLEGUIDE ════════════════════════════════════════════════ */

.sg-farben {
    display: grid;
    gap: var(--r3);
    grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
}
.sg-feld {
    display: flex;
    gap: var(--r3);
    align-items: stretch;
    background: var(--panel2);
    border: 1px solid var(--line2);
    border-radius: var(--rad-m);
    padding: var(--r3);
}
.sg-probe {
    width: 46px;
    flex: 0 0 auto;
    border-radius: var(--rad-s);
    border: 1px solid var(--line3);
}
.sg-info { min-width: 0; }
.sg-name { font-size: var(--fs-body); font-weight: 600; }
.sg-var {
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink3);
    word-break: break-all;
}
.sg-kontrast {
    font-family: var(--mono);
    font-size: var(--fs-readout);
    margin-top: var(--r1);
    display: flex;
    align-items: baseline;
    gap: var(--r2);
    flex-wrap: wrap;
}
.sg-kontrast.gut { color: var(--ok); }
.sg-kontrast.schlecht { color: var(--crit); }
.sg-kontrast.deko { color: var(--ink3); }
.sg-soll {
    font-size: var(--fs-label);
    color: var(--ink3);
    letter-spacing: 0.08em;
}


/* ══ 5. ANMELDESEITE ═══════════════════════════════════════════════ */

body.anmelden {
    display: grid;
    place-items: center;
    min-height: 100vh;
    padding: var(--r5);
}
.login-karte {
    width: min(420px, 92vw);
    background: var(--panel);
    border: 1px solid var(--line2);
    border-radius: var(--rad-l);
    padding: var(--r6) var(--r6) var(--r5);
    position: relative;
    z-index: 1;
    box-shadow: var(--schatten-hoch);
    overflow: hidden;
}
.login-karte::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--marke);
}
.login-form { display: flex; flex-direction: column; gap: var(--r3); margin-top: var(--r5); }
.login-err {
    color: var(--crit);
    font-size: var(--fs-sub);
    min-height: 1.2em;
    margin: var(--r1) 0 0;
}


/* ══ 6. MOBIL ══════════════════════════════════════════════════════ */

@media (max-width: 900px) {
    /* Strecke: Bühne über die Infotafel, und die Stationszeile scrollt
       waagerecht statt die Kacheln unlesbar schmal zu quetschen. */
    .station-halter { grid-template-columns: 1fr; }
    .fluss { padding-bottom: var(--r3); }
    .fluss-station { min-width: 116px; flex: 0 0 auto; }
    .fs-bild { height: 52px; }
    .fs-bild img { max-height: 52px; }
    .fluss-pfeil { flex-basis: 22px; }

    .luftig { padding: var(--r5) var(--r4); margin-bottom: var(--r5); }
    .luftig + .luftig { margin-top: 0; }
    .sf-reihe { gap: var(--r5); }
    .sk-kpis { grid-template-columns: repeat(3, 1fr); gap: var(--r2); }
    .sf-kopf { gap: var(--r3); flex-wrap: wrap; }
    .sf-kopf .sf-kopf-sub { margin-left: 0; flex-basis: 100%; }
    /* Auf Touch gibt es kein Hover — die Namen der nicht angebundenen
       Standorte entfallen dort ganz. Sie stehen in den Kacheln. */
    .pin[data-angebunden="nein"] .pin-name { display: none; }
    /* Das Raster ist auf kleinen Geräten reine Batterielast */
    .hg-raster { display: none; }
}


/* ══ 7. ABSCHALTER ═════════════════════════════════════════════════
   Bewegungsempfindliche Nutzer bekommen die Bühne ohne Bühne: die
   Ebenen bleiben sichtbar, aber absolut still. Der Abschalter in
   v2.css stellt zusätzlich alle Dauern auf 1 ms. */

@media (prefers-reduced-motion: reduce) {
    .hg-raster, .hg-schein, .hg-marke,
    .pin[data-angebunden="ja"]::after,
    body.buehne .enthuellen {
        animation: none !important;
    }
    body.buehne .enthuellen { opacity: 1 !important; transform: none !important; }
}
