/* ==========================================================================
   PHYSIOTHERAPIE AM AASEE — Krankengymnastik, Manuelle Therapie, Lymphdrainage
   Basis-Stufe (29 EUR). Standbilder, ein Einblende-Effekt pro Abschnitt,
   Hover und Fokus. Kein Parallax, kein Pinning, kein Scrub, kein Zaehler.

   Herkunft
   --------
   Uebersetzt aus dem Claude-Design-Entwurf "Physiotherapie am Aasee.dc.html"
   nach `docs/regeln/vorlagen.md`. Der Entwurf laedt Poppins und Open Sans
   (samt kursivem Schnitt) von `fonts.googleapis.com`, dazu Font Awesome 6.5.2
   von `cdnjs.cloudflare.com` fuer rund vierzehn Symbole und vier Fotos von
   `images.unsplash.com`; dazu `{{ }}`, vier `<sc-if>`-Bloecke, `style-hover`
   und `style-focus` an ueber vierzig Knoten und eine `DCLogic`-Klasse mit
   Scroll-Listener — nichts davon laeuft in einem Browser ohne die
   Claude-Design-Umgebung (V1).

   Gebaut wird nach Benedikts Entscheidung vom 20.08.2026 nur die
   Starter-Fassung: kein `js/scroll.js`, keine Parallaxe, keine
   scroll-gebundenen Zaehler (V7).

   Abweichungen vom Entwurf, jede mit Grund
   ----------------------------------------
    1. Poppins ist ersetzt durch Jost (Ersetzungstabelle,
       `docs/vorlagen/uebernahme-anleitung.md`, Schritt 4: "Poppins verraet den
       generierten Entwurf"). Vorhanden, selbst gehostet, gleiche geometrische
       Grotesk. Jost steht AUSSCHLIESSLICH in Ueberschriften, Kleinzeilen und
       Zahlen: die Schrift hat eine sehr kleine x-Hoehe und wirkt in
       Fliesstextgroesse zu klein (README der Branche).
    2. Der Entwurf verlangt Poppins 500 und Open Sans 500. Die Open-Sans-Datei
       fuehrt 300, 400, 600, 700 und 800 als benannte Instanzen, aber KEIN 500.
       Wo der Entwurf 500 wollte (Kleintext in der Kopfleiste, Zwischenzeilen
       in den Leistungskarten), laeuft die Schrift in 600 und ist dafuer
       kleiner und gesperrt gesetzt, nicht duenner.
    3. In JEDER Regel steht das `font-weight` ausdruecklich da — auch bei
       `strong`, `summary`, `th` und Knopfbeschriftungen, die es sonst vom
       Browser bekaemen. Grund steht in der README der Branche: bei den
       variablen Dateien dieser Sammlung ist der Standardwert nicht
       verlaesslich 400 (Montserrat steht dort auf 100). Wer sich angewoehnt,
       Gewichte zu benennen, tappt bei der naechsten Datei nicht hinein.
    4. Kursiv ist gestrichen. Zu keiner der beiden Familien liegt ein kursiver
       Schnitt vor (`italicAngle` ist 0, das Italic-Bit ist nicht gesetzt);
       `font-style: italic` erzeugt darauf eine schraeg gescherte Faelschung.
       Der Entwurf laedt Open Sans ausdruecklich mit `ital,wght@1,400`.
    5. Font Awesome ist vollstaendig ersetzt durch gezeichnete Strichsymbole
       aus `_shared/gesundheit/icons.svg.html` (V3, V6). Inline, kein Abruf,
       keine Symbolschrift. Zwei Zeichen kommen aus den Nachbarordnern, wie es
       die README dieser Branche vorsieht: `leaf` aus `_shared/pflege` (Nr. 13)
       fuer die Massage ohne Verordnung und `house` aus `_shared/handwerk`
       (Nr. 11) fuer die Hausbesuche.
       Ohne Gegenstueck geblieben sind `fa-map-location-dot` und
       `fa-chevron-up` in ihrer Entwurfsrolle: das eine stand in der
       Karten-Attrappe, das andere an einem Knopf, den ein Scroll-Listener
       ein- und ausblendete.
    6. Das Zeichen "→" kommt nirgends als Schriftzeichen vor. Keine der beiden
       Schriften fuehrt U+2192 (gegen die `cmap` geprueft, nicht angenommen);
       ein gesetzter Pfeil kaeme aus einer Ersatzschrift des Systems und saehe
       auf jedem Geraet anders aus. Ueberall steht das gezeichnete
       `arrow-right` (Nr. 28). Dasselbe gilt fuer den Haken: `check-circle`
       (Nr. 17) statt "✓".
    7. Der Cookie-Hinweis ist ersatzlos weg (V12). Seine beiden Knoepfe
       setzten dieselbe Zustandsvariable und schlossen nur das Fenster; die
       Seite laedt ohnehin nichts von Dritten. Der echte kommt aus dem Zusatz
       `cookie-pro`. Damit faellt auch der Verweis "Cookie-Einstellungen" im
       Fuss weg — er zeigte auf `#kontakt`.
    8. Die Karten-Attrappe ist eine gezeichnete Umgebungskarte geworden
       (V12, Muster: `_shared/arztpraxis`, Nr. 11). Der Entwurf zeigte einen
       Knopf "Karte laden", nannte Google Maps beim Namen und blendete danach
       ein Streifenmuster mit der Aufschrift "KARTENAUSSCHNITT" ein — eine
       Attrappe, die nie eine Karte geladen haette. Eine eingebettete Karte
       kommt auch nicht in Frage: sie gibt die Adresse des Besuchers an einen
       Dritten weiter, bevor irgendjemand zugestimmt hat (V3). Anschrift und
       Anfahrt stehen als Text daneben — die Zeichnung ist keine
       Informationsquelle.
    9. Der Knopf "nach oben" haengt im Entwurf an einem Scroll-Listener
       (`window.scrollY > 700`). Das ist Bewegung beziehungsweise ein Stilwert
       aus der Scroll-Position und gehoert der Premium-Stufe (V7). Hier ist es
       ein gewoehnlicher Verweis auf `#main`, ab Rechnerbreite dauerhaft
       sichtbar.
   10. `style-hover` und `style-focus` an ueber vierzig Knoten sind echtes
       `:hover` und `:focus-visible` in dieser Datei (V6). Inline-`style` an
       jedem einzelnen Knoten sind Klassen und Tokens in :root.
   11. Jede Zulassungs- und Fortbildungsbehauptung ist gestrichen (V11):
       "Zulassung nach § 124 SGB V" in der Leistungskarte,
       "Zugelassen fuer alle gesetzlichen Krankenkassen sowie Privatpatienten
       und Beihilfe" als eigene Fussspalte, "Alle Kassen & Privat" im
       Merkmalsband, "Alle Kassen und Privatpatienten" im Hero-Vorspann,
       "Zertifizierte Therapeut:innen" unter der Manuellen Therapie,
       "Fortbildungen in Manueller Therapie und Kiefergelenkbehandlung (CMD)"
       und "Bobath-Konzept fuer Erwachsene" im Team-Teil. An ihrer Stelle steht
       jeweils, was die Praxis tatsaechlich TUT: auf Verordnung oder als
       Selbstzahler behandeln, in geschlossenen Einzelraeumen arbeiten,
       Schwerpunkte benennen ohne Abschluesse zu behaupten. Ein Siegel oder
       Abzeichen wuerde die Qualifikation auch dann noch behaupten, wenn der
       Text laengst weg ist — deshalb ist auch nichts bebildert.
       Bei der Pruefung kam eine weitere dazu: "Ebenerdige, barrierefreie
       Praxisraeume" im Merkmalsband. "Barrierefrei" ist ein festgelegter
       Begriff (§ 4 BGG, DIN 18040) und verlangt mehr als einen Zugang ohne
       Stufe — Tuerbreiten, Bewegungsflaechen, ein entsprechendes WC. Die
       Seite sagt an drei anderen Stellen ohnehin genauer "ebenerdig, ohne
       Stufe"; jetzt sagt sie es auch dort. Das Rollstuhl-Zeichen bleibt
       stehen: es zeigt den stufenlosen Zugang, ohne Barrierefreiheit zu
       behaupten.
   12. "ab 39 € / 30 Min." unter der Massage ist weg. Ein fester Betrag mitten
       in einer Leistungskarte ist beim naechsten Preisaushang falsch, und
       niemand liest eine Demo-Seite nach. Genannt ist stattdessen, dass die
       Leistung ohne Rezept buchbar ist.
   13. Die Zuzahlung in der Frageliste nennt den MECHANISMUS, nicht die Zahl:
       gesetzlich festgelegter Anteil, Hoehe haengt vom Wert der Verordnung ab,
       Befreiung per Nachweis. Ein Eurobetrag aus einem Gesetz veraltet mit der
       naechsten Aenderung (Uebernahme-Anleitung, Schritt 5). Dasselbe gilt fuer
       das Ausfallhonorar: genannt ist die Frist, nicht der Betrag.
   14. "27 Jahre in Muenster" ist weg. Der Entwurf nennt an einer Stelle die
       Gruendung 1998, an anderer 27 Jahre und im Fuss "© 2022" — drei
       Angaben, die sich schon im Entwurf widersprechen. Die Jahreszahl 1998
       bleibt (sie bleibt richtig), die Differenz nicht. An ihre Stelle tritt
       die Zahl der Behandlungsraeume.
   15. Anschrift, Telefon und E-Mail sind erkennbar erfunden (V10, Benedikts
       Vorgabe vom 20.08.2026): Musterstrasse 27, 12345 Musterstadt,
       0123 456789 (Verweisziel `tel:+49123456789`),
       `praxis@physio-am-aasee.example`. Der Entwurf nannte eine echte Strasse
       in Muenster, eine erreichbare Rufnummer und eine erreichbare Domain.
       Der Ortsbezug ist mitgezogen: "mitten am Aasee" ist "direkt am
       Seeufer", die Haltestelle "Aasee" ist "Haltestelle am Seeufer". Der
       Name der Praxis bleibt — er ist der Titel dieser Vorlage.
   16. "Umsetzung: Weber & Kollegen Medienbuero, Muenster" im Fuss ist weg:
       eine erfundene Agentur, die echt aussieht (V11). Wer die Seite gemacht
       hat, sagt die Hinweisleiste aus A17.
   17. Die Jahreszahl im Fuss war 2022 und ist 2026.
   18. Impressum, Datenschutz und AGB bleiben verlinkt und zeigen auf den
       Abschnitt `#rechtliches` am Seitenende (V17). Sozialnetz-Zeichen hat
       der Entwurf keine — die Servicezeile mit "f" und "in" aus der Sichtung
       steht in dieser Fassung des Entwurfs nicht mehr drin; waere sie da,
       kaeme sie ohne Profil dahinter weg.
   19. NEU hinzugefuegt: ein Filter ueber den Leistungen (Alle, Therapie,
       Anwendung, Training). Der Entwurf zeigte sechs Karten ohne jede
       Ordnung nebeneinander. Der Filter laeuft ueber vier
       `<input type="radio">` plus `:checked` (V8) — bedienbar mit der
       Tastatur, funktioniert mit abgeschaltetem Skript, und mit abgeschaltetem
       CSS stehen alle sechs Karten untereinander da.
   20. NEU hinzugefuegt: die Frageliste als `<details>`-Aufklapper. Sie faengt
       auf, was der Entwurf an drei Stellen nur behauptete (Kassen, Zuzahlung,
       Wartezeit) und beantwortet es, statt es zuzusagen — bedienbar mit der
       Tastatur, auffindbar ueber die Suche im Browser, ohne eine Zeile
       Javascript.
   21. NEU hinzugefuegt: eine Leiste am unteren Bildrand (Anrufen, Termin) fuer
       Handybreiten und ein Sprunglink zum Inhalt. Der Entwurf setzt seine
       Navigation in ein `display:flex` ohne jede Bedingung und laesst
       Handybesucher mit vier ueberlaufenden Menuepunkten stehen (V5).
   22. Das Formular hat kein `action` und einen `type="button"`, im Markup
       steht der Grund (V12). Im Entwurf hing am Knopf ein
       `onClick="{{ onSubmit }}"`, das nur einen Dankestext in den Zustand
       schrieb.
   23. Die Namen im Team-Teil BLEIBEN stehen — ausdrueckliche Entscheidung von
       Benedikt am 20.08.2026, dieselbe Regel wie fuer Kundenstimmen. Die
       Portraits werden erzeugt, nie das Foto eines echten Menschen unter
       falschem Namen. Im Markup steht dahinter `<!-- Vom Kunden zu ersetzen -->`.
       Eine Kundenstimme hat dieser Entwurf nicht; erfunden wird hier keine
       (V11).

   Farblogik
   ---------
   Der Entwurf hat ein Petrol, ein dunkles Petrolgrau und ein Gold. Petrol
   #14746c traegt Verweise, Kleinzeilen und die Flaechen der Handlungsbaender;
   #1f2d2c die Ueberschriften, den Fuss und den Text auf goldener Flaeche.
   Gold #e2a33c ist der Akzent. Der Grund ist Weiss, ruhige Abschnitte liegen
   auf #f4f7f7.

   Das Gold des Entwurfs traegt in dieser Datei KEINEN weissen Text und steht
   nirgends als Text auf hellem Grund. Weiss auf #e2a33c sind 2,20:1, Gold auf
   Weiss ebenso — der Hero-Knopf des Entwurfs fiel damit durch. Statt das Gold
   abzudunkeln und sein Kennzeichen zu verlieren, ist der Text darauf
   umgedreht: auf goldener Flaeche steht #1f2d2c (6,49:1). Auf DUNKLEM Grund
   traegt eine aufgehellte Fassung #edb861 die Kleinzeilen.

   Was jede Farbe darf:
     --teal      #14746c  Text auf hellem Grund (Verweise, Kleinzeilen,
                          Symbole) UND Flaeche unter weissem Text.
     --teal-dk   #0f5b55  Hover dazu, auf hell wie auf Flaeche.
     --teal-2    #12564f  nur in der gezeichneten Karte, auf der hellen
                          Praxisflaeche.
     --dark      #1f2d2c  Ueberschriften auf hell; Flaeche fuer den Fuss; der
                          einzige Text, der auf --gold stehen darf.
     --gold      #e2a33c  nur FLAECHE und Strich: Knopf, Balken unter jeder
                          Ueberschrift, Kartennadel. Als Flaeche traegt sie
                          ausschliesslich --dark. NIE weisser Text darauf, nie
                          als Text auf hellem Grund.
     --gold-lt   #edb861  Kleinzeilen und Hover auf DUNKLEM Grund.
     --on-teal   #dcefed  Text auf --teal (Kopfleiste, Handlungsband).
     --on-dark   #dbe7e5  Text auf dem Hero-Schleier und auf --dark.
     --on-dark-soft #9fb0ae  Kleinschrift im Fuss.

   Gemessene Kontraste (relative Luminanz nach WCAG 2.1, gerechnet)
   ----------------------------------------------------------------
     --ink       #3d4a4a auf --paper #ffffff      9,22:1
     --ink       #3d4a4a auf --wash  #f4f7f7      8,56:1
     --ink       #3d4a4a auf --field #fbfcfc      8,97:1
     --ink       #3d4a4a auf --tint  #e7f0ef      7,95:1   (Symbolflaeche)
     --muted     #5d6b6a auf --paper              5,56:1
     --muted     #5d6b6a auf --wash               5,16:1
     --muted     #5d6b6a auf --field              5,41:1
     --muted     #5d6b6a auf --tint               4,79:1
     --teal      #14746c auf --paper              5,61:1
     --teal      #14746c auf --wash               5,21:1
     --teal      #14746c auf --field              5,46:1
     --teal      #14746c auf --tint               4,84:1
     --teal-dk   #0f5b55 auf --paper              7,93:1
     --teal-dk   #0f5b55 auf --wash               7,36:1
     --teal-dk   #0f5b55 auf --tint               6,84:1
     --dark      #1f2d2c auf --paper             14,29:1
     --dark      #1f2d2c auf --wash              13,26:1
     --dark      #1f2d2c auf --tint              12,32:1
     #ffffff             auf --teal   #14746c     5,61:1
     #ffffff             auf --teal-dk #0f5b55    7,93:1
     #ffffff             auf --dark   #1f2d2c    14,29:1
     --dark      #1f2d2c auf --gold   #e2a33c     6,49:1   (Knopf, Hover im
                                                            Handlungsband)
     --on-teal   #dcefed auf --teal                4,70:1
     --on-dark   #dbe7e5 auf --dark               11,27:1
     --on-dark-soft #9fb0ae auf --dark             6,32:1
     --gold-lt   #edb861 auf --dark                7,91:1
     --teal      #14746c auf --gold                2,55:1  (siehe unten:
                                                            traegt nie Text)

   PREMIUM-ZUSATZ (Aufgabe 13b): Die folgenden Absaetze zu `img/hero.jpg`
   beschreiben die STARTER-Fassung, aus der diese Datei hervorgegangen ist.
   In der Premium-Fassung ist der Hero mit dem Film zu einem Abschnitt
   verschmolzen (siehe ".hero--film" weiter unten); `img/hero.jpg` wird hier
   nicht mehr geladen, das Standbild des Films traegt denselben Platz. Die
   Rechnung fuer den neuen Kopf steht im Abschnitt FILM.

   Der Hero ist ein Fotoband und deshalb am Schleier gerechnet, nicht gegen
   Reinweiss. Der Schleier deckt mit 88 % #143432 gleichmaessig. NACHGEMESSEN
   am fertigen `img/hero.jpg` (1600 × 900), nicht mehr geschaetzt.
   Gemessen wird ueber das GANZE Foto und nicht nur unter dem Textblock:
   `background-position: center 35 %` zeigt auf Rechnerbreite die volle
   Bildbreite, und auf Handybreite laeuft der Textblock ueber die ganze
   Spalte. Hellste 48-px-Kachel im ganzen Bild: #f3f3f4, das gegen das
   Tageslicht ausgebrannte Fenster oben rechts (bei x 1424, y 208); mit
   Schleier #2f4b49:
       #ffffff    (h1, Knopfbeschriftung auf dem Geisterknopf)   9,44:1
       --on-dark  (Vorspann)                                     7,45:1
       --gold-lt  (Kleinzeile ueber der Ueberschrift)            5,23:1
   Unter dem Textblock links allein ist die hellste Kachel das beleuchtete
   Handtuch (#fddeb8, mit Schleier #304842): 9,85:1 / 7,78:1 / 5,46:1.
   Angesetzt war vor der Erzeugung #d9dad4; das Foto faellt nicht heller aus
   als angesetzt, der Schleier bleibt deshalb bei 88 % und muss nicht auf
   90 % steigen.
   Mit dem Gold des Entwurfs (#e2a33c) laege die Kleinzeile auf dem gemessenen
   Grund bei 4,29:1 — unter der Grenze. Deshalb traegt sie auf dunklem Grund
   die aufgehellte Fassung --gold-lt.
   (Die drei Zahlen standen vor der Pruefung eine Hundertstelstufe hoeher:
   notiert war #f0f0f2 statt der wirklich hellsten Kachel #f3f3f4. Nachgezaehlt
   ueber alle 48-px-Kacheln des Bildes im 8-px-Raster; alle Werte bleiben klar
   ueber 4,5:1, der Schleier bleibt bei 88 %.)

   Der Entwurf legte hier einen WAAGERECHTEN Verlauf von 86 % auf 35 %
   Deckung. Auf dem Handy laeuft der Textblock ueber die ganze Breite, also
   auch ueber das Drittel mit 35 % — Weiss kaeme dort ueber einem hellen Foto
   auf rund 1,6:1. Deshalb deckt der Schleier hier ueberall gleich.

     GEZEICHNETE KARTE (`.map`, eigene --map-*-Toene)
       Die Beschriftungen stehen auf fuenf Gruenden, nicht nur auf --map-bg:
         --map-ink #4d5a59 auf --map-bg    #eef2f2           6,37:1
         --map-ink #4d5a59 auf --map-block #e0e7e6           5,73:1
         --map-ink #4d5a59 auf --map-road  #ffffff           7,19:1
         --map-ink #4d5a59 auf --map-water #c8e0e5           5,22:1
         --map-ink #4d5a59 auf den zwei Schildchen
           (90 % --map-bg ueber --map-block, #edf1f1)        6,31:1
         --map-accent-ink #12564f auf der Praxisflaeche
           (12 % --map-accent ueber --map-bg, #d4e3e2)       6,43:1
       Die Nadel ist --map-pin #e2a33c und traegt keinen Text. Auf der
       Praxisflaeche steht ABSICHTLICH nicht --teal (4,24:1), sondern das
       dunklere --teal-2.

   Was ABSICHTLICH unter 4,5:1 liegt und deshalb NIE Text traegt:
     --gold #e2a33c als Flaeche unter WEISSEM Text (2,20:1) und als Text auf
     hellem Grund (2,20:1). Genau deshalb steht auf jeder goldenen Flaeche
     --dark, und auf hellem Grund steht nirgends Gold als Text — die goldenen
     Balken unter den Ueberschriften sind reine Flaeche.
     --gold auf --teal (2,55:1): das Gold kommt im Handlungsband nur als
     Hover-FLAECHE vor, nie als Schrift auf Petrol.

   Aus dem Entwurf ersetzt, weil sie Text trugen und durchfielen:
     #ffffff auf #e2a33c  2,20:1 (Hero-Knopf "Termin anfragen")
       -> Text auf Gold ist --dark, 6,49:1
     #8ba09e auf #ffffff  2,76:1 (Zwischenzeilen unter jeder Leistungskarte,
       "nach Vereinbarung" und "geschlossen" in den Oeffnungszeiten, die
       Fussnote zur telefonischen Erreichbarkeit, der Untertitel der Marke)
       -> --muted #5d6b6a, 5,56:1
     #cfe6e3 auf #14746c  4,29:1 (Kopfleiste und Vorspann im Handlungsband)
       -> --on-teal #dcefed, 4,70:1
     #7d908e auf #dfe7e4  2,50:1 (Aufschrift der Karten-Attrappe)
       -> Karte ist ersetzt (V12)
     #5d6b6a auf #ffffff  5,56:1 (Fliesstext) -> bestanden, bleibt
     #9fb0ae auf #1f2d2c  6,32:1 (Fuss) -> bestanden, bleibt
     #dbe7e5 auf dem Hero-Schleier -> bestanden, bleibt

   Aufbau der Datei
   ----------------
   Mobil zuerst. Alle Media Queries sind min-width; die schmale Ansicht ist
   der Ausgangszustand, breitere Fenster bekommen Spalten dazu. Geprueft bei
   360, 768 und 1280 Pixeln.

   DIE FOTOS SIND DA — sieben Stueck, alle erzeugt, keines von einer
   Fremdseite geholt (V3, V13). Die Beschreibungen, mit denen sie entstanden
   sind, stehen in `docs/vorlagen/bild-prompts-physio-aasee.md`; wer eines
   ersetzen will, findet dort den Wortlaut.
   Sechs davon sind `<img>` im Markup, mit `alt`, `width`, `height` und
   `loading="lazy"` — die Groessenangaben halten den Platz frei, damit beim
   Nachladen nichts rutscht.
   Das siebte, `img/hero.jpg`, war in der STARTER-Fassung die Ausnahme: es
   steckte als CSS-Hintergrund in der Gestaltung. PREMIUM-ZUSATZ (Aufgabe
   13b): In dieser Fassung entfaellt `img/hero.jpg` vollstaendig — der Kopf
   ist mit dem Film verschmolzen und zeigt dessen Standbild
   (`img/film-ende.jpg`, echtes `<img>`, siehe Abschnitt FILM). Kein Vorladen
   mehr fuer ein CSS-Hintergrundbild noetig.
   ========================================================================== */

