/* =========================================================================
   alc-story.css – Designsystem „Werkstatt-Blaupause" für alc.gmbh
   Einzige Stylesheet-Datei der Animationsseite. Kein Bootstrap, keine Icon-Font,
   kein externer Request (DSGVO/CSP, Spec 6).

   BLOCKSTRUKTUR (Reihenfolge verbindlich):
     === Tokens ===            Farb-/Typo-Variablen, @font-face
     === Grundgerüst ===       Seite, Header (nur Wortmarke), Footer, Rechtsseiten
     === Story ===             3D-Story: Bühne, Kapitel, Transitionen, Progress,
                               Formular-Layer, Fallbacks
     === Kontaktformular ===   Formularkarte, Felder, Meldungen

   Alle Pfade sind absolut ab Docroot (/fonts/…, /css/…, /js/…, /lib/…).
   ========================================================================= */


/* =========================================================================
   === Tokens ===
   ========================================================================= */

/* Ubuntu + Ubuntu Mono lokal – kein Google-Fonts-Request.
   Runde 14 (Final Review tempo-12): WOFF2 zuerst (verlustfrei mit fontTools
   aus den TTF erzeugt, gleiche Glyphen/cmap; 325 -> 145 KB fuer die fuenf
   Startschnitte), TTF bleibt als Rueckfall fuer sehr alte Browser. */
@font-face { font-family: 'Ubuntu'; font-style: normal; font-weight: 300; font-display: swap; src: url('/fonts/ubuntu-300.woff2') format('woff2'), url('/fonts/ubuntu-300.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/ubuntu-400.woff2') format('woff2'), url('/fonts/ubuntu-400.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu'; font-style: italic; font-weight: 400; font-display: swap; src: url('/fonts/ubuntu-400i.woff2') format('woff2'), url('/fonts/ubuntu-400i.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/ubuntu-500.woff2') format('woff2'), url('/fonts/ubuntu-500.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/ubuntu-700.woff2') format('woff2'), url('/fonts/ubuntu-700.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/ubuntu-mono-400.woff2') format('woff2'), url('/fonts/ubuntu-mono-400.ttf') format('truetype'); }
@font-face { font-family: 'Ubuntu Mono'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/ubuntu-mono-700.woff2') format('woff2'), url('/fonts/ubuntu-mono-700.ttf') format('truetype'); }

:root {
  /* Farb-Tokens – exakt gespiegelt in /js/story/palette.js (Storyboard 0.8) */
  --paper: #F4F2EC;
  --paper-2: #EAE7DF;
  /* Runde 2 (Storyboard 0.8): eigener Bodenton – im Dark-Theme liegt er drei
     Stufen unter --paper-2, damit sich Boden und Wand trennen (Fix 7). */
  --floor: #E3DFD5;
  --ink: #1C1F22;
  --graphite: #3A3F45;
  --line: #C9C5BB;
  --metal: #B8BCC2;
  --steel: #6F7680;
  --inox: #D8DBDE;
  --corten: #8C4A2E;
  --accent: #E84747;
  --spark: #FFD9A0;

  /* Neu nach Spec 5 */
  --rust: #7A5A45;
  --wood: #C8A66B;
  --arc: #DFF2FF;
  --go: #3CB371;

  /* Neu in Runde 3 (SPEC-RUNDE-2 Abschnitt 9.3 „mehr Farbe von Intro bis
     Cortenstahl", Storyboard 0.8). Körperfarben – nie additiv, nie
     transparent, nie moduliert; die Seitenstufe liefert mat.side() in
     /js/story/palette.js. Werte identisch dort gespiegelt. */
  --signal: #F2B705;    /* Kranbrücke, Laufkatze, Ameise, Helme, Bodenmarkierungen */
  --machine: #2F6DB5;   /* Schweißgeräte, Absaugarme, Maschinengehäuse, Arbeitskleidung */
  --safety: #F07D1A;    /* Warnwesten, Hebegurte, Leitkegel, Griffe, Flaschenkappen */
  --plant: #3E8E5A;     /* Schutzgasflaschen und Ventile (--go bleibt DiveAir) */

  /* Transluzente Tokens: in palette.js stehen Farbe und Deckung getrennt
     (--glass #DCE6EA @ 30 %, --shadow #1C1F22 @ 12 %). */
  --glass: rgba(220, 230, 234, 0.30);
  --shadow: rgba(28, 31, 34, 0.12);

  /* Akzent für FLÄCHEN MIT TEXT und Fließtext-Links: --accent erreicht als
     Textfarbe auf Papier nur 3,5:1 und fällt damit unter WCAG AA. */
  --accent-deep: #BC3232;

  /* RGB-Tripel für rgba()-Flächen (Backdrops, Raster) */
  --paper-rgb: 244, 242, 236;
  --ink-rgb: 28, 31, 34;
  --accent-rgb: 232, 71, 71;

  /* Runde 18 (SPEC-RUNDE-2 20, „AI-Slop"-Befund 29.09.): eigene SEITEN- und
     UI-Flaechen, getrennt von den 3D-Materialtoken oben (--paper, --paper-2,
     --floor, --line bleiben exakt wie in palette.js). Kuehles Stahlweiss
     statt des warmen Papiertons fuer Seite, Buehnengrund (unter dem Startbild
     und im Rueckfall ohne WebGL), Pop-ups, Leiste, Tasten, Formular und
     Rechtsseiten; dazu eine zweite, dunklere Stufe (Formularkarte,
     Tabellenkopf, Kasten, statische Karten) und eine kuehle UI-Linie
     (dekorative Rahmen). Der Himmel im Film ist die Kuppel aus
     scenes/shared/umgebung.js (Canvas deckend) und bleibt unveraendert.
     Die Fusszeile hat eigene Farben (--ft-*). Kontraste siehe
     docs/qa/r4-progress/r18-slop-fix.md. */
  --page: #F4F5F7;
  --page-2: #E9ECF0;
  --page-line: #C8CDD4;
  --page-rgb: 244, 245, 247;

  /* Typografie */
  --font-mono: 'Ubuntu Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --font-sans: 'Ubuntu', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Rhythmus */
  --rhythm: 96px;
  --radius: 4px;
  --rule: 1px;

  /* Kapitel- und Zonenhöhen (Storyboard 0.4, RUNDE 4) – Desktop.
     Kette: 200 + 80 + 220 + 80 + 240 + 170 + 230 + 140 + 200 + 125 + 230
            + 100 + 260 = 2.275 vh (Runde 4d: Schwenk diveair>montage 180 → 125 vh). Kein Outro (SPEC-RUNDE-2, Nachtrag):
     unter dem Kapitel kontakt beginnt direkt die Fußzeile.
     Reihenfolge: intro · fachwerk · hochbeet · carport · diveair · montage
     · kontakt (diveair und montage haben in Runde 3 getauscht).
     RUNDE 4 (SPEC-RUNDE-2 10.7, „Animation Richtung Schreibtisch zu langsam"):
     Zone montage>kontakt 160 → 100 vh (mobil 120 → 80 vh). Die Kette ist
     20,2 m lang – das sind 0,202 m/vh statt 0,126 m/vh, bei 14 vh/s Autoscroll
     7,1 s statt 11,4 s. Der WEG (zwei Türwischer über data-via) ist
     unverändert: die Engine fährt die Kurve bogenlängenparametrisiert, die
     Zonenhöhe bestimmt nur das Tempo. */
  --h-intro: 200vh;
  --h-fachwerk: 220vh;
  --h-hochbeet: 240vh;     /* + Kranhub (SPEC-RUNDE-2 9.2) */
  --h-carport: 230vh;      /* + I-Träger längs und quer, Wellblechbahnen */
  --h-diveair: 200vh;
  --h-montage: 230vh;
  --h-kontakt: 260vh;
  --h-transition: 80vh;
  /* Vier Zonen brauchen mehr Weg: Torfahrt, Auto zur Füllstation,
     der Schwenk und die beiden Türwischer. */
  --h-t-hochbeet-carport: 330vh;  /* Runde 11b (SPEC 19, Verweilen per data-dwell): war 300vh; Runde 11 (SPEC-RUNDE-2 17, Pause im Schwenk: Corten-Garten + Regal ganz im Bild): war 170vh */
  --h-t-carport-diveair: 140vh;
  --h-t-diveair-montage: 125vh;   /* Runde 4d (SPEC 11.4, Betreiber: „etwas schneller zur Treppe schwenken"): war 180vh */
  --h-t-montage-kontakt: 430vh;   /* Runde 14 (Final Review kamera-02, Planecke-Halt): war 390vh. Runde 11b (SPEC 19, Verweilen per data-dwell): war 290vh; Kette Desktop 2.725 vh. Runde 11 (SPEC-RUNDE-2 17/18, Haltepunkt Europakarte): war 160vh (Runde 9), davor 100vh (Runde 4 / 10.7: 160 → 100) */

  color-scheme: light;
}

[data-theme="dark"] {
  --paper: #15171A;
  --paper-2: #20242A;
  --floor: #131619;
  --ink: #ECEAE4;
  --graphite: #A9AEB5;
  --line: #3C424A;
  --metal: #7E848B;
  --steel: #9AA1A9;
  --inox: #C2C7CC;
  --corten: #A85A38;
  --accent: #F05A5A;
  --spark: #FFE2B0;

  --rust: #8C6A52;
  --wood: #9E8358;
  --arc: #EAF6FF;
  --go: #57C98C;

  /* Runde 3 (Storyboard 0.8) */
  --signal: #F7C33C;
  --machine: #5B93D6;
  --safety: #F5993F;
  --plant: #5DB57E;

  --glass: rgba(127, 160, 174, 0.25);
  --shadow: rgba(0, 0, 0, 0.35);
  --accent-deep: #F05A5A;

  --paper-rgb: 21, 23, 26;
  --ink-rgb: 236, 234, 228;
  --accent-rgb: 240, 90, 90;

  /* Runde 18: Seiten-/UI-Flaechen im Dark-Theme = bisherige Werte */
  --page: #15171A;
  --page-2: #20242A;
  --page-line: #3C424A;
  --page-rgb: 21, 23, 26;

  color-scheme: dark;
}

/* Ohne JavaScript setzt niemand data-theme – dann entscheidet die
   Systemeinstellung (Spec 2.1: kein Toggle, Theme folgt prefers-color-scheme). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #15171A;
    --paper-2: #20242A;
    --floor: #131619;
    --ink: #ECEAE4;
    --graphite: #A9AEB5;
    --line: #3C424A;
    --metal: #7E848B;
    --steel: #9AA1A9;
    --inox: #C2C7CC;
    --corten: #A85A38;
    --accent: #F05A5A;
    --spark: #FFE2B0;
    --rust: #8C6A52;
    --wood: #9E8358;
    --arc: #EAF6FF;
    --go: #57C98C;
    --signal: #F7C33C;
    --machine: #5B93D6;
    --safety: #F5993F;
    --plant: #5DB57E;
    --glass: rgba(127, 160, 174, 0.25);
    --shadow: rgba(0, 0, 0, 0.35);
    --accent-deep: #F05A5A;
    --paper-rgb: 21, 23, 26;
    --ink-rgb: 236, 234, 228;
    --accent-rgb: 240, 90, 90;
    --page: #15171A;
    --page-2: #20242A;
    --page-line: #3C424A;
    --page-rgb: 21, 23, 26;
    color-scheme: dark;
  }
}

@media (max-width: 767.98px) {
  :root {
    --rhythm: 64px;
    /* Kapitelhöhen mobil (Storyboard 0.4) */
    --h-intro: 150vh;
    --h-fachwerk: 160vh;
    --h-hochbeet: 180vh;
    --h-carport: 170vh;
    --h-diveair: 150vh;
    --h-montage: 170vh;
    --h-kontakt: 220vh;
    --h-transition: 60vh;
    --h-t-hochbeet-carport: 310vh;  /* Runde 11b (Verweilen per data-dwell): war 280vh; Runde 11 (Pause im Schwenk): war 130vh */
    --h-t-carport-diveair: 105vh;
    --h-t-diveair-montage: 95vh;    /* Runde 4d (11.4): war 135vh; Kette mobil 1.730 vh */
    --h-t-montage-kontakt: 390vh;   /* Runde 14 (kamera-02, Planecke-Halt): war 350vh. Runde 11b (Verweilen per data-dwell): war 260vh; Kette mobil 2.180 vh. Runde 11 (Haltepunkt Europakarte): war 110vh (Runde 9), davor 80vh (Runde 4 / 10.7: 120 → 80) */
  }
}


/* =========================================================================
   === Grundgerüst ===
   Seite, Header (nur Wortmarke), Footer, schlanke Vorlage der Rechtsseiten
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-padding-top: 4rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background-color: var(--page);
  color: var(--graphite);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
}

h1, h2, h3, h4, h5, h6 {
  color: var(--ink);
  font-family: var(--font-sans);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

a { color: var(--accent-deep); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 2px;
}

.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Sprunglink (Audit html-css-a11y-2): erstes fokussierbares Element der Seite,
   sichtbar nur bei Tastaturfokus. Ziel ist der Anker #kontakt im Kapitel
   „kontakt" (siehe .story__anchor). */
.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 30;
  padding: 0.65rem 1.1rem;
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  background-color: var(--page);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 6px 20px rgba(var(--ink-rgb), 0.12);
}

.skip-link:not(:focus) {
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  box-shadow: none;
}

/* --- Header: nur die Wortmarke (Spec 2.1) -------------------------------- */

.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  padding: 0.9rem clamp(1rem, 3vw, 2.2rem);
  pointer-events: none;                     /* der Scroll gehört der Seite */
  background: transparent;
}

/* Runde 18 (SPEC-RUNDE-2 20): die EINZIGE Stelle mit Versalien + Sperrung ist
   die Wortmarke (Kopf und Fuss) – sie gibt den Logo-Schriftzug wieder (Logo
   img/logo-alc.png: „A L C / METALLTECHNIK“ gesperrt in Versalien), keine
   Abschnittsbeschriftung. Alle Beschriftungen stehen in Satzschreibung. */
