/* ============================================================
   Psychotherapie am Fluß – Michael Hegemann
   Design nach cms/DESIGN.md (Referenz: elenaborisova.life)
   Architektur: markus-website-struktur
   ============================================================ */

/* ---------- Schriften ----------
   Hauptschrift: Stack Sans Text (Koto / Dylan Young, SIL Open Font License),
   selbst gehostet in fonts/. Zweitschrift: IBM Plex Mono, nur Meta-Ebene
   (Eyebrows, Labels, Preise, Kontaktdaten, Bildunterschriften), nie
   Fliesstext.
   ------------------------------------------------------------ */

/* Stack Sans Text - Koto / Dylan Young, SIL Open Font License.
   Variable Font, Gewichtsachse 200-700, Euro-Zeichen und Umlaute vollstaendig.
   Lizenztext: fonts/OFL-StackSans.txt */
/* WOFF2 zuerst (52 KB statt 124 KB als TTF): Die Ueberschrift der Startseite
   ist das groesste Element im ersten Bild, und sie wird erst in ihrer
   endgueltigen Schrift gezeigt, wenn die Datei da ist. Jede gesparte
   Kilobyte-Menge zieht diesen Moment nach vorne. Die TTF bleibt als Rueckfall
   fuer sehr alte Browser stehen, sie wird nur geladen, wenn WOFF2 fehlt. */
@font-face {
  font-family: 'Stack Sans Text';
  src: url('fonts/StackSansText-VariableFont_wght.woff2') format('woff2'),
       url('fonts/StackSansText-VariableFont_wght.ttf') format('truetype-variations');
  font-weight: 200 700; font-style: normal; font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  --ink:        #252d22;
  --ink-66:     rgba(37, 45, 34, .66);
  --ink-33:     rgba(37, 45, 34, .33);
  --ink-12:     rgba(37, 45, 34, .12);
  --white:      #ffffff;

  --bg-stein:   #f4f4f2;
  --bg-fluss:   #edf1ec;
  --bg-schilf:  #f3f0e8;
  --bg-moos:    #dfe6dd;

  --header-tone: #d9d7d2;

  --font:      'Stack Sans Text', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --text-xs: 1.6rem;
  --text-s:  2.4rem;
  --text-m:  3.4rem;
  --text-l:  max(4.6vw, 7.6rem);
  --text-xl: min(12.6vw, 21rem);

  --gap:     3.6vw;
  --space-s: 5rem;
  --space-m: 12rem;
  --space-l: 20rem;

  --ease:     cubic-bezier(.6, 0, 0, 1);
  --ease-out: cubic-bezier(.23, 1, .32, 1);
}

/* ---------- Mobile Typo-Skala (wie Referenz: kleinere Basiswerte) ----------
   Ohne diese Stufe stuende der Fliesstext auf dem Handy bei ~36 px. */
@media (max-width: 639px) {
  :root {
    --text-xs: 1.3rem;
    --text-s:  1.6rem;
    --text-m:  2rem;
    --text-l:  3.6rem;
    --text-xl: 9rem;
    --gap:     2rem;
    /* Sektionsabstaende grosszuegiger als in der Referenz: mit 7rem klebten
       die Bloecke auf dem Handy aneinander. */
    --space-s: 4rem;
    --space-m: 10rem;
    --space-l: 14rem;
  }
}

/* ---------- Fluides Root-Sizing (wie Referenz) ---------- */
/* Untergrenze 8.6px statt 7.2: bei 7.2 fielen auf Tablets (640-1400px)
   Fusszeile und Hilfstexte unter 12px - zu klein zum Lesen. */
html { font-size: max(.62vw, 8.6px); }
@media (min-width: 1600px) { html { font-size: 10px; } }
@media (max-width: 700px)  { html { font-size: min(2.8vw, 11px); } }

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* overflow-x: CLIP, nicht hidden. "hidden" macht aus html/body einen
   Scroll-Container und setzt damit jedes position:sticky im Dokument ausser
   Kraft - genau daran ist die Hero-Fixierung gescheitert. "clip" verhindert
   waagrechtes Scrollen ebenso, erzeugt aber keinen Scroll-Container. */
html { scroll-behavior: smooth; overflow-x: clip; }
body {
  overflow-x: clip;
  background: var(--white);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--text-m);   /* Fliesstext wie Referenz (~30px) */
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }

::selection { background: var(--ink); color: var(--white); }

/* lowercase nur auf Display-Ebene (Entscheidung DESIGN.md 3.1) */
.lc { text-transform: lowercase; }

h1, h2, h3 { font-weight: 500; line-height: 1.1; }
/* Keine Silbentrennung. Lange Komposita duerfen als Ganzes umbrechen,
   aber niemals mit Trennstrich zerlegt werden. */
h1, h2, h3, p, .intro-text, li, a { hyphens: none; -webkit-hyphens: none; overflow-wrap: normal; }
h1 { letter-spacing: -.04em; }
h2 { letter-spacing: -.03em; }
strong, b { font-weight: 700; }

/* Listen mit einem Kiesel als Bullet. DESIGN.md sah den Geviertstrich vor
   (wie die Referenzseite), der faellt aber unter die Regel "keine langen
   Gedankenstriche". Der Kiesel greift stattdessen das Leitmotiv auf. */
.dash-list li {
  position: relative;
  /* Grosszuegig: der Kiesel braucht Platz neben sich, und die Eintraege sind
     oft zweizeilig - eng gesetzt verschwimmen dann die Punkte ineinander. */
  padding-left: 4.4rem;
  margin-bottom: 1.8rem;
  line-height: 1.45;
  color: var(--ink-66);
}
.dash-list li:last-child { margin-bottom: 0; }
/* Ein echter Kiesel als Aufzaehlungszeichen. Nicht nachgebaut, sondern aus
   Illus/kiesel.svg herausgeloest (ein einzelner Pinselpfad) - so trifft die
   ausgerissene Kante genau den Stil der uebrigen Zeichnungen. Als MASKE
   eingebunden, nicht als Bild: dadurch traegt der Kiesel die Tintenfarbe und
   folgt spaeteren Farbwechseln, statt sie einzubrennen. */
.dash-list li::before {
  content: "";
  position: absolute;
  left: .2rem;
  /* Vertikal auf die Mitte der ERSTEN Zeile: der Kasten ist genau eine
     Zeilenhoehe hoch und beginnt an deren Oberkante, die Maske sitzt darin
     zentriert. Ein fester top-Wert verrutscht, sobald sich die Schriftgroesse
     oder der Zeilenabstand aendert. */
  top: 0;
  height: 1.45em;
  width: 2.1rem;
  background: var(--ink);
  /* Von Markus zugeschnittene Einzeldatei (165.8 x 154), nicht mehr mein
     Ausschnitt aus der grossen Zeichenflaeche. */
  -webkit-mask: url("Illus/kiesel-list.svg") no-repeat center / contain;
  mask: url("Illus/kiesel-list.svg") no-repeat center / contain;
  /* Die Kontur ist im Original rund 9 von 235 Einheiten stark - auf
     Bulletgroesse heruntergerechnet ein halber Pixel, also fast unsichtbar.
     Die vier Schlagschatten legen sich um die Maskenform und verdicken sie
     nach allen Seiten, ohne die Datei anzufassen. */
  filter:
    drop-shadow(.5px 0 0 var(--ink)) drop-shadow(-.5px 0 0 var(--ink))
    drop-shadow(0 .5px 0 var(--ink)) drop-shadow(0 -.5px 0 var(--ink));
}

/* Hover-Underline (wachsende Linie) */
.u-link {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size .45s var(--ease);
  padding-bottom: .3rem;
}
.u-link:hover, .u-link.active { background-size: 100% 1px; }

/* Sektions-Hintergründe */
.bg-stein  { background: var(--bg-stein); }
.bg-fluss  { background: var(--bg-fluss); }
.bg-schilf { background: var(--bg-schilf); }
.bg-moos   { background: var(--bg-moos); }

/* ============================================================
   Header – fixed, mix-blend-mode: exclusion (Referenz-Mechanik)
   ============================================================ */
#site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 3rem var(--gap);
  mix-blend-mode: exclusion;
  color: var(--header-tone);
  font-size: var(--text-s);
  font-weight: 500;
  pointer-events: none;
}
#site-header a, #site-header button { pointer-events: auto; }

.nav-brand {
  font-weight: 700;
  letter-spacing: -.02em;
  white-space: nowrap;
}
.nav-links { display: flex; gap: 3.4rem; }
.nav-links a { padding-bottom: .3rem; }

/* Burger – nur mobil */
.nav-toggle {
  display: none;
  pointer-events: auto;
  width: 40px;
  height: 32px;
  position: relative;
  z-index: 130;
}
.nav-toggle span {
  position: absolute;
  left: 6px;
  right: 6px;
  height: 2px;
  background: currentColor;
  transition: transform .4s var(--ease), top .4s var(--ease);
}
.nav-toggle span:nth-child(1) { top: 11px; }
.nav-toggle span:nth-child(2) { top: 19px; }
body.menu-open .nav-toggle span:nth-child(1) { top: 15px; transform: rotate(45deg); }
body.menu-open .nav-toggle span:nth-child(2) { top: 15px; transform: rotate(-45deg); }

/* Mobile-Menü Overlay (außerhalb des Blend-Kontexts) */
#mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: var(--bg-stein);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 8vw;
  gap: 2.4rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s var(--ease), visibility 0s .5s;
}
body.menu-open #mobile-menu {
  opacity: 1;
  visibility: visible;
  transition: opacity .5s var(--ease);
}
body.menu-open { overflow: hidden; }
body.menu-open #site-header { mix-blend-mode: normal; color: var(--ink); }
#mobile-menu a {
  font-size: var(--text-l);
  font-weight: 500;
  letter-spacing: -.03em;
  opacity: 0;
  transform: translateY(2rem);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
}
body.menu-open #mobile-menu a { opacity: 1; transform: none; }
body.menu-open #mobile-menu a:nth-child(2) { transition-delay: .05s; }
body.menu-open #mobile-menu a:nth-child(3) { transition-delay: .1s; }
body.menu-open #mobile-menu a:nth-child(4) { transition-delay: .15s; }
body.menu-open #mobile-menu a:nth-child(5) { transition-delay: .2s; }
#mobile-menu .mm-contact {
  margin-top: 3rem;
  font-size: var(--text-xs);
  color: var(--ink-66);
  line-height: 1.9;
}
/* Mailadresse einzeilig: lieber verkleinern als umbrechen */
#mobile-menu .mm-contact a {
  white-space: nowrap;
  display: inline-block;
  max-width: 100%;
  font-size: min(var(--text-xs), 4.2vw);
}
/* Schliessen-Knopf */
.mm-close {
  position: absolute;
  top: 2.4rem;
  right: var(--gap);
  width: 44px;
  height: 44px;
  z-index: 130;
}
.mm-close span {
  position: absolute;
  left: 10px;
  right: 10px;
  top: 21px;
  height: 2px;
  background: var(--ink);
}
.mm-close span:nth-child(1) { transform: rotate(45deg); }
.mm-close span:nth-child(2) { transform: rotate(-45deg); }

