/* ============================================================================
   bewegung.css  ·  Nordsachsen Websites GbR
   Bewegungsbibliothek, Stand 01.09.2026

   40 benannte Muster, dazu die Variante Staffel-eng (A8 neu am 08.09.2026 nach
   Referenzanalyse schneidezimmer.com; A9/C11/C12/D5/G2 neu am 08.09.2026 nach
   Referenzanalyse freshcut-barbershop.com; C13/D6/E5 neu am 08.09.2026 nach
   Live-Pruefung schneidezimmer.com — Herkunft je Muster in Abschnitt 6 von
   Bewegungsbibliothek.md). Im Briefing steht nur der Name — die fuenf Angaben
   (Ausloeser, Distanz, Dauer, Kurve, Versatz) stehen in
   Bewegungsbibliothek.md im selben Ordner (seit 05.09.2026; die frueher genannte .html ist nie angekommen).

   EINBINDEN
     <link rel="stylesheet" href="stil.css">
     <link rel="stylesheet" href="bewegung.css">
   Dazu den Aufdeck-Schnipsel aus skript.js: er setzt html.js und die
   Klasse "sichtbar", sobald ein Element in den Sichtbereich kommt.

   ZWEI BEDINGUNGEN, DIE NICHT VERHANDELBAR SIND
     1. Versteckt wird nur unter html.js. Laeuft kein JavaScript, ist alles
        von Anfang an sichtbar. Bewegung darf nie Inhalt verbergen.
     2. prefers-reduced-motion schaltet jede Bewegung ab.

   R84 — DIE GRENZE
     Hoechstens 12 Elemente je Seite tragen die Klasse .bw, der ueberwiegende
     Teil davon in EINEM Raster. Diese Datei ist ein Vorrat, keine
     Einkaufsliste. Nachzaehlen im Quelltext, so verlangt es das Pruefmass.

   R36/R118 — SEITENWECHSEL
     Der @view-transition-Block am Ende ist Pflicht auf jeder Seite, samt
     Schutzblock. Beides prueft auffindbarkeit-check.js maschinell.
     Erst vorladen (R118), dann ueberblenden.
   ============================================================================ */