.site-header__mark {
  display: inline-block;
  pointer-events: auto;
  font-family: var(--font-mono);
  font-size: 0.86rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.site-header__mark b { color: var(--accent-deep); font-weight: 700; }
.site-header__mark span { font-weight: 400; color: var(--graphite); }

/* Tablet und Handy: kein Header (Spec 2.1). */
@media (max-width: 1024px) {
  .site-header { display: none; }
}

/* --- Footer (Spec 2.4; Runde 13 „Footer neu", SPEC-RUNDE-2 19) -------------
   Betreiber 27.09.: „der Footer gefällt mir nicht" → kompakt & edel.
   Dunkle, ruhige Leiste in BEIDEN Themes (Light: Tinte #1C1F22, Dark: eine
   Stufe unter dem Papier, mit Haarlinie oben). Die Farben sind footer-lokale
   Variablen aus den Palette-Werten (--ink light / --ink, --graphite,
   --accent dark), weil die globalen Tokens mit dem Theme umspringen.
   Kontrast (WCAG): Text #ECEAE4 13,8:1 · Nebentext #A9AEB5 7,4:1 ·
   Akzent/Fokus #F05A5A 5,0:1 auf #1C1F22 (auf #0E1012: 15,9 / 8,5 / 5,7).
   Aufbau (auf index, impressum, datenschutz, cookie identisch):
     Wortmarke + Adresse | Kontakt (Symbole) | LinkedIn, Facebook
     fünf Marken-Chips (neuer Tab)
     Schlusszeile: © 2026 ALC Metalltechnik GmbH · Impressum · Datenschutz · Cookies
   Icons sind Inline-SVG (kein Request), keine Cookies/kein Storage. */

.site-footer {
  --ft-bg: #1C1F22;
  --ft-edge: #1C1F22;                        /* Light: dunkle Kante reicht */
  --ft-fg: #ECEAE4;
  --ft-muted: #A9AEB5;
  --ft-accent: #F05A5A;
  --ft-accent-rgb: 240, 90, 90;
  --ft-line: rgba(236, 234, 228, 0.12);      /* Haarlinien, dekorativ */
  --ft-ring: rgba(236, 234, 228, 0.18);      /* Chip-/Knopfrand, dekorativ */
  --ft-pad: clamp(1rem, 4vw, 2.5rem);

  position: relative;
  z-index: 4;
  background-color: var(--ft-bg);
  border-top: var(--rule) solid var(--ft-edge);
  color: var(--ft-muted);
  padding: clamp(2.25rem, 4.5vw, 3.25rem) 0 1.4rem;
  font-family: var(--font-sans);
  font-size: 0.92rem;
  line-height: 1.55;
}

/* Dark: eine Stufe unter dem Papier (#15171A), Haarlinie trennt die Leiste
   von der Bühne. Beide Wege wie die Tokens: data-theme und Systemeinstellung. */
[data-theme="dark"] .site-footer {
  --ft-bg: #0E1012;
  --ft-edge: #2A2F36;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-footer {
    --ft-bg: #0E1012;
    --ft-edge: #2A2F36;
  }
}

.site-footer ul { margin: 0; padding: 0; list-style: none; }
.site-footer p { margin: 0; }

.site-footer a {
  color: var(--ft-fg);
  text-decoration: none;
}

.site-footer a:focus-visible {
  outline: 2px solid var(--ft-accent);
  outline-offset: 3px;
}

.site-footer__inner {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 var(--ft-pad);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas:
    "brand   contact social"
    "brands  brands  brands";
  align-items: center;
  gap: 1.9rem clamp(1.5rem, 4vw, 3.25rem);
}

/* Wortmarke wie im Kopf (Ubuntu Mono lokal), darüber ein kurzer Akzentstrich */
.site-footer__brand { grid-area: brand; min-width: 0; }

.site-footer__mark {
  font-family: var(--font-mono);
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ft-fg);
  line-height: 1.3;
}
.site-footer__mark::before {
  content: "";
  display: block;
  width: 1.75rem;
  height: 2px;
  margin-bottom: 0.85rem;
  background-color: var(--ft-accent);
}
.site-footer__mark b { color: var(--ft-accent); font-weight: 700; }
.site-footer__mark span { color: var(--ft-muted); font-weight: 400; }

.site-footer__address {
  margin-top: 0.4rem;
  font-style: normal;
  color: var(--ft-muted);
}
/* Runde 14 (Final Review seo-inhalt-03): Öffnungszeiten unter der Adresse */
.site-footer__hours {
  margin-top: 0.15rem;
  color: var(--ft-muted);
}
.site-footer__hours span { white-space: nowrap; }

/* Kontakt mit kleinen Symbolen */
.site-footer__contact {
  grid-area: contact;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.75rem;
}

.site-footer__contact a {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 2rem;
  white-space: nowrap;
}
.site-footer__contact svg {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  color: var(--ft-muted);
}
.site-footer__contact a:hover { color: var(--ft-accent); }
.site-footer__contact a:hover svg { color: var(--ft-accent); }
.site-footer__contact a:hover span {
  text-decoration: underline;
  text-underline-offset: 0.22em;
}

/* Social: nur LinkedIn und Facebook, runde Knöpfe */
.site-footer__social {
  grid-area: social;
  display: flex;
  gap: 0.6rem;
}

.site-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: var(--rule) solid var(--ft-ring);
  border-radius: 50%;
}
.site-footer__social svg { width: 1.05rem; height: 1.05rem; }
.site-footer__social a:hover {
  border-color: var(--ft-accent);
  color: var(--ft-accent);
}
.site-footer__social a:focus-visible { outline-offset: 2px; }

/* Fünf Marken als schlichte Chips */
.site-footer__brands { grid-area: brands; }

.site-footer__brands ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
}

.site-footer__brands a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 2.1rem;
  padding: 0.3rem 0.95rem;
  border: var(--rule) solid var(--ft-ring);
  border-radius: 999px;
  background-color: rgba(236, 234, 228, 0.03);
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  line-height: 1.2;
  color: var(--ft-fg);
}
.site-footer__brands svg {
  flex: none;
  width: 0.62rem;
  height: 0.62rem;
  color: var(--ft-muted);
}
.site-footer__brands a:hover {
  border-color: var(--ft-accent);
  background-color: rgba(var(--ft-accent-rgb), 0.08);
}
.site-footer__brands a:hover svg { color: var(--ft-accent); }

/* Schlusszeile: Rechtslinks genau einmal */
.site-footer__legal {
  position: relative;
  max-width: 72rem;
  margin: 2.1rem auto 0;
  padding: 1.1rem var(--ft-pad) 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 1.5rem;
  align-items: baseline;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: var(--ft-muted);
}
.site-footer__legal::before {               /* Haarlinie nur über dem Inhalt */
  content: "";
  position: absolute;
  top: 0;
  left: var(--ft-pad);
  right: var(--ft-pad);
  height: 1px;
  background-color: var(--ft-line);
}

.site-footer__legal nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.6rem;
}
.site-footer__legal a {
  position: relative;
  color: var(--ft-muted);
}
.site-footer__legal a + a::before {         /* Trennpunkt, nicht klickbar */
  content: "";
  position: absolute;
  top: 50%;
  left: -0.8rem;
  width: 3px;
  height: 3px;
  margin: -1px 0 0 -1.5px;
  border-radius: 50%;
  background-color: var(--ft-muted);
  opacity: 0.55;
  pointer-events: none;
}
.site-footer__legal a:hover {
  color: var(--ft-fg);
  text-decoration: underline;
  text-underline-offset: 0.22em;
}

@media (prefers-reduced-motion: no-preference) {
  .site-footer a,
  .site-footer svg {
    transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
  }
}

/* Tablet: Social rechts neben der Wortmarke, Kontakt darunter */
@media (max-width: 899.98px) {
  .site-footer__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "brand   social"
      "contact contact"
      "brands  brands";
    align-items: start;
    gap: 1.5rem 1.5rem;
  }
}

/* Handy: Wortmarke oben, Kontakt je Zeile mit den Social-Knöpfen rechts
   daneben, Chips darunter, Schlusszeile zweizeilig */
@media (max-width: 559.98px) {
  .site-footer { padding-top: 2.25rem; }
  .site-footer__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "brand   brand"
      "contact social"
      "brands  brands";
    align-items: center;
    gap: 1.4rem 1rem;
  }
  .site-footer__contact { flex-direction: column; gap: 0.2rem; }
  .site-footer__brands ul { gap: 0.5rem; }
  .site-footer__legal { flex-direction: column; gap: 0.55rem; margin-top: 1.8rem; }
}

/* --- Rechtsseiten: schlanke eigene Vorlage (Spec 2.4) --------------------- */

.page {
  max-width: 52rem;
  margin: 0 auto;
  padding: clamp(4rem, 10vw, 7rem) clamp(1rem, 4vw, 2rem) var(--rhythm);
}

/* Runde 18 (SPEC-RUNDE-2 20): keine Versalien/Sperrung mehr – die Dachzeile
   steht als ruhige Zeile in Satzschreibung (Sans, gedaempft) ueber der h1. */
.page__eyebrow {
  font-family: var(--font-sans);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--graphite);
  margin: 0 0 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.page__eyebrow::before {
  content: "";
  width: 1.7rem;
  height: 2px;
  background-color: var(--accent);
}

.page h1 {
  font-size: clamp(1.9rem, 4.5vw, 2.8rem);
  font-weight: 700;
  margin: 0 0 1.5rem;
}

.page h2 {
  font-size: clamp(1.2rem, 2.4vw, 1.5rem);
  font-weight: 500;
  margin: 2.2rem 0 0.7rem;
  padding-top: 0.9rem;
  border-top: var(--rule) solid var(--page-line);
}

.page h3 {
  font-size: 1.02rem;
  font-weight: 700;
  margin: 1.4rem 0 0.5rem;
}

.page p, .page li { max-width: 62ch; }
.page ul, .page ol { padding-left: 1.3rem; }
.page li { margin-bottom: 0.3rem; }

.page table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.8rem 0 1.4rem;
  font-size: 0.92rem;
}

.page th, .page td {
  border: var(--rule) solid var(--page-line);
  padding: 0.45rem 0.6rem;
  text-align: left;
  vertical-align: top;
}

.page th { background: var(--page-2); color: var(--ink); font-weight: 700; }

.page__back {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 2.5rem 0 0;
  padding: 0.7rem 1.3rem;
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
}

.page__back:hover,
.page__back:focus {
  background-color: var(--accent-deep);
  border-color: var(--accent-deep);
  color: var(--page);
  text-decoration: none;
}

.page__toc {
  background: var(--page-2);
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  padding: 1.1rem 1.4rem;
  margin: 0 0 2rem;
}

.page__toc h2 {
  margin: 0 0 0.6rem;
  padding: 0;
  border: 0;
  font-size: 0.78rem;
  font-family: var(--font-mono);
}

.page__note {
  border-left: 3px solid var(--accent);
  background: var(--page-2);
  padding: 0.9rem 1.1rem;
  margin: 1.2rem 0;
  border-radius: 0 var(--radius) var(--radius) 0;
}


/* =========================================================================
   === Story ===
   3D-Scroll-Story „Werkstatt-Blaupause" (Spec 2.2, Storyboard 0.4)
   ========================================================================= */

#werkstatt.story {
  position: relative;
  padding: 0;
  margin: 0;
  background-color: var(--page);
  color: var(--ink);
  overflow: visible;
}

/* Die Bühne klebt, die Kapitel scrollen darüber hinweg. Sie sitzt dafür in
   einem absolut positionierten Rahmen, der genau die Sektion ausfüllt: der
   Rahmen trägt keine Layouthöhe (die Kapitel bestimmen die Sektionshöhe allein),
   und die klebende Bühne wird sauber an der Sektionsunterkante entlassen. */
#werkstatt .story__stagewrap {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 1;
  pointer-events: none;
}

#werkstatt .story__stage {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background-color: var(--page);

  /* Blaupausen-Raster: 8-px-Feinraster über 40-px-Grobraster, Deckung <= 6 %. */
  background-image:
    repeating-linear-gradient(to right, rgba(var(--ink-rgb), 0.055) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(to bottom, rgba(var(--ink-rgb), 0.055) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(to right, rgba(var(--ink-rgb), 0.026) 0 1px, transparent 1px 8px),
    repeating-linear-gradient(to bottom, rgba(var(--ink-rgb), 0.026) 0 1px, transparent 1px 8px);
  background-position: center center;
}

#werkstatt .story__canvas {
  display: block;
  width: 100%;
  height: 100%;
  /* Der Canvas ist transparent – das Raster darunter bleibt sichtbar. */
}

/* --- Fortschrittsleiste --------------------------------------------------- *
   Runde 18 (SPEC-RUNDE-2 20, Betreiber 29.09.: „1 einleitung – dann
   businessunit-url – 6 kontakt"): statt der Nummern 01–06 stehen die
   Stationen in der Leiste – Einleitung, pooldecks.eu, cortenstahl.shop,
   ihrcarport.eu, diveair.eu, schlossermeister.cc, Kontakt (Markup
   .story__progress-label, Satzschreibung, keine Sperrung). Reine Anzeige
   (aria-hidden, keine Links). Hochkant unter 1100 px nur Striche (Block
   „Runde 15 … nk-04" weiter unten), quer <= 500 px hoch ausgeblendet. */

#werkstatt .story__progress {
  position: absolute;
  top: 50%;
  right: clamp(0.9rem, 3vw, 2.6rem);
  transform: translateY(-50%);
  margin: 0;
  /* Runde 18: knapper als die Nummernleiste (Stationsnamen sind breiter) –
     Schrift 0,7…0,78rem je Fensterbreite, Ticks und Innenabstand kleiner. */
  padding: 0.55rem 0.5rem 0.55rem 0.6rem;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.15rem;
  font-family: var(--font-mono);
  font-size: clamp(0.7rem, 0.55rem + 0.25vw, 0.78rem);
  color: var(--graphite);
  /* Runde 14 (Final Review barrierefreiheit-kontrast-kapitelleiste, WCAG
     1.4.3): die Nummern standen ohne Flaeche auf dem Canvas (bis 1,04:1).
     Jetzt eine ruhige Flaeche wie bei den Tasten, aber zu 94 % deckend
     (Text braucht 4,5:1): --graphite und --accent-deep erreichen darauf im
     ungünstigsten Fall (schwarzes bzw. weisses Bild dahinter) Light 7,1:1 /
     4,9:1, Dark 5,5:1 / 4,5:1. */
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  background-color: rgba(var(--page-rgb), 0.94);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  transition: opacity 0.4s linear;
}

/* Audit html-css-a11y-7 / Runde 14: KEINE Deckung 0,75 mehr auf den nicht
   aktiven Eintraegen (Final Review: bis 1,04:1) – alle voll deckend,
   inaktiv --graphite, erledigt --ink, aktiv --accent-deep fett (Ubuntu Mono:
   fett gleich breit, die Leiste springt nicht). */
#werkstatt .story__progress li {
  position: relative;
  padding-right: 1.65rem;
  line-height: 1;
  text-align: right;
  white-space: nowrap;
  transition: color 0.25s linear, opacity 0.25s linear;
}

/* Ticks rechts neben dem Eintrag – Zeichnungssprache statt Punkte. */
#werkstatt .story__progress li::after {
  content: "";
  position: absolute;
  right: 0;
  top: 50%;
  width: 1.1rem;
  height: 1px;
  background-color: currentColor;
  transform: translateY(-50%) scaleX(0.55);
  transform-origin: right center;
  transition: transform 0.25s ease-out;
}

#werkstatt .story__progress li.is-done { color: var(--ink); }
#werkstatt .story__progress li.is-active { color: var(--accent-deep); font-weight: 700; opacity: 1; }
#werkstatt .story__progress li.is-active::after { transform: translateY(-50%) scaleX(1); }