/* ============================================================
   Hero – Referenz-Mechanik (elenaborisova.life), OHNE sticky
   Buehne absolut im oberen Viewport, Inhalt startet tief und treibt beim
   Scrollen mit. --p = Roh-Fortschritt 0..1, --f = Fuege-Faktor.
   ============================================================ */
.hero {
  /* Startwerte im CSS: --f = 1 heisst VERSTREUT. Ohne diese Vorgabe greift
     der Rueckfall var(--f, 0) - und 0 ist der gefuegte Zustand, also das
     fertige Endbild, solange das JavaScript noch nichts gesetzt hat. */
  --f: 1;
  --p: 0;
  height: 150vh;
  min-height: 70rem;
  position: relative;
  overflow: hidden;   /* schneidet den abtreibenden Block an der Unterkante ab */
}
.hero-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  perspective: 90rem;
  overflow: visible;
  pointer-events: none;
}
/* ---------- Sparbetrieb nach dem Fuegen ----------
   Die 3D-Buehne und die vielen Einzelebenen werden NUR beim Zusammenfuegen
   gebraucht. Danach treibt der Block als Ganzes ab - dann sind sie reine
   Last: preserve-3d verhindert das Zusammenlegen der Ebenen, und 20 einzeln
   angemeldete Buchstaben plus 6 Steingruppen ergeben ueber 25 Schichten, die
   iOS in jedem Frame getrennt zusammensetzt. Genau das war das Ruckeln im
   Standbild. Bei --f = 0 setzt includes.js die Klasse und alles faellt
   zusammen; sichtbar aendert sich nichts, weil bei --f = 0 ohnehin kein
   Buchstabe mehr in der Tiefe steht. */
.hero.ist-gefuegt .hero-stage { perspective: none; }
.hero.ist-gefuegt .hero-inner { transform-style: flat; }
.hero.ist-gefuegt .hero-title .ltr,
.hero.ist-gefuegt .hero-illu g[data-stein] { will-change: auto; }

.hero-inner {
  position: absolute;
  top: 36vh;                     /* startet tief, aber nicht zu tief */
  left: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8vh;                      /* Luft zwischen Steinmaennchen und Text */
  transform-style: preserve-3d;
  /* Ruhezustand fuer den Fall, dass kein JavaScript laeuft: --p faellt auf 0
     zurueck, der Block steht also unveraendert da. Die Fixierung waehrend des
     Scrollens rechnet includes.js aus der gemessenen Hero-Hoehe - pauschale
     vh-Werte koennen den Scrollweg nicht exakt ausgleichen, weil der Hero
     mobil 118vh und am Desktop 150vh hoch ist. */
  transform: translateY(calc(var(--p, 0) * 100vh));
  opacity: 1;
  /* Eigene GPU-Schicht: dieser Block bewegt sich bei jedem Frame. Ohne den
     Hinweis rastert iOS die grosse Flaeche samt SVG jedes Mal neu. */
  will-change: transform, opacity;
}
.hero-illu {
  /* KEIN eigener Gegenlauf mehr: das Steinmaennchen steht mit dem Schriftzug
     still, der Abstand zwischen beiden bleibt dadurch ueber den ganzen
     Scrollweg konstant. Frueher stieg es um 14vh auf und lief am Desktop
     oben aus dem Bild. */
  will-change: transform;
  /* Hoehenbasiert skaliert. KEINE max-width: der SVG-Canvas ist 2456 breit,
     die Wasserlinie soll ueber die Sektionsbreite hinauslaufen - der Hero
     schneidet sie ab. Eine Breitenbegrenzung wuerde das Steinmaennchen
     dagegen aus der Mitte schieben. */
  position: relative;
  width: 100%;
  height: min(26vh, 30rem);
}
/* Absolut zentriert: ueberbreite Flex-Elemente werden sonst nicht zuverlaessig
   mittig ausgerichtet, sondern am Anfang angeschlagen. */
.hero-illu svg {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  height: 100%;
  width: auto;
  display: block;
  overflow: visible;
}
/* Steine verstreut (--f = 1) -> gefuegt (--f = 0). Die Gruppen werden von
   includes.js aus der Geometrie gebildet, der Export hat keine IDs.
   Streuwerte sind Vielfache der Canvas-Breite, daher em-frei in %. */
.hero-illu g[data-stein] {
  transform:
    translate(calc(var(--sx, 0) * var(--f, 1) * 300px + var(--cx, 0) * var(--pz, 0) * var(--f, 1) * 26px),
              calc(var(--sy, 0) * var(--f, 1) * 230px + var(--cy, 0) * var(--pz, 0) * var(--f, 1) * 26px))
    rotate(calc(var(--sr, 0) * var(--f, 1) * 1deg));
  transform-box: fill-box;
  transform-origin: center;
  opacity: calc(1 - var(--f, 1) * .55);
}
/* Bodenlinie zeichnet sich von links nach rechts (clip-Wischmaske).
   Die Pinselform ist gefuellt, stroke-dasharray geht daher nicht. */
.hero-illu g[data-wasser] {
  clip-path: inset(-8% calc(var(--f, 1) * 100%) -8% 0);
}
.hero-title {
  font-size: min(12.6vw, 21rem);
  line-height: .82;
  font-weight: 700;
  text-align: center;
  letter-spacing: -.04em;
}
.hero-title .word { display: inline-block; white-space: nowrap; }
.hero-title .ltr {
  display: inline-block;
  will-change: transform;
  /* Rueckfall zuerst: kennt der Browser color-mix nicht (aeltere iOS-Safari),
     wuerde sonst die geerbte Tintenfarbe greifen - die Buchstaben staenden
     von Beginn an voll schwarz da, als waere die Animation fertig. */
  color: var(--ink-33);
  color: color-mix(in srgb, var(--ink) calc((1 - var(--f, 1)) * 100%), var(--ink-33));
  opacity: calc(1 - var(--f, 1) * 0.62);
  transform:
    translate3d(
      calc((var(--x) + var(--cx, 0) * var(--px, 0) * 6) * var(--f, 1) * 1rem),
      calc((var(--y) + var(--cy, 0) * var(--px, 0) * 4) * var(--f, 1) * 1rem),
      calc(var(--z) * var(--f, 1) * 1rem))
    rotate(calc(var(--rz) * var(--f, 1) * 1deg));
}
.hero-scroll-hint {
  position: absolute;
  bottom: 4rem;
  left: 0;
  width: 100%;
  text-align: center;
  font-size: var(--text-xs);
  color: var(--ink-33);
  opacity: calc(1 - var(--p, 0) * 6);
  pointer-events: none;
}

/* ---------- Desktop-Korrektur bei breitem Seitenverhaeltnis ----------
   Der Hero-Stapel ist Startversatz (36vh) + Steinmaennchen (26vh) + Abstand
   (8vh) + Titel. Der Titel ist ueber die BREITE bemessen (12.6vw), zwei Zeilen
   ergeben rund 21vw = auf 16:9 etwa 37vh. Macht in Summe ~107vh > 100vh:
   "am fluss" liegt unter der Kante und wird beim Scrollen weiter verdeckt.
   Das haengt NICHT an der Pixel-Hoehe (1440x820 wie 1920x1080 sind beide 16:9
   und beide betroffen), sondern am breiten Seitenverhaeltnis - deshalb ueber
   min-aspect-ratio eingegrenzt. Ab 3:2 aufwaerts (16:10, 16:9, breiter) rueckt
   der ganze Block nach oben und der Titel wird per vh gedeckelt, damit er
   vollstaendig steht. Hohe/quadratische Schirme (unter 3:2) und das Handy
   bleiben unveraendert. */
@media (min-width: 901px) and (min-aspect-ratio: 3 / 2) {
  .hero-inner { top: 15vh; gap: 4vh; }
  /* Steinmaennchen eine Spur groesser, Titel eine Spur kleiner - auf dem
     breiten Laptop wirkte der Titel sonst zu wuchtig gegenueber der Marke. */
  .hero-illu { height: min(23vh, 26rem); }
  .hero-title { font-size: min(11vw, 21rem, 21vh); }
}

/* ============================================================
   Sektionen allgemein
   ============================================================ */
section { position: relative; }
.section-pad { padding: var(--space-m) var(--gap); }

.section-eyebrow {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--ink-66);
  margin-bottom: 2.4rem;
}
.section-title {
  font-size: var(--text-m);
  max-width: 92rem;
  margin-bottom: 3rem;
}
.section-title--l { font-size: var(--text-l); line-height: .95; max-width: none; }
.section-intro {
  font-size: var(--text-m);
  font-weight: 400;
  line-height: 1.2;
  color: var(--ink-66);
  max-width: 92rem;
}
.section-intro strong { color: var(--ink); font-weight: 500; }

/* ---------- Meta-Ebene: IBM Plex Mono ----------
   Zustaendig fuer Eyebrows, Illustrations-Labels, Preise, Kontaktdaten und
   Bildunterschriften. NIE fuer Fliesstext - sonst wirkt die Praxis technisch.
   Mono laeuft optisch groesser als die Grotesk, daher .92em Ausgleich.
   ------------------------------------------------------------ */
.section-eyebrow,
.page-eyebrow,
.illu-label,
.preis-wert,
.bild-caption,
.u-mono {
  font-family: var(--font-mono);
  font-size: .92em;
  font-weight: 400;
  letter-spacing: .04em;
}
.section-eyebrow, .page-eyebrow { letter-spacing: .12em; }

/* ---------- Meta-Ebene: EINE Behandlung fuer alle Beschriftungen ----------
   Mono kennzeichnet, was ueber den Inhalt spricht statt Inhalt zu sein:
   Spaltenbeschriftungen und Zaehlwerk. Damit das als System liest und nicht
   beliebig wirkt, teilen sich alle diese Stellen dieselbe Auszeichnung -
   kleingeschrieben wie die uebrige Display-Ebene der Seite, gleiche
   Laufweite, gleiche Tonwertrolle. Versalien waren hier das einzige laute
   Element auf einer durchgehend klein sprechenden Seite. */
.footer-label,
.hs-zaehler,
.bereich-nr,
.mini-label,
.contact-form label,
.thema-feld legend,
.legal-page td::before {
  font-family: var(--font-mono);
  /* Feste Groessenrolle, KEIN em: die drei Stellen haengen an verschieden
     grossen Elternelementen - mit em waeren sie absolut unterschiedlich
     gross und die Ebene wieder beliebig. */
  font-size: var(--text-xs);
  font-weight: 400;
  letter-spacing: .08em;
  text-transform: lowercase;
  color: var(--ink-33);
}

/* Preise: Ziffern auf gleicher Breite, damit die Spalte sauber steht */
.preis-wert { font-variant-numeric: tabular-nums; }

/* Label unter jeder Illustration (Regel aus HANDOUT 4.4) */
.illu-label {
  display: block;
  margin-top: 1.2rem;
  color: var(--ink-66);
  text-transform: lowercase;
  font-size: var(--text-xs);
}