/* GRUNDMUSTER DER AUFDECKUNG
   Versteckt wird ausschliesslich unter html.js. Laeuft kein JavaScript, ist
   alles von Anfang an sichtbar — nie ein leerer Bildschirm (R51-Sicherheitsnetz,
   uebernommen aus Website/skript.js und Animations-Muster.html vom 15.08.2026).

   Der gesamte Block haengt an prefers-reduced-motion: no-preference. Wer
   Bewegung abbestellt hat, bekommt die Seite ohne jede Animation und ohne
   jedes Versteck.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  html.js .bw {
    opacity: 0;
    transition:
      opacity   var(--bw-dauer, .5s) var(--bw-kurve, cubic-bezier(.16, 1, .3, 1)) var(--bw-versatz, 0ms),
      transform var(--bw-dauer, .5s) var(--bw-kurve, cubic-bezier(.16, 1, .3, 1)) var(--bw-versatz, 0ms),
      clip-path var(--bw-dauer, .5s) var(--bw-kurve, cubic-bezier(.16, 1, .3, 1)) var(--bw-versatz, 0ms);
  }
  html.js .bw.sichtbar { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }

  /* --- A1 Einblenden-unten ------------------------------------------------ */
  html.js .bw-unten   { transform: translateY(24px); }

  /* --- B1/B2 Einblenden-links, Einblenden-rechts -------------------------- */
  html.js .bw-links   { transform: translateX(-32px); }
  html.js .bw-rechts  { transform: translateX(32px); }

  /* --- B3 Wachsen-sanft --------------------------------------------------- */
  html.js .bw-wachsen { transform: scale(.92); }

  /* --- B4 Maske-nach-oben ------------------------------------------------- */
  html.js .bw-maske   { opacity: 1; clip-path: inset(100% 0 0 0); }

  /* --- B6 Drehen-herein --------------------------------------------------- */
  html.js .bw-dreh-links  { transform: translateX(-70px) translateY(20px) rotate(-18deg) scale(.75); }
  html.js .bw-dreh-rechts { transform: translateX( 70px) translateY(20px) rotate( 18deg) scale(.75); }

  /* --- A2 Kacheln-gestaffelt / B5 Schrift-zeilenweise ---------------------
     Der Versatz haengt an der Position im Raster, nicht am Element. Deshalb
     nth-child am Elternteil statt einer Klasse je Kachel.
     R84: hoechstens 12 Elemente je Seite tragen ueberhaupt .bw.             */
  html.js .bw-staffel > *:nth-child(1) { --bw-versatz:   0ms; }
  html.js .bw-staffel > *:nth-child(2) { --bw-versatz:  80ms; }
  html.js .bw-staffel > *:nth-child(3) { --bw-versatz: 160ms; }
  html.js .bw-staffel > *:nth-child(4) { --bw-versatz: 240ms; }
  html.js .bw-staffel > *:nth-child(5) { --bw-versatz: 320ms; }
  html.js .bw-staffel > *:nth-child(6) { --bw-versatz: 400ms; }
  html.js .bw-staffel > *:nth-child(7) { --bw-versatz: 480ms; }
  html.js .bw-staffel > *:nth-child(8) { --bw-versatz: 560ms; }

  html.js .bw-staffel-eng > *:nth-child(1) { --bw-versatz:   0ms; }
  html.js .bw-staffel-eng > *:nth-child(2) { --bw-versatz:  60ms; }
  html.js .bw-staffel-eng > *:nth-child(3) { --bw-versatz: 120ms; }
  html.js .bw-staffel-eng > *:nth-child(4) { --bw-versatz: 180ms; }
  html.js .bw-staffel-eng > *:nth-child(5) { --bw-versatz: 240ms; }

  /* --- A5 Linie-zeichnet-sich --------------------------------------------
     Fuer technische Zeichnungen (Kabel, Leitungswege, Grundrisse). Reines
     SVG, kein Bild, kein fremder Server — deshalb ohne R109-Hinweis und
     ohne Konflikt mit R50/R94.                                             */
  html.js .bw-strich {
    opacity: 0;
    stroke-dasharray: var(--bw-laenge, 200);
    stroke-dashoffset: var(--bw-laenge, 200);
    transition:
      opacity           .4s ease-out var(--bw-versatz, 0ms),
      stroke-dashoffset var(--bw-dauer, .8s) cubic-bezier(.16, 1, .3, 1) var(--bw-versatz, 0ms);
  }
  html.js .bw-strich.sichtbar { opacity: 1; stroke-dashoffset: 0; }

  /* --- A4 Kopfleiste-verdichtet ------------------------------------------ */
  .bw-kopfleiste {
    transition: height .22s ease, background-color .22s ease, box-shadow .22s ease;
  }
  .bw-kopfleiste.dicht { box-shadow: 0 1px 12px rgba(1, 27, 79, .12); }

  /* --- A6 Bild-Parallaxe-leicht ------------------------------------------
     Hoechstens 40 px Weg. Alles darueber laesst die Seite rutschen statt
     ruhig zu wirken, und kostet auf dem Handy Bildrate.                    */
  .bw-parallaxe { will-change: transform; transition: none; }

  /* --- A9 Flaeche-driftet-seitlich -----------------------------------------
     Wie A6, aber auf der X- statt der Y-Achse und fuer eine ganze Hintergrund-
     flaeche statt ein einzelnes Bild. Hoechstens 24 px Weg: eine Flaeche ist
     meist breiter als ein Bild, ein groesserer Wert wirkt schneller unruhig
     als die 40 px von A6. Herkunft: freshcut-barbershop.com, siehe Abschnitt 6. */
  .bw-flaeche-seitlich { will-change: transform; transition: none; }

  /* --- A7 Kopfleiste-weicht ------------------------------------------------
     Ergaenzt A4 oder ersetzt es, nie beides an derselben Kopfzeile. Kein
     bw/sichtbar noetig — die Kopfzeile ist immer da, nur die Richtung des
     Scrollens entscheidet, ob sie zur Seite weicht.                        */
  .bw-kopfleiste-weicht { transition: transform .3s ease; }
  .bw-kopfleiste-weicht.versteckt { transform: translateY(-100%); }

  /* --- C1 Karte-hebt-sich ------------------------------------------------- */
  .bw-hebt { transition: transform .18s ease-out, box-shadow .18s ease-out; }
  @media (hover: hover) {
    .bw-hebt:hover { transform: translateY(-4px); box-shadow: 0 8px 22px rgba(1, 27, 79, .13); }
  }

  /* --- C2 Knopf-drueckt-sich ---------------------------------------------- */
  .bw-drueckt { transition: transform .09s ease-out; }
  .bw-drueckt:active { transform: scale(.97); }

  /* --- C6 Beschriftung-deckt-auf (Kachel mit versteckter Beschriftung) ----
     Beschriftung ist echter Inhalt, kein Zierrat — deshalb zusaetzlich zu
     :hover auch bei :focus-within sichtbar, ungegattert von @media(hover).  */
  .bw-deckt-auf { position: relative; overflow: hidden; }
  .bw-deckt-auf-text {
    transform: translateY(65%);
    opacity: 0;
    transition: transform .35s ease, opacity .35s ease;
  }
  .bw-deckt-auf:focus-within .bw-deckt-auf-text { transform: translateY(0); opacity: 1; }
  @media (hover: hover) {
    .bw-deckt-auf:hover .bw-deckt-auf-text { transform: translateY(0); opacity: 1; }
  }

  /* --- C7 Flyout-schwebt-ein (Untermenue, Tooltip, kleine Vorschau) -------
     Reines CSS, kein JavaScript. visibility verzoegert das Ausblenden, damit
     kein unsichtbares Element klickbar bleibt.                             */
  .bw-flyout { position: relative; }
  .bw-flyout-inhalt {
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity .25s ease, transform .25s ease, visibility 0s linear .25s;
  }
  .bw-flyout:focus-within .bw-flyout-inhalt,
  .bw-flyout:hover .bw-flyout-inhalt {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition-delay: 0s;
  }

  /* --- C8 Unterstrich-waechst (Textlinks, Menuepunkte) -------------------- */
  .bw-unterstrich { position: relative; text-decoration: none; }
  .bw-unterstrich::after {
    content: "";
    position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .2s ease-out .1s;
  }
  .bw-unterstrich:hover::after, .bw-unterstrich:focus-visible::after { transform: scaleX(1); }

  /* --- C9 Doppel-Unterstrich-wechselt (Text-CTAs) -------------------------
     --bw-akzent faellt auf currentColor zurueck, wenn keine Seiten-Akzent-
     farbe gesetzt ist. Nicht mit C8 auf demselben Element kombinieren.     */
  .bw-unterstrich-tausch { position: relative; text-decoration: none; }
  .bw-unterstrich-tausch::before, .bw-unterstrich-tausch::after {
    content: "";
    position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
    transition: transform .25s ease;
  }
  .bw-unterstrich-tausch::before { background: currentColor; opacity: .35; transform: scaleX(1); }
  .bw-unterstrich-tausch::after  { background: var(--bw-akzent, currentColor); transform: scaleX(0); }
  .bw-unterstrich-tausch:hover::before,   .bw-unterstrich-tausch:focus-visible::before { transform: scaleX(0); }
  .bw-unterstrich-tausch:hover::after,    .bw-unterstrich-tausch:focus-visible::after  { transform: scaleX(1); }

  /* --- C10 Flaeche-tauscht-Farbe (Buttons, Icon-Flaechen) -----------------
     Traegt keine eigenen Farben. Hover-/Fokus-Farben stehen schon in der
     Seiten-CSS des Buttons — diese Klasse macht aus dem harten Wechsel nur
     einen weichen.                                                        */
  .bw-flaeche-tauscht { transition: background-color .25s ease, color .25s ease, border-color .25s ease; }

  /* --- C11 Flaeche-zoomt-bei-Hover (Kachel mit Hintergrundbild) -----------
     Bewusst deutlich langsamer als die uebrigen C-Muster (1,4 s statt
     90-350 ms) — ein "edler" Ausreisser fuer Kacheln, die mehr Gewicht
     bekommen sollen. Traegt keine eigenen Farben, wie C10: der Schleier-
     Verlauf kommt aus der Seiten-CSS. Herkunft: freshcut-barbershop.com,
     Standort-Karten "Nos salons", siehe Abschnitt 6.                       */
  .bw-flaeche-zoomt { position: relative; overflow: hidden; }
  .bw-flaeche-zoomt-bild {
    position: absolute; inset: -6px;
    width: calc(100% + 12px); height: calc(100% + 12px);
    object-fit: cover;
    transition: transform 1.4s ease;
  }
  .bw-flaeche-zoomt-schleier { position: absolute; inset: 0; transition: opacity 1.4s ease; }
  @media (hover: hover) {
    .bw-flaeche-zoomt:hover .bw-flaeche-zoomt-bild { transform: scale(1.1); }
  }

  /* --- C12 Bild-tauscht-bei-Hover (zweites Foto bei Hover) ----------------
     Das zweite Bild liegt schon im Markup uebereinander und blendet beim
     Hover ein — kein Nachladen, kein Sprung wie bei einem Groessenwachstum
     aus 0x0. Herkunft: freshcut-barbershop.com, Produktkarten im Shop-
     Raster, siehe Abschnitt 6.                                             */
  .bw-bild-tauscht { position: relative; overflow: hidden; }
  .bw-bild-tauscht-zweit { position: absolute; inset: 0; opacity: 0; transition: opacity .4s ease; }
  @media (hover: hover) {
    .bw-bild-tauscht:hover .bw-bild-tauscht-zweit { opacity: 1; }
  }

  /* --- C3 Feld-wackelt (Fehlermeldung im Formular) ------------------------ */
  @keyframes bw-wackeln {
    0%, 100% { transform: translateX(0); }
    15%, 45%, 75% { transform: translateX(-6px); }
    30%, 60%, 90% { transform: translateX( 6px); }
  }
  .bw-wackelt { animation: bw-wackeln .4s ease-in-out; }

  /* --- C4 Haken-zeichnet-sich --------------------------------------------- */
  @keyframes bw-haken { to { stroke-dashoffset: 0; } }
  .bw-haken { stroke-dasharray: 40; stroke-dashoffset: 40; animation: bw-haken .45s cubic-bezier(.65, 0, .35, 1) .1s forwards; }

  /* --- C5 Skelett-pulst (Wartezustand) ------------------------------------ */
  @keyframes bw-pulsen { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
  .bw-skelett { animation: bw-pulsen 1.4s ease-in-out infinite; }

  /* --- D1 Punkt-pulsiert (Ring, z. B. "jetzt geoeffnet") ------------------ */
  @keyframes bw-ring {
    0%   { transform: scale(1);   opacity: .55; }
    70%  { transform: scale(2.4); opacity: 0;   }
    100% { transform: scale(2.4); opacity: 0;   }
  }
  .bw-ring { animation: bw-ring 2s ease-out infinite; }

  /* --- D2 Pfeil-tippt-an (Scroll-Hinweis) --------------------------------- */
  @keyframes bw-tippen {
    0%, 60%, 100% { transform: translateY(0); }
    30%           { transform: translateY(7px); }
  }
  .bw-tippt { animation: bw-tippen 2.4s ease-in-out infinite; }

  /* --- D3 Band-laeuft (Logoband, Auszeichnungen) -------------------------- */
  @keyframes bw-band { to { transform: translateX(-50%); } }
  .bw-band { display: flex; width: max-content; animation: bw-band 22s linear infinite; }
  .bw-band-halter:hover .bw-band { animation-play-state: paused; }

  /* --- D4 Inhalt-wechselt-blendend (rotierende Kurzaussagen, kein Slider) -
     Kinder liegen uebereinander; nur .ist-aktiv steht im Textfluss und gibt
     dem Feld seine Hoehe, alle anderen sind absolut positioniert und warten
     unsichtbar auf ihren Auftritt.                                         */
  .bw-rotation { position: relative; }
  .bw-rotation > * {
    position: absolute; inset: 0;
    opacity: 0;
    transform: translateX(-16px);
    transition: opacity .6s ease, transform .6s ease;
    pointer-events: none;
  }
  .bw-rotation > .ist-aktiv { position: relative; opacity: 1; transform: translateX(0); pointer-events: auto; }
  .bw-rotation > .verlaesst { transform: translateX(16px); }

  /* --- D6 Folie-schiebt-von-rechts (grosse Diaschau, z. B. Hero) -----------
     Verwandt mit D4, aber mit voller Breite statt 16 px: die kommende Folie
     faehrt komplett von rechts herein, die gehende bleibt an Ort und Stelle
     und blendet nur aus. Das erste Kind traegt ist-aktiv schon im Markup
     (Pflicht, wie bei G2) — so ist ohne JavaScript immer eine Folie da.
     Herkunft: Live-Pruefung schneidezimmer.com 08.09.2026, siehe Abschnitt 6. */
  .bw-folien { position: relative; overflow: hidden; }
  /* visibility: hidden ist Pflicht, nicht Feinschliff. Mit opacity: 0 allein
     bleiben Knoepfe und Links der unsichtbaren Folien in der Tab-Reihenfolge:
     der Tastaturnutzer landet im Nichts (gemessen 09.09.2026). Der Wechsel
     auf hidden ist um die Uebergangsdauer verzoegert, damit die gehende
     Folie ihre 300 ms noch zu Ende blendet. */
  .bw-folien > * {
    position: absolute; inset: 0;
    opacity: 0;
    visibility: hidden;
    transform: translateX(100%);
    transition: transform 300ms ease, opacity 300ms ease, visibility 0s linear 300ms;
    pointer-events: none;
  }
  .bw-folien > .ist-aktiv {
    opacity: 1; transform: translateX(0); pointer-events: auto;
    visibility: visible;
    transition: transform 300ms ease, opacity 300ms ease, visibility 0s;
  }
  .bw-folien > .verlaesst { transform: translateX(0); visibility: visible; }
}