/* --- Autoscroll-Taste (Storyboard 0.12, neu in Runde 2) ------------------ *
   Eine einzige Taste, unten rechts an derselben Flucht wie die Fortschritts-
   leiste. Sie wird von der Engine eingehängt: erst wenn der Autoscroll
   wirklich läuft, setzt sie <html class="story-autoscroll"> – bei
   ?autoplay=0, prefers-reduced-motion und im Fallback ohne WebGL bleibt die
   Taste deshalb unsichtbar und unbedienbar (kein toter Knopf).            */

#werkstatt .story__controls {
  position: absolute;
  right: clamp(0.9rem, 3vw, 2.6rem);
  bottom: clamp(1.1rem, 4vh, 2.4rem);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  pointer-events: none;
}

#werkstatt .story__autoplay {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  margin: 0;
  align-items: center;
  justify-content: center;
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  background-color: rgba(var(--page-rgb), 0.86);
  color: var(--ink);
  cursor: pointer;
  pointer-events: auto;
  transition: border-color 0.2s linear, color 0.2s linear, background-color 0.2s linear;
}

.story-autoscroll #werkstatt .story__autoplay { display: inline-flex; }

/* Runde 14 (Final Review funktion-5, SPEC-RUNDE-2 18 „Bedienelemente …
   liegen darueber", SPEC 3 „sichtbar ab dem ersten Bild"): die Play-Taste
   steht schon im Startbild, BEVOR die Engine geladen ist (vorher erst mit
   .story-autoscroll – bis zu mehreren Sekunden nur der Theme-Schalter, der
   dann um ~41 px zur Seite sprang). Bis <html class="story-ready"> im
   Zustand „armed" (Markup: Play-Symbol) ohne ablaufenden Balken, Zeiger
   „progress" (der Film laedt noch). Mit story-ready uebernimmt die Engine:
   Autoplay -> .story-autoscroll wie bisher; ?autoplay=0 (nur QA) -> Taste
   weg. Bei reduzierter Bewegung gibt es keinen Autoplay – dort bleibt sie
   auch waehrend des Ladens aus. Ohne WebGL/JS: kein Knopf. */
html.js:not(.story-nogl):not(.story-ready) #werkstatt .story__autoplay {
  display: inline-flex;
  cursor: progress;
}
html.js:not(.story-ready) #werkstatt .story__autoplay::after { display: none; }
@media (prefers-reduced-motion: reduce) {
  html.js:not(.story-nogl):not(.story-ready) #werkstatt .story__autoplay { display: none; }
}

#werkstatt .story__autoplay svg { display: block; width: 18px; height: 18px; }
/* Symbolwechsel (Audit html-css-a11y-8): der Zustand steht in
   data-state="running|paused" – Muster „wechselndes aria-label", KEIN
   aria-pressed mehr (beides zusammen widerspricht sich in der Sprachausgabe).
   Solange engine.js noch aria-pressed schreibt, gilt uebergangsweise auch das. */
#werkstatt .story__autoplay .story__autoplay-play { display: none; }
#werkstatt .story__autoplay[data-state="paused"] .story__autoplay-play,
#werkstatt .story__autoplay[aria-pressed="false"] .story__autoplay-play { display: block; }
#werkstatt .story__autoplay[data-state="paused"] .story__autoplay-pause,
#werkstatt .story__autoplay[aria-pressed="false"] .story__autoplay-pause { display: none; }

/* Runde 12 (SPEC-RUNDE-2 18): data-state="armed" = der Film steht, laeuft aber
   nach 10 s ohne Eingabe von selbst (wieder) an. Play-Symbol wie „paused",
   dazu ein duenner Balken unten in der Taste, der in 10 s voll laeuft. Die
   Engine startet die Animation bei jedem Neu-Scharfschalten neu. */
#werkstatt .story__autoplay { position: relative; overflow: hidden; }
#werkstatt .story__autoplay[data-state="armed"] .story__autoplay-play { display: block; }
#werkstatt .story__autoplay[data-state="armed"] .story__autoplay-pause { display: none; }
#werkstatt .story__autoplay[data-state="armed"]::after {
  content: "";
  position: absolute;
  left: 5px; right: 5px; bottom: 4px;
  height: 2px;
  border-radius: 1px;
  background-color: var(--accent-deep);
  transform-origin: 0 50%;
  transform: scaleX(0);
  animation: alc-autoplay-arm var(--arm-ms, 10000ms) linear forwards;
}
@keyframes alc-autoplay-arm {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

#werkstatt .story__autoplay:hover { border-color: var(--graphite); }
#werkstatt .story__autoplay:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Zustandsmeldung für Screenreader – sichtbar nur für assistive Technik. */
#werkstatt .story__autoplay-status {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Light/Dark-Schalter (Betreiber 26.09.) -------------------------------
   Gleiche Bauart wie die Autoplay-Taste; sichtbar, sobald JavaScript laeuft
   (ohne JS gibt es nichts umzuschalten, das Theme folgt dem System). */
#werkstatt .story__controls { gap: 0.6rem; }
#werkstatt .story__theme {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  margin: 0;
  align-items: center;
  justify-content: center;
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  background-color: rgba(var(--page-rgb), 0.86);
  color: var(--ink);
  cursor: pointer;
  pointer-events: auto;
  transition: border-color 0.2s linear, color 0.2s linear, background-color 0.2s linear;
}
html.js:not(.story-nogl) #werkstatt .story__theme { display: inline-flex; }
#werkstatt .story__theme svg { display: block; width: 18px; height: 18px; }
#werkstatt .story__theme .story__theme-sun { display: none; }
[data-theme="dark"] #werkstatt .story__theme .story__theme-moon { display: none; }
[data-theme="dark"] #werkstatt .story__theme .story__theme-sun { display: block; }
#werkstatt .story__theme:hover { border-color: var(--graphite); }
#werkstatt .story__theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- Rechtslinks ueber der Buehne (Runde 14, Final Review recht-1) --------
   § 5 Abs. 1 ECG: Impressum/Datenschutz „leicht und unmittelbar zugaenglich"
   – bisher nur in der Schlusszeile am Filmende. Kleine, ruhige Pille im Stil
   der Tasten, dauerhaft sichtbar (klebt mit der Buehne), bewegt sich nicht
   mit dem Startbild-Zustand. Desktop: rechts unten UEBER Theme-/Play-Taste
   (Kapitelleiste und mittige Pop-up-Karte bleiben frei); niedrige Fenster
   (<= 560 px): links neben den Tasten in derselben Zeile; mobil: oben rechts
   UNTER den Tasten. --ink auf 90 % Papier (>= 12:1). Zielgroesse >= 24 px. */
#werkstatt .story__legal {
  position: absolute;
  right: clamp(0.9rem, 3vw, 2.6rem);
  bottom: calc(clamp(1.1rem, 4vh, 2.4rem) + 44px + 0.5rem);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.1rem;
  margin: 0;
  padding: 0 0.3rem;
  border: var(--rule) solid var(--page-line);
  border-radius: 999px;
  background-color: rgba(var(--page-rgb), 0.9);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  line-height: 1;
  pointer-events: none;
}
#werkstatt .story__legal a {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  padding: 0 0.4rem;
  color: var(--ink);
  text-decoration: none;
  pointer-events: auto;
}
#werkstatt .story__legal a:hover { text-decoration: underline; text-underline-offset: 0.2em; }
#werkstatt .story__legal a:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: 1px; border-radius: 999px; }
#werkstatt .story__legal-sep { color: var(--graphite); }
@media (min-width: 768px) and (max-height: 560px) {
  #werkstatt .story__legal {
    right: calc(clamp(0.9rem, 3vw, 2.6rem) + 88px + 1.2rem);
    bottom: calc(clamp(1.1rem, 4vh, 2.4rem) + 9px);
  }
}
@media (max-width: 767.98px) {
  #werkstatt .story__legal {
    top: calc(clamp(0.8rem, 3vh, 1.6rem) + 44px + 0.4rem);
    bottom: auto;
    right: clamp(0.9rem, 3vw, 2.6rem);
    font-size: 0.68rem;
  }
}

/* --- Startbild (Runde 12, SPEC-RUNDE-2 18; ersetzt das ALC-Start-Bild 4e) --
   Beim Laden liegt das ERSTE FILMBILD (intro t = 0) als Standbild ueber dem
   noch leeren Canvas (.story__poster), darueber Play-Taste und Light/Dark-
   Schalter gross unten mittig und der Hinweis „Scrollen, um abzuspielen".
   Der Zustand „Startbild" gilt, solange <html> NICHT .story-started traegt
   (setzt engine.js beim ersten Scrollen, beim Start des Films und bei einem
   Deep-Link) – vor dem ersten Paint ohne Skript, CSS-Standard. Ein Deep-Link
   (#kontakt, #fachwerk …) zeigt kein Startbild (:target, schon vor der
   Engine). Die Klasse .story-splash von theme.js wirkt nicht mehr.
   Das Standbild blendet weich aus, sobald die Engine das erste vollstaendige
   WebGL-Bild gezeichnet hat (<html class="story-live">); Bildausschnitt
   deckungsgleich: hoehenfuellend und mittig wie die Kamera (festes
   vertikales Sichtfeld). Positioniert wird die Taste immer ueber `left` +
   translateX, damit beide Zustaende stetig ineinander uebergehen. */
#werkstatt .story__controls {
  right: auto;
  left: calc(100% - clamp(0.9rem, 3vw, 2.6rem));
  transform: translateX(-100%);
  transform-origin: 50% 100%;
  transition: left 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              bottom 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
html.js:not(.story-nogl):not(.story-started) #werkstatt .story__controls {
  left: 50%;
  bottom: clamp(2.4rem, 11vh, 6rem);
  transform: translateX(-50%) scale(1.6);
}
html.js:has(#werkstatt :target) #werkstatt .story__controls {
  left: calc(100% - clamp(0.9rem, 3vw, 2.6rem));
  bottom: clamp(1.1rem, 4vh, 2.4rem);
  transform: translateX(-100%);
}

/* Standbild: nur der WebGL-Canvas (tools/startbild/erzeuge-startbild.mjs),
   das Blaupausen-Raster der Buehne bleibt live. */
#werkstatt .story__poster {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background-color: transparent;
  background-image: url("/img/startbild-desktop-light.webp");
  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: auto 100%;
  pointer-events: none;
  opacity: 1;
  visibility: visible;
  /* kurz genug, dass bewegte Figuren (Ambient-Posen seit dem Laden) nicht
     sichtbar doppelt stehen, lang genug fuer einen weichen Wechsel */
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}
[data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-desktop-dark.webp"); }
@media (max-width: 767.98px) {
  #werkstatt .story__poster { background-image: url("/img/startbild-mobil-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-mobil-dark.webp"); }
}
/* Runde 14 (Final Review funktion-4): das Hochformat-Bild deckt nur bis
   0,54:1 – Smartphones QUER (und breitere Fenster unter 768 px, ab 3:5)
   bekommen einen eigenen Satz mit der Mobilkamera bis 2,3:1
   (startbild-mobilquer-*, 1149 x 499); Tablets HOCHKANT 768–1099 px nutzen
   seit kamera-03 (engine.js detect(): h > w && w < 1100) ebenfalls die
   Mobilkamera -> startbild-tablet-* (Mobilkamera, bis 0,87:1, 1440 x 1650).
   Das Desktop-Bild ist jetzt 2,4:1 (2400 x 1000) und deckt 21:9-Monitore.
   Erzeugt mit den Aufnahmeparametern von tools/startbild/erzeuge-startbild.mjs
   (Varianten siehe docs/qa/r4-progress/r14-fix-seite.md). */
@media (max-width: 767.98px) and (min-aspect-ratio: 3/5) {
  #werkstatt .story__poster { background-image: url("/img/startbild-mobilquer-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-mobilquer-dark.webp"); }
}
@media (min-width: 768px) and (max-width: 1099.98px) and (orientation: portrait) {
  #werkstatt .story__poster { background-image: url("/img/startbild-tablet-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-tablet-dark.webp"); }
}
html.story-live #werkstatt .story__poster,
html.js:has(#werkstatt :target) #werkstatt .story__poster {
  opacity: 0;
  visibility: hidden;
}

/* Hinweis „Scrollen, um abzuspielen" – etwas unter der Bildmitte (wie unter
   dem frueheren Schriftzug); der Pfeil wippt, bei reduzierter Bewegung nicht. */
#werkstatt .story__hint {
  position: absolute;
  left: 50%;
  top: 54%;
  z-index: 2;
  margin: 0;
  padding: 0.5em 1.15em;
  transform: translate(-50%, -50%);
  border: var(--rule) solid var(--page-line);
  border-radius: 999px;
  background-color: rgba(var(--page-rgb), 0.88);
  color: var(--ink);
  font-family: 'Ubuntu', system-ui, sans-serif;
  font-weight: 500;
  font-size: clamp(0.95rem, 2.1vw, 1.3rem);
  line-height: 1.3;
  letter-spacing: 0.04em;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}
html.js:not(.story-nogl):not(.story-started) #werkstatt .story__hint {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.35s ease, visibility 0s linear 0s;
}
html.js:has(#werkstatt :target) #werkstatt .story__hint { opacity: 0; visibility: hidden; }
#werkstatt .story__hint-arrow {
  display: inline-block;
  margin-left: 0.35em;
  animation: alc-splash-hint 1.6s ease-in-out infinite;
}
@keyframes alc-splash-hint {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(0.3rem); }
}

/* Querformat-Hinweis (Runde 12): nur Smartphones im Hochformat, nur am
   Anfang (Startbild bzw. Kapitel intro), schliessbar (engine.js setzt
   <html class="story-rotate-off">, nur fuer diesen Besuch). Blockiert nichts:
   nur die Schliessen-Taste nimmt Zeiger an. */
#werkstatt .story__rotate {
  display: none;
  position: absolute;
  top: clamp(0.8rem, 3vh, 1.6rem);
  left: 0.75rem;
  z-index: 3;
  max-width: calc(100% - 8.5rem);
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.3rem 0.3rem 0.65rem;
  border: var(--rule) solid var(--page-line);
  border-radius: 999px;
  background-color: rgba(var(--page-rgb), 0.9);
  color: var(--ink);
  font-family: 'Ubuntu', system-ui, sans-serif;
  font-size: 0.82rem;
  line-height: 1.25;
  pointer-events: none;
}
#werkstatt .story__rotate-icon { flex: none; width: 20px; height: 20px; color: var(--accent-deep); }
#werkstatt .story__rotate-close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--graphite);
  cursor: pointer;
  pointer-events: auto;
}
#werkstatt .story__rotate-close svg { width: 14px; height: 14px; display: block; }
#werkstatt .story__rotate-close:hover { color: var(--ink); }
#werkstatt .story__rotate-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (max-width: 767.98px) and (orientation: portrait) and (pointer: coarse) {
  html.js:not(.story-nogl):not(.story-rotate-off) #werkstatt:not([data-stop]) .story__rotate,
  html.js:not(.story-nogl):not(.story-rotate-off) #werkstatt[data-stop="intro"] .story__rotate { display: flex; }
}