/* Zweispaltig: Text + Bild mit Parallaxe */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  align-items: center;
}
.split--rev .split-media { order: -1; }
.split-media {
  overflow: hidden;
  border-radius: .6rem;
}
.split-media img,
.split-media video {
  width: 100%;
  height: 100%;
  min-height: 60rem;
  object-fit: cover;
  transform: translateY(calc((var(--sp, .5) - .5) * 9vh)) scale(1.18);
}
.copy p { margin-bottom: 2.4rem; color: var(--ink-66); max-width: 92rem; }
.copy p strong { color: var(--ink); }

/* Wegbegleiter: gleich breite Spalten, damit der Text Raum bekommt.
   minmax(0,1fr) statt 1fr - sonst kann die Medienspalte durch ihren
   Inhalt ueber die Haelfte hinauswachsen. */
.split--gross { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; }
.split--gross .split-media { width: 84%; margin-left: auto; }
.split--gross .split-media img,
.split--gross .split-media video { min-height: 0; height: auto; aspect-ratio: 4 / 5; }
@media (max-width: 900px) {
  .split--gross { grid-template-columns: 1fr; }
  .split--gross .split-media { width: 100%; margin-left: 0; }
  .split--gross .split-media img,
  .split--gross .split-media video { min-height: 0; height: auto; aspect-ratio: 4 / 5; }
}

/* Praxisraum: Bild bewusst klein - der Text traegt, das Foto belegt nur */
.split--klein { grid-template-columns: 1.5fr 1fr; align-items: center; }
/* Bei umgekehrter Reihenfolge liegt das Bild links - dann muss die schmale
   Spalte die erste sein, sonst bekommt das Foto die grosse. */
.split--klein.split--rev { grid-template-columns: 1fr 1.9fr; }
.split--klein .split-media img { min-height: 0; height: auto; aspect-ratio: 4 / 5; }
@media (max-width: 900px) {
  .split--klein { grid-template-columns: 1fr; }
  .split--klein .split-media { max-width: 46rem; }
}

/* ============================================================
   Praxisraum – zwei ueber Eck ueberlappende Fotos, Text eingerueckt
   ============================================================ */
.praxis {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: start;
}
.praxis-bilder {
  position: relative;
  /* Platz fuer das ueberlappende zweite Bild, das unten hinausragt */
  padding-bottom: 13%;
}
.praxis-bild { object-fit: cover; }
/* Leichte Gegenbewegung: das grosse Bild wandert ein Stueck mit, das kleine
   deutlich staerker. Die Differenz laesst es ueber dem ersten schweben. */
.praxis-bild--gross { transform: translateY(calc((var(--sp, .5) - .5) * 3vh)); }
.praxis-bild--gross {
  /* Nach innen gerueckt, damit sich die beiden Bilder deutlich ueberlappen.
     Das querformatige sitzt rechts buendig, dieses schiebt sich darunter. */
  width: 62%;
  margin-left: 13%;
  aspect-ratio: 3 / 4;
}
.praxis-bild--klein {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 54%;
  aspect-ratio: 3 / 2;   /* querformatig */
  /* Deutlich staerkerer Versatz als beim grossen Bild - daraus entsteht das
     Schweben. Wichtig: KEIN Schatten, die Tiefe kommt allein aus der Bewegung. */
  transform: translateY(calc((var(--sp, .5) - .5) * -9vh));
}
.praxis-text {
  /* Text eingerueckt, und etwas tiefer angesetzt als die Bildkante */
  padding-left: var(--gap);
  padding-top: 8vh;
}
.praxis-text .copy p { margin-bottom: 3rem; }
/* Fliesstext und Link gegenueber der Ueberschrift eingerueckt - wie in der
   Vorlage, wo die Headline links steht und der Text darunter einsetzt.
   Gemeinsame Klasse fuer Wegbegleiter und Praxisraum, damit beide Sektionen
   denselben Versatz haben und nicht auseinanderlaufen. */
/* Absoluter Wert, nicht Prozent: die beiden Textspalten sind unterschiedlich
   breit, prozentual liefe der Versatz sonst auseinander. */
.eingerueckt { padding-left: 8rem; margin-top: 3rem; }
@media (max-width: 900px) { .eingerueckt { padding-left: 0; margin-top: 2rem; } }

@media (max-width: 900px) {
  .praxis { grid-template-columns: 1fr; gap: 4rem; }
  /* Volle Spaltenbreite: das grosse Bild beginnt links buendig, das kleine
     endet rechts buendig - zusammen nutzen sie die ganze Breite. */
  .praxis-bilder { padding-bottom: 26%; }
  .praxis-bild--gross { width: 76%; margin-left: 0; }
  .praxis-bild--klein { width: 62%; }
  .praxis-text { padding-left: 0; padding-top: 0; }
}

/* Angebots-Raster */
.offer-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gap);
  margin-top: var(--space-s);
}
.offer-card {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  padding: var(--space-s) 0 0;
  border-top: 1px solid var(--ink-12);
  transition: opacity .4s var(--ease-out);
}
.offer-card:hover { opacity: .62; }
.offer-card img, .offer-card svg {
  /* Flaechen-normalisiert statt quadratisch: die Motive sind sehr
     unterschiedlich breit (4.7:1 bis 1.7:1). In einer festen 14rem-Box
     schrumpfen die queren auf einen Strich, waehrend die kompakten sie
     fuellen - optisch wirkten sie dann verschieden gross. Die Hoehe traegt
     hier die Groesse, die Breite ergibt sich aus dem Motiv, gedeckelt auf
     die Spaltenbreite. Pinselzeichnungen brauchen dabei Flaeche: unter
     etwa 110px wird die ausgerissene Kante zu Matsch. */
  /* Breite je Motiv aus --illu-b, gesetzt im Markup: width = Wurzel aus
     (Zielflaeche x Seitenverhaeltnis). Nur so wiegen die Motive optisch
     gleich schwer. Eine gemeinsame Box mit object-fit reicht NICHT - darin
     zeichnet ein 1.7:1-Motiv nur die halbe Flaeche eines 4.7:1-Motivs. */
  width: var(--illu-b, 20rem);
  max-width: 100%;
  /* Gemeinsame Kastenhoehe (die des hoechsten Motivs) mit Ausrichtung nach
     unten: so stehen alle Motive auf EINER Standlinie und die Titel darunter
     fluchten. Ohne das schoebe das hohe Motiv seinen Titel nach unten.
     Die Hoehe muss ausserdem ausdruecklich gesetzt sein - diese SVGs tragen
     nur eine viewBox, ohne width/height kennt der Browser keine intrinsische
     Groesse und rechnet die Hoehe auf ein paar Pixel herunter. */
  height: 8.4rem;
  object-fit: contain;
  object-position: left bottom;
  margin-bottom: .8rem;
  /* Platzhalter sind JPEGs mit weissem Grund - multiply laesst ihn
     verschwinden. Kann raus, sobald die SVGs mit currentColor da sind. */
  mix-blend-mode: multiply;
  transform: rotate(calc(5deg - var(--sp, .5) * 10deg));
}
.offer-card h3 {
  font-size: var(--text-m);
  font-weight: 500;
  letter-spacing: -.02em;
}
.offer-card p { color: var(--ink-66); flex: 1; font-size: var(--text-s); }
.offer-card .offer-more {
  font-weight: 700;
  align-self: flex-start;
}

/* ============================================================
   Leistungen – horizontal scrollende Sektion
   Desktop: Sektion wird fixiert, vertikaler Scroll schiebt die Spur seitlich.
   Mobil:  nativer Wisch-Slider mit scroll-snap, kein Scroll-Hijacking.
   ============================================================ */
/* Abstand als PADDING, nicht als margin: der Footer liegt unter den Sektionen
   (Vorhang-Mechanik), und ein Aussenabstand ist durchsichtig - der Footer
   schien als abgeschnittenes Band zwischen den Sektionen durch. Padding
   gehoert dagegen zur eingefaerbten Flaeche und deckt zuverlaessig ab. */
.leistungen { position: relative; padding-top: var(--space-m); }
.hs-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  /* Nicht zentriert, sondern nach UNTEN ausgerichtet: der ganze Block -
     Titel, Illustration, Balken, Karten - sitzt dadurch tiefer im Bild.
     Abstaende werden einzeln gesetzt, nicht ueber einen gemeinsamen gap. */
  justify-content: flex-end;
  gap: 0;
  overflow: hidden;
  /* Unterer Abstand gehoert an die Buehne, nicht an die Fusszeile: so ist er
     bei Unterausrichtung deterministisch und der Block kann nicht ueberlaufen.
     Oben kein Polster - der Freiraum entsteht durch flex-end von selbst. */
  padding: 0 0 var(--space-m);
}
.hs-head {
  padding: 0 var(--gap) var(--space-s);          /* unten: Mindestabstand zum Balken */
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gap);
  align-items: center;                    /* Illustration auf Titelhoehe */
}
.hs-head h2 { margin: 0 0 1.6rem; }
.hs-foot {
  padding: var(--space-s) var(--gap) 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap);
}
/* Zaehler und Fortschrittsbalken zeigen dasselbe an, nur in zwei Sprachen:
   Am Desktop faehrt die Spur per Scroll-Hijack, dort traegt der Balken die
   Position. Mobil wischt man selbst durch die Karten - dort der Zaehler.
   Nie beide gleichzeitig. */
.hs-zaehler { display: none; }
@media (max-width: 900px) { .hs-zaehler { display: block; } }

/* Flache Fenster (Laptop): Illustration und Karten kleiner, Buehne knapper. */
@media (max-height: 900px) {
  .hs-sektionsillu img { height: min(15vh, 13rem); }
  .hs-card { min-height: 24rem; }
  .hs-stage { padding-bottom: var(--space-s); }
}

/* Sektions-Illustration rechts neben der Ueberschrift, vertikal auf deren
   Hoehe zentriert. Ueber die Hoehe gesteuert, damit unterschiedlich breite
   Motive gleich viel Raum einnehmen. */
.hs-sektionsillu { display: block; color: var(--ink); }
/* Kiesel sind noch der generierte JPEG-Platzhalter. Sein Grund ist NICHT
   reines Weiss, sondern warmes Papier - mit multiply bliebe auf dem
   gruenlichen Sektionsgrund ein heller Kasten stehen. "darken" nimmt je
   Kanal den dunkleren Wert: das Papier verschwindet vollstaendig, die
   Tinte bleibt. Raus, sobald das SVG da ist (I-02).
   Quadratisch statt hoehenbasiert, sonst wird es winzig. */
.hs-illu--kiesel img { height: auto; width: min(34rem, 100%); mix-blend-mode: darken; }
.hs-sektionsillu img { height: min(17vh, 18rem); width: auto; display: block; }
@media (max-width: 900px) {
  .hs-head { grid-template-columns: 1fr; padding-top: var(--space-s); }
  .hs-sektionsillu img { height: min(10vh, 10rem); max-width: 100%; }
}

/* Textlinks mit schraegem Pfeil - moderner als der waagrechte, und er
   bewegt sich beim Hovern in seine eigene Richtung. */
