/* =============================================================================
   Myra — Landing. Stand 28.08.2026.
   Ersetzt die deutsche Fassung vollstaendig (gesichert als Tag
   `website/stand-20260828`). Text: web/COPY_EN_2026-08.md, acht Bloecke.
   Bauplan: web/REFERENZ_VERTUS.md.

   -----------------------------------------------------------------------------
   1 · DIE MARKE — Joels Festlegung vom 28.08.2026
   -----------------------------------------------------------------------------
   Weiss, Schwarz, Blau. Kein Gold, kein Beige. Das Blau ist aus Joels
   Referenzbild GEMESSEN, nicht gewaehlt: Farbton 219-223 Grad, volle Saettigung,
   helle Kerne kippen Richtung Cyan.

     Rolle                    Wert       Farbton   Kontrast
     Seitengrund hell         #FFFFFF    --        --
     Buehne dunkel            #05070E    226,7     --
     Blau fuer Text auf Weiss #0A2E9E    225,4     11,07:1 auf Weiss
     Blau kraeftig            #0B3FD1    224,2      7,94:1 auf Weiss
     Flow-Tiefe   (P25)       #001A4D    219,7      --
     Flow-Mitte   (P50)       #002887    222,2      --
     Flow-Koerper (P75)       #0B3FD1    224,2      2,54:1 auf der Buehne
     Flow-Kern    (P95)       #3795EF    209,3      6,43:1 auf der Buehne
     Flow-Spitzlicht (P99)    #5B9BFF    216,6      7,26:1 auf der Buehne
     Tinte                    #0F1115    220,0     18,90:1 auf Weiss

   Auch die Grautoene sind dieses Blau, nur entsaettigt: --gedaempft 219,3 ·
   --linie-stark 220,0 · --buehne-gedaempft 220,6 · --linie 220,0. Die Seite hat
   keinen einzigen neutralen Grauwert; jede Flaeche liegt im gemessenen Band.

   NACHGERECHNET, NICHT BEHAUPTET: jede Zahl oben steht so in kontrast.py und
   wird bei jedem Lauf neu gerechnet. `python3 web/landing-neu/kontrast.py`
   muss mit 0 zurueckkommen. Kommentare luegen, das Skript nicht.

   -----------------------------------------------------------------------------
   2 · TIEFE — benannte Stufen
   -----------------------------------------------------------------------------
   Die alte Regel aus docs/marke.md ("eine Schattenfamilie, weich und flach —
   Papier, kein Startup-Gluehen") ist am 28.08.2026 gefallen. Joel ausdruecklich:
   "die Buttons mit Schatten in Farbverlaeufen." vertus.ai traegt gemessen 194
   border-radius, 42 Verlaeufe, 40 Schatten, 30 Weichzeichner. Tiefe ist gewollt.

   An ihre Stelle treten FUENF benannte Stufen. Mehr gibt es nicht; wer eine
   sechste braucht, hat ein Layoutproblem, kein Schattenproblem.

     --tiefe-1  KANTE    Karte in Ruhe. Haarlinie plus ein Hauch Streuung.
                         Sie hebt die Karte vom Grund ab, nicht von der Seite.
     --tiefe-2  ABHEBEN  Karte unter dem Zeiger, Produktausschnitt, Portraet.
                         Doppelt so weit gestreut, immer noch blau statt schwarz.
     --tiefe-3  KNOPF    Primaerknopf in Ruhe. Drei Lagen: Innenlicht oben
                         (die Kante faengt Licht), harter Nahschatten (er liegt
                         auf), farbiger Fernschatten (er leuchtet).
     --tiefe-4  GRIFF    Primaerknopf unter dem Zeiger. Dieselben drei Lagen,
                         weiter und farbiger. Der Knopf kommt entgegen.
     --tiefe-glut GLUT   Nur auf der dunklen Buehne. Kein Umgebungsschatten —
                         auf Schwarz sieht man keinen Schatten, nur Licht.
                         Ein blauer Rand plus ein weiter, tiefer Schein.

   Alle Schattenfarben sind das Blau (10 46 158 / 11 63 209 / 91 155 255), nie
   Schwarz. Ein schwarzer Schatten unter einer blauen Flaeche wird grau und
   schmutzig; ein blauer bleibt Farbe.

   -----------------------------------------------------------------------------
   3 · DIE NAHT ZUM FLOW (web/landing-neu/flow.js, anderer Bau)
   -----------------------------------------------------------------------------
   Vollstaendiger Vertrag: web/landing-neu/FLOW_KONTRAKT.md. Kurzfassung:

     <div class="buehne" data-flow="ruhig|stroemung|strom">
       <div class="buehne-ersatz" aria-hidden="true"></div>   Ersatzverlauf, CSS
       <canvas class="buehne-flow" data-flow-canvas aria-hidden="true"></canvas>
       <div class="buehne-inhalt"> ... </div>
     </div>

   · Drei Buehnen, drei benannte Zustaende: ruhig (Kopf) · stroemung
     (Zwischenruf) · strom (Abschluss und Aufforderung).
   · Der Ersatzverlauf liegt IMMER darunter und ist der Grund. Er greift ohne
     JavaScript, vor dem Laden von flow.js und bei prefers-reduced-motion.
     Die Seite ist ohne flow.js vollstaendig und schoen — das ist die Bedingung,
     unter der die Naht ueberhaupt erlaubt ist.
   · Das Canvas liegt IM MARKUP und gehoert der Huelle. flow.js erzeugt keines,
     es zeichnet in das vorhandene. Es startet auf opacity 0; erst wenn flow.js
     sein erstes Bild gezeichnet hat, setzt es .flow-laeuft auf die Buehne, und
     dann blendet das Canvas ueber den Ersatzverlauf. Kein Aufblitzen, kein
     leeres Schwarz. Beim Abbau nimmt flow.js die Klasse wieder herunter.
   · Bei prefers-reduced-motion nimmt CSS das Canvas hart aus dem Fluss.
   · SECHS Farbmerkmale, nicht drei (Token-Block unten): flow.js liest die
     ganze Rampe --flow-grund … --flow-spitze. kontrast.py vergleicht die Liste
     mit der in flow.js — ein Name, zwei Farben ist genau der Fehler, den hier
     am 28.08. niemand gesehen haette (FLOW_KONTRAKT.md §3).
   · Lesbarkeit: die Huelle legt ihren Text OHNE Schleier auf die Buehne.
     Deshalb misst flow.js die Textkaesten in .buehne-inhalt und deckelt dort
     seine Helligkeit auf #043AA9 — weiss 9,6:1, --buehne-gedaempft 5,3:1.
     Gemessen mit flow-messen.py, nicht behauptet.

   -----------------------------------------------------------------------------
   4 · SCHRIFT
   -----------------------------------------------------------------------------
   Aspekta Variable 2.100 (Ivo Dolenc), SIL Open Font License 1.1, Reserved Font
   Name "Aspekta" — Lizenztext liegt bei: fonts/OFL-Aspekta.txt. Dieselbe Schrift
   wie vertus.ai, ein Achsengewicht 100-900, 30 KB fuer die ganze Familie.
   Unveraendert uebernommen; der Reserved Font Name verbietet Aenderung unter
   diesem Namen, und wir aendern nichts.

   Aspekta 2.100 hat kein Paragraphenzeichen (U+00A7) und keine Tilde (U+007E).
   Beide stehen auf der Seite ("§ 7 UWG") und massenhaft auf Impressum und
   Datenschutzerklaerung. Dafuer liegt ein 1,8-KB-Ausschnitt aus Inter daneben
   (fonts/ergaenzung-latin.woff2, OFL 1.1 ohne Reserved Font Name, Lizenztext
   fonts/OFL-Inter.txt), per unicode-range auf genau diese zwei Zeichen begrenzt.
   Der Browser laedt ihn nur, wenn eines davon vorkommt.

   BEIDE liegen lokal in fonts/. Kein CDN, kein fremder Host — das ist keine
   Geschmacksfrage, sondern die Zusage im Fuss der Seite: "This page loads no
   script, no font and no image from a third-party server."

   -----------------------------------------------------------------------------
   5 · BEWEGUNG
   -----------------------------------------------------------------------------
   Handgeschrieben: IntersectionObserver plus CSS-Uebergaenge, main.js, rund
   siebzig Zeilen. Keine Bibliothek. vertus laedt GSAP, Lenis, Swiper und jQuery
   von fremden Servern und braucht deshalb ein Einwilligungsbanner. Wir nicht.

   prefers-reduced-motion: reduce schaltet ALLES ab — Einblenden, Flow,
   Wortwechsel. Und ohne JavaScript ist nichts verborgen: jede Regel, die etwas
   unsichtbar macht, haengt an .js am <html>.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   Schrift
   --------------------------------------------------------------------------- */