@media (prefers-reduced-motion: reduce) {
  #werkstatt .story__hint-arrow { animation: none; }
  #werkstatt .story__controls,
  #werkstatt .story__poster,
  #werkstatt .story__hint { transition: none; }
  #werkstatt .story__autoplay[data-state="armed"]::after { animation: none; transform: scaleX(1); }
}

/* Startbild bei reduzierter Bewegung (Runde 13, Rolle startbild-reduced):
   Mit prefers-reduced-motion zeigt die Engine im Intro NICHT t = 0, sondern
   eine FESTE Kamera (chapterPose(intro, REDUCED_HOLD_T = 0,5), Szene auf
   update(1), kein ambient()). Eigener Bildsatz, erzeugt mit
   tools/startbild/erzeuge-startbild.mjs --set reduced (gleiche Aufnahme-
   parameter, gleicher Ausschnitt: hoehenfuellend, mittig) – das Standbild
   geht so auch hier ohne Bildwechsel in den Film ueber. */
@media (prefers-reduced-motion: reduce) {
  #werkstatt .story__poster { background-image: url("/img/startbild-desktop-reduced-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-desktop-reduced-dark.webp"); }
}
@media (prefers-reduced-motion: reduce) and (max-width: 767.98px) {
  #werkstatt .story__poster { background-image: url("/img/startbild-mobil-reduced-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-mobil-reduced-dark.webp"); }
}
@media (prefers-reduced-motion: reduce) and (max-width: 767.98px) and (min-aspect-ratio: 3/5) {
  #werkstatt .story__poster { background-image: url("/img/startbild-mobilquer-reduced-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-mobilquer-reduced-dark.webp"); }
}
@media (prefers-reduced-motion: reduce) and (min-width: 768px) and (max-width: 1099.98px) and (orientation: portrait) {
  #werkstatt .story__poster { background-image: url("/img/startbild-tablet-reduced-light.webp"); }
  [data-theme="dark"] #werkstatt .story__poster { background-image: url("/img/startbild-tablet-reduced-dark.webp"); }
}

/* --- Kapitel und Transition-Zonen (Höhen: Storyboard 0.4) ---------------- */

#werkstatt .story__chapter {
  position: relative;
  z-index: 2;
  display: block;
  min-height: 200vh;
  pointer-events: none;   /* der Scroll gehört der Seite, nur Text/Links reagieren */
}

#werkstatt .story__chapter[data-scene="intro"]    { min-height: var(--h-intro); }
#werkstatt .story__chapter[data-scene="fachwerk"] { min-height: var(--h-fachwerk); }
#werkstatt .story__chapter[data-scene="hochbeet"] { min-height: var(--h-hochbeet); }
#werkstatt .story__chapter[data-scene="carport"]  { min-height: var(--h-carport); }
#werkstatt .story__chapter[data-scene="diveair"]  { min-height: var(--h-diveair); }
#werkstatt .story__chapter[data-scene="montage"]  { min-height: var(--h-montage); }
#werkstatt .story__chapter[data-scene="kontakt"]  { min-height: var(--h-kontakt); }

#werkstatt .story__transition {
  position: relative;
  z-index: 2;
  min-height: var(--h-transition);
  pointer-events: none;
}

/* Vier Zonen tragen mehr Weg als die Standard-80 vh (Storyboard 0.4; Runde 4:
   montage>kontakt 100 vh statt 160 vh, SPEC-RUNDE-2 10.7). */
#werkstatt .story__transition[data-from="hochbeet"][data-to="carport"] { min-height: var(--h-t-hochbeet-carport); }
#werkstatt .story__transition[data-from="carport"][data-to="diveair"]  { min-height: var(--h-t-carport-diveair); }
#werkstatt .story__transition[data-from="diveair"][data-to="montage"]  { min-height: var(--h-t-diveair-montage); }
#werkstatt .story__transition[data-from="montage"][data-to="kontakt"]  { min-height: var(--h-t-montage-kontakt); }

/* --- Kapiteltexte (Overlays) ---------------------------------------------- *
   Die Blöcke sind nach Spec 2.3 im Markup AUSKOMMENTIERT. Diese Regeln bleiben
   trotzdem stehen: das Einkommentieren der <!-- OVERLAY … --> Klammern genügt,
   es ist keine CSS-Änderung nötig. Für „kein WebGL" und reduced motion klont
   story.js die Texte aus <template class="story__fallback-text">.            */

#werkstatt .story__text {
  position: -webkit-sticky;
  position: sticky;
  top: 18vh;
  max-width: 34rem;
  margin-left: clamp(1.25rem, 7vw, 7rem);
  padding: 0;
  pointer-events: auto;
  opacity: 1;
  transform: none;
  transition: opacity 0.45s linear, transform 0.45s ease-out;
}

/* Kapitel 02 links, 03 rechts über dem Pritschenwagen (Übergabe 9.1). */
#werkstatt .story__chapter[data-scene="hochbeet"] .story__text,
#werkstatt .story__chapter[data-scene="carport"] .story__text,
#werkstatt .story__chapter[data-scene="montage"] .story__text {
  margin-left: auto;
  margin-right: clamp(1.25rem, 7vw, 7rem);
}

#werkstatt .story__chapter.is-leaving .story__text {
  opacity: 0;
  transform: translateY(-0.75rem);
  pointer-events: none;
}

/* --- Kurztext-Pop-ups (Runde 12, SPEC-RUNDE-2 18) ------------------------ *
   Ersetzen die fruehere, visuell versteckte Textalternative
   .story__text--fallback: KEIN versteckter Text mehr. Je Kapitel ein
   kompaktes Pop-up .story__pop ueber der Animation (Desktop unten links, mobil
   unten, halbtransparente Karte in Light/Dark) mit Ueberschrift, Link
   (neuer Tab) und dem bisherigen langen Text wortgleich in <details>
   „Mehr lesen" (standardmaessig zu; oeffnet nach oben, die Buehne bleibt
   stehen).
   Geometrie: .story__popwrap spannt absolut von 100vh ueber dem Kapitel bis
   zu dessen Ende; darin klebt .story__popdock (Hoehe 100vh, top 0). Damit
   steht das Dock genau von p = 0 (Kapitelanfang an der Viewport-Unterkante)
   bis p = 1 (Kapitelende an der Viewport-Unterkante) deckungsgleich ueber der
   Buehne – ohne Layouthoehe, ohne Einfluss auf das Scroll-Mapping.
   Sichtbar ist nur das Pop-up des laufenden Kapitels (#werkstatt[data-stop],
   Engine); in den Fahrten zwischen den Kapiteln keines (Europakarte in
   montage>kontakt bleibt frei). Kapitel 06: nur bis die Formularkarte
   einblendet (#werkstatt.story--form-in). Inaktive Pop-ups sind durchsichtig
   und nehmen keine Zeiger an, bleiben aber im DOM und fuer Screenreader
   lesbar; bekommt ein Link/„Mehr lesen" darin den Tastaturfokus, wird das
   Pop-up sichtbar (kein unsichtbares Fokusziel). */

#werkstatt .story__popwrap {
  position: absolute;
  top: -100vh;
  bottom: 0;
  left: 0;
  right: 0;
  pointer-events: none;
}

#werkstatt .story__popdock {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100vh;
  pointer-events: none;
}

@supports (height: 100dvh) {
  #werkstatt .story__popwrap { top: -100dvh; }
  #werkstatt .story__popdock { height: 100dvh; }
}

#werkstatt .story__pop {
  position: absolute;
  left: clamp(0.9rem, 3vw, 2.6rem);
  bottom: clamp(1.1rem, 4vh, 2.4rem);
  width: min(24rem, calc(50vw - 8rem));
  margin: 0;
  padding: 0.8rem 1rem 0.55rem 1.05rem;
  border: var(--rule) solid var(--page-line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  /* Runde 14 (barrierefreiheit-kontrast-popup-light): 0,84 -> 0,94 deckend –
     Link (bis Runde 17 auch die Nummer) in --accent-deep erreichen so auch ueber dunklen Bildteilen
     >= 4,5:1 (Light 4,9:1 im ungünstigsten Fall). */
  background-color: rgba(var(--page-rgb), 0.94);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 10px 28px rgba(var(--ink-rgb), 0.10);
  color: var(--ink);
  opacity: 0;
  transform: translateY(0.6rem);
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.22s ease;
}

#werkstatt:not([data-stop]) .story__chapter[data-scene="intro"] .story__pop,
#werkstatt[data-stop="intro"] .story__chapter[data-scene="intro"] .story__pop,
#werkstatt[data-stop="fachwerk"] .story__chapter[data-scene="fachwerk"] .story__pop,
#werkstatt[data-stop="hochbeet"] .story__chapter[data-scene="hochbeet"] .story__pop,
#werkstatt[data-stop="carport"] .story__chapter[data-scene="carport"] .story__pop,
#werkstatt[data-stop="diveair"] .story__chapter[data-scene="diveair"] .story__pop,
#werkstatt[data-stop="montage"] .story__chapter[data-scene="montage"] .story__pop,
#werkstatt[data-stop="kontakt"]:not(.story--form-in) .story__chapter[data-scene="kontakt"] .story__pop,
#werkstatt .story__pop:focus-within {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition: opacity 0.45s ease 0.08s, transform 0.45s ease 0.08s;
}

#werkstatt .story__pop-title {
  margin: 0 0 0.4rem;
  color: var(--ink);
  font-size: clamp(1.1rem, 1.45vw, 1.35rem);
  font-weight: 500;
  line-height: 1.22;
}
#werkstatt h1.story__pop-title { font-size: clamp(1.25rem, 1.9vw, 1.6rem); font-weight: 700; }

#werkstatt .story__pop .story__eyebrow { margin: 0 0 0.25rem; font-size: 0.85rem; }

#werkstatt .story__pop-lead {
  margin: 0 0 0.45rem;
  color: var(--graphite);
  font-size: 0.95rem;
  line-height: 1.45;
}

#werkstatt .story__pop-link {
  display: inline-block;
  margin: 0 0 0.3rem;
  color: var(--accent-deep);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.35;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}
#werkstatt .story__pop-link svg {
  display: inline-block;
  width: 0.78em;
  height: 0.78em;
  margin-left: 0.35em;
  vertical-align: -0.05em;
}
#werkstatt .story__pop-link:hover { color: var(--ink); }
#werkstatt .story__pop-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

#werkstatt .story__more { margin: 0; }
#werkstatt .story__more > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0;
  list-style: none;
  cursor: pointer;
  color: var(--graphite);
  font-family: var(--font-mono);
  font-size: 0.74rem;
}
#werkstatt .story__more > summary::-webkit-details-marker { display: none; }
#werkstatt .story__more > summary::after {
  content: "";
  width: 0.42rem;
  height: 0.42rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.12rem) rotate(45deg);
  transition: transform 0.2s ease;
}
#werkstatt .story__more[open] > summary::after { transform: translateY(0.1rem) rotate(-135deg); }
#werkstatt .story__more > summary:hover { color: var(--ink); }
#werkstatt .story__more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

#werkstatt .story__more-body {
  max-height: min(42vh, 20rem);
  overflow-y: auto;
  margin: 0.15rem 0 0.35rem;
  padding: 0.55rem 0.3rem 0 0;
  border-top: var(--rule) solid var(--page-line);
}
#werkstatt .story__more-body .story__eyebrow { margin: 0 0 0.35rem; font-size: 0.85rem; }
#werkstatt .story__more-body h3 {
  margin: 0 0 0.4rem;
  color: var(--ink);
  font-size: 1.02rem;
  font-weight: 500;
  line-height: 1.25;
}
#werkstatt .story__more-body p {
  max-width: none;
  margin: 0 0 0.6rem;
  color: var(--graphite);
  font-size: 0.92rem;
  line-height: 1.55;
}
#werkstatt .story__more-body .story__caption { margin: 0 0 0.6rem; }
#werkstatt .story__more-links a {
  color: var(--accent-deep);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
}

/* Niedrige Fenster im Desktop-Pfad (Smartphone quer ab 768 px, kleine
   Laptopfenster): Hinweis hoeher, Pop-up kompakter (<= ca. 1/3 der Hoehe). */
@media (min-width: 768px) and (max-height: 560px) {
  #werkstatt .story__hint { top: 40%; }
  #werkstatt .story__pop { padding: 0.55rem 0.8rem 0.35rem 0.85rem; }
  #werkstatt .story__pop-title { font-size: 1.02rem; margin-bottom: 0.25rem; }
  #werkstatt h1.story__pop-title { font-size: 1.12rem; }
  #werkstatt .story__pop-lead { font-size: 0.85rem; line-height: 1.35; margin-bottom: 0.25rem; }
  #werkstatt .story__more-body { max-height: 45vh; }
}

/* Runde 14 (Final Review barrierefreiheit-reflow-400-mehr-lesen, WCAG
   1.4.10): in sehr niedrigen Fenstern (z. B. 1280 x 1024 bei 400 % Zoom =
   320 x 256) wurde die Karte mit offenem „Mehr lesen" hoeher als das Fenster
   – Nummer und Titel oben abgeschnitten, im klebenden Dock nicht
   erreichbar. Dort ist die GANZE Karte auf die Fensterhoehe begrenzt und
   scrollt als Ganzes (eine Scrollleiste, Textfeld ohne eigene Grenze). */
@media (max-height: 420px) {
  html.js:not(.story-nogl) #werkstatt .story__pop {
    max-height: calc(100vh - 1.8rem);
    max-height: calc(100dvh - 1.8rem);
    overflow-y: auto;
  }
  html.js:not(.story-nogl) #werkstatt .story__more-body {
    max-height: none;
    overflow: visible;
  }
}

/* Runde 13 (SPEC-RUNDE-2 19, Betreiber 27.09.: „mobile Ansicht passt, die
   Textkarten am Desktop sind zu klein und sollten in der Mitte zentriert
   sein"): ab 900 px Breite bei normaler Fensterhoehe (> 560 px) deutlich
   groessere Karten, HORIZONTAL MITTIG unten. Breite hoechstens 40rem und
   20rem schmaler als die Buehne – die Tasten unten rechts und die
   Kapitelleiste rechts bleiben frei. Zentriert ueber left/right 0 + margin
   auto (transform gehoert der Einblendung). „Mehr lesen" offen: Text in
   eigener Scrollleiste, hoechstens 36vh bzw. 22rem – die Karte bleibt weit
   unter dem oberen Rand. Mobil (< 768 px), 768–899 px und niedrige Fenster
   unveraendert. */