/* ── Schriften (selbst gehostet, latin-Teilmenge, 74 896 B = 73,1 KB) ─────
   Beide Dateien sind variabel. Deklariert wird nur der Bereich, der auch
   benutzt wird, nicht der volle Achsenbereich: Jost kann 100–900, aber ein
   Haarstrich-100 verschwindet auf schlechten Bildschirmen. Open Sans laeuft
   auf der Achse 300–800 und fuehrt kein 500 als benannte Instanz. Kursive
   gibt es zu keiner der beiden. Budget der Basis-Stufe: 120 KB.             */

@font-face {
  font-family: "Jost";
  src: url("../vendor/fonts/jost-var.woff2") format("woff2");
  font-weight: 400 700;   /* Datei traegt wght 100-900, Standard 400 */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Open Sans";
  src: url("../vendor/fonts/open-sans-var.woff2") format("woff2");
  font-weight: 400 700;   /* Datei traegt wght 300-800, kein benanntes 500 */
  font-style: normal;
  font-display: swap;
}

/* ── Tokens ─────────────────────────────────────────────────────────────── */

:root {
  /* Jost laeuft breiter als die meisten Systemschriften und hat eine sehr
     kleine x-Hoehe. Faellt sie aus, springt der Titel auf die Systemschrift —
     die laeuft schmaler und mit groesserer x-Hoehe, und eine Ueberschrift, die
     vorher in zwei Zeilen passte, sieht danach anders aus. Deshalb nirgends
     feste Hoehen fuer Titelzeilen und kein Layout, das auf genau zwei Zeilen
     gebaut ist. */
  --font-title: "Jost", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
  --font-body: "Open Sans", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;

  --teal: #14746c;       /* Text auf hell UND Flaeche unter weissem Text */
  --teal-dk: #0f5b55;    /* Hover dazu */
  --teal-2: #12564f;     /* nur in der gezeichneten Karte */
  --dark: #1f2d2c;       /* Ueberschriften, Fuss; Text auf --gold */

  --gold: #e2a33c;       /* nur Flaeche und Strich, NIE Text darauf ausser --dark */
  --gold-lt: #edb861;    /* Kleinzeilen und Hover auf dunklem Grund */

  --ink: #3d4a4a;
  --muted: #5d6b6a;

  --paper: #ffffff;
  --wash: #f4f7f7;
  --field: #fbfcfc;      /* Formularfeld */
  --tint: #e7f0ef;       /* Symbolflaeche */

  --line: #e6ecec;
  --line-2: #d5dfde;

  --on-teal: #dcefed;
  --on-dark: #dbe7e5;
  --on-dark-soft: #9fb0ae;

  --focus: #14746c;
  --focus-halo: #ffffff;

  --radius: 3px;         /* der Entwurf rundet auf 2 bis 3 Pixel */
  --wrap: 1180px;
  --pad: clamp(1rem, 4vw, 1.5rem);
  --notice: 26px;        /* Hoehe der Demo-Hinweisleiste, fix im Markup */
  --quickbar: 58px;      /* Hoehe der Handy-Leiste am unteren Bildrand */
}

