/* =========================================================================
   Leator — Basis + Trichter-Szene
   Farbskala ist final: nur diese vier Töne, keine weiteren Farbthemen.
   ========================================================================= */

/* ------------------------------------------------------------- Webfonts */
/* Die vier Schriften liegen auf DIESEM Server (assets/fonts/), nicht bei
   Google. Das ist kein Geschmack, sondern Datenschutz: eine eingebundene
   Google-Schrift laesst den Browser jedes Besuchers eine Verbindung zu
   fonts.gstatic.com aufbauen und dabei seine IP-Adresse an Google in den USA
   uebertragen — ein Drittlandtransfer, der in der Datenschutzerklaerung
   offengelegt und begruendet werden muesste. Lokal eingebunden entfaellt das
   ersatzlos: die Seite laedt ueberhaupt nichts von fremden Servern, und der
   entsprechende Satz in der Erklaerung ist wieder wahr.

   Geholt sind nur die Schnitte, die auch gebraucht werden, und davon nur die
   Latin-Untermengen — zusammen 150 KB, wovon ein deutscher Text nur die
   "latin"-Dateien anfasst (rund 90 KB). Die "latin-ext"-Dateien laedt der
   Browser nur, wenn ein Zeichen daraus vorkommt; sie liegen fuer Namen mit
   osteuropaeischer Diakritik bereit und kosten sonst nichts.

   Wer eine Schrift, einen Schnitt oder eine Sprache ergaenzt, holt die Datei
   nach — tools/schriften-holen.py macht genau das und schreibt diesen Block
   neu. Nicht wieder auf die Google-URL zurueckstellen, sonst ist der Punkt
   "keine Drittanbieter" in der Datenschutzerklaerung falsch.

   Raleway 400 und 500 zeigen auf dieselbe Datei: Google liefert die Schrift
   als variablen Schnitt aus, eine Datei traegt beide Gewichte. Die Angaben
   sind wortgleich uebernommen, damit der Browser exakt dasselbe waehlt wie
   vorher ueber Google. */