/* Abbestellte Bewegung: der ganze Block oben haengt an no-preference, also
   greift dort KEINE der Folien-Regeln — ohne diese zwei Zeilen stuenden alle
   Folien untereinander im Fluss. Bei D4 sind das ein paar Zeilen Text, bei D6
   drei volle Heros. Nur die im Markup ausgezeichnete Folie bleibt stehen;
   das ist dieselbe Zusage wie "ohne JavaScript ist immer eine Folie da".
   Gefunden am 09.09.2026 beim Einbau auf der Kundenseite [Kunde].      */
@media (prefers-reduced-motion: reduce) {
  .bw-rotation > :not(.ist-aktiv),
  .bw-folien > :not(.ist-aktiv) { display: none; }

  /* --- E5 Nach-oben-Knopf-taucht-auf -----------------------------------
     Fester Knopf, erscheint erst ab einer Scrollschwelle. Absichtlich
     schneller rein (300 ms) als raus (150 ms). Regelt nur das Auftauchen —
     Hoverfarbe kommt bei Bedarf zusaetzlich aus C10 Flaeche-tauscht-Farbe.
     Herkunft: Live-Pruefung schneidezimmer.com 08.09.2026, siehe Abschnitt 6. */
  .bw-nachoben {
    position: fixed; right: 20px; bottom: 20px; z-index: 40;
    opacity: 0; visibility: hidden;
    transition: opacity 150ms ease, visibility 0s linear 150ms;
  }
  .bw-nachoben.sichtbar {
    opacity: 1; visibility: visible;
    transition: opacity 300ms ease, visibility 0s;
  }

  /* --- C13 Schalter-faehrt-um (Ein/Aus-Schalter) ---------------------------
     Ausschliesslich aus einer echten Checkbox gebaut, keine eigene Logik.
     Farbe im eingeschalteten Zustand ueber --bw-akzent, wie bei C9.
     Herkunft: Live-Pruefung schneidezimmer.com 08.09.2026, siehe Abschnitt 6. */
  .bw-schalter { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
  .bw-schalter input { position: absolute; opacity: 0; width: 0; height: 0; }
  .bw-schalter-spur {
    position: relative; width: 52px; height: 28px; flex: 0 0 auto;
    border-radius: 14px; background: #b8b8b8;
    transition: background-color 400ms ease;
  }
  .bw-schalter-griff {
    position: absolute; left: 3px; top: 3px; width: 22px; height: 22px;
    border-radius: 50%; background: #fff;
    transition: transform 400ms ease;
  }
  .bw-schalter input:checked + .bw-schalter-spur { background: var(--bw-akzent, #2a8a4a); }
  .bw-schalter input:checked + .bw-schalter-spur .bw-schalter-griff { transform: translateX(24px); }
  .bw-schalter input:focus-visible + .bw-schalter-spur { outline: 2px solid currentColor; outline-offset: 3px; }

  /* --- D5 Ring-zeichnet-sich-im-Kreis (Dauerlaeufer um eine Hervorhebung) -
     Wie A5, aber als Dauerlaeufer statt Einmal-Trigger: der Kreis zeichnet
     sich, haelt kurz, verblasst, macht Pause, wiederholt. --bw-ring-laenge
     ist der Kreisumfang (2 * PI * r), hier fuer r=46 vorbelegt. Herkunft:
     freshcut-barbershop.com, "-30%"-Rabattmarke, siehe Abschnitt 6.        */
  @keyframes bw-ring-kreis-zeichnen {
    0%     { stroke-dashoffset: var(--bw-ring-laenge, 289); opacity: 1; }
    15%    { stroke-dashoffset: 0; opacity: 1; }
    55%    { stroke-dashoffset: 0; opacity: 1; }
    68%    { stroke-dashoffset: 0; opacity: 0; }
    68.01% { stroke-dashoffset: var(--bw-ring-laenge, 289); opacity: 0; }
    100%   { stroke-dashoffset: var(--bw-ring-laenge, 289); opacity: 0; }
  }
  .bw-ring-kreis {
    fill: none; stroke-linecap: round;
    stroke-dasharray: var(--bw-ring-laenge, 289);
    stroke-dashoffset: var(--bw-ring-laenge, 289);
    animation: bw-ring-kreis-zeichnen 8s ease-in-out infinite;
  }

  /* --- E4 Aufklapper-weich ------------------------------------------------
     0fr auf 1fr statt height: auto. Der einzige Weg, unbekannte Hoehen
     ohne JavaScript weich zu oeffnen.                                       */
  .bw-klapp-innen { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .28s ease-out; }
  .bw-klapp[open] .bw-klapp-innen { grid-template-rows: 1fr; }
  .bw-klapp-innen > div { overflow: hidden; }
}

/* --- A8 Hintergrund-steht-still -------------------------------------------
   Der Hintergrund haengt am Fenster, der Abschnitt faehrt als Fenster
   darueber. Reines CSS, kein JavaScript, KEINE .bw-Klasse — zaehlt darum
   nicht gegen R84. Hoechstens ZWEI Abschnitte je Seite.
   Steht bewusst AUSSERHALB des no-preference-Blocks: der Grundzustand (Bild
   fuellt den Abschnitt und scrollt mit) muss immer gelten, sonst fehlt bei
   abbestellter Bewegung das Bild. Festgenagelt wird erst in der Medienabfrage.
   Herkunft: salon-freestyle.de, nachgebaut und gemessen am 08.09.2026
   (interne Ablage).    */
.bw-still { position: relative; isolation: isolate; display: grid; place-items: center; }
.bw-still-bild {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  /* grayscale nimmt dem Foto die Eigenfarbe, damit der Schleier die Flaeche
     einfaerbt statt mit ihr zu kaempfen; brightness deckelt die hellen
     Stellen — genau dort kippt der Kontrast, nicht in der Flaeche insgesamt. */
  filter: grayscale(1) brightness(.58) contrast(1.06);
}
/* Der Schleier ist Pflicht, nicht Geschmack: darunter liegt ein Foto, darauf
   steht helle Schrift. Farbe aus der Seitenpalette setzen, nicht Schwarz —
   so gehoert der Abschnitt zur Marke statt zu wirken wie ein fremdes Fenster. */
.bw-still-schleier {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
    var(--bw-still-oben, rgba(0, 0, 0, .66)) 0%,
    var(--bw-still-unten, rgba(0, 0, 0, .78)) 100%);
}
/* ERST HIER steht der Hintergrund still: nur mit Zeigergeraet, nur bei
   erlaubter Bewegung. Auf dem Handy lebt der Effekt nicht (kurzer Scrollweg)
   und kostet nur Leistung; iOS-Safari behandelt fixed dort ohnehin als scroll.
   clip-path erzeugt KEINEN Bezugsrahmen fuer position:fixed (gemessen
   08.09.2026: Bild-Oberkante 0 px ueber 1200 px Scrollweg) — das Bild bleibt
   am Fenster und wird nur auf die Abschnittsflaeche beschnitten.
   ACHTUNG: filter, transform oder will-change auf dem ABSCHNITT wuerden sehr
   wohl einen Bezugsrahmen erzeugen und den Effekt aufheben. Filter nur
   aufs Bild, nie auf .bw-still.                                             */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .bw-still { clip-path: inset(0); }
  .bw-still-bild { position: fixed; }
}

/* --- E1 Seitenwechsel-ueberblendet (R36, Pflicht auf jeder Seite) ---------
   Steht bewusst AUSSERHALB des no-preference-Blocks: die Regel schreibt den
   Schutz als eigenen Block vor, und beide Teile werden maschinell geprueft.  */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* --- E2 Anker-gleitet ----------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* --- E3 Fortschritt-Balken (Lesefortschritt, reines CSS) ------------------
   animation-timeline: scroll() braucht kein JavaScript. Safari kann es noch
   nicht — dort bleibt der Balken auf 0 stehen und stoert nichts, weil er
   reine Zutat ist und keinen Inhalt traegt.                                  */
@media (prefers-reduced-motion: no-preference) {
  @keyframes bw-fortschritt { from { scale: 0 1; } to { scale: 1 1; } }
  .bw-fortschritt {
    transform-origin: left center; scale: 0 1;
    animation: bw-fortschritt linear both;
    animation-timeline: scroll(root block);
  }
}

/* ============================================================================
   G — Scroll-Erzaehlung
   Neu am 08.09.2026. Herkunft: Testseite Dachdecker-Scrollseite vom 24.08.2026
   (04_Eigene_Website/Demo-Projekte/Testseiten/2026-08_Dachdecker-Scrollseite).
   Dort ist die Bauform gebaut, gemessen und dreimal nachgebessert worden; hier
   steht sie nur noch verallgemeinert. Die drei Nachbesserungen von damals sind
   im Schnipsel in Bewegungsbibliothek.md Abschnitt 4b vermerkt — wer den
   Schnipsel kuerzt, holt sich die Fehler zurueck.

   WANN: hoechstens EINE Strecke je Seite, und nur, wenn es etwas zu erzaehlen
   gibt, das eine Verwandlung IST (vorher/nachher, Aufbau, Ablauf). Nicht als
   Zierde. Sie kostet den Besucher mehrere Bildschirmhoehen Scrollweg.

   WAS SIE BRAUCHT: einen Clip (moeglichst unter 5 MB, Obergrenze 8 MB, ohne
   Ton) UND ein Standbild. Das Standbild ist kein Notnagel, sondern der
   Regelfall auf Fingergeraeten: Scrubbing erstickt dort.

   R109: Ist der Clip KI-erzeugt, gehoert der Hinweis SICHTBAR an die Strecke,
   nicht in den Fuss.                                                          */

/* Die Bahn ist so hoch wie der Scrollweg, den die Erzaehlung bekommen soll.
   Faustwert: eine Bildschirmhoehe je Textschritt, mindestens vier. */
.bw-strecke { height: var(--bw-strecke-hoehe, 500vh); }

.bw-strecke-buehne {
  position: sticky;
  top: var(--bw-strecke-oben, 0px);
  height: calc(100vh - var(--bw-strecke-oben, 0px));
  overflow: hidden;
  isolation: isolate;
  background: var(--bw-strecke-grund, #14171a);
}
.bw-strecke-buehne > video,
.bw-strecke-buehne > img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--bw-strecke-ausschnitt, 50% 50%);
}
/* Schleier: ohne ihn steht heller Text auf wechselndem Bildinhalt, und der
   Kontrast schwankt mit jedem Einzelbild. */