@media (min-width: 900px) and (min-height: 561px) {
  #werkstatt .story__pop {
    left: 0;
    right: 0;
    bottom: clamp(1.4rem, 4.5vh, 2.8rem);
    width: min(40rem, calc(100% - 20rem));
    margin: 0 auto;
    padding: 1.2rem 1.7rem 0.85rem 1.8rem;
    border-left-width: 4px;
    box-shadow: 0 14px 36px rgba(var(--ink-rgb), 0.14);
  }
  #werkstatt .story__pop .story__eyebrow { margin-bottom: 0.3rem; font-size: 1rem; }
  #werkstatt .story__pop-title {
    margin-bottom: 0.55rem;
    font-size: clamp(1.6rem, 1rem + 1.1vw, 2rem);
    line-height: 1.18;
  }
  #werkstatt h1.story__pop-title { font-size: clamp(1.75rem, 1.05rem + 1.25vw, 2.2rem); }
  #werkstatt .story__pop-lead { margin-bottom: 0.6rem; font-size: 1.12rem; line-height: 1.5; }
  #werkstatt .story__pop-link { margin-bottom: 0.4rem; font-size: 1.05rem; }
  /* Nachbesserung Abnahme R13: Umschalter wie der Link ca. 1rem */
  #werkstatt .story__more > summary { padding: 0.45rem 0; font-size: 1rem; }
  #werkstatt .story__more > summary::after { width: 0.55rem; height: 0.55rem; }
  #werkstatt .story__more-body { max-height: min(36vh, 22rem); padding-top: 0.75rem; }
  #werkstatt .story__more-body p { font-size: 1.04rem; line-height: 1.62; }

  /* Startbild: das Intro-Pop-up steht jetzt unten MITTIG – Play-/Theme-Taste
     (1,6-fach) deshalb direkt unter dem Hinweis statt am unteren Rand (wie
     mobil). Hinweis wie bisher bei 54 %, in niedrigeren Fenstern so weit
     hoeher, dass Hinweis, Tasten und Karte (ca. 13rem ueber dem Rand) sich
     nicht beruehren. */
  #werkstatt .story__hint {
    top: min(54%, calc(100% - clamp(1.4rem, 4.5vh, 2.8rem) - 20.5rem));
  }
  html.js:not(.story-nogl):not(.story-started) #werkstatt .story__controls {
    bottom: max(calc(46% - 118px), calc(clamp(1.4rem, 4.5vh, 2.8rem) + 13rem));
  }

  /* Nachbesserung (Abnahme Runde 13): „Mehr lesen" im Intro-Pop-up schon im
     Startbild aufgeklappt (Klick/Enter) – die Karte waechst nach oben und lag
     ueber Hinweis und Starttasten. Dann ist die Karte auf --pop-open-max
     (62vh, hoechstens 30rem) begrenzt und scrollt als Ganzes (eine
     Scrollleiste statt zweier); Tasten und Hinweis ruecken weich UEBER diese
     hoechstmoegliche Kartenoberkante (1rem Luft; Tasten 1,6-fach = 70 px,
     Hinweis ca. 3,1rem hoch) – frei bei jeder Textlaenge. Ab 561 px
     Fensterhoehe reicht der Platz (Hinweis oben >= ca. 2rem). Nach dem Start
     (Film, Scrollen) oder mit zugeklapptem Text gilt wieder die Lage oben. */
  #werkstatt {
    --pop-b: clamp(1.4rem, 4.5vh, 2.8rem);
    --pop-open-max: min(62vh, 30rem);
  }
  html.js:not(.story-nogl):not(.story-started) #werkstatt:has(.story__chapter[data-scene="intro"] .story__more[open]) .story__chapter[data-scene="intro"] .story__pop {
    max-height: var(--pop-open-max);
    overflow-y: auto;
  }
  html.js:not(.story-nogl):not(.story-started) #werkstatt:has(.story__chapter[data-scene="intro"] .story__more[open]) .story__chapter[data-scene="intro"] .story__more-body {
    max-height: none;
    overflow: visible;
  }
  html.js:not(.story-nogl):not(.story-started) #werkstatt:has(.story__chapter[data-scene="intro"] .story__more[open]) .story__controls {
    bottom: calc(var(--pop-b) + var(--pop-open-max) + 1rem);
  }
  html.js:not(.story-nogl):not(.story-started) #werkstatt:has(.story__chapter[data-scene="intro"] .story__more[open]) .story__hint {
    top: calc(100% - var(--pop-b) - var(--pop-open-max) - 1rem - 70px - 0.9rem - 1.6rem);
  }
  @media (prefers-reduced-motion: no-preference) {
    html.js:not(.story-nogl):not(.story-started) #werkstatt .story__hint {
      transition: opacity 0.35s ease, visibility 0s linear 0s,
                  top 0.7s cubic-bezier(0.22, 1, 0.36, 1);
    }
  }
}

/* Anker #kontakt (Audit html-css-a11y-2): liegt im Kapitel „kontakt" so, dass
   der Hash-Sprung bei p = 1 landet – Kapitelende, Formular vollstaendig im
   Bild, zugleich das Ende des Autoscrolls (engine autoEndY). Das
   html { scroll-padding-top: 4rem } ist eingerechnet:
   Ankeroberkante = Kapitelende - 100vh + 4rem. */
#werkstatt .story__anchor {
  position: absolute;
  left: 0;
  bottom: calc(100vh - 4rem);
  width: 1px;
  height: 1px;
}

@supports (height: 100dvh) {
  #werkstatt .story__anchor { bottom: calc(100dvh - 4rem); }
}

/* Anker je Kapitel (Runde 12, SPEC-RUNDE-2 18): #fachwerk … #montage fuehren
   an den KapitelANFANG. Der native Sprung setzt die Ankeroberkante auf
   scroll-padding-top (4rem) – die Scrollposition ist dann Kapitelbeginn
   - 100vh + 1px, also p knapp ueber 0 (Kapitel aktiv, erstes Bild). Die
   Engine wiederholt den Sprung beim Laden exakt (innerHeight). */
#werkstatt .story__anchor--start {
  top: calc(4rem + 1px - 100vh);
  bottom: auto;
}
@supports (height: 100dvh) {
  #werkstatt .story__anchor--start { top: calc(4rem + 1px - 100dvh); bottom: auto; }
}

/* Runde 18: Dachzeile in Satzschreibung (Sans, gedaempft), keine Versalien */
#werkstatt .story__eyebrow {
  font-family: var(--font-sans);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--graphite);
  margin: 0 0 0.9rem;
}

#werkstatt .story__text h1,
#werkstatt .story__text h2 {
  color: var(--ink);
  line-height: 1.12;
  margin: 0 0 1rem;
}

#werkstatt .story__text h1 { font-size: clamp(2.1rem, 5.2vw, 3.6rem); font-weight: 700; }
#werkstatt .story__text h2 { font-size: clamp(1.65rem, 3.4vw, 2.5rem); font-weight: 500; }

#werkstatt .story__text p {
  color: var(--graphite);
  font-size: clamp(1rem, 1.2vw, 1.12rem);
  line-height: 1.62;
  margin: 0 0 1.1rem;
  max-width: 33rem;
}

#werkstatt .story__caption {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.06em;
  color: var(--graphite);
  opacity: 0.85;
  margin-top: 0.4rem;
  border-top: var(--rule) solid var(--page-line);
  padding-top: 0.45rem;
  display: inline-block;
}

#werkstatt .story__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  padding: 0.72rem 1.35rem;
  border-radius: var(--radius);
  border: var(--rule) solid var(--ink);
  background-color: transparent;
  color: var(--ink);
  text-decoration: none;
  transition: background-color 0.18s linear, color 0.18s linear, border-color 0.18s linear;
  margin: 0 0.65rem 0.65rem 0;
}

#werkstatt .story__cta:hover,
#werkstatt .story__cta:focus {
  background-color: var(--accent-deep);
  border-color: var(--accent-deep);
  color: var(--page);
  text-decoration: none;
}

#werkstatt .story__scroll {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 2.2rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--graphite);
}

#werkstatt .story__scroll::before {
  content: "";
  width: 1px;
  height: 2.4rem;
  background: linear-gradient(to bottom, var(--page-line), var(--accent));
  animation: alc-scroll-hint 2.4s ease-in-out infinite;
  transform-origin: top center;
}

@keyframes alc-scroll-hint {
  0%, 100% { transform: scaleY(0.45); opacity: 0.6; }
  50%      { transform: scaleY(1);    opacity: 1; }
}

/* --- Formular-Layer (Spec 2.4, Storyboard Kapitel 05) --------------------- *
   Eigener Layer über der Bühne: er spannt wie der Bühnenrahmen die ganze
   Sektion, sein Dock klebt mit derselben Geometrie wie die Bühne. Dadurch sind
   die projizierten Bildschirmkoordinaten der Engine direkt verwendbar.
   Die Engine setzt --form-x / --form-y und die Klasse .is-anchored; kippt die
   Projektion oder läuft der Mobilpfad, gilt die Ruhelage.                     */

#werkstatt .story__formlayer {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 3;
  pointer-events: none;
}

#werkstatt .story__formdock {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
}

#werkstatt .story__form {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(30rem, 92vw);
  max-height: 86vh;
  /* Bewusst OHNE overscroll-behavior:contain – sonst haengt der Scroll an der
     Karte fest, sobald ihr Ende erreicht ist, und das Kapitel laeuft nicht
     weiter. So kettet der Scroll wie erwartet an die Seite durch. */
  overflow-y: auto;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s linear;
}

/* Sichtbar, sobald das Kapitel „kontakt" läuft (Klasse setzt die Engine). */
#werkstatt.story--form .story__form {
  pointer-events: auto;
  visibility: visible;
  opacity: var(--form-in, 1);
}

/* An die 3D-Position geheftet (Zeichenblatt auf dem Planungstisch). */
#werkstatt .story__form.is-anchored {
  left: 0;
  top: 0;
  transform: translate3d(var(--form-x, 50%), var(--form-y, 50%), 0) translate(-50%, -50%);
}

/* --- „Von vorne abspielen" (Runde 13, SPEC-RUNDE-2 19) -------------------- *
   Liegt im Formular-Dock (gleiche Geometrie wie die Buehne) und erscheint
   mit der Formularkarte (#werkstatt.story--form-in, setzt die Engine; auch
   bei reduzierter Bewegung und ?autoplay=0). Desktop oben rechts in der
   Flucht der Kapitelleiste (die Karte beginnt dort frühestens ca. 70 px unter
   dem Rand), mobil in der Tastenreihe oben rechts links neben Theme-/Play-
   Taste (dort liegt die Karte unten); niedrige Fenster ab 768 px unten links
   (Block „Niedrige Fenster" weiter unten). z-index -1 im Dock: die Formularkarte
   liegt immer darueber – der Knopf verdeckt nie ein Feld. Ohne WebGL und
   ohne JavaScript gibt es keinen Film – dann kein Knopf. */
#werkstatt .story__replay {
  position: absolute;
  top: clamp(0.8rem, 3vh, 1.6rem);
  right: clamp(0.9rem, 3vw, 2.6rem);
  z-index: -1;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  height: 44px;
  margin: 0;
  padding: 0 1.05rem 0 0.8rem;
  border: 1.5px solid var(--accent-deep);
  border-radius: var(--radius);
  background-color: rgba(var(--page-rgb), 0.94);   /* Runde 18: war 0.92 (Text 4,4 -> 4,6:1 im ungünstigsten Fall) */
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 8px 22px rgba(var(--ink-rgb), 0.12);
  color: var(--accent-deep);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  pointer-events: auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s,
              background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
html.js:not(.story-nogl) #werkstatt.story--form-in .story__replay {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.35s ease 0.1s, visibility 0s linear 0s,
              background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
#werkstatt .story__replay svg { flex: none; display: block; width: 20px; height: 20px; }
#werkstatt .story__replay:hover {
  border-color: var(--accent-deep);
  background-color: var(--accent-deep);
  color: var(--page);
}
#werkstatt .story__replay:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Runde 14 (Abnahme r1, WCAG 2.4.11 Fokus nicht verdeckt): per Tastatur
   fokussiert liegt der Knopf UEBER der Formularkarte. Mobil (< 768 px) und in
   niedrigen Fenstern schiebt die Seite die Karte nach „Anfrage senden“ ueber
   die Tastenreihe oben – ohne das lag der Fokus (Tab aus „Anfrage senden“)
   unsichtbar unter der Karte. Nur solange fokussiert; sonst bleibt z-index -1
   (der Knopf verdeckt kein Feld). */
#werkstatt .story__replay:focus-visible { z-index: 4; }
html:not(.js) #werkstatt .story__replay,
.story-nogl #werkstatt .story__replay { display: none; }
/* Fokusziel nach „Von vorne" ohne Autoplay (engine.js setzt tabindex="-1"
   nur fuer diesen Moment): kein Rahmen um die ganze Seite. */
#main[tabindex="-1"]:focus { outline: none; }

@media (max-width: 767.98px) {
  /* links neben der Tastenreihe oben rechts: Theme (44 px) und – mit
     Autoplay – Play/Pause (44 px), Abstand je 0,6rem wie in der Reihe */
  #werkstatt .story__replay {
    right: calc(clamp(0.9rem, 3vw, 2.6rem) + 44px + 0.6rem);
    gap: 0.45rem;
    padding: 0 0.8rem 0 0.62rem;
    font-size: 0.74rem;
  }
  .story-autoscroll #werkstatt .story__replay {
    right: calc(clamp(0.9rem, 3vw, 2.6rem) + 88px + 1.2rem);
  }
}
@media (max-width: 359.98px) {
  /* sehr schmal: sichtbar „Von vorne", Name bleibt „Von vorne abspielen" */
  #werkstatt .story__replay-rest { display: none; }
}
/* Niedrige Fenster im Desktop-Pfad (Smartphone quer ab 768 px, <= 560 px
   hoch; Nachbesserung Abnahme Runde 13): oben rechts lag der Knopf teilweise
   unter der Formularkarte – sie fuellt hier fast die ganze Hoehe (812x375:
   Karte 200–680 x 36–359), rechts bleiben neben Kapitelleiste und Theme-/
   Play-Taste nur ca. 110 px. Frei ist die LINKE Spalte: der Formularanker
   steht bei ca. 54 % der Breite, links der 30rem-Karte bleiben ab 768 px
   mindestens ca. 175 px. Deshalb unten links auf der Grundlinie der
   Tastenreihe; bis 1099 px Breite zweizeilig („Von vorne / abspielen",
   ca. 115 px breit, 44 px hoch). */
@media (min-width: 768px) and (max-height: 560px) {
  #werkstatt .story__replay {
    top: auto;
    right: auto;
    bottom: clamp(1.1rem, 4vh, 2.4rem);
    left: clamp(0.9rem, 3vw, 2.6rem);
  }
}
@media (min-width: 768px) and (max-width: 1099.98px) and (max-height: 560px) {
  #werkstatt .story__replay {
    height: auto;
    min-height: 44px;
    gap: 0.5rem;
    padding: 0.36rem 0.85rem 0.36rem 0.65rem;
    font-size: 0.74rem;
    line-height: 1.25;
    text-align: left;
    white-space: normal;
  }
  #werkstatt .story__replay-rest { display: block; }
}