.pfeil { white-space: nowrap; }
.pfeil::after {
  content: "↗";
  display: inline-block;
  margin-left: .3em;
  /* Das Glyph sitzt hoch im Kegel - Grundversatz nach unten, damit es
     optisch auf der Zeile steht. Der Hover-Weg rechnet darauf auf. */
  transform: translateY(.12em);
  transition: transform .35s var(--ease-out);
}
.pfeil:hover::after { transform: translate(.16em, -.04em); }
.btn {
  display: inline-flex;
  align-items: center;
  gap: .8em;
  padding: 1.3em 2.4em;
  border: 1px solid var(--ink);
  border-radius: 100px;
  font-size: var(--text-s);
  font-weight: 500;
  transition: background-color .4s var(--ease), color .4s var(--ease);
}
.btn:hover { background: var(--ink); color: var(--bg-stein); }
.hs-track {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: auto;      /* eine Reihe */
  grid-auto-columns: min(40rem, 78vw);
  align-content: start;
  gap: var(--gap);
  padding: 0 var(--gap);
  width: max-content;
  /* Die Spur bildet wegen des Transforms einen eigenen Stapelkontext.
     mix-blend-mode der Platzhalter-JPEGs braucht darin einen Hintergrund
     zum Multiplizieren - sonst bleibt der weisse Grund stehen. */
  background: var(--bg-fluss);
  will-change: transform;
  transform: translateX(calc(var(--hp, 0) * var(--hs-weg, 0px) * -1));
}
.hs-card {
  display: flex;
  flex-direction: column;
  gap: 2.2rem;
}
/* Kein :hover mehr - die Karten sind keine Links. Ein Aufhellen unter dem
   Zeiger wuerde Klickbarkeit versprechen, die es nicht gibt. Der Weg zur
   Angebotsseite fuehrt ueber "mehr erfahren" unter der Spur. */
.hs-card {
  padding-top: 0;
  /* Nutzt die freie Hoehe der Fullscreen-Buehne */
  min-height: 38rem;
  /* Keine Silbentrennung, keine Wortumbrueche in den Karten */
  hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
}
.hs-card h3, .hs-card p { hyphens: none; overflow-wrap: normal; }
/* Beschreibung bleibt direkt unter dem Titel - der Abstand ist der
   gemeinsame Spaltenabstand der Karte (gap), nicht ausgereizte Hoehe. */
/* Fortschrittsbalken: bei horizontalem Scrollen sieht man sonst nicht,
   wie viel noch kommt. Fuellt sich mit --hp aus includes.js. */
/* ---------- Fortschritt: zwei Anzeigen, je Breite eine ----------
   Am Desktop faehrt die Spur per Scroll-Hijack stufenlos - dort passt der
   DURCHLAUFENDE Balken, er liest sich fliessender. Am Handy wischt man selbst
   von Karte zu Karte, dort zeigen elf Striche die Stationen. */
.hs-fortschritt {
  margin: 0 var(--gap) 2.4rem;
  /* flex: none - als Flex-Element in der Spalte wuerde die Hoehe
     sonst auf 0 zusammengedrueckt. */
  flex: none;
  height: 2px;
  background: var(--ink-12);
  position: relative;
}
.hs-fuellung {
  /* scaleX statt Prozentbreite: die Prozentangabe loeste sich in diesem
     Kontext nicht auf, und Transform ist ohnehin guenstiger.
     KEINE transition: nicht registrierte Custom Properties animieren nicht -
     der Uebergang friert den Anfangswert 0 ein und der Balken bleibt leer.
     Der rAF-Loop schreibt --hp ohnehin in jedem Frame, das laeuft fluessig. */
  display: block;
  height: 100%;
  background: var(--ink);
  transform: scaleX(var(--hp, 0));
  transform-origin: left center;
}
.hs-striche { display: none; }

.hs-card h3 { font-size: var(--text-m); font-weight: 500; letter-spacing: -.02em; }
.hs-card p  { color: var(--ink-66); font-size: var(--text-s); }

/* Mobil und bei reduzierter Bewegung: echter Wisch-Slider */
@media (max-width: 900px) {
  /* Mobil traegt die Buehne ihr eigenes Polster - hier KEIN zusaetzlicher
     Abstand, sonst stehen 2 x --space-m untereinander (die grosse Luecke
     unter dem Video). */
  .leistungen { height: auto !important; padding-top: 0; }
  .hs-stage {
    position: static;
    height: auto;
    overflow: visible;
    /* Ohne Buehnenhoehe traegt die Sektion ihre Abstaende selbst */
    padding: var(--space-m) 0;
  }
  .hs-head { padding-bottom: var(--space-s); }
  .hs-foot { padding-top: var(--space-s); }
  /* Striche statt durchlaufendem Balken: hier gibt es abzaehlbare Stationen,
     und man sieht auf einen Blick, dass es eine Slideshow ist. Gespeist wird
     die Anzeige mobil NICHT von --hp (kein Scroll-Hijacking), sondern vom
     Wischstand der Spur - siehe standAktualisieren(). */
  .hs-fortschritt { background: none; }
  .hs-fuellung { display: none; }
  .hs-striche { display: flex; gap: .4rem; height: 100%; }
  .hs-striche span {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    background: var(--ink-12);
    transition: background .35s var(--ease-out);
  }
  .hs-striche span.ist-aktiv { background: var(--ink); }
  .hs-track {
    transform: none;
    width: auto;
    grid-auto-flow: column;
    grid-template-rows: auto;      /* mobil eine Reihe, echte Slideshow */
    grid-auto-columns: calc(100vw - 2 * var(--gap));
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 1rem;
  }
  .hs-track::-webkit-scrollbar { display: none; }
  /* Eine Karte je Ansicht statt seitlichem Scrollen durch alle */
  .hs-card {
    scroll-snap-align: center;
    scroll-snap-stop: always;
    width: calc(100vw - 2 * var(--gap));
    min-height: 0;
  }
}

/* ============================================================
   Vorstellung: Text auf ganzflaechigem Foto (Referenz-Mechanik)
   ============================================================ */
.intro-photo {
  position: relative;
  /* KEINE aspect-ratio: Bei einem hochformatigen Rahmen wird das quadratische
     Foto nur seitlich beschnitten - object-position haette dann vertikal
     keinen Angriffspunkt. Breiter Rahmen -> vertikaler Beschnitt -> der
     Ausschnitt laesst sich steuern. */
  height: 112vh;
  min-height: 70rem;
  display: flex;
  align-items: flex-start;
  padding: calc(var(--space-s) + 6rem) var(--gap) var(--space-m);
  overflow: hidden;
}
.intro-photo > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 76%;   /* mehr vom unteren Bereich zeigen */
  z-index: 0;
  /* Parallaxe MUSS negativ sein: Bild und Text liegen in derselben Sektion,
     der Versatz wirkt also unmittelbar auf den Abstand zwischen beiden.
     Positiv hiesse: der Kopf entfernt sich beim Scrollen vom Text. */
  /* scale muss > Verschiebeweg sein: +/-10vh Versatz braucht mindestens
     13vh Ueberstand je Seite, sonst entsteht oben/unten ein leerer Streifen. */
  transform: scale(1.28) translateY(calc((var(--sp, .5) - .5) * -20vh));
}
.intro-photo::after {
  /* Das Foto ist hell - ohne diesen Schleier traegt weisse Schrift nicht.
     Text steht oben, also laeuft der Verlauf von oben nach unten aus. */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(37,45,34,.46) 0%, rgba(37,45,34,.20) 18%, rgba(37,45,34,0) 34%);
  z-index: 1;
}
.intro-photo .intro-text {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: none;
  color: var(--white);
  /* Drei Zeilen stehen als feste <br> im Markup - der automatische Umbruch
     ist zu fensterabhaengig. Die Schrift skaliert mit, damit die laengste
     Zeile ("Akademischer Psychotherapeut") auf keiner Breite umbricht. */
  font-size: min(var(--text-l), 5.2vw);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -.03em;
  text-wrap: normal;
}
/* Mobil bricht der Satz frei um - dort waeren die festen Zeilen zu lang */
@media (max-width: 639px) {

}

/* Buchstabenweises Aufhellen (JS setzt .on nacheinander) */
.tr-ltr {
  opacity: .22;
  transition: opacity .45s var(--ease-out);
}
.tr-ltr.on { opacity: 1; }

/* Desktop: hoehere Sektion, damit man durch das Bild scrollt (Kopf oben unter
   dem Text, weiter unten kommen Rumpf und Haende) und die naechste Section
   spaeter beginnt, statt das Foto frueh zu ueberdecken. Das Foto ist quadratisch
   (1920x1920), die Haende liegen ganz unten; eine hoehere Box zeigt mit `cover`
   einen groesseren senkrechten Ausschnitt. Der Ausschnitt (object-position)
   ist gegenjustiert (66% statt der Handy-76%), damit der Kopf beim Eintritt
   direkt unter dem Text sitzt - genau wie vorher, nur dass beim Weiterscrollen
   mehr vom Therapeuten sichtbar wird. Am Handy bleibt alles wie es war. */
@media (min-width: 901px) {
  .intro-photo { height: 135vh; }
  .intro-photo > img { object-position: 50% 66%; }
}

@media (max-width: 700px) {
  /* KEIN aspect-ratio: dadurch richtete sich die Breite nach der Hoehe
     und die Sektion war schmaler als das Fenster. */
  /* Polster muss den fixierten Kopf freihalten, sonst laeuft der Text
     in die Wortmarke. */
  .intro-photo { width: 100%; height: 84vh; min-height: 50rem; padding-top: calc(var(--space-s) + 4.5rem); }
  .intro-photo .intro-text {
    /* Etwas kleiner: ergibt vier Zeilen statt fuenf und laesst mehr Luft
       zwischen Text und Kopf. */
    font-size: min(var(--text-l), 8.2vw);
    /* Feste Umbrueche raus, dafuer ausgeglichener Flattersatz - sonst steht
       ein einzelnes Wort auf einer Zeile. Das Leerzeichen vor dem <br> im
       Markup verhindert, dass Woerter dabei verschmelzen. */
    text-wrap: balance;
  }
  .intro-photo .intro-text br { display: none; }
}

/* ============================================================
   Foto-Band ueber die volle Breite
   Regel HANDOUT 4.4: Illustration behauptet, Foto beweist.
   Nie direkt neben einer Illustration platzieren.
   ============================================================ */
.photo-band { overflow: hidden; }
.photo-band img {
  width: 100%;
  height: clamp(38rem, 62vh, 78rem);
  object-fit: cover;
  transform: scale(1.06) translateY(calc((var(--sp, .5) - .5) * -6vh));
  will-change: transform;
}
.photo-band figcaption {
  padding: 1.6rem var(--gap) 0;
  color: var(--ink-66);
}

/* ============================================================
   Salzach-Band – Stroemungsfoto vollflaechig, Text darauf
   Der Name ist eine Ortsangabe, keine Metapher (HANDOUT 4.3)
   ============================================================ */