.bw-strecke-schleier { position: absolute; inset: 0; z-index: -1; background: var(--bw-strecke-schleier, linear-gradient(90deg, rgba(20,23,26,.9) 0%, rgba(20,23,26,.7) 45%, rgba(20,23,26,.3) 100%)); }

/* Die Textschritte liegen uebereinander; sichtbar ist immer genau einer. */
.bw-strecke-schritte { position: relative; height: 100%; display: flex; align-items: center; }
.bw-strecke-schritt {
  position: absolute;
  opacity: 0; visibility: hidden;
  transition: opacity .25s linear, visibility 0s .25s;
}
.bw-strecke-schritt.an { opacity: 1; visibility: visible; transition: opacity .25s linear, visibility 0s; }

/* Ohne JavaScript traegt kein Schritt die Klasse "an". Dann stehen alle
   untereinander und die Seite ist vollstaendig lesbar — die Erzaehlung
   verliert die Bewegung, nicht den Inhalt. */
html:not(.js) .bw-strecke { height: auto; }
html:not(.js) .bw-strecke-buehne { position: relative; height: min(60vh, 26rem); }
html:not(.js) .bw-strecke-schritte { display: block; height: auto; }
html:not(.js) .bw-strecke-schritt { position: relative; opacity: 1; visibility: visible; padding-block: 1.5rem; }