/* =========================================================================
   Mobil (Spec 2.2 / 2.4)
   ========================================================================= */

@media (max-width: 767.98px) {
  #werkstatt .story__text {
    top: 30vh;
    max-width: none;
    margin: 0 1rem;
    padding: 1.15rem;
    border: var(--rule) solid var(--page-line);
    border-radius: var(--radius);
    background-color: rgba(var(--page-rgb), 0.85);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
  }

  #werkstatt .story__chapter[data-scene="hochbeet"] .story__text,
  #werkstatt .story__chapter[data-scene="carport"] .story__text,
  #werkstatt .story__chapter[data-scene="montage"] .story__text { margin: 0 1rem; }

  #werkstatt .story__text p { max-width: none; font-size: 0.98rem; }

  /* Mobil liegt die Formularkarte unten und reicht bis fast an den Rand –
     die Autoscroll-Taste wandert deshalb im Kapitel „kontakt" nach oben,
     damit sie nichts vom Formular verdeckt. */
  #werkstatt.story--form .story__controls {
    bottom: auto;
    top: clamp(0.8rem, 3vh, 1.6rem);
  }

  /* Runde 12 (SPEC-RUNDE-2 18): unten liegen mobil jetzt die Kurztext-Pop-ups
     (volle Breite) – die Tasten stehen deshalb immer oben rechts (dieselbe
     Stelle wie bisher im Kapitel „kontakt"; ueber `bottom` gesetzt, damit der
     Wechsel aus dem Startbild stetig gleitet). Im Startbild stehen sie gross
     in der Bildmitte unter dem Hinweis, das Intro-Pop-up bleibt unten frei. */
  #werkstatt .story__controls { bottom: calc(100% - 44px - clamp(0.8rem, 3vh, 1.6rem)); }
  html.js:not(.story-nogl):not(.story-started) #werkstatt .story__controls {
    left: 50%;
    bottom: 47%;
    transform: translateX(-50%) scale(1.5);
  }
  html.js:has(#werkstatt :target) #werkstatt .story__controls {
    left: calc(100% - clamp(0.9rem, 3vw, 2.6rem));
    bottom: calc(100% - 44px - clamp(0.8rem, 3vh, 1.6rem));
    transform: translateX(-100%);
  }
  #werkstatt .story__hint { top: 41%; font-size: 1rem; }

  /* Pop-ups mobil: unten, volle Breite, zu hoechstens ca. 1/3 der Bildhoehe
     (geschlossen); „Mehr lesen" scrollt in sich. */
  #werkstatt .story__pop {
    left: 0.6rem;
    right: 0.6rem;
    bottom: 0.6rem;
    width: auto;
    padding: 0.65rem 0.85rem 0.4rem 0.9rem;
  }
  #werkstatt .story__pop-title { font-size: 1.08rem; }
  #werkstatt h1.story__pop-title { font-size: 1.22rem; }
  #werkstatt .story__pop-lead { font-size: 0.9rem; margin-bottom: 0.35rem; }
  #werkstatt .story__more-body { max-height: 30vh; }
  #werkstatt .story__more-body p { font-size: 0.9rem; }

  /* Smartphone QUER (< 768 px breit, Querformat): wenig Hoehe – Pop-up unten
     links in Kartenbreite statt ueber die ganze Breite (<= ca. 1/3 der Hoehe),
     im Startbild die Tasten rechts unten neben dem Pop-up, der Hinweis hoeher. */
  @media (orientation: landscape) {
    #werkstatt .story__pop {
      right: auto;
      width: min(22rem, 56vw);
      padding: 0.5rem 0.75rem 0.3rem 0.8rem;
    }
    #werkstatt .story__pop-title { font-size: 1rem; margin-bottom: 0.25rem; }
    #werkstatt h1.story__pop-title { font-size: 1.08rem; }
    #werkstatt .story__pop-lead { font-size: 0.84rem; line-height: 1.35; }
    #werkstatt .story__more-body { max-height: 45vh; }
    html.js:not(.story-nogl):not(.story-started) #werkstatt .story__controls {
      left: calc(100% - 1rem);
      bottom: 1rem;
      transform: translateX(-100%) scale(1.25);
      transform-origin: 100% 100%;
    }
    #werkstatt .story__hint { top: 36%; }
  }

  #werkstatt .story__progress { right: 0.7rem; gap: 0.85rem; font-size: 0.72rem; }
  #werkstatt .story__progress li { padding-right: 1.5rem; }
  #werkstatt .story__progress li::after { width: 0.9rem; }

  /* Formularkarte liegt unter der Bühne, volle Breite (Spec 2.4). */
  #werkstatt .story__form,
  #werkstatt .story__form.is-anchored {
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    width: auto;
    max-height: 62vh;
    margin: 0 0.6rem 0.6rem;
    transform: none;
  }
}

/* Sehr kleine Viewports: Progressleiste weicht dem Formular. */
@media (max-width: 359.98px) {
  #werkstatt .story__progress { display: none; }
  /* Die Autoscroll-Taste bleibt: sie ist das einzige Bedienelement. */
}

/* =========================================================================
   Runde 15 (Kamera-Nachkontrolle nk-04 / nk-03): Overlays geben die
   Hauptmotive frei
   -------------------------------------------------------------------------
   nk-04: Seit Runde 14 traegt die Kapitelleiste eine zu 94 % deckende Flaeche
   (WCAG 1.4.3). Hochkant stand sie rechts mittig mitten im Bild – ueber dem
   Monteur auf dem Balkon, dem DiveAir-Auto, dem hochbeet-LKW und dem rechten
   Rand der Europakarte (375 x 812: in 46 von 71 Proben >= 10 %). Hochkant
   (Smartphone und Tablet bis 1099 px, wie die Mobil-Kamera der Engine) wird
   sie deshalb zur flachen ZEILE oben rechts (Runde 18: nur noch Striche
   nebeneinander, ohne Text – die sieben Stationsnamen passen hochkant nicht
   in eine Zeile; aktiv lang in --accent-deep, erledigt --ink, offen
   --graphite), Flaeche, Rahmen und Farben wie bisher. Smartphone: unter der Rechtspille; Tablet:
   am oberen Rand (dort steht nach dem Film „Von vorne abspielen" – die Zeile
   weicht dann aus, Kapitel 06 ist erreicht). Oben liegen nur Hallendach,
   Himmel oder Decke. Die Leiste ist aria-hidden (rein visuell).
   Desktop (quer, > 500 px hoch): die senkrechte Leiste bleibt, steht aber
   OBEN rechts statt mittig (1280 x 800 lag sie mittig ueber dem DiveAir-Auto
   bis 22 % und den hochbeet-LKW-Raedern bis 42 %) – knapper gesetzt, unter
   der Stelle von „Von vorne abspielen" (44 px), damit beide nie kollidieren. */
html.js:not(.story-nogl) #werkstatt .story__progress {
  top: calc(clamp(0.8rem, 3vh, 1.6rem) + 44px + 0.8rem);
  transform: none;
  gap: 0.62rem;   /* Runde 18: war 0.75rem (7 statt 6 Eintraege) */
}
@media (max-width: 1099.98px) and (orientation: portrait) {
  html.js:not(.story-nogl) #werkstatt .story__progress {
    top: clamp(1.1rem, 4vh, 2.4rem);
    right: clamp(0.9rem, 3vw, 2.6rem);
    transform: none;
    flex-direction: row;
    gap: 0;
    padding: 0.1rem 0.3rem;
    font-size: 0.72rem;
  }
  /* Runde 18: Striche ohne Text (7 x 1,3rem, Hoehe wie die fruehere Zeile) */
  html.js:not(.story-nogl) #werkstatt .story__progress li {
    width: 1.3rem;
    height: 1.5rem;
    padding: 0;
  }
  html.js:not(.story-nogl) #werkstatt .story__progress-label { display: none; }
  html.js:not(.story-nogl) #werkstatt .story__progress li::after {
    top: 50%;
    right: auto;
    left: 50%;
    width: 0.95rem;
    height: 2px;
    transform: translate(-50%, -50%) scaleX(0.5);
    transform-origin: center center;
  }
  html.js:not(.story-nogl) #werkstatt .story__progress li.is-active::after {
    transform: translate(-50%, -50%) scaleX(1);
  }
}
@media (max-width: 767.98px) and (orientation: portrait) {
  /* unter Theme-/Play-Taste (44 px) und Rechtspille (26 px + Rahmen) */
  html.js:not(.story-nogl) #werkstatt .story__progress {
    top: calc(clamp(0.8rem, 3vh, 1.6rem) + 44px + 0.4rem + 28px + 0.45rem);
  }
}
@media (min-width: 768px) and (max-width: 1099.98px) and (orientation: portrait) {
  html.js:not(.story-nogl) #werkstatt.story--form-in .story__progress { opacity: 0; }
}
/* Nachbesserung Abnahme r1 (nk-04 / kontakt-zertifikate): oben rechts lag die
   senkrechte Leiste am Desktop ueber dem EN-1090-Zertifikat (blauer Rahmen),
   das beim Einschwenken ins Buero am rechten Rand oben durchs Bild zieht –
   Kapitelanfang kontakt t 0 … 0,1 (1280 x 800 bis 65 %), bei schmaleren
   Fenstern (1024 x 768, 1180 x 820) schon in den letzten 3 % der Fahrt
   montage>kontakt (bis 72 %). Die Leiste blendet deshalb am Desktop aus,
   sobald Kapitel 06 das aktive ist (data-active-scene, ab der Fahrt
   montage>kontakt; vgl. SPEC 3.6 Outro und SPEC-RUNDE-2 13.5 Desktop-
   Endbild) – Planecke, Europakarte, Zertifikate und Bilderwand
   bleiben frei. Hochkant < 1100 px (Zeile oben, dort frei) und quer <= 500 px
   (Leiste aus) unveraendert. */
@media (orientation: landscape), (min-width: 1100px) {
  html.js:not(.story-nogl) #werkstatt[data-active-scene="kontakt"] .story__progress { opacity: 0; }
}

/* Runde 18, Nachtrag Abnahme optik-a11y (Betreiber: Leiste mit allen Namen
   bleibt): die breitere Namensleiste stiess an zwei Stellen an, die es mit
   01-06 nicht gab. (1) Quer, 640-767 px breit und > 500 px hoch: die
   Rechtspille lag ueber „Einleitung" -> Leiste wie hochkant unter die Pille.
   (2) Quer bis 1099 px (gemessen 870-990 x 520-650): die geoeffnete
   „Mehr lesen"-Karte schnitt den linken Rand der Leiste an
   („hlossermeister.cc") -> Leiste blendet aus, solange „Mehr lesen" offen ist
   (aria-hidden, rein visuell; Browser ohne :has() behalten die Leiste). */
@media (orientation: landscape) and (max-width: 767.98px) and (min-height: 500.02px) {
  html.js:not(.story-nogl) #werkstatt .story__progress {
    top: calc(clamp(0.8rem, 3vh, 1.6rem) + 44px + 0.4rem + 28px + 0.45rem);
  }
}
@media (orientation: landscape) and (max-width: 1099.98px) {
  html.js:not(.story-nogl) #werkstatt:has(.story__more[open]) .story__progress { opacity: 0; }
}

/* nk-03: Smartphone QUER (und jedes Querformat-Fenster <= 500 px hoch) – die
   Karte lag unten links (844 x 390: 294 x 130 px, ein Drittel der Hoehe)
   ueber LKW-Raedern, Ameise, Schlosser und Monteur, die Kapitelleiste rechts
   ueber LKW-Raedern und DiveAir-Auto. Jetzt: die Karte als FLACHE LEISTE
   OBEN LINKS – der Titel in der ersten Zeile (bis Runde 17 mit der
   Kapitelnummer davor), darunter Link und „Mehr lesen" (geoeffnet: Text darunter, eigene Scrollleiste bzw. ganze Karte
   scrollt, siehe <= 420 px). Oben liegen Hallendach und Himmel; rechts
   bleiben Tasten und Rechtspille frei (Breite hoechstens Fenster − 13rem).
   Die Kapitelleiste entfaellt hier – die Karte nennt das Kapitel selbst. */
@media (orientation: landscape) and (max-height: 500px) {
  html.js:not(.story-nogl) #werkstatt .story__progress { display: none; }
  html.js:not(.story-nogl) #werkstatt .story__pop {
    top: 0.5rem;
    right: auto;
    bottom: auto;
    left: 0.5rem;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0.6rem;
    width: min(29rem, calc(100% - 13rem));
    margin: 0;
    padding: 0.32rem 0.75rem 0.12rem 0.8rem;
  }
  html.js:not(.story-nogl) #werkstatt .story__pop .story__eyebrow { margin: 0; }
  /* Titel fuellt die erste Zeile (Kapitel 06: unter der Dachzeile) – Link
     und „Mehr lesen" rutschen immer in die zweite (auch bei kurzem Link wie
     diveair.eu). Runde 18: ohne Kapitelnummer volle Breite. */
  html.js:not(.story-nogl) #werkstatt .story__pop-title {
    flex: 1 1 100%;
    min-width: 0;
    margin: 0;
    font-size: 0.98rem;
    line-height: 1.25;
  }
  html.js:not(.story-nogl) #werkstatt h1.story__pop-title { font-size: 1.04rem; }
  html.js:not(.story-nogl) #werkstatt .story__pop-lead {
    flex: 1 1 100%;
    margin: 0.1rem 0 0;
    font-size: 0.8rem;
    line-height: 1.35;
  }
  html.js:not(.story-nogl) #werkstatt .story__pop-link { margin: 0.1rem 0 0; font-size: 0.74rem; }
  html.js:not(.story-nogl) #werkstatt .story__more { flex: 0 0 auto; }
  html.js:not(.story-nogl) #werkstatt .story__more[open] { flex: 1 1 100%; }
  html.js:not(.story-nogl) #werkstatt .story__more > summary { padding: 0.24rem 0; font-size: 0.7rem; }
  /* Nachbesserung Abnahme r1 (nk-03, 844 x 390 und 932 x 430): die Leiste
     war 56 px hoch (8 … 64 px) – der Kopf des Schlossers am Schweissplatz
     (hochbeet t 0,32 … 0,36, nur der Kopf zu sehen, 844 x 390: y 42 … 74)
     lag in drei Proben darunter. Die Karten 01 … 06 werden deshalb flacher
     (ca. 41 statt 56 px): 0,25rem vom oberen Rand, knappere Innenabstaende,
     Zeilenhoehen 1,12 / 1,3; „Mehr lesen" als Block-Flex ohne die 25-px-
     Zeilenbox des <details>. Breite, Schrift und Farben bleiben. Die Intro-
     Karte (Startbild) bleibt unveraendert. */
  html.js:not(.story-nogl) #werkstatt .story__chapter:not([data-scene="intro"]) .story__pop {
    top: 0.25rem;
    padding-top: 0.2rem;
    padding-bottom: 0.05rem;
  }
  html.js:not(.story-nogl) #werkstatt .story__chapter:not([data-scene="intro"]) .story__pop-title { line-height: 1.12; }
  html.js:not(.story-nogl) #werkstatt .story__chapter:not([data-scene="intro"]) .story__pop-link { line-height: 1.3; }
  html.js:not(.story-nogl) #werkstatt .story__chapter:not([data-scene="intro"]) .story__more > summary {
    display: flex;
    width: fit-content;
    padding: 0.1rem 0;
    line-height: 1.3;
  }
}
/* Ab 768 px Breite (Desktop-Pfad, z. B. 844 x 390) standen Theme-/Play-Taste
   und Rechtspille unten rechts ueber den Raedern des DiveAir-Autos (mit
   Autoplay-Taste >= 20 % in 34 von 51 Proben). Quer und niedrig deshalb wie
   bei den schmaleren Smartphones: Tasten oben rechts, die Pille darunter
   (ueber `bottom`, damit der Wechsel aus dem Startbild stetig gleitet; das
   Startbild selbst bleibt unveraendert). */