/* Auf dunklem Grund braucht der Fokusring die umgekehrte Aufteilung, sonst
   verschwindet der weisse Hof im Weiss des Rings. */
.is-dark {
  --focus: #ffffff;
  --focus-halo: #1f2d2c;
}

/* ── Grundlagen ─────────────────────────────────────────────────────────── */

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--notice) + 1rem);
}

/* Nur dort, wo js/gleiten.js Lenis anschaltet (Bedingung 1 dort: identisches
   pointer: fine), schaltet dieser Block den nativen Smooth-Scroll wieder ab.
   Warum: Laedt die Seite direkt mit einem #anker in der Adresse (genau der
   Fall beim Stufen-Schalter, der auf die Zieladresse eine Sprungmarke
   haengt), startet der Browser wegen scroll-behavior: smooth eine eigene,
   zeitgestreckte Sprung-Animation. Lenis (autoRaf: true) liest beim Start
   die aktuelle Scroll-Position einmalig aus und haelt sie danach jeden
   Frame fest -- greift das genau in diesem Moment mitten in der noch
   laufenden nativen Animation ab, friert die Seite dort ein, meist nahe 0.
   Wortgleich aus dem Muster Alte Linde uebernommen (dort am laufenden
   Server nachgemessen, Aufgabe 11b). Ausserhalb von pointer: fine laeuft
   kein Lenis, dort bleibt smooth. */
@media (pointer: fine) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  padding-top: var(--notice);
  padding-bottom: var(--quickbar);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 {
  font-family: var(--font-title);
  font-weight: 600;
  color: var(--dark);
  line-height: 1.2;
  letter-spacing: 0;
  margin: 0 0 .5em;
  text-wrap: balance;
}

h1 { font-weight: 700; font-size: clamp(2rem, 7.6vw, 3.35rem); line-height: 1.14; }
h2 { font-size: clamp(1.6rem, 5vw, 2.4rem); line-height: 1.25; }
h3 { font-size: 1.3rem; }

h4 {
  font-family: var(--font-title);
  font-weight: 600;
  font-size: .82rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 .8rem;
}

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--teal); text-decoration: none; font-weight: inherit; }
a:hover { color: var(--teal-dk); text-decoration: underline; }

/* NICHT weglassen: sonst holt sich der Browser sein eigenes Fettgewicht aus
   einer variablen Datei, und das ist bei dieser Sammlung nicht verlaesslich. */
strong, b { font-weight: 700; }

::selection { background: var(--teal); color: #fff; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding-inline: var(--pad);
}

/* Die gesperrte Kleinzeile ueber jeder Ueberschrift — das durchgaengige
   Zeichen des Entwurfs. Auf hellem Grund petrol, auf dunklem gold. */
.eyebrow {
  display: block;
  font-family: var(--font-title);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--teal);
  margin: 0 0 .9rem;
}

.eyebrow--bar {
  display: flex;
  align-items: center;
  gap: .75rem;
}

.eyebrow--bar::before {
  content: "";
  flex: none;
  width: 30px;
  height: 3px;
  background: var(--gold);
}

.eyebrow--center { justify-content: center; }

.is-dark .eyebrow { color: var(--gold-lt); }

/* Der goldene Balken unter der Ueberschrift, im Entwurf 60 x 3 Pixel.
   Reine Flaeche, traegt nie Text. */
.rule {
  width: 60px;
  height: 3px;
  background: var(--gold);
  border: 0;
  margin: 1.1rem 0 1.3rem;
}

.rule--center { margin-inline: auto; }

/* Steht der Balken direkt unter einer Ueberschrift, faellt deren Grundabstand
   weg — sonst stehen 0,5em plus 1,1rem uebereinander und der Balken haengt in
   der Luft. Die zentrierte Fassung in `.section__head--center` bringt ihren
   eigenen Abstand mit und ist spezifischer; sie bleibt unberuehrt. */
h2 + .rule { margin-top: 0; }

.icon { width: 1.25rem; height: 1.25rem; flex: none; vertical-align: -.18em; }

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

.skip {
  position: absolute;
  left: 50%;
  top: calc(var(--notice) + .5rem);
  transform: translate(-50%, -250%);
  z-index: 200;
  background: var(--dark);
  color: #fff;
  padding: .7rem 1.2rem;
  border-radius: var(--radius);
  font-weight: 700;
  font-size: .9rem;
  letter-spacing: .04em;
}

.skip:focus { transform: translate(-50%, 0); color: #fff; text-decoration: none; }

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--focus-halo);
}

/* ── Einblenden: genau ein Effekt pro Abschnitt ──────────────────────────── */

.has-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(12px);
}

.has-reveal [data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 400ms ease-out, transform 400ms ease-out;
}

/* ── Knoepfe ────────────────────────────────────────────────────────────── */
/* Der Entwurf setzt weissen Text auf #e2a33c — 2,20:1. Statt das Gold
   abzudunkeln und damit sein Kennzeichen zu verlieren, steht darauf jetzt
   das dunkle Petrolgrau: 6,49:1, und der Knopf leuchtet weiter. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  font-family: var(--font-body);
  font-size: .92rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .95rem 1.8rem;
  border: 2px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-align: center;
  transition: background-color 170ms ease, color 170ms ease, border-color 170ms ease;
}

.btn:hover { text-decoration: none; }

.btn--gold { background: var(--gold); border-color: var(--gold); color: var(--dark); }
.btn--gold:hover { background: var(--dark); border-color: var(--dark); color: #fff; }

.btn--teal { background: var(--teal); border-color: var(--teal); color: #fff; }
.btn--teal:hover { background: var(--teal-dk); border-color: var(--teal-dk); color: #fff; }

/* Nur auf dunklem Grund, deshalb weisse Kante. */
.btn--ghost { background: transparent; border-color: rgb(255 255 255 / .7); color: #fff; }
.btn--ghost:hover { background: #fff; border-color: #fff; color: var(--teal); }

/* Weisse Flaeche auf Petrol, mit Petrol beschriftet: 5,61:1. Beim Hover
   dreht die Flaeche auf Gold, der Text auf --dark: 6,49:1. */
.btn--paper {
  background: #fff;
  border-color: #fff;
  color: var(--teal);
  font-family: var(--font-title);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: none;
  white-space: nowrap;
}

.btn--paper:hover { background: var(--gold); border-color: var(--gold); color: var(--dark); }

.btn--block { width: 100%; }

/* ── Kopfleiste ─────────────────────────────────────────────────────────── */

.topbar {
  background: var(--teal);
  color: var(--on-teal);
  font-size: .8rem;
  line-height: 1.5;
}

.topbar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem 1.4rem;
  padding-block: .55rem;
}

.topbar__item { display: inline-flex; align-items: center; gap: .5rem; }
.topbar .icon { width: 1rem; height: 1rem; color: var(--on-teal); }
.topbar a { color: #fff; font-weight: 600; }
.topbar a:hover { color: #fff; }

/* Anschrift und Sprechzeiten stehen auf dem Handy weiter unten auf der Seite;
   hier oben kosten sie zwei ganze Zeilen ueber der Falz. */
.topbar__hide { display: none; }

/* ── Kopf ───────────────────────────────────────────────────────────────── */

.header {
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 8px rgb(31 45 44 / .06);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 70px;
  padding-block: .7rem;
}

.brand { display: flex; align-items: center; gap: .75rem; color: inherit; }
.brand:hover { text-decoration: none; }

.brand__mark {
  width: 42px; height: 42px;
  flex: none;
  border-radius: 50%;
  background: var(--teal);
  color: #fff;
  display: grid;
  place-items: center;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1;
}

.brand__name {
  display: block;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1.15;
  color: var(--dark);
}

/* Im Entwurf #8ba09e auf Weiss — 2,76:1. */
.brand__sub {
  display: block;
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: .25rem;
}

.nav { display: none; }

.header__cta { display: none; }

/* ── Hero ───────────────────────────────────────────────────────────────── */
/* Aufgabe 13b (uebernommen vom Muster Alte Linde, Aufgabe 12b): Kopf und
   Film sind jetzt EIN Abschnitt. Vorher stand hier ein eigenes
   Hintergrundfoto (`img/hero.jpg`, per CSS-Hintergrund samt eigenem
   Verlauf); jetzt traegt das Standbild des Films (`.film__standbild`,
   dieselbe Aufnahme wie das Filmende) denselben Platz — ein echtes <img>
   statt eines CSS-Hintergrunds, siehe Kommentar an ".hero--film" weiter
   unten und im Markup. `img/hero.jpg` wird dadurch nicht mehr geladen; der
   Preload dafuer im <head> ist entfernt (A5). Keine Einblendung am
   LCP-Element (V7 und Qualitaetsuntergrenze): Der Entwurf blendete den
   Textblock mit einer `fadeUp`-Keyframe ein. */

.hero {
  position: relative;
  color: #fff;
}

/* position: relative + z-index: 1 (wortgleich aus dem Muster Alte Linde
   uebernommen): ohne eigenen Stapel-Level wuerde .hero__inner als nicht
   positioniertes Element IMMER unter .film__bild/.film__canvas (position:
   absolute, z-index: auto) gemalt -- unabhaengig von der Dokumentreihenfolge,
   das ist die CSS-Stapelregel fuer positionierte gegen unpositionierte
   Geschwister. Die Ueberschrift bliebe dann hinter dem scrubbenden Filmbild
   verschwunden. z-index: 1 liegt unter dem Lader (z-index: 5, siehe LADER
   weiter unten), damit der Ladeschleier die Ueberschrift waehrend des Ladens
   weiterhin bedeckt. */
.hero__inner { position: relative; z-index: 1; padding-block: clamp(3.5rem, 13vw, 7rem); }

.hero h1 {
  color: #fff;
  margin: 0 0 1.1rem;
  max-width: 20ch;
}

.hero__sub {
  font-size: clamp(1rem, 2.4vw, 1.18rem);
  line-height: 1.65;
  color: var(--on-dark);
  max-width: 54ch;
  margin: 0 0 2.1rem;
}

.hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; }

/* ── Merkmalsband unter dem Hero ────────────────────────────────────────── */

.facts {
  background: var(--wash);
  border-bottom: 1px solid var(--line);
  padding-block: clamp(1.4rem, 5vw, 1.8rem);
}

.facts__grid { display: grid; grid-template-columns: 1fr; gap: 1rem 1.6rem; }

.facts__grid p {
  display: flex;
  align-items: center;
  gap: .85rem;
  margin: 0;
  font-size: .95rem;
}

.facts .icon { width: 1.55rem; height: 1.55rem; color: var(--teal); }

/* ── Abschnitte ─────────────────────────────────────────────────────────── */

.section { padding-block: clamp(3rem, 9vw, 5.5rem); }
.section--wash { background: var(--wash); }
.section--line { border-top: 1px solid var(--line); }
.section--line-b { border-bottom: 1px solid var(--line); }

.section__head { margin-bottom: 2.4rem; }
.section__head h2 { margin-bottom: 0; }
.section__head p { font-size: 1.02rem; margin: 0; }
.section__head--center { text-align: center; max-width: 42rem; margin-inline: auto; }
.section__head--center .rule { margin-block: 1.1rem 1.3rem; }

/* ── Leistungen mit Filter: Radios plus :checked, kein Javascript ───────── */

.svc { position: relative; }

/* Die Radios bleiben bedienbar und mit der Tastatur erreichbar; sie sind nur
   optisch entfernt. Sichtbar ist das <label> daneben. */
.svc__in {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  margin: 0;
  pointer-events: none;
}

.svc__tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
  margin-bottom: 2rem;
}

.svc__tab {
  display: inline-block;
  padding: .55rem 1.25rem;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--muted);
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 170ms ease, color 170ms ease, border-color 170ms ease;
}

.svc__tab:hover { border-color: var(--teal); color: var(--teal); }

.svc__grid { display: grid; grid-template-columns: 1fr; gap: 1.4rem; }

.card {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.7rem 1.5rem 1.6rem;
  transition: box-shadow 220ms ease, border-color 170ms ease;
}

.card:hover { border-color: var(--line-2); box-shadow: 0 14px 34px rgb(31 45 44 / .1); }

/* `p.card__icon` und nicht `.card__icon`: die Symbolzeile IST ein <p>, und
   `.card p` weiter unten waere sonst spezifischer und wuerde Farbe und
   Abstand hier ueberschreiben. */