.salzach {
  position: relative;
  padding: var(--space-m) var(--gap);
  min-height: 80vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  isolation: isolate;
}
.salzach-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -2;
  transform: scale(1.22) translateY(calc((var(--sp, .5) - .5) * -12vh));
}
.salzach::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(37, 45, 34, .42);
  z-index: -1;
}
.salzach p {
  position: relative;
  color: var(--white);
  /* Drei Zeilen stehen als feste <br> im Markup - ein Satz je Zeile.
     Die Groesse ist gedeckelt, damit die laengste Zeile auch auf sehr
     breiten Schirmen nicht ueber den Rand laeuft. */
  font-size: min(var(--text-l), 4vw);
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -.03em;
  max-width: none;
  text-align: center;
  text-wrap: normal;
}
@media (max-width: 639px) {
  /* Groesser, fuenf bis sechs Zeilen - der Satz soll die Sektion tragen */
  .salzach p {
    font-size: min(var(--text-l), 7.6vw);
    line-height: 1.15;
    text-wrap: balance;
  }
  .salzach p br { display: none; }

  .salzach { min-height: 70vh; }
}
/* Buchstaben-Aufhellung wie beim Vorstellungstext - auf dem Foto aber
   heller angesetzt, sonst verschwindet der ungelesene Teil im Bild. */
.salzach .tr-ltr { opacity: .34; }
/* MERKE fuer kuenftige Verwendungen von data-textreveal ausserhalb der
   Fotobaender: Ein eigener Ausgangswert braucht IMMER die passende
   .on-Zeile dazu. Beide haben dieselbe Spezifitaet - steht der Ausgangswert
   spaeter in der Datei, gewinnt er auch im aufgehellten Zustand, und der
   Text bleibt grau, obwohl die Buchstaben laengst geschaltet sind.
   Siehe die beiden .salzach-Zeilen darueber. */
.salzach .tr-ltr.on { opacity: 1; }

/* ============================================================
   Kontakt-Band vor dem Footer – traegt die Bildmarke
   ============================================================ */
.kontakt-band {
  /* Ausdrueckliche Deckung gegen den Footer. Der liegt per Vorhang-Mechanik
     darunter (sticky, z-index 0), und die Sektionen decken ihn ueber die
     Sammelregel `body > section` ab. Als LETZTE Sektion vor dem Footer haengt
     hier alles daran, deshalb steht es zusaetzlich direkt an der Sektion und
     eine Stufe hoeher: so kann kein Stapelkontext von aussen das aushebeln. */
  position: relative;
  z-index: 2;
  background: var(--white);
  padding: var(--space-m) var(--gap);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: center;
}
/* Bildmarke: der SVG-Canvas ist 3:1, das Steinmaennchen belegt darin nur die
   Mitte. Deshalb ueber die HOEHE steuern - ueber die Breite bliebe es winzig.
   min-width:0 ist Pflicht: sonst waechst die Rasterspalte mit dem ueberbreiten
   Bild mit und quetscht die Textspalte zusammen. */
.kontakt-band .kb-mark {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* Diese Regel galt der Bildmarke, die hier frueher stand: feste Hoehe, ihr
   Seitenverhaeltnis, und eine Deckkraft von .42, weil ihr Export eine harte
   Farbe eingebrannt hatte. Nichts davon trifft noch zu - alle drei Seiten
   zeigen hier ein Motiv mit currentColor, und die Deckkraft liess es
   grau statt schwarz erscheinen. Es bleibt nur, was fuer alle gilt. */
.kontakt-band .kb-mark img {
  max-width: none;
  flex: none;
}

/* Versuch: elf Kiesel statt der Bildmarke - in voller Tiefe, nicht abgesoftet.
   Noch ein JPEG-Platzhalter, multiply nimmt den weissen Grund weg. */
/* Flusslauf: ueber die BREITE gesteuert, nicht ueber die Hoehe wie die
   Bildmarke. Das Motiv ist quer (907.5 : 396.5) - hoehenbasiert wuerde es
   aus der Spalte laufen und von deren overflow abgeschnitten. Kein
   mix-blend-mode noetig, das SVG hat keinen Grund. */
.kontakt-band .kb-mark img.kb-weg {
  height: auto;
  /* Volle Spaltenbreite. Bewusst KEINE rem-Obergrenze: die Wurzelgroesse ist
     ab 1600px bei 10px gedeckelt, die Spalte und die Ueberschrift daneben
     wachsen aber weiter mit dem Fenster - eine rem-Grenze liesse das Motiv
     auf grossen Schirmen relativ schrumpfen. So bleibt das Verhaeltnis zur
     Ueberschrift auf jeder Breite gleich. */
  width: 100%;
  aspect-ratio: 907.5 / 396.5;   /* Flusslauf (Startseite) */
}
/* Je Motiv sein eigenes Seitenverhaeltnis: die Box gibt es vor, und ein <img>
   fuellt sie standardmaessig VERZERRT aus. Neues Motiv, neue Zeile. */
.kontakt-band .kb-mark img.kb-weg--boot { aspect-ratio: 954 / 195.8; }
.kontakt-band .kb-mark img.kb-weg--trittsteine {
  aspect-ratio: 972.2 / 281.3;

  opacity: 1;
}
.kontakt-band .kb-mark img.kb-weg--knoten { aspect-ratio: 955.7 / 205.3; }
.kontakt-band .kb-text { min-width: 0; }
.kontakt-band .kb-text h2 { font-size: min(var(--text-l), 4.4vw); line-height: .95; margin-bottom: 3rem; }
.kontakt-band .kb-praxis {
  font-size: var(--text-s);
  color: var(--ink);
  margin-bottom: 1.6rem;
}
/* Dreizeiler zum Flusslauf. Enger gefuehrt als die alten Kontaktdaten
   (1.9 war Datenzeilen-Abstand, kein Fliesstext) und in der Tinte des
   Fliesstexts statt im Grau der Metadaten - es ist eine Aussage, keine
   Angabe. */
.kontakt-band .kb-satz {
  font-size: var(--text-s);
  line-height: 1.45;
  color: var(--ink-66);
  margin-bottom: 3.4rem;
  text-wrap: pretty;
}

@media (max-width: 900px) {
  .kontakt-band { grid-template-columns: 1fr; }
  .kontakt-band .kb-text h2 { font-size: var(--text-l); }
  .kontakt-band .kb-mark { order: -1; }
  /* mobile Bildmarken-Regel entfaellt mit ihr, die Motive tragen ihr eigenes Mass */
}

/* ============================================================
   Footer – Vorhang-Mechanik wie im Hero
   Der Footer bleibt am unteren Rand stehen, die letzte Inhaltssektion
   schiebt sich darueber hinweg und gibt ihn beim Scrollen frei.
   Damit das traegt, muessen alle Sektionen davor deckend und hoeher
   gestapelt sein - sonst scheint der Footer durch.
   ============================================================ */
body > section { position: relative; z-index: 1; }
body > section:not([class*="bg-"]) { background: var(--white); }
/* Bewusst `body > footer` statt `footer`: der Cookie-Dialog von Silktide
   bringt ein eigenes <footer> fuer seine Buttonzeile mit - die stand durch
   die globale Regel auf 0 Pixel Hoehe. */
body > footer {
  position: sticky;
  bottom: 0;
  z-index: 0;
}
/* Auf dem Handy KEIN Vorhang: dort wirkt der freigelegte Footer wie ein
   Fremdkoerper zwischen den Sektionen. */
@media (max-width: 900px) {
  body > footer { position: static; }
}
body > footer {
  background: var(--bg-moos);
  padding: var(--space-m) var(--gap) 4rem;
}
.footer-word {
  display: block;
  font-size: min(11vw, 19rem);
  font-weight: 700;
  letter-spacing: -.04em;
  line-height: .84;
  margin-bottom: var(--space-m);
}
.footer-word span { display: block; }
.footer-word:hover { color: var(--ink-66); transition: color .4s var(--ease); }
.footer-label { display: block; margin-bottom: 1.4rem; }
.footer-spalte p + p { margin-top: 1.2rem; }

.footer-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
  padding-top: var(--space-s);
  font-size: var(--text-xs);
}
.footer-grid .col-label {
  display: block;
  font-weight: 700;
  margin-bottom: 1.6rem;
}
.footer-grid p, .footer-grid li { color: var(--ink-66); margin-bottom: .9rem; line-height: 1.5; }
.footer-grid a:hover { color: var(--ink); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: var(--space-s);
  color: var(--ink-33);
  font-size: var(--text-xs);
}
.footer-bottom a { color: var(--ink-66); }

/* ============================================================
   Unterseiten-Hero
   ============================================================ */
.page-hero {
  padding: calc(var(--space-m) + 8rem) var(--gap) var(--space-s);
}
.page-hero .page-eyebrow {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--ink-66);
  margin-bottom: 2.4rem;
}
.page-hero h1 {
  font-size: var(--text-l);
  font-weight: 700;
  line-height: .9;
  margin-bottom: 3rem;
}
.page-hero .page-subtitle {
  font-size: var(--text-s);
  line-height: 1.35;
  color: var(--ink-66);
  max-width: 78rem;
}

/* Seiten-Hero mit Illustration daneben (Angebotsseite).
   Gleiches Spaltenmass wie das Kontakt-Band, damit die Seite ein Raster hat. */
.page-hero--illu {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: center;
  /* Flacher als der Standard-Seitenhero: die Illustration daneben fuellt die
     Hoehe bereits, zusaetzliches Polster liesse den Block leer wirken. */
  padding-top: calc(var(--space-m) + 8rem);
  padding-bottom: var(--space-m);
  /* Gleiche Hoehe auf allen Unterseiten. Ohne das bestimmt die Illustration
     die Hoehe, und ein flaches Motiv (die Bruecke, 4.3:1) ergaebe einen
     deutlich niedrigeren Kopf als ein kompaktes (die Kiesel).
     Mass in REM, nicht vh: die Illustrationen sind in rem bemessen: mit einer
     vh-Untergrenze fallen beide bei kurzen Fenstern auseinander, weil dann
     das Motiv die Hoehe treibt statt der Mindestwert. */
  min-height: 82rem;
}
.page-hero--illu .ph-text { min-width: 0; }

/* ---------- Kiesel-Buehne: elf Steine, elf Ebenen ----------
   Jede Gruppe im SVG traegt --pz (Tiefe) und --rx/--ry (Richtung), gesetzt
   von initKiesel(). Die Mausposition kommt als --cx/--cy von der Sektion.
   Bewusst klein gehalten: 14px Ausschlag beim vordersten Stein. Es soll
   lebendig wirken, nicht wackeln. */
/* Ruhende Illustration im Seiten-Hero. Nutzt denselben Platz wie die
   Kiesel-Buehne, aber ohne deren Mechanik - diese SVGs bringen keine Gruppen
   mit und sollen auch nicht wandern. Sie tragen nur ihr Seitenverhaeltnis,
   weil ein SVG ohne width/height sonst auf ein paar Pixel zusammenfaellt. */
.ph-illu {
  /* Volle Spaltenbreite. Die Motive hier sind sehr flach (die Bruecke 4.3:1),
     sie erreichen die Flaechenwirkung der Kiesel auch ausgereizt nicht -
     schmaler wirken sie daneben aber verloren. */
  width: 100%;
  max-height: 50rem;
  height: auto;
  display: block;
  color: var(--ink);
}