@media (orientation: landscape) and (max-height: 500px) and (min-width: 768px) {
  html.js:not(.story-nogl) #werkstatt .story__controls,
  html.js:not(.story-nogl):has(#werkstatt :target) #werkstatt .story__controls {
    bottom: calc(100% - 44px - clamp(0.8rem, 3vh, 1.6rem));
  }
  html.js:not(.story-nogl) #werkstatt .story__legal {
    top: calc(clamp(0.8rem, 3vh, 1.6rem) + 44px + 0.4rem);
    right: clamp(0.9rem, 3vw, 2.6rem);
    bottom: auto;
  }
  /* Formularkarte (fast volle Hoehe, ca. 54 % der Breite): die Pille laege
     halb darunter – sie wechselt dann in die freie linke Spalte oben, zwei
     Zeilen (ab 768 px bleiben links der Karte nur ca. 150 px; „Von vorne
     abspielen" steht links unten). */
  html.js:not(.story-nogl) #werkstatt.story--form-in .story__legal,
  html.js:not(.story-nogl) #werkstatt[data-stop="kontakt"] .story__legal {
    top: clamp(0.8rem, 3vh, 1.6rem);
    right: auto;
    left: clamp(0.9rem, 3vw, 2.6rem);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.12rem 0.2rem;
    border-radius: var(--radius);
  }
  html.js:not(.story-nogl) #werkstatt.story--form-in .story__legal-sep,
  html.js:not(.story-nogl) #werkstatt[data-stop="kontakt"] .story__legal-sep { display: none; }
  /* Runde 16 (Nachbesserung fix15, EN 1090 quer): im Kapitel 06 zieht das
     EN-1090-Zertifikat (blauer Rahmen) beim Einschwenken ins Buero oben
     rechts durchs Bild und bleibt dort haengen (844 x 390: x 634 … 828,
     y 0 … 125) – genau unter Theme-/Play-Taste und Rechtspille (kontakt
     t 0,075 … 0,175 bis 66 %, 932 x 430 bis 59 %). Solange Kapitel 06 steht
     (data-stop="kontakt", ab dem Kapitelanfang; die Fahrt montage>kontakt
     und nk-03 bleiben unberuehrt): die Tasten gleiten nach UNTEN rechts
     (Grundlage des Desktops; darunter Regal/Sideboard, die Formularkarte
     endet links davon), die Pille steht gleich in ihrer Formularlage oben
     links (zweizeilig, links der Urkunde) – sie springt damit nur einmal. */
  html.js:not(.story-nogl) #werkstatt[data-stop="kontakt"] .story__controls,
  html.js:not(.story-nogl):has(#werkstatt :target) #werkstatt[data-stop="kontakt"] .story__controls {
    bottom: clamp(1.1rem, 4vh, 2.4rem);
  }
  /* Nachbesserung Abnahme r1: Kapitel 06 zeigt bei der Ankunft im Buero die
     Zertifikate oben an der Wand – die Karte 06 (bis das Formular kommt)
     lag oben links ueber der Urkunde (844 x 390 kontakt t 0 … 0,175: 53 …
     58 %). Sie steht deshalb hier unten links; darunter liegen nur Boden,
     Wandsockel und die Tischbeine (die Tischplatte bleibt frei). */
  html.js:not(.story-nogl) #werkstatt .story__chapter[data-scene="kontakt"] .story__pop {
    top: auto;
    bottom: 0.5rem;
  }
}
/* Runde 16 (Nachbesserung fix15, Reflow 400 %, WCAG 1.4.10): schmaler als
   480 px bleibt fuer die Leiste oben links neben Tasten und Rechtspille zu
   wenig Breite (1280 x 1024 bzw. 1280 x 800 bei 400 % = 320 x 256 / 320 x 200:
   Karte 97 px, Titel und Text liefen waagrecht ueber). Echte Smartphones
   quer sind breiter (ab 480 px) – dort bleibt nk-03 unveraendert. Hier steht
   die Karte deshalb UNTEN in voller Breite, hoechstens bis knapp unter die
   Rechtspille (Tasten 44 px + 0,4rem + Pille 28 px); was nicht passt – auch
   „Mehr lesen" offen –, scrollt die ganze Karte senkrecht (eine Scrollleiste).
   Im Startbild stehen die Tasten 1,25-fach unten rechts (bis 122 px breit):
   die Intro-Karte endet links davor. */
@media (orientation: landscape) and (max-height: 500px) and (max-width: 479.98px) {
  html.js:not(.story-nogl) #werkstatt .story__chapter[data-scene] .story__pop {
    top: auto;
    right: 0.5rem;
    bottom: 0.5rem;
    left: 0.5rem;
    width: auto;
    max-height: calc(100vh - 0.9rem - clamp(0.8rem, 3vh, 1.6rem) - 44px - 0.4rem - 28px);
    max-height: calc(100dvh - 0.9rem - clamp(0.8rem, 3vh, 1.6rem) - 44px - 0.4rem - 28px);
    overflow-y: auto;
    overflow-wrap: anywhere;
    -webkit-hyphens: auto;
    hyphens: auto;
  }
  /* Startbild (320 px: Karte 151 px): knappere Seitenabstaende und schmale
     Scrollleiste; das eine zu lange Wort („Schlossereibetrieb" im
     aufgeklappten Text) trennt, statt waagrecht ueberzulaufen. */
  html.js:not(.story-nogl):not(.story-started) #werkstatt .story__chapter[data-scene] .story__pop {
    right: auto;
    width: calc(100% - 2rem - 122px);
    padding-right: 0.45rem;
    padding-left: 0.55rem;
    scrollbar-width: thin;
  }
  html.js:not(.story-nogl) #werkstatt .story__more-body {
    max-height: none;
    overflow: visible;
  }
}

/* =========================================================================
   Statisches Layout – zwei Ausloeser, dieselben Regeln:
     html:not(.js)      kein JavaScript (die Klasse `js` setzt /js/theme.js
                        synchron im <head>, vor dem ersten Paint)
     html.story-nogl    kein WebGL / Modul-Fehler (setzt story.js) oder
                        story.js selbst nicht ladbar (setzt theme.js)
   Die Kapitel werden zu normalen Sektionen, die Buehne verschwindet, die
   Textalternativen tragen die Information, das Formular steht im Fluss.
   (Audit html-css-a11y-1, form-php-2)
   ========================================================================= */

html:not(.js) #werkstatt .story__stagewrap,
html:not(.js) #werkstatt .story__transition,
.story-nogl #werkstatt .story__stagewrap,
.story-nogl #werkstatt .story__transition {
  display: none;
}

html:not(.js) #werkstatt.story,
.story-nogl #werkstatt.story { padding: var(--rhythm) 0; }

html:not(.js) #werkstatt .story__chapter,
.story-nogl #werkstatt .story__chapter {
  min-height: 0;
  padding: 0 1rem var(--rhythm);
  pointer-events: auto;
}

html:not(.js) #werkstatt .story__text,
.story-nogl #werkstatt .story__text {
  position: static;
  opacity: 1 !important;
  transform: none !important;
  max-width: 46rem;
  margin: 0 auto !important;
  padding: 1.75rem;
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  background-color: var(--page-2);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

html:not(.js) #werkstatt .story__chapter[data-scene="intro"] .story__text,
.story-nogl #werkstatt .story__chapter[data-scene="intro"] .story__text {
  background-color: transparent;
  border: 0;
  padding: 1rem 0 0;
  text-align: center;
}

html:not(.js) #werkstatt .story__scroll,
.story-nogl #werkstatt .story__scroll { display: none; }

/* Runde 12 (SPEC-RUNDE-2 18): ohne WebGL/JavaScript bleibt das Startbild
   (erstes Filmbild) als Titelbild ueber den Kapiteln stehen – die Buehne
   wird dafuer zu einem statischen Bildblock ohne Canvas und Bedienelemente. */
html:not(.js) #werkstatt .story__stagewrap,
.story-nogl #werkstatt .story__stagewrap {
  display: block;
  position: relative;
  margin: calc(-1 * var(--rhythm)) 0 var(--rhythm);
  pointer-events: none;
}
html:not(.js) #werkstatt .story__stage,
.story-nogl #werkstatt .story__stage {
  position: relative;
  height: min(56.25vw, 72vh);
}
html:not(.js) #werkstatt .story__canvas,
html:not(.js) #werkstatt .story__progress,
html:not(.js) #werkstatt .story__controls,
html:not(.js) #werkstatt .story__hint,
html:not(.js) #werkstatt .story__rotate,
html:not(.js) #werkstatt .story__legal,
.story-nogl #werkstatt .story__legal,
.story-nogl #werkstatt .story__canvas,
.story-nogl #werkstatt .story__progress,
.story-nogl #werkstatt .story__controls,
.story-nogl #werkstatt .story__hint,
.story-nogl #werkstatt .story__rotate { display: none; }
html:not(.js) #werkstatt .story__poster,
.story-nogl #werkstatt .story__poster {
  opacity: 1;
  visibility: visible;
  background-size: cover;
  transition: none;
}

/* Kurztext-Pop-ups als Karten im Fluss; „Mehr lesen" funktioniert ohne Skript. */
html:not(.js) #werkstatt .story__popwrap,
html:not(.js) #werkstatt .story__popdock,
.story-nogl #werkstatt .story__popwrap,
.story-nogl #werkstatt .story__popdock {
  position: static;
  height: auto;
}
html:not(.js) #werkstatt .story__pop,
.story-nogl #werkstatt .story__pop {
  position: static;
  width: auto;
  max-width: 46rem;
  margin: 0 auto;
  padding: 1.5rem 1.75rem 1.1rem;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  background-color: var(--page-2);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  transition: none;
}
html:not(.js) #werkstatt .story__more-body,
.story-nogl #werkstatt .story__more-body {
  max-height: none;
  overflow: visible;
}

/* Der Anker #kontakt steht im Fluss am Anfang des Kapitels „kontakt". */
html:not(.js) #werkstatt .story__anchor,
.story-nogl #werkstatt .story__anchor {
  position: static;
  display: block;
  width: auto;
  height: 0;
}

/* Das Formular bleibt immer erreichbar – auch ohne WebGL und ohne JavaScript. */
html:not(.js) #werkstatt .story__formlayer,
.story-nogl #werkstatt .story__formlayer { position: static; }

html:not(.js) #werkstatt .story__formdock,
.story-nogl #werkstatt .story__formdock {
  position: static;
  height: auto;
  padding: 0 1rem;      /* Seitenabstand wie die Kapitel */
}

html:not(.js) #werkstatt .story__form,
html:not(.js) #werkstatt .story__form.is-anchored,
.story-nogl #werkstatt .story__form,
.story-nogl #werkstatt .story__form.is-anchored {
  position: static;
  width: auto;
  max-width: 46rem;
  max-height: none;
  overflow: visible;
  margin: 0 auto;
  transform: none;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  /* Ohne Engine gibt es niemanden, der die Einblendung zu Ende faehrt – im
     Fallback steht die Karte deshalb sofort und ohne Uebergang. */
  transition: none;
}

/* =========================================================================
   prefers-reduced-motion MIT WebGL (Audit html-css-a11y-3 b): die Engine setzt
   .story-reduced und wuerde die Karte weiter an die 3D-Projektion heften –
   dort laege sie ueber dem Kapiteltext. Im reduzierten Modus dockt die Karte
   deshalb rechts an (breite Viewports) bzw. unten (schmale); der Text bleibt
   oben links und wird schmaler. Die Texte selbst tragen als
   .story__text--fallback bereits Flaeche und Rahmen (Teil a des Befunds).
   ========================================================================= */

@media (min-width: 1100px) {
  .story-reduced #werkstatt .story__form,
  .story-reduced #werkstatt .story__form.is-anchored {
    left: auto;
    right: clamp(4.5rem, 8vw, 7rem);
    top: 50%;
    transform: translateY(-50%);
  }

  .story-reduced #werkstatt .story__chapter[data-scene="kontakt"] .story__text {
    margin-left: clamp(1.25rem, 7vw, 7rem);
    margin-right: 0;
    max-width: min(34rem, calc(100vw - 30rem - clamp(4.5rem, 8vw, 7rem) - clamp(1.25rem, 7vw, 7rem) - 3rem));
  }
}

@media (max-width: 1099.98px) {
  .story-reduced #werkstatt .story__chapter[data-scene="kontakt"] .story__text {
    top: 0.75rem;
    max-width: none;
    margin: 0 0.75rem;
    padding: 0.85rem 1rem;
  }

  .story-reduced #werkstatt .story__chapter[data-scene="kontakt"] .story__text h2 {
    font-size: 1.25rem;
    margin: 0.35rem 0 0.4rem;
  }

  .story-reduced #werkstatt .story__chapter[data-scene="kontakt"] .story__text p {
    font-size: 0.92rem;
    margin: 0;
    max-width: none;
  }

  .story-reduced #werkstatt .story__form,
  .story-reduced #werkstatt .story__form.is-anchored {
    left: 50%;
    right: auto;
    top: auto;
    bottom: 0.75rem;
    width: min(30rem, 92vw);
    /* Runde 14 (funktion-1): war 100vh - 13rem (Platz fuer den frueheren
       Kapiteltext oben, den es nicht mehr gibt) – die Karte passt jetzt ohne
       innere Scrollbox; niedrige Fenster: Block „Formularkarte OHNE innere
       Scrollbox". */
    max-height: calc(100vh - 1.5rem);
    margin: 0;
    transform: translateX(-50%);
  }
}