.card p.card__icon { margin: 0 0 1.1rem; color: var(--teal); }
.card__icon .icon { width: 2rem; height: 2rem; }

.card h3 { margin-bottom: .6rem; }
.card p { font-size: .95rem; margin: 0 0 1.1rem; }

/* Der Entwurf setzte diese Zeile in #8ba09e auf Weiss — 2,76:1. Und er wollte
   sie in Gewicht 500, das Open Sans nicht als benannte Instanz fuehrt:
   kleiner und gesperrt statt duenner. */
.card__meta {
  display: block;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.1rem;
}

.card__more {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.card__more .icon { width: 1rem; height: 1rem; }

/* Genau vier Zeilen, eine je Filterknopf. Das angehakte Radio faerbt sein
   Label ein; "Alle" braucht keine Ausblende-Regel. */
#f-alle:checked      ~ .svc__tabs [for="f-alle"],
#f-therapie:checked  ~ .svc__tabs [for="f-therapie"],
#f-anwendung:checked ~ .svc__tabs [for="f-anwendung"],
#f-training:checked  ~ .svc__tabs [for="f-training"] {
  background: var(--teal);
  border-color: var(--teal);
  color: #fff;
}

#f-therapie:checked  ~ .svc__grid .card:not(.is-therapie),
#f-anwendung:checked ~ .svc__grid .card:not(.is-anwendung),
#f-training:checked  ~ .svc__grid .card:not(.is-training) { display: none; }

/* Der Fokusring gehoert sichtbar an das Label, nicht an das versteckte
   Radio — sonst sieht man beim Tabben nichts. */
#f-alle:focus-visible      ~ .svc__tabs [for="f-alle"],
#f-therapie:focus-visible  ~ .svc__tabs [for="f-therapie"],
#f-anwendung:focus-visible ~ .svc__tabs [for="f-anwendung"],
#f-training:focus-visible  ~ .svc__tabs [for="f-training"] {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--focus-halo);
}

.svc__note { margin: 2rem 0 0; font-size: .88rem; color: var(--muted); text-align: center; }

/* ── Die Praxis ─────────────────────────────────────────────────────────── */

.praxis { display: grid; gap: 2.4rem; align-items: center; }

.praxis__text p { font-size: 1rem; }

/* Feste Zahlen im Markup — der Entwurf zeigte sie ebenfalls als Text, und
   hochlaufen duerfen sie in der Basis-Stufe ohnehin nicht (V7). */
.praxis__stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.4rem;
  border-top: 1px solid var(--line-2);
  margin-top: 1.8rem;
  padding-top: 1.6rem;
}

/* Jede Zahl steht in einem <p>; ohne diese Zeile haengt unter der letzten
   Zeile der Grundabstand von `p` im Raster. */
.praxis__stats .stat { margin: 0; }

.stat__num {
  display: block;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 2rem;
  line-height: 1;
  color: var(--teal);
  margin: 0 0 .3rem;
}

.stat__lbl { display: block; font-size: .88rem; color: var(--muted); }

/* Die Collage aus dem Entwurf: ein breites Bild oben, zwei schmale darunter.
   Der Entwurf setzt dafuer feste Zeilenhoehen von 190 px; hier tragen die
   Platzhalter beziehungsweise spaeter die Bilder ihr Seitenverhaeltnis
   selbst, damit auf 360 px nichts beschnitten wird. */
.praxis__media { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
.praxis__media > :first-child { grid-column: 1 / -1; }

/* ── Team ───────────────────────────────────────────────────────────────── */

.team { display: grid; grid-template-columns: 1fr; gap: 2rem; }

.team__item { text-align: center; }
.team__item h3 { margin: 1.1rem 0 .3rem; font-size: 1.2rem; }

.team__role {
  display: block;
  font-size: .86rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--teal);
  margin-bottom: .7rem;
}

.team__item p { font-size: .92rem; margin: 0; color: var(--muted); }

/* ── Handlungsband ──────────────────────────────────────────────────────── */

.cta {
  background: var(--teal);
  color: var(--on-teal);
  padding-block: clamp(2.6rem, 8vw, 4.2rem);
}

.cta__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1.6rem;
  align-items: center;
  justify-content: space-between;
}

.cta h2 { color: #fff; font-size: clamp(1.5rem, 4.4vw, 2rem); margin: 0 0 .6rem; }
.cta p { font-size: 1.05rem; margin: 0; max-width: 46ch; }
.cta__text { max-width: 40rem; }

/* ── Fragen: <details>/<summary> statt eines Aufklapp-Skripts ───────────── */
/* Bedienbar mit der Tastatur, auffindbar ueber die Suche im Browser, und es
   kostet keine einzige Zeile Javascript (V8). */

.faq {
  max-width: 46rem;
  margin-inline: auto;
  border-top: 1px solid var(--line);
}

.faq details { border-bottom: 1px solid var(--line); }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 1.08rem;
  color: var(--dark);
}

.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--teal); }
.faq summary .icon { color: var(--teal); transition: transform 200ms ease; }
.faq details[open] summary .icon { transform: rotate(180deg); }

.faq__body { padding: 0 0 1.2rem; font-size: .95rem; max-width: 62ch; }
.faq__body p { margin: 0 0 .7rem; }
.faq__body p:last-child { margin: 0; }

/* ── Kontakt ────────────────────────────────────────────────────────────── */

.contact { display: grid; gap: 2.4rem; }

.contact__lead { font-size: 1rem; margin-bottom: 1.8rem; }

.infobox {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem 1.4rem;
}

.infobox h3 { font-size: 1.2rem; margin-bottom: 1.1rem; }
.infobox h3 + .hours { margin-top: 0; }
.infobox address { font-style: normal; }

.hours { display: grid; gap: .5rem; font-size: .95rem; }

.hours__row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  padding-bottom: .5rem;
  border-bottom: 1px dotted var(--line-2);
}

.hours__row:last-child { border-bottom: 0; padding-bottom: 0; }
.hours__row strong { color: var(--dark); font-weight: 700; }

/* Im Entwurf #8ba09e auf Weiss — 2,76:1. */
.hours__row--off span:last-child { color: var(--muted); }

.infobox__note { font-size: .84rem; color: var(--muted); margin: 1.2rem 0 0; }

.infobox__split { border-top: 1px solid var(--line-2); margin-top: 1.5rem; padding-top: 1.4rem; }

.contactlist { display: grid; gap: .8rem; font-size: .95rem; margin-top: 1rem; }
.contactlist > div { display: flex; align-items: flex-start; gap: .8rem; }
.contactlist .icon { color: var(--teal); margin-top: .25rem; }

/* ── Formular ───────────────────────────────────────────────────────────── */

.formbox {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.7rem 1.4rem 1.9rem;
}

.form { display: grid; gap: 1.05rem; }
.form__pair { display: grid; grid-template-columns: 1fr; gap: 1.05rem; }
.field { margin: 0; }

.field label {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dark);
  margin-bottom: .45rem;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: .8rem .85rem;
  border: 1px solid var(--line-2);
  border-radius: 2px;
  background: var(--field);
  color: var(--ink);
  font-family: inherit;
  font-size: .95rem;
  font-weight: 400;
  line-height: 1.5;
}

.field textarea { resize: vertical; }
.field input::placeholder,
.field textarea::placeholder { color: var(--muted); opacity: 1; }

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { border-color: var(--teal); }

.consent {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  margin: 0;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--muted);
}

.consent input { margin-top: .25rem; flex: none; width: 1.1rem; height: 1.1rem; accent-color: var(--teal); }
.consent label { font-size: inherit; }

.form__note { margin: 0; font-size: .8rem; color: var(--muted); }

/* ── Gezeichnete Umgebungskarte ─────────────────────────────────────────── */
/* Statt eines Kartendienstes und statt der Attrappe, die der Entwurf hinter
   einem Knopf "Karte laden" versteckte: keine Kacheln, keine Koordinaten,
   kein Dritter, der die Adresse des Besuchers sieht (V3, V12). Anschrift und
   Anfahrt stehen als Text daneben — die Zeichnung ist keine
   Informationsquelle. Muster: `_shared/arztpraxis/icons.svg.html`, Nr. 11. */

.mapbox { margin-top: 1.5rem; }

/* Die Zeichnung misst 320 x 220 Einheiten. Ohne Deckel skaliert sie auf die
   volle Spaltenbreite, und die Beschriftungen laufen bei 1280 px auf rund
   40 px Schriftgroesse auf — die Karte sieht dann aus wie ein Plakat. */
.map {
  display: block;
  width: 100%;
  max-width: 620px;
  margin-inline: auto;
  height: auto;
  aspect-ratio: 320 / 220;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: #eef2f2;
  --map-bg: #eef2f2;
  --map-block: #e0e7e6;
  --map-road: #ffffff;
  --map-water: #c8e0e5;
  --map-ink: #4d5a59;
  --map-frame: #d5dedd;
  /* Die Praxisflaeche traegt eine Beschriftung, deshalb steht darauf das
     dunklere --teal-2: auf 12 % Petrol ueber --map-bg kaeme --teal nur auf
     4,24:1. Die Nadel ist gold und traegt keinen Text. */
  --map-accent: #14746c;
  --map-accent-ink: #12564f;
  --map-pin: #e2a33c;
}

.map__note {
  font-size: .8rem;
  color: var(--muted);
  margin: .8rem auto 0;
  max-width: 620px;
}

/* ── Fotos in Collage und Team ──────────────────────────────────────────── */
/* Hier steht bewusst wenig: die Hoehe kommt aus dem Seitenverhaeltnis des
   Bildes (`img { height: auto }` weiter oben) und nicht aus einer festen
   Zeilenhoehe. Der Entwurf setzte fuer die Collage 190 px je Zeile; auf
   360 px waere davon jedes Bild beschnitten worden. Kein `object-fit`, kein
   Zuschnitt im Browser — die Bilder liegen schon im richtigen Verhaeltnis
   auf der Platte: 16:9 fuer das breite, 4:3 fuer die zwei Kacheln, 3:4 fuer
   die Portraits. */

.praxis__media img,
.team__item img { width: 100%; border-radius: var(--radius); }

/* ── Fuss ───────────────────────────────────────────────────────────────── */

.footer {
  background: var(--dark);
  color: var(--on-dark-soft);
  font-size: .9rem;
  line-height: 1.75;
}

.footer__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  padding-block: clamp(2.6rem, 8vw, 3.75rem);
}

.footer h2 {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: #fff;
  margin: 0 0 .9rem;
}

.footer__name {
  display: block;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 1.15rem;
  color: #fff;
  margin-bottom: .9rem;
}

.footer p { margin: 0 0 .8rem; }
.footer p:last-child { margin-bottom: 0; }
.footer a { color: var(--on-dark); }
.footer a:hover { color: var(--gold-lt); }

.footer__list { list-style: none; padding: 0; margin: 0; display: grid; gap: .5rem; }

.footer__legal { border-top: 1px solid rgb(255 255 255 / .12); }

.footer__legalinner {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  padding-block: 1.3rem 1.6rem;
  font-size: .82rem;
}

.footer__legalinner p { margin: 0; }
.footer__links { display: flex; flex-wrap: wrap; gap: .8rem 1.4rem; }

/* ── Handy-Leiste am unteren Bildrand ───────────────────────────────────── */
/* Neu gegenueber dem Entwurf: der hat auf dem Handy weder Menue noch
   Anrufknopf. */

.quickbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 80;
  display: grid;
  grid-template-columns: 1fr 1fr;
  height: var(--quickbar);
  background: var(--teal);
  border-top: 1px solid rgb(255 255 255 / .14);
}

.quickbar a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  color: #fff;
  font-size: .88rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.quickbar a:hover { text-decoration: none; background: var(--teal-dk); }