.kiesel-buehne { min-width: 0; display: flex; justify-content: center; }
.kiesel-buehne svg {
  width: min(60rem, 100%);
  /* Deckel, damit kein Motiv den Kopf ueber die gemeinsame Hoehe treibt */
  max-height: 50rem;
  height: auto;
  display: block;
  color: var(--ink);
  /* Ueberstand fuer den Mausversatz: die Steine wandern bis zu 44px aus
     ihrer Ruhelage, ohne Luft wuerden die aeusseren angeschnitten. */
  overflow: visible;
}
/* Flaches Motiv (die Trittsteine, 3.5:1) auf voller Spaltenbreite. Die
   60rem-Grenze der Buehne ist fuer die kompakten Kiesel gedacht; ein flaches
   Motiv wirkt damit neben der H1 verloren - wie die Bruecke auf "Ueber mich",
   die ebenfalls die Spalte fuellt. */
.kiesel-buehne--breit svg { width: 100%; }
/* Die Feder liegt in weiten Ringen, die viel Flaeche belegen, ohne Bild zu
   sein. Eine Spur schmaler als die uebrigen Hero-Motive, nicht mehr. */
.wellen-buehne svg { width: min(70rem, 100%); }

/* KEIN transform und KEINE transition hier: die Steine werden in
   initKiesel() ueber das SVG-Attribut transform bewegt, in einem rAF-Loop
   mit Annaeherung. Eine CSS-transition darueber wuerde beides gegeneinander
   laufen lassen und ruckeln. Der Loop rechnet drei Anteile zusammen:
   Drift (Maus im Fenster), Ausweichen (Maus ueber der Buehne) und Absinken
   (Scrollposition). */

@media (max-width: 900px) {
  .page-hero--illu {
    grid-template-columns: 1fr;
    gap: var(--space-s);
    /* Einspaltig folgt die Hoehe dem Inhalt. Die gemeinsame Mindesthoehe
       gilt nur nebeneinander: gestapelt haetten Motive verschiedener
       Proportion sonst unterschiedlich viel Leerraum unter sich. */
    min-height: 0;
  }
  .page-hero--illu .kiesel-buehne { order: -1; }
  .page-hero--illu .ph-illu { max-height: 34rem; }
}


/* ---------- Bildband: Illustration links, Text rechts ----------
   Gleiches Spaltenmass wie die Bereichszeilen, damit die Seite ein Raster
   behaelt. Die Illustration nutzt .ph-illu und bekommt damit dieselbe leichte
   Mausbewegung wie das Motiv im Hero - nur kleiner, weil sie hier neben
   Fliesstext steht und nicht neben einer H1. */
.illu-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: var(--gap);
  align-items: center;
}
.illu-band-bild { min-width: 0; display: flex; justify-content: center; }
.illu-band-text { min-width: 0; }
.illu-band .ph-illu { width: min(48rem, 100%); max-height: 34rem; }

/* Steinmaennchen, das sich beim Hereinscrollen zusammensetzt. Dieselbe
   Zerlegung wie im Hero der Startseite (includes.js), nur mit kleinerer
   Streuung: der Block ist keine volle Bildschirmhoehe, die Steine sollen im
   Blickfeld bleiben und nicht in die Textspalte laufen. */
.steinbau { width: min(48rem, 100%); }
.steinbau svg {
  width: 100%;
  height: auto;
  display: block;
  color: var(--ink);
  overflow: visible;
}
.steinbau g[data-stein] {
  transform:
    translate(calc(var(--sx, 0) * var(--f, 1) * 130px),
              calc(var(--sy, 0) * var(--f, 1) * 100px))
    rotate(calc(var(--sr, 0) * var(--f, 1) * 1deg));
  transform-box: fill-box;
  transform-origin: center;
  opacity: calc(1 - var(--f, 1) * .55);
}
/* Die Bodenlinie wischt von links herein, wie auf der Startseite. */
.steinbau g[data-wasser] { clip-path: inset(-8% calc(var(--f, 1) * 100%) -8% 0); }

@media (max-width: 900px) {
  .illu-band { grid-template-columns: 1fr; gap: var(--space-s); }
  .illu-band-bild { justify-content: flex-start; }
  .illu-band .ph-illu { width: min(26rem, 70%); }
}


/* ---------- Die vier Bereiche, zweispaltig ----------
   Jeder Bereich traegt seine Unterpunkte selbst. align-items: start, weil die
   Bereiche unterschiedlich viele Punkte haben und nicht auf gleiche Hoehe
   gezogen werden sollen. */
/* Jeder Bereich ist eine eigene Zeile, in sich zweispaltig: links Name und
   Einleitung, rechts die Aufklapper. Vier Zeilen untereinander.
   Das loest das Hoehenproblem des 2x2-Rasters vollstaendig - ein Bereich mit
   drei Aufklappern und einer mit elf stehen einfach in verschieden hohen
   Zeilen, ohne Loch daneben. */
/* Abstand von der Ueberschrift zur ersten Bereichszeile. Frueher als Inline-
   style="margin-top:var(--space-m)" im Markup - jetzt hier, damit der Wert am
   Handy kleiner werden kann. */
.bereiche { margin-top: var(--space-m); }

.bereich {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: var(--gap);
  align-items: start;
  padding: var(--space-m) 0;
  /* WEISSE Trennlinie, nicht die uebliche graue: der Bereich enthaelt ein
     Akkordeon, dessen Zeilen bereits graue Haarlinien tragen. Eine zweite
     graue Linie derselben Machart schlaegt sich damit - man sieht nicht
     mehr, was Trennung und was Aufklapper ist. Weiss auf dem warmen Grund
     trennt, ohne mitzureden. */
  border-top: 1px solid var(--white);
}
.bereich:first-child { border-top: none; padding-top: 0; }
.bereich:last-child { padding-bottom: 0; }
.bereich-kopf { min-width: 0; }
/* Zaehlt die vier Bereiche durch und loest damit das "vier Bereiche" aus dem
   Hero ein. Auszeichnung kommt aus der Meta-Regel weiter oben, dieselbe wie
   die Footer-Labels - hier nur die Stellung. */
.bereich-nr { display: block; margin-bottom: 1.4rem; }
/* Zwischenueberschrift im Fliesstext, gleiche Auszeichnung wie die uebrige
   Meta-Ebene. Traegt die Listen im Lebenslauf. */
.mini-label { display: block; margin: var(--space-s) 0 1.2rem; }
.bereich-kopf h2 { margin-bottom: 2rem; }
.bereich-klappen { min-width: 0; }
.bereich > h2 {
  font-size: var(--text-m);
  letter-spacing: -.02em;
  margin-bottom: 1.6rem;
}
.bereich-intro {
  color: var(--ink-66);
  font-size: var(--text-s);
  line-height: 1.5;
  margin-bottom: var(--space-s);
}
/* KEINE Verkleinerung der Akkordeons in den Bereichen: sie sollen sich
   genauso grosszuegig anfassen wie auf einer vollbreiten Seite. Nur die
   Listen in den Klappen bekommen die Fliesstextgroesse. */
.bereich .dash-list { font-size: var(--text-s); }

/* Flacheres Fotoband fuer Unterseiten - das Vollbild der Startseite ist als
   wiederkehrendes Element auf jeder Seite zu wuchtig. */
.salzach--flach { min-height: 0; height: 58vh; }
.bereich .dash-list li { margin-bottom: 1.8rem; }
@media (max-width: 900px) {
  .bereich { grid-template-columns: 1fr; gap: 2.4rem; }
  /* Am Handy stapeln sich die Zeilen ohnehin; --space-m Innenabstand liesse
     zwischen zwei Zeilen eine sehr grosse Luecke. */
  .bereich { padding: var(--space-s) 0; }
  /* Keine weisse Trennlinie zwischen den Kategorien am Handy: einspaltig steht
     Name, Einleitung und Akkordeon derselben Kategorie schon untereinander -
     eine Linie obendrauf trennt dann nicht mehr Kategorien, sondern schneidet
     mitten durch den Lesefluss. Der Abstand allein gliedert genug. */
  .bereich { border-top: none; padding-top: 0; }
  .bereich + .bereich { padding-top: var(--space-s); }
  /* Weniger Luft von der Ueberschrift zur ersten Zeile - am Desktop traegt
     der grosse Abstand die Gliederung, am schmalen Schirm wirkt er als Loch. */
  .bereiche { margin-top: var(--space-s); }
  .bereich-intro { margin-bottom: 2.4rem; }
}

/* ---------- Schwerpunkte als Raster ----------
   Elf Themen, jedes eine Zeile. Als Akkordeon waeren das elf Klappen fuer je
   einen Satz - das lohnt den Klick nicht. Als Raster stehen sie alle offen da
   und lassen sich ueberfliegen. */
.themen {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-s) var(--gap);
  margin-top: var(--space-s);
}
.thema { min-width: 0; border-top: 1px solid var(--ink-12); padding-top: 1.8rem; }
.thema h3 {
  font-size: var(--text-s);
  font-weight: 500;
  letter-spacing: -.02em;
  margin-bottom: .8rem;
}
.thema p { color: var(--ink-66); font-size: var(--text-xs); line-height: 1.5; }
.thema .thema-wo {
  display: block;
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: .08em;
  text-transform: lowercase;
  color: var(--ink-33);
}
@media (max-width: 900px) { .themen { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 639px) { .themen { grid-template-columns: 1fr; gap: var(--space-s); } }

/* Anker-Unternav (Angebotsseite) */
.anchor-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2rem;
  padding: 0 var(--gap) var(--space-s);
}
.anchor-nav a {
  border: 1px solid var(--ink-33);
  border-radius: 99rem;
  padding: 1rem 2.2rem;
  font-weight: 500;
  transition: background .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.anchor-nav a:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--white);
}

/* ============================================================
   Akkordeon (Schwerpunkte)
   ============================================================ */
.accordion { border-top: 1px solid var(--ink-12); }
.accordion:last-child { border-bottom: 1px solid var(--ink-12); }
.accordion-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: 2.2rem 0;
  text-align: left;
  font-size: var(--text-s);
  font-weight: 500;
  letter-spacing: -.02em;
  cursor: pointer;
}
/* ---------- Rollover: die Zeile ruecke ein, davor waechst eine Linie ----------
   Dieselbe Sprache wie der Unterstrich der Textlinks, nur waagrecht vor der
   Beschriftung. Kein Farbwechsel: die Zeilen stehen ohnehin in Tinte, ein
   Aufhellen wuerde sie schwaecher statt aktiver wirken lassen.
   Die Linie liegt im Innenabstand des Knopfes und schiebt nichts um - sie
   waechst nur in eine Luecke hinein, die die Beschriftung freimacht. */
.accordion-trigger { position: relative; }
.acc-label {
  display: inline-block;
  transition: transform .4s var(--ease-out);
}
/* Die Linie haengt am KNOPF, nicht an der Beschriftung: ein transform macht
   das Element zum Bezugsrahmen seiner absolut gesetzten Nachfahren, die Linie
   waere also mitgewandert und quer durch den Text gelaufen. */