/* Abbestellte Bewegung: dasselbe wie ohne JavaScript, dazu kein Uebergang.
   Das Skript liefert hier ohnehin das Standbild statt des Videos aus. */
@media (prefers-reduced-motion: reduce) {
  .bw-strecke { height: auto; }
  .bw-strecke-buehne { position: relative; height: min(60vh, 26rem); }
  .bw-strecke-schritte { display: block; height: auto; }
  .bw-strecke-schritt { position: relative; opacity: 1; visibility: visible; transition: none; padding-block: 1.5rem; }
}

/* Fortschritt in Segmenten, eines je Abschnitt der Erzaehlung. */
.bw-strecke-balken { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; }
.bw-strecke-balken span { height: 4px; background: var(--bw-strecke-balken-grund, rgba(255,255,255,.18)); overflow: hidden; }
.bw-strecke-balken span i { display: block; height: 100%; transform-origin: left; transform: scaleX(0); background: var(--bw-strecke-balken-fuellung, #fff); }

/* Der Hinweis, dass einmal getippt werden muss (iOS, siehe Schnipsel). */
.bw-strecke-tippdeckel {
  position: absolute; inset: auto 0 1.5rem 0; z-index: 2;
  text-align: center; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--bw-strecke-hinweis, rgba(255,255,255,.8)); pointer-events: none;
}

/* ============================================================================
   G2 — Hintergrund-loest-sich-ab
   Neu am 08.09.2026. Herkunft: freshcut-barbershop.com, Zitat-Abschnitt
   (Elementor-Hintergrund-Diaschau), siehe Abschnitt 6 von Bewegungsbibliothek.md.

   WANN: hoechstens EINE je Seite — mehrere automatisch wechselnde Flaechen
   auf einer Seite konkurrieren um Aufmerksamkeit.

   Keine .bw-Klasse, zaehlt nicht gegen R84 (wie A8). Steht bewusst AUSSERHALB
   des no-preference-Blocks: das zuerst im Markup mit "ist-aktiv" ausgezeich-
   nete Bild muss immer sichtbar sein, ganz ohne JavaScript und unabhaengig
   von der Bewegungseinstellung — erst der Wechsel selbst ist Bewegung. */
.bw-abloese { position: relative; isolation: isolate; }
.bw-abloese-bild {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transform: translateY(6%);
  transition: opacity .5s ease, transform .5s ease;
}
.bw-abloese-bild.ist-aktiv { opacity: 1; transform: translateY(0); }

/* Reduzierte Bewegung: der Wechsel bleibt (das Skript pausiert ihn ohnehin,
   siehe Bewegungsbibliothek.md Abschnitt 4), nur ohne Gleiten/Ueberblenden. */
@media (prefers-reduced-motion: reduce) {
  .bw-abloese-bild { transition: none; transform: none; }
}