.quickbar a + a { background: var(--gold); color: var(--dark); }
.quickbar a + a:hover { background: var(--dark); color: #fff; }

/* Zurueck nach oben — erst ab Rechnerbreite, sonst kollidiert er mit der
   Leiste am unteren Bildrand. Im Entwurf haengt dieser Knopf an einem
   Scroll-Listener; hier ist es ein gewoehnlicher Verweis (V7). */
.totop { display: none; }

/* ══ Ab 700px ════════════════════════════════════════════════════════════ */

@media (min-width: 700px) {
  .topbar__hide { display: inline-flex; }

  /* minmax(0, 1fr) statt 1fr: sonst bekommt die Spalte mit der laengsten
     Zeile mehr Platz als die anderen, und die Merkmale stehen sichtbar
     ungleich nebeneinander. */
  .facts__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .svc__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .praxis__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .team { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.6rem; }

  .form__pair { grid-template-columns: 1fr 1fr; }

  .formbox { padding: 2.1rem 1.9rem 2.3rem; }
  .infobox { padding: 1.9rem 1.7rem; }
  .card { padding: 2.2rem 2rem 2rem; }

  .footer__grid { grid-template-columns: 1fr 1fr; gap: 2.4rem; }
  .footer__legalinner { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* ══ Ab 1000px ═══════════════════════════════════════════════════════════ */

@media (min-width: 1000px) {
  html { scroll-padding-top: calc(var(--notice) + 84px + 1rem); }

  .header {
    position: sticky;
    top: var(--notice);
    z-index: 60;
  }

  .header__inner { min-height: 84px; gap: 1.5rem; }

  .nav {
    display: flex;
    align-items: center;
    gap: 1.6rem;
    margin-left: auto;
    font-size: .95rem;
    font-weight: 600;
  }

  .nav a { color: var(--ink); }
  .nav a:hover { color: var(--teal); text-decoration: none; }
  .nav a.is-here { color: var(--teal); }

  .header__cta { display: inline-flex; padding: .8rem 1.4rem; font-size: .82rem; }

  .facts__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  .svc__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* Erst hier, nicht schon ab 700 px: bei halber Breite von 768 px bleiben
     der Ueberschrift rund 340 px, und "ein Trainingsbereich" bricht dann in
     zwei Zeilen um, von denen die zweite aus einem Wort besteht. */
  .praxis { grid-template-columns: 1fr 1fr; gap: 3.5rem; }

  .contact { grid-template-columns: 1fr 1fr; gap: 3.5rem; }

  .footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: 2.6rem; }

  .quickbar { display: none; }
  body { padding-bottom: 0; }

  .totop {
    display: grid;
    place-items: center;
    position: fixed;
    right: 22px;
    bottom: 24px;
    z-index: 80;
    width: 44px;
    height: 44px;
    border-radius: var(--radius);
    background: var(--dark);
    color: #fff;
    box-shadow: 0 2px 8px rgb(31 45 44 / .3);
  }

  .totop:hover { background: var(--teal); color: #fff; text-decoration: none; }
}

/* ── Bewegung aus ───────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .has-reveal [data-reveal],
  .has-reveal [data-reveal].is-in {
    opacity: 1;
    transform: none;
  }

  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ── Druck ──────────────────────────────────────────────────────────────── */

@media print {
  #ew-demo-notice, .quickbar, .totop, .header, .topbar, .hero__actions, .svc__tabs { display: none; }
  body { padding: 0; color: #000; background: #fff; }
  .hero, .cta, .footer { background: none; color: #000; }
  .hero h1, .hero__sub, .cta h2, .cta p { color: #000; }
  .footer h2, .footer__name, .footer a { color: #000; }
  /* Auf Papier gibt es keine Filterknoepfe — alle sechs Leistungen werden
     gedruckt, egal was am Bildschirm ausgewaehlt war. */
  .svc__grid .card { display: flex !important; }
  .faq details { border: 1px solid #999; }
  .faq__body { display: block !important; }
}

/* ── Rechtliches ───────────────────────────────────────────────────────────
   Sprungziel fuer Impressum, Datenschutz und AGB. Die Fusszeile und das
   Ankreuzfeld im Formular verweisen darauf; ohne dieses Ziel waeren das
   Verweise ins Leere (V17). */

.legalnote {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 1.75rem clamp(1rem, 4vw, 1.75rem) 2.5rem;
  font-size: .85rem;
  line-height: 1.7;
  color: var(--muted);
  background: var(--paper);
}

.legalnote h2 {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .02em;
  margin: 0 0 .35rem;
  color: var(--dark);
}

.legalnote p { margin: 0; max-width: 62ch; }

/* ═══════════════════════════════════════════════════════ PREMIUM-TEIL ════
   Alles ab hier gibt es nur in der Premium-Fassung: der Lesebalken, der Film
   am Scrollrad, die vier Nahaufnahmen und der Schlussabschnitt.

   Jeder Block hat zwei Zustaende, und der Ausgangszustand ist immer der ohne
   Skript. Ohne js/scroll.js fehlt .has-scrollfx, ohne js/film.js fehlt
   .has-film — dann ist der Film ein gewoehnlicher Bildblock und der Balken
   gar nicht da.

   Aufgabe 13b rollt den Premium-Aufschlag aus dem Muster Alte Linde auf
   diese Vorlage aus: die drei Leitern, die drei Abschnittsformen
   (.grammar-a/b/c) und die fuenf Zuege. Ihre Bauplaetze in dieser Vorlage:
     Z1 [data-pin]    "Leistungen": Therapie / Anwendung / Training loesen
                      einander ab
     Z2 .hud          sechs Kapitel am linken Rand, siehe Abschnitt HUD
     Z3 [data-worte]  der Kernsatz in "Der Beweis" faerbt sich Wort fuer Wort
     Z4 [data-rail]   die vier Nahaufnahmen aus "Vorbereitung" fahren quer
     Z5 .lader        der echte Ladestand vor dem Film
   Tiefe ueber [data-tilt] sitzt an der Bild-Collage in "Die Praxis". Alle
   fuenf Zuege und die Rechnungen dahinter stehen unveraendert in
   js/scroll.js — nur das Markup ist je Vorlage anders zugeordnet (siehe die
   Kommentare dort und in index.html).

   BESONDERHEIT DIESER VORLAGE: Die Zaesur ("Der Beweis") ist HELL statt
   dunkel. Beim Muster und bei Fliesen Brandhoff ist Grammatik C eine dunkle
   Flaeche; bei einer Physiotherapie-Praxis mit durchgehend heller Bildwelt
   wirkt das nicht (Aufgabe 13b). Die Zaesur bleibt als Zug bestehen, ihre
   Farbe nicht — Begruendung am Abschnitt BEWEIS weiter unten. Ebenso ist der
   Zug [data-pin] hier HELL statt dunkel: dieselbe Entscheidung, und dieselbe
   Freiheit, die schon "feiern" beim Muster Alte Linde zeigt (section--wash
   statt is-dark).
   ====================================================================== */

:root {
  --fx-dur: 400ms;              /* Eintrittsdauer je Element */
  --fx-step: 50ms;              /* Staffelschritt, hoechstens 4 Stufen */
  --fx-ease: cubic-bezier(.22, .61, .36, 1);

  /* ── Die drei Leitern ────────────────────────────────────────────────
     Wortgleich aus dem Muster Alte Linde uebernommen (docs/regeln/
     premium-vorlagen.md, Aufgabe 13, Schritt 2): Sie tragen keine
     Markenfarbe, sondern Mass und Rhythmus, und sind deshalb in allen
     Premium-Fassungen gleich. Kopiert, nicht verlinkt (V2). */
  --step--1: clamp(0.83rem, 0.81rem + 0.12vw, 0.90rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.22vw, 1.13rem);
  --step-1:  clamp(1.20rem, 1.12rem + 0.36vw, 1.41rem);
  --step-2:  clamp(1.44rem, 1.32rem + 0.55vw, 1.76rem);
  --step-3:  clamp(1.73rem, 1.54rem + 0.82vw, 2.20rem);
  --step-4:  clamp(2.07rem, 1.81rem + 1.17vw, 2.75rem);
  --step-5:  clamp(2.49rem, 2.12rem + 1.64vw, 3.43rem);
  --step-6:  clamp(2.99rem, 2.48rem + 2.27vw, 4.29rem);

  --space-3xs: clamp(0.25rem, 0.23rem + 0.11vw, 0.31rem);
  --space-2xs: clamp(0.50rem, 0.48rem + 0.11vw, 0.56rem);
  --space-xs:  clamp(0.75rem, 0.70rem + 0.22vw, 0.88rem);
  --space-s:   clamp(1.00rem, 0.95rem + 0.22vw, 1.13rem);
  --space-m:   clamp(1.50rem, 1.43rem + 0.33vw, 1.69rem);
  --space-l:   clamp(2.00rem, 1.90rem + 0.43vw, 2.25rem);
  --space-xl:  clamp(3.00rem, 2.85rem + 0.65vw, 3.38rem);
  --space-2xl: clamp(4.00rem, 3.80rem + 0.87vw, 4.50rem);
  --space-3xl: clamp(6.00rem, 5.41rem + 2.61vw, 7.50rem);

  /* Zeilenlaenge. Fliesstext lief bisher bis an die Spaltenbreite. */
  --measure: 66ch;

  /* Der Haken, an dem src/lib/__tests__/premium-aufschlag.test.ts erkennt,
     dass diese Fassung den Aufschlag traegt. Wird zuletzt gesetzt, erst
     wenn alle fuenf Zuege stehen (Aufgabe 13b, Schritt 5) — vorher wuerden
     alle Pruefungen dieser Datei sofort greifen, bevor das Markup fertig
     ist. */
  --aufschlag: 1;
}

/* ── Ebenen, die mitziehen ───────────────────────────────────────────────
   js/scroll.js setzt --py auf jedem [data-parallax]. Der Weg ist die Haelfte
   des Wertes im Attribut, weil die Ebene um ihre Mitte schwingt.

   Nachgerechnet, damit es bei der naechsten Aenderung nicht kippt: "Der
   Beweis" braucht keine Vergroesserung, seine Ebene ragt oben und unten je
   64 px ueber den Abschnitt hinaus; ihr Weg ist 72 px, also 36 px je Seite —
   deutlich weniger als der Ueberhang. */
.has-scrollfx [data-parallax] .beweis__media {
  transform: translate3d(0, var(--py, 0px), 0);
}

/* ── Lesefortschritt ─────────────────────────────────────────────────────
   Sitzt direkt unter der Demo-Hinweisleiste. Ohne Skript gibt es ihn nicht:
   ein Balken, der bei 0 Prozent stehen bliebe, waere genau das Element, das
   so tut, als taete es etwas.                                             */

.progress { display: none; }

.has-scrollfx .progress {
  display: block;
  position: fixed;
  top: var(--notice);
  left: 0;
  right: 0;
  z-index: 2147482999;   /* eine Stufe unter der Hinweisleiste */
  height: 3px;
  background: rgb(31 45 44 / .16);
  pointer-events: none;
}

.progress__bar {
  display: block;
  width: 0;
  height: 100%;
  background: var(--teal);
}

/* ── Geloester Kopf ──────────────────────────────────────────────────────
   Nur ab 1000 px, denn erst dort ist der Kopf ueberhaupt klebend.         */

@media (min-width: 1000px) {
  .has-scrollfx .header {
    transition: box-shadow 220ms ease, background-color 220ms ease;
  }

  .has-scrollfx .header.is-stuck {
    box-shadow: 0 8px 24px rgb(31 45 44 / .14);
  }
}

/* ============================================================== FILM ====
   Der Raum wird hell am Scrollrad. Aufbau in js/film.js, Markup in
   index.html.

   Aufgabe 13b (uebernommen vom Muster Alte Linde, Aufgabe 12b): Kopf und
   Film sind jetzt EIN Abschnitt (".hero--film" auf derselben <section> wie
   ".hero", statt einer eigenen ".film"-Sektion weiter unten auf der Seite).
   Alle ".film__…"-Klassen heissen unveraendert; nur die Huelle selbst,
   vorher ".film", heisst jetzt ".hero--film".

   ZWEI ZUSTAENDE, und der Ausgangszustand ist der ohne Skript:

   OHNE .has-film   Ein gewoehnlicher Bildblock. Das Standbild (der helle
                    Raum) steht oben, darunter die Ueberschrift mit Untertext
                    und Knoepfen (.hero__inner), darunter die drei Saetze als
                    Liste. Alles sichtbar, nichts auf opacity 0, keine Hoehe,
                    die von Javascript abhaengt.

   MIT .has-film    Der Abschnitt wird hoch (vier Bildschirme), die Buehne
                    klebt oben fest, die Leinwand liegt ueber dem Standbild,
                    die Ueberschrift schwebt mittig darueber (.hero__inner,
                    per flex zentriert) und die drei Saetze liegen
                    uebereinander im unteren Bereich.

   DIESER FILM IST DER HELLSTE DER DREI. Neu erzeugt nach dem Rezept aus
   PV11 (Aufgabe 13b): 97 Einzelbilder, 1280 x 720, CRF 14, zusammen
   2,18 MB. Gemessen ueber alle 97 Bilder, im unteren 42 Prozent, auf
   64 x 14 weichgezeichnet, ist der hellste Fleck 235 von 255 hell
   (Bild 84 von 97). Weisse Schrift darauf ohne Verlauf: rund 1,1:1 — der
   Verlauf ist also Pflicht, nicht Geschmack.

   Gerechnet gegen diesen hellsten Fleck (rgb(239, 236, 230)), Verlaufsfarbe
   --dark:
     Satz, unten (96 Prozent Deckkraft)        weiss 12,81:1
     Zeitangabe (94 Prozent)                   --gold-lt 6,70:1
     Oberkante der Ueberschrift (78 Prozent)   weiss  7,48:1

   Der Verlauf liegt nur dort, wo Text steht. Ein Schleier ueber dem ganzen
   Bild wuerde das Aufklaren mit abdunkeln, und das traegt den Abschnitt.

   NACHTRAG (03.09.2026, Rohpixel-Nachmessung): Alle 97 Bilder plus Standbild
   roh auf rgb24 dekodiert und die unteren 42 % ungeglaettet durchsucht:
   echtes Weiss rgb(255, 255, 255) kommt vor (53 der 98 Quellen, als Flaeche
   bis 91 Bildpunkte am Stueck), heller als das gemeldete rgb(239, 236, 230).
   Gegen den echten Wert:
     Satz, unten (96 Prozent)                  weiss     12,67:1 (war 12,81)
     Zeitangabe (94 Prozent)                   --gold-lt   6,59:1 (war 6,70)
     Oberkante der Ueberschrift (78 Prozent)   weiss      7,01:1 (war 7,48)
   Alle drei bleiben deutlich ueber 5,0:1 — keine Aenderung noetig.

   DIE KOPFZEILE (Aufgabe 13b): Beim Zusammenlegen von Kopf und Film steht
   jetzt zusaetzlich eine Ueberschrift mit Untertext ueber den OBEREN
   60 Prozent des Bildes (.hero__inner, per flex vertikal zentriert). Eigene
   Rechnung, eigener Schleier (.film__bild::after) — die Kopfzeile steht ueber
   wechselnden Filmbildern, nicht ueber einem festen Foto, und braucht daher
   einen gegen ALLE 97 Bilder UND das Standbild gerechneten Schleier statt des
   unteren Verlaufs, der nur fuer die untere Bildhaelfte gilt. Gemessen: die
   mittleren 60 Prozent der Bildhoehe (20–80 %), 97. Perzentil der Helligkeit
   je Bild auf 64 x 22 weichgezeichnet (ein einzelner Lichtpunkt ist keine
   echte helle Flaeche), das hellste Bild darunter ist das Standbild selbst
   (der fertig helle Raum), rgb(227, 225, 221).

   NACHTRAG (03.09.2026): Bei 72 Prozent Deckung reichte die Reserve gegen
   den absoluten Ausreisser-Bildpunkt (rgb(247, 246, 242)) fuer --on-dark nur
   bis 4,73:1 — 5 Prozent ueber der Pflichtgrenze von 4,5:1, aufgebraucht von
   der naechsten Neukodierung des Films. Gesucht: die kleinste Deckung, bei
   der --on-dark gegen genau diesen Ausreisser mindestens 5,0:1 haelt.
   Durchgerechnet in Ein-Prozent-Schritten (Alpha-Mischung aus Bildpunkt und
   rgb(31, 45, 44), WCAG-Kontrast auf --on-dark = #dbe7e5): bei 73 Prozent
   4,88:1 (noch zu wenig), bei 74 Prozent 5,03:1 (erste Stufe ueber der
   Grenze). Deckung deshalb auf 74 Prozent angehoben.

   NACHTRAG 2 (03.09.2026, ROHPIXEL statt Perzentil): Die obige Rechnung ging
   von einem "absoluten Ausreisser-Bildpunkt" rgb(247, 246, 242) als hellstem
   Fall aus. Eine Nachmessung GEGEN DIE ROHPIXEL — jedes der 97 AVIF-Bilder
   per ffmpeg auf rgb24 dekodiert, keine Weichzeichnung, kein Perzentil, dazu
   das Standbild film-ende.jpg — widerlegt das: In der gemessenen Zone
   (20-80 % der Bildhoehe) tragen 41 der 98 Quellen mindestens einen
   Bildpunkt mit exakt rgb(255, 255, 255). Kein Streupixel: Bei einer
   Schwelle von "alle drei Kanaele >= 250" bildet dieselbe Stelle (das
   Fenster, Bild 3 aus dem Kopfzeile-Kommentar oben) eine zusammenhaengende
   Flaeche von bis zu 221 Bildpunkten am Stueck (Bild f_0096, rund 0,04 % der
   gemessenen Zone) — real, nicht wegweichgezeichnet. Der echte hellste Wert
   ist also nicht rgb(247, 246, 242), sondern rgb(255, 255, 255).

   Gegen rgb(255, 255, 255) hielt der bisherige Schleier von .74 nur noch
   4,85:1 — ueber der Pflichtgrenze von 4,5:1, aber unter der bevorzugten
   5,0:1. Dieselbe Ein-Prozent-Suche wie oben, diesmal gegen den echten Wert:
   bei 74 Prozent 4,85:1 (noch zu wenig), bei 75 Prozent 5,01:1 (erste Stufe
   ueber der Grenze). Deckung deshalb von 74 auf 75 Prozent angehoben.

   Mit einem Schleier von rgb(31 45 44 / .75) — derselbe Ton wie beim
   unteren Verlauf, hier als durchgehende Bahn statt als Verlauf — ergibt
   sich gegen den echten hellsten Bildpunkt rgb(255, 255, 255):
     Ueberschrift (Grosstext, ab 24px, Grenze 3:1)       weiss     6,35:1
     Untertext (Fliesstext, Grenze 4,5:1)                --on-dark 5,01:1
   Beide ueber ihrer Grenze. --gold-lt traegt in der Kopfzeile keinen Text
   und muss hier deshalb nicht gerechnet werden.

   ZU DUNKEL? Ein Prozentpunkt mehr Deckung (74 -> 75) dunkelt das Bild kaum
   sichtbar ab: am hellsten TYPISCHEN Punkt (rgb(227, 225, 221), das
   Standbild — nicht der seltene Weiss-Ausreisser) sinkt die relative
   Luminanz der sichtbaren Flaeche um rund 4 Prozent (0,1015 -> 0,0973). Der
   Schleier bleibt eine durchsichtige Bahn ueber den oberen 60 Prozent des
   Bildes, kein deckendes Feld — er traegt weiterhin nur den Text, nicht das
   Bild.

   METHODE (gilt fuer alle drei Vorlagen, siehe premium-vorlagen.md): Der
   Fehler beim ersten Anlauf war, mit einem WEICHGEZEICHNETEN Perzentil zu
   rechnen statt mit den Rohpixeln. Ein Perzentil glaettet genau die kleinen,
   hellen Flaechen weg, die tatsaechlich Kontrast kosten — ein Fenster ist
   keine Kamera-Rauschspitze, sondern ein wiederkehrendes Motiv. Deshalb
   jetzt: volle Aufloesung, keine Weichzeichnung, Schwelle auf echte Flaeche
   (zusammenhaengende Bildpunkte) statt auf Einzeltreffer geprueft.
   ====================================================================== */

.hero--film {
  position: relative;
  background: var(--dark);
  color: #fff;
}

.film__bild {
  position: relative;
  overflow: hidden;
  background: var(--dark);
}

/* Der Kontrast-Schleier fuer die Kopfzeile: Rechnung im Kopf dieses
   Abschnitts. */
.has-film .film__bild::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    transparent 0%,
    rgb(31 45 44 / .75) 20%,
    rgb(31 45 44 / .75) 80%,
    transparent 100%);
  pointer-events: none;
}

.film__standbild {
  display: block;
  width: 100%;
  height: auto;
}

/* Ohne Skript gibt es keine Leinwand zu sehen. Sie steht im Markup, damit das
   Skript sie nicht bauen muss, aber sie ist leer und darf nichts verdecken. */
.film__canvas { display: none; }

.film__texte { padding: var(--space-xl) 0 var(--space-2xl); }

.film__ueber { color: var(--gold-lt); }

.film__h {
  font-family: var(--font-title);
  font-weight: 700;
  font-size: clamp(1.9rem, 5.2vw, 3.1rem);
  line-height: 1.12;
  margin: .2em 0 .9em;
  color: #fff;
}

.film__spur {
  display: block;
  max-width: 34em;
  margin: 0 0 1.4em;
}

.film__zeit {
  display: block;
  font-size: var(--step-0);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold-lt);
  margin-bottom: .45em;
}

.film__satz {
  display: block;
  font-size: clamp(1.02rem, 2.4vw, 1.22rem);
  line-height: 1.55;
  color: var(--on-dark);
}

/* ---------------------------------------------------- mit laufendem Film -- */

.has-film .hero--film {
  /* Vier Bildschirme Weg fuer die Bildfolge. Weniger, und zwei Bilder liegen
     auf demselben Scrollpunkt; mehr, und der Besucher scrollt an einem Bild,
     das sich nicht bewegt — beides liest sich als Fehler. */
  height: 400vh;
}

.has-film .film__buehne {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;      /* auf dem Telefon die Hoehe OHNE die Adressleiste */
  overflow: hidden;
  /* .hero__inner ist jetzt ein Kind dieser Buehne statt ein Geschwister von
     einem eigenen Hintergrundfoto und muss deshalb selbst zentriert werden.
     flex-direction: column, DAMIT diese Regel auch im
     Reduzierte-Bewegung-Sicherheitsnetz weiter unten nicht schadet: dort
     werden .film__bild und .film__texte wieder zu normalen Fluss-Kindern
     (position: relative/static), und ohne column staenden Bild, Ueberschrift
     und Zeiten dann nebeneinander statt untereinander. */
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.has-film .film__bild {
  position: absolute;
  inset: 0;
}

/* Das Standbild bleibt liegen und traegt die Leinwand, bis das erste Bild
   gezeichnet ist. Ein Blitz von leerem Dunkel waere teurer als ein Standbild,
   das eine Zehntelsekunde zu lange steht. */
.has-film .film__standbild {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 45%;
}

.has-film .film__canvas {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* .hero__inner steckt jetzt in einer FESTEN Hoehe (100svh, .film__buehne
   oben) statt in einer wachsenden. Der alte, breitenbezogene Innenabstand
   konnte auf einem kurzen Querformat-Bildschirm mehr Platz verlangen, als
   die Buehne hoch ist — overflow: hidden haette dann oben und unten
   abgeschnitten. Hoehenbezogen (svh) statt breitenbezogen und kleiner: Bei
   knapper Bildschirmhoehe schrumpft der Abstand mit ihr. Nur im
   has-film-Zustand — die reduzierte-Bewegung-Ausnahme direkt darunter gibt
   den grosszuegigen Abstand zurueck, weil dort keine feste Hoehe mehr gilt. */
.has-film .hero--film .hero__inner {
  padding-block: clamp(1.5rem, 6svh, 3rem);
}

@media (prefers-reduced-motion: reduce) {
  .has-film .hero--film .hero__inner {
    padding-block: clamp(3.5rem, 13vw, 7rem);
  }
}

.has-film .film__texte {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 0 0 clamp(1.6rem, 5vh, 3.2rem);
  background: linear-gradient(to top,
    rgb(31 45 44 / .96) 0%,
    rgb(31 45 44 / .94) 46%,
    rgb(31 45 44 / .78) 78%,
    rgb(31 45 44 / 0) 100%);
  padding-top: clamp(4rem, 14vh, 9rem);
  pointer-events: none;
}

.has-film .film__h {
  font-size: clamp(1.7rem, 4.4vw, 2.8rem);
  margin: .15em 0 .7em;
}

/* Uebereinander gelegt: Der Kasten ist so hoch wie die laengste der drei
   Zeilen, damit die Ueberschrift darueber beim Wechsel nicht springt. */
.has-film .film__spuren {
  position: relative;
  min-height: 7.2em;
}

.has-film .film__spur {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  margin: 0;
  opacity: 0;
  transition: opacity 220ms linear, transform 220ms var(--fx-ease);
  will-change: opacity, transform;
}

@media (min-width: 900px) {
  .has-film .film__spuren { min-height: 5.4em; }
}

/* Sicherheitsnetz: Sollte .has-film aus irgendeinem Grund gesetzt sein,
   waehrend der Besucher reduzierte Bewegung verlangt, faellt alles auf den
   ruhigen Zustand zurueck. */
@media (prefers-reduced-motion: reduce) {
  .has-film .hero--film { height: auto; }
  .has-film .film__buehne { position: static; height: auto; }
  .has-film .film__bild { position: relative; }
  /* Der Kopfzeile-Schleier (.film__bild::after, oben) hat hier nichts mehr
     zu verdunkeln: .hero__inner steht nicht mehr ueberlagert ueber dem
     Standbild, sondern normal darunter im Textfluss. */
  .has-film .film__bild::after { display: none; }
  .has-film .film__standbild { height: auto; }
  .has-film .film__canvas { display: none; }
  .has-film .film__texte { position: static; background: none; padding-top: clamp(2rem, 6vw, 3.5rem); }
  .has-film .film__spuren { min-height: 0; }
  .has-film .film__spur { position: static; opacity: 1; transform: none; }
}

/* ============================================================ LADER ====
   Z5: das Ladebild vor dem Film. Die Zahl zeigt den echten Ladestand der
   ersten VORLAUF Bilder (js/film.js) -- kein Balken, der an einem Zeitgeber
   haengt statt an geladenen Bildern (V12).

   Der Schleier liegt UEBER dem Kopfbereich, nicht ANSTELLE von ihm: Kind von
   .film__buehne (index.html), Geschwister von .film__bild und .hero__inner,
   position: absolute.

   Kontrast (V9): --on-dark auf dem HELLSTEN Bereich, den irgendeines der 97
   Bilder oder das Standbild in der BILDMITTE zeigen kann -- die Zahl steht
   per place-items: center immer genau dort. Gemessen wurde die mittleren
   20 Prozent von Breite und Hoehe, ueber jedes achte Bild (repraesentative
   Stichprobe) plus Standbild und Anfangsbild. Hellster Einzelwert im
   Datensatz: rgb(185, 183, 175). Mit dem Schleier bei 72 Prozent Deckung
   ergab das 6,21:1 -- weit ueber 4,5:1.

   NACHTRAG (03.09.2026, Rohpixel-Nachmessung, siehe Kopfzeile-Kommentar
   weiter oben): Die Stichprobe (jedes achte Bild) hat den echten hellsten
   Treffer verfehlt. Ueber ALLE 97 Bilder plus Standbild in der Bildmitte
   (mittlere 20 % von Breite und Hoehe, Rohpixel, keine Weichzeichnung) liegt
   der hellste Wert bei rgb(239, 240, 232) (Bild 3 -- dasselbe fruehe
   Tageslicht wie in der Kopfzeile). Gegen diesen Wert hielt der Schleier bei
   72 Prozent nur noch 4,87:1 -- ueber der Pflichtgrenze, aber unter der
   bevorzugten 5,0:1. Dieselbe Ein-Prozent-Suche: bei 72 Prozent 4,87:1
   (noch zu wenig), bei 73 Prozent 5,02:1 (erste Stufe ueber der Grenze).
   Deckung deshalb von 72 auf 73 Prozent angehoben -- eine kaum wahrnehmbare
   Verdunklung fuer eine Flaeche, die ohnehin nur waehrend des Ladens kurz
   sichtbar ist. */
.lader { display: none; }

.has-film .lader {
  display: grid;
  position: absolute;
  inset: 0;
  z-index: 5;
  place-items: center;
  background: rgb(31 45 44 / .73);
  color: var(--on-dark);
  font-size: var(--step-6);
  font-variant-numeric: tabular-nums;
  transition: opacity 420ms var(--fx-ease);
  /* Die Zahl ist Dekoration (aria-hidden, keine Bedienung) -- der Schleier
     hat keinen Grund, Klicks abzufangen. */
  pointer-events: none;
}

.has-film.ist-offen .lader {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .has-film .lader { display: none; }
}

/* ============================================================== PIN ====
   Z1: der Abschnitt, der stehen bleibt. Dieselbe Bauart wie der Film oben —
   ein hohes Huellelement ([data-pin]), darin eine klebende Buehne
   (.pin__buehne) — nur kuerzer, weil der Film der Hoehepunkt bleibt und den
   laengsten Weg behaelt: 200vh statt 400vh, 80vh auf dem Telefon.

   In dieser Vorlage traegt "Leistungen" den Zug: Therapie, Anwendung und
   Training loesen einander ab, statt als drei gleichzeitige Filterkacheln
   zu stehen. Die vorhandene Filterleiste (vier Radios, :checked) und das
   Leistungsraster bleiben davon UNBERUEHRT — sie stehen unveraendert
   unterhalb der klebenden Buehne und bleiben mit abgeschaltetem Javascript
   genauso bedienbar wie in der Starter-Fassung.

   Innerhalb der Buehne uebernimmt .kategorien die Rolle von .film__spuren:
   eine Flaeche mit fester Mindesthoehe, in der die drei .pin__spur-Bereiche
   uebereinander liegen (position: absolute) und nur der, dessen
   [data-von, data-bis) den aktuellen Fortschritt enthaelt, sichtbar ist
   (.is-da). js/scroll.js setzt und entfernt ausschliesslich diese eine
   Klasse; alles andere ist reines CSS.

   OHNE .has-scrollfx passiert gar nichts: [data-pin] hat seine normale
   Abschnittshoehe, .kategorien bleibt eine gewoehnliche senkrechte Liste und
   alle drei Bereiche stehen lesbar untereinander — der Zustand ohne Skript
   und bei reduzierter Bewegung. */
.has-scrollfx [data-pin] {
  height: 200vh;
  padding-block: 0;
}

.has-scrollfx [data-pin] .pin__buehne {
  position: sticky;
  top: var(--notice);
  min-height: 100svh;
  display: flex;
  align-items: center;
}

/* Feste Hoehe, damit der Wechsel der Bereiche die Buehne nicht springen
   laesst — derselbe Grund wie bei .film__spuren weiter oben. Breite: 100%,
   weil .pin__buehne ein Flex-Container ist (Grundregel oben) und .kategorien
   sein einziges Kind — ohne eigene Breite haette es keine, denn seine
   Kinder (.pin__spur) sind position: absolute und tragen nichts zur
   Breitenberechnung des Elternteils bei. */
.has-scrollfx [data-pin] .kategorien {
  position: relative;
  width: 100%;
  min-height: 7.2rem;
}

.has-scrollfx [data-pin] .pin__spur {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--fx-dur) var(--fx-ease);
}

.has-scrollfx [data-pin] .pin__spur.is-da {
  opacity: 1;
}

@media (max-width: 699px) {
  .has-scrollfx [data-pin] {
    height: 80vh;
  }

  .has-scrollfx [data-pin] .pin__buehne {
    align-items: flex-start;
    padding-top: var(--space-xl);
  }
}

/* Sicherheitsnetz: sollte [data-pin] doch einmal mitten in eine gesetzte
   .has-scrollfx-Klasse hineinlaufen, waehrend reduzierte Bewegung gilt,
   faengt dieser Block das ab.

   WICHTIG — dieselbe Falle wie bei [data-tilt]: ".has-scrollfx" muss VOR
   jedem Selektor hier stehen, nicht nur "[data-pin]"/".pin__spur" allein. */
@media (prefers-reduced-motion: reduce) {
  .has-scrollfx [data-pin] { height: auto; padding-block: var(--space-3xl); }
  .has-scrollfx [data-pin] .pin__buehne { position: static; min-height: 0; display: block; }
  .has-scrollfx [data-pin] .kategorien { position: static; min-height: 0; }
  .has-scrollfx [data-pin] .pin__spur { position: static; opacity: 1; transition: none; }
}

/* ── Leistungen: die drei Arten (Inhalt fuer [data-pin]) ─────────────────
   HELL statt dunkel (Aufgabe 13b) — anders als beim Muster (dort dunkel,
   Grund "Referenzen"): die Bildwelt dieser Praxis ist durchgehend hell,
   siehe Begruendung am Abschnitt BEWEIS weiter unten und im Markup. Ohne
   Skript ODER bei reduzierter Bewegung (Regel oben: .kategorien wird
   position: static) stehen alle drei Zeilen einfach lesbar untereinander --
   .svc-pin traegt dafuer einen Abstand nach unten zum Leistungsraster
   darunter.
   Kontrast (V9), auf --paper:
     --dark  #1f2d2c auf --paper   14,29:1  (kategorie__name)
     --muted #5d6b6a auf --paper    5,56:1  (kategorie__note)
     --teal  #14746c auf --paper    5,61:1  (kategorie__zahl) */
.svc-pin { margin-bottom: var(--space-2xl); }

.kategorien {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--line-2);
  border: 1px solid var(--line-2);
}

.kategorie {
  background: var(--paper);
  padding: 1.15rem 1.35rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.kategorie__name {
  display: block;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 1.2rem;
  color: var(--dark);
  line-height: 1.3;
}

.kategorie__note { display: block; font-size: var(--step-0); color: var(--muted); margin: .15rem 0 0; }

.kategorie__zahl {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--teal);
  white-space: nowrap;
}

/* ============================================================== HUD ====
   Z2: die Kapitelanzeige am linken Rand. Klein, am Rand, nie ueber dem
   Motiv (E7, premium-vorlagen.md).

   Auf dem Telefon ist kein Rand mehr uebrig — dort laege das HUD ueber dem
   Inhalt statt daneben. Deshalb erst ab einem feinen Zeigegeraet (kein
   Finger) und ab 1100px Breite.

   Kontrast (V9), vier Werte, auf --paper und auf --dark (der Grund des
   dunklen Kopf-und-Film-Abschnitts, der einzigen dunklen Kapitel-Sektion
   dieser Vorlage — "Der Beweis" nutzt seit Aufgabe 13b bewusst KEINEN
   dunklen Zustand mehr, siehe js/scroll.js, farbZusatz, und die Begruendung
   am Abschnitt BEWEIS weiter unten):
     Ruhe   hell:    --muted    #5d6b6a auf --paper #ffffff   5,56:1
     Aktiv  hell:    --teal     #14746c auf --paper            5,61:1
     Ruhe   dunkel:  --on-dark-soft #9fb0ae auf --dark #1f2d2c 6,32:1
     Aktiv  dunkel:  --gold-lt  #edb861 auf --dark              7,91:1
   Alle vier ueber 4,5:1. KEINE opacity auf Text in diesem Bauteil, auch nicht
   auf der Ziffer im <i> — derselbe Fallstrick wie im Muster: opacity: .45
   ergibt dort nur 1,93:1, opacity: .9 waere kaum noch "gedaempft". Der
   Unterschied kommt aus Farbe UND einem Einzug (transform: translateX, kein
   Layout-Reflow, keine opacity). */
.hud { display: none; }

@media (pointer: fine) and (min-width: 1100px) {
  .has-scrollfx .hud {
    display: grid;
    position: fixed;
    left: clamp(0.75rem, 2vw, 1.5rem);
    top: 50%;
    transform: translateY(-50%);
    z-index: 40;
    gap: var(--space-2xs);
    font-size: var(--step--1);
  }

  .hud__mark {
    display: flex;
    align-items: baseline;
    gap: var(--space-3xs);
    color: var(--muted);          /* Kontrast auf --paper: 5,56:1 */
    text-decoration: none;
    transform: translateX(0);
    transition: color var(--fx-dur) var(--fx-ease),
                transform var(--fx-dur) var(--fx-ease);
  }

  /* Kein Kursiv-Text: das <i> im Markup ist der Haken fuer die Ziffer, klein
     und tabellarisch neben dem Wort. Keine eigene Farbe/opacity: sie erbt
     von .hud__mark, siehe Kontrast-Kommentar oben. */
  .hud__mark i {
    font-style: normal;
    font-variant-numeric: tabular-nums;
  }

  .hud__mark.is-da {
    color: var(--teal);           /* Kontrast auf --paper: 5,61:1 */
    transform: translateX(var(--space-2xs));
  }

  .hud--dunkel .hud__mark {
    color: var(--on-dark-soft);   /* Kontrast auf --dark: 6,32:1 */
  }

  .hud--dunkel .hud__mark.is-da {
    color: var(--gold-lt);        /* Kontrast auf --dark: 7,91:1 */
  }
}

@media (prefers-reduced-motion: reduce) {
  .has-scrollfx .hud { display: none; }
}

/* =============================================================== Z3 ====
   Der Kernsatz im Abschnitt "Der Beweis" faerbt sich Wort fuer Wort ein,
   waehrend man am Abschnitt vorbeiscrollt (js/scroll.js, Kind "worte",
   Rechnung in worteZustand()). Die Woerter stehen als eigene <span
   class="wort"> im HTML, nicht aus einem Textknoten gebaut.

   Ausgangszustand ist die volle Textfarbe der Basis-Fassung: erst wenn
   .has-scrollfx steht, daempft das CSS die Woerter ab.

   Gedaempft heisst FARBE, nicht Deckkraft (V9). Beide Farben sind gerechnet,
   gegen den hellsten gemessenen Bildpunkt unter dem Schleier von "Der
   Beweis" (siehe Kontrastblock dort, rgb(236, 236, 235), der ungueltigste
   Fall):
     ungefuellt --muted #5d6b6a auf diesem Grund   4,70:1
     gefuellt   --dark  #1f2d2c auf diesem Grund   12,08:1
   Beide ueber der Grenze von 4,5:1 fuer Fliesstext. */
.has-scrollfx [data-worte] .wort {
  color: var(--muted);
  transition: color 320ms var(--fx-ease);
}

.has-scrollfx [data-worte] .wort.is-da {
  color: var(--dark);
}

@media (prefers-reduced-motion: reduce) {
  .has-scrollfx [data-worte] .wort { color: var(--dark); transition: none; }
}

/* =============================================================== Z4 ====
   Die vier Nahaufnahmen aus "Vorbereitung" fahren seitwaerts, waehrend die
   Seite senkrecht scrollt (js/scroll.js, Kind "rail", Rechnung in
   railZustand()). Erst ab 700px Breite, weil die Reihe darunter ohnehin
   schon voll ins Bild passt und das native Fingerscrollen aus der Grundregel
   ([data-rail] weiter unten) der einfachere Weg bleibt.

   Das Kippen (--rail) sitzt auf .rail__spur, NICHT auf [data-rail] selbst
   und traegt kein [data-reveal] -- dieselbe Falle wie bei [data-tilt]. */
@media (min-width: 700px) {
  .has-scrollfx [data-rail] {
    overflow-x: hidden;   /* jetzt faehrt das Scrollrad */
  }

  .has-scrollfx [data-rail] .rail__spur {
    transform: translate3d(var(--rail, 0px), 0, 0);
    will-change: transform;
  }
}

@media (prefers-reduced-motion: reduce) {
  .has-scrollfx [data-rail] .rail__spur { transform: none; }
}

/* ================================================== GRAMMATIK ====
   Gegen "jeder Abschnitt benutzt dieselbe Karte": drei Formen, die sich
   abwechseln. Keine der drei haengt an Javascript — sie sind reines CSS und
   stehen unveraendert da, egal ob .has-reveal/.has-scrollfx gesetzt ist.

   Reihenfolge auf dieser Seite: "Die Praxis" (grammar-b) -> "Team"
   (grammar-a) -> "Der Beweis" (grammar-c). Nie zwei gleiche hintereinander. */

/* ── Grammatik A: ungleiches Kachelraster ────────────────────────────
   Fuer drei gleich wichtige Personen ohne Leitangebot bleibt es bei drei
   gleichen Spalten statt einer grossen und mehreren kleinen — die
   Nachbesserung direkt darunter haelt die eigene Dreispalten-Regel von
   .team gegen die generische Vierspalten-Form dieser Grammatik. */
.grammar-a {
  display: grid;
  gap: var(--space-s);
  grid-template-columns: 1fr;
}

@media (min-width: 700px) {
  .grammar-a {
    grid-template-columns: repeat(4, 1fr);
  }

  .grammar-a > .is-gross {
    grid-column: span 2;
    grid-row: span 2;
  }
}

/* Nachbesserung: .team hat eine eigene Dreispalten-Regel ab 700px (weiter
   oben in dieser Datei) — die generische Vierspalten-Regel oben wuerde sie
   ueberschreiben, weil beide Selektoren dieselbe Spezifitaet haben und
   diese Regel spaeter im Text steht. .team.grammar-a (zwei Klassen) gewinnt
   unabhaengig von der Reihenfolge im Text gegen die einklassige Regel oben
   und gibt den drei Personen ihre urspruengliche Spaltenzahl zurueck. */
@media (min-width: 700px) {
  .team.grammar-a { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ── Grammatik B: freier Satz ────────────────────────────────────────
   Kein Karton, kein Rahmen, keine Schattenkante. Ueberschrift links, Text
   rechts, viel Luft. Der Abschnitt sagt durch seine Form: hier wird
   gelesen, nicht geklickt. */
.grammar-b {
  display: grid;
  gap: var(--space-l);
  padding-block: var(--space-3xl);
}

.grammar-b > * {
  background: none;
  border: 0;
  box-shadow: none;
}

.grammar-b p {
  max-width: var(--measure);
}

@media (min-width: 860px) {
  .grammar-b {
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    gap: var(--space-xl);
  }
}

/* Nachbesserung: "Die Praxis" hat ab 1000px eine eigene, gleich breite
   Zweispalten-Regel (siehe weiter oben, @media (min-width: 1000px)) — die
   generische 20rem-Spalte der Grammatik oben presste die Bild-Collage sonst
   zu schmal. .praxis.grammar-b (zwei Klassen) gewinnt unabhaengig von der
   Reihenfolge im Text gegen die einklassige Regel oben. Zwischen 860 und
   999px bleibt es bewusst bei der generischen 20rem-Spalte: dort ist noch
   nicht genug Platz fuer zwei gleich breite Spalten mit einer dreiteiligen
   Collage. */
@media (min-width: 1000px) {
  .praxis.grammar-b {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

/* ── Grammatik C: die Zaesur ─────────────────────────────────────────
   Eine Flaeche ueber die volle Breite, ein einziger Kernsatz, sonst Text in
   normaler Groesse. Sie trennt den ersten Teil der Seite vom zweiten und
   gibt dem Auge eine Pause.

   Bewusst NUR auf blockquote, nicht auf jedes <p>: "Der Beweis" behaelt
   seinen ersten Satz in normaler Lesegroesse (.beweis__zeile, unveraendert),
   nur der neue Kernsatz (Z3, [data-worte]) bekommt die grosse, schmale
   Zeilenform. Ohne die Beschraenkung waere auch der erste Satz faelschlich
   auf Ueberschriftengroesse gesprungen. */
.grammar-c {
  padding-block: var(--space-3xl);
  text-align: center;
}

.grammar-c blockquote {
  margin-inline: auto;
  max-width: 24ch;
  font-size: var(--step-4);
  line-height: 1.2;
  text-wrap: balance;
}

/* .beweis__h traegt ein eigenes max-width (18em, "BEWEIS"-Abschnitt weiter
   unten) und braucht deshalb einen eigenen Zentrier-Zusatz — text-align:
   center allein zentriert nur Inline-Inhalt, nicht die Blockbox selbst. */
.grammar-c .beweis__h,
.grammar-c .beweis__zeile {
  margin-inline: auto;
}

/* ── Tiefe ───────────────────────────────────────────────────────────
   perspective() und rotateX() sitzen bewusst beide auf demselben Element,
   nicht Perspektive am Elternteil und Winkel am Kind: perspective() als
   Transform-Funktion wirkt nur lokal auf das Element, das sie traegt. Ohne
   .has-scrollfx bleibt --tilt leer und der Fallback 0deg gilt: kein Skript,
   kein Kippen, kein Unterschied im Layout.

   WICHTIG — Konflikt mit [data-reveal]: [data-tilt] gehoert nie auf ein
   Element, das auch [data-reveal] traegt. js/reveal.js setzt .is-in
   einmalig und beobachtet danach nicht weiter; .has-reveal
   [data-reveal].is-in hat Spezifitaet (0,3,0) und setzt transform: none
   dauerhaft — hoeher als diese Regel hier (0,2,0), unabhaengig von der
   Reihenfolge im Stylesheet. Deshalb sitzt [data-tilt] in dieser Vorlage an
   der Bild-Collage selbst (.praxis__media), nicht am umschliessenden Kasten
   mit [data-reveal] (.praxis) — siehe Kommentar dazu in index.html. */
.has-scrollfx [data-tilt] {
  transform: perspective(1200px) rotateX(var(--tilt, 0deg));
  transform-origin: center 120%;
  will-change: transform;
}

/* ============================================================ ABLAUF ====
   Die vier Nahaufnahmen. Kein zweites Video: Das sind vier Bilder, die der
   Code bewegt.

   Aufgabe 13b: Z4, die Reihe, die seitwaerts faehrt, waehrend die Seite
   senkrecht scrollt (js/scroll.js, Kind "rail", Rechnung in railZustand()).
   Vorher stand hier ein zweispaltiges Raster; die vier Schritte sind aber
   eine Abfolge (Handtuecher, Matten, Papier, Waerme) — eine Reihe, durch die
   man faehrt, erzaehlt das eher als ein Raster. [data-rail] ist der
   sichtbare Rahmen, .rail__spur die tatsaechlich fahrende Spur.

   [data-rail] traegt overflow-x: auto UNGEBUNDEN an .has-scrollfx: Ohne
   Skript oder bei blockiertem Javascript ist das eine ganz normale, mit dem
   Finger schiebbare Reihe — nichts geht verloren, nur die Kopplung ans
   Scrollrad (weiter oben, Abschnitt Z4, ergaenzt um overflow-x: hidden ab
   700px, sobald das Scrollrad uebernimmt). */

[data-rail] {
  overflow-x: auto;
  scrollbar-width: thin;
}

.ablauf__liste .rail__spur {
  display: flex;
  gap: clamp(1.25rem, 3vw, 2rem);
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
}

.ablauf__liste .rail__spur > .ablauf__schritt {
  flex: 0 0 min(85vw, 24rem);
  margin: 0;
}

.ablauf__rahmen {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  background: var(--tint);
}

.ablauf__rahmen img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ablauf__nr {
  display: block;
  font-family: var(--font-title);
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: .3rem;
}

.ablauf__text {
  display: block;
  margin-top: .75rem;
  font-size: .98rem;
  line-height: 1.55;
  color: var(--ink);
}

/* ============================================================ BEWEIS ====
   Der Text steht vor einem Bild, das beim Scrollen naeher kommt. Das Bild ist
   eine Ebene mit [data-parallax], kein background-attachment: fixed — das
   steht auf dem Telefon still.

   AUFGABE 13B — HELL STATT DUNKEL, UND WARUM:
   Vor diesem Umbau trug dieser Abschnitt bereits einen Schleier in --dark
   ueber demselben Bild, das der Kommentar direkt darueber "durchgehend
   hell" nennt — ein dunkler Schleier ueber einem hellen Bild widerspricht
   sich selbst. Grammatik C ist beim Muster und bei Fliesen Brandhoff eine
   dunkle Flaeche; bei einer Physiotherapie-Praxis mit durchgehend heller,
   ruhiger Bildwelt (High-key, siehe docs/regeln/premium-vorlagen.md,
   Bildwelt dieser Vorlage) wirkt eine dunkle Zaesur mitten auf der Seite
   falsch. Die Zaesur bleibt als Zug bestehen — volle Breite, ein
   Kernsatz, eine Pause im Lesefluss, viel Luft (padding-block:
   var(--space-3xl) aus .grammar-c) — ihre Farbe nicht: heller Schleier,
   dunkler Text. Kein is-dark auf dieser <section>: js/scroll.js fragt fuer
   die HUD-Farbe (Befund 2, farbZusatz) deshalb nur noch "#top" ab, nicht
   mehr diesen Abschnitt (siehe Kommentar dort).

   DER SCHLEIER, GERECHNET: Ein flacher weisser Schleier statt eines
   Verlaufs — ein Verlauf mit einer schwaecheren Stelle in der Bildmitte
   (dieselbe Bauart wie beim Film) haette dort einen niedrigeren Kontrast
   ergeben, genau dort, wo der zentrierte Kernsatz steht. Gemessen auf
   `img/feierabend.jpg`, 64 x 36 weichgezeichnet: das 3. Perzentil der
   dunkelsten Flaeche liegt bei rgb(146, 142, 133), der dunkelste einzelne
   Bildpunkt (ein schattiger Ausreisser) bei rgb(67, 68, 56). Mit einem
   Schleier von rgb(255 255 255 / .90):
     Ueberschrift/gefuellter Kernsatz  --dark  #1f2d2c   12,98:1 / 12,08:1
     Kleinzeile/Aktiv-Zustand          --teal  #14746c    5,10:1 /  4,76:1
     Fliesstext/ungefuellter Kernsatz  --muted #5d6b6a    5,05:1 /  4,72:1
     Fliesstext (Absatz)               --ink   #3d4a4a    8,38:1 /  7,80:1
   Jeweils der erste Wert gegen das 3. Perzentil, der zweite gegen den
   Ausreisser-Bildpunkt — beide ueber 4,5:1 (bzw. 3:1 fuer die
   Ueberschrift als Grosstext). --dark bleibt als Grund darunter stehen,
   damit der Text auch vor dem Laden des Bildes lesbar ist.
   ====================================================================== */

.beweis {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  padding: clamp(3.5rem, 12vw, 7rem) 0;
}

.beweis > .wrap { position: relative; }

.beweis__media {
  position: absolute;
  left: 0;
  right: 0;
  top: -64px;
  bottom: -64px;
  z-index: -1;
  background-image: url("../img/feierabend.jpg");
  background-size: cover;
  background-position: 50% 45%;
  background-repeat: no-repeat;
}

.beweis__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(255 255 255 / .90);
}

.beweis__ueber { color: var(--teal); }

.beweis__h {
  font-family: var(--font-title);
  font-weight: 700;
  font-size: clamp(1.7rem, 4.4vw, 2.7rem);
  line-height: 1.14;
  margin: .2em 0 .8em;
  color: var(--dark);
  max-width: 18em;
}

.beweis__zeile {
  margin: 0 0 1rem;
  max-width: 34em;
  font-size: clamp(1rem, 2.3vw, 1.15rem);
  line-height: 1.6;
  color: var(--ink);
}

/* ── Bewegung aus ────────────────────────────────────────────────────────
   Alle drei Skripte steigen bei dieser Einstellung aus, bevor sie irgendetwas
   tun — .has-reveal, .has-scrollfx und .has-film erscheinen also gar nicht
   erst, und die Regeln hier greifen im Normalfall ins Leere.

   Sie stehen trotzdem da, fuer den einen Fall, in dem es darauf ankommt:
   Jemand schaltet die Einstellung um, waehrend die Seite offen ist.       */

@media (prefers-reduced-motion: reduce) {
  .has-scrollfx [data-parallax] .beweis__media { transform: none; }
  .has-scrollfx .progress { display: none; }
  .has-scrollfx .header.is-stuck { box-shadow: none; }

  /* Kein Kippen, jedes Element flach an seinem Endzustand. .has-scrollfx
     davor, nicht nur [data-tilt]: ohne die Klasse waere die Spezifitaet
     niedriger als bei .has-scrollfx [data-tilt] weiter oben, und diese
     Regel wuerde nie gewinnen. So ist die Spezifitaet gleich und die
     spaetere Regel im Text zaehlt. */
  .has-scrollfx [data-tilt] { transform: none; }
}

@media print {
  .has-scrollfx .progress { display: none; }
  .has-scrollfx [data-parallax] .beweis__media { transform: none; }

  /* Auf Papier ist der Film ein Bild: das Standbild, in normaler Hoehe. */
  .has-film .hero--film { height: auto; }
  .has-film .film__buehne { position: static; height: auto; }
  .has-film .film__bild { position: relative; }
  .has-film .film__bild::after { display: none; }
  .has-film .film__standbild { height: auto; }
  .has-film .film__canvas { display: none; }
  .has-film .film__texte { position: static; background: none; }
  .has-film .film__spuren { min-height: 0; }
  .has-film .film__spur { position: static; opacity: 1; transform: none; }
}