.accordion-trigger::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2.4rem;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .4s var(--ease-out);
}
.accordion-trigger:hover .acc-label,
.accordion-trigger:focus-visible .acc-label { transform: translateX(3.4rem); }
.accordion-trigger:hover::before,
.accordion-trigger:focus-visible::before { transform: scaleX(1); }
/* Im geoeffneten Zustand bleibt die Zeile stehen - sie ist dann Titel des
   sichtbaren Textes, kein Angebot mehr. */
.accordion.is-open .acc-label { transform: none; }
.accordion.is-open .accordion-trigger::before { transform: scaleX(0); }
/* Am Handy kein Rollover: es gibt keinen Mauszeiger, und ein Fingertipp laesst
   :hover haengen - die Zeile ruckt beim Antippen zur Seite und die Linie
   erscheint, ohne dass es gemeint war. */
@media (hover: none), (max-width: 900px) {
  .accordion-trigger:hover .acc-label { transform: none; }
  .accordion-trigger:hover::before { transform: scaleX(0); }
}

.accordion-trigger .acc-icon {
  flex: none;
  width: 2.4rem;
  height: 2.4rem;
  position: relative;
}
.accordion-trigger .acc-icon::before,
.accordion-trigger .acc-icon::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 0;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transition: transform .4s var(--ease);
}
.accordion-trigger .acc-icon::after { transform: rotate(90deg); }
.accordion.is-open .acc-icon::after { transform: rotate(0deg); }
.accordion-body {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .42s cubic-bezier(.32,.72,0,1), opacity .3s ease;
}
/* 90rem statt 40: die Texte kommen jetzt vollstaendig aus dem
   Word-Dokument, und eine zu knappe Hoehe schneidet sie lautlos ab. */
.accordion.is-open .accordion-body { max-height: 90rem; opacity: 1; }
.accordion-body p {
  color: var(--ink-66);
  max-width: 72rem;
  padding-bottom: 2.4rem;
  /* Nie groesser als die Klapp-Ueberschrift darueber: der Fliesstext der
     Seite (--text-m) liegt hoeher als --text-s und liesse den geoeffneten
     Text wichtiger wirken als seine eigene Zeile. */
  font-size: var(--text-s);
  line-height: 1.5;
}

/* ============================================================
   Preistabelle (Ablauf & Kosten)
   ============================================================ */
.price-table { width: 100%; border-collapse: collapse; }
.price-table tr { border-top: 1px solid var(--ink-12); }
.price-table tr:last-child { border-bottom: 1px solid var(--ink-12); }
.price-table th, .price-table td {
  text-align: left;
  padding: 2.2rem 0;
  font-weight: 400;
  vertical-align: baseline;
}
.price-table th {
  font-size: var(--text-s);
  font-weight: 500;
  letter-spacing: -.02em;
}
.price-table td:last-child {
  text-align: right;
  font-size: var(--text-s);
  font-weight: 500;
  white-space: nowrap;
}
/* Nicht an die Tabelle gebunden: der Vorbehalt steht auf dieser Seite unter
   den Zuschusskarten, nicht in einer Tabellenzelle. */
.price-note { color: var(--ink-66); font-size: var(--text-xs); }

/* Zuschuss-Karten */
.subsidy-grid {
  display: grid;
  /* Nicht fest dreispaltig: in der rechten Spalte einer .bereich-Zeile bleiben
     am iPad quer nur rund 500px, dort sind drei Karten so schmal, dass der
     Betrag umbricht. auto-fit legt die dritte Karte dann in eine zweite
     Zeile, statt alle drei zu quetschen. */
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: calc(var(--gap) * .6);
  max-width: 86rem;
}
.subsidy-card {
  background: rgba(255,255,255,.6);
  border-radius: .6rem;
  padding: 2.8rem;
}
.subsidy-card .amount {
  display: block;
  /* Ein Geldbetrag bricht nie um. Vorher stand am iPad quer das Eurozeichen
     von "45,00 €" allein in der zweiten Zeile. */
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-size: var(--text-m);
  font-weight: 500;
  letter-spacing: -.03em;
  margin-bottom: .6rem;
}
.subsidy-card .kasse { color: var(--ink-66); }

/* ============================================================
   Standort-Karte (Kontaktseite)
   ============================================================ */
/* Volle Breite wie die Fotobaender, am Desktop rund 600px hoch. */
.karte {
  position: relative;
  width: 100%;
  height: 67rem;   /* rund 600px am Desktop */
  background: var(--bg-fluss);
  overflow: hidden;
}
/* Die Karte selbst faerbt sich ueber die Stilvorlage in kontakt.html, nicht
   ueber einen CSS-Filter - ein Filter wuerde auch die Nadel entfaerben. */
.karte-feld { width: 100%; height: 100%; }
.karte-feld img { max-width: none; }   /* Googles Kacheln nicht beschneiden */
.karte-platzhalter {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1.6rem;
  padding: var(--space-s) var(--gap);
}
.karte-adresse { font-size: var(--text-m); line-height: 1.25; }
.karte-hinweis {
  font-size: var(--text-xs);
  color: var(--ink-66);
  line-height: 1.5;
  max-width: 62rem;
  margin-top: .8rem;
}

@media (max-width: 900px) {
  .karte { height: 44rem; }
}

/* ============================================================
   Kontakt
   ============================================================ */
.kontakt-grid {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: calc(var(--gap) * 1.5);
  align-items: start;
}
.kontakt-info h2 { font-size: var(--text-s); margin-bottom: 2rem; }
.kontakt-info .k-block { margin-bottom: 4rem; }
.kontakt-info p { color: var(--ink-66); margin-bottom: .6rem; }
.kontakt-info a { font-weight: 500; color: var(--ink); }

/* Formular */
.form-group { margin-bottom: 3.2rem; }
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.4rem;
}
/* Schrift, Groesse, Laufweite und Farbe kommen aus der Meta-Ebene weiter oben
   (Monoschrift, klein geschrieben) - hier nur noch die Anordnung. */
.contact-form label {
  display: block;
  margin-bottom: 1.2rem;
}
.contact-form input,
.contact-form textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: transparent;
  border: none;
  /* Volle Tinte, nicht 33 Prozent: die Linie IST das Feld. Blass gesetzt
     verschwindet sie neben der Monoschrift-Beschriftung. */
  border-bottom: 1px solid var(--ink);
  padding: 1rem 0;
  border-radius: 0;
  transition: border-color .3s var(--ease);
}
.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-bottom-color: var(--ink);
}
.contact-form textarea { min-height: 14rem; resize: vertical; }
/* Absenden ist ein Link, keine gefuellte Pille: Markus hat gefuellte Buttons
   ausdruecklich abgelehnt ("Links ohne Flaeche und Border, Pfeil schraeg nach
   oben"). Die Klassen u-link und pfeil kommen im Markup dazu, hier bleibt nur
   das Zuruecknehmen der Button-Optik. */