/* =========================================================================
   prefers-reduced-motion: keine Eigenbewegung im DOM.
   Die 3D-Seite regelt die Engine über ctx.reduced (Szenen auf t = 1, Kamera
   springt statt zu gleiten, keine Funken).
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  #werkstatt .story__scroll::before { animation: none; transform: scaleY(1); opacity: 1; }

  #werkstatt .story__progress,
  #werkstatt .story__progress li,
  #werkstatt .story__progress li::after,
  #werkstatt .story__text,
  #werkstatt .story__form,
  #werkstatt .story__cta,
  #werkstatt .story__pop,
  #werkstatt .story__replay,
  html.js:not(.story-nogl) #werkstatt.story--form-in .story__replay,
  #werkstatt .story__more > summary::after { transition: none; }
  #werkstatt .story__pop { transform: none; }

  #werkstatt .story__chapter.is-leaving .story__text { transform: none; }
}


/* =========================================================================
   Formularkarte OHNE innere Scrollbox (Runde 14, Final Review funktion-1)
   -------------------------------------------------------------------------
   Mobil (< 768 px), in niedrigen Fenstern (ab 768 px, <= 640 px hoch) und
   bei reduzierter Bewegung auf 768–1099 px war die Karte auf 62vh / 86vh /
   100vh-13rem begrenzt und scrollte INNEN – Checkbox und „Anfrage senden"
   lagen unter der sichtbaren Kartenhoehe, wer neben der Karte wischte, sah
   die abgeschnittene Karte direkt ueber der Fusszeile. Jetzt scrollt die
   Karte mit der SEITE:
   - Waehrend des Kapitels „kontakt" steht sie wie bisher (oben bei
     --fk-top, bzw. unten buendig, wenn sie ganz passt).
   - Ist sie hoeher als der Platz, waechst die Seite unter dem Kapitel um
     genau den Ueberhang: nach p = 1 (Ende des Autoplays, Ziel von #kontakt)
     schiebt normales Weiterwischen die Karte nach oben, Checkbox und
     „Anfrage senden" erscheinen VOR der Fusszeile. Die Buehne bleibt stehen.
   Technik (nur CSS): der Formular-Layer steht im Fluss hinter dem Kapitel
   „kontakt" und reicht per negativem Rand (--h-kontakt + --fk-pre) davor;
   das Dock ist eine Flex-Spalte mit Mindesthoehe = Kapitel + Vorlauf, ein
   Abstandhalter (::before) setzt die Karte so, dass ihre Oberkante bei
   p = 1 genau auf --fk-top liegt. Die Karte ist sticky (top --fk-top,
   bottom --fk-gap): im Kapitel steht sie still, danach nimmt sie das
   Dock-Ende mit. „Von vorne abspielen" bleibt sticky an seinem Platz (oben
   rechts bzw. in niedrigen Fenstern unten links), z-index -1 unter der
   Karte, ohne eigene Flusshoehe. Desktop in normalen Fenstern (Karte an die
   3D-Position geheftet) und das statische Layout bleiben unveraendert.
   ========================================================================= */

/* Gemeinsamer Aufbau (aktiviert ueber die Medienabfragen unten) */
@media (max-width: 767.98px), (min-width: 768px) and (max-height: 640px) {
  html.js:not(.story-nogl) #werkstatt .story__formlayer {
    --fk-pre: 100vh;
    position: relative;
    top: auto; right: auto; bottom: auto; left: auto;
    margin-top: calc(-1 * (var(--h-kontakt) + var(--fk-pre)));
  }
  html.js:not(.story-nogl) #werkstatt .story__formdock {
    position: static;
    display: flex;
    flex-direction: column;
    height: auto;
    min-height: calc(var(--h-kontakt) + var(--fk-pre));
  }
  html.js:not(.story-nogl) #werkstatt .story__formdock::before {
    content: "";
    flex: none;
    height: calc(var(--h-kontakt) + var(--fk-pre) - 100dvh + var(--fk-top));
  }
  html.js:not(.story-nogl) #werkstatt .story__form,
  html.js:not(.story-nogl) #werkstatt .story__form.is-anchored {
    position: -webkit-sticky;
    position: sticky;
    top: var(--fk-top);
    bottom: var(--fk-gap);
    left: auto;
    right: auto;
    flex: none;
    max-height: none;
    overflow: visible;
    transform: none;
  }
}

/* Mobil: volle Breite unten, Oberkante wie bisher bei 100dvh - 62vh */
@media (max-width: 767.98px) {
  html.js:not(.story-nogl) #werkstatt .story__formlayer {
    --fk-top: calc(100dvh - 62vh - 0.6rem);
    --fk-gap: 0.6rem;
  }
  html.js:not(.story-nogl) #werkstatt .story__form,
  html.js:not(.story-nogl) #werkstatt .story__form.is-anchored {
    width: auto;
    margin: auto 0.6rem var(--fk-gap);
  }
  /* „Von vorne abspielen": oben rechts links neben Theme-/Play-Taste (wie
     bisher), jetzt sticky statt absolut im Dock */
  html.js:not(.story-nogl) #werkstatt .story__replay {
    position: -webkit-sticky;
    position: sticky;
    top: clamp(0.8rem, 3vh, 1.6rem);
    right: auto;
    order: -1;
    flex: none;
    align-self: flex-end;
    margin: clamp(0.8rem, 3vh, 1.6rem) calc(clamp(0.9rem, 3vw, 2.6rem) + 44px + 0.6rem)
            calc(-44px - clamp(0.8rem, 3vh, 1.6rem)) 0;
  }
  html.js.story-autoscroll:not(.story-nogl) #werkstatt .story__replay {
    right: auto;
    margin-right: calc(clamp(0.9rem, 3vw, 2.6rem) + 88px + 1.2rem);
  }
  /* etwas kompakter (Textfeld 4 statt 6 Zeilen hoch, laesst sich aufziehen) */
  html.js:not(.story-nogl) .kontakt-form-card textarea.form-control { height: 7.2rem; min-height: 0; }
  html.js:not(.story-nogl) .kontakt-form-card__lead { margin-bottom: 0.9rem; }
}

/* Niedrige Fenster ab 768 px: Karte oben (1rem), horizontal an der
   projizierten Stelle (--form-x der Engine, sonst mittig) */
@media (min-width: 768px) and (max-height: 640px) {
  html.js:not(.story-nogl) #werkstatt .story__formlayer {
    --fk-top: 1rem;
    --fk-gap: 1rem;
  }
  html.js:not(.story-nogl) #werkstatt .story__form,
  html.js:not(.story-nogl) #werkstatt .story__form.is-anchored {
    align-self: flex-start;
    width: min(30rem, 92vw);
    margin: auto 0 var(--fk-gap) calc(var(--form-x, 50%) - min(15rem, 46vw));
  }
  /* 561–640 px hoch: „Von vorne" oben rechts (wie Desktop), sticky */
  html.js:not(.story-nogl) #werkstatt .story__replay {
    position: -webkit-sticky;
    position: sticky;
    top: clamp(0.8rem, 3vh, 1.6rem);
    right: auto;
    order: -1;
    flex: none;
    align-self: flex-end;
    margin: clamp(0.8rem, 3vh, 1.6rem) clamp(0.9rem, 3vw, 2.6rem)
            calc(-44px - clamp(0.8rem, 3vh, 1.6rem)) 0;
  }
}
/* <= 560 px hoch: „Von vorne" unten links (wie bisher), sticky unten, ohne
   eigene Flusshoehe hinter der Karte */
@media (min-width: 768px) and (max-height: 560px) {
  html.js:not(.story-nogl) #werkstatt .story__replay {
    top: auto;
    bottom: clamp(1.1rem, 4vh, 2.4rem);
    order: 0;
    align-self: flex-start;
    margin: calc(-44px - clamp(1.1rem, 4vh, 2.4rem)) 0 clamp(1.1rem, 4vh, 2.4rem) clamp(0.9rem, 3vw, 2.6rem);
  }
}
@media (min-width: 768px) and (max-width: 1099.98px) and (max-height: 560px) {
  /* zweizeilig (min-height 44px, Hoehe waechst nicht ueber 44 px hinaus) */
  html.js:not(.story-nogl) #werkstatt .story__replay { height: 44px; min-height: 0; }
}

/* Kompakter in mittleren Fenstern ab 768 px (bis 760 px hoch): Textfeld
   niedriger – so passt die Karte bis ca. 640 px Fensterhoehe noch ganz ins
   Bild (normale, an die 3D-Position geheftete Karte ohne Scrollbox). */
@media (min-width: 768px) and (max-height: 760px) {
  html.js:not(.story-nogl) .kontakt-form-card textarea.form-control { height: 7.5rem; min-height: 0; }
  html.js:not(.story-nogl) .kontakt-form-card__lead { margin-bottom: 0.9rem; }
}
@media (min-width: 768px) and (min-height: 641px) and (max-height: 760px) {
  html.js:not(.story-nogl) #werkstatt .story__form { max-height: calc(100vh - 2rem); }
}

/* =========================================================================
   === Kontaktformular ===
   Vollständig eigenständig (kein Bootstrap): Karte, Felder mit Floating-Labels,
   Fehlerzustände, Statusmeldung. Klassennamen und Struktur entsprechen
   /js/kontakt-form.js und /api/kontakt.php.
   ========================================================================= */

.kontakt-form-card {
  background: var(--page-2);
  border: var(--rule) solid var(--page-line);
  border-radius: var(--radius);
  box-shadow: 0 10px 34px rgba(var(--ink-rgb), 0.10);
  color: var(--ink);
  padding: clamp(1.1rem, 3vw, 1.75rem);
}

.kontakt-form-card h2 {
  margin: 0 0 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ink);
}

.kontakt-form-card__lead {
  margin: 0 0 1.2rem;
  font-size: 0.92rem;
  color: var(--graphite);
}

.contact-form .form__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 0.9rem;
}

.contact-form .form__group {
  position: relative;
  margin-bottom: 18px;
}

.contact-form .form__group--wide { grid-column: 1 / -1; }

/* --- Eingabefelder mit Floating-Label ------------------------------------ */

.form-floating { position: relative; }

.kontakt-form-card .form-control {
  display: block;
  width: 100%;
  padding: 24px 12px 8px;
  background: var(--page);
  /* Audit html-css-a11y-7: Feldbegrenzung in --steel (Light 3,7:1 auf der
     Karte, Dark 5,9:1) statt --line (1,4:1) – WCAG 1.4.11 verlangt 3:1. */
  border: var(--rule) solid var(--steel);
  border-radius: var(--radius);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 0.98rem;
  line-height: 1.35;
  box-shadow: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.kontakt-form-card .form-control:hover { border-color: var(--graphite); }

.kontakt-form-card .form-control:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18);
  /* transparent statt none: im Windows-Kontrastmodus (forced-colors) werden
     box-shadow und Randfarbe verworfen, der Outline bleibt als Fokusrahmen. */
  outline: 2px solid transparent;
  outline-offset: 2px;
}

.kontakt-form-card textarea.form-control {
  min-height: 148px;
  padding-top: 28px;
  resize: vertical;
}

.kontakt-form-card .form-floating label {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--graphite);
  font-family: var(--font-mono);
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  line-height: 1.2;
  pointer-events: none;
  transition: top 0.15s ease, font-size 0.15s ease, color 0.15s ease;
}

.kontakt-form-card .form-floating .form-control:focus ~ label,
.kontakt-form-card .form-floating .form-control:not(:placeholder-shown) ~ label {
  top: 9px;
  transform: none;
  color: var(--accent-deep);
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
  font-size: 0.7rem;
}

/* Die leere, nicht fokussierte Textarea trägt ihr Label in der ersten Zeile. */
.kontakt-form-card textarea.form-control:placeholder-shown:not(:focus) ~ label {
  top: 26px;
  transform: none;
}

/* Ein select hat immer einen Wert – :placeholder-shown greift dort nicht. */
.kontakt-form-card .form-floating--select label {
  top: 9px;
  transform: none;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0;
}

.kontakt-form-card .form-floating--select .form-control:focus ~ label { color: var(--accent-deep); }

.kontakt-form-card .form-floating--select select.form-control {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  padding-right: 40px;
  cursor: pointer;
}

/* Pfeil als reines CSS-Dreieck – kein Icon, kein Data-URI-Bild. */
.kontakt-form-card .form-floating--select::after {
  content: "";
  position: absolute;
  right: 18px;
  top: 50%;
  width: 8px;
  height: 8px;
  margin-top: -7px;
  border-right: 2px solid var(--graphite);
  border-bottom: 2px solid var(--graphite);
  transform: rotate(45deg);
  pointer-events: none;
}

/* --- Datenschutz-Checkbox ------------------------------------------------- */

.contact-form .form__checkbox {
  display: flex;
  align-items: flex-start;
  margin-bottom: 0;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--graphite);
  cursor: pointer;
}

.contact-form .form__checkbox input[type="checkbox"] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 3px 12px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.contact-form .form__checkbox a { color: var(--accent-deep); text-decoration: underline; }
.contact-form .form__checkbox a:hover,
.contact-form .form__checkbox a:focus { color: var(--ink); }

/* --- Fehlerzustand -------------------------------------------------------- */

.contact-form .form__error {
  display: none;
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--accent-deep);
}

.contact-form .form__group.error .form__error { display: block; }

.kontakt-form-card .form-control.is-invalid,
.kontakt-form-card .form__group.error .form-control { border-color: var(--accent); }

.kontakt-form-card .form-control.is-invalid:focus,
.kontakt-form-card .form__group.error .form-control:focus {
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.25);
}

.contact-form .form__group.error .form__checkbox { color: var(--accent-deep); }

/* --- Status-Meldung ------------------------------------------------------- */

.contact-form .form-status {
  margin: 4px 0 16px;
  padding: 12px 14px;
  border: var(--rule) solid var(--page-line);
  border-left-width: 4px;
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--page);
}

.contact-form .form-status:empty { display: none; }
.contact-form .form-status--success { border-left-color: var(--steel); }
.contact-form .form-status--error { border-left-color: var(--accent); }

/* --- Absende-Button ------------------------------------------------------- */

.contact-form .btn-submit {
  display: inline-block;
  padding: 0.78rem 1.5rem;
  border: var(--rule) solid var(--accent-deep);
  border-radius: var(--radius);
  background-color: var(--accent-deep);
  color: var(--page);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.contact-form .btn-submit:hover,
.contact-form .btn-submit:focus {
  background-color: var(--ink);
  border-color: var(--ink);
  color: var(--page);
}

.contact-form .btn-submit:disabled,
.contact-form .btn-submit[disabled] { opacity: 0.6; cursor: progress; }

.contact-form .form__hint {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--graphite);
}

/* --- Honeypot ------------------------------------------------------------- */

/* Visuell entfernt, aber NICHT display:none – manche Bots überspringen
   display:none-Felder. Aus dem Barrierefreiheitsbaum ist das Feld per
   aria-hidden und tabindex="-1" im Markup genommen. */
.hp-field {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
}

@media (max-width: 575.98px) {
  .contact-form .form__grid { grid-template-columns: 1fr; }
  .contact-form .form__group { margin-bottom: 14px; }
  .kontakt-form-card textarea.form-control { min-height: 110px; }
}

@media (prefers-reduced-motion: reduce) {
  .kontakt-form-card .form-floating label,
  .kontakt-form-card .form-control,
  .contact-form .btn-submit { transition: none; }
}