/* Raleway 400 — latin-ext */
@font-face{
  font-family: 'Raleway';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/raleway-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Raleway 400 — latin */
@font-face{
  font-family: 'Raleway';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/raleway-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Raleway 500 — latin-ext */
@font-face{
  font-family: 'Raleway';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/raleway-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Raleway 500 — latin */
@font-face{
  font-family: 'Raleway';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/raleway-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Cormorant Garamond 400 kursiv — latin-ext */
@font-face{
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/cormorant-garamond-400-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Cormorant Garamond 400 kursiv — latin */
@font-face{
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/cormorant-garamond-400-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Poiret One 400 — latin-ext */
@font-face{
  font-family: 'Poiret One';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/poiret-one-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Poiret One 400 — latin */
@font-face{
  font-family: 'Poiret One';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/poiret-one-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Jost 200 — latin-ext */
@font-face{
  font-family: 'Jost';
  font-style: normal;
  font-weight: 200;
  font-display: swap;
  src: url('../assets/fonts/jost-200-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Jost 200 — latin */
@font-face{
  font-family: 'Jost';
  font-style: normal;
  font-weight: 200;
  font-display: swap;
  src: url('../assets/fonts/jost-200-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root{
  --creme:    #F3E9DD;   /* hellste Stufe — Hintergrund */
  --hell:     #E6D5C1;   /* helle Stufe — Flächen, Trennlinien */
  --akzent:   #A67C52;   /* mittlere Stufe — Akzent, Buttons */
  --kontrast: #6B4E3D;   /* dunkelste Stufe — Text */

  --nav-h: 62px;

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans:  "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
}

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

html{ background: var(--creme); }

body{
  margin: 0;
  /* KEIN eigener Hintergrund: html traegt ihn (oben) und faerbt damit die
     Leinwand. Am body waere er nur eine Wiederholung — und eine schaedliche:
     er wuerde die Hintergrundebene des Mittelteils (.flow-bg, z-index -1)
     zudecken. Negative z-index-Ebenen liegen unter den Hintergruenden der
     Elemente im Fluss, aber ueber der Leinwand. */
  color: var(--kontrast);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3{
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

a{ color: inherit; }

/* ------------------------------------------------------------------ Buttons */
.btn{
  display: inline-block;
  background: var(--akzent);
  color: var(--creme);
  text-decoration: none;
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.01em;
  padding: 14px 26px;
  border-radius: 999px;
  transition: background .22s ease, transform .22s ease;
}
/* Nur fuer Geraete mit echtem Zeigegeraet. Auf einem Touchscreen gibt es kein
   Schweben: der Browser setzt den Hover-Zustand beim Antippen und laesst ihn
   danach stehen, bis woanders hingetippt wird — der zuletzt benutzte Knopf
   sieht dann dauerhaft gedrueckt aus. Der Ersatz ist :active weiter unten.
   Fuer Maus und Trackpad aendert die Umhuellung nichts. */
@media (hover: hover){
  .btn:hover{ background: var(--kontrast); transform: translateY(-1px); }
}
.btn-sm{ font-size: 14px; padding: 9px 18px; }
.btn-lg{ font-size: 17px; padding: 17px 34px; }

/* --------------------------------------------------------------- Navigation */
/* Von Anfang an sichtbar, schmal, ohne eigene Auftritts-Animation. */
.nav{
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--nav-h);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(20px, 4vw, 52px);
  background: color-mix(in srgb, var(--creme) 84%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in srgb, var(--kontrast) 10%, transparent);
}
.nav-brand{
  font-family: var(--serif);
  font-size: 25px;
  letter-spacing: 0.04em;
  text-decoration: none;
}
.nav-right{ display: flex; align-items: center; gap: clamp(18px, 2.4vw, 34px); }
.nav-right a{ font-size: 15px; text-decoration: none; opacity: .72; transition: opacity .2s ease; }
@media (hover: hover){
  .nav-right a:hover{ opacity: 1; }
}
.nav-right .btn{ opacity: 1; }

/* ====================================================================== */
/*  Trichter-Szene (drei Bloecke + fixe Buehne)                           */
/*  Spacer geben nur Scrollstrecke (Hoehe von funnel.js), die fixe .stage  */
/*  haengt immer im Viewport und wird aus der Scrollposition angesteuert.  */
/* ====================================================================== */
.scene-spacer{ position: relative; }
.band-flow{ position: relative; }
/* Fallback-Hoehen, damit der Mittelteil nicht vor dem ersten measure() kurz
   oben aufblitzt; funnel.js setzt die exakten Werte (EXPLODE_VH + Naht 1 bzw.
   Outro-Spacer). */
#sceneIntro{ height: 300vh; }
#sceneOutro{ height: 180vh; }

/* Fixe Buehne: immer im Viewport, ueber dem Dokumentinhalt (z-index 40, unter
   der Nav 100). pointer-events:none, damit im Mittelteil (Buehne unsichtbar)
   der Toggle im Fluss klickbar bleibt; interaktive Kinder (CTAs) setzen selbst
   wieder auto. Deckkraft steuert funnel.js als Master ueber alle Kinder —
   startet bei 0, wird beim ersten Frame hochgelerpt (Ersatz fuer .ready). */
.stage{
  position: fixed;
  inset: 0;
  overflow: hidden;
  z-index: 40;
  pointer-events: none;
  opacity: 0;
}

/* ------------------------------------------------------------- Glas */
/* Eine Machart, zwei Orte: Hero und Outro. Bewusst als gemeinsame Klasse und
   nicht zweimal abgeschrieben — so bleiben Blur, Transparenz, Rand und Radius
   garantiert gleich, wenn an einer Stelle nachjustiert wird. */
:root{ --glass-radius: 26px; }

.glass{
  border-radius: var(--glass-radius);
  /* Helle Cremeglasfläche. Bewusst niedrig deckend — das Glas soll den
     Hintergrund durchscheinen lassen, nicht zudecken. */
  background: color-mix(in srgb, var(--creme) 20%, transparent);
  /* -webkit- muss mit: ohne das Präfix ist der Effekt in Safari nicht da,
     und das Panel wäre dort eine fast unsichtbare Fläche. */
  -webkit-backdrop-filter: blur(20px) saturate(115%);
  backdrop-filter: blur(20px) saturate(115%);
  /* Ohne die helle Kante liest man es nur als Unschärfe, nicht als Glas. */
  border: 1px solid color-mix(in srgb, #fff 42%, transparent);
  /* Weicher Schatten: das Panel soll vor dem Hintergrund schweben. */
  box-shadow:
    0 24px 60px -18px color-mix(in srgb, var(--kontrast) 34%, transparent),
    0 2px 10px color-mix(in srgb, var(--kontrast) 10%, transparent);
}

/* -------------------------------------------------- Hero-Hintergrund */
/* Nur Phase 0/1. Unterste Ebene der Bühne, unter dem Trichter (z-index 2).
   Deckkraft UND Position setzt funnel.js: der Hintergrund wandert am Übergang
   nach oben aus dem Bild (statt nur zu faden), danach steht wieder die flache
   Cremefläche des body, der Rest der Sequenz bleibt also unverändert. */
.hero-bg{
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--creme) url("../assets/hero-bg.jpg") center / cover no-repeat;
  will-change: opacity, transform;
}

/* ------------------------------------------------- Outro-Hintergrund */
/* Gegenstück zu .hero-bg, gleiche Ebene und gleiche Machart. Die beiden
   überlappen zeitlich nie, deshalb brauchen sie keine eigene z-Ebene.
   Wandert beim Reassemble von unten herauf in Position (Gegenstück zur
   Hero-Bewegung), Deckkraft und Position kommen von funnel.js. */
.outro-bg{
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  background: var(--creme) url("../assets/outro-bg.jpg") center / cover no-repeat;
  will-change: opacity, transform;
}

/* -------------------------------------------- Hintergrund des Mittelteils */
/* Der Grund, auf dem die fuenf Stufen liegen. Bis hierher stand dort die flache
   Cremeflaeche: .hero-bg faehrt am Ende der Fokus-Phase nach oben aus dem Bild,
   .outro-bg kommt erst zum Schluss von unten herauf, und dazwischen war nichts.
   Liegt bewusst AUSSERHALB von .stage und nicht als dritte Ebene darin: die
   Deckkraft der Buehne ist im Mittelteil 0, dort waere die Ebene unsichtbar.
   z-index -1 statt 0: eine positionierte Ebene mit z-index 0 laege ueber dem
   Inhalt im Fluss und wuerde Karten und Baender zudecken. Mit -1 liegt sie
   darunter — und ueber der Leinwand, deren Farbe html setzt (siehe body).
   position:fixed und nicht background-attachment:fixed am body: das kippt auf
   iOS auf "scroll" um, und der Ausschnitt richtete sich dann nach der 10 000 px
   hohen Dokumenthoehe statt nach dem Bild.
   Cremefarbe darunter, damit die Flaeche schon steht, bevor das Bild da ist. */
.flow-bg{
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--creme) url("../assets/flow-bg.jpg") center / cover no-repeat;
  pointer-events: none;
}

/* ------------------------------------------------------------------- Hero */
/* .hero IST das Glaspanel — ein Element für Kicker, Headline, Subline und
   Button. Damit verschwindet der ganze Block über heroOp zeitgleich, ohne
   getrennte Timings. Ersetzt den früheren radialen Cremeschleier. */
.hero{
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(760px, 84vw);
  padding: clamp(34px, 4.4vw, 52px) clamp(26px, 4vw, 54px) clamp(30px, 4vw, 46px);
  text-align: center;
  z-index: 6;
  will-change: transform, opacity;
}
.hero-kicker{
  margin: 0 0 20px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Auf dem Glaspanel kam --akzent nur auf 2,2:1 — für Text dieser Größe zu
     wenig. Dunkelster Ton der Palette statt Akzent; Größe, Laufweite und
     Position bleiben unverändert. */
  color: var(--kontrast);
}
/* Die Hero-Headline ist die einzige Stelle mit einer eigenen Schrift. Gewuenscht
   war der Charakter der Kauf-Schrift "Santiago" (Sensatype) — sehr leicht, breit,
   luftig, einstoeckiges a. Poiret One ist die naechstliegende freie
   freie Entsprechung. Verglichen wurde mit Jost 300, Josefin Sans
   300, Tenor Sans, Gruppo und Raleway 200 (tools/hero-schrift.html stellt die
   Proben nebeneinander); Poiret One traf Breite und Leichtigkeit am besten.
   Fallback ist die Sans der Seite und NICHT --serif: laedt die Schrift nicht,
   soll die Zeile leicht bleiben und nicht in einen anderen Charakter kippen.

   Die Laufweite wird dabei von negativ auf leicht positiv gedreht. Die -0.012em
   der geteilten h1/h2/h3-Regel sind fuer die Serifenschrift gerechnet; eine
   duenne Display-Sans zieht sich damit zusammen, und genau die Luft zwischen
   den Buchstaben macht bei dieser Schriftgattung den Auftritt (die Vorlage
   steht ebenfalls weit). */
.hero h1{
  font-family: "Poiret One", var(--sans);
  font-size: clamp(34px, 4.0vw, 60px);
  letter-spacing: 0.01em;
}
.hero-sub{
  margin: 24px auto 0;
  max-width: 61ch;
  /* Raleway wie der Fliesstext der fuenf Stufenkarten (.s1-static-sub und
     Geschwister). Der Hero-Satz hat dieselbe Aufgabe wie die dort: er erklaert
     die Zeile darueber. Vorher lief er in der System-Sans, was ihn von den
     Karten abgesetzt hat, ohne dass es dafuer einen Grund gab. */
  font-family: "Raleway", var(--sans);
  font-size: 17.5px;
  /* Auf der flachen Cremefläche war .82 unproblematisch; auf dem Glas fiel der
     Kontrast damit auf 2,4:1 und lag unter den 4,5:1, die Fließtext braucht.
     Voller Kontrastton statt aufgehellt. */
}
.hero-actions{
  margin-top: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 26px;
  flex-wrap: wrap;
}

/* ------------------------------------ Die zwei Woerter, die den Trichter flankieren */
/* "UNSER" (links) und "SERVICE" (rechts), weiss, sehr gross, HINTER dem Trichter
   (z-index 1) auf seiner Mittelhoehe. funnel.js blendet sie ein, wenn das
   Hero-Panel das Wort abgibt; danach stehen sie voll da, ueber den ganzen Explode.
   Sobald der letzte Abteil geloest ist (Ende der Explode-Phase), fahren sie als
   Teil der Scrollbewegung nach oben aus dem Bild (--leistung-up) - kein Verblassen.
   Hier steht nur, wie sie aussehen; das Timing steht in funnel.js.

   Layout: die Box laeuft ueber die volle Breite, die beiden Woerter werden per
   space-between nach aussen geschoben, der Trichter steht mittig dazwischen (und
   davor). Kein einziger Wert haengt an der Trichterbreite - die Woerter stehen
   einfach am Rand, der Trichter fuellt die Mitte. Bei breiten Fenstern (>= ~1280)
   stehen beide frei neben ihm; wird das Fenster schmaler, wird der Trichter
   relativ breiter und "Service" (das laengere Wort) taucht mit seiner Innenkante
   ein Stueck hinter ihn - unkritisch, es liegt ja ohnehin dahinter.

   Zur Groesse: 6.5vw bei Jost 200 / 0.10em Laufweite. Groesser wuerde "Service"
   auf mittleren Breiten zu weit hinter den Trichter schieben; kleiner verliert die
   Zeile an Praesenz.

   white-space:nowrap pro Wort (siehe .l-wort): jedes Wort bleibt ein Block, keins
   bricht um. */
.leistung{
  position: absolute;
  left: 50%;
  top: 50%;
  /* HINTER dem Trichter (z-index 1, der Trichter liegt auf 2), auf seiner
     Mittelhoehe. Kein Verblassen: --leistung-up faehrt die Woerter beim Scrollen
     nach oben aus dem Bild (funnel.js), sie sind also Teil der Scrollbewegung und
     verschwinden ueber die obere Kante statt zu faden. */
  transform: translate(-50%, calc(-50% - var(--leistung-up, 0px)));
  z-index: 1;
  margin: 0;
  /* "Unser" links, "Service" rechts, der Trichter mittig dazwischen (und davor).
     Trick fuer symmetrische Innenkanten UNABHAENGIG von der Wortbreite: jedes Wort
     bekommt eine halbe Zeile (flex:1), "Unser" rechtsbuendig, "Service"
     linksbuendig (siehe .l-wort). Dazwischen eine feste Luecke (gap), die etwas
     breiter ist als der Trichter an seiner breitesten Stelle (oberer Rand). Die
     Innenkanten liegen damit exakt bei Mitte +/- gap/2 - egal wie unterschiedlich
     lang die Woerter sind. (Mit justify-content:center + gap kippte das: die
     breitere "Service" schob beide Innenkanten nach links, sie ueberlappte den
     Trichter.)
     41vw ist an der breitesten sichtbaren Trichterphase (Fokus ~0.78, Box ~570 px
     bei 1490) eingemessen und per Screenshot geprueft: ~21 px Luft links UND rechts
     (symmetrisch). Bei 1280 sind es ~9 px; darunter taucht die Innenkante hinter
     den Trichter - unkritisch, der Text liegt ja dahinter. Groesser = mehr Abstand,
     kleiner = die Innenkanten kuessen frueher den Rand. */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 41vw;
  font-family: "Jost", var(--sans);
  font-weight: 200;
  font-size: 6.5vw;
  line-height: 1.06;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: #fff;
  /* Ein dunkler Schein hinter der Schrift. Kein Schatten im ueblichen Sinn - er
     hat keinen Versatz, man sieht ihn nicht als Hof; er senkt nur den Grund
     unmittelbar hinter den Buchstaben ab.
     Gebraucht wird er, weil der Stoff im Hintergrund nach rechts sehr hell
     wird. Gemessen am gerenderten Bild, Grund im Umkreis von 6 px um die
     Striche:
                          links     rechts
         ohne Schein      3,23      1,85
         weit und weich   3,64      2,11      (38 px Radius)
         eng und kraeftig 4,08      2,48      (10 px Radius)   <- steht hier
     Der Radius ist dabei der entscheidende Wert, nicht die Deckkraft: bei
     duennen Strichen verteilt ein grosser Radius dieselbe Farbe auf so viel
     Flaeche, dass davor kaum etwas ankommt. Eng gesetzt wirkt er, ohne als
     Hof aufzufallen.
     Die 3,0 werden auf der hellsten Stelle rechts trotzdem nicht erreicht -
     dazu muesste der Grund selbst abgedunkelt werden, siehe Notiz beim Nutzer.
     Die Schriftfarbe bleibt reines Weiss. */
  text-shadow: 0 0 10px rgba(75, 52, 38, .90),
               0 0 26px rgba(75, 52, 38, .55);
  opacity: 0;
  pointer-events: none;
  will-change: opacity, transform;
}
/* Jedes Wort bekommt eine halbe Zeile (flex:1), damit die Innenkanten
   symmetrisch bei Mitte +/- gap/2 liegen - unabhaengig davon, dass "Service"
   breiter ist als "Unser". "Unser" rechtsbuendig (Innenkante rechts), "Service"
   linksbuendig (Innenkante links). nowrap: keins bricht um. min-width:0, damit die
   flex:1-Haelften wirklich gleich breit werden und nicht an der Wortbreite haengen. */
.leistung .l-wort{ flex: 1 1 0; min-width: 0; white-space: nowrap; }
.leistung .l-wort:first-child{ text-align: right; }
.leistung .l-wort:last-child{ text-align: left; }

/* --- Telefon: die Woerter uebereinander ---------------------------------
   Das Nebeneinander lebt davon, dass links und rechts des Trichters Platz
   ist. Auf 390 px gibt es den nicht: nachgemessen bleiben von "UNSER" nur das
   U und von "SERVICE" nur das ICE stehen, alles dazwischen liegt hinter dem
   Trichter. Also uebereinander.

   Gestapelt reicht die Mittellage aber nicht mehr: dort ist der Trichter am
   breitesten und deckt beide Zeilen vollstaendig zu (ausprobiert, es blieben
   zwei weisse Splitter an den Raendern). Nach vorne holen half auch nicht —
   die Frame-Sequenz liegt darueber. Deshalb `top: 78%`: die Zeilen stehen
   unter dem Trichter, dort wo er sich zur Tuelle verjuengt und seit dem
   Breitendeckel ohnehin Platz frei wird. Der Auslauf greift dabei leicht in
   "UNSER" hinein, was die beiden zusammenbindet, statt sie zu trennen.

   Die Groesse steigt kraeftig mit (6.5vw -> 15vw): gestapelt hat jede Zeile
   die volle Breite statt einer knappen Haelfte, und bei 6.5vw waeren die
   Woerter auf dem Telefon 25 px hoch — als Bildmarke zu wenig.

   Nur unterhalb 640 px. Der Desktop laeuft unveraendert im Nebeneinander. */
@media (max-width: 640px){
  .leistung{
    flex-direction: column;
    align-items: center;
    /* Ueber die volle Bildhoehe aufgespannt und die beiden Woerter an die
       Enden geschoben: "UNSER" steht damit ueber dem Trichter, "SERVICE"
       darunter. 78vh ist gemessen, nicht geschaetzt — der Trichter ist auf dem
       Telefon rund 385 px hoch und mittig, bei 844 px Bildhoehe bleiben oben
       und unten je rund 60 px, in denen eine Zeile Platz hat. Groesser, und
       die Woerter stossen an Navigation und Bildkante; kleiner, und sie
       ueberlappen den Trichter wieder. */
    height: 78vh;
    justify-content: space-between;
    gap: 0;
    font-size: 15vw;
    top: 50%;
  }
  .leistung .l-wort{ flex: 0 0 auto; }
  .leistung .l-wort:first-child,
  .leistung .l-wort:last-child{ text-align: center; }
  /* SERVICE eine Spur hoeher. Nachgemessen bei 390x844 stand die Unterkante
     auf 751 px — nur 93 px ueber dem Bildrand, und auf dem Geraet liegt in
     diesem Streifen die Adressleiste des Browsers. Das Wort stand damit
     praktisch auf ihr auf. 4vh (34 px) hoeher: Unterkante 717, Abstand zum
     Trichterauslauf (617) 38 px — also fast derselbe Abstand, den UNSER
     nach oben zum Trichter hat (72 px oben, aber dort ist der Trichter am
     breitesten und UNSER steht frei).
     Bewusst nur das zweite Wort und nicht ueber die Blockhoehe geloest:
     `height` bewegt beide Zeilen gegeneinander, UNSER sitzt aber richtig. */
  .leistung .l-wort:last-child{ transform: translateY(-4vh); }
}

/* Kein schmale-Fenster-Sonderfall mehr noetig: die Woerter flankieren den
   Trichter links und rechts und stehen damit ohnehin frei neben ihm - auf jeder
   Breite. (Bei sehr schmalen Fenstern ist der Trichter breiter als das Fenster;
   dann ruecken die Woerter nah an die Raender, bleiben aber lesbar.) */

/* ---------------------------------------------------------------- Trichter */
/* Der geschlossene Trichter. Sein Zuschnitt stammt aus derselben Box wie die
   gemessene Ring-Geometrie, deshalb übernehmen die Bänder im Explode seine
   Silhouette ohne Versatz. */
.funnel{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  will-change: transform, opacity, filter;
}
.funnel-img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* ----------------------------------------------------------- Frame-Sequenz */
/* Liegt zwischen dem geschlossenen Trichter (z-index 2) und den Bändern (4).
   Größe und Lage setzt funnel.js so, dass der letzte Frame deckungsgleich auf
   Band 1 in Banner-Position liegt. */
.funnel-video{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transform-origin: 0 0;   /* funnel.js positioniert über translate + scale */
  will-change: opacity, transform;
}

/* -------------------------------------------- Beschriftung der Ringe */
/* Liegt über der Sequenz. Lage, Größe und Deckkraft setzt funnel.js je Frame
   aus der gemessenen Ring-Spur; hier steht nur, wie sie aussieht. */
.ring-labels{
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}
.ring-label{
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--kontrast);
  white-space: nowrap;
  opacity: 0;
  will-change: transform, opacity;
}

/* ------------------------------------------------------------------ Bänder */
.bands{
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}

.band{
  position: absolute;
  left: 0;
  top: 0;
  will-change: transform, opacity;
}
/* Nur dieses Element wird skaliert — Text bleibt dadurch unverzerrt. */
.band-shape{
  display: block;
  width: 100%;
  height: 100%;
  will-change: transform;
}
.band-label{
  position: absolute;
  left: 0;
  width: 100%;
  text-align: center;
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--kontrast);
  white-space: nowrap;
  will-change: opacity;
}


/* -------------------------------------------- Mittelteil: Fluss-Sektionen */
/* Jede Sektion ~1 Viewport; funnel.js setzt die genaue Hoehe (SECTION_VH),
   hier der Fallback. Band bzw. Karte ist bei ~23vh / mittig verankert. */
/* Hoehe kommt von funnel.js in px. Hier nur der Startwert fuer das erste
   Bild — bewusst height und NICHT min-height: min-height wuerde die von JS
   gesetzte Hoehe ueberstimmen, sobald 100vh und innerHeight auseinanderlaufen
   (Headless-Chrome, mobile Adressleiste). Dann saessen die Dokument-Baender
   tiefer als die fixe Buehne rechnet, und Naht 1 traefe nicht mehr. */
.flow-section{
  position: relative;
  height: 100vh;
}
/* Sektion 1 braucht keine eigene Regel mehr: ihre Karte liegt wie alle anderen
   absolut in der Sektion, funnel.js setzt die Lage. Vorher zentrierte hier ein
   flex-Container — dann haette aber die Sektionshoehe die Kartenlage
   mitbestimmt, und genau die muss frei sein, damit der Abstand zum naechsten
   Banner ueberall gleich sein kann. */
/* Baender 2-5: einfache Platzhalter-Boxen (Bild + Label + Caption) an der
   Banner-Position. Breite, Bandmitte und Beschriftungslage setzt funnel.js in
   px — und zwar mit denselben Formeln wie fuer die Baender der Sequenz. Das ist
   nicht Kosmetik: an Naht 1 loest das Sequenz-Band 1 das Dokument-Band ab, und
   die Staffelung aller Stufen haengt an genau diesen Formeln — laufen die
   beiden Seiten auseinander, stimmen Abstaende und Ruhelagen nicht mehr.
   Die Werte hier sind der Startwert fuers erste Bild. */
.flow-band{
  position: absolute;
  top: 23vh;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(900px, 82vw);
}
.flow-band-img{ display: block; width: 100%; height: auto; }
/* Bis auf den Namen identisch mit .band-label — dieselbe Lage, dieselbe
   Groesse, gesetzt von funnel.js. */
.flow-band-label{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  text-align: center;
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--kontrast);
  white-space: nowrap;
}


/* ------------------------------------------------- Stufe-1-Karte + Toggle */
/* Grosse, nahezu bildschirmfuellende Glaskarte (wie das Nike-Referenzpanel),
   jetzt im Dokumentfluss (Sektion 1 des Mittelteils). Nutzt .glass unverändert
   (Blur, Radius, Rand) — nur der Hintergrund wechselt im Video-Zustand auf die
   Akzentfläche. Toggle sitzt oben mittig, Rest der Karte bleibt bewusst leer. */
/* Gemeinsames Mass aller Stufenkarten. Die Karten der Stufen 2-5 muessen
   dieselbe Groesse haben wie die der Stufe 1 — an ihr haengt die Staffelung:
   funnel.js rechnet Abstand zum Banner und Ruhelage aus der gemessenen
   Kartenhoehe, und die Sektionen 2-5 sind genau so hoch, dass die Karte dort
   dieselbe Ruhelage erreicht wie die Stufe-1-Karte. */
.stage1-card, .flow-card{
  width: min(1100px, 92vw);
  height: min(82vh, 820px);
  padding: clamp(38px, 6.5vh, 76px) clamp(24px, 4vw, 48px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}
/* Alle Stufenkarten liegen absolut in ihrer Sektion — die Lage setzt funnel.js
   in px, damit sie an denselben Formeln haengt wie die Naehte und nicht an
   vh-Werten im Stylesheet. Inhalt der Karten 2-5 kommt spaeter, deshalb leer. */
.stage1-card, .flow-card{
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

/* Inhaltsflaeche einer Stufenkarte. Fuellt den Rest der Karte unter dem, was
   oben fest sitzt (bei Stufe 1 der Toggle), und zentriert ihren Inhalt.
   Steht hier bei der Kartengeometrie und nicht in einem Stufen-Abschnitt, weil
   Stufe 1 und 2 sie teilen: die Karten sind gleich gross und ruhen an derselben
   Stelle im Bild — begaenne ihr Inhalt jeweils woanders, fiele beim Scrollen
   von Stufe zu Stufe der Sprung auf.
   min-height:0 ist Pflicht, nicht Kosmetik: die Kartenhoehe ist fest
   (min(82vh,820px)) und funnel.js liest sie fuer die Stufen-Staffelung — der
   Slot darf sie also nicht ueber flex sprengen. */
.card-slot{
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  display: flex;
  /* Oben ausgerichtet und nicht mittig: der Inhalt beginnt dicht unter der
     Kartenoberkante. */
  align-items: flex-start;
  justify-content: center;
}
/* Karten 2 und 4 stapeln, statt eine zentrierte Spaltengruppe zu tragen: oben
   die Ueberschrift quer ueber die ganze Karte, darunter erst das Zwei-Spalten-
   Layout. justify-content muss dabei auf flex-start, weil die Hauptachse jetzt
   senkrecht laeuft — sonst zentrierte die geerbte Regel den Inhalt vertikal
   statt ihn oben beginnen zu lassen. align-items:center haelt Ueberschrift und
   Spaltengruppe waagerecht mittig. */
.card-slot--stack{
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}
.stage1-card{
  /* Sanfter Farbwechsel der Kartenfläche beim Umschalten auf Video. */
  transition: background .34s ease;
  /* Der Toggle sitzt näher an der Oberkante als der allgemeine Innenabstand
     der Karten vorgibt. Bewusst nur hier und nicht in der gemeinsamen Regel:
     der Innenabstand der Karten 2-5 soll für den späteren Inhalt gelten und
     nicht davon abhängen, wo dieser eine Knopf steht. */
  padding-top: clamp(24px, 4vh, 48px);
}
/* Video-Zustand: die Karte nimmt einen warmen Akzentton an — getönt, nicht
   flächig gefärbt. Die Deckung ist nicht Geschmack: der Schein des Toggles ist
   im Video-Zustand selbst #A67C52 (Nutzer-Vorgabe), und auf einer satt
   akzentgefärbten Fläche wäre er unsichtbar. Bei dieser Tönung trägt er, und
   die Beschriftung bleibt im dunklen Ton lesbar. */
.stage1-card[data-state="video"]{
  background: color-mix(in srgb, var(--akzent) 20%, transparent);
}
/* Im Video-Zustand traegt die Pille etwas heller auf. Nicht Geschmack: die
   Beschriftung steht darauf im dunklen Ton, und auf der getoenten Karte mit
   dem Akzentschein dahinter kam sie sonst nur auf 3,0:1. Gemessen an der
   gerenderten Seite: mit diesem Auftrag 4,6:1 (gefordert sind 4,5:1). */
.s1-toggle[data-state="video"] .s1-track{
  background: color-mix(in srgb, #fff 36%, transparent);
}

/* Pill-Toggle im Glas-Look (Machart der Referenz-Vorlage): eine Glaskugel
   gleitet von links (Static) nach rechts (Video), traegt das Symbol des aktiven
   Zustands und ist GROESSER als die Pille — sie ragt oben, unten und ueber
   deren Ende hinaus. Genau das macht den Effekt: die Kugel liegt sichtbar VOR
   der Flaeche, statt in ihr zu sitzen. Deshalb ist der Knopf nur die Buehne
   (ohne eigene Flaeche), und Schein, Pille, Beschriftung und Kugel sind eigene
   Ebenen in dieser Reihenfolge.
   Farben sind die Palettentoene, keine neuen: der Schein hinter der Pille
   wechselt mit dem Zustand die Seite der Skala, damit er auf beiden
   Kartenhintergruenden traegt (Akzent auf der hellen Karte, Hell auf der
   akzentgefaerbten). */
.s1-toggle{
  /* Alle vier Masse haengen zusammen und wurden gemeinsam um den Faktor 0,9
     verkleinert (vorher 44/60/18/190). Wer weiter aendert, sollte sie wieder
     gemeinsam anfassen — die Verhaeltnisse untereinander tragen den Effekt,
     nicht die absoluten Werte. Beim Verkleinern gehoert das scale des Filters
     #s1-liquid in index.html dazu: es ist an den Kugelradius gebunden. */
  --h: 40px;         /* Hoehe der Pille */
  --bubble: 54px;    /* Durchmesser der Glaskugel (1.35 x Pillenhoehe) */
  /* Ueberstand ueber das linke Pillenende. Nicht frei gewaehlt: durch die Kugel
     sieht man das runde Ende der Pille (in der Vorlage ist das der
     Brechungseffekt). Liegen beide Mittelpunkte uebereinander, liest es als
     konzentrischer Doppelkreis; erst ein Versatz macht daraus den Bogen, der
     durch die Kugel laeuft.
     Gerechnet in Koordinaten des Knopfes: die Pille laeuft von 0 bis --w, ihr
     linker Endbogen hat den Mittelpunkt bei h/2 = 20 px. Die Kugel sitzt bei
     left: -over, ihr Mittelpunkt also bei (bubble/2 - over) = 11 px. Bleiben
     9 px Versatz, ein Drittel des Kugelradius — dasselbe Verhaeltnis wie in
     der Vorlage. */
  --over: 16px;
  --w: 171px;
  /* Weg der Kugel: Pillenbreite minus ihr Durchmesser, plus der Ueberstand auf
     beiden Seiten. */
  --slide: calc(var(--w) - var(--bubble) + 2 * var(--over));
  /* Nutzer-Vorgabe: Static hell, Video Akzent. Der helle Schein auf der
     cremefarbenen Karte ist zwangsläufig zurückhaltend — zwei Stufen der
     Palette liegen dort nah beieinander. Deshalb steht die Deckkraft des
     Scheins höher als der Akzentschein sie bräuchte. */
  --glow: var(--hell);
  position: relative;
  width: var(--w);
  height: var(--bubble);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
}
.s1-toggle:focus-visible{
  outline: 2px solid color-mix(in srgb, var(--akzent) 70%, transparent);
  outline-offset: 6px;
  border-radius: 999px;
}

/* Der farbige Schein hinter der Pille — in der Vorlage der lila Blur. Eigene
   Ebene und nicht als box-shadow der Pille, weil er weicher und groesser sein
   muss als deren Kontur und sonst an ihrem Rand abgeschnitten wirkte. */
.s1-glow{
  position: absolute;
  /* Reicht bis unter den Ueberstand der Kugel: dort soll sie im Licht stehen,
     nicht daneben. */
  left: calc(-1 * var(--over));
  right: calc(-1 * var(--over));
  top: 50%;
  height: var(--h);
  transform: translateY(-50%);
  border-radius: 999px;
  background: var(--glow);
  filter: blur(20px);
  /* Deckkraft an der Lesbarkeit ausgerichtet, nicht am Effekt: der Schein liegt
     hinter der ganzen Pille, also auch unter der Beschriftung, und jeder Punkt
     mehr drueckt deren Kontrast. Bei .35 traegt er sichtbar und die Schrift
     bleibt ueber 4,5:1. */
  opacity: .35;
  transition: background .34s ease, opacity .34s ease;
}

/* Die Pille selbst: frostiges Glas. Bewusst KEIN backdrop-filter — Glas auf
   Glas (die Karte hat schon einen) wuerde ueber die ganze Breite truebe. Heller
   Rand und Innenglanz tragen den Glaseindruck. */
/* Gemeinsame Optik von Pille und ihrer Kopie in der Kugel. Beide muessen
   denselben Auftrag haben, sonst faellt die gebrochene Kontur als Fremdkoerper
   auf: was durch das Glas zu sehen ist, ist DIESELBE Pille, nur verbogen.
   Dezentes Milchglas wie die Light/Dark-Vorlage: durchscheinend, NICHT weiss.
   Die Pille nimmt den Ton der Karte auf und traegt nur einen Reflex oben und
   einen Schatten unten. Die Lesbarkeit der Labels loest die zustandsabhaengige
   Textfarbe — nicht ein deckend heller Auftrag.
   Der Rand ist bewusst kraeftiger als die Flaeche: er ist die Linie, aus der
   die Linse den Haken formt. Ist er zu blass, hat die Brechung nichts zu
   verbiegen und die Kugel wirkt leer (so war es vorher). */
.s1-track, .s1-lens-track{
  border-radius: 999px;
  background: color-mix(in srgb, #fff 22%, transparent);
  border: 1.5px solid color-mix(in srgb, #fff 66%, transparent);
  box-shadow:
    inset 0 1.5px 1px color-mix(in srgb, #fff 52%, transparent),
    inset 0 -5px 10px -6px color-mix(in srgb, var(--kontrast) 24%, transparent);
}
/* Zweite, eingerueckte Kontur — in der Vorlage laeuft im Pillenrand eine feine
   Innenlinie mit. Durch die Kugel gesehen wird daraus die zweite Kurve neben
   der Aussenkante; erst zu zweit lesen sie als Flusslinien und nicht als
   einzelner Strich. */
.s1-track::after, .s1-lens-track::after{
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #fff 40%, transparent);
  pointer-events: none;
}
.s1-track{
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--h);
  transform: translateY(-50%);
  /* Der backdrop-filter ist hier vertretbar, wo er es frueher nicht war: die
     Karte dahinter ist flaechig, die Pille wird davon glasig statt truebe. */
  -webkit-backdrop-filter: blur(7px) saturate(1.2);
  backdrop-filter: blur(7px) saturate(1.2);
  /* Aussenschatten nur am Original: an der Kopie in der Kugel wuerde er als
     Schleier ueber dem Glas liegen. */
  box-shadow:
    inset 0 1.5px 1px color-mix(in srgb, #fff 52%, transparent),
    inset 0 -5px 10px -6px color-mix(in srgb, var(--kontrast) 24%, transparent),
    0 6px 16px -10px color-mix(in srgb, var(--kontrast) 40%, transparent);
}

/* Modus-Label steht auf der der Kugel gegenueberliegenden Seite (wie in der
   Vorlage), es ist immer nur das aktive sichtbar: Kugel links -> "Static"
   rechts, Kugel rechts -> "Video" links. */
.s1-mode{
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--kontrast);
  white-space: nowrap;
  opacity: 0;
  transition: opacity .28s ease, color .34s ease;
  pointer-events: none;
}
/* Beide Beschriftungen im dunklen Ton. Die Karte bleibt in beiden Zuständen
   hell (der Video-Zustand ist nur noch getönt), ein helles Label käme darauf
   nicht auf den geforderten Kontrast. */
.s1-mode-static{ right: 23px; }
.s1-mode-video{ left: 23px; }
.s1-toggle[data-state="static"] .s1-mode-static{ opacity: .92; }
.s1-toggle[data-state="video"]  .s1-mode-video{ opacity: .96; }

/* Die Glaskugel. Sie besteht aus wenig: einem Lichtfleck oben links, einer
   harten hellen Kante, dem Spitzlicht (::after) — und dem, was durch sie
   hindurch zu sehen ist. Mehr vertraegt sie nicht, siehe die Hinweise am
   Verlauf und am fehlenden box-shadow weiter unten.
   Der leichte backdrop-filter ist hier vertretbar, wo er es fuer die Pille
   nicht waere: die Kugel ist klein, und was hinter ihr liegt (Karte, Pillenende)
   ist nahezu flaechig — sie wird davon glasig, nicht truebe. */
.s1-bubble{
  position: absolute;
  top: 50%;
  left: calc(-1 * var(--over));
  width: var(--bubble);
  height: var(--bubble);
  margin-top: calc(var(--bubble) / -2);
  border-radius: 50%;
  display: grid;
  place-items: center;
  /* Die MITTE bleibt fast klar — dort sieht man Karte und Pillenende durch —,
     hell wird es nur an der Lichtseite oben links und unten als Streulicht. */
  /* Der Glaskoerper steckt komplett in den Verlaeufen, NICHT in inset-Schatten:
     die zeichnen bei einem Kreis dieser Groesse ihre eigene Kante nach und
     lassen die Kugel als zwei ineinander liegende Kreise lesen (nachgemessen
     an einer Fassung ohne box-shadow — dort war der Effekt weg).
       1. Lichtseite oben links, sonst klar.
       2. Ein Hauch Waerme unten rechts als Gegenlicht.
     Auch ein RINGfoermiger Verlauf ("Licht sammelt sich am Rand") faellt aus:
     seine Farbstopps zeichnen bei diesem Durchmesser wieder einen zweiten
     Kreis. Die Kante macht der Rahmen — schmal, hell, hart. */
  background:
    radial-gradient(72% 72% at 32% 24%,
      color-mix(in srgb, #fff 30%, transparent),
      transparent 48%),
    radial-gradient(60% 60% at 74% 84%,
      color-mix(in srgb, #fff 7%, transparent),
      transparent 56%);
  /* Mattierung des echten Hintergrunds. Der Wert ist nicht Geschmack: er muss
     die UNgebrochene Pillenkante, die hinter der Kugel durchlaeuft, unkenntlich
     machen — sonst stuende sie als gerader Strich neben der gebrochenen Kopie
     und die Kugel zeigte zwei Pillen. Kein url(#s1-liquid) mehr hier: feImage
     liefert im backdrop-filter nichts (siehe Kommentar in index.html), der
     Filter hat den Hintergrund bloss um -scale/2 gleichmaessig verschoben. */
  -webkit-backdrop-filter: blur(5px) saturate(1.3) brightness(1.05);
  backdrop-filter: blur(5px) saturate(1.3) brightness(1.05);
  border: 1px solid color-mix(in srgb, #fff 46%, transparent);
  /* Weiterhin KEIN box-shadow: hinter der durchsichtigen Kugel gezeichnet,
     schiene er durch sie hindurch und legte einen zweiten Kreis in ihre Mitte.
     Praesenz kommt vom Schein hinter der Pille, dem Reflexrand (::before) und
     dem Spitzlicht (::after). */
  /* Kein CSS-Transition auf transform: die Feder-Animation (funnel.js, WAAPI)
     steuert die Bewegung samt Ueberschwinger und Stretch. Im Ruhezustand setzt
     die data-state-Regel die Endlage, dorthin faellt die Kugel nach der
     Animation zurueck (fill:none). transform-origin mittig, damit der Stretch
     symmetrisch ist. */
  transform-origin: center center;
  transition: none;
}
/* --- Was durch die Kugel zu sehen ist ------------------------------------
   Drei Ebenen, weil jede genau eine Aufgabe hat:
     .s1-lens        beschneidet auf die Kreisflaeche (sonst zoege die
                     Verschiebung Bildinhalt ueber den Kugelrand hinaus),
     .s1-lens-warp   traegt den Linsenfilter (Filterregion = diese Box, damit
                     die Map deckungsgleich auf der Kugel liegt),
     .s1-lens-track  die Kopie der Pille, an ihrer echten Stelle.
   Reihenfolge in der Kugel: Verlaeufe (Kugelhintergrund) -> Linse -> Rand und
   Spitzlicht -> Symbol. Die Glasoberflaeche liegt also ueber dem Bild, das
   durch sie hindurch zu sehen ist. */
.s1-lens{
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
}
.s1-lens-warp{
  position: absolute;
  inset: 0;
  filter: url(#s1-liquid);
}
/* Steht im Ruhezustand exakt ueber der echten Pille: die Kugel sitzt um --over
   links von der Pille, die Kopie also um --over rechts vom Kugelrand. Das eine
   Pixel ist der Kugelrahmen, um den die Innenflaeche eingerueckt ist. */
.s1-lens-track{
  position: absolute;
  left: calc(var(--over) - 1px);
  top: calc(50% - var(--h) / 2);
  width: var(--w);
  height: var(--h);
}
/* Reflexrand: ein 1px-Ring als Kegelverlauf, oben links hell, unten gedaempft —
   die harte Glaskante der Vorlage. Als maskierter Ring, damit nur der Rand
   gefaerbt ist und die Mitte klar bleibt (kein zweiter Kreis). */
.s1-bubble::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: 50%;
  padding: 1.25px;
  background: conic-gradient(from 216deg,
    color-mix(in srgb, #fff 88%, transparent),
    color-mix(in srgb, #fff 22%, transparent) 34%,
    color-mix(in srgb, #fff 8%, transparent)  54%,
    color-mix(in srgb, #fff 34%, transparent) 74%,
    color-mix(in srgb, #fff 88%, transparent));
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask-composite: exclude;
  pointer-events: none;
}
/* Spitzlicht oben links, weich und klein — ohne das liest die Kugel als Scheibe. */
.s1-bubble::after{
  content: "";
  position: absolute;
  z-index: 2;
  left: 17%;
  top: 11%;
  width: 32%;
  height: 22%;
  border-radius: 50%;
  background: color-mix(in srgb, #fff 90%, transparent);
  filter: blur(3.5px);
  transform: rotate(-16deg);
  pointer-events: none;
}

/* Symbol in der Kugel: Foto fuer Static, Video fuer Video. Immer nur eines
   sichtbar, es wechselt mit dem Zustand. */
.s1-icon{
  position: absolute;
  z-index: 3;
  width: 40%;
  height: 40%;
  color: var(--kontrast);
  opacity: 0;
  transition: opacity .26s ease;
}
.s1-toggle[data-state="static"] .s1-icon-static{ opacity: .92; }
.s1-toggle[data-state="video"]  .s1-icon-video{ opacity: .92; }

/* Umgeschaltet: Kugel nach rechts, Schein wechselt auf den Akzentton. */
.s1-toggle[data-state="video"]{ --glow: var(--akzent); }
.s1-toggle[data-state="video"] .s1-bubble{ transform: translateX(var(--slide)); }
/* Gegenversatz: die Kugel wandert um --slide nach rechts, die Kopie in ihr um
   denselben Betrag nach links — zusammen steht sie still, genau ueber der
   echten Pille. Waehrend der Feder uebernimmt das funnel.js (dort geteilt durch
   den Stretch, damit die Kugelmitte trotz Dehnung stimmt). */
.s1-toggle[data-state="video"] .s1-lens-track{ transform: translateX(calc(-1 * var(--slide))); }

/* Schmale Viewports: Toggle verkleinern, damit er in die Karte passt. */
@media (max-width: 460px){
  /* Ueberstand mitverkleinert, aber so, dass der Versatz zwischen
     Kugelmittelpunkt und Pillenende erhalten bleibt (siehe --over oben). */
  .s1-toggle{ --h: 36px; --bubble: 48px; --over: 14px; --w: 158px; }
  .s1-mode{ font-size: 13px; }
  .s1-mode-static{ right: 20px; }
  .s1-mode-video{ left: 20px; }
}

/* --------------------------------------- Stufe-1-Karte: Static-Inhalt */
/* Zweispaltiger Inhalt der Karte im Static-Zustand: links Headline + Text,
   rechts der Sneak-Peek einer real laufenden Anzeige. Nur hier sichtbar — im
   Video-Zustand blendet die Regel weiter unten den ganzen Slot aus, die Karte
   ist dort (vorerst) leer. Minimalismus wie in der Referenz: viel Luft, ruhige
   Bild/Text-Teilung, kein Seitenindex, keine Blaetter-Navigation. */

.s1-static,
.s2-cols,
.s3-cols,
.s4-cols,
.s5-cols{
  display: flex;
  /* Beide Spalten oben ausgerichtet: Headline und Label beginnen auf gleicher
     Hoehe, das Bild darf darunter weiter nach unten laufen. */
  align-items: flex-start;
  gap: clamp(30px, 4.5vw, 72px);
  width: 100%;
  /* Bewusst schmaler als die Karte: der Weissraum links und rechts traegt den
     ruhigen Eindruck der Referenz. */
  max-width: 900px;
  /* Etwas Luft unter dem Toggle, damit die Headline nicht dagegenstoesst. */
  margin-top: clamp(20px, 3vh, 40px);
  text-align: left;
}

/* Linke Spalte: Aussage. Headline in der Serifenschrift wie im Hero, damit sie
   als Ueberschrift liest; die Subline ruhig im Fliesstext-Sans.
   Gilt ueber die mitlaufenden .s2-*-Selektoren auch fuer die Stufe-2-Karte —
   die beiden Karten sollen dieselbe Typografie tragen, nicht zwei gepflegte. */
.s1-static-copy,
.s2-copy,
.s3-copy,
.s4-copy,
.s5-copy{ flex: 1 1 auto; }
/* Nur Stufe 1: die Textspalte fuellt die volle Bildhoehe (align-self:stretch)
   und ist eine eigene flex-Spalte. Die Headline sitzt oben, per padding-top
   genau auf Hoehe der BILD-Oberkante (nicht des Labels darueber): die Peek-
   Spalte traegt ueber dem Bild die Label-Zeile (~20px) plus 12px gap = 32px
   (nachgemessen), also beginnt die Headline 32px unter der Spalten-Oberkante —
   buendig mit dem Bild. Der Wert ist viewportstabil (Label-Font 12.5px und der
   gap sind fest). Der Subtext bekommt darunter auto-Raender und sitzt damit
   mittig im freien Raum (etwa auf halber Bildhoehe wie zuvor); dazwischen
   entsteht bewusst mehr Weissraum. Nur .s1-static-copy/.s1-static-sub — die
   Karten 2-5 bleiben oben ausgerichtet (align-items:flex-start der geteilten
   Regel). */
.s1-static-copy{
  align-self: stretch;
  display: flex;
  flex-direction: column;
  padding-top: 32px;
}
.s1-static-head,
.s2-head,
.s3-head,
.s4-head,
.s5-head{
  margin: 0;
  font-family: var(--serif);
  /* Kursiv fuer einen editorialen, boutique-artigen Charakter (Referenz
     "Look of the City"). KEIN neuer Font — dieselbe Serifenschrift wie im Hero
     und in den Ring-/Bandbeschriftungen, nur font-style:italic. Erst nur auf
     Stufe 1 erprobt, jetzt fuer alle fuenf Karten: eine Karte mit aufrechter
     und eine mit kursiver Ueberschrift faellt beim Scrollen von Stufe zu Stufe
     sofort auf — die Karten ruhen an derselben Stelle im Bild.
     Die Laufweite bleibt bei -0.012em wie im aufrechten Schnitt: die Vorlage
     laeuft zwar weiter, ihre Wirkung kommt dort aber von einer eigenen
     Display-Schrift in Versalien. Hier stehen ganze Saetze in gemischter
     Schreibweise, und aufgezogene Laufweite laesst die nur zerfallen.
     Gilt bei Stufe 1 in beiden Toggle-Zustaenden, weil .s1-static-head in
     beiden dieselbe Komponente ist; der Subtext bleibt ueberall aufrecht. */
  font-style: italic;
  font-size: clamp(30px, 3.3vw, 48px);
  line-height: 1.14;
  letter-spacing: -0.012em;
  color: var(--kontrast);
  text-wrap: balance;
}
.s1-static-sub,
.s2-sub,
.s3-sub,
.s4-sub,
.s5-sub{
  margin: clamp(16px, 2.2vh, 26px) 0 0;
  max-width: 42ch;
  /* Raleway (lokal, siehe @font-face am Dateianfang) fuer den Fliesstext ALLER
     fuenf Karten — das Ergebnis des Schriftart-Tests, der vorher nur im
     Stufe-1-Subtext lief. Fallback auf die System-Sans der Seite, falls die
     Schrift nicht laedt: dann steht dort dieselbe Schrift wie vor dem Test. */
  font-family: "Raleway", var(--sans);
  /* Eine Stufe groesser als zuvor (17-19px), auf Wunsch: der Erklaersatz stand
     neben der grossen Ueberschrift und der etwas groesseren Aufzaehlung zu
     zurueckhaltend da. Angehoben ist die ganze Kurve um rund einen Punkt, nicht
     nur ein Endwert — sonst waere der Satz auf breiten Fenstern groesser und
     auf schmalen unveraendert. NUR dieser Absatz: Ueberschriften und die
     Aufzaehlungen der Karten 2 und 4 bleiben, wo sie waren. */
  font-size: clamp(18px, 1.28vw, 20px);
  line-height: 1.6;
  /* Voller Kontrastton, kein Aufhellen: auf dem hellen Glas braucht Fliesstext
     die 4,5:1, dieselbe Ueberlegung wie bei .hero-sub. */
  color: var(--kontrast);
}
/* Nur Stufe 1: der Subtext sitzt mittig im freien Raum unter der (jetzt oben
   an der Bildkante klebenden) Headline. auto-Raender oben UND unten verteilen
   den Rest der gestreckten Copy-Spalte gleichmaessig — der Subtext landet damit
   etwa auf halber Bildhoehe, waehrend die Headline oben bleibt. Steht bewusst
   NACH der geteilten .s1-static-sub-Regel, sonst gewaenne deren margin-top.
   Das translateY zieht den Subtext ein kleines Stueck naeher an die Headline:
   der zentrierte Abstand ist ~111px, -20px sind ~18% weniger (Nutzer-Wunsch),
   ohne aber auf den frueheren, sehr engen Abstand zurueckzufallen. Rein optisch
   (kein Reflow), damit die Zentrierung als Basis erhalten bleibt. */
.s1-static-sub{ margin: auto 0; transform: translateY(-20px); }
/* Telefon: Sonderregel wieder aufheben. Sie setzt darauf, dass in der
   gestreckten Copy-Spalte Platz uebrig ist, den die auto-Raender verteilen
   koennen. Auf 390 px ist er das nicht — dann fallen beide Raender auf 0,
   und das translateY zieht den Subtext die restlichen 20 px in die
   Ueberschrift hinein. Nachgemessen: der Satz lag auf der zweiten Zeile von
   "Deine Kampagne wird laufend optimiert", siehe
   .scratch/mobile/karten/at_card-rest.png (Aufnahme vor der Korrektur).
   Zurueck auf denselben Abstand, den die Karten 2-5 haben. */
@media (max-width: 640px){
  .s1-static-sub{
    margin: clamp(16px, 2.2vh, 26px) 0 0;
    transform: none;
  }
}
/* Der Erklaersatz wechselt mit dem Toggle. Gleiche Machart wie der
   Medienwechsel darunter (.s1-peek-frame--foto/--video): beide Saetze stehen im
   Dokument, sichtbar ist immer der zum Kartenzustand passende.
   Kein Ueberblenden: das Bild daneben wechselt hart, und ein Satz, der sich
   langsamer austauscht als das Bild, liefe der Umschaltung hinterher.
   display und nicht opacity, damit der unsichtbare Satz auch aus dem Fluss und
   aus der Vorlesereihenfolge faellt — er nimmt sonst weiter Hoehe ein, und die
   auto-Raender darueber verteilten den Platz falsch. */
.s1-sub--video{ display: none; }
.stage1-card[data-state="video"] .s1-sub--static{ display: none; }
.stage1-card[data-state="video"] .s1-sub--video{ display: block; }
/* Nur Stufe 3 und 5: dort steht die Ueberschrift IN der linken Spalte, direkt
   ueber dem Erklaersatz — und stand ihm zu dicht auf den Fersen. Auf Wunsch
   angehoben, von rund 20px auf rund 30px (1490x900). Die Stufen 2 und 4 sind
   nicht gemeint: dort steht die Ueberschrift quer ueber der ganzen Karte und
   der Satz beginnt bewusst buendig mit der Anschauung daneben (margin-top:0).
   Stufe 1 auch nicht, die verteilt ihren Satz ueber auto-Raender. */
.s3-sub,
.s5-sub{ margin-top: clamp(24px, 3.3vh, 40px); }
/* Der Schriftart-A/B im Stufe-1-Subtext (erste Haelfte Raleway, zweite
   "Classico"/Marcellus) ist entschieden und ausgebaut: Raleway hat gewonnen und
   steht jetzt in der geteilten Subtext-Regel darueber fuer alle fuenf Karten.
   Die beiden <span>s im Satz sind damit ebenfalls weg (index.html), und
   Marcellus wird nicht mehr geladen. */

/* Rechte Spalte: Sneak-Peek. Label ueber dem Bild, dann das Bild in einem
   Rahmen in der .glass-Machart (heller Rand + weicher Schatten), damit es zur
   Karte gehoert und nicht als nackte Grafik draufliegt. */
.s1-static-peek{
  flex: 0 0 auto;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}
.s1-peek-label{
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--akzent);
}
/* Buehne fuer das Bild: relativ, damit der Schein absolut DAHINTER liegen kann.
   inline-block, damit sie sich auf die Bildgroesse zusammenzieht. */
.s1-peek-stage{
  position: relative;
  display: inline-block;
  /* Lichtfarbe der Hinterleuchtung. BEWUSST NICHT --akzent (#A67C52): das ist ein
     dunkles Braun und liest als Glow wie ein brauner Fleck, nicht wie Licht.
     Dies ist ein warmes Amber im Charakter einer warmweissen LED (~2700K), wie
     die indirekte Beleuchtung im Referenzbild. Kein neues UI-Farbthema — nur die
     Lichtfarbe dieses einen Scheins, deshalb lokal und nicht in :root.
     Etwas heller/weniger gesaettigt als reines Amber (Richtung warmweisse LED,
     ~3000K) — so wie die Deckenbeleuchtung im zweiten Referenzbild. */
  --peek-licht: #F7D3A0;
}
/* Indirekte Beleuchtung: ein weicher, warmer Akzent-Schein hinter dem Bild,
   groesser als der Rahmen und stark verwaschen. Muss AUSSERHALB des Rahmens
   liegen (der hat overflow:hidden fuer die runden Ecken). Zusammen mit dem
   tiefen Schatten am Rahmen wirkt das Bild hinterleuchtet und tritt nach vorne. */
.s1-peek-stage::before{
  content: "";
  position: absolute;
  z-index: 0;
  /* Breiter, weicher, gleichmaessiger warmer Wash — wie die LED-Voutenbeleuchtung
     im Referenzfoto: das Licht umgibt das Bild sanft von allen Seiten, kein
     harter Fleck. */
  inset: -32% -36% -40%;
  border-radius: 64px;
  background: radial-gradient(62% 64% at 50% 48%,
    color-mix(in srgb, var(--peek-licht) 88%, transparent),
    color-mix(in srgb, var(--peek-licht) 46%, transparent) 46%,
    transparent 74%);
  filter: blur(54px);
  opacity: 1;
  pointer-events: none;
}
.s1-peek-frame{
  position: relative;
  z-index: 1;   /* ueber dem Schein */
  border-radius: 18px;
  overflow: hidden;
  /* Kein Rahmen (Nutzer-Vorgabe): nur runde Ecken. */
  border: 0;
  /* NUR warmes Licht, KEIN dunkler Schatten mehr (der wirkte wie ein schwarzer
     Rand). Ein enger heller Rim-Schein direkt am Bild + ein weicher warmer
     Auslauf — zusammen mit dem grossen Wash dahinter (::before) sitzt das Bild
     in warmem Licht wie im Referenzfoto, statt auf einem Schlagschatten. */
  box-shadow:
    0 0 34px -2px color-mix(in srgb, var(--peek-licht) 78%, transparent),
    0 12px 60px -6px color-mix(in srgb, var(--peek-licht) 52%, transparent);
}
/* Ueber die Hoehe skaliert, Breite folgt dem Seitenverhaeltnis (Hochformat
   0.8): so passt das Bild in den Kartenrest, ohne die feste Kartenhoehe zu
   sprengen. */
.s1-peek-img{
  display: block;
  height: clamp(300px, 50vh, 480px);
  width: auto;
  max-width: 100%;
}

/* Medien-Wechsel je Zustand: Static zeigt das Foto, Video das Video. Text
   (Headline, Subline, Label) ist in beiden Zustaenden identisch und bleibt
   stehen — es wechselt nur die Medienspalte. */
.s1-peek-frame--video{ display: none; }
.stage1-card[data-state="video"] .s1-peek-frame--foto{ display: none; }
.stage1-card[data-state="video"] .s1-peek-frame--video{ display: block; }

/* Der schwarze Rand im Quellmaterial. Auf den gefilmten Einstellungen (der
   Mann vor der Wand) traegt das Video links und rechts eine schwarze Kante.
   Gemessene Spaltenhelligkeit, gemittelt ueber die Bildhoehe:
     Original 1536 px breit, bei 0/5/20 s:  0, 0, 1, 150, 151 ...
     Webfassung 720 px breit, dieselbe Stelle: 0, 84, 145, 142 ...
   also 3 Pixel im Original, nach dem Verkleinern rund 1,5. Auf den
   Bildschirmaufnahmen dazwischen ist die Kante nicht da — deshalb faellt sie
   nur auf, wenn der Mann zu sehen ist.
   Sie ist ins Material eingebacken und KEINE Folge der Einbettung: nachgeprueft
   mit einem nackten <video> ohne Rahmen und mit einem canvas, in das derselbe
   Frame roh gezeichnet wurde — beide zeigen dieselbe Kante. Element- und
   Videoverhaeltnis sind beide exakt 0,8, es wird also auch nichts gelettert
   (Standbild und Poster sind sauber).
   Sauber waere eine neue Fassung der Datei mit weggeschnittener Kante (dazu
   fehlt hier ffmpeg); bis dahin zoomt die Wiedergabe um 1 %. Der Rahmen hat
   overflow:hidden, damit liegt die Kante ausserhalb. Die Rechnung ist
   groessenunabhaengig: der Ueberstand je Seite ist (s-1)/2 der Breite, die
   Kante 2/720 davon — 1 % deckt 3,6 Quellpixel je Seite ab, gebraucht werden 2.
   Am gerenderten Bild nachgemessen: mit dieser Regel ist die Kante weg. */
.s1-peek-video{ transform: scale(1.01); }

/* Play-Button in der Mitte des Videos. Dunkle Glaskugel + weisses Dreieck,
   damit es auf jedem Videoframe lesbar ist. Startet das Video (funnel.js).
   Verschwindet, sobald es laeuft — dann pausiert ein Klick aufs Video. */
.s1-peek-play{
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 74px;
  height: 74px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, #fff 46%, transparent);
  background: color-mix(in srgb, var(--kontrast) 46%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(1.2);
  backdrop-filter: blur(6px) saturate(1.2);
  box-shadow: 0 10px 28px -10px color-mix(in srgb, #000 60%, transparent);
  display: grid;
  place-items: center;
  cursor: pointer;
  pointer-events: auto;
  z-index: 2;
  transition: transform .18s ease, background .18s ease, opacity .22s ease;
}
@media (hover: hover){
  .s1-peek-play:hover{
    transform: translate(-50%, -50%) scale(1.06);
    background: color-mix(in srgb, var(--kontrast) 58%, transparent);
  }
}
.s1-peek-play svg{
  width: 30px;
  height: 30px;
  margin-left: 3px;   /* optischer Ausgleich des Dreiecks zur Kreismitte */
  color: #fff;
}
/* Laeuft das Video, ist der Button weg (Klick aufs Video pausiert dann). */
.s1-peek-frame--video.is-playing .s1-peek-play{
  opacity: 0;
  pointer-events: none;
}
/* Waehrend das Video laeuft, Zeiger als Hinweis, dass ein Klick pausiert. */
.s1-peek-frame--video.is-playing .s1-peek-video{ cursor: pointer; }

/* Lautstaerke-Regelung unten rechts: Stumm-Knopf + Slider in einer Glas-Pille.
   Nur sichtbar, waehrend das Video laeuft. */
.s1-peek-vol{
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--kontrast) 48%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(1.2);
  backdrop-filter: blur(6px) saturate(1.2);
  border: 1px solid color-mix(in srgb, #fff 28%, transparent);
  opacity: 0;
  pointer-events: none;
  transition: opacity .22s ease;
}
.s1-peek-frame--video.is-playing .s1-peek-vol{ opacity: 1; pointer-events: auto; }
.s1-vol-btn{
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  cursor: pointer;
}
.s1-vol-btn svg{ width: 20px; height: 20px; }
/* Stumm: durchgestrichenes Symbol zeigen, normales verstecken. */
.s1-vol-ico-off{ display: none; }
.s1-peek-frame--video.is-muted .s1-vol-ico-on{ display: none; }
.s1-peek-frame--video.is-muted .s1-vol-ico-off{ display: block; }
/* Schlanker, heller Slider. accent-color faerbt Spur und Griff einheitlich. */
.s1-vol-slider{
  width: 78px;
  height: 4px;
  accent-color: #fff;
  cursor: pointer;
}

/* Schmale Viewports: Spalten stapeln, Bild kleiner — sonst wird die zweispaltige
   Teilung in der 92vw-Karte zu eng. */
@media (max-width: 640px){
  .s1-static,
  .s2-cols,
  .s3-cols,
  .s4-cols,
  .s5-cols{ flex-direction: column; align-items: flex-start; gap: 20px; }
  .s1-peek-img{ height: clamp(190px, 30vh, 260px); }
}

/* ------------------------------------------ Stufe-2-Karte: Landingpage */
/* Aufbau wie die Stufe-3-Karte: links die Aussage (Ueberschrift, Text,
   Gespraechspunkte), rechts die Anschauung — hier der Browser-Rahmen.
   Spaltenteilung und Typografie kommen aus denselben Regeln weiter oben
   (.s2-cols laeuft in .s1-static mit, .s2-copy in .s1-static-copy, .s2-head in
   .s1-static-head, .s2-sub in .s1-static-sub), den Ausgleich fuer den
   fehlenden Toggle teilt sie sich mit .s3-cols. Hier steht nur, was Stufe 2
   eigenes hat: die Gespraechspunkte als Liste und der Browser-Rahmen. */

/* Ueber dem Inhalt der Stufe-1-Karte steht der Toggle, ueber dem der Stufen 2
   und 3 nichts. Damit die Ueberschrift in ALLEN Karten auf derselben Hoehe beginnt —
   die Karten ruhen an derselben Stelle im Bild, ein Versatz fiele beim Scrollen
   von Stufe zu Stufe sofort auf — traegt der Block genau die Luft, die dort der
   Toggle einnimmt: das kleinere Kartenpolster der Stufe 1 plus Kugeldurchmesser
   plus deren Abstand nach unten, abzueglich des groesseren Polsters, das die
   Karte ohne Toggle oben hat. Als Rechnung und nicht als fester Wert, damit sie
   den Polstern folgt, wenn die geaendert werden. --toggle-h ist der
   Kugeldurchmesser (--bubble am .s1-toggle) und steht als eigene Variable da,
   weil er auf schmalen Fenstern kleiner wird. Die Deckelung auf 900px kommt
   wie bei den anderen zweispaltigen Karten aus der geteilten Regel weiter
   oben, hier steht nur der Toggle-Ausgleich.
   Nur die Stufen 3 und 5 tragen ihn hier (die Ueberschrift steht dort in der
   linken Spalte). Die Stufen 2 und 4 tragen ihn NICHT: dort steht die
   Ueberschrift quer oben und sitzt bewusst hoeher, dicht unter der
   Kartenoberkante (siehe .s2-head/.s4-head, margin-top:0). */
.s3-cols,
.s5-cols{
  --toggle-h: 54px;
  width: 100%;
  margin-top: calc(clamp(24px, 4vh, 48px) + var(--toggle-h) + clamp(20px, 3vh, 40px)
                   - clamp(38px, 6.5vh, 76px));
  text-align: left;
}

/* Die Ueberschrift steht quer und mittig ueber der ganzen Karte (im
   card-slot--stack, ausserhalb der linken Spalte). Eigene, etwas kleinere
   Schriftgroesse als die geteilte Headline, damit der Satz in EINE Zeile passt —
   in der schmalen linken Spalte brach er auf drei Zeilen um. margin-top:0 setzt
   sie dicht unter die Kartenoberkante (es bleibt nur das Kartenpolster) —
   bewusst hoeher als der Inhalt der uebrigen Stufen (Nutzer-Wunsch: der Titel
   soll weit oben in der Box stehen). Alles andere (Serif, Farbe, Zeilenhoehe,
   Laufweite) kommt aus der geteilten .s1-static-head-Regel. */
.s2-head,
.s4-head{
  width: 100%;
  margin-top: 0;
  font-size: clamp(23px, 3.35vw, 41px);
  text-align: center;
}

/* Der Erklaersatz ist jetzt das erste Element der linken Spalte (die Ueberschrift
   steht darueber quer). Sein oberer Abstand aus der geteilten .s1-static-sub-
   Regel faellt deshalb weg, damit er buendig mit der Oberkante der Anschauung
   rechts beginnt. */
.s2-sub,
.s4-sub{ margin-top: 0; }

/* Die Gespraechspunkte, in der linken Spalte unter dem Erklaersatz. Reine
   Textliste OHNE Icons — die Seite kommt ueberall sonst ohne Piktogramme aus,
   ein Symbolsatz nur hier waere ein Fremdkoerper. Eine Spalte, linksbuendig:
   in der halben Kartenbreite neben der Anschauung waere ein Zwei-Spalten-
   Raster zu eng. Der Zeilenabstand kommt aus gap (flex-column) statt aus
   li+li-Raendern.
   Das Aufzaehlungszeichen ist ein gezeichneter Punkt (siehe li::before) und kein
   list-style: nur so lassen sich Groesse, Farbe und die Hoehe festlegen, auf der
   er neben der ersten Zeile sitzt. Serif und deutlich groesser als der Text
   darueber: die Punkte sind keine Fussnote, sondern die zweite Haelfte der
   Aussage. Gilt ueber .s4-list auch fuer die Stufe-4-Karte. */
.s2-list,
.s4-list{
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 1.8vh, 20px);
  width: 100%;
  /* Abstand zum Erklaersatz darueber. Deutlich groesser als der gap zwischen
     den Eintraegen (oben): sonst steht die Liste so dicht am Absatz wie ihre
     Punkte untereinander und liest als dessen Fortsetzung statt als eigener
     Block. Gemessen auf 1490x900 sind es jetzt rund 30px gegen 16px von Punkt
     zu Punkt — das reicht zum Absetzen, ohne ein Loch zu reissen. */
  margin: clamp(24px, 3.3vh, 40px) 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
}
.s2-list li,
.s4-list li{
  position: relative;
  /* Einzug in em statt px: bricht ein Eintrag um, laeuft die zweite Zeile
     unter dem Text und nicht unter dem Zeichen — und das Verhaeltnis bleibt
     erhalten, wenn die Schriftgroesse sich aendert. */
  padding-left: 1.1em;
  /* Cormorant Garamond kursiv, das Ergebnis des Schriftvergleichs, der eine
     Fassung lang mit vier Schriften auf den vier Punkten der Landingpage-Karte
     lief. Sie stand dort fuer die Vorlage "La Condamine" — ein Beispielwort auf
     einem Moodboard, dessen Schrift nirgends genannt ist; Cormorant Garamond
     ist die naechstliegende freie Entsprechung und im Gegensatz zur Vorlage
     ueberhaupt verfuegbar.
     Sie gilt fuer BEIDE Aufzaehlungen (Karte 2 und 4) — die Karten ruhen an
     derselben Stelle im Bild, zwei verschiedene Listenschriften fielen beim
     Scrollen von Stufe zu Stufe sofort auf.
     Kursiv ist Absicht und kein Versehen: die Ueberschriften der Karten laufen
     ebenfalls kursiv, und die Aufzaehlung nimmt diesen Ton auf, waehrend der
     Erklaersatz dazwischen aufrecht in Raleway steht. Vorher stand hier
     Raleway, davor var(--serif). */
  font-family: "Cormorant Garamond", var(--serif);
  font-style: italic;
  /* Zwei Faktoren, die getrennt gehoeren:
       clamp(...)  ist die GEMEINTE Groesse — genau eine Nummer ueber dem
                   Erklaersatz darueber. Die drei Werte sind aus dessen Regel
                   abgeleitet (dort clamp(18px, 1.28vw, 20px)), jeweils einen
                   Punkt hoeher; auch die vw-Steigung geht mit, sonst waere der
                   Abstand auf breiten Fenstern zusammengeschrumpft.
                   WER DIE SUBTEXT-GROESSE AENDERT, MUSS DIESE MITZIEHEN.
       1.25        ist der optische Ausgleich fuer DIESE Schrift. Cormorants
                   Kleinbuchstaben sind ungewoehnlich klein (x-Hoehe 0.63 der
                   Versalhoehe, Raleway: 0.73) — ohne den Faktor saehe die Liste
                   trotz gleicher Punktgroesse deutlich kleiner aus als der
                   Erklaersatz. Gemessen an der gerenderten Seite: reiner
                   x-Ausgleich waere 1.316, reiner Versal-Ausgleich 1.136; 1.25
                   liegt dazwischen, weil die langen Oberlaengen sonst ueber die
                   Zeile ragen. BEI SCHRIFTWECHSEL NEU MESSEN. */
  font-size: calc(clamp(19px, 1.36vw, 21px) * 1.25);
  /* Etwas luftiger als die frueheren 1.3: Cormorant hat lange Ober- und
     Unterlaengen, und bei zweizeiligen Eintraegen (Karte 4) stiessen die
     sonst aneinander. */
  line-height: 1.35;
  letter-spacing: -0.008em;
  color: var(--kontrast);
}
.s2-list li::before,
.s4-list li::before{
  content: "";
  position: absolute;
  left: 0;
  /* Auf der Mitte der ERSTEN Zeile, nicht der Box: bei einem zweizeiligen
     Eintrag saesse der Punkt sonst zwischen den Zeilen. 0.65em ist die halbe
     Zeilenhoehe (line-height 1.3). */
  top: 0.65em;
  width: 0.26em;
  height: 0.26em;
  margin-top: -0.13em;
  border-radius: 50%;
  background: color-mix(in srgb, var(--akzent) 80%, var(--kontrast));
}


@media (max-width: 460px){
  .s3-cols,
  .s5-cols{ --toggle-h: 48px; }
}

/* ---- Der Browser-Rahmen der rechten Spalte (Stufe 2) ------------------
   Das Panel-Glas (schwebende Flaeche, Frost, Rim, Auftrieb) kommt aus der
   geteilten .s3-form-Regel weiter unten — dieselbe Flaeche wie Formular und
   Kalender, kein zweites Glas-Rezept. Hier steht nur der Inhalt im Rahmen. */
.s2-browser{
  /* Etwas engerer Innenabstand als der Feldabstand des Formulars: Chrome-
     Leiste und Seite sollen dicht sitzen. */
  gap: clamp(12px, 1.8vh, 18px);
}

/* Chrome-Leiste: drei gleiche, gedeckte Punkte (bewusst KEINE Ampelfarben —
   das waere das einzige grelle Detail der ganzen Seite). Eine feine
   Trennlinie setzt sie vom Seiteninhalt ab. */
.s2-bw-bar{
  display: flex;
  gap: 7px;
  padding-bottom: clamp(10px, 1.6vh, 15px);
  border-bottom: 1px solid color-mix(in srgb, var(--kontrast) 14%, transparent);
}
.s2-bw-dot{
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--kontrast) 30%, transparent);
}

/* Die angedeutete Seite im Rahmen: mittig gestapelt, damit sie wie ein
   ruhiger Landingpage-Aufbau liest (Headline, Text, Knopf, Trust-Reihe). */
.s2-bw-page{
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(12px, 1.9vh, 18px);
  padding: clamp(6px, 1vh, 12px) clamp(4px, 1vw, 12px) clamp(2px, 0.6vh, 6px);
}

/* Platzhalter-Headline: bewusst LEER — ein heller Block in der Groesse der
   frueheren zwei Textzeilen. So ist erkennbar, dass hier spaeter eigener Text
   reinkommt, ohne schon einen zu setzen. Als flex-Item (die .s2-bw-page ist
   flex) respektiert der <span> Breite und Hoehe. */
.s2-bw-title{
  width: 80%;
  height: clamp(38px, 6.5vh, 50px);
  border-radius: 10px;
  background: color-mix(in srgb, var(--hell) 60%, transparent);
  border: 1px solid color-mix(in srgb, var(--kontrast) 10%, transparent);
}

/* Duennere Fliesstext-Zeile: ein schmaler, abgerundeter Balken als Platzhalter
   fuer den Absatz unter der Headline. */
.s2-bw-text{
  width: 78%;
  height: 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--kontrast) 18%, transparent);
}

/* CTA-Knopf. Farbe und Form kommen aus .btn/.btn-sm (derselbe Knopf wie in
   Nav und Hero); hier nur eine Lichtkante oben und ein knapper Schatten, damit
   er auf der schwebenden Flaeche sitzt statt ihr davonzuschweben. */
.s2-bw-cta{
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 38%, transparent),
    0 6px 12px -7px color-mix(in srgb, var(--kontrast) 52%, transparent);
}

/* Trust-Signal: Sterne ueber drei runden Avatar-Platzhaltern. Sterne im
   Akzentbraun (kein Gold — nur Palette), die Avatare ueberlappen leicht mit
   Cremerand, damit sie sich voneinander abheben. */
.s2-bw-trust{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: clamp(2px, 0.8vh, 8px);
}
.s2-bw-stars{
  font-size: 13px;
  letter-spacing: 2px;
  color: var(--akzent);
}
.s2-bw-avatars{ display: flex; }
.s2-bw-avatar{
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--akzent) 55%, var(--hell));
  border: 2px solid var(--creme);
}
.s2-bw-avatar + .s2-bw-avatar{ margin-left: -8px; }

/* Zweiter Abschnitt der angedeuteten Seite. Er traegt keine eigene Aussage,
   sondern zieht die Seite in die Laenge und zeigt mehr Platzhalter — so wirkt
   der Rahmen wie eine ganze Landingpage und nicht nur wie ein Hero-Ausschnitt.
   Trennlinie, ein kraeftigerer Abschnitts-Titel, eine Reihe gleicher Kacheln
   (Feature-/Logo-Streifen) und ein paar Textzeilen. */
.s2-bw-divider{
  width: 100%;
  height: 1px;
  margin-top: clamp(4px, 1vh, 10px);
  background: color-mix(in srgb, var(--kontrast) 12%, transparent);
}
.s2-bw-subhead{
  width: 46%;
  height: 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--kontrast) 24%, transparent);
}
.s2-bw-tiles{
  display: flex;
  gap: 10px;
  width: 100%;
}
.s2-bw-tile{
  flex: 1;
  height: clamp(34px, 6vh, 52px);
  border-radius: 10px;
  background: color-mix(in srgb, var(--hell) 70%, transparent);
  border: 1px solid color-mix(in srgb, var(--kontrast) 10%, transparent);
}
.s2-bw-lines{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  width: 100%;
}
.s2-bw-lines span{
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--kontrast) 16%, transparent);
}
.s2-bw-lines span:nth-child(1){ width: 88%; }
.s2-bw-lines span:nth-child(2){ width: 72%; }
.s2-bw-lines span:nth-child(3){ width: 80%; }

/* ---------------------------------------- Stufe-4-Karte: KI-Bot */
/* Aufbau wie die Stufe-2-Karte: links die Aussage (Ueberschrift, Text,
   Aufgaben), rechts die Anschauung — hier ein Chat-Fenster. Spaltenteilung,
   Typografie, Toggle-Ausgleich und die Aufgabenliste laufen deshalb in den
   geteilten Regeln mit (.s4-cols in .s1-static/.s2-cols, .s4-copy in
   .s1-static-copy, .s4-head in .s1-static-head, .s4-sub in .s1-static-sub,
   .s4-list in .s2-list). Hier steht nur, was Stufe 4 eigenes hat: das Chat-
   Fenster in der rechten Spalte. Das Panel-Glas traegt .s4-chat gemeinsam mit
   .s3-form/.s5-cal (dieselbe schwebende Flaeche). */
.s4-chat{
  width: clamp(280px, 34vw, 420px);
  /* Enger als der Feldabstand des Formulars: Blase und Zeitstempel gehoeren
     zusammen, die Nachrichten duerfen dichter stehen. */
  gap: clamp(10px, 1.6vh, 16px);
  justify-content: center;
}

/* Eine Nachricht: Blase plus Zeitstempel, als schmale Spalte, die sich je nach
   Absender links oder rechts an den Rand legt. */
.s4-msg{
  display: flex;
  flex-direction: column;
  max-width: 82%;
}
.s4-msg--bot{ align-self: flex-start; align-items: flex-start; }
.s4-msg--kunde{ align-self: flex-end; align-items: flex-end; }

/* Die Sprechblase. Bot: heller Ton (--hell nach Weiss aufgehellt), dunkle
   Schrift. Kunde: Akzentbraun mit cremefarbener Schrift — dieselbe Paarung wie
   der .btn und der belegte Kalender-Slot. Je eine Ecke an der Absenderseite ist
   eckig, das ist die "Spitze" der Blase. */
.s4-bubble{
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 14.5px;
  line-height: 1.4;
}
.s4-msg--bot .s4-bubble{
  background: color-mix(in srgb, var(--hell) 82%, #fff);
  color: var(--kontrast);
  border-bottom-left-radius: 5px;
  box-shadow: 0 1px 2px -1px color-mix(in srgb, var(--kontrast) 38%, transparent);
}
.s4-msg--kunde .s4-bubble{
  background: color-mix(in srgb, var(--akzent) 92%, transparent);
  color: var(--creme);
  border-bottom-right-radius: 5px;
  box-shadow: 0 1px 2px -1px color-mix(in srgb, var(--kontrast) 45%, transparent);
}

/* Kleiner, gedaempfter Zeitstempel unter der Blase. */
.s4-time{
  margin-top: 4px;
  font-size: 10.5px;
  color: color-mix(in srgb, var(--kontrast) 55%, transparent);
}

/* Tipp-Blase: drei Punkte in einer Bot-Blase. Ein sehr ruhiges Pulsieren
   deutet "schreibt gerade" an; bei prefers-reduced-motion bleibt es still. */
.s4-typing{
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 12px 14px;
}
.s4-dot{
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--kontrast) 45%, transparent);
}
@media (prefers-reduced-motion: no-preference){
  .s4-dot{ animation: s4-typing 1.4s ease-in-out infinite; }
  .s4-dot:nth-child(2){ animation-delay: 0.2s; }
  .s4-dot:nth-child(3){ animation-delay: 0.4s; }
}
@keyframes s4-typing{
  0%, 60%, 100%{ opacity: 0.35; }
  30%{ opacity: 1; }
}

/* --------------------------------------------- Stufe-3-Karte: Formular */
/* Aufbau wie die Stufe-1-Karte und NICHT wie die der Stufe 2: links
   Ueberschrift und Text, rechts die Anschauung. Spaltenteilung und Typografie
   kommen deshalb aus denselben Regeln weiter oben (.s3-cols laeuft in
   .s1-static mit, .s3-copy in .s1-static-copy, .s3-head in .s1-static-head,
   .s3-sub in .s1-static-sub), den Ausgleich fuer den fehlenden Toggle teilt
   sie sich mit .s2-block. Hier steht nur, was Stufe 3 eigenes hat: das
   nachgebaute Formular in der rechten Spalte.
   Der Text der linken Spalte fehlt noch (kommt vom Nutzer), .s3-copy ist
   deshalb vorerst leer — sie nimmt ueber flex-grow trotzdem den freien Platz
   ein und haelt das Formular an seiner endgueltigen Stelle. */

/* ---- Die Glasflaeche, die das ganze Formular traegt --------------------
   Wunsch des Nutzers: nicht die einzelnen Felder sollen schweben, sondern das
   Formular ALS EINES soll sich von der Karte abheben. Also traegt diese eine
   Flaeche den Liquid-Glass-Effekt, und die Felder darin treten zurueck
   (siehe .s3-eingabe weiter unten). Dieselbe Schichtung wie in der Vorlage:
   ein Panel im Panel, nicht drei Glasebenen uebereinander.

   Vier Ebenen, jede mit einer Aufgabe — die Reihenfolge, in der das Material
   auch physikalisch entsteht:

     1. Frost   — eigenes backdrop-filter. Die Flaeche sammelt den Hintergrund
                  selbst ein, statt nur eine helle Flaeche zu sein.
     2. Rim     — die brechende Kante. Lichtsaum nach INNEN, oben am staerksten
                  (dort faellt das Licht ein), Aussenkante dunkel.
     3. Sheen   — das Glanzlicht ueber der oberen linken Ecke, als
                  Hintergrundebene und NICHT als ::after: Hintergruende liegen
                  unter dem Inhalt, ein Pseudoelement laege darueber und wuerde
                  Labels und Felder aufhellen.
     4. Auftrieb— ein weicher Schlagschatten. Ohne ihn liegt die Flaeche in der
                  Karte; mit ihm schwebt sie darueber, und genau darum ging es.

   Die Zahlen sind auf eine HELLE, warme Karte gerechnet und nicht aus den
   ueblichen Dark-Mode-Rezepten uebernommen. Drei Werte kippen dort ins
   Gegenteil, alle ausprobiert und verworfen:
     - mix-blend-mode: screen aufs Glanzlicht ergibt gegen eine helle Flaeche
       Weiss und sonst nichts.
     - Ein WEISSER Aussenrand verschwindet auf der hellen Karte spurlos; hier
       muss die Aussenkante abdunkeln und der Lichtsaum nach innen wandern.
     - saturate(180%) zieht die Flaeche ins Beige statt ins Glasige, weil der
       Hintergrund unter der Karte ein warmes Foto ist. Die Helligkeit macht
       die Arbeit, nicht die Saettigung.

   BEWUSST NICHT dabei: echte Brechung ueber ein SVG-feDisplacementMap im
   backdrop-filter. Das ist die einzige Zutat, die Apples Original noch hat,
   und sie laeuft nur in Chromium — in Safari und Firefox faellt sie ersatzlos
   aus. Auf einer Seite, die auf dem iPhone gelesen wird, waere das die eine
   Stelle, die dort schlechter aussieht als ueberall sonst.

   Feste eigene Breite statt Anteil an der Zeile: ein Formular liest man als
   Block, und seine Feldbreite soll nicht davon abhaengen, wie lang der Text
   daneben geraet. Sie darf schrumpfen (0 1 auto), damit sie auf schmalen
   Fenstern nicht ueber die Karte hinauslaeuft.
   pointer-events:none fuer den GANZEN Block: er ist eine Anschauung, kein
   Bedienelement. Ohne das reagierte der Sende-Knopf (er traegt .btn) auf die
   Maus und versprach eine Handlung, die es hier nicht gibt.
   Dieselbe Flaeche traegt auch der Browser-Rahmen (.s2-browser) und das Chat-
   Fenster (.s4-chat) — alle vier Mockups stehen auf demselben Glas. */
.s2-browser,
.s3-form,
.s4-chat,
.s5-cal{
  /* NICHT schrumpfen (0 0), so wie der Sneak-Peek der Stufe-1-Karte. Mit
     flex-shrink: 1 zog die Ueberschrift daneben die Flaeche zusammen, sobald
     Text in der linken Spalte stand: deren Eigenbreite ist die der ungebrochenen
     Zeile, und beim Verteilen der Ueberlaenge schrumpfte die Formularflaeche
     mit — von 400px auf 286px. Die Breite eines Formulars darf nicht davon
     abhaengen, wie lang die Ueberschrift daneben ist. */
  flex: 0 0 auto;
  width: clamp(272px, 33vw, 400px);
  max-width: 100%;
  /* Polster in vh/vw, weil die Karte eine feste Hoehe hat und die Flaeche auf
     niedrigen Fenstern mit ihr zusammenruecken muss. */
  padding: clamp(18px, 2.6vh, 28px) clamp(18px, 2vw, 26px);
  /* Kleiner als der Kartenradius (--glass-radius, 26px): die innere Flaeche
     darf nicht runder wirken als die Karte, die sie traegt. */
  border-radius: 22px;
  display: flex;
  flex-direction: column;
  /* Abstand von Feld zu Feld. */
  gap: clamp(14px, 2.2vh, 22px);
  pointer-events: none;

  /* (1) Frost */
  -webkit-backdrop-filter: blur(14px) saturate(120%) brightness(1.1);
  backdrop-filter: blur(14px) saturate(120%) brightness(1.1);
  /* (3) Glanzlicht ueber (2) der Glasfuellung. Die Fuellung geht nach oben ins
     Weisse und nach unten in den Cremeton — das ist die Lichtrichtung der
     ganzen Seite und laesst die Scheibe nach oben kippen. */
  background:
    linear-gradient(135deg,
      color-mix(in srgb, #fff 52%, transparent),
      color-mix(in srgb, #fff 10%, transparent) 34%,
      transparent 62%),
    linear-gradient(180deg,
      color-mix(in srgb, #fff 28%, transparent),
      color-mix(in srgb, var(--creme) 20%, transparent));
  border: 1px solid color-mix(in srgb, var(--kontrast) 26%, transparent);
  /* Links und rechts fast durchsichtig. Der dunkle Rahmen ist oben und unten
     richtig — dort steht direkt ein heller Lichtsaum dagegen und die beiden
     zusammen lesen als Glaskante. An den SEITEN ist der Saum nur halb so
     kraeftig und weichgezeichnet, dort blieb der Rahmen allein stehen und lief
     als dunkler Streifen ueber die volle Hoehe. Nachgemessen am Bild: die
     Kantenpixel lagen bei Helligkeit 192 gegen 230 in der Flaeche und 201 auf
     der Karte davor — dunkler als BEIDE Nachbarn, und genau das sieht man.
     Betrifft alle vier Mockups (Browser, Formular, Chat, Kalender). */
  border-left-color: color-mix(in srgb, var(--kontrast) 6%, transparent);
  border-right-color: color-mix(in srgb, var(--kontrast) 6%, transparent);
  box-shadow:
    /* (2) Rim: Lichtsaum innen, oben scharf, seitlich und unten schwaecher */
    inset 0 1px 0 color-mix(in srgb, #fff 88%, transparent),
    /* Seitlich ohne Weichzeichnung (frueher 1px) und kraeftiger: der Saum ist
       jetzt das, was die Kante zeichnet, nachdem der dunkle Rahmen dort weg
       ist. Verwaschen wuerde er die Kante ausfransen lassen. */
    inset 1px 0 0 color-mix(in srgb, #fff 58%, transparent),
    inset -1px 0 0 color-mix(in srgb, #fff 58%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 38%, transparent),
    /* Die untere Kante nimmt einen Hauch Akzent an — der Rest der Farbfassung,
       die eine gebrochene Kante im Original traegt. Kein neuer Farbton, nur
       der Akzent der Seite, so schwach, dass er als Waerme und nicht als Farbe
       liest. */
    inset 0 -3px 4px -2px color-mix(in srgb, var(--akzent) 20%, transparent),
    /* Innenschatten unten: gibt der Scheibe Dicke */
    inset 0 -14px 18px -16px color-mix(in srgb, var(--kontrast) 38%, transparent),
    /* (4) Auftrieb. Groesser als bei einem einzelnen Feld, weil hier ein
       groesserer Koerper schwebt — aber weiter eng und dunkel statt breit und
       blass: ein breiter Schatten direkt unter dem Koerper laesst ihn weich und
       gummiartig wirken (ausprobiert), ein engerer mit mehr Versatz laesst ihn
       schweben. */
    0 22px 38px -22px color-mix(in srgb, var(--kontrast) 58%, transparent),
    0 6px 13px -8px color-mix(in srgb, var(--kontrast) 32%, transparent);
}
.s3-feld{ display: flex; flex-direction: column; gap: 7px; }

/* Beschriftung ueber dem Feld. Bewusst NICHT die Versalien-Mikroschrift des
   Sneak-Peek-Labels (.s1-peek-label): drei Versalzeilen untereinander lesen
   laut, und die Beschriftung soll hier zurueckstehen. Sans wie der uebrige
   Fliesstext, nur kleiner und halbfett. */
.s3-label{
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.3;
  color: var(--kontrast);
}

/* Das Feld. Es TRAEGT den Glaseffekt nicht mehr — den traegt die Flaeche
   darum. Entscheidung des Nutzers, und die richtige: drei Glasebenen
   uebereinander (Karte -> Flaeche -> Feld) zeichnen den Hintergrund dreimal
   hintereinander weich, und was unten ankommt, ist nur noch Matsch. Genau so
   macht es auch die Vorlage: das innere Panel ist aus Glas, das Suchfeld darin
   ist eine ruhige helle Pille.

   Deshalb hier: kein eigenes backdrop-filter, kein Schlagschatten, kein
   Lichtsaum rundum. Nur eine helle Fuellung (heller als die Flaeche darum,
   damit sie sich abhebt und der Platzhalter genug Kontrast bekommt), eine
   feine dunkle Kante und ein knapper Innenschatten oben, der das Feld
   einlaesst statt es aufliegen zu lassen.

   Radius voll rund: die Form der Vorlage, und schon die Form des Knopfes
   darunter (.btn) — Feld und Knopf gehoeren damit sichtbar zusammen. Das
   Polster links waechst mit, sonst stuende der Text in der Rundung. */
.s3-eingabe{
  display: block;
  padding: 14px 22px;
  border-radius: 999px;
  background: color-mix(in srgb, #fff 46%, transparent);
  border: 1px solid color-mix(in srgb, var(--kontrast) 20%, transparent);
  box-shadow:
    inset 0 2px 3px -2px color-mix(in srgb, var(--kontrast) 34%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 55%, transparent);
  font-size: 15.5px;
  line-height: 1.3;
  /* Kraeftiger als das uebliche Platzhalter-Grau. Auf dem warmen Glas kommt
     ein gedaempfter Ton nicht ueber 3:1 (nachgemessen), und der Text hier ist
     das Einzige, was in den Feldern steht — er soll im Vorbeiscrollen lesbar
     sein. Die Karte wandert dabei ueber ein Foto: die Feldflaeche ist an der
     dunkelsten Stelle merklich dunkler als an der hellsten, gemessen wurde
     deshalb dort. Vom Label unterscheidet der Platzhalter sich ueber Schnitt
     und Groesse (klein/halbfett gegen groesser/normal), nicht ueber die
     Helligkeit. */
  color: color-mix(in srgb, var(--kontrast) 92%, transparent);
}

/* Der Sende-Knopf. Farbe, Form und Polster kommen aus .btn und bleiben
   unangetastet — der Knopf im Beispiel soll derselbe sein wie der echte in Nav
   und Hero. Dazu nur eine Lichtkante oben und ein knapper Schatten: er steht
   jetzt INNERHALB der schwebenden Flaeche und darf ihr nicht davonschweben,
   deshalb deutlich weniger Auftrieb als die Flaeche selbst. */
.s3-senden{
  align-self: flex-start;
  margin-top: clamp(4px, 1.2vh, 12px);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 38%, transparent),
    0 6px 12px -7px color-mix(in srgb, var(--kontrast) 52%, transparent),
    0 2px 4px -2px color-mix(in srgb, var(--kontrast) 24%, transparent);
}
/* Schmale Fenster. Die Stufe-3-Karte traegt von allen fuenf den meisten
   Inhalt: Ueberschrift, Fliesstext UND ein Formular aus drei beschrifteten
   Feldern plus Knopf. Sobald die Spalten unter 640px uebereinander stehen,
   addiert sich beides und sprengt die feste Kartenhoehe (min(82vh, 820px)) —
   bei 420x760 nachgemessen um rund 70px, der Knopf stand dann unter der
   Kartenkante.
   Deshalb hier engere Masse fuer genau diesen Fall. Angefasst ist nur, was
   Luft ist: Polster, Abstaende und ein halber Punkt Schriftgroesse an
   Beschriftung und Platzhalter. Die Ueberschrift und der Fliesstext daneben
   bleiben unangetastet — die teilen sich ihre Groessen mit den Karten 1 und 2,
   und zwei Karten mit verschieden grosser Ueberschrift faellt beim Scrollen
   sofort auf. */
@media (max-width: 640px){
  .s3-cols{ gap: 16px; }
  .s3-form{
    padding: 13px 15px;
    border-radius: 18px;
    gap: 12px;
  }
  .s3-feld{ gap: 5px; }
  .s3-label{ font-size: 12.5px; }
  .s3-eingabe{ padding: 11px 19px; font-size: 15px; }
  .s3-sub{ margin-top: 12px; }
  .s3-senden{ margin-top: 2px; }
}

/* ---------------------------------------- Stufe-5-Karte: Terminbuchung */
/* Aufbau wie die Stufe-3-Karte (links Ueberschrift und Text, rechts die
   Anschauung) — Spaltenteilung, Typografie und der Toggle-Ausgleich kommen
   deshalb aus denselben geteilten Regeln weiter oben (.s5-cols laeuft in
   .s1-static und in .s2-block/.s3-cols mit, .s5-copy in .s1-static-copy,
   .s5-head in .s1-static-head, .s5-sub in .s1-static-sub). Das Panel-Glas des
   Mockups traegt .s3-form gemeinsam mit .s5-cal (dieselbe Flaeche, die auch das
   Formular traegt — kein zweites Glas-Rezept). Hier steht nur, was Stufe 5
   eigenes hat: der Kalender-Aufbau in der rechten Spalte.

   Warum die Slots eine feste Hoehe statt einer echten 30-Minuten-Proportion
   tragen: ueber 0-24 Uhr auf der festen Kartenhoehe ist eine halbe Stunde nur
   rund 11px hoch — zu wenig fuer lesbare Beschriftung. Die Position (top) sitzt
   zeitgenau, die Hoehe ist auf Lesbarkeit gesetzt (~18px, optisch knapp 45min).
   Der ganze Block ist eine Anschauung wie das Formular: aria-hidden im HTML,
   pointer-events:none kommt aus .s3-form. */
.s5-cal{
  /* Panel-Glas, flex-column, Polster und pointer-events kommen aus .s3-form.
     Nur breiter (3 Tagesspalten + Stundenleiste) und mit engerem Innenabstand
     zwischen Kopf und Raster als der Feldabstand des Formulars. */
  width: clamp(300px, 40vw, 460px);
  gap: clamp(8px, 1.2vh, 12px);
  /* Masse des Rasters an einer Stelle, damit sie sich gemeinsam anpassen. */
  --s5-gutter: 26px;                  /* Breite der Stundenleiste links */
  --s5-h: clamp(360px, 52vh, 540px);  /* Hoehe des 0-24h-Rasters */
  --s5-slot: clamp(15px, 2.2vh, 19px);/* feste, lesbare Slot-Hoehe */
}

/* Kopfzeile: leere Ecke ueber der Stundenleiste, dann die Tagesnamen ueber
   ihren Spalten. Die linke Luecke ist genau die Leistenbreite. */
.s5-cal-head{
  display: flex;
  padding-left: var(--s5-gutter);
}
.s5-cal-tag{
  flex: 1;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--kontrast);
}

/* Koerper: Stundenleiste links, Rasterflaeche rechts. */
.s5-cal-body{
  display: flex;
  height: var(--s5-h);
}

/* Stundenmarken 0-24. space-between verteilt die 13 Marken ueber die volle
   Rasterhoehe, sodass sie mit den Rasterlinien fluchten. Rechtsbuendig an der
   Leiste, damit die Zahlen an der Rasterkante stehen. */
.s5-cal-hours{
  width: var(--s5-gutter);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  padding-right: 6px;
}
.s5-cal-hours span{
  font-size: 9px;
  line-height: 1;
  color: color-mix(in srgb, var(--kontrast) 60%, transparent);
}

/* Rasterflaeche: eine feine Stundenlinie alle 2 Stunden (12 Abschnitte ueber
   0-24) als Verlauf, darueber die drei Tagesspalten. */
.s5-cal-grid{
  position: relative;
  flex: 1;
  display: flex;
  border: 1px solid color-mix(in srgb, var(--kontrast) 16%, transparent);
  border-radius: 8px;
  overflow: hidden;
  background:
    repeating-linear-gradient(
      to bottom,
      color-mix(in srgb, var(--kontrast) 12%, transparent) 0,
      color-mix(in srgb, var(--kontrast) 12%, transparent) 1px,
      transparent 1px,
      transparent calc(100% / 12));
}
.s5-cal-day{
  position: relative;
  flex: 1;
}
.s5-cal-day + .s5-cal-day{
  border-left: 1px solid color-mix(in srgb, var(--kontrast) 12%, transparent);
}

/* Ein belegter Termin. top setzt die Uhrzeit (Anteil des Tages), die Hoehe ist
   fest auf Lesbarkeit gesetzt. Brauner Akzent-Block mit cremefarbenem Text —
   dieselbe Paarung wie der .btn, ein belegter Slot liest damit als "gebucht". */
.s5-cal-slot{
  position: absolute;
  left: 3px;
  right: 3px;
  height: var(--s5-slot);
  padding: 0 6px;
  display: flex;
  align-items: center;
  border-radius: 5px;
  background: color-mix(in srgb, var(--akzent) 90%, transparent);
  box-shadow: 0 1px 2px -1px color-mix(in srgb, var(--kontrast) 55%, transparent);
}
.s5-cal-slot span{
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.05;
  color: var(--creme);
}

/* Schmale Fenster: Raster niedriger, Leiste schmaler, Beschriftung kleiner —
   sonst sprengt der gestapelte Block die feste Kartenhoehe. */
@media (max-width: 640px){
  .s5-cal{ --s5-h: clamp(300px, 46vh, 420px); --s5-gutter: 22px; }
  .s5-cal-slot span{ font-size: 9px; }
  .s5-cal-tag{ font-size: 11px; }
}

/* ------------------------------------------------------------------- Outro */
/* Sitzt unterhalb des geschlossenen Trichters, nicht dahinter.
   Das genaue top setzt funnel.js aus der gemessenen Texthöhe. */
.outro{
  position: absolute;
  left: 50%;
  top: 70%;
  transform: translate(-50%, -50%);
  width: min(680px, 84vw);
  text-align: center;
  z-index: 6;
  will-change: transform, opacity;
}
.outro h2{ font-size: clamp(28px, 2.9vw, 42px); }

/* Zwei Glasflächen (Botschaft, Beleg) plus ein freistehender CTA. Ein Panel um
   alles wirkte bei dieser Elementdichte zu voll; drei gestapelte Glasflächen
   dagegen blockig — vor allem der fast leere Slab um den Button. Der CTA-Button
   ist selbst ein satter Akzent-Pill und steht deshalb frei auf dem Hintergrund,
   ohne eigene Glasfläche. Reihenfolge Botschaft -> Beleg -> Handlung bleibt. */
.outro-panel{
  padding: clamp(26px, 3.4vw, 40px) clamp(24px, 3.6vw, 46px) clamp(24px, 3vw, 34px);
  margin: 0 0 16px;
}
.outro-panel p{
  margin: 16px auto 0;
  max-width: 56ch;
  font-size: 16.5px;
  /* Kein Aufhellen: auf dem Glas fiel der Kontrast damit unter die 4,5:1,
     die Fließtext braucht — dieselbe Korrektur wie bei .hero-sub. */
}
/* Kein Glas mehr: nur noch etwas Abstand nach oben, damit der Button nicht an
   der Proof-Reihe klebt. Kontrast bringt der Button selbst mit. */
.outro-action{
  margin-top: clamp(8px, 1.6vw, 18px);
}
.outro-fine{ margin: 14px 0 0; font-size: 14px; opacity: .82; }

/* Mehr Milchigkeit fuer das Outro-Glas. Gleiche .glass-Machart und identischer
   Blur wie der Hero (20px), aber der Grund dahinter ist unruhiger (kraeftige
   Faltenkaemme + heller Lichtfleck statt ruhiger Wand). Bei gleichem Tint liest
   das Glas darueber weniger frostig — deshalb hier ein etwas dickerer
   Cremeschleier (28% statt 20%), damit das Outro-Glas so milchig wirkt wie das
   Hero-Panel. Blur bewusst NICHT erhoeht, sonst weicht der Charakter ab. Hero
   bleibt unberuehrt. */
.outro .glass{
  background: color-mix(in srgb, var(--creme) 28%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(115%);
  backdrop-filter: blur(20px) saturate(115%);
}

/* --------------------------------------------------------- Proof-Sektion */
/* Steht zwischen Schluss-Message und Button. Noch ohne Inhalt — die Karten
   halten nur den Platz und die Anmutung fest. Höhe geht über outroEl.offsetHeight
   in measure() ein, der Trichter im Outro passt sich also von selbst an.
   Als eigene Glaskarten statt als Kästen im Hauptpanel: Glas auf Glas wird
   trüb, und die Karten sind ein eigener Inhaltstyp. */
.proof{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin: 0 0 16px;
}
.proof-card{ min-height: 104px; }
@media (max-width: 640px){
  /* Untereinander statt nebeneinander — nebeneinander waeren die drei Kaesten
     auf 390 px je gut 110 px breit und damit unbrauchbar schmal.
     Gestapelt kosten sie dafuer Hoehe, und die ist am Seitenende knapp: unter
     ihnen steht noch der Schluss-Knopf, ueber ihnen der Trichter. 56 px statt
     74 sparen ueber die drei Kaesten und die Abstaende rund 60 px — genug,
     damit der Trichter am Ende nicht auf die Schlussbotschaft rutscht. */
  .proof{ grid-template-columns: 1fr; gap: 8px; margin-bottom: 12px; }
  .proof-card{ min-height: 56px; }
}

/* ------------------------------------------ Terminanfrage im Schlussbild */
/* Schlussbild, Formular und Bestaetigung liegen im SELBEN Grid-Feld
   uebereinander und werden ueber die Deckkraft gekreuzt.

   Der Grund ist Statik, nicht Optik: .outro haengt absolut in der fixen Buehne
   und ist unten verankert — measure() in js/funnel.js liest seine Hoehe, setzt
   daraus top und rechnet aus dem verbleibenden Platz darueber die GROESSE DES
   TRICHTERS. Verdraengten die Zustaende einander, aenderte sich diese Hoehe beim
   Umschalten: der Trichter spraenge beim naechsten measure() (Fenstergroesse,
   Neuladen) auf ein anderes Mass, und bis dahin liefe der Block unten aus dem
   Bild. Uebereinander gelegt ist die Hoehe dagegen immer die des hoechsten
   Zustands — konstant, egal was gerade sichtbar ist. Gemessen: der Wechsel
   bewegt weder .outro noch den Trichter um ein Pixel.

   visibility statt display:none fuer die unsichtbaren Zustaende: display wuerde
   sie aus dem Raster nehmen und die gemeinsame Hoehe waere wieder die des
   sichtbaren. visibility haelt den Platz, nimmt sie aber genauso aus
   Tabreihenfolge und Vorlesereihenfolge. Der Uebergang schaltet sie beim
   Einblenden sofort sichtbar (0s) und beim Ausblenden erst nach der Blende. */
.outro-swap{ display: grid; }
.outro-swap > *{
  grid-area: 1 / 1;
  align-self: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(10px);
  transition: opacity .34s ease, transform .34s ease, visibility 0s linear .34s;
}
.outro-swap > .ist-da{
  opacity: 1;
  visibility: visible;
  /* inherit und NICHT auto — teuer gelernt. funnel.js schaltet .outro auf
     pointer-events: none, solange das Schlussbild ausgeblendet ist; der Block
     liegt aber trotzdem die ganze Zeit ueber der Bildmitte. Mit "auto" hebt das
     Kind diese Sperre auf und faengt die Klicks ab, die dem Hero-Panel
     darunter gelten — der Knopf "Kostenloses Erstgespraech" war dadurch tot,
     waehrend der in der Navileiste (ausserhalb der Flaeche) weiter ging.
     Mit inherit folgt der sichtbare Zustand dem, was funnel.js dem Outro
     vorgibt: gesperrt, solange es unsichtbar ist, bedienbar, sobald es da ist.
     Getestet gehoert das mit einem ECHTEN Klick auf die Koordinate — ein
     el.click() im Skript ruft den Handler direkt auf und laeuft an jeder
     Ueberdeckung vorbei, ohne sie zu bemerken. */
  pointer-events: inherit;
  transform: none;
  transition: opacity .34s ease, transform .34s ease, visibility 0s;
}
@media (prefers-reduced-motion: reduce){
  .outro-swap > *{ transition: none; transform: none; }
}

/* .btn ist fuer <a> gebaut. Der Schluss-Knopf ist jetzt ein <button> (er
   navigiert nicht, er schaltet um) und braucht deshalb den Browser-Vorgabestil
   abgeraeumt: eigener Rahmen, eigene Schrift, eigene Zeilenhoehe. */
button.btn{
  border: 0;
  font-family: inherit;
  line-height: 1.2;
  cursor: pointer;
}

/* Die senkrechten Masse hier sind knapp gehalten, und das hat einen Grund:
   .outro ist unten verankert, und was das Formular an Hoehe braucht, nimmt
   measure() dem Trichter darueber weg. Mit dem siebten Feld (Wunschtermin) war
   das Formular 492 px hoch — 49 px mehr als das Schlussbild — und der Trichter
   schrumpfte auf 1490x900 von 311 auf 262 px. Nach dem Zusammenruecken sind es
   455 px und 295 px. Wer hier Polster vergroessert oder ein Feld ergaenzt,
   nimmt das dem Trichter weg; ab .anfrage-hoehe 443 px kostet es nichts. */
.anfrage{
  padding: clamp(16px, 2vh, 24px) clamp(20px, 3vw, 34px);
  /* Der Rest des Outros ist zentriert; ein Formular liest sich linksbuendig. */
  text-align: left;
}
/* Kleiner als .outro h2 (clamp(28px,2.9vw,42px)): die Schlussbotschaft darf
   gross auftreten, die Ueberschrift ueber einem Formular soll nur benennen. */
.anfrage-titel{
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(20px, 2vw, 25px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--kontrast);
}

.anfrage-raster{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(7px, 1.1vh, 11px) 16px;
  margin-top: clamp(10px, 1.4vh, 14px);
}
/* justify-content: flex-end richtet die Felder an der UNTERKANTE ihrer
   Rasterzeile aus. Das ist noetig, weil eine Beschriftung zweizeilig sein kann
   ("Wie viele Erstgespraeche …") und ihre Nachbarin einzeilig — ohne das
   stuenden die beiden Eingabefelder derselben Zeile auf verschiedener Hoehe. */
.anfrage-feld{
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 5px;
  min-width: 0;
}
.anfrage-feld label{
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--kontrast);
}
/* Optisch dasselbe Feld wie im Formular-Mockup der Stufe 3 (.s3-eingabe) —
   dort gezeichnet, hier echt. */
.anfrage-feld input{
  width: 100%;
  padding: 10px 18px;
  border-radius: 999px;
  background: color-mix(in srgb, #fff 46%, transparent);
  border: 1px solid color-mix(in srgb, var(--kontrast) 20%, transparent);
  box-shadow:
    inset 0 2px 3px -2px color-mix(in srgb, var(--kontrast) 34%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 55%, transparent);
  font-family: inherit;
  font-size: 15px;
  line-height: 1.3;
  color: var(--kontrast);
}
.anfrage-feld input:focus-visible{
  outline: 2px solid color-mix(in srgb, var(--akzent) 70%, transparent);
  outline-offset: 2px;
}
/* :user-invalid und nicht :invalid — sonst waeren alle sechs Pflichtfelder
   schon beim Aufklappen markiert, bevor jemand etwas getan hat. So faerbt sich
   ein Feld erst, wenn es benutzt oder abgeschickt wurde. Markiert wird ueber
   Rahmen und Ring im Akzentton: die Palette hat kein Rot, und ein
   Fremdfarbton nur fuer Fehler waere hier ein Bruch. */
.anfrage-feld input:user-invalid{
  border-color: color-mix(in srgb, var(--akzent) 90%, var(--kontrast));
  box-shadow:
    inset 0 2px 3px -2px color-mix(in srgb, var(--kontrast) 34%, transparent),
    0 0 0 2px color-mix(in srgb, var(--akzent) 30%, transparent);
}

/* Das siebte Feld (Wunschtermin) laeuft ueber beide Spalten und steht mittig —
   es gehoert zu keiner der beiden Spalten, sondern schliesst das Formular ab.
   Die Eingabezeile bekommt dabei eine Hoechstbreite: ueber die vollen 680 px
   gezogen waere sie fast doppelt so lang wie jedes Feld darueber und wirkte wie
   ein Fremdkoerper. Mit 420 px liegt sie zwischen der Spaltenbreite und der
   vollen Breite und bleibt als eigene, letzte Zeile erkennbar. */
.anfrage-feld--breit{
  grid-column: 1 / -1;
  text-align: center;
}
.anfrage-feld--breit input{
  max-width: 420px;
  margin: 0 auto;
  text-align: center;
}

.anfrage-aktion{
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: clamp(11px, 1.5vh, 15px);
}
.anfrage-zurueck{
  background: none;
  border: 0;
  padding: 4px 2px;
  font: inherit;
  font-size: 14px;
  color: var(--kontrast);
  opacity: .72;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: opacity .2s ease;
}
@media (hover: hover){
  .anfrage-zurueck:hover{ opacity: 1; }
}
/* Waehrend gesendet wird: Knopf sichtbar taub, aber an seinem Platz. */
.anfrage-laeuft{ opacity: .55; pointer-events: none; }
.anfrage-fehler{
  margin: 12px 0 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--kontrast);
}
.anfrage-fehler[hidden]{ display: none; }
/* Honigtopf: aus dem Bild geschoben statt display:none — manche Bots
   ueberspringen Felder, die gar nicht gerendert werden. */
.anfrage-honig{
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.anfrage-dank{
  padding: clamp(26px, 3.4vw, 40px) clamp(24px, 3.6vw, 46px);
}
.anfrage-dank h2{ margin: 0; }
.anfrage-dank p{ margin: 14px auto 0; max-width: 46ch; font-size: 16.5px; }
.anfrage-dank:focus-visible{
  outline: 2px solid color-mix(in srgb, var(--akzent) 70%, transparent);
  outline-offset: 4px;
}

/* Schmale Fenster. Die Grenze liegt bei 560 und nicht bei den 640 der
   .proof-Kacheln — zwei Eingabefelder nebeneinander tragen laenger als drei
   Referenzkacheln.

   NICHT alles auf eine Spalte, und das ist nachgemessen: .outro ist unten
   verankert und waechst nach OBEN, jede zusaetzliche Zeile also um rund 68 px.
   Mit sechs Einzelzeilen war das Formular auf 360x740 volle 681 px hoch und
   schob sich unter die Navileiste (nutzbar sind dort 645 px). Vorname und
   Nachname bleiben deshalb nebeneinander — zwei kurze Woerter, die auch in
   einer halben Zeile lesbar sind; die vier laengeren Felder gehen ueber die
   ganze Breite. Das spart genau eine Zeile und bringt das Formular wieder
   unter die Leiste. */
@media (max-width: 560px){
  .anfrage-feld:nth-child(n+3){ grid-column: 1 / -1; }
  .anfrage{ padding: 15px 14px; }
  .anfrage-titel{ font-size: 19px; }
  /* Auf dem Telefon wird getippt, nicht geklickt: hier bekommen die Felder
     wieder mehr Hoehe als auf dem Schreibtisch (46 px statt 42), damit sie als
     Beruehrungsziel taugen. Der Platz dafuer kommt aus den Abstaenden.
     Die sind hier knapper als auf dem Schreibtisch, weil das Formular in einer
     Spalte laeuft und damit fast 200 px hoeher ist: auf 360x740 stehen zwischen
     Navileiste und Unterkante nur 645 px zur Verfuegung. Gemessen sind es
     jetzt 632 — wer die Abstaende wieder aufmacht, schiebt den Titel unter die
     Leiste. */
  .anfrage-feld input{ padding: 12px 18px; }
  .anfrage-raster{ gap: 6px 12px; margin-top: 9px; }
  .anfrage-aktion{ gap: 14px; margin-top: 11px; }
}

/* ------------------------------------------------------------------ Footer */
.footer{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  padding: 40px clamp(20px, 4vw, 52px);
  border-top: 1px solid color-mix(in srgb, var(--kontrast) 12%, transparent);
  background: var(--hell);
}
.footer-brand{ font-family: var(--serif); font-size: 21px; letter-spacing: .04em; }
.footer-links{ display: flex; gap: 26px; }
.footer-links a{ font-size: 15px; text-decoration: none; opacity: .72; }
@media (hover: hover){
  .footer-links a:hover{ opacity: 1; }
}

/* ====================================================================== */
/*  Unterseiten                                                           */
/* ====================================================================== */
.page{
  max-width: 760px;
  margin: 0 auto;
  padding: calc(var(--nav-h) + 90px) clamp(20px, 5vw, 40px) 110px;
}
.page h1{ font-size: clamp(32px, 4vw, 50px); }
.page h2{ font-size: 24px; margin: 48px 0 12px; }
/* Dritte Ebene fuer die Datenschutzerklaerung: die hat unter EINER Ueberschrift
   mehrere Punkte (Verantwortlicher, Logdaten, Hosting, Rechte …), und die
   sollen als Unterpunkte lesbar sein und nicht wie eigene Kapitel. */
.page h3{ font-size: 17px; margin: 30px 0 8px; letter-spacing: .01em; }
.page p{ opacity: .85; }
.page ul{ margin: 10px 0 0; padding-left: 20px; opacity: .85; }
.page li{ margin: 5px 0; }
.page a{ text-underline-offset: 3px; }
.page .lead{ font-size: 19px; opacity: .9; margin-top: 22px; }
/* Angaben, die erst mit der Gewerbeanmeldung feststehen. Bewusst SICHTBAR
   ausgezeichnet und nicht als HTML-Kommentar versteckt: ein unvollstaendiges
   Impressum, das vollstaendig aussieht, ist die gefaehrlichere Variante.
   Beim Ausfuellen verschwindet das span mitsamt Klasse — danach ist die Seite
   durch eine Suche nach "offen" nachweislich sauber. */
.offen{
  color: var(--akzent);
  font-style: italic;
  white-space: nowrap;
}
.placeholder-note{
  margin: 34px 0;
  padding: 16px 20px;
  border-left: 3px solid var(--akzent);
  background: var(--hell);
  font-size: 15px;
  border-radius: 0 8px 8px 0;
}
.portrait{
  width: 168px;
  height: 168px;
  border-radius: 50%;
  background: var(--hell);
  border: 1px solid color-mix(in srgb, var(--kontrast) 14%, transparent);
  display: grid;
  place-items: center;
  font-size: 13px;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .55;
  margin: 40px 0 0;
}

/* ====================================================================== */
/*  Statischer Fallback: reduzierte Bewegung oder kein JavaScript          */
/*  Gleiche Inhalte, nur ohne Pin und ohne Sequenz.                        */
/* ====================================================================== */
/* Ohne Sequenz: Spacer und Mittelteil-Fluss entfallen, die Buehne wird zur
   statischen Inhaltsspalte (Hero, Trichter, 5 Baender, Outro) — wie zuvor. */
html.no-anim .scene-spacer,
html.no-anim .band-flow{ display: none; }
html.no-anim .stage{
  position: static; height: auto; overflow: visible;
  z-index: auto;
  padding: calc(var(--nav-h) + 80px) 20px 100px;
  opacity: 1;
}

html.no-anim .hero,
html.no-anim .outro{ position: static; transform: none; width: min(760px, 90vw); margin: 0 auto; opacity: 1 !important; }

html.no-anim .funnel{ position: static; width: min(340px, 60vw); height: auto; aspect-ratio: 1205 / 1400; margin: 70px auto; opacity: 1 !important; filter: none !important; transform: none !important; }
/* Bei reduzierter Bewegung keine Sequenz — das statische Trichterbild oben und
   die fünf Bänder darunter zeigen denselben Inhalt. */
html.no-anim .hero-bg,
html.no-anim .outro-bg{ display: none; }
/* Ohne Bewegung faellt der Hero-Hintergrund weg, und weisse Schrift auf der
   Cremeflaeche waere unsichtbar. Die Zeile wird hier zu einer normalen
   Ueberschrift ueber dem Trichterbild: im Textton, sichtbar, im Fluss. */
html.no-anim .leistung{
  position: static;
  transform: none;
  opacity: 1;
  color: var(--kontrast);
  font-size: clamp(26px, 5vw, 54px);
  margin: 0 auto 10px;
  max-width: min(760px, 90vw);
  /* Die Telefon-Regel weiter oben spannt die Zeile ueber 78vh auf, damit die
     beiden Woerter den Trichter flankieren koennen. Ohne Bewegung gibt es
     keinen Trichter dazwischen — dort waere das nur ein Loch von zwei Dritteln
     Bildhoehe zwischen "UNSER" und "SERVICE". */
  height: auto;
  justify-content: flex-start;
}
/* Der Telefon-Versatz von SERVICE (siehe oben) gilt nur fuer die gestapelte
   Lage um den Trichter. Ohne Bewegung stehen die Woerter als normale
   Ueberschrift im Fluss — dort waere er ein Ueberlappen. */
html.no-anim .leistung .l-wort{ transform: none; }
/* Ohne Bewegung kein Glas: der Text steht dort auf der flachen Cremefläche,
   ein Panel mit backdrop-filter über Nichts wäre nur ein grauer Kasten. */
html.no-anim .glass{
  padding: 0; background: none; border: 0; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
html.no-anim .proof-card{
  background: color-mix(in srgb, var(--hell) 55%, transparent);
  border: 1px solid color-mix(in srgb, var(--kontrast) 12%, transparent);
}
html.no-anim .funnel-video,
html.no-anim .ring-labels,
/* Ohne Sequenz gibt es keine Banner-Position — die Stufe-1-Karte entfaellt,
   Band 1 steht dann als normale Bandzeile mit Label in der statischen Liste. */
html.no-anim .stage1-card{ display: none; }

html.no-anim .bands{ position: static; display: flex; flex-direction: column; gap: 54px; margin: 90px auto; width: min(760px, 90vw); }
html.no-anim .band{ position: static; width: 100%; height: auto; transform: none !important; opacity: 1 !important; text-align: center; }
html.no-anim .band-shape{ width: min(100%, 460px); height: auto; margin: 0 auto; transform: none !important; }
html.no-anim .band-label{ position: static; display: block; font-size: 26px !important; margin-top: 10px; opacity: 1 !important; }
html.no-anim .outro{ margin-top: 90px; }

/* ------------------------------------------------- Standbild (Screenshots)
   Gesetzt von funnel.js, sobald ?p= / preview() ein Standbild stellt. Zweck
   ist allein die Reproduzierbarkeit: die Aufnahme soll zweimal hintereinander
   dasselbe Bild liefern, damit tools/vergleich.py eine Abweichung als echte
   Aenderung melden kann und nicht als Zufall.

   Deshalb `animation: none` und nicht `animation-play-state: paused` — pausiert
   wuerde an der Stelle eingefroren, an der die Animation gerade steht, und die
   ist von Lauf zu Lauf eine andere. Ohne Animation gilt der Grundzustand der
   Regel, und der ist immer derselbe.

   Im normalen Betrieb greift hier nichts. */
html.standbild *,
html.standbild *::before,
html.standbild *::after{
  animation: none !important;
  transition: none !important;
}

/* ====================================================================== */
/*  Touch: Trefferflaechen, Rueckmeldung, Geraeteaussparungen             */
/* ====================================================================== */
/* Alles hier greift nur auf Geraeten ohne Zeigegeraet bzw. auf schmalen
   Schirmen. Der Desktop laeuft durch keine dieser Regeln. */

/* Trefferflaechen auf 44 px. Das ist keine gerundete Zahl aus dem Nichts,
   sondern das Mass, unter dem eine Fingerkuppe das Ziel nicht mehr
   zuverlaessig trifft (WCAG 2.2, Target Size). Nachgemessen lagen sechs
   Elemente darunter, die kleinsten waren der Zurueck-Knopf des Formulars mit
   46x30 und die Fusszeilen-Links mit 24 px Hoehe.

   Vergroessert wird die FLAECHE, nicht die Schrift: die Links sollen aussehen
   wie vorher, nur mehr Rand haben. Deshalb inline-flex mit min-height statt
   groesserer font-size. In der Navigation ist dafuer Platz — sie ist 62 px
   hoch, das Ziel 44. */
@media (pointer: coarse){
  .nav-brand,
  .nav-right a,
  .footer-links a{
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .anfrage-zurueck{
    min-height: 44px;
    padding: 4px 10px;
  }
  /* Die Fusszeilen-Links stehen in einer Reihe: der groessere Abstand haelt
     die vergroesserten Flaechen auseinander, sonst grenzen sie aneinander und
     man trifft den Nachbarn. */
  .footer-links{ gap: 30px; }
}

/* Rueckmeldung beim Antippen. Ohne sie fuehlt sich ein Knopf auf dem Telefon
   tot an: zwischen Fingerdruck und der Reaktion der Seite liegt sonst nichts.
   Bewusst sehr kurz und ohne Uebergang — eine Animation waere langsamer als
   der Druck selbst. */
@media (hover: none){
  .btn:active{
    background: var(--kontrast);
    transform: translateY(1px);
  }
  .nav-right a:active,
  .footer-links a:active,
  .anfrage-zurueck:active{ opacity: 1; }
  .s1-peek-play:active{
    transform: translate(-50%, -50%) scale(0.96);
  }
}

/* Geraeteaussparungen (Notch, Home-Anzeige, gerundete Ecken). Ohne das
   schiebt sich der Fusszeileninhalt auf einem iPhone unter die Home-Anzeige
   und die Navigation unter die Statusleiste.
   env() ist auf Geraeten ohne Aussparung 0, die Regel kostet dort also
   nichts — sie steht trotzdem im Telefon-Zweig, damit auf dem Desktop
   garantiert nichts davon ausgewertet wird. */
@media (max-width: 640px){
  .nav{
    padding-left: max(clamp(20px, 4vw, 52px), env(safe-area-inset-left));
    padding-right: max(clamp(20px, 4vw, 52px), env(safe-area-inset-right));
  }
  .footer{
    padding-left: max(clamp(20px, 4vw, 52px), env(safe-area-inset-left));
    padding-right: max(clamp(20px, 4vw, 52px), env(safe-area-inset-right));
    padding-bottom: calc(40px + env(safe-area-inset-bottom));
  }
}

/* ============================ Telefon: Karten 2, 4 und 5 zum Passen bringen */
/* Die Kartenhoehe ist fest (min(82vh, 820px)) und muss es bleiben: funnel.js
   misst sie an der Stufe-1-Karte und rechnet daraus die Ruhelage ALLER fuenf
   Stufen. Eine Karte, die mitwaechst, verschoebe die Staffelung. Hoeher setzen
   geht auch nicht — die Ruhelage ist navH + (H - navH - Kartenhoehe)/2, und
   sobald die Karte hoeher als der Bildschirm wird, wandert sie hinter die
   Navigation.

   Unterhalb 640 px stapeln sich die Spalten aber untereinander (Regel weiter
   oben), und damit passt der Inhalt nicht mehr. Nachgemessen bei 390x844,
   verfuegbar sind 580 px:

       Karte 2   887 px Inhalt   307 zu viel
       Karte 4   829 px Inhalt   249 zu viel
       Karte 5   780 px Inhalt   200 zu viel

   Karte 1 und 3 passen und bleiben deshalb unberuehrt.

   Muesste allein die Anschauung schrumpfen, fiele das Chat-Fenster auf die
   Haelfte. Deshalb kommt der Platz aus drei Quellen: Innenabstand der Karte,
   etwas engerer Text — und erst dann die Anschauung. */
@media (max-width: 640px){
  /* Nur die Karten 2-5: die Stufe-1-Karte hat einen eigenen oberen Abstand
     (der Toggle sitzt hoeher) und passt ohnehin. */
  /* Etwas hoehere Karten. 82vh -> 90vh bringt bei 780 px Fensterhoehe 62 px,
     und mehr ist nicht drin: die Ruhelage ist navH + (H - navH - Kartenhoehe)/2,
     bei 90vh sind das noch 8 px Luft unter der Navigation, bei 95vh waere der
     Wert negativ und die Karte startete dahinter.

     Gerechnet wird der Anteil aber NICHT von `vh`, sondern von der gemessenen
     Buehnenhoehe (`--buehne-h`, gesetzt in funnel.js/measure). Auf dem Desktop
     ist das derselbe Wert; auf dem Telefon nicht, und genau daran hing ein
     gemeldeter Fehler: `vh` ist dort immer die Hoehe mit EINGEZOGENER
     Adressleiste, H die mit ausgefahrener. Bei 844 zu 756 wurde die Karte
     760 px hoch, waehrend measure() ihre Lage aus 756 rechnete — die Formel
     oben ergab dann -33 px statt +11, und die Karte lag ueber der unteren
     Haelfte ihres Banners. Mit --buehne-h koennen die beiden nicht mehr
     auseinanderlaufen.

     Der Rueckfallwert 100vh gilt nur fuer die Zeit vor dem ersten measure()
     und fuer den Fall ohne JS — dort stand vorher ebenfalls vh.

     Der dritte Term ist ein Riegel gegen sehr flache Fenster. Aus derselben
     Formel folgt: bei 0.9 * H bleiben (0.1 * H - navH) / 2 Luft, und das wird
     unter rund 620 px Buehnenhoehe negativ — auf einem kleinen Telefon mit
     ausgefahrener Leiste (iPhone SE: rund 553 px) laege die Karte dann wieder
     ueber ihrem Band, nur weniger weit. `H - navH - 16px` haelt in jedem Fall
     8 px auf jeder Seite frei. Bei 844 px bindet er nicht (766 gegen 760), die
     Lage auf den ueblichen Geraeten aendert er also nicht. */
  .stage1-card, .flow-card{
    height: min(calc(var(--buehne-h, 100vh) * 0.9),
                820px,
                calc(var(--buehne-h, 100vh) - var(--nav-h) - 16px));
  }
  .flow-card{
    padding-top: clamp(22px, 3.2vh, 34px);
    padding-bottom: clamp(22px, 3.2vh, 34px);
  }
  .s2-sub, .s4-sub, .s5-sub{ font-size: 17px; line-height: 1.5; }
  .s2-list,
  .s4-list{
    gap: clamp(8px, 1.2vh, 14px);
    margin-top: clamp(12px, 1.7vh, 20px);
  }

  /* ---- Der Kartenkopf enger, auf Wunsch --------------------------------
     Gemeldet nach der Geraetepruefung: "alles in der Karte ist ein bisschen
     zu tief". Nachgemessen bei 412 px Breite und 720 px Buehnenhoehe (die
     Masse des gemeldeten Geraets), Abstand von der Kartenoberkante bis zur
     Ueberschrift:

         Stufe 1   132 px     <- Polster + Toggle + Luft + 32 px Spaltenpolster
         Stufe 2    26 px
         Stufe 3    78 px     <- Toggle-Ausgleich
         Stufe 4    26 px
         Stufe 5    78 px

     Zwei Dinge fielen dabei auf. Erstens war der Wert schon vorher
     uneinheitlich: der Toggle-Ausgleich der Stufen 3 und 5 rechnet mit dem
     Kartenpolster der geteilten Regel (6.5vh), auf dem Telefon gilt aber ein
     kleineres (3.2vh) — er zielt also auf eine Hoehe, die es hier nicht gibt.
     Zweitens ragte der Inhalt unten ueber die Karte hinaus: 13 px bei Stufe 1
     und 2, 36 px bei Stufe 4 und 5. Genau das sieht man auf den Aufnahmen als
     angeschnittene Anschauung.

     Beides kommt aus derselben Ecke, deshalb hier gesammelt: die Abstaende im
     Kartenkopf werden enger, und der Toggle-Ausgleich faellt auf dem Telefon
     weg. Er ist ohnehin eine Desktop-Ueberlegung — dort stehen Text und
     Anschauung nebeneinander und alle fuenf Stufen sollen auf derselben Hoehe
     beginnen. Auf dem Telefon stapeln sie, und die Stufen 2 und 4 beginnen
     schon laengst am Polster. */
  .stage1-card{ padding-top: clamp(20px, 3vh, 36px); }
  .flow-card{
    padding-top: clamp(18px, 2.6vh, 30px);
    padding-bottom: clamp(18px, 2.6vh, 30px);
  }
  /* Steht NACH der Toggle-Ausgleich-Regel der Stufen 3 und 5 und hat dieselbe
     Spezifitaet — deshalb gewinnt sie hier und der Ausgleich ist weg. */
  .s1-static,
  .s2-cols,
  .s3-cols,
  .s4-cols,
  .s5-cols{
    margin-top: clamp(14px, 2vh, 24px);
    gap: 10px;
  }
  /* Die 32 px halten auf dem Desktop die Ueberschrift auf Hoehe der
     BILD-Oberkante der rechten Spalte. Gestapelt gibt es keine rechte Spalte,
     die Zeile schiebt die Ueberschrift nur nach unten. */
  .s1-static-copy{ padding-top: 0; }

  /* Und die Anschauungen selbst. `zoom` und nicht `transform: scale()`, weil
     nur zoom auch den Platzbedarf im Layout mitnimmt — eine Transformation
     verkleinert das Bild, laesst aber die Luecke in voller Groesse stehen, und
     dann waere nichts gewonnen. Eine Hoehenbegrenzung waere ebenfalls falsch:
     die Mockups sind aus einem Dutzend Einzelteilen gestapelt, ein max-height
     wuerde sie unten abschneiden statt verkleinern.

     Die Faktoren sind nicht gerundet geraten, sondern so gewaehlt, dass die
     Summe je Karte genau in den Slot passt. */
  /* Karte 4 traegt den laengsten Text (ein Absatz plus vier Punkte, davon
     zwei zweizeilig) und die hoechste Anschauung. Nach dem Engersetzen des
     Kartenkopfes blieben bei 720 px Buehnenhoehe noch 8 px Ueberlauf; die
     kommen aus dem Chat-Fenster. Nachgemessen bei 412x806 mit 720 px Buehne,
     Rest zwischen Inhaltsunterkante und Kartenkante:

         0.58   -8 (Ueberlauf)
         0.52   11
         0.49   23

     0.49 nimmt die Reserve, die auch die schmalen Telefone brauchen. Karte 2
     einen Hauch mit, damit die Reserve dort aehnlich ausfaellt. */
  .s2-browser{ zoom: 0.54; }
  .s4-chat{ zoom: 0.49; }
  .s5-cal{ zoom: 0.75; }

  /* Die gestapelte Spalte setzt alles linksbuendig (align-items: flex-start),
     was fuer den Text richtig ist und fuer die Anschauung nicht: die stand
     dadurch an der linken Kante statt unter der Mitte des Textes. Nur diese
     vier zuruecknehmen, der Text bleibt linksbuendig. */
  .s2-browser,
  .s3-form,
  .s4-chat,
  .s5-cal{ align-self: center; }
}

/* Schmale Telefone (360 px und darunter). Nicht die Hoehe ist hier das
   Problem, sondern die Breite: der Text bricht eine Zeile mehr um, und die
   Karten 2 und 5 liefen dadurch wieder ueber die Kante — nachgemessen bei
   360x800 mit 714 px Buehne 2 bzw. 7 px. Es sind dieselben Werte, die die
   kurzen Telefone ohnehin bekommen.
   Steht NACH dem 640er-Block, sonst gewaenne dessen spaetere Regel. */
@media (max-width: 460px){
  .s2-browser{ zoom: 0.50; }
  .s5-cal{ zoom: 0.69; }
}

/* Kurze Telefone (iPhone SE und Verwandte, 667 px hoch). Hier reicht das
   Verkleinern der Anschauung allein nicht mehr: Karte 4 traegt einen Absatz
   plus vier Aufzaehlungspunkte, und der Text allein fuellt bei 600 px
   Kartenhoehe fast den ganzen Slot. Waere nur die Anschauung der Regler,
   muesste das Chat-Fenster auf 39 Prozent — dann ist es Dekoration und keine
   Anschauung mehr.

   Also wird hier auch der Text kleiner. 16 px sind fuer einen kurzen
   Erklaerabsatz vertretbar; unter 16 ginge es an die Lesbarkeit, und dann
   waere die richtige Antwort, den Text zu kuerzen statt ihn zu schrumpfen. */
@media (max-width: 640px) and (max-height: 720px){
  .s2-sub, .s4-sub, .s5-sub{ font-size: 16px; line-height: 1.45; }
  .s2-list, .s4-list{ gap: 8px; margin-top: 12px; }
  .s2-list li, .s4-list li{ font-size: 16px; }
  .s1-peek-img{ height: clamp(150px, 26vh, 200px); }
  .s2-browser{ zoom: 0.50; }
  .s4-chat{ zoom: 0.50; }
  .s5-cal{ zoom: 0.70; }
}

/* =========================== Telefon: Balken am unteren Bildrand vermeiden */
/* Auf dem Telefon zieht der Browser seine Adressleiste beim Scrollen ein. Das
   Sichtfenster wird dabei hoeher, die Layout-Ebene aber nicht — und unter den
   bildschirmfuellenden Ebenen (`inset: 0`) blitzt fuer einen Moment die nackte
   Cremeflaeche des Dokuments durch. Der Nutzer sieht das als hellen Balken,
   der von unten hereinfaehrt und wieder verschwindet.

   `lvh` ist die Bildhoehe MIT eingezogener Leiste, also die groesste, die
   vorkommen kann. Die beiden Ebenen sind damit in jedem Zustand mindestens so
   hoch wie das Sichtfenster. Was bei ausgefahrener Leiste unten uebersteht,
   liegt hinter ihr und stoert nicht — es ist Hintergrund.

   `bottom: auto` ist noetig, weil `inset: 0` sonst mit der Hoehe streitet. */
@media (max-width: 640px){
  .flow-bg{ bottom: auto; height: 100lvh; }

  /* Zweiter Anlauf: der Balken war damit weg, die KANTE nicht.
     Was uebrig blieb, war die Naht zwischen zwei verschiedenen Bildern. Der
     Streifen ist ja nicht leer — er zeigt jetzt `.flow-bg`, also den Stoff des
     Mittelteils, waehrend darueber noch das Hero-Bild steht. Zwei Fotos, harte
     Grenze quer ueber den Schirm: genau die "Barriere", die der Auftraggeber
     nach der ersten Runde noch gesehen hat.

     Also traegt der Streifen jetzt DASSELBE Bild weiter. `.hero-bg` steckt in
     der Buehne und die schneidet an ihrer Unterkante ab (`overflow: hidden`),
     kommt als Traeger also nicht in Frage. `.flow-bg` liegt dagegen frei und
     ist ohnehin schon 100lvh hoch — sie bekommt das Hero-Bild als zweite
     Lage obendrauf.

     Damit die Naht wirklich verschwindet, muessen beide Lagen DENSELBEN
     Bildausschnitt zeigen. `cover` rechnet den Ausschnitt aus der Boxhoehe;
     also bekommt `.hero-bg` hier ebenfalls 100lvh, obwohl die Buehne sie
     frueher abschneidet. Gleiche Breite, gleiche Hoehe, gleicher Ursprung
     oben — gleicher Ausschnitt.

     Deckkraft und Versatz kommen aus funnel.js (dieselben Werte wie fuer
     `.hero-bg`, siehe render()); ohne JS bleibt die Lage unsichtbar, der
     Vorher-Zustand also unveraendert. */
  .hero-bg{ bottom: auto; height: 100lvh; }
  .flow-bg::after{
    content: "";
    position: absolute;
    inset: 0;
    background: var(--creme) url("../assets/hero-bg.jpg") center / cover no-repeat;
    opacity: calc(var(--saum-hero, 1) * var(--saum-buehne, 0));
    transform: translate3d(0, var(--saum-y, 0px), 0);
  }
}
/* Die Buehne selbst bleibt bewusst auf `inset: 0`. Sie waere der naechste
   Kandidat, aber ihre Hoehe IST die Rechengroesse der ganzen Sequenz
   (`H = stage.clientHeight` in funnel.js). Auf `lvh` gesetzt waere H immer die
   Hoehe MIT eingezogener Leiste — und alles, was unten verankert ist, laege
   hinter der ausgefahrenen Leiste. Der Balken verschwindet auch so: dahinter
   steht dann der Stoffgrund des Mittelteils statt der nackten Cremeflaeche. */

/* ================ Telefon: Foto und Video auf der Stufe-1-Karte auf Hoehe */
/* Die Karte traegt zwei Erklaersaetze, je einen fuer Foto und Video, und zeigt
   immer nur den passenden. Auf dem Telefon bricht der Video-Satz eine Zeile
   mehr um: nachgemessen 173 px gegen 144. Beim Umschalten sprang die Anzeige
   darunter deshalb um genau diese 29 px nach unten.

   Loesung: beide Saetze in dieselbe Rasterzelle. Die Zeile ist dann so hoch
   wie der laengere von beiden, und der Wechsel verschiebt nichts mehr.
   Sichtbar/unsichtbar laeuft dabei ueber `visibility` statt `display`, denn
   ein Satz auf `display: none` traegt keine Hoehe bei — und genau die wird
   hier gebraucht. `visibility: hidden` nimmt ihn trotzdem aus der
   Vorlesereihenfolge, der Screenreader liest also weiterhin nur einen. */
@media (max-width: 640px){
  .stage1-card .s1-static-copy{
    display: grid;
    grid-template-columns: 1fr;
    align-content: start;
  }
  .stage1-card .s1-static-head{ grid-row: 1; grid-column: 1; }
  .stage1-card .s1-static-sub{
    grid-row: 2;
    grid-column: 1;
    display: block;
    visibility: hidden;
  }
  .stage1-card .s1-sub--static{ visibility: visible; }
  .stage1-card[data-state="video"] .s1-sub--static{ display: block; visibility: hidden; }
  .stage1-card[data-state="video"] .s1-sub--video{ display: block; visibility: visible; }
}

/* ================================ Telefon: kein Zoom beim Antippen im Formular */
/* Die Eingabefelder stehen auf 15 px. iOS Safari zoomt beim Fokussieren
   automatisch hinein, sobald ein Feld kleiner als 16 px schreibt — das ist
   kein Fehler des Browsers, sondern seine Lesbarkeitshilfe. Der Zoom
   verschiebt aber den Bildausschnitt, und die Ueberschrift "Terminanfrage"
   ueber dem Formular rutscht dabei aus dem Bild. Zurueckzoomen kann man von
   Hand, aber der Nutzer weiss nicht, wohin es verschwunden ist.

   16 px sind die Schwelle, ab der Safari es laesst. Sichtbar ist der
   Unterschied kaum; das Formular wird dadurch nur unwesentlich hoeher. */
@media (max-width: 640px){
  .anfrage-feld input,
  .anfrage-feld textarea,
  .s3-eingabe{ font-size: 16px; }
}

/* ===================== Kurze Telefone: Schlussbild und Formular kompakter */
/* Die Hoehe des Schlussbilds wird nicht vom Schlussbild bestimmt, sondern vom
   FORMULAR: beide liegen im selben Rasterfeld uebereinander (siehe
   .outro-swap), und das Feld ist so hoch wie das hoechste der drei. Das
   Formular misst auf 375 px Breite 618 px — zwischen Navigation und Unterkante
   eines 667 px hohen Telefons passen aber nur 605.

   Deshalb hier enger: kleinere Innenabstaende in den Feldern, dichteres
   Raster, schmaleres Panel. Die 16 px Schriftgroesse der Felder bleiben
   unangetastet — sie sind kein Schmuck, sondern verhindern, dass iOS beim
   Antippen hineinzoomt. */
@media (max-width: 640px) and (max-height: 720px){
  .anfrage{ padding: 12px 12px; }
  .anfrage-titel{ font-size: 20px; }
  .anfrage-feld input{ padding: 9px 16px; }
  .anfrage-raster{ row-gap: 4px; }
  .anfrage-aktion{ margin-top: 8px; }
  /* Die Stufe-1-Karte ragte hier um 5 px heraus, seit beide Erklaersaetze
     denselben Platz belegen (siehe Raster-Regel weiter oben). Das Bild traegt
     die Differenz. */
  .s1-peek-img{ height: clamp(136px, 24vh, 190px); }
}