.form-submit {
  display: inline-block;
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.form-submit:disabled { opacity: .45; cursor: wait; }
/* Rueckmeldung nach dem Absenden. Gross genug, dass man sie nicht uebersieht -
   sie ist das Einzige, woran man erkennt, dass die Nachricht weg ist. */
.form-message {
  margin-top: 3.2rem;
  padding-top: 2.4rem;
  border-top: 1px solid var(--ink-12);
  font-size: var(--text-s);
  font-weight: 500;
  line-height: 1.4;
}
.form-message--success { color: #2e6b4f; }
.form-message--error { color: #a34032; }
/* Ueber die volle Spaltenbreite, nicht auf 56rem gedeckelt: der Absatz steht
   unter einem Formular, das die ganze Breite nutzt - ein schmaler Block darunter
   sieht aus wie vergessen. */
.form-privacy { font-size: var(--text-xs); color: var(--ink-66); margin-bottom: 2.6rem; }
.form-privacy a { text-decoration: underline; }

/* ---------- Kontaktseite: grosszuegige Felder ----------
   Das Formular steht allein in der Sektion (Anschrift und Zeiten stehen im
   Footer). Ueber die volle Breite waeren die Felder unbrauchbar lang, deshalb
   ein Deckel - grosszuegig, aber noch in einem Zug lesbar. */
/* Volle Breite. Die beiden Zweierzeilen (Name, Kontakt) geben dem Formular
   auch breit eine Ordnung, und die Seite haelt damit dasselbe Mass wie die
   Preistabelle auf "Ablauf & Kosten". */

.contact-form .form-group { margin-bottom: 4.4rem; }
.contact-form .form-row { gap: var(--gap); }
/* Die Beschriftung der Auswahl traegt die Themen selbst, nicht die Meta-Ebene:
   sie sind Text zum Anklicken, keine Auszeichnung. Deshalb hier zurueckgesetzt. */
.thema-wahl label {
  font-family: var(--font);
  letter-spacing: -.01em;
  text-transform: none;
}
.contact-form label .label-zusatz { opacity: .6; }
.contact-form input,
.contact-form textarea {
  /* Deutlich mehr Luft als der Baustein bisher hatte: die Felder tragen die
     Schriftgroesse des Fliesstextes, mit 1rem Polster wirkten sie gedrueckt. */
  padding: 1.8rem 0 2rem;
  line-height: 1.3;
}
.contact-form textarea { min-height: 20rem; }
/* Platzhalter dezent: eine Stufe kleiner als der Eingabetext und blasser als
   --ink-33. Sie sind ein Hinweis, keine Beschriftung - die steht darueber. In
   voller Textgroesse sahen die Felder aus, als waeren sie schon ausgefuellt. */
.contact-form input::placeholder,
.contact-form textarea::placeholder {
  color: rgba(37, 45, 34, .22);
  font-size: var(--text-s);
}
/* Fehlende Pflichtangabe: nur die Linie faerbt sich, kein Kasten, kein Rot
   als Flaeche. */
.contact-form .ist-leer { border-bottom-color: #a34032; }

/* ---------- Themenauswahl ----------
   Echte Radioknoepfe, untereinander. Der Kreis ist gezeichnet, nicht der des
   Systems: der Systemknopf bringt Blau und eine fremde Groesse mit. Er nimmt
   das Zeichen der .dash-list auf, damit die Seite eine Formsprache behaelt. */
.thema-feld { border: none; padding: 0; margin-inline: 0; }
.thema-feld legend { padding: 0; margin-bottom: 2rem; }
/* Am Desktop nebeneinander - fuenf kurze Begriffe brauchen keine fuenf
   Zeilen, und die Seite spart die Hoehe. Unter 900px untereinander, sonst
   stehen die Kreise in unregelmaessigen Abstaenden. */
.thema-wahl { display: flex; flex-wrap: wrap; gap: 1.4rem 3.4rem; }
/* Der Systemknopf verschwindet, aber NICHT mit display:none - damit waere das
   Feld fuer die Tastatur verloren. */
.thema-wahl input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.thema-wahl label {
  display: flex;
  align-items: center;
  gap: 1.8rem;
  margin: 0;
  padding: .4rem 0;
  font-size: var(--text-s);
  font-weight: 400;
  color: var(--ink-66);
  cursor: pointer;
  transition: color .3s var(--ease);
}
.thema-wahl label::before {
  content: "";
  flex: none;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  border: 1px solid var(--ink-33);
  background: transparent;
  transition: border-color .3s var(--ease), background-color .3s var(--ease),
              box-shadow .3s var(--ease);
}
.thema-wahl label:hover { color: var(--ink); }
.thema-wahl label:hover::before { border-color: var(--ink); }
/* Gewaehlt: der Kreis fuellt sich, ein weisser Ring laesst den Punkt stehen. */
.thema-wahl input:checked + label { color: var(--ink); }
.thema-wahl input:checked + label::before {
  border-color: var(--ink);
  background: var(--ink);
  box-shadow: inset 0 0 0 .55rem var(--white);
}
.thema-wahl input:focus-visible + label::before {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

@media (max-width: 900px) {
  .contact-form .form-row { grid-template-columns: 1fr; gap: 0; }
  .thema-wahl { flex-direction: column; gap: 1.4rem; }
  .thema-wahl label { padding: 1rem 2rem; }
}

/* ============================================================
   Rechtsseiten
   ============================================================ */
.legal-page {
  /* Vollbreit statt max-width + margin auto: die Deckflaeche gegen den
     darunterliegenden Footer muss ueber die ganze Fensterbreite reichen,
     sonst schiene er seitlich neben der Textspalte durch. Die Lesespalte
     von 86rem entsteht jetzt ueber die Innenabstaende. */
  padding: calc(var(--space-m) + 8rem)
           max(var(--gap), calc((100% - 86rem) / 2))
           var(--space-m);
}
/* Eigene Typo-Stufe: Rechtstext ist Lesetext, nicht Auftritt. Der Fliesstext
   der Startseite (--text-m) ist dafuer zu gross - auf dem Handy standen vier
   Woerter in der Zeile. Ausserdem war die Hierarchie verkehrt: h2 lag unter
   der Absatzgroesse, h1 auf gleicher Hoehe wie ein Absatz. */
/* Deckend und hoeher gestapelt - wie body > section. Der Footer liegt per
   Vorhang-Mechanik UNTER dem Inhalt (position: sticky, z-index 0); ein
   <main> ohne eigenen Stapelwert und ohne Hintergrund verschwindet sonst
   dahinter, der Footer lag mitten im Rechtstext. */
.legal-page {
  position: relative;
  z-index: 1;
  background: var(--white);
  font-size: var(--text-s);
  line-height: 1.55;
}
.legal-page h1 {
  font-size: min(var(--text-l), 5.4rem);
  line-height: .95;
  margin-bottom: 3.4rem;
  /* "manual", nicht "auto": WebKit unterdrueckt bei hyphens:none AUCH den
     weichen Trennstrich &shy;, und "datenschutzerklaerung" lief dadurch auf
     dem Handy 31px ueber den Rand. "manual" erlaubt ausschliesslich den
     selbst gesetzten Trennpunkt - automatisch getrennt wird weiterhin nie. */
  hyphens: manual;
  -webkit-hyphens: manual;
}
.legal-page h2 {
  font-size: var(--text-m);
  line-height: 1.15;
  margin: 5rem 0 1.6rem;
}
.legal-page p, .legal-page li {
  color: var(--ink-66);
  margin-bottom: 1.4rem;
  font-size: inherit;
  line-height: inherit;
}
.legal-page > p:first-of-type { color: var(--ink); }
.legal-page ul { list-style: none; }
.legal-page a { text-decoration: underline; }
.legal-page table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.legal-page th, .legal-page td {
  text-align: left;
  padding: 1.2rem 1rem 1.2rem 0;
  border-top: 1px solid var(--ink-12);
  /* NICHT "anywhere": das zerlegte auf dem Handy auch normale Woerter -
     "Loeschung" stand als "Loeschun / g". Nur die Speicher-Schluessel
     duerfen hart brechen, die haben eine eigene Regel (.legal-page code). */
  overflow-wrap: break-word;
  color: var(--ink-66);
  font-size: var(--text-xs);
  vertical-align: top;
}
.legal-page th { font-weight: 700; color: var(--ink); }
/* Lange Speicher-Schluessel in der Cookie-Tabelle brechen sonst nicht um */
.legal-page code {
  font-family: var(--font-mono);
  font-size: .82em;
  overflow-wrap: anywhere;
  word-break: break-all;
}
.legal-page .btn { margin-bottom: 1.4rem; }

/* ---------- Offene Stellen im Rechtstext ----------
   ABSICHTLICH knallig: diese Seiten duerfen nicht oeffentlich gehen, solange
   noch eine Angabe fehlt. Nach dem Ausfuellen die <span class="tbd"> ganz
   entfernen - nicht nur die Farbe wegnehmen. */
.tbd {
  display: inline-block;
  background: #fff2a8;
  color: #4a3d00;
  border-left: 3px solid #d9a600;
  padding: .8rem 1.2rem;
  margin: .4rem 0;
  font-size: .92em;
  line-height: 1.45;
}
.tbd::before {
  content: "OFFEN: ";
  font-family: var(--font-mono);
  font-weight: 700;
  letter-spacing: .06em;
}
@media print { .tbd { border: 1px solid #000; background: none; } }

/* ---------- Rechtstabellen auf dem Handy gestapelt ----------
   Drei Spalten auf 390px hiessen: die Dauer-Spalte war 59px breit und
   zerlegte "Loeschung" in "Loeschun / g". Statt an Prozenten zu drehen,
   loesen sich die Zeilen mobil in Bloecke auf - jede Zelle mit ihrer
   Spaltenueberschrift aus data-label. */
@media (max-width: 639px) {
  .legal-page table,
  .legal-page tbody,
  .legal-page tr,
  .legal-page td { display: block; width: auto; }
  .legal-page thead { display: none; }
  .legal-page tr {
    border-top: 1px solid var(--ink-12);
    padding: 1.8rem 0 1rem;
  }
  .legal-page td {
    border: none;
    padding: 0 0 1.2rem;
  }
  .legal-page td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: .4rem;
  }
}

/* CTA-Band */
.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 3rem;
  padding: var(--space-m) var(--gap);
}
.cta-band h2 { font-size: var(--text-m); max-width: 70rem; }
.cta-primary {
  display: inline-block;
  background: var(--ink);
  color: var(--white);
  border-radius: 99rem;
  padding: 1.8rem 4rem;
  font-weight: 500;
  font-size: var(--text-xs);
  white-space: nowrap;
  transition: opacity .3s var(--ease), transform .3s var(--ease-out);
}
.cta-primary:hover { opacity: .85; transform: translateY(-2px); }

/* ============================================================
   Scroll-Reveal
   ============================================================ */
.reveal, .fade-in,
.reveal-stagger > * {
  opacity: 0;
  transform: translateY(2.4rem);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
}
.reveal.visible, .fade-in.visible,
.reveal-stagger.visible > * {
  opacity: 1;
  transform: none;
}
.reveal-stagger.visible > *:nth-child(2) { transition-delay: .12s; }
.reveal-stagger.visible > *:nth-child(3) { transition-delay: .24s; }
.reveal-stagger.visible > *:nth-child(4) { transition-delay: .36s; }
.reveal-stagger.visible > *:nth-child(5) { transition-delay: .48s; }
.reveal-stagger.visible > *:nth-child(6) { transition-delay: .6s; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1100px) {
  .offer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-toggle { display: block; }

  .hero { height: 118vh; }
  .hero-title { font-size: 11.6vw; }
  .hero-illu { height: min(20vh, 18rem); }
  .hero-inner { gap: 3vh; top: 29vh; }

  .split, .split--rev { grid-template-columns: 1fr; gap: 4rem; }
  /* Gleiche Innenabstaende oben wie unten - vorher stand unter dem Video
     deutlich mehr Luft als darueber. Und kompakter als die vollen --space-m
     (10rem): am schmalen Schirm fallen die Sektionen sonst auseinander,
     besonders die beigen auf den Unterseiten. */
  .section-pad { padding: 6.5rem var(--gap); }
  .split--gross .split-media { margin-bottom: 0; }
  .split--rev .split-text { order: 1; }
  .split--rev .split-media { order: 2; }
  .split-media img { min-height: 46rem; }

  .photo-hello { height: 80vh; }
  .photo-hello h2 { font-size: var(--text-m); }

  /* Einspaltig: groessere Schrift, dafuer engere Reihen - sonst wird der
     Footer auf dem Handy unnoetig lang. */
  .footer-grid { grid-template-columns: 1fr; row-gap: 2.6rem; }
  .footer-grid p, .footer-grid li { font-size: var(--text-s); line-height: 1.45; margin-bottom: .5rem; }
  .footer-label { margin-bottom: .8rem; }
  .footer-spalte p + p { margin-top: .7rem; }
  .footer-bottom { margin-top: 3.4rem; gap: .6rem; }
  .footer-bottom p { font-size: var(--text-xs); }
  body > footer { padding: var(--space-m) var(--gap); }
  .footer-grid { padding-top: 0; border-top: none; }
  .kontakt-grid { grid-template-columns: 1fr; gap: 6rem; }
  .subsidy-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .offer-grid { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
  .footer-word { font-size: 13vw; }
  .cta-band { flex-direction: column; align-items: flex-start; }
}

/* ============================================================
   Reduced Motion (DESIGN.md 3.4.5)
   Bewusst SCHMAL gehalten: alle grossen Effekte der Seite sind an den
   Scrollfortschritt gekoppelt - sie bewegen sich nur, wenn und so schnell
   der Nutzer selbst scrollt, und stehen still, sobald er stoppt. Solche
   Effekte laufen wie auf der Referenzseite fuer alle. Hintergrund: iOS
   meldet "Bewegung reduzieren" auch ueber Umwege (Pro-App-Einstellung,
   Energiesparmodus mancher Versionen) - der fruehere Komplett-Ausstieg
   zeigte dann kommentarlos das fertige Endbild ohne jede Animation.
   Abgeschaltet wird nur, was von selbst laeuft. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero-scroll-hint { animation: none; }
  .media-loop { animation: none; }
}

/* Zugang zur Inhaltsverwaltung in der Fusszeile: nur ein kleines Schloss,
   bewusst zurueckhaltend neben den Rechtslinks. */
.fuss-schloss {
  display: inline-flex;
  align-items: center;
  /* Mittig zur Textzeile: ohne das sitzt das Symbol auf der Schriftlinie
     und wirkt dadurch zu hoch. */
  vertical-align: middle;
  margin: 0;
  padding: .6rem;            /* unsichtbare Trefferflaeche fuers Antippen */
  color: inherit;
  opacity: .45;
  transition: opacity .2s var(--ease-out);
}
.fuss-schloss:hover,
.fuss-schloss:focus-visible { opacity: 1; }
/* Symbol klein; die Trefferflaeche macht das unsichtbare Polster (padding).
   Ein Pixel nach oben: mathematisch mittig wirkt neben Kleinbuchstaben mit
   Unterlaengen (p, y) eine Spur zu tief. */
.fuss-schloss svg { width: 1.25rem; height: 1.25rem; transform: translateY(-1px); }
@media (max-width: 900px) {
  /* Am Handy unsichtbar groesser: Fingerkuppen brauchen rund 44px. */
  .fuss-schloss { padding: 17px; margin-left: 0; }
}