@font-face {
  font-family: "Aspekta";
  src: url("fonts/aspekta-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Die Wortmarke laeuft in Outfit (SIL OFL, fonts/OFL-Outfit.txt) — beschlossen
   von Joel am 30.08.2026, zusammen mit dem Cut-m. Nur die Marke; der Text der
   Seite bleibt Aspekta. Selbst gehostet wie alles hier — ein Fremdabruf waere
   der einzige der ganzen Seite. */
@font-face {
  font-family: "Outfit";
  src: url("fonts/outfit-latin-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Nur U+007E und U+00A7. Aspekta 2.100 hat beide nicht; ohne diese Zeile
   springt der Browser fuer jedes Paragraphenzeichen in die Systemschrift und
   das Impressum bekommt acht fremde Glyphen. */
@font-face {
  font-family: "Ergaenzung";
  src: url("fonts/ergaenzung-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+007E, U+00A7;
}

/* ---------------------------------------------------------------------------
   Token
   --------------------------------------------------------------------------- */

:root {
  /* Flaechen */
  --grund: #ffffff;
  --flaeche: #f1f5fd;
  --flaeche-2: #e2eaf8;
  --buehne: #05070e;

  /* Schrift auf hellem Grund */
  --tinte: #0f1115;
  /* vertus faerbt seinen Fliesstext #808080. Das sind auf Weiss 3,95:1 und
     reisst SC 1.4.3. #5B6577 ist der hellste Ton, der auf ALLEN drei hellen
     Gruenden traegt — auch auf --flaeche-2 (#E2EAF8), dem dunkelsten davon:
     5,88 / 5,38 / 4,86:1. Von #4B5568 aus ein sichtbarer Schritt Richtung
     vertus, ohne die Schwelle zu reissen. kontrast.py rechnet es nach. */
  --gedaempft: #5b6577;
  --akzent: #0a2e9e;
  --akzent-stark: #0b3fd1;
  --akzent-licht: #1350d8;

  /* Linien auf hellem Grund */
  --linie: #dde4f2;
  --linie-stark: #6e7686;

  /* Auf der dunklen Buehne */
  --buehne-tinte: #ffffff;
  --buehne-gedaempft: #b6c1d7;
  --buehne-linie: #1b2436;
    --knopf-hell: #1e63e8;

  /* Flow — die SECHS Stufen der Rampe, von flow.js ueber getComputedStyle
     gelesen. EINE Quelle fuer Shader und Ersatzverlauf; Reihenfolge und Namen
     stehen genauso in flow.js (FARBEN) und werden von kontrast.py verglichen.
     Die Werte sind Joels Perzentile aus dem Referenzbild: P25 / P50 / P75 /
     P95 / P99, dazu der Grund aus den Ecken.
     --flow-koerper ist die P75-Stufe — die dunklere P50-Stufe heisst
     --flow-mitte. Warum das wichtig ist: FLOW_KONTRAKT.md §3.

     ⚠ 29.08.2026: zwei der sechs Stufen sind NICHT mehr Joels Perzentile.
     Gemessen kippten die hellen Stufen Richtung Cyan (Spitze #43CFFF lag bei
     Farbton 195,3 — das Referenzbild hat sie so hergegeben, aber die Marke
     kennt kein Cyan). Joel: das ist das falsche Blau. Ersetzt sind genau die
     zwei, die man sieht: --flow-koerper #074AC7 -> #0B3FD1 (das Blau kraeftig
     der Marke) und --flow-spitze #43CFFF -> #5B9BFF. Damit liegt die ganze
     Rampe im Band 209-224 Grad statt 195-224, und die Spitze traegt auf der
     Buehne 7,26:1 statt 11,13:1 — weniger Reserve, immer noch weit ueber der
     Schwelle. Nachgerechnet in kontrast.py, nicht geschaetzt. */
  --flow-grund: #05070e;
  --flow-tiefe: #001a4d;
  --flow-mitte: #002887;
  --flow-koerper: #0b3fd1;
  --flow-kern: #3795ef;
  --flow-spitze: #5b9bff;

  /* Schriftgroessen — gemessen an vertus.ai (28.08.2026), nicht geschaetzt:
     H1 48 px / Gewicht 500 / Laufweite -1,44 px, H2 40 px / -1,2 px,
     Fliesstext 16 px. Myra stand vorher bei 100 px H1 und 18 px Text.
     Die Riesenzeile DARF jetzt kleiner werden, weil ein Bild die Seite
     traegt — das ist der ganze Grund, warum vertus mit 48 px auskommt.
     clamp-Deckel so gesetzt, dass 1440 px Fensterbreite genau die
     gemessenen Werte ergibt: 3,35vw = 48,2 px, 2,8vw = 40,3 px. */
  --t-riese: clamp(2.125rem, 3.35vw, 3.25rem);
  --t-gross: clamp(1.625rem, 2.8vw, 2.5rem);
  --t-mittel: clamp(1.125rem, 1.35vw, 1.375rem);
  --t-text: 1rem;
  --t-klein: 0.9375rem;
  --t-mikro: 0.8125rem;

  /* Raster */
  --breit: 1180px;
  --schmal: 720px;
  --luft: clamp(20px, 4vw, 40px);
  --abschnitt-luft: clamp(76px, 9vw, 148px);

  /* Radien — vertus benutzt ELF verschiedene Werte, bis 60 px und 500 px.
     Myra hatte vier. Rund ist hier kein Zierrat, sondern das, was die Seite
     von einem Formular unterscheidet. Jeder Wert unten kommt im Blatt
     mindestens einmal vor; ein Token, das nichts faerbt, waere gelogen. */
  --r-mikro: 4px;
  --r-fein: 6px;
  --r-klein: 10px;
  --r: 14px;
  --r-mittel: 18px;
  --r-gross: 24px;
  --r-weit: 32px;
  --r-schale: 40px;
  --r-buehne: 60px;
  --r-band: 500px;
  --r-voll: 999px;

  /* Tiefe. Fuenf Stufen, benannt im Kopf dieser Datei. */
  --tiefe-1:
    0 1px 2px rgb(10 46 158 / 0.06),
    0 8px 20px -12px rgb(10 46 158 / 0.22);
  --tiefe-2:
    0 2px 4px rgb(10 46 158 / 0.08),
    0 22px 48px -20px rgb(10 46 158 / 0.34);
  --tiefe-3:
    inset 0 1px 0 rgb(255 255 255 / 0.24),
    0 1px 2px rgb(7 20 60 / 0.30),
    0 12px 26px -12px rgb(11 63 209 / 0.62);
  --tiefe-4:
    inset 0 1px 0 rgb(255 255 255 / 0.30),
    0 2px 5px rgb(7 20 60 / 0.32),
    0 20px 44px -14px rgb(11 63 209 / 0.78);
  --tiefe-glut:
    0 0 0 1px rgb(55 149 239 / 0.30),
    0 28px 80px -26px rgb(11 63 209 / 0.90);

  /* Innenfase — das Detail, an dem vertus teuer aussieht: eine 1 px feine
     helle Kante oben links auf jeder Flaeche, als saesse Licht darauf.
     vertus traegt drei solche Schatten, Myra hatte einen. Jetzt drei
     eigenstaendige, plus die Innenkante in --tiefe-3 und --tiefe-4. */
  --fase: inset 1px 1px 0 rgb(255 255 255 / 0.65);
  --fase-blau:
    inset 1px 1px 0 rgb(255 255 255 / 0.9),
    inset 0 -1px 0 rgb(10 46 158 / 0.09);
  --fase-dunkel:
    inset 1px 1px 0 rgb(255 255 255 / 0.16),
    inset -1px -1px 0 rgb(255 255 255 / 0.05);

  /* Bewegung */
  --kurve: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dauer: 0.24s;
  --dauer-lang: 0.72s;
}

/* ---------------------------------------------------------------------------
   Grundlagen
   --------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* scroll-padding: sonst verschwindet das Sprungziel unter der Kopfleiste. */
  scroll-padding-top: 84px;
  /* clip statt hidden: `overflow-x: hidden` macht aus <body> einen eigenen
     Scroll-Behaelter — ScrollTrigger und Lenis rechnen dann am falschen
     Element. `clip` schneidet ab, ohne einen Behaelter aufzumachen. */
  overflow-x: clip;
}

/* ---------------------------------------------------------------------------
   Lenis — weiches Scrollen
   ---------------------------------------------------------------------------
   Die vier Regeln, die die Bibliothek braucht. Sie stehen HIER und nicht in
   einer zweiten Datei, weil die Seite genau ein Stylesheet laedt. Die Klassen
   setzt Lenis selbst; ohne Lenis greift keine davon.
   --------------------------------------------------------------------------- */

html.lenis,
html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: hidden;
}

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

body {
  margin: 0;
  background: var(--grund);
  color: var(--tinte);
  font-family: "Aspekta", "Ergaenzung", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--t-text);
  font-weight: 380;
  /* vertus setzt 16/20 (1,25). Auf Absaetze mit 60 Zeichen Zeilenmass ist das
     eine Wand — WCAG SC 1.4.8 nennt 1,5 als Richtwert fuer Textbloecke. 1,45
     ist der Schritt, den die Seite vertraegt: von 1,62 spuerbar dichter,
     ohne dass die langen Absaetze zulaufen. Bewusst NICHT auf 1,25. */
  line-height: 1.45;
  letter-spacing: -0.003em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/* Silbentrennung nur auf Deutsch. Englische Woerter auf dieser Seite sind
   kurz; deutsche Komposita sind es nicht — das laengste im Bestand ist
   „Auftragsverarbeitungsvertrag" (28 Zeichen, datenschutz.html). In einer
   350-px-Spalte reisst so ein Wort entweder die Zeile auf oder haengt ueber
   den Rand. `hyphens: auto` braucht das lang-Attribut und die Silbentabelle
   des Browsers, und genau deshalb steht es an :lang(de) und nicht an html:
   der Slogan im Kopf traegt lang="en" und ist damit automatisch ausgenommen.
   -webkit-hyphens fuer Safari vor 17. */
:lang(de) {
  -webkit-hyphens: auto;
  hyphens: auto;
}

h1,
h2,
h3 {
  margin: 0;
  /* vertus: Gewicht 500, Laufweite -1,44 px auf 48 px = -0,03em. */
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

p {
  margin: 0 0 1.05em;
  text-wrap: pretty;
}

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

a {
  color: var(--akzent);
  text-decoration-color: rgb(10 46 158 / 0.35);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: color var(--dauer) var(--kurve),
    text-decoration-color var(--dauer) var(--kurve);
}

a:hover {
  color: var(--akzent-stark);
  text-decoration-color: currentColor;
}

strong {
  font-weight: 640;
}

img,
svg,
canvas {
  display: block;
  max-width: 100%;
}

::selection {
  background: rgb(11 63 209 / 0.16);
}

:focus-visible {
  outline: 2px solid var(--tinte);
  outline-offset: 3px;
  border-radius: var(--r-mikro);
}

.buehne :focus-visible {
  outline-color: var(--flow-spitze);
}

/* Sprunglink — erste Taste auf jeder Seite. */
.sprung {
  position: absolute;
  left: 12px;
  top: -80px;
  z-index: 99;
  padding: 12px 18px;
  border-radius: var(--r-klein);
  background: var(--grund);
  color: var(--akzent);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--dauer) var(--kurve);
}

/* Der Schatten erst im Fokus. Ohne diese Trennung ragte der Schein des
   ausgeblendeten Sprunglinks oben links sichtbar in die Buehne — auf dem
   dunklen Kopf war das ein heller Fleck ohne Ursache. */
.sprung:focus {
  top: 12px;
  box-shadow: var(--fase), var(--tiefe-2);
}

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

/* 30.08.2026: `viewport-fit=cover` steht seit jeher im <head>, benutzt wurde
   env() nirgends — gemessen null Vorkommen. Auf einem Telefon mit Kerbe im
   Querformat lief der Text damit unter die Kerbe und unter die abgerundete
   Ecke. Es steht HIER und nicht an drei Einzelstellen, weil jede Spalte der
   Seite eine .wrap ist: Kopfleiste, Abschnitte, Fuss. Ohne Kerbe ist env()
   null, `max()` liefert dann exakt --luft — auf dem Schreibtisch aendert
   sich kein Pixel. Der 0px-Rueckfall in env() ist Pflicht: kennt ein Browser
   env() nicht, ist sonst die ganze Zeile ungueltig und die Luft weg. */
.wrap {
  width: 100%;
  max-width: var(--breit);
  margin-inline: auto;
  padding-inline:
    max(var(--luft), env(safe-area-inset-left, 0px))
    max(var(--luft), env(safe-area-inset-right, 0px));
}

.wrap-schmal {
  max-width: var(--schmal);
}

/* ---------------------------------------------------------------------------
   Knoepfe — Joels Satz: "die Buttons mit Schatten in Farbverlaeufen"
   --------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 28px;
  border: 0;
  border-radius: var(--r-voll);
  font: inherit;
  font-size: var(--t-klein);
  font-weight: 600;
  letter-spacing: -0.006em;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--dauer) var(--kurve),
    box-shadow var(--dauer) var(--kurve),
    background-color var(--dauer) var(--kurve),
    color var(--dauer) var(--kurve);
}

/* Der Pfeil ist gezeichnet, kein Zeichensatz-Glyph und kein Bild:
   ein 8x8-Quadrat, um 45 Grad gedreht, zwei Kanten sichtbar. */
.btn::after {
  content: "";
  width: 7px;
  height: 7px;
  border-top: 1.6px solid currentColor;
  border-right: 1.6px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.9;
  transition: transform var(--dauer) var(--kurve);
}

.btn:hover::after {
  transform: rotate(45deg) translate(2px, -2px);
}

.btn-primaer {
  /* Zwei Stops, beide gemessen: #0B3FD1 traegt weissen Text mit 7,94:1,
     #0A2E9E mit 11,07:1. Ein hellerer Stop waere huebscher und wuerde die
     4,5:1 reissen — deshalb steht er nicht hier. */
  background-image: linear-gradient(178deg, var(--akzent-stark) 0%, var(--akzent) 100%);
  color: #fff;
  box-shadow: var(--tiefe-3);
}

.btn-primaer:hover {
  background-image: linear-gradient(178deg, var(--akzent-licht) 0%, var(--akzent-stark) 100%);
  box-shadow: var(--tiefe-4);
  transform: translateY(-1px);
}

.btn-primaer:active {
  transform: translateY(0);
  box-shadow: var(--tiefe-3);
}

/* Auf dunklem Grund — Buehne und Kopfleiste — traegt der Knopf von oben mit
   2,54:1 gegen Schwarz keine erkennbare Grenze (SC 1.4.11 will 3:1). Zwei
   hellere Stops: #1E63E8 liegt bei 3,84:1 gegen die Buehne, #1350D8 bei
   3,04:1; weisser Text steht mit 5,24:1 bzw. 6,63:1 darauf.

   Und ein DURCHGEHENDER Rand im Spitzlicht. Er ist nicht Zierrat, er ist die
   Erfuellung: sobald der Flow hinter dem Knopf hell wird, faellt die Grenze
   Fuellung-gegen-Grund unter 3:1 — rechnerisch bei JEDER Aufhellung, weil der
   untere Stop schon auf blankem Schwarz nur 3,04:1 hat. Der Rand haelt
   dagegen: #5B9BFF steht ueber der hellsten Mischung der drei Buehnen noch
   mit 5,4 bis 6,0:1. kontrast.py rechnet beides nach. */
.buehne .btn-primaer,
.leiste .btn-primaer {
  background-image: linear-gradient(178deg, var(--knopf-hell) 0%, var(--akzent-licht) 100%);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.30),
    0 0 0 2px var(--flow-spitze),
    0 16px 46px -14px rgb(30 99 232 / 0.85);
}

.buehne .btn-primaer:hover,
.leiste .btn-primaer:hover {
  /* NICHT heller als --knopf-hell: weisser Text auf --flow-kern haette
     3,13:1. Der Zeiger-Zustand wird ueber Rand und Schein heller, nicht
     ueber die Fuellung. */
  background-image: linear-gradient(178deg, var(--knopf-hell) 0%, var(--akzent-stark) 100%);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.36),
    0 0 0 2px #fff,
    0 24px 60px -14px rgb(55 149 239 / 0.95);
}

.btn-still {
  background: var(--grund);
  color: var(--akzent);
  box-shadow: var(--fase), inset 0 0 0 1px var(--linie-stark);
}

.btn-still:hover {
  background: var(--flaeche);
  box-shadow: inset 0 0 0 1px var(--akzent-stark), var(--tiefe-1);
}

/* Zusatz hinter der Beschriftung: "45 minutes, free" traegt weniger Gewicht
   als "Pick a time", steht aber im selben Knopf. */
.btn-zusatz {
  font-weight: 420;
  opacity: 0.82;
}

/* ---------------------------------------------------------------------------
   Kopfleiste
   --------------------------------------------------------------------------- */

.leiste {
  position: sticky;
  top: 0;
  z-index: 40;
  /* Dunkles Glas — IMMER, nicht erst nach dem Scrollen. Ueber der Buehne
     verschwindet die Leiste im Grund, ueber den weissen Abschnitten steht sie
     als schwarzer Balken. Beides ist beabsichtigt, und beides funktioniert
     ohne JavaScript: eine Leiste, die ihre Farbe erst per Skript findet, ist
     ohne Skript weisse Schrift auf weissem Grund. */
  background: rgb(5 7 14 / 0.92);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border-bottom: 1px solid rgb(255 255 255 / 0.07);
  transition: background-color var(--dauer) var(--kurve),
    border-color var(--dauer) var(--kurve);
}

@supports not (backdrop-filter: blur(4px)) {
  .leiste {
    background: rgb(5 7 14 / 0.96);
  }
}

/* main.js setzt das, sobald der Waechter oben aus dem Bild ist. Reine Zugabe. */
.leiste.ist-gescrollt {
  background: rgb(5 7 14 / 0.95);
  border-bottom-color: rgb(55 149 239 / 0.28);
}

.leiste-innen {
  display: flex;
  align-items: center;
  gap: 20px;
  min-height: 68px;
}

.waechter {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
}

/* Die Wortmarke: das Cut-m als erster Buchstabe, "yra" als gesetzter Text
   (Joel, 30.08.2026 — „das m den cut hat wie das icon logo von der app").
   Markup und Begruendung stehen im Vorratsblock oben in index.html.

   Der Vorrat traegt nur das Symbol und darf keinen Platz belegen. Nicht
   `display: none`: ein `<use>`, das auf Inhalt in einem ausgeblendeten Baum
   zeigt, ist genau die Ecke, in der sich Browser unterschiedlich verhalten.
   Aus dem Fluss nehmen und auf null setzen tut dasselbe und ist unstrittig. */
.marke-vorrat {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Die zwei Masse sind die Metrik der Glyphe, nicht geschaetzt: Outfit Medium,
   upm 1000, das kleine m hat 861 Einheiten Vorbreite und 490 Einheiten Hoehe
   (mit fontTools aus `fonts/outfit-latin-500.woff2` gelesen). In em gesetzt
   waechst das Zeichen deshalb exakt mit dem Text daneben — Kopfleiste 1,5rem,
   Fuss 1,625rem, eine Regel.

   `display: inline-block` hebt die globale Regel `svg { display: block }` auf.
   `vertical-align: baseline` legt die Unterkante des Kastens auf die
   Grundlinie, und die Unterkante IST die Grundlinie des m: der Ausschnitt des
   Symbols endet bei y=48, wo die Glyphe aufsitzt. */
.marke-m {
  display: inline-block;
  vertical-align: baseline;
  width: 0.861em;
  height: 0.49em;
}

.marke-wort {
  margin: 0;
  margin-right: auto;
  color: var(--buehne-tinte);
  text-decoration: none;
  /* Groesser als der alte 17-px-Schriftzug (Joel, 30.08.2026: "groesser als
     das jetztige") und in der Markenschrift statt Aspekta. */
  font-family: "Outfit", "Aspekta", "Ergaenzung", system-ui, sans-serif;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.marke-wort:hover {
  color: var(--flow-spitze);
}

.leiste-nav {
  display: flex;
  gap: 26px;
}

/* Das padding ist ein Tippziel, kein Abstand. Nachgerechnet, nicht geraten:
   15 px Schrift mal Zeilenhoehe 1,45 = 21,75 px Zeilenkasten; mit 2x12 px sind
   es 45,75 px. WCAG 2.2 SC 2.5.8 verlangt 24 px, Apple und Google nennen 44 —
   die Leiste ist 68 px hoch, der Platz ist da, also die groessere Zahl.
   Sichtbar aendert sich nichts: die Glieder stehen mittig in der Leiste.
   30.08.2026. */
.leiste-nav a {
  display: flex;
  align-items: center;
  padding-block: 12px;
  color: var(--buehne-gedaempft);
  font-size: var(--t-klein);
  font-weight: 480;
  text-decoration: none;
}

.leiste-nav a:hover {
  color: var(--buehne-tinte);
}

.leiste-rechts {
  display: flex;
  align-items: center;
  gap: 18px;
}

/* Der Sprachumschalter. Er liegt im Register von .leiste-anmelden — gleiche
   Groesse, gleiche Zeilenlage —, traegt aber weniger Gewicht und die
   gedaempfte Farbe: "Sign in" ist die Tuer nach innen, "Deutsch" ist eine
   Einstellung. Dasselbe Tippziel wie die Navigationsglieder: 21,75 + 2x12 =
   45,75 px. 30.08.2026. */
.leiste-sprache {
  display: flex;
  align-items: center;
  padding-block: 12px;
  color: var(--buehne-gedaempft);
  font-size: var(--t-klein);
  font-weight: 480;
  text-decoration: none;
}

.leiste-sprache:hover {
  color: var(--buehne-tinte);
}

/* Die globale Fokusregel setzt einen Rahmen mit 3 px Abstand. In einer 68 px
   hohen Leiste um ein 45,75 px hohes Glied herum stoesst der oben und unten
   an die Kante. 2 px Abstand halten ihn drin, ohne ihn zu verkleinern. */
.leiste-sprache:focus-visible {
  outline-offset: 2px;
}

.leiste-anmelden {
  display: flex;
  align-items: center;
  padding-block: 12px;
  color: var(--buehne-tinte);
  font-size: var(--t-klein);
  font-weight: 560;
  text-decoration: none;
}

.leiste-anmelden:hover {
  color: var(--flow-spitze);
}

/* 13 statt 11 px oben und unten: 13 px Schrift mal 1,45 = 18,85 px, plus
   2x13 = 44,85 px. Mit den alten 11 px waren es 40,85 px und damit unter dem
   Tippziel. In einer 68-px-Leiste faellt der Unterschied nicht auf.
   30.08.2026. */
.leiste-btn {
  padding: 13px 20px;
  font-size: var(--t-mikro);
}

/* ---------------------------------------------------------------------------
   Das Menue fuer schmale Schirme
   ---------------------------------------------------------------------------
   Ein <details>. Warum kein Knopf mit aria-expanded: index.html, am Markup.
   Kurz — <details> klappt der Browser selbst auf, ohne eine Zeile Skript, und
   meldet den Zustand selbst. Ein Knopf braeuchte JavaScript, um ueberhaupt
   etwas zu tun, und naehme die Navigation mit sich, wenn main.js ausfaellt.

   Ueber 900 px ist das Ganze display:none — dann tragen Leiste und
   .leiste-rechts die Glieder selbst. Unter 900 px ist es umgekehrt.
   --------------------------------------------------------------------------- */

.menue {
  display: none;
}

.menue-knopf {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-right: -10px; /* der Balken sitzt damit buendig zur Luft der .wrap */
  color: var(--buehne-tinte);
  cursor: pointer;
  /* Das Dreieck des Browsers weg — zwei Wege, weil zwei Familien es
     unterschiedlich zeichnen. */
  list-style: none;
}

.menue-knopf::-webkit-details-marker {
  display: none;
}

.menue-knopf:focus-visible {
  outline: 2px solid var(--flow-spitze);
  outline-offset: -2px;
  border-radius: var(--r-klein);
}

/* Drei Striche aus einem Element: der mittlere ist der Kasten selbst, die
   zwei anderen sind ::before und ::after. Im offenen Zustand faellt der
   mittlere weg und die beiden anderen kreuzen sich — dasselbe Element, kein
   zweites Zeichen, kein Bild. */
.menue-balken,
.menue-balken::before,
.menue-balken::after {
  display: block;
  width: 21px;
  height: 2px;
  border-radius: var(--r-voll);
  background: currentColor;
  transition: transform var(--dauer) var(--kurve), top var(--dauer) var(--kurve),
    background-color var(--dauer) var(--kurve);
}

.menue-balken {
  position: relative;
}

.menue-balken::before,
.menue-balken::after {
  content: "";
  position: absolute;
  left: 0;
}

.menue-balken::before {
  top: -6px;
}

.menue-balken::after {
  top: 6px;
}

.menue[open] .menue-balken {
  background: transparent;
}

.menue[open] .menue-balken::before,
.menue[open] .menue-balken::after {
  top: 0;
}

.menue[open] .menue-balken::before {
  transform: rotate(45deg);
}

.menue[open] .menue-balken::after {
  transform: rotate(-45deg);
}

/* Das Blatt haengt an der LEISTE, nicht am <details>: .leiste ist sticky und
   damit positioniert, also spannt left/right ueber die ganze Leistenbreite
   statt nur ueber den 44 px breiten Knopf. Es liegt im Stapel der Leiste
   (z-index 40) und deckt damit den Seiteninhalt darunter zu.
   `max-height` plus eigenes Rollen: im Querformat ist ein Telefon rund 390 px
   hoch, und sechs Glieder zu 48 px plus Knopf sind mehr. svh und nicht vh —
   sonst rechnet die Regel mit der eingefahrenen Adressleiste. */
.menue-blatt {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  display: flex;
  flex-direction: column;
  padding:
    6px
    max(var(--luft), env(safe-area-inset-right, 0px))
    calc(18px + env(safe-area-inset-bottom, 0px))
    max(var(--luft), env(safe-area-inset-left, 0px));
  /* Fast deckend und BEWUSST ohne backdrop-filter, anders als die Leiste
     darueber: das Blatt liegt in einem Element, das selbst einen
     backdrop-filter traegt, und geschachtelte Hintergrundfilter sampeln nicht
     die Seite, sondern den schon gefilterten Grund des Elternteils. Bei 2 %
     Restdurchsicht waere der Unterschied ohnehin nicht zu sehen — dann lieber
     die Regel, die in jedem Browser dasselbe tut. */
  background: rgb(5 7 14 / 0.98);
  border-bottom: 1px solid rgb(55 149 239 / 0.28);
  /* 68 px ist die min-height der Leiste, nicht geschaetzt: .leiste-innen. */
  max-height: calc(100svh - 68px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* `:not(.btn)` ist hier kein Zierrat, sondern das, was den Knopf heil laesst:
   `.menue-blatt a` waere spezifischer als `.btn` und wuerde ihm Gewicht,
   Groesse und die untere Trennlinie aufzwingen — ein Primaerknopf mit
   Schriftgewicht 480 und einem Strich darunter. So greifen die Listenregeln
   nur auf Listenglieder, und der Knopf behaelt seine eigenen. */
.menue-blatt a:not(.btn) {
  display: flex;
  align-items: center;
  min-height: 48px;
  color: var(--buehne-tinte);
  font-size: 1.0625rem;
  font-weight: 480;
  text-decoration: none;
  border-bottom: 1px solid var(--buehne-linie);
}

.menue-blatt a:not(.btn):hover {
  color: var(--flow-spitze);
}

/* Gleich spezifisch wie die Regel darueber (a + zwei Klassen) und danach
   notiert — deshalb gewinnt sie, ohne !important. Der Zeigerzustand liegt
   eine Stufe hoeher und bleibt davon unberuehrt. */
.menue-blatt a.menue-sprache {
  color: var(--buehne-gedaempft);
}

/* Der Knopf ist kein Listenglied: keine Trennlinie, volle Breite, Luft
   darueber. Er ist die Handlung, der Rest ist Weg.
   Zwischen 621 und 900 px steht derselbe Knopf auch in der Leiste. Das ist
   Absicht und keine Doppelung aus Versehen: das aufgeklappte Blatt deckt die
   Leiste zu, und ein Menue ohne die eine Handlung, um die es geht, schickt
   den Leser zum Zuklappen zurueck. */
.menue-btn {
  display: flex; /* .btn ist inline-flex; hier soll er die Breite fuellen */
  margin-top: 16px;
  min-height: 52px;
  justify-content: center;
}

/* ---------------------------------------------------------------------------
   Abschnitte und Rhythmus
   --------------------------------------------------------------------------- */

.abschnitt {
  padding-block: var(--abschnitt-luft);
}

/* Bandabschnitt: dieselbe Blaufläche, die auf Weiss eine Karte ist. Damit
   liegen nie zwei helle Abschnitte mit demselben Grund nebeneinander, und
   Karten sind auf dem Band weiss statt blau — sie kehren sich um. */
.band {
  background: var(--flaeche);
}

/* ---------------------------------------------------------------------------
   Die dunkle Buehne — Naht zu flow.js
   --------------------------------------------------------------------------- */

.buehne {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: var(--buehne);
  color: var(--buehne-tinte);
}

.buehne h1,
.buehne h2,
.buehne h3 {
  color: var(--buehne-tinte);
}

.buehne p {
  color: var(--buehne-gedaempft);
}

.buehne a:not(.btn) {
  color: var(--flow-spitze);
  text-decoration-color: rgb(91 155 255 / 0.45);
}

.buehne a:not(.btn):hover {
  color: #fff;
}

.buehne-ersatz {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.buehne-inhalt {
  position: relative;
  z-index: 2;
}

/* Zustand "ruhig" — der Kopf.
   Zwei Aufgaben, und die erste ist neu: die NAHT. Ueber der Bildbahn steht der
   blanke Buehnengrund #05070E, die oberste Bildzeile von flow-3 misst #081225.
   Nebeneinander ist das eine sichtbare Kante. Der senkrechte Verlauf hebt den
   Grund nach unten hin genau auf diesen Ton — dann geht die Buehne ohne Kante
   ins Bild ueber. Die zwei Lichtkoerper liegen jetzt UNTER dem unteren Rand
   (bei 112 und 118 % Hoehe): sichtbar sind sie nur, wenn das Bild fehlt, denn
   sonst deckt die Bahn sie zu. Das ist der Sinn des Ersatzes — er zeigt, was
   dastuende, wenn nichts laedt, und draengt sich sonst nicht vor. */
.buehne[data-flow="ruhig"] .buehne-ersatz {
  background:
    radial-gradient(150% 62% at 50% 118%, rgb(11 63 209 / 0.34) 0%, rgb(11 63 209 / 0) 68%),
    radial-gradient(92% 40% at 50% 112%, rgb(55 149 239 / 0.20) 0%, rgb(55 149 239 / 0) 70%),
    linear-gradient(180deg, rgb(10 19 34 / 0) 18%, rgb(10 19 34 / 0.95) 56%),
    var(--buehne);
}

/* Zustand "stroemung" — der Zwischenruf.

   ⚠ Am 29.08.2026 umgestellt, weil die Bildbahn raus ist. Vorher lag das Licht
   bei 112–116 % Hoehe, also UNTER dem unteren Rand, und ein senkrechter
   Verlauf dunkelte nach unten nach: beides diente der Naht zum Bild, das dort
   anfing. Ohne Bild las sich genau das als Fehler — die Buehne wurde nach
   unten hin heller und schnitt dann hart ins Weisse.

   Jetzt sitzt das Licht in der Mitte und laeuft zu beiden Raendern aus. Die
   Buehne ist damit eine beleuchtete Flaeche mit dunklen Kanten statt eines
   Verlaufs, der auf etwas zulief, das nicht mehr da ist. */
.buehne[data-flow="stroemung"] .buehne-ersatz {
  background:
    radial-gradient(112% 74% at 50% 52%, rgb(11 63 209 / 0.34) 0%, rgb(11 63 209 / 0) 68%),
    radial-gradient(64% 40% at 50% 52%, rgb(55 149 239 / 0.18) 0%, rgb(55 149 239 / 0) 72%),
    var(--buehne);
}

/* Zustand "strom" — Abschluss und Aufforderung. Das Licht liegt jetzt um das
   gerahmte Bild herum und ist an BEIDEN Enden der Buehne bei null: oben trifft
   sie auf einen weissen Abschnitt, unten auf den Fuss, der denselben Grund
   hat. Ein Verlauf, der bis zur Unterkante leuchtet, zog dort eine sichtbare
   Linie zwischen Buehne und Fuss. */
.buehne[data-flow="strom"] .buehne-ersatz {
  background:
    radial-gradient(84% 34% at 50% 44%, rgb(11 63 209 / 0.32) 0%, rgb(11 63 209 / 0) 72%),
    radial-gradient(50% 20% at 50% 44%, rgb(55 149 239 / 0.18) 0%, rgb(55 149 239 / 0) 74%),
    radial-gradient(28% 12% at 50% 44%, rgb(91 155 255 / 0.12) 0%, rgb(91 155 255 / 0) 76%),
    var(--buehne);
}

/* Die Naht nach oben und unten: eine Haarlinie aus dem Flow-Kern, damit die
   Buehne nicht als abgeschnittener Kasten auf Weiss klebt. */
.buehne::before,
.buehne::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  z-index: 3;
  background: linear-gradient(90deg, rgb(55 149 239 / 0) 0%, rgb(55 149 239 / 0.5) 50%,
    rgb(55 149 239 / 0) 100%);
  pointer-events: none;
}

.buehne::before {
  top: 0;
}

.buehne::after {
  bottom: 0;
}

/* Kein Strich am Seitenanfang und keiner zwischen Schlussbuehne und Fuss —
   beide traefen auf Schwarz und waeren ein Strich im Nichts. */
.kopf::before,
.schluss::after {
  display: none;
}

/* ---------------------------------------------------------------------------
   Der lebende Kopf — kopf-flow.js
   ---------------------------------------------------------------------------
   Hier stand bis zum 29.08.2026 der ganze Bildbahn-Bau: `.bild-band`,
   `.bild-rahmen`, `.bild-grund`, `.bild-video` und ihre drei Auspraegungen.
   Alle drei Bahnen sind weg — die beiden unteren auf Joels Ansage („nicht
   animiert"), die im Kopf, weil an ihrer Stelle eine Stroemung steht, die
   sich selbst bewegt.

   Was bleibt, sind DREI Lagen in jeder Buehne, und die Reihenfolge ist die
   ganze Regel:

     .buehne-ersatz   z 0   CSS-Verlauf. Traegt allein, wenn kein Canvas kommt.
     .kopf-flow       z 1   das WebGL-Canvas. Kann fehlen, ohne Loch.
     .buehne-inhalt   z 2   alles Lesbare.

   Der Flow zeichnet mit Alpha, der Ersatz scheint also durch ihn hindurch —
   das ist gewollt: er ist der Grundton, auf dem die Baender liegen. Bei Nika
   war genau das einmal ein Fehler (dort lag eine statische Textur darunter,
   die durch jedes Motiv durchschien, Joel am 5.8.). Der Unterschied: hier ist
   die untere Lage ein Verlauf in derselben Farbe, kein Muster.
   --------------------------------------------------------------------------- */

.kopf-flow {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}

.kopf-flow canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* Der Schleier -------------------------------------------------------------
   Der Flow ist hell — sein Kern misst bis #32A9ED, und weisser Text darauf
   kommt auf 2,61:1, gedaempfter auf 1,44:1 (gemessen 29.08.2026, kontrast.py,
   390 px, Flow t=6 s). Das ist keine Feinheit, das ist Stufe A.

   Drei Wege standen zur Wahl:
     · den Flow insgesamt dunkler stellen — dann ist er ueberall weg, auch
       rechts, wo gar kein Text steht;
     · nur das Halo an den Buchstaben — traegt gegen ein DUNKLES Band, nicht
       gegen einen Kern, der doppelt so hell ist wie der Text daneben;
     · einen Schleier genau dort, wo Text steht.

   Also der dritte. Die Textspalte endet bei 1440 px an x = 678 (die Riesen-
   zeile) beziehungsweise 669 (der Satz), also bei 47 % der Breite. Der
   Schleier steht bis 50 % voll und ist bei 78 % bei null — die rechte Haelfte,
   in der der Flow seine Kreuzungen zeigt, bleibt unberuehrt.

   `:has(canvas)`: ohne Canvas gibt es nichts zu daempfen, und der
   Ersatzverlauf soll nicht zweimal verdunkelt werden. Kennt ein Browser
   `:has()` nicht, liegt der Schleier trotzdem — dunkler als noetig ist kein
   Fehler, heller waere einer. */
.kopf-flow:has(canvas)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    93deg,
    rgb(5 7 14 / 0.52) 0%,
    rgb(5 7 14 / 0.50) 50%,
    rgb(5 7 14 / 0) 78%
  );
}

/* Schmales Fenster: die Spalte fuellt die Breite, ein seitlicher Verlauf hat
   nichts, wohin er ausklingen koennte. Dann deckt der Schleier ganz — der
   Flow bleibt als bewegter Ton sichtbar, nicht als Lichtband. */
@media (max-width: 719px) {
  .kopf-flow:has(canvas)::after {
    background: rgb(5 7 14 / 0.60);
  }
}

/* ---------------------------------------------------------------------------
   1 · Kopf
   --------------------------------------------------------------------------- */

/* Der Kopf haelt jetzt seine eigene Hoehe. Vorher gab die Bildbahn sie vor
   (460 px Bahn plus Text); ohne sie waere der Kopf auf 585 px zusammengefallen
   und der lebende Hintergrund haette einen Streifen statt einer Buehne. 78 svh
   lassen unten rund 130 px des naechsten Abschnitts stehen — die Kante, an der
   man sieht, dass es weitergeht. `svh` und nicht `vh`: auf dem Telefon zaehlt
   die kleine Fassung, sonst schiebt die einfahrende Adressleiste den Knopf
   unter den Bildrand. */
.kopf {
  min-height: min(78svh, 760px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.kopf .buehne-inhalt {
  /* Frueher war unten wenig Platz, weil die Bildbahn sich um 7 % der Breite
     hier hereinzog. Ohne Bahn traegt der Kopf seine Hoehe selbst — der Flow
     liegt hinter ihm, nicht unter ihm. Symmetrisch waere trotzdem falsch: die
     Buehne soll oben Luft haben und unten an den weissen Abschnitt stossen. */
  padding-block: clamp(76px, 12vh, 148px) clamp(72px, 10vh, 132px);
}

.riese {
  font-size: var(--t-riese);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.03em;
  max-width: 17ch;
}

/* Der Kopf traegt seit dem 29.08.2026 einen lebenden Hintergrund, und der
   schiebt helle Baender durch die Ueberschrift. Ein weiches dunkles Halo
   direkt an den Buchstaben repariert genau die Flaeche, auf die es ankommt —
   im Gegensatz zu einer Abdunklung der ganzen Buehne, die den Flow ueberall
   totschlagen wuerde. Drei Radien: der weite traegt, der mittlere fuellt, der
   enge zieht die Kante nach. Dieselbe Loesung wie bei Nika, dort gemessen.

   Es steht auf `.kopf .buehne-inhalt`, nicht auf `.riese`: Satz, Band und
   Knopf stehen auf demselben Flow und brauchen dasselbe. Der Knopf hat eine
   eigene Flaeche, das Band auch — bei ihnen faellt das Halo nicht auf. */
.kopf .buehne-inhalt {
  text-shadow:
    0 0 10px rgb(5 7 14 / 0.95),
    0 0 24px rgb(5 7 14 / 0.90),
    0 0 48px rgb(5 7 14 / 0.75);
}

/* Auf einer eigenen Flaeche braucht Text kein Halo — dort steht er nicht auf
   dem Flow, sondern auf Glas beziehungsweise auf dem Knopf. */
.kopf .btn,
.kopf-band {
  text-shadow: none;
}

.riese-fest {
  color: var(--buehne-tinte);
}

/* Das wechselnde Wort ------------------------------------------------------
   inline-grid, alle drei Woerter uebereinander in derselben Zelle. Die Breite
   ist die des laengsten Wortes ("addressable"), und sie aendert sich nie —
   ohne das springt die ganze Zeile bei jedem Wechsel um.
   Die drei Woerter sind aria-hidden; den Satz fuer Screenreader traegt EINMAL
   .nur-lesen in derselben Ueberschrift. Kein Live-Bereich: WCAG 2.2 SC 2.2.2
   behandelt sich selbst wechselnden Text als auto-updating, und ein
   Live-Bereich wuerde ihn zusaetzlich vorlesen. */
/* Die Schreibmaschine ------------------------------------------------------
   Bauart aus Project Nika (`web/landing/styles.css`, `.tw*`), Namen auf
   Deutsch wie der Rest dieses Blatts.

   Der Geist ist unsichtbar, misst aber: er haelt die Breite des laengsten
   Wortes frei. Ohne ihn springt die Zeile bei jedem Zeichen — und bei einer
   Riesenzeile springt dann der halbe Kopf mit. */
.schreib {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}

.schreib-geist {
  visibility: hidden;
}

.schreib-live {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  color: var(--flow-spitze);
}

/* Der Strich unter dem letzten Wort. Er waechst von links, in derselben Farbe
   wie das Wort, und verschwindet ohne Uebergang, sobald geloescht wird — ein
   Strich, der sich zurueckzieht, sieht aus wie ein Fehler.

   `transform` statt `width`: das laeuft auf dem Verbundlayer und macht keinen
   Umbruch in einer Zeile, die 5 vw gross ist. */
.schreib-live::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0.14em;
  bottom: -0.14em;
  height: 0.045em;
  background: var(--flow-spitze);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.schreib-live.betont::after {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .schreib-live::after {
    transition: none;
  }
}

/* Der Strich blinkt in Stufen, nicht weich: ein Cursor faded nicht, er ist an
   oder aus. `steps(1, end)` ist genau das. */
.schreib-strich {
  display: inline-block;
  width: 0.06em;
  height: 0.82em;
  margin-left: 0.07em;
  vertical-align: -0.04em;
  background: var(--flow-spitze);
  animation: strich-blinken 1.05s steps(1, end) infinite;
}

@keyframes strich-blinken {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

/* Ohne Bewegung tippt nichts, und dann blinkt auch nichts — ein blinkender
   Strich hinter einem stehenden Wort waere die Behauptung, da schriebe noch
   jemand. */
@media (prefers-reduced-motion: reduce) {
  .schreib-strich {
    animation: none;
    opacity: 0;
  }
}


.kopf-satz {
  max-width: 52ch;
  margin-top: clamp(20px, 2.4vw, 30px);
  font-size: clamp(1rem, 0.9vw, 1.125rem);
  line-height: 1.5;
}

/* Aus dem Zusatzsatz wird eine Plakette: 500 px Radius, dunkles Glas,
   Innenfase. Genau die Sorte Detail, die vertus teuer aussehen laesst — und
   sie kostet kein Wort mehr, als vorher dastand. */
.kopf-band {
  display: inline-block;
  margin-top: clamp(18px, 2vw, 24px);
  padding: 8px 18px 9px;
  border-radius: var(--r-band);
  background: rgb(255 255 255 / 0.06);
  box-shadow:
    var(--fase-dunkel),
    0 0 0 1px rgb(255 255 255 / 0.10);
  color: var(--buehne-tinte);
  font-size: var(--t-klein);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.kopf-knopf {
  margin-top: clamp(26px, 3vw, 38px);
  /* ⚠ `width: max-content`, nicht aus Gestaltung, sondern aus Messbarkeit.
     Als normaler Absatz war der Kasten dieses <p> fensterbreit — von 170 bis
     1270 px, obwohl darin nur ein 283 px breiter Knopf steht. kontrast.py
     misst den KASTEN, nicht die Buchstaben (bewusst: strenger als die
     Wirklichkeit), und verlangte deshalb, dass der Flow auf der ganzen Breite
     dunkel genug fuer Text ist. Ein Kasten soll beschreiben, wo Text steht. */
  width: max-content;
  max-width: 100%;
}

/* ---------------------------------------------------------------------------
   2 · Haken
   --------------------------------------------------------------------------- */

.haken-raster {
  display: grid;
  gap: clamp(36px, 5vw, 64px);
  align-items: center;
}

@media (min-width: 1000px) {
  .haken-raster {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  }
}

.haken-titel {
  font-size: var(--t-gross);
  max-width: 17ch;
}

.haken-text {
  margin-top: 26px;
  max-width: 54ch;
  color: var(--gedaempft);
}

/* ---------------------------------------------------------------------------
   3 · Drei Saeulen · 5 · Drei Angebote · 6 · Drei Zielgruppen
   Ein Kartensystem, drei Auspraegungen.
   --------------------------------------------------------------------------- */

.drei {
  display: grid;
  gap: clamp(18px, 2vw, 26px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}

.karte {
  position: relative;
  padding: clamp(24px, 2.4vw, 34px);
  border-radius: var(--r-weit);
  background: var(--grund);
  border: 1px solid var(--linie);
  box-shadow: var(--fase), var(--tiefe-1);
  transition: transform var(--dauer) var(--kurve),
    box-shadow var(--dauer) var(--kurve),
    border-color var(--dauer) var(--kurve);
}

/* Auf Weiss ist die Karte blau getoent, auf dem Band ist sie weiss. Die
   Umkehr haelt den Abstand zum Grund konstant, ohne eine zweite Farbe.
   Auf der Blauflaeche traegt die Innenfase sichtbar — dort ist sie das
   Detail, das die Karte aus dem Papier hebt. */
.abschnitt:not(.band) .karte {
  background: var(--flaeche);
  box-shadow: var(--fase-blau), var(--tiefe-1);
}

.karte:hover {
  transform: translateY(-3px);
  border-color: rgb(11 63 209 / 0.34);
  box-shadow: var(--fase), var(--tiefe-2);
}

/* Der Lichtstrich am oberen Rand: der einzige Ort, an dem der Flow-Kern auf
   hellem Grund vorkommt. Rein dekorativ, deshalb ohne Kontrastanforderung. */
.karte::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 2px;
  border-radius: var(--r-weit) var(--r-weit) 0 0;
  background: linear-gradient(90deg, rgb(11 63 209 / 0) 0%, rgb(11 63 209 / 0.55) 42%,
    rgb(55 149 239 / 0.35) 78%, rgb(55 149 239 / 0) 100%);
  opacity: 0;
  transition: opacity var(--dauer) var(--kurve);
}

.karte:hover::before {
  opacity: 1;
}

.karte-titel {
  font-size: var(--t-mittel);
  letter-spacing: -0.022em;
}

.karte p {
  margin-top: 13px;
  color: var(--gedaempft);
  font-size: var(--t-text);
  line-height: 1.45;
}

/* Das Zeichen ueber jedem Saeulentitel: drei gezeichnete Bilder, kein Text.
   Sie erzaehlen, wovon der Block handelt — Raster, Stufen, Verzweigung — und
   kosten kein einziges Wort. */
/* Das Zeichen sitzt jetzt in einer eigenen Kachel: 14 px Radius, blau
   getoent, mit der hellen Innenfase. Aus einem Strich wird damit ein
   Gegenstand — dieselbe Bewegung, die vertus mit seinen Flaechen macht. */
.karte-zeichen {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin-bottom: 20px;
  border-radius: var(--r);
  background: rgb(11 63 209 / 0.07);
  box-shadow: var(--fase-blau);
  color: var(--akzent-stark);
}

.karte-zeichen svg {
  width: 40px;
  height: 40px;
}

/* Die Kachel reagiert mit, wenn die Karte angefahren wird — ein Ton tiefer,
   kein Ortswechsel (MOTION.md P3). */
.karte-zeichen {
  transition: background-color var(--dauer) var(--kurve);
}

.karte:hover .karte-zeichen {
  background: rgb(11 63 209 / 0.13);
}

/* ═══ Die Zeichen zeichnen sich ═══════════════════════════════════════════
   Joel, 30.08.2026, ueber vertus.ai: „die haben ja diese nicen animierten
   icon animation in den 3er bereichen, wuerde das gerne auch bei der website
   einbauen".

   NACHGEMESSEN, wie vertus es macht (30.08.2026, an der ausgelieferten Seite):
   drei Lottie-Dateien (`Icon 1/2/3.json`, 80x80, 30 fps, 1,50 bis 1,70 s,
   `data-loop="0"`, `data-renderer="svg"`), ausgeloest beim Hovern der Karte.
   Die Mittel darin sind genau drei: **Trim Path** (ein Strich zeichnet sich),
   **Deckkraft** und **kleine Groessenwechsel**. Mehr steckt nicht drin.

   Genau diese drei gibt es in CSS, ohne eine Zeile Bibliothek:
   `stroke-dashoffset` IST der Trim Path, `opacity` die Deckkraft, `transform`
   der Rest. vertus laedt dafuer `lottie.js` plus drei JSON-Dateien von einem
   fremden Server; hier waere das der einzige Fremdabruf der ganzen Seite und
   staende dem Satz im Fuss entgegen („no script, no font and no image from a
   third-party server").

   `pathLength="1"` ist der Kniff, der ohne Messung auskommt: er normiert die
   Laenge JEDES Pfades auf 1, egal wie lang er wirklich ist. Damit heisst
   `stroke-dasharray: 1` immer „genau einmal ganz herum" und
   `stroke-dashoffset: 1` immer „noch gar nichts". Ohne ihn muesste jede Laenge
   einzeln per `getTotalLength()` gemessen werden — und die Zeichen haengen
   wieder am Skript, statt nur ihre Bewegung.

   MOTION.md P2 bleibt gewahrt: **der Grundzustand ist das fertige Bild.** Alle
   Regeln hier haengen an `.zeichnet`, und die Klasse setzt main.js. Ohne
   Skript steht das Zeichen einfach da; bei `prefers-reduced-motion` setzt
   main.js sie gar nicht erst, und die Sperre unten faengt den Fall, dass sie
   doch einmal am Element klebt.

   Zwei Stellschrauben je Element, beide inline im Markup, weil die Choreo
   dorthin gehoert, wo die Form steht:
     --start   wann dieses Teil anfaengt (0 ist der Anfang des Zeichens)
     --zeit    wie lange es sich zeichnet (nur bei .z-strich)
   Dazu kommt `--verzug` von der Karte: der Beobachter in main.js staffelt
   damit ohnehin schon die drei Karten einer Reihe (0 / 90 / 180 ms). Die
   Zeichen erben ihn und laufen deshalb von links nach rechts an.
   ---------------------------------------------------------------------- */

/* Ein Strich, der sich zieht — der Trim Path.

   `1 2` und nicht `1`: ein einzelner Wert heisst „Strich 1, Luecke 1", und dann
   faengt am Ende des Pfades der naechste Strich mit Laenge null an. Mit
   `stroke-linecap: round` malt der Browser genau dort einen Punkt — im
   verborgenen Zustand stand deshalb an jedem Pfadende ein Fleck, sichtbar bis
   zu einer Sekunde lang, bevor das Teil an der Reihe war. Gefunden im
   Filmstreifen am 30.08.2026, dritte Karte, erste Aufnahme. Mit einer Luecke
   von 2 passt nach dem einen Strich kein zweiter mehr in die Laenge 1. */
.karte-zeichen.zeichnet .z-strich {
  stroke-dasharray: 1 2;
  animation: zeichnen var(--zeit, 420ms) var(--kurve)
    calc(var(--verzug, 0ms) + var(--start, 0ms)) both;
}

@keyframes zeichnen {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* Eine Flaeche, die auftaucht. `fill-opacity` bleibt unberuehrt — deshalb
   tragen die halbdurchsichtigen Teile im Markup `fill-opacity` und nicht
   `opacity`: sonst wuerde diese Animation ihren Wert am Ende ueberschreiben
   und aus 0,16 wuerde 1. */
.karte-zeichen.zeichnet .z-auf {
  transform-box: fill-box;
  transform-origin: center;
  animation: auftauchen 380ms var(--kurve)
    calc(var(--verzug, 0ms) + var(--start, 0ms)) both;
}

@keyframes auftauchen {
  from {
    opacity: 0;
    transform: scale(0.55);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Eine Stufe, die aus der Grundlinie waechst. Ursprung unten Mitte — sie steht
   auf der Linie, sie schwebt nicht darueber. Nicht ganz von 0 aus: eine auf
   null gestauchte Form hat keine Richtung mehr und blitzt beim Start. */
.karte-zeichen.zeichnet .z-wachs {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: wachsen 460ms var(--kurve)
    calc(var(--verzug, 0ms) + var(--start, 0ms)) both;
}

@keyframes wachsen {
  from {
    opacity: 0;
    transform: scaleY(0.06);
  }
  to {
    opacity: 1;
    transform: scaleY(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .karte-zeichen.zeichnet .z-strich,
  .karte-zeichen.zeichnet .z-auf,
  .karte-zeichen.zeichnet .z-wachs {
    animation: none;
  }
}

/* Angebotskarte: der Titel ist ein Wort mit Punkt ("Build."), er steht
   deshalb groesser und blau — sonst liest er sich als Satzanfang. */
.angebot .karte-titel {
  color: var(--akzent);
  font-size: clamp(1.5rem, 2.4vw, 1.95rem);
  letter-spacing: -0.03em;
}

/* Der Nachsatz nach einer Dreiergruppe — Mitwirkungspflichten, und der Satz,
   der Leute wegschickt. Eine Linie LINKS, nicht darueber: eine Haarlinie ueber
   einem Absatz mit Zeilenmass endet mitten im Weiss und sieht aus wie ein
   Fehler. Die senkrechte Linie sagt dasselbe und ist so lang wie der Text. */
.nachsatz {
  margin-top: clamp(30px, 3.4vw, 44px);
  padding-left: clamp(18px, 2vw, 24px);
  border-left: 2px solid var(--akzent-stark);
  border-radius: 0 var(--r-mikro) var(--r-mikro) 0;
  max-width: 74ch;
  color: var(--gedaempft);
  font-size: var(--t-text);
}

.nachsatz strong {
  color: var(--tinte);
}

/* ---------------------------------------------------------------------------
   4 · Zwischenruf
   --------------------------------------------------------------------------- */

.zwischenruf .buehne-inhalt {
  padding-block: clamp(72px, 9vw, 124px) clamp(40px, 5vw, 72px);
}

.zwischenruf-zeile {
  margin: 0;
  max-width: 22ch;
  color: var(--buehne-tinte);
  font-size: var(--t-gross);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

/* ---------------------------------------------------------------------------
   7 · Abschluss  ·  8 · Aufforderung
   Eine Buehne, zwei Abschnitte. Der Flow laeuft durch.
   --------------------------------------------------------------------------- */

.schluss .buehne-inhalt > .wrap {
  padding-block: clamp(76px, 9vw, 132px) clamp(48px, 5vw, 68px);
}

.schluss-zeile {
  max-width: 24ch;
  font-size: var(--t-gross);
  font-weight: 500;
  letter-spacing: -0.03em;
}

.schluss-text {
  margin-top: 26px;
  max-width: 56ch;
}

/* Das Portraet kommt am 30.08.2026. Bis dahin steht die Textspalte allein —
   KEIN grauer Kasten, kein "Foto folgt": eine Leerstelle, die sich selbst
   ankuendigt, ist schlechter als keine. Der fertige <img>-Aufruf steht als
   Kommentar im Markup; der Tausch ist eine Zeile. */
.person {
  margin-top: clamp(38px, 4.6vw, 60px);
  padding-top: clamp(28px, 3vw, 38px);
  border-top: 1px solid var(--buehne-linie);
  max-width: 62ch;
}

.person-name {
  color: var(--buehne-tinte);
  font-weight: 620;
}

.person p + p {
  margin-top: 14px;
}

.cta-block {
  padding-block: clamp(48px, 5vw, 68px) clamp(84px, 10vw, 140px);
}

.cta-titel {
  font-size: var(--t-gross);
  max-width: 16ch;
}

.cta-text {
  margin-top: 26px;
  max-width: 56ch;
}

.cta-knopf {
  margin-top: clamp(30px, 3.4vw, 44px);
}

.cta-knopf .btn {
  padding: 18px 34px;
  font-size: 1.0625rem;
}

/* ---------------------------------------------------------------------------
   Produktausschnitte — gestaltete Platzhalter, keine grauen Kaesten
   ---------------------------------------------------------------------------
   Joel am 28.08.2026: "keine grauen Kaesten". Also ein Rahmen in Blau, Weiss
   und Schwarz, der wie ein Ausschnitt aus der eigenen Anwendung liest — Leiste,
   Seitenschiene, Kurve, Spalten. Er traegt KEIN Wort: erstens zaehlt jedes
   Wort auf dieser Seite (809 sind gesetzt), zweitens waeren erfundene Zahlen
   in einem Produktbild genau die Behauptung, die diese Seite nicht macht.
   Echte Bildschirmfotos kommen, wenn die App ueberarbeitet ist. Der Tausch ist
   dann ein <img> an derselben Stelle — die Groesse steht schon.
   --------------------------------------------------------------------------- */

.ausschnitt {
  margin: 0;
  border-radius: var(--r-schale);
  background: linear-gradient(160deg, #0a1024 0%, var(--buehne) 62%);
  border: 1px solid rgb(55 149 239 / 0.22);
  box-shadow: var(--tiefe-2);
  overflow: hidden;
}

.ausschnitt-koerper {
  display: grid;
  border-radius: 0 0 var(--r-gross) var(--r-gross);
  grid-template-columns: 78px minmax(0, 1fr);
  gap: 2px;
  background: rgb(255 255 255 / 0.06);
}

/* Der Koerper traegt jetzt ein Bild statt der gezeichneten Attrappe: eine
   Spalte, kein Raster, und das Bild fuellt die ganze Schale.

   ⚠ 30.08.2026, der Nachtrag zum geloeschten Browserrahmen: das Bild hatte
   OBEN keine eigene Rundung (`0 0 24px 24px`), weil dort die aufgemalte
   Leiste sass und sie trug. Ohne sie stiess eine scharfe Ecke an die runde
   Schale. Jetzt rundet das Bild oben selbst, und zwar auf den INNENradius der
   Schale: --r-schale minus die 1-px-Kante von .ausschnitt.
   Auf `overflow: hidden` der Schale allein zu bauen reicht nicht — an einer
   40-px-Rundung bleibt je nach Browser eine haarfeine Sichel des
   Schalenverlaufs zwischen Bild und Kante stehen. Zwei Rundungen, die
   uebereinander liegen, sind hier billiger als ein Browserunterschied. */
.ausschnitt-koerper.ist-bild {
  display: block;
  grid-template-columns: none;
  gap: 0;
  background: transparent;
  overflow: hidden;
  border-radius: calc(var(--r-schale) - 1px);
}

.ausschnitt-koerper.ist-bild img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: calc(var(--r-schale) - 1px);
}

/* Die Zeile unter dem Rahmen gehoert zum Bild, nicht zum Text daneben: klein,
   leise, und mit dem Weg zur Begruendung. Ein Bildschirmfoto mit erfundenen
   Zahlen ohne diesen Satz ist eine Behauptung.

   ⚠ Sie steht NEBEN dem <figure>, nicht darin: `.ausschnitt` hat
   `overflow: hidden` fuer die Rundung, und eine figcaption darin wird davon
   angeschnitten. Im ersten Wurf lag sie halb ueber dem Bild. */
.ausschnitt-fuss {
  margin-top: 0.6rem;
  font-size: 0.82rem;
  line-height: 1.5;
  /* Farbe vom Abschnitt erben statt einen festen Ton setzen: dieselbe Zeile
     steht einmal auf dunklem und einmal auf hellem Grund. Ein fester Wert war
     auf einem der beiden Gruende grau in grau. */
  color: inherit;
  opacity: 0.68;
}

.ausschnitt-block {
  display: grid;
  gap: 0;
}

.ausschnitt-fuss a {
  color: inherit;
  text-underline-offset: 0.2em;
}

.ausschnitt-schiene,
.ausschnitt-feld {
  background: linear-gradient(180deg, rgb(10 16 36 / 0.9), rgb(5 7 14 / 0.9));
  padding: 18px 16px;
}

.ausschnitt-schiene {
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.schiene-strich {
  height: 7px;
  border-radius: var(--r-voll);
  background: rgb(255 255 255 / 0.12);
}

.schiene-strich.ist-aktiv {
  background: linear-gradient(90deg, var(--flow-kern), var(--flow-spitze));
  box-shadow: 0 0 16px rgb(55 149 239 / 0.55);
}

.schiene-strich:nth-child(2) {
  width: 74%;
}

.schiene-strich:nth-child(3) {
  width: 88%;
}

.schiene-strich:nth-child(4) {
  width: 62%;
}

.schiene-strich:nth-child(5) {
  width: 80%;
}

.ausschnitt-feld {
  padding: 22px 22px 26px;
}

.feld-kopf {
  display: flex;
  gap: 10px;
  margin-bottom: 18px;
}

.feld-kachel {
  flex: 1;
  height: 46px;
  border-radius: var(--r-klein);
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.07);
  position: relative;
  overflow: hidden;
}

.feld-kachel::before {
  content: "";
  position: absolute;
  left: 12px;
  top: 13px;
  width: 42%;
  height: 6px;
  border-radius: var(--r-voll);
  background: rgb(255 255 255 / 0.22);
}

.feld-kachel::after {
  content: "";
  position: absolute;
  left: 12px;
  bottom: 12px;
  width: 26%;
  height: 8px;
  border-radius: var(--r-voll);
  background: var(--flow-kern);
}

.feld-kachel:nth-child(2)::after {
  width: 34%;
  background: var(--flow-spitze);
}

.feld-kachel:nth-child(3)::after {
  width: 20%;
}

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

/* Spaltentafel — der zweite Ausschnitt, unter den drei Angeboten. */
.tafel {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 2px;
  background: rgb(255 255 255 / 0.06);
}

.tafel-spalte {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 18px 14px 24px;
  background: linear-gradient(180deg, rgb(10 16 36 / 0.92), rgb(5 7 14 / 0.92));
}

.tafel-kopf {
  height: 7px;
  margin-bottom: 6px;
  border-radius: var(--r-voll);
  background: rgb(255 255 255 / 0.2);
}

.tafel-spalte.ist-aktiv .tafel-kopf {
  background: linear-gradient(90deg, var(--flow-kern), var(--flow-spitze));
  box-shadow: 0 0 18px rgb(91 155 255 / 0.5);
}

.tafel-karte {
  height: 34px;
  border-radius: var(--r-klein);
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.07);
  position: relative;
}

.tafel-karte::before {
  content: "";
  position: absolute;
  left: 9px;
  top: 10px;
  width: 58%;
  height: 5px;
  border-radius: var(--r-voll);
  background: rgb(255 255 255 / 0.2);
}

.tafel-karte::after {
  content: "";
  position: absolute;
  left: 9px;
  bottom: 9px;
  width: 32%;
  height: 5px;
  border-radius: var(--r-voll);
  background: rgb(55 149 239 / 0.75);
}

.tafel-spalte.ist-aktiv .tafel-karte {
  border-color: rgb(55 149 239 / 0.4);
  box-shadow: 0 0 24px -6px rgb(55 149 239 / 0.55);
}

.tafel-karte.ist-kurz {
  height: 26px;
}

.ausschnitt--tafel {
  margin-top: clamp(34px, 4vw, 52px);
}

/* ---------------------------------------------------------------------------
   Fuss
   --------------------------------------------------------------------------- */

.fuss {
  background: var(--buehne);
  color: var(--buehne-gedaempft);
  border-top: 1px solid var(--buehne-linie);
  padding-block: clamp(48px, 6vw, 72px);
  /* Unten kommt die Leiste des Telefons dazu (Wischbalken beim iPhone, die
     Gestensteuerung bei Android). Ohne diese Zeile liegt der letzte Link der
     Seite darunter. 30.08.2026. */
  padding-bottom: calc(clamp(48px, 6vw, 72px) + env(safe-area-inset-bottom, 0px));
  font-size: var(--t-klein);
}

.fuss-raster {
  display: grid;
  gap: 32px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
}

.fuss-spalte {
  display: flex;
  flex-direction: column;
  gap: 9px;
  align-items: flex-start;
}

.fuss-marke {
  max-width: 34ch;
  color: var(--buehne-gedaempft);
  font-size: var(--t-klein);
}

.fuss .marke-wort {
  display: block;
  margin-right: 0;
  margin-bottom: 6px;
  font-size: 1.625rem;
}

.fuss-kopf {
  margin: 0 0 4px;
  color: var(--buehne-tinte);
  font-size: var(--t-mikro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.fuss a {
  color: var(--buehne-gedaempft);
  text-decoration: none;
}

.fuss a:hover {
  color: var(--buehne-tinte);
  text-decoration: underline;
}

.fuss p {
  margin: 0;
}

.fuss-hinweis {
  max-width: 42ch;
  line-height: 1.55;
}

.klein {
  font-size: var(--t-klein);
}

/* ---------------------------------------------------------------------------
   Einblenden beim Scrollen
   ---------------------------------------------------------------------------
   Jede verbergende Regel haengt an .js. Ohne Skript ist nichts unsichtbar —
   das ist die harte Bedingung, nicht die Kür. --verzug staffelt Geschwister;
   main.js setzt ihn als Inline-Stil.
   --------------------------------------------------------------------------- */

/* Szenentexte auf den drei Buehnen. Verborgen wird NUR, wenn szene.js
   bestaetigt hat, dass GSAP und ScrollTrigger stehen und die Zeitleisten
   gebaut sind (.hat-szenen am <html>). Ohne Skript, ohne Bewegung, bei einem
   fehlgeschlagenen Nachladen: nichts ist unsichtbar. */
.hat-szenen [data-szene-text] {
  opacity: 0;
}

.js [data-zeig] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
  will-change: opacity, transform;
}

.js [data-zeig].ist-da {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dauer-lang) var(--kurve) var(--verzug, 0ms),
    transform var(--dauer-lang) var(--kurve) var(--verzug, 0ms);
  will-change: auto;
}

/* ---------------------------------------------------------------------------
   Rechtsseiten — Impressum und Datenschutzerklaerung
   ---------------------------------------------------------------------------
   Der TEXT dieser beiden Seiten bleibt unangetastet und deutsch. Hier steht
   nur ihre Gestaltung, in der neuen Palette.
   --------------------------------------------------------------------------- */

.rechtsseite {
  padding-block: clamp(40px, 5vw, 72px) clamp(64px, 8vw, 108px);
}

.rechtsseite h1 {
  font-size: clamp(2rem, 4vw, 2.75rem);
  margin-bottom: 28px;
}

.rechtsseite h2 {
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  margin-top: 44px;
  margin-bottom: 14px;
}

.rechtsseite h3 {
  font-size: 1.0625rem;
  margin-top: 28px;
  margin-bottom: 10px;
}

.rechtsseite p,
.rechtsseite li {
  color: var(--gedaempft);
}

.rechtsseite li {
  margin-bottom: 8px;
}

.rechtsseite code {
  padding: 2px 6px;
  border-radius: var(--r-fein);
  background: var(--flaeche-2);
  color: var(--akzent);
  font-size: 0.9em;
  font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, monospace;
}

.zurueck {
  display: inline-block;
  margin-bottom: 26px;
  font-size: var(--t-klein);
  font-weight: 560;
  text-decoration: none;
}

.pruefkasten {
  margin-bottom: 36px;
  padding: clamp(20px, 2.4vw, 28px);
  border-radius: var(--r-mittel);
  border: 1px solid rgb(11 63 209 / 0.3);
  border-left: 3px solid var(--akzent-stark);
  background: var(--flaeche);
  box-shadow: var(--tiefe-1);
}

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

.pruefkasten p:last-child {
  margin-bottom: 0;
}

/* Offene Stelle im Rechtstext. Frueher trug sie eine eigene Signalfarbe; die
   ist mit Gold und Beige am 28.08.2026 gefallen. Jetzt traegt sie das Blau
   und eine gepunktete Unterlaenge — die Form unterscheidet, nicht eine
   vierte Farbe. */
.auszufuellen {
  color: var(--akzent);
  font-weight: 560;
  text-decoration: underline dotted var(--akzent-stark);
  text-underline-offset: 0.22em;
  background: rgb(11 63 209 / 0.07);
  padding: 1px 4px;
  border-radius: var(--r-mikro);
}

/* ---------------------------------------------------------------------------
   Schmale Schirme
   --------------------------------------------------------------------------- */

@media (max-width: 900px) {
  /* Ab hier traegt das Menue die Navigation. Bis zum 30.08.2026 stand hier
     nur `.leiste-nav { display: none }` — die drei Abschnittslinks waren
     dann nicht klein, sie waren weg, ohne Ersatz. */
  .leiste-nav,
  .leiste-sprache,
  .leiste-anmelden {
    display: none;
  }

  .menue {
    display: block;
  }

  /* Die Wortmarke ist hier das zweite Tippziel neben dem Menueknopf.
     24 px Schrift mal Zeilenhoehe 1,45 = 34,8 px; mit 2x5 px sind es 44,8 px.
     Nur in der Leiste: im Fuss ist die Marke ein <span> und kein Ziel. */
  .leiste .marke-wort {
    padding-block: 5px;
  }
}

@media (max-width: 719px) {
  /* Die zwei Bildschirmfotos, bis das Hochformat da ist (Dateinamen und
     Schwelle stehen als Kommentar am <figure> in index.html).
     Nachgerechnet: das Bild ist 2160x1230, auf 350 px Bildflaeche also 199 px
     hoch. Bei voller Breite (1180 px) ist es 672 px hoch, und 40 px Radius
     sind dort 6 % der Hoehe; dieselben 40 px sind bei 199 px 20 %, und die
     Figur liest sich als Pille statt als Bildschirm. Proportional waeren
     40 x 350/1180 = 11,9 px — --r (14 px) ist der naechste Wert im Bestand
     darueber. Und der weite Schatten der Stufe 2 gehoert unter eine Karte,
     die abhebt, nicht unter einen 199-px-Streifen. 30.08.2026. */
  .ausschnitt {
    border-radius: var(--r);
    box-shadow: var(--tiefe-1);
  }

  .ausschnitt-koerper.ist-bild,
  .ausschnitt-koerper.ist-bild img {
    border-radius: calc(var(--r) - 1px);
  }

  /* Die Links im Fuss stehen 9 px auseinander und sind 21,75 px hoch (15 px
     mal 1,45) — zusammen 30,75 px von Mitte zu Mitte. Das erfuellt die
     Abstandsausnahme von SC 2.5.8, ist auf einem Telefon aber Zielen mit dem
     Daumen. 44 px Hoehe kosten hier nichts. 30.08.2026. */
  .fuss-spalte a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

@media (max-width: 620px) {
  /* Die Beschriftung ist ueberall dieselbe und hier schlicht zu lang. Auf dem
     ersten Bildschirm steht derselbe Knopf ueber die volle Breite — und seit
     dem 30.08.2026 auch im Menue, ist also nach dem Scrollen erreichbar
     statt verschwunden.
     Ausgeblendet wird jetzt der ganze Behaelter statt nur des Knopfes darin:
     Sprachumschalter und "Sign in" sind unter 900 px ohnehin schon im Menue,
     und ein Flex-Behaelter mit lauter unsichtbaren Kindern kostet trotzdem
     seine 20 px Luecke neben der Wortmarke. */
  .leiste-rechts {
    display: none;
  }

  .riese {
    max-width: none;
  }

  .kopf-knopf .btn,
  .cta-knopf .btn {
    width: 100%;
    justify-content: center;
  }

  .ausschnitt-koerper {
    grid-template-columns: 58px minmax(0, 1fr);
  }

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

  .tafel-spalte:nth-child(n + 4) {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
   Bewegung aus
   ---------------------------------------------------------------------------
   Alles. Einblenden, Wortwechsel, Flow. vertus hat dafuer gemessen NULL
   Vorkehrungen; das ist der Punkt, an dem wir nicht kopieren.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-zeig] {
    opacity: 1 !important;
    transform: none !important;
  }

  /* Das Canvas kommt gar nicht erst ins Bild. flow.js prueft dieselbe
     Medienabfrage und startet nicht — das hier ist der Guertel zum Hosentraeger. */
  .buehne-flow {
    display: none !important;
  }
}

/* ---------------------------------------------------------------------------
   Druck
   --------------------------------------------------------------------------- */

@media print {
  .leiste,
  .sprung,
  .buehne-flow,
  .buehne-ersatz,
  .ausschnitt {
    display: none !important;
  }

  .buehne,
  .fuss {
    background: #fff !important;
    color: #000 !important;
  }

  .buehne p,
  .fuss {
    color: #333 !important;
  }

  body {
    font-size: 11pt;
  }
}
