@charset "utf-8";

/* ============================================================
   ModernOne — Basis-Stylesheet
   Schweizer Sachlichkeit: Raster 1280 / 48 / 32, Haarlinien,
   System-Grotesk, Farbe nur als Akzent.
   ============================================================ */

/* ---------- Design-Tokens ---------- */
:root {
  --bg: #fbfaf8;
  --ink: #111;
  --ink-2: #3d3a35;
  --ink-3: #5c5852;
  --ink-4: #8f8b84;
  --ink-footer: #6f6a62;
  --accent: oklch(0.55 0.19 32);
  --accent-blue: oklch(0.55 0.15 250);
  --accent-green: oklch(0.55 0.15 145);
  --hairline: rgba(17, 17, 17, .12);
  --hairline-strong: rgba(17, 17, 17, .16);
  --input-line: rgba(17, 17, 17, .42);
  --font: 'Helvetica Neue', Helvetica, 'Arial Nova', Arial, sans-serif;
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

/* ---------- Basis ---------- */
* { box-sizing: border-box; }

html {
  /* Sicherung gegen waagrechtes Schieben: Zierrat, der absichtlich in
     den Rand hinausreicht, darf die Seite nicht breiter machen. clip
     und nicht hidden -- hidden macht aus der Seite einen Bildlaufrahmen
     und nimmt sticky-Elementen ihren Bezug. */
  overflow-x: clip;
  scroll-behavior: smooth;
  scroll-padding-top: calc(90px + env(safe-area-inset-top, 0px));
  /* Ausdruecklich und als schlichte Farbe, nicht ueber color-mix wie
     am Koerper: Safari auf dem iPhone nimmt diese Farbe als Rueckfall
     fuer seine Leisten, und ohne sie faellt es auf Weiss zurueck. */
  background-color: #fbfaf8;
  /* Zieht jemand unten ueber den Fuss hinaus, soll dort nicht das helle
     Papier liegen, sondern derselbe Ton wie im Fuss. Der Grund des
     Wurzelelements wird ueber die ganze Leinwand gemalt, ausgerichtet
     aber an der Seitenhoehe -- also wird der Verlauf um vier Meter
     ueberhoeht und nur dieses Stueck unterhalb der Seite dunkel
     gehalten. Oben bleibt es Papier.

     Zwei Wege davor gingen nicht: sich wiederholend fing der Verlauf
     unterhalb der Seite wieder mit Papier an, und am Fenster
     festgemacht (background-attachment: fixed) hielt sich Safari auf
     dem iPhone nicht daran. Der Koerper deckt die Seite selbst ab, in
     ihr ist von dem Verlauf nichts zu sehen. */
  background-image: linear-gradient(to top, #111 0 4000px, #fbfaf8 4000px);
  background-repeat: no-repeat;
  background-size: 100% calc(100% + 4000px);
  background-position: 0 0;
  /* Und ueberhaupt nicht weiter als bis zum Fuss: sonst schiebt das
     Ueberziehen die klebende Kopfzeile aus dem Bild. */
  overscroll-behavior-y: none;
}

/* Liegt der Fuss am unteren Rand, ist die ganze Leinwand in seinem Ton
   -- damit ist der Bereich unter dem Fuss schwarz, ganz gleich wie
   Safari den Verlauf oben verankert. Zu sehen ist davon in der Seite
   nichts, der Koerper deckt sie ab. Die Klasse setzt js/main.js. */
html.ist-am-fuss {
  background-color: #111;
  background-image: none;
}

/* Und am Koerper: den Bereich, den man beim Ueberziehen unten sieht,
   malt Safari auf dem iPhone nach dessen Grund und nicht nach dem der
   Leinwand -- mit der Leinwand allein blieb dort das helle Papier. Die
   Seite selbst traegt ihren Ton an main (weiter unten) und geht darum
   nicht mit. */
html.ist-am-fuss body { background-color: #111; }

/* Solange das Klappmenue offen ist, liegt ein Schleier ueber der Seite.
   Den Streifen hinter Safaris Leiste am unteren Rand deckt er nicht mit
   ab -- dort malt der Browser die Farbe des Wurzelelements, und die war
   der helle Papierton. Unter der verdunkelten Seite stand darum eine
   helle Flaeche, die als weisser Balken auffiel.

   Das Wurzelelement bleibt dabei hell. Safari nimmt seine Farbe auch
   fuer die Zeile ganz oben, und die soll beim Menue nicht mitdunkeln;
   unten genuegt die Verdunkelung im Inhalt selbst, die die Glasleiste
   ohnehin abtastet -- bis zum Dokumentende traegt sie der Fuss. */

/* ---------- Buehnenton der Stil-Strecke ----------
   Einzelne Stile faerben Seitengrund und Kopfzeile ein, damit die Strecke
   nicht nur im Rahmen, sondern rundherum ihren Ton wechselt. Der Anteil
   steht in --stil-ton (0 = normaler Seitenton, 1 = ganz im Ton des Stils),
   die Zielfarbe in --stil-ton-farbe; beides setzt js/main.js aus dem
   data-ton des jeweiligen Abschnitts. Aeltere Browser ohne color-mix
   bleiben bei der jeweils davor stehenden, ungemischten Farbe. */
:root {
  --stil-ton: 0;
  --stil-ton-farbe: var(--bg);
  --buehne: var(--bg);
}

@supports (background: color-mix(in oklab, #000, #fff 50%)) {
  :root {
    --buehne: color-mix(in oklab, var(--bg), var(--stil-ton-farbe) calc(var(--stil-ton) * 100%));
  }
}

body {
  margin: 0;
  /* Sichere Raender (viewport-fit=cover, siehe Kopf der Seiten): oben
     der Streifen unter der Statusleiste, seitlich die Kerbe im
     Querformat. Unten traegt sie der Fuss selbst, damit sein Grund bis
     an den Rand reicht. Ohne cover sind alle Werte null. */
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  background: var(--buehne);
  color: var(--ink);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--accent); }

button { font-family: inherit; cursor: pointer; }
input, textarea { font-family: inherit; }
input::placeholder, textarea::placeholder { color: var(--ink); opacity: .28; }

h1, h2, h3, h4, h5, h6 { cursor: default; }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@keyframes einfahren {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
  html { scroll-behavior: auto !important; }
}

/* ---------- Layout ---------- */
.sec {
  max-width: 1280px;
  margin: 0 auto;
  padding: 96px 48px;
  border-bottom: 1px solid var(--hairline);
}

.sec--head { padding: 120px 48px 96px; }
.sec--closing { padding: 120px 48px 128px; border-bottom: 0; }
.sec--last { border-bottom: 0; }

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 32px;
}

/* Spalten-Utilities: .c{Start}-{Breite} */
.c1-2  { grid-column: 1 / span 2; }
.c1-3  { grid-column: 1 / span 3; }
.c1-4  { grid-column: 1 / span 4; }
.c1-5  { grid-column: 1 / span 5; }
.c1-6  { grid-column: 1 / span 6; }
.c1-7  { grid-column: 1 / span 7; }
.c1-8  { grid-column: 1 / span 8; }
.c1-10 { grid-column: 1 / span 10; }
.c1-12 { grid-column: 1 / span 12; }
.c2-10 { grid-column: 2 / span 10; }
.c3-3  { grid-column: 3 / span 3; }
.c3-8  { grid-column: 3 / span 8; }
.c4-5  { grid-column: 4 / span 5; }
.c4-6  { grid-column: 4 / span 6; }
.c6-3  { grid-column: 6 / span 3; }
.c6-5  { grid-column: 6 / span 5; }
.c7-6  { grid-column: 7 / span 6; }
.c8-4  { grid-column: 8 / span 4; }
.c8-5  { grid-column: 8 / span 5; }
.c9-3  { grid-column: 9 / span 3; }
.c9-4  { grid-column: 9 / span 4; }
.c10-3 { grid-column: 10 / span 3; }

.self-end { align-self: end; }
.self-start { align-self: start; }

/* ---------- Typografie ---------- */
.h1 {
  margin: 0;
  font-size: clamp(44px, 6.4vw, 96px);
  line-height: .98;
  letter-spacing: -.035em;
  font-weight: 600;
  text-wrap: balance;
}

.h2 {
  margin: 0;
  font-size: clamp(30px, 3.4vw, 50px);
  line-height: 1.06;
  letter-spacing: -.025em;
  font-weight: 600;
  text-wrap: balance;
}

.h2--display {
  font-size: clamp(34px, 4.6vw, 68px);
  line-height: 1.02;
  letter-spacing: -.03em;
}

.center { text-align: center; }

/* ---------- Warp-Text: Glas-Verzerrung per WebGL ----------
   Klein und kursiv, als Teil des Satzes (nicht als eigener Block).
   Der Container bleibt ein normales, sichtbares Textelement (Fallback
   ohne JS/WebGL); js/warptext.js legt bei Erfolg ein Canvas darüber
   und blendet den Originaltext nur farblich aus (bleibt für
   Screenreader vorhanden). */
.warp-text {
  position: relative;
  display: inline-block;
  vertical-align: top;
  cursor: default;
  font-style: italic;
}

.warp-text canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* Intern wird hell auf transparent gezeichnet (nötig für die
     Chrom-/Regenbogen-Kanaltrennung, siehe js/warptext.js); invert()
     dreht das auf dunkel für den hellen Seitenhintergrund, die
     Farbsäume bleiben dabei erhalten. */
  filter: invert(1);
}

.warp-text.warp-text--ready {
  color: transparent;
}

.lead {
  margin: 44px 0 0;
  font-size: 19px;
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}

.lead-md {
  margin: 0;
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-2);
  text-wrap: pretty;
}

.label {
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.label--light { color: var(--ink-4); }
.label span.normal { text-transform: none; letter-spacing: 0; }

.note { font-size: 13px; color: var(--ink-4); }
.note--md { font-size: 14px; }

/* ---------- Links & Buttons ---------- */
.link {
  font-size: 15px;
  font-weight: 500;
  border-bottom: 1.5px solid var(--ink);
  padding-bottom: 3px;
}

.link--soft {
  font-size: 15px;
  font-weight: 400;
  color: var(--ink-3);
  border-bottom: 1px solid rgba(17, 17, 17, .3);
  padding-bottom: 2px;
}

.link--inline {
  border-bottom: 1px solid rgba(17, 17, 17, .3);
  padding-bottom: 1px;
  white-space: nowrap;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  background: var(--ink);
  color: var(--bg);
  border: none;
  padding: 17px 30px;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: .01em;
  transition: background .2s;
}

.btn:hover { background: var(--accent); color: var(--bg); }
.btn .arr { opacity: .6; }

/* ---------- Knopf im Pendelzustand ----------
   Beschriftung bleibt stehen, nur der Pfeil weicht einem laufenden Ring:
   so springt die Breite des Knopfes nicht, und es ist auf einen Blick zu
   sehen, dass noch etwas unterwegs ist. Der Ring sitzt im Pfeil selbst,
   damit er genau an dessen Platz liegt. Die eigene Farbe steht am Ring,
   weil der Pfeil daneben durchsichtig geschaltet ist -- currentColor waere
   sonst ebenfalls durchsichtig. */
/* Nicht wie ein toter Knopf aussehen: waehrend des Wartens bleibt er
   dunkel und lesbar, nur eben nicht bedienbar. Ohne das griffe die Regel
   fuer [disabled] weiter oben, und Beschriftung wie Ring waeren kaum noch
   zu sehen. */
.btn.ist-pendent[disabled] {
  background: var(--ink);
  color: var(--bg);
  opacity: .85;
}

.btn.ist-pendent { cursor: progress; }
.btn.ist-pendent .arr {
  position: relative;
  color: transparent;
}

.btn.ist-pendent .arr::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 13px;
  height: 13px;
  margin: -7px 0 0 -7px;
  color: var(--bg);
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: knopf-dreht .7s linear infinite;
}

@keyframes knopf-dreht {
  to { transform: rotate(1turn); }
}

/* Ohne Bewegung: statt zu drehen pulst der Ring leicht -- es bleibt
   erkennbar, dass etwas laeuft, ohne dass sich etwas dreht. */
@media (prefers-reduced-motion: reduce) {
  .btn.ist-pendent .arr::after {
    animation: knopf-pulst 1.4s ease-in-out infinite;
    border-top-color: currentColor;
  }
  @keyframes knopf-pulst {
    50% { opacity: .35; }
  }
}

.btn--sm { padding: 15px 26px; gap: 10px; }

.btn[disabled], .btn.is-disabled {
  background: rgba(17, 17, 17, .12);
  color: var(--ink-4);
  pointer-events: none;
}

.btn-ghost {
  background: none;
  border: none;
  padding: 0 0 3px;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  border-bottom: 1.5px solid var(--ink);
}

.btn-plain {
  background: none;
  border: none;
  padding: 0 0 2px;
  font-size: 15px;
  color: var(--ink-3);
  border-bottom: 1px solid rgba(17, 17, 17, .3);
}

.btn-back {
  background: none;
  border: none;
  padding: 0;
  font-size: 15px;
  color: var(--ink-3);
}

.btn-back[disabled] { color: #c4c0b8; pointer-events: none; }

/* ---------- Kontakt: Kopf ---------- */
.kontakt-titel { align-self: center; }

/* Zwei Sprechblasen im Gespraech: die graue vorn und groesser, die
   gruene dahinter, kleiner und unten rechts ueberlappend, wie eine
   zweite, gerade antwortende Person. Das Grau ist ein eigener, blasser
   Ton, nicht --ink-4 (das waere fuer eine so grosse Flaeche zu dunkel);
   Beide sind an der gemeinsamen senkrechten Mittelachse gespiegelt:
   die zuerst gebaute liegt jetzt oben rechts (gruen, gespiegelt), die
   zweite unten links (grau, seitenrichtig) -- Positionen UND Farben
   gegenueber der vorigen Fassung getauscht, nicht nur eine der beiden. */
.kontakt-blasen {
  position: relative;
  align-self: center;
  justify-self: end;
  width: clamp(168px, 22vw, 320px);
  aspect-ratio: 512 / 414;
}

.kontakt-blase { display: block; height: auto; }

.kontakt-blase--eins {
  position: absolute;
  right: 0;
  top: 0;
  width: 68%;
  transform: scaleX(-1) scale(0.7);
  transform-origin: center;
  opacity: 0;
  fill: var(--accent-green);
  animation: kontakt-blase-auf-li 0.4s cubic-bezier(0.2, 0.9, 0.3, 1.2) 0.15s forwards;
}

.kontakt-blase--zwei {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 68%;
  transform: scale(0.7);
  transform-origin: center;
  opacity: 0;
  fill: #d8d4cb;
  animation: kontakt-blase-auf 0.4s cubic-bezier(0.2, 0.9, 0.3, 1.2) 2.15s forwards;
}

/* Gruen ploppt beim Laden zuerst auf, Grau folgt zwei Sekunden
   spaeter -- wie eine Antwort, die auf sich warten laesst. Eigene
   Variante fuer die gespiegelte Blase, damit die Spiegelung waehrend
   der ganzen Animation erhalten bleibt (sonst ueberschriebe die
   Skalierung im Keyframe das scaleX(-1)). Verzoegerung 0.15s/2.15s
   statt 0s/2s, damit beim Laden nicht auch das Layout selbst noch
   springt. */
@keyframes kontakt-blase-auf {
  from { opacity: 0; transform: scale(0.7); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes kontakt-blase-auf-li {
  from { opacity: 0; transform: scaleX(-1) scale(0.7); }
  to   { opacity: 1; transform: scaleX(-1) scale(1); }
}

/* "Tippt gerade": unten links von der gruenen Blase, im Zeitfenster,
   in dem die Antwort (die graue Blase) noch aussteht -- von 0,5s bis
   2s ab dem Laden, also bevor Grau bei 2,15s startet. Drei Punkte
   wippen darin, ohne Sprechblasen-Kontur: sie sind der Hinweis, nicht
   selbst eine dritte Blase. */
.kontakt-tippt {
  position: absolute;
  /* Weiter rechts als die Kante des Bildes: dort haengen sie unter der
     Blase, statt allein am Rand zu stehen. */
  left: 15%;
  bottom: 17%;
  display: flex;
  gap: 9px;
  opacity: 0;
  animation: kontakt-tippt-rahmen 1.5s ease 0.5s forwards;
}

.kontakt-tippt__punkt {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--ink-4);
  animation: kontakt-tippt-wippen 0.5s ease-in-out 0.5s 3;
}

.kontakt-tippt__punkt:nth-child(2) { animation-delay: 0.62s; }
.kontakt-tippt__punkt:nth-child(3) { animation-delay: 0.74s; }

@keyframes kontakt-tippt-rahmen {
  0%, 100% { opacity: 0; }
  14%, 86% { opacity: 1; }
}

@keyframes kontakt-tippt-wippen {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-7px); }
}

@media (prefers-reduced-motion: reduce) {
  .kontakt-blase--eins, .kontakt-blase--zwei { animation: none; opacity: 1; }
  .kontakt-blase--eins { transform: scaleX(-1); }
  .kontakt-blase--zwei { transform: none; }
  .kontakt-tippt { display: none; }
}

@media (max-width: 900px) {
  .kontakt-blasen { display: none; }
}

.jumplinks {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 26px;
  margin-top: 44px;
}

.textlinks { display: flex; gap: 32px; margin-top: 56px; }

/* ---------- Sprachhinweis-Streifen ---------- */
.lang-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 9px 24px;
  background: var(--ink);
  color: var(--bg);
  font-size: 13px;
  letter-spacing: .01em;
}

.lang-banner a {
  color: var(--bg);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.lang-banner__close {
  margin-left: 6px;
  background: none;
  border: none;
  color: var(--ink-4);
  font-size: 15px;
  line-height: 1;
  padding: 2px 4px;
}

.lang-banner[hidden] { display: none; }

/* ---------- Header ---------- */
/* Die Kopfzeile kann einen eigenen Ton annehmen, unabhaengig vom
   Buehnenton der Seite: Abschnitte mit data-kopf faerben sie ein, waehrend
   sie heraufkommen (--kopf-ton und --kopf-farbe setzt js/main.js). Schrift,
   Trennlinien und Burger richten sich nach --kopf-schrift, damit sie auf
   dunklem Grund hell stehen. */
.site-header {
  --kopf-grund: var(--buehne);
  --kopf-schrift: var(--ink);
  position: sticky;
  /* Klebt unter der Statusleiste, nicht dahinter. */
  top: env(safe-area-inset-top, 0px);
  z-index: 20;
  background: rgba(251, 250, 248, .92);
  /* Gewoehnlich leicht durchscheinend, damit der Inhalt darunter ahnbar
     bleibt. Nimmt die Zeile den Ton eines Stils an, wird sie mit ihm
     zunehmend deckend: Auf farbigem Grund wirkt durchscheinend schmutzig,
     weil sich der Ton mit dem Inhalt mischt. */
  background: color-mix(in srgb,
    var(--kopf-grund) calc(92% + var(--kopf-ton, 0) * 8%), transparent);
  color: var(--kopf-schrift);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hairline);
}

@supports (background: color-mix(in oklab, #000, #fff 50%)) {
  .site-header {
    --kopf-grund: color-mix(in oklab, var(--buehne), var(--kopf-farbe, var(--bg)) calc(var(--kopf-ton, 0) * 100%));
    --kopf-schrift: color-mix(in oklab, var(--ink), var(--bg) calc(var(--kopf-ton, 0) * 100%));
    border-bottom-color: color-mix(in oklab, var(--hairline), transparent calc(var(--kopf-ton, 0) * 100%));
  }
}

/* Titel und Links folgen dem Ton der Zeile statt der Seitenfarbe. */
.site-header .brand,
.site-header .site-nav a,
.site-header .lang-switch a { color: var(--kopf-schrift); }

.site-header .lang-switch {
  color: color-mix(in oklab, var(--kopf-schrift), transparent 40%);
  border-left-color: color-mix(in oklab, var(--kopf-schrift), transparent 80%);
}

.site-header__inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 48px;
  height: 76px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Georgia wie im Zeichen fuer den Reiter: dort steht das M1 in derselben
   Schrift, so passt der Name im Kopf dazu. In den Stilen auf der
   Startseite bleibt es bei deren eigenen Schriften — die Regeln zu
   data-marke stehen in css/pages.css und wiegen schwerer. */
.brand {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -.01em;
}

/* Der Name faltet sich beim Bildlauf auf das Zeichen zusammen: "odernOne"
   zieht sich hinter das M zurueck, und von seinem rechten Bein blendet
   eine 1 nach rechts aus -- am Ende steht M1 wie im Zeichen fuer den
   Reiter. Gemacht wird das ueber die Breite und nicht ueber die
   Sichtbarkeit: so bleibt das M an seinem Platz stehen, waehrend der
   Rest verschwindet, und die Zeile springt nicht.

   inline-flex und Grundlinie: die Stuecke sollen auf einer Linie sitzen,
   auch wenn eines gerade schmal ist. */
.brand {
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
}

.brand__rest {
  display: inline-block;
  overflow: hidden;
  /* Reichlich bemessen: der genaue Wert spielt keine Rolle, solange er
     ueber der Breite des Wortes liegt -- eng gesetzt wuerde er ihn
     beschneiden. */
  max-width: 7em;
  transition: max-width .5s var(--ease), opacity .3s var(--ease);
}

/* Das M traegt die 1 als eigenes Kind: an left: 100% haengt sie genau an
   seiner rechten Kante, also an seinem rechten Bein -- ohne dass
   irgendwo eine Breite der Schrift nachgerechnet werden muesste. */
.brand__m { position: relative; }

.brand__eins {
  position: absolute;
  left: 100%;
  top: 0;
  /* Verborgen wird von links her abgeschnitten, nicht ausgeblendet: so
     kommt die 1 wirklich aus dem Bein heraus und erscheint nicht
     irgendwo daneben. Zuvor lag sie im Fluss hinter dem Wort und kam
     darum erst zum Vorschein, wenn das schon fast zusammengelaufen
     war. */
  clip-path: inset(0 100% 0 0);
  transform: translateX(-.5em);
  opacity: 0;
  /* Der Rueckweg ist keine Rueckwaertsfahrt: hinauf blendet die 1
     schlicht aus, wie in der ersten Fassung. Der Schnitt und die
     Verschiebung springen erst danach zurueck (Dauer null, verzoegert),
     sonst kroche sie sichtbar ins Bein zurueck. */
  transition: opacity .28s var(--ease),
              clip-path 0s linear .28s,
              transform 0s linear .28s;
}

.site-header.ist-kurz .brand__rest { max-width: 0; opacity: 0; }

.site-header.ist-kurz .brand__eins {
  /* Ein Hauch ueber die Kante hinaus, damit die Rundung der 1 nicht
     angeschnitten wird. */
  clip-path: inset(0 -.12em 0 0);
  transform: none;
  opacity: 1;
  /* Hinunter kommt sie aus dem Bein: der Schnitt laeuft, die Deckkraft
     steht von Anfang an. */
  transition: clip-path .5s var(--ease),
              transform .5s var(--ease),
              opacity .01s linear;
}

/* Wo der Streckenlauf den Namen fuehrt (Startseite), bleibt die 1 aus:
   dort ist der Name selbst in Bewegung, und Stil 3 bringt sein eigenes
   Kuerzel mit. */
.site-header[data-kompakt] .brand__eins { display: none; }

/* Der erste Zustand kommt ohne Bewegung -- siehe js/main.js. */
.site-header.brand-ohne-flug .brand__rest,
.site-header.brand-ohne-flug .brand__eins { transition: none; }

/* Platz fuer die 1, die als abgesetztes Kind keinen im Fluss braucht:
   ohne ihn liegt die Klickflaeche des Verweises zu eng am M. */
.site-header.ist-kurz .brand { padding-right: .62em; }

@media (prefers-reduced-motion: reduce) {
  .brand__rest,
  .brand__eins { transition-duration: .01ms; }
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 34px;
}

.site-nav a { font-size: 14px; }

.site-nav a.active {
  font-weight: 600;
  border-bottom: 1.5px solid var(--ink);
  padding-bottom: 2px;
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink-4);
  padding-left: 14px;
  border-left: 1px solid rgba(17, 17, 17, .14);
}

.lang-switch a { font-weight: 600; color: var(--ink); }

/* ---------- Farbstreifen fuer die Glasleiste von Safari 26 ----------
   Safari auf dem iPhone faerbt seine Leiste nach einem feststehenden
   Element, das bis auf drei Bildpunkte an den unteren Rand reicht,
   mindestens vier Fuenftel der Breite hat und sichtbar ist. Gibt es
   keins, faellt es auf Weiss zurueck. theme-color liest es nicht mehr.

   Dieser Streifen ist genau so ein Element: er haengt acht Bildpunkte
   unter den Rand, davon ragen vier herein -- zu wenig, um ihn zu sehen,
   genug, um gelesen zu werden. Seine Farbe fuehrt js/main.js mit dem,
   was gerade am unteren Rand liegt: Papier, der Schleier des Menues
   oder der Fuss. So sieht die Leiste aus wie ein Stueck Seite.

   Auf Geraeten ohne Zeiger, also auf Handy und Tablet. Am Schreibtisch
   bleibt er weg, dort laege sonst ein vier Bildpunkte hoher Streifen
   ueber dem Fuss. Frueher stand hier eine Weiche aus drei @supports-
   Abfragen, die nur WebKit auf iOS treffen sollte -- sie traf es nicht,
   der Streifen blieb aus, und die Leiste fiel auf Weiss zurueck. Die
   Abfrage auf den fehlenden Zeiger ist gutmuetiger: auf einem Android
   liegt der Streifen dann eben auch da, farbgleich und unsichtbar. */
.leistenfarbe {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  /* Ganz aus dem Bild heraus: Safari liest Flaechen, die bis auf drei
     Bildpunkte an den unteren Rand reichen -- drin liegen muessen sie
     nicht. Vorher ragten vier Bildpunkte herein und standen ueber einem
     Bild oder einer getoenten Sektion als fremdfarbiges Band da. */
  bottom: -3px;
  height: 3px;
  /* Ueber allem: laege ein anderes feststehendes Element darueber,
     laese Safari womoeglich das. */
  z-index: 2147483000;
  /* Die Farbe setzt js/main.js: der Ton, der gerade hinter der Leiste
     liegt -- Papier, die abgegraute Sektion, der Fuss oder die
     Verdunkelung der Grossansicht. Damit sieht die Leiste aus wie das,
     was hinter ihr liegt. Ganz ohne Farbe geht es nicht: Safari faellt
     dann auf den Grund des Koerpers zurueck, und wo der nicht passt,
     stand ein heller Balken. Hier steht nur der Anfangswert. */
  background-color: #fbfaf8;
  pointer-events: none;
}

/* Gegenstueck am oberen Rand: es deckt den Streifen unter der
   Statusleiste. Der gehoert mit viewport-fit=cover zur Seite, gefuellt
   hat ihn aber das obere Polster des Koerpers -- also der Papierton,
   und der stand ueber jeder Verdunkelung als heller Balken. Hoehe genau
   der sichere Rand: wo es keinen gibt, ist der Streifen null hoch. */
.leistenfarbe--oben {
  /* Gespiegelt, fuer die Zeile mit Uhr und Ladestand: Safari sucht dort
     in den ersten vier Bildpunkten und liest nur feststehende Flaechen,
     die mindestens vier Fuenftel breit und drei Bildpunkte hoch sind.
     Die Kopfzeile klebt unter dem sicheren Rand, also rund sechzig
     Bildpunkte tiefer, und fiel aus der Lesung -- Safari nahm den Grund
     des Koerpers, und das war oben das helle Polster. Auch dieser
     Streifen liegt ganz ausserhalb des Bildes. */
  top: -4px;
  bottom: auto;
  height: 4px;
}

@media (max-width: 1024px) and (hover: none) {
  .leistenfarbe { display: block; }
}

/* ---------- Kopfzeile im Kompaktzustand ----------
   Ab der Stil-Strecke (s1k1, siehe js/main.js) rueckt der Titel in die Mitte
   und die Seitenlinks weichen einem Burger-Knopf. Der Titel wird dabei nur
   verschoben, nicht umgehaengt — so bleibt die Zeile ruhig und es springt
   nichts, wenn die Links verschwinden. Die Strecke steht als --brand-shift
   am Kopf, weil sie von der Breite des Titels abhaengt. */
.site-header__inner { position: relative; }

/* Deckung neben der Verschiebung: Beim Wechsel der Schrift blendet der
   Titel kurz aus, damit der Tausch nicht offen geschieht (siehe
   markeSetzen in js/main.js). Schrift, Groesse und Verschiebung wechseln
   dort gemeinsam und ohne Uebergang; die Angaben hier gelten fuer die
   uebrigen Faelle, etwa den Weg in die Mitte beim Kompaktwerden. */
.brand {
  transition: transform .5s var(--ease),
              opacity .18s var(--ease),
              font-size .45s var(--ease);
}

.brand.is-wechsel { opacity: 0; }

.site-header.is-kompakt .brand {
  transform: translateX(var(--brand-shift, 0px));
}

.site-nav {
  transition: opacity .3s var(--ease), transform .4s var(--ease);
}

.site-header.is-kompakt .site-nav {
  opacity: 0;
  transform: translateX(14px);
  pointer-events: none;
  visibility: hidden;
}

/* Burger-Knopf: liegt ueber der rechten Kante, wo vorher die Links standen. */
.burger {
  position: absolute;
  right: 48px;
  top: 50%;
  width: 34px;
  height: 34px;
  margin-top: -17px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateX(-10px);
  transition: opacity .3s var(--ease) .12s,
              transform .4s var(--ease) .12s,
              visibility 0s linear .42s;
}

.site-header.is-kompakt .burger {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .3s var(--ease) .16s,
              transform .4s var(--ease) .16s,
              visibility 0s linear 0s;
}

/* Der Knopf ist 34 Pixel gross, fuer den Finger sind 44 empfohlen --
   ein unsichtbares Feld weitet die Trefferflaeche, ohne das Bild zu
   veraendern. */
.burger::before {
  content: '';
  position: absolute;
  inset: -5px;
}

/* Zwei Striche aus einem Element: der zweite kommt aus ::after.
   Beim Oeffnen kippen sie zum Kreuz in zwei Zuegen: erst ruecken die
   Striche zusammen, dann drehen sie. Beim Zumachen laeuft es umgekehrt
   -- erst zurueckdrehen, dann auseinander. Die Verzoegerungen stehen
   darum an beiden Zustaenden getrennt. */
.burger__lines,
.burger__lines::after {
  position: absolute;
  left: 7px;
  width: 20px;
  height: 1.5px;
  background: var(--kopf-schrift, var(--ink));
  transition: top .2s var(--ease), transform .26s var(--ease) .16s;
}

.burger__lines { top: 13px; }
.burger__lines::after { content: ""; left: 0; top: 7px; }

.burger[aria-expanded="true"] .burger__lines,
.burger[aria-expanded="true"] .burger__lines::after {
  transition: top .2s var(--ease), transform .26s var(--ease) .18s;
}

.burger[aria-expanded="true"] .burger__lines {
  top: 16px;
  transform: rotate(45deg);
}

.burger[aria-expanded="true"] .burger__lines::after {
  top: 0;
  transform: rotate(-90deg);
}

/* ---------- Ausklappmenue ----------
   Haengt unter der Kopfzeile und faehrt auf; die Hoehe steht als
   --menu-height am Element, damit der Uebergang eine Zahl hat. */
.menu-panel {
  /* Ueberlagernd, nicht mitschiebend: waechst das Menue in den Fluss hinein,
     rutscht der Seiteninhalt nach unten — und damit auch die Stil-Strecke,
     die den Kompaktzustand ausloest. Das Menue wuerde sich so selbst wieder
     schliessen. */
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  overflow: hidden;
  max-height: 0;
  background: rgba(251, 250, 248, .96);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid transparent;
  z-index: 2;
  transition: max-height .42s var(--ease), border-color .42s var(--ease);
}

.menu-panel[hidden] { display: none; }

/* Schleier unter dem Klappmenue. Nur auf schmalen Schirmen, wo das
   Menue die Bedienung uebernimmt; am Schreibtisch gehoert es zur
   Stil-Strecke und soll die Buehne nicht verdecken.

   Er steht als Geschwister der Kopfzeile im Dokument, nicht darin: die
   Kopfzeile traegt einen backdrop-filter und ist damit selbst der
   Bezugsrahmen fuer feststehende Kinder -- ein Schleier darin waere nur
   so hoch wie die Zeile geworden, gemessen null. Feststehend deckt er
   die Seite, der Kopf liegt mit z-index 20 darueber.

   Geschlossen ist er nur unsichtbar (Deckkraft null), nicht aus dem
   Baum: seit er unten zwoelf Bildpunkte frei laesst (siehe inset),
   liest Safari 26 ihn ohnehin nicht mehr fuer die Farbe seiner
   Glasleiste. Ein Umschalten von display hatte auf dem iPhone die
   Verdunkelung selbst ausfallen lassen. */
.menu-schleier {
  display: none;
  position: fixed;
  /* Unten zwoelf Bildpunkte frei, mit Absicht: Safari 26 liest fuer die
     Farbe seiner Glasleiste feststehende Elemente, die bis auf drei
     Bildpunkte an den unteren Rand reichen -- den offenen Schleier
     eingeschlossen, die Leiste wurde dann zum Balken. Zwoelf Bildpunkte
     Abstand nehmen ihn aus der Lesung; die Luecke liegt unter dem
     Balken fuer den Startbildschirm und faellt nicht auf. Die Deckkraft
     .99 allein hat nicht gereicht. */
  inset: 0 0 12px;
  z-index: 15;
  /* Nur ein Schleier, kein backdrop-filter: auf dem iPhone erschien
     beim Oeffnen des Menues eine weisse Flaeche am unteren Rand. Ein
     feststehendes Feld ueber das ganze Bild mit backdrop-filter ist in
     Safari genau dafuer bekannt -- es faellt beim Zusammensetzen der
     Ebenen aus und malt seine Flaeche hell. Der Weichzeichner war
     Beigabe, die Verdunkelung allein genuegt. */
  /* Ohne eigene Farbe: er ist nur noch die Flaeche zum Antippen. Die
     Verdunkelung liegt auf dem Inhalt selbst (siehe .hat-menue-offen
     unten), weil die Glasleiste von Safari 26 nur den scrollenden
     Inhalt zeigt und feststehende Schichten wie diesen Schleier
     auslaesst -- hinter der Leiste blieb die Seite hell, waehrend sie
     darueber dunkel war. */
  background: transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity .36s var(--ease);
}

/* Verdunkelung bei offenem Menue, im Inhalt statt als feststehender
   Schleier darueber: so ist sie auch in dem Ausschnitt da, den die
   Glasleiste von Safari zeigt. Die Kopfzeile mit dem Menue bleibt
   aussen vor.

   Als absolut gesetzte Flaeche ueber dem Inhalt, nicht als filter am
   Inhalt: ein brightness() auf main hat Safari auf dem iPhone stumm
   fallen lassen -- die Seite ist rund 5800 Bildpunkte hoch, mit
   dreifacher Aufloesung uebersteigt die gefilterte Ebene die groesste
   Textur, und WebKit laesst den Filter dann einfach weg. Eine gemalte
   Flaeche hat diese Grenze nicht. */
main, .site-footer, .lang-banner { position: relative; }

/* Der Seitenton sitzt auch am Inhalt selbst, nicht nur am Koerper: den
   Grund des Koerpers nimmt Safari auf dem iPhone fuer den Bereich, den
   man beim Ueberziehen am unteren Rand sieht, und der soll am Fuss
   schwarz sein, ohne dass die Seite mitgeht (siehe .ist-am-fuss). */
main { background: var(--buehne); }

main::after, .site-footer::after, .lang-banner::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Die Staerke steht als Wert da: das Menue nimmt .45, die
     Grossansicht des Diploms deckt ganz zu (siehe .hat-grossansicht in
     css/pages.css). */
  background: rgba(17, 17, 17, var(--schleier, .45));
  opacity: 0;
  pointer-events: none;
  transition: opacity .36s var(--ease);
}

.hat-menue-offen main::after,
.hat-menue-offen .site-footer::after,
.hat-menue-offen .lang-banner::after,
.hat-grossansicht main::after,
.hat-grossansicht .site-footer::after,
.hat-grossansicht .lang-banner::after { opacity: 1; }

/* Die Grossansicht des Diploms nimmt dieselbe Verdunkelung, dazu die
   Kopfzeile: dort deckt kein Menue sie ab, und hell stehen bleiben soll
   sie nicht. Sie klebt oben, ihre eigene Flaeche traegt darum den Ton.
   Die Regeln zur Schicht selbst stehen bei .lupe in css/pages.css. */
.site-header::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(17, 17, 17, var(--schleier, .45));
  opacity: 0;
  pointer-events: none;
  transition: opacity .36s var(--ease);
}

.hat-grossansicht .site-header::after {
  opacity: 1;
  /* Hinauf bis ueber den Streifen unter der Statusleiste: die Kopfzeile
     klebt darunter, und ohne das blieb er als heller Balken oben
     stehen. */
  top: calc(-1 * env(safe-area-inset-top, 0px));
  /* Und einen Bildpunkt hinunter ueber die Haarlinie: inset bezieht sich
     auf das Polsterfeld, der Rand liegt ausserhalb -- er blieb als
     heller Strich unter der Zeile stehen. */
  bottom: -1px;
}

.menu-panel.is-open {
  max-height: var(--menu-height, 320px);
  border-bottom-color: var(--hairline);
}

.menu-panel__inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 26px 48px 32px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
}

.menu-panel__inner a {
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -.02em;
}

.menu-panel__inner .lang-switch {
  margin-top: 6px;
  padding-left: 0;
  border-left: none;
}

.menu-panel__inner .lang-switch a { font-size: 11px; font-weight: 600; }

/* Die Zeilen laufen nacheinander ein, damit das Menue sich entfaltet
   statt als Block zu erscheinen. Verzoegerung nur beim Aufgehen: beim
   Zumachen sollen alle zugleich weg sein, sonst haengt die letzte Zeile
   im schon geschlossenen Feld. */
.menu-panel__inner > * {
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity .26s var(--ease), transform .36s var(--ease);
}

.menu-panel.is-open .menu-panel__inner > * { opacity: 1; transform: none; }
.menu-panel.is-open .menu-panel__inner > :nth-child(1) { transition-delay: .06s; }
.menu-panel.is-open .menu-panel__inner > :nth-child(2) { transition-delay: .12s; }
.menu-panel.is-open .menu-panel__inner > :nth-child(3) { transition-delay: .18s; }
.menu-panel.is-open .menu-panel__inner > :nth-child(4) { transition-delay: .24s; }
.menu-panel.is-open .menu-panel__inner > :nth-child(5) { transition-delay: .3s; }

/* Die Seite, auf der man ist, steht kraeftiger da. */
.menu-panel__inner a[aria-current] { font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .menu-panel__inner > * { transition: none; }
}

/* ---------- Karten mit Oberlinie ---------- */
.cards-3, .cards-4, .cards-2 {
  display: grid;
  gap: 32px;
}
.cards-3 { grid-template-columns: repeat(3, 1fr); }
.cards-4 { grid-template-columns: repeat(4, 1fr); }
.cards-2 { grid-template-columns: repeat(2, 1fr); }

.tcard {
  border-top: 2px solid var(--ink);
  padding-top: 16px;
}

.tcard h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.01em;
}

.tcard p {
  margin: 11px 0 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-3);
}

.tcard--lg { padding-top: 18px; }
.tcard--lg h3 { font-size: 17px; }
.tcard--lg p { margin-top: 14px; }

.tcard--info h3 { font-size: 18px; }
.tcard--info p {
  margin: 14px 0 0;
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* Zeilen-Liste (Faktoren, Werdegang) */
.rowline {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 32px;
  padding: 44px 0;
  border-bottom: 1px solid var(--hairline);
}

.rowline h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.01em;
}

.rowline p {
  margin: 0;
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink-3);
}

.rowline .tag {
  font-size: 15px;
  color: var(--ink-4);
  text-align: right;
}

/* Die letzte Zeile schliesst ohne Strich ab -- darunter kommt nichts
   mehr, was er abgrenzen koennte. */
.faktoren > .rowline:last-child { border-bottom: 0; }

/* Ziffer im Seitenrand ----------------------------------------------------

   Sie sitzt links neben den Zeilen, ausserhalb des Rasters, und fliegt
   beim Scrollen vom Bildschirmrand herein.

   Ihr Streifen liegt zwischen Bildschirmrand und Textkante und reicht
   ueber alle Zeilen; die Ziffer klebt darin auf halber Bildhoehe. So
   bleibt sie ab dem Hereinfliegen stehen, bis die letzte Zeile durch
   ist -- der Streifen begrenzt das Kleben von selbst.

   Die Breite des Streifens steht als Rechnung statt als feste Zahl: der
   Abschnitt ist zentriert und hoechstens 1280 Pixel breit, sein Weg zum
   Rand ist also die halbe Differenz zwischen Fensterbreite und
   Inhaltsbreite. Damit stimmt der Sitz bei jeder Fenstergroesse.

   Bewegt wird ueber eine Zeitleiste aus dem Bildlauf: kein Skript, und
   die Bewegung haengt am Scrollstand statt an der Uhr. Wo der Browser
   das nicht kennt, steht die Ziffer einfach an ihrem Platz. */
.faktoren { position: relative; }

/* Oben und unten endet der Streifen auf der Mitte der ersten und der
   letzten Zeile: dort setzt die Ziffer auf der Mittellinie auf, und
   dort loest sie sich wieder. Die beiden Masse setzt js/preise.js, weil
   die Zeilen je nach Umbruch verschieden hoch sind; ohne Skript reicht
   der Streifen wie zuvor ueber den ganzen Block. */
.faktoren__rand {
  position: absolute;
  top: var(--rand-oben, 0px);
  bottom: var(--rand-unten, 0px);
  left: calc((100% - 100vw) / 2);          /* linker Bildschirmrand */
  width: calc((100vw - 100%) / 2);         /* bis zur Textkante */
  pointer-events: none;
}

.faktoren__ziffer {
  position: sticky;
  top: calc(50vh - .5em);                  /* Mitte der Bildhoehe */
  display: block;
  text-align: center;
  font-size: clamp(72px, 7vw, 128px);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -.04em;
  color: var(--ink);
}

/* Unterhalb dieser Breite bleibt neben dem Satzspiegel kein Rand mehr
   uebrig; die Ziffer laege sonst auf dem Text. */
@media (max-width: 1359px) {
  .faktoren__rand { display: none; }
}

@supports (animation-timeline: view()) {
  @media (min-width: 1360px) and (prefers-reduced-motion: no-preference) {
    .faktoren__ziffer {
      animation: ziffer-einfaden linear both;
      animation-timeline: view();
      /* Nicht "entry": das waere abgeschlossen, bevor die Ziffer ueber
         den unteren Bildrand geschoben ist -- man saehe das Aufblenden
         also nie. Ueber "cover" laeuft es, waehrend sie sichtbar nach
         oben wandert, und ist vor dem Kleben in der Mitte fertig. */
      animation-range: cover 8% cover 27%;
    }
  }
}

/* Sie blendet aus einem kurzen Weg von links auf, statt vom Rand
   hereinzufahren: derselbe Anlauf, nur leiser. */
@keyframes ziffer-einfaden {
  from { opacity: 0; transform: translateX(-48px); }
  to   { opacity: 1; transform: none; }
}

/* Die Zahl steckt noch einmal in einem eigenen Feld: das Aufblenden am
   Anfang haengt an der Zeitleiste des Bildlaufs, der Wechsel beim
   Weiterzaehlen an der Uhr -- beides auf einem Element vertruege sich
   nicht. Beim Zaehlen wechselt nur die Deckkraft, ohne Weg: die Zahl
   steht ja schon an ihrem Platz. */
.faktoren__zahl { display: block; }

.faktoren__zahl.ist-neu { animation: ziffer-zaehlen .28s var(--ease); }

@keyframes ziffer-zaehlen {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .faktoren__zahl.ist-neu { animation: none; }
}

/* Abgesetzter Info-Block (Immer Festpreis, Warum bei mir …) */
.infoblock {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 32px;
  margin-top: 64px;
  padding-top: 28px;
  border-top: 1px solid var(--hairline-strong);
}

.infoblock h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.01em;
}

.infoblock p {
  margin: 0;
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink-3);
  text-wrap: pretty;
}

.infoblock p + p { margin-top: 16px; }

/* ---------- FAQ-Akkordeon ---------- */
.faq-item { border-top: 1px solid var(--hairline-strong); }
.faq-item:first-child { border-top: 0; }
.faq-item:last-child { border-bottom: 1px solid var(--hairline-strong); }

.faq-q {
  width: 100%;
  background: none;
  border: none;
  padding: 24px 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  text-align: left;
  color: var(--ink);
}

.faq-q .q {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -.01em;
}

.faq-q .ic {
  font-size: 20px;
  color: var(--ink-4);
  line-height: 1;
}

.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .38s var(--ease);
}

.faq-a > div { overflow: hidden; }

.faq-a p {
  margin: 0;
  padding-bottom: 0;
  max-width: 34em;
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink-3);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .3s ease 0s,
              transform .38s var(--ease),
              padding-bottom .38s var(--ease);
}

.faq-item.open .faq-a { grid-template-rows: 1fr; }

.faq-item.open .faq-a p {
  padding-bottom: 28px;
  opacity: 1;
  transform: none;
  transition: opacity .3s ease .08s,
              transform .38s var(--ease),
              padding-bottom .38s var(--ease);
}

.faq-group-label { display: block; margin-top: 56px; }
.faq-group { margin-top: 14px; }

/* ---------- Formulare ---------- */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px 32px;
}

.form-grid .span2 { grid-column: 1 / span 2; }

/* Verborgen heisst verborgen: das display unten schlaegt sonst das
   display:none, das der Browser fuer [hidden] mitbringt. */
.field[hidden] { display: none; }

/* Die Frage darueber sagt schon, was gefragt ist -- die Beschriftung
   waere dieselbe Zeile zweimal. Sie wird nur aus dem Bild genommen und
   nicht ausgebaut, damit das Feld benannt bleibt. */
[data-angaben-text] .label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.field input,
.field textarea {
  font-size: 16px;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1.5px solid var(--input-line);
  padding: 8px 0;
  outline: none;
}

.field textarea { line-height: 1.6; resize: vertical; }

.field input:focus,
.field textarea:focus { border-bottom-color: var(--ink); }

/* Beanstandetes Feld: nur die Linie faerbt sich, der Rest bleibt ruhig. */
.field input.is-invalid,
.field textarea.is-invalid { border-bottom-color: var(--accent); }

/* Sammelmeldung unter dem Formular (Fehler oder Bestaetigung). */
.form-status {
  margin: 22px 0 0;
  font-size: 14px;
  line-height: 1.6;
}

.form-status.is-error { color: var(--accent); }
.form-status.is-ok { color: var(--accent-green); }
/* Waehrend des Wartens: gedeckt, weder Zusage noch Absage. */
.form-status.is-laeuft { color: var(--ink-3); }

/* Honigtopf: fuer Menschen unsichtbar, fuer Bots ein gefundenes Fressen.
   Kein display:none — manche Bots ueberspringen versteckte Felder. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Anrede-Radios */
.radio-row {
  display: flex;
  gap: 26px;
  align-items: center;
  min-height: 33px;
}

.radio {
  font-size: 16px;
  color: var(--ink-2);
  background: none;
  border: none;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  line-height: 1;
}

.radio .ring {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  flex: none;
  position: relative;
  top: -1px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid rgba(17, 17, 17, .28);
  transition: border-color .18s;
}

.radio .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink);
  transform: scale(0);
  transition: transform .18s;
}

/* Fehlende Anrede: die Ringe der Reihe nehmen die Fehlerfarbe an -- das
   versteckte Feld selbst kann nichts zeigen. */
.radio-row.is-invalid .ring,
[data-anrede].is-invalid .ring { border-color: var(--accent); }

.radio.active .ring { border-color: var(--ink); }
.radio.active .dot { transform: scale(1); }

.radio-other {
  font-size: 16px;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1.5px solid var(--input-line);
  padding: 6px 0;
  outline: none;
  flex: 1;
  min-width: 0;
  animation: rise .25s ease both;
}

.radio-other:focus { border-bottom-color: var(--ink); }
.radio-other[hidden] { display: none; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--ink);
  color: var(--bg);
}

.site-footer__inner {
  max-width: 1280px;
  margin: 0 auto;
  /* Unten dazu der Rand mit dem Balken fuer den Startbildschirm: der
     dunkle Grund des Fusses laeuft so bis an die Bildkante, der Text
     bleibt darueber. */
  padding: 80px 48px calc(40px + env(safe-area-inset-bottom, 0px));
}

.site-footer a { color: var(--bg); font-size: 15px; }
.site-footer a:hover { color: var(--accent); }

/* Groesser als die Zeilen um sie: im Fuss ist die Wortmarke die
   Unterschrift des Ganzen und nicht eine Angabe unter vielen. */
.site-footer .brand { font-size: 22px; }

.site-footer .claim {
  margin: 14px 0 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-4);
  max-width: 22em;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer-col .label { color: var(--ink-footer); }

.footer-col .cta {
  border-bottom: 1px solid var(--ink-2);
  padding-bottom: 3px;
  align-self: flex-start;
}

.site-footer__meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  margin-top: 72px;
  padding-top: 24px;
  border-top: 1px solid #2a2723;
  font-size: 13px;
  color: var(--ink-footer);
  flex-wrap: wrap;
}

.site-footer__meta a { color: var(--ink-footer); font-size: 13px; }
.site-footer__meta .links { display: flex; gap: 24px; }

/* Passt die Zeile nicht auf eine Hoehe, faellt der FAQ-Verweis weg --
   er ist der Zusatz, Impressum und Datenschutz muessen bleiben. Ob es
   passt, misst js/main.js und setzt danach diese Klasse; eine feste
   Breite waere geraten, denn die Schrift setzt auf dem iPhone breiter. */
.site-footer__meta.ist-eng .fuss-faq { display: none; }

/* Kleiner Weichzeichner an der unteren Bildkante: was hinausscrollt,
   loest sich auf statt hart abgeschnitten zu werden. Die Maske laesst
   ihn nach oben auslaufen, unten wirkt er voll.

   Nur am Schreibtisch: auf dem Handy sitzt dort die Leiste des
   Browsers, die ohnehin Glas ist -- und ein feststehendes Feld mit
   backdrop-filter am unteren Rand hat dort schon einmal Aerger
   gemacht (siehe .menu-schleier). */
@media (min-width: 1025px) and (hover: hover) and (pointer: fine) {
  body::after {
    content: '';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: 30px;
    z-index: 12;
    pointer-events: none;
    -webkit-backdrop-filter: blur(2.5px);
    backdrop-filter: blur(2.5px);
    /* Gerade Rampe ohne Zwischenhalt: mit einem Halt auf halber Hoehe
       blieb der Weichzeichner oben noch halb stark stehen, und das las
       sich als Schimmer statt als Kante. */
    -webkit-mask-image: linear-gradient(to top, #000, transparent);
    mask-image: linear-gradient(to top, #000, transparent);
  }
}

/* ---------- Einfahren beim Scrollen (Über mich) ---------- */
.reveal {
  animation: einfahren .55s cubic-bezier(.2, .6, .2, 1) both;
  animation-timeline: view();
  animation-range: entry 8% cover 26%;
}

@supports not (animation-timeline: view()) {
  .reveal { animation: einfahren .55s cubic-bezier(.2, .6, .2, 1) both; }
}

/* ---------- Responsiv ---------- */

/* Flache Fenster (kleine Notebooks, Browser-Zoom): Der Seitenkopf ist mit
   120/96px Abstand und 96px-Überschrift 758px hoch — darunter rutschen Lead
   und „Weiterlesen" unter die Sichtkante. Hier kompakter, damit der Einstieg
   ohne Scrollen vollständig lesbar bleibt. Auf hohen Bildschirmen und auf
   Mobil greift die Regel nicht, dort bleiben die Konzeptmaße unverändert. */
@media (min-width: 961px) and (max-height: 880px) {
  .sec--head {
    padding-top: clamp(52px, 10vh, 80px);
    padding-bottom: clamp(40px, 8vh, 64px);
  }

  /* Die Flaeche ist vier von zwoelf Spalten breit und quadratisch, bei
     1280 Pixeln also 373 hoch -- damit reichte der Kopf in einem 680
     Pixel hohen Fenster genau bis an die Unterkante und in einem 600
     Pixel hohen fuenfzig darueber hinaus. Nach der Bildhoehe begrenzt
     und rechts an die Spaltenkante gestellt passt er wieder ganz ins
     Bild. */
  .sec--head .kopfvideo {
    width: min(100%, 46vh);
    margin-left: auto;
  }

  /* Wo der Fensterstapel steht, braucht der Kopf mehr Polster oben. Der
     Stapel ist 412 Pixel hoch und sitzt mittig in der Rasterzeile; die
     schrumpft hier aber auf gut 230, weil Ueberschrift und Abstaende
     kleiner werden. Er ragt dann oben ueber die Zeile hinaus -- gemessen
     bis zu 22 Pixel weit hinter die Navigation, wo seine Titelleiste
     verschwand. Das Polster faengt diesen Ueberhang auf. */
  /* Der Stapel ist 412 Pixel hoch und braucht ueber und unter sich
     Luft, sonst klebt er an der Navigation und an der Trennlinie --
     gemessen blieben in einem 820 Pixel hohen Fenster 25 Pixel oben und
     6 unten. Das Polster hier gilt nur fuer den Kopf mit dem Stapel;
     die anderen Koepfe bleiben kompakt. */
  .sec--head:has(.fenster-stapel) {
    padding-top: 158px;
    padding-bottom: 132px;
  }
  .sec--head .h1 { font-size: clamp(40px, 5.2vw, 76px); }
  .sec--head .lead { margin-top: 32px; font-size: 18px; }
  .sec--head .jumplinks, .sec--head .hero-cta-row { margin-top: 32px; }
}

@media (max-width: 960px) {
  .sec { padding-left: 24px; padding-right: 24px; }
  .sec--head { padding-top: 72px; }
  .site-header__inner { padding: 0 24px; height: 64px; }
  .site-nav { gap: 18px; }
  .burger { right: 24px; }
  .menu-panel__inner { padding: 22px 24px 28px; }
  .site-footer__inner { padding: 56px 24px calc(32px + env(safe-area-inset-bottom, 0px)); }

  .grid { gap: 24px; }

  /* Alle Spalten-Utilities einzeln aufgezaehlt statt ueber [class^="c"]:
     der Praefix-Vergleich sieht nur den Anfang der ganzen Klassenliste,
     und der beginnt bei <h1 class="h1 c1-7"> nicht mit einem c. Auf
     dieser Seite betraf das zweiundzwanzig Elemente -- Ueberschriften,
     Vorspann und das Rechnerfeld blieben mobil auf sieben oder acht
     Zwoelfteln stehen, statt die Breite zu nehmen. */
  .grid > :is(.c1-2, .c1-3, .c1-4, .c1-5, .c1-6, .c1-7, .c1-8, .c1-10,
              .c1-12, .c2-10, .c3-3, .c3-8, .c4-5, .c4-6, .c6-3, .c6-5,
              .c7-6, .c8-4, .c8-5, .c9-3, .c9-4, .c10-3) {
    grid-column: 1 / span 12;
  }

  .jumplinks { justify-content: flex-start; margin-top: 28px; }

  .cards-3, .cards-4, .cards-2 { grid-template-columns: 1fr; }

  /* Untereinander statt einspaltiges Raster: die Kinder tragen selbst
     Spaltenklassen, und in einem Raster wirken die weiter -- die
     Ueberschriften bekamen dadurch 20 Pixel Kasten fuer 138 Pixel Text.
     Im Flexkasten ist grid-column wirkungslos, das Problem kann also
     nicht ueber eine vergessene Klasse zurueckkommen. */
  .rowline { display: flex; flex-direction: column; gap: 10px; padding: 22px 0; }
  .rowline .tag { text-align: left; }

  .infoblock { display: flex; flex-direction: column; gap: 14px; }

  .form-grid { grid-template-columns: 1fr; }
  .form-grid .span2 { grid-column: auto; }

  .textlinks { flex-wrap: wrap; gap: 18px; margin-top: 40px; }
}

/* Vier Verweise und der Sprachschalter brauchen neben der Wortmarke
   rund 300 Pixel Zeile -- unter 640 bleibt dafuer kein Platz. Dort
   treten Knopf und Klappmenue an ihre Stelle. Auf der Startseite ist
   es derselbe Knopf, der zur Stil-Strecke gehoert; er steht hier nur
   dauerhaft da statt erst im Kompaktzustand. */
@media (max-width: 640px) {
  .site-header .site-nav { display: none; }

  .site-header .burger {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
  }

  /* Zugeklappt aus dem Baum genommen und nicht bloss auf Deckkraft null
     gestellt: der Schleier ist feststehend und reicht bis an den oberen
     Rand, und Safari liest solche Flaechen auch bei Deckkraft null --
     er kaeme dem Streifen dazwischen, der die Leistenfarbe traegt. Eine
     Blende braucht er nicht, er ist nur die Flaeche zum Antippen. */
  .menu-schleier.is-an { display: block; opacity: 1; pointer-events: auto; }

  /* Bei offenem Menue nimmt die Zeile denselben Grund wie das Blatt
     darunter -- deckend statt durchscheinend, sonst schimmert der
     Inhalt durch die Zeile und das Blatt liest sich als zweite Flaeche.
     Die Kante gehoert dann ans Menue, nicht an die Zeile; sonst liegen
     zwei Haarlinien uebereinander. */
  .site-header.hat-menue-offen {
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-bottom-color: transparent;
  }

  /* Deckend statt durchscheinend: mit 96 Prozent schimmerte die
     Ueberschrift der Seite als Geist durch die Verweise. */
  .menu-panel {
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: 0 18px 30px -22px rgba(17, 17, 17, .3);
  }

  .menu-panel__inner {
    padding: 4px 24px 22px;
    gap: 0;
    align-items: stretch;
  }

  /* Zeilen statt einer Liste: ganze Breite, Haarlinie darunter, Pfeil
     am rechten Rand. Die 18 Pixel Polster machen jede Zeile 56 hoch --
     bequem fuer den Finger. */
  .menu-panel__inner a {
    display: block;
    padding: 18px 0;
    font-size: 21px;
    border-bottom: 1px solid var(--hairline);
  }

  .menu-panel__inner a:last-of-type { border-bottom: 0; }

  .menu-panel__inner .lang-switch {
    display: flex;
    margin-top: 14px;
  }
}

/* Unter 400 Pixeln passen Wortmarke und vier Verweise nicht mehr in eine
   Zeile -- gemessen fehlten bei 320 Pixeln drei, und die Kopfzeile zog
   einen Seitenlauf nach sich. Der Kopf bricht darum um, die Verweise
   ruecken unter die Wortmarke. */
@media (max-width: 400px) {
  .site-header__inner { flex-wrap: wrap; row-gap: 10px; }
  .site-nav { gap: 16px; width: 100%; }
}

/* ---------- Cookie-Hinweis ----------
   Karte unten links, gleiche Sprache wie der Sprachhinweis-Streifen:
   Haarlinie, heller Grund, Schaltflaechen aus .btn / .btn-plain. */
/* Fade + Hover-Bewegung von/nach unten: gesteuert per .is-open-Klasse
   (siehe js/main.js), nicht per Keyframe-Animation, damit sich das
   Ein- UND Ausblenden abspielt (eine @keyframes-Animation liefe beim
   Schliessen nicht rueckwaerts ab). [hidden] greift erst, nachdem die
   Ausblend-Transition fertig ist. */
.cookie {
  position: fixed;
  left: 24px;
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  z-index: 40;
  width: min(400px, calc(100vw - 48px));
  padding: 26px 28px 24px;
  background: var(--bg);
  border: 1px solid var(--hairline-strong);
  box-shadow: 0 18px 44px rgba(17, 17, 17, .09);
  opacity: 0;
  /* 14 statt 28 Bildpunkte Anlauf: der Hinweis steht 24 ueber dem Rand,
     mit 28 Anlauf begann er 4 darunter -- und Safari 26 liest in diesem
     Augenblick seine Farbe fuer die Glasleiste und behaelt sie. */
  transform: translateY(14px);
  pointer-events: none;
  transition: opacity .32s var(--ease), transform .32s var(--ease);
}

.cookie.is-open {
  /* .99 statt 1, mit Absicht: Safari 26 liest fuer die Farbe seiner
     Glasleiste feststehende Elemente am unteren Rand -- den Hinweis
     eingeschlossen, sobald er offen ist; die Leiste wurde dann zum
     hellen Balken. Elemente mit einer Deckkraft unter 1 liest es nicht
     (andesco/safari-color-tinting). Ein Prozent sieht niemand. */
  opacity: .99;
  transform: none;
  pointer-events: auto;
}

.cookie[hidden] { display: none; }

.cookie__label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 18px;
}

/* Titelzeile: Beim Einblenden steht zuerst nur der Keks linksbuendig (auf
   20px vergroessert). Der Schriftzug COOKIES wird ab 0.85s fliessend
   revealt. Der Keks rollt ab 0.9s nach rechts an seinen Platz —
   dreht sich dabei und schrumpft auf 16px. Beides laeuft nur ueber
   transform/clip-path, das Layout (und damit der Abstand zum Text
   darunter) bleibt die ganze Zeit das des Endzustands: 13px-Text neben
   16px-Keks. */
.cookie__label .label {
  position: relative;
  z-index: 0;
  font-size: 13px;
  letter-spacing: .02em;
  animation: cookie-titel-reveal .5s var(--ease) .85s both;
}

/* Der Keks liegt ueber dem Schriftzug: beim Rollen laeuft er darueber
   hinweg, nicht darunter durch. */
.cookie__label .icon {
  position: relative;
  z-index: 1;
  font-size: 16px;
  filter: grayscale(1) opacity(.55);
  animation: cookie-rollen .6s var(--ease) .9s both;
}

@keyframes cookie-titel-reveal {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* -66px ≈ Breite des Schriftzugs (13px, Versalien) plus gap — bringt den
   Keks an den linken Rand der Titelzeile. Bei geaenderter Schriftgroesse
   oder anderem Titeltext mit anpassen. 1.25 = 20px / 16px. */
@keyframes cookie-rollen {
  from { transform: translateX(-66px) translateY(0) scale(1.25) rotate(0deg); }
  to   { transform: translateX(0) translateY(-1px) scale(1) rotate(360deg); }
}

.cookie__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

.cookie__text a {
  border-bottom: 1px solid rgba(17, 17, 17, .3);
  padding-bottom: 1px;
}

.cookie__why {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 22px;
  background: none;
  border: none;
  padding: 0;
  font-size: 13px;
  text-align: left;
  color: var(--ink-4);
}

.cookie__why:hover { color: var(--ink-2); }

.cookie__why .ic {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}

.cookie__why-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .38s var(--ease);
}

.cookie__why-wrap > div { overflow: hidden; }

.cookie__why-text {
  margin: 0;
  padding-top: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-3);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .3s ease 0s,
              transform .38s var(--ease),
              padding-top .38s var(--ease);
}

.cookie__why-wrap.open { grid-template-rows: 1fr; }

.cookie__why-wrap.open .cookie__why-text {
  padding-top: 10px;
  opacity: 1;
  transform: none;
}

.cookie__actions {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-top: 22px;
}

@media (max-width: 640px) {
  .cookie {
    left: 16px;
    right: 16px;
    bottom: 16px;
    width: auto;
    padding: 22px 20px 20px;
  }

  .cookie__actions { gap: 18px; }
}

/* Bildlauf neben einer Seitenueberschrift ------------------------------
   Quadratisch angelegt, weil die Quelle quadratisch ist; das feste
   Seitenverhaeltnis haelt die Flaeche schon vor dem Laden frei, damit die
   Ueberschrift daneben nicht nachspringt. Auf schmalen Fenstern faellt er
   unter den Titel und wird flacher, sonst schoebe er den Text zu weit
   nach unten. */
.kopfvideo {
  position: relative;
  margin: 0;
  align-self: start;
  /* Kein Grund und keine Rundung: der Lauf ist freigestellt und soll auf
     dem Papier stehen, nicht in einem Kasten. */
}

/* Das Standbild spannt die Flaeche auf; die Drehung liegt als
   Bilderfolge darueber und wird nur waehrend der Drehung eingeblendet.
   Im Ruhezustand steht also das scharfe Standbild da. */
.kopfvideo__standbild {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  /* contain statt cover: beschnitten wuerde hier nur die freigestellte
     Flaeche, aber bei abweichendem Verhaeltnis auch die Muenze. */
  object-fit: contain;
}

/* Die Bilderfolge: ein Blatt mit sechs mal sechs Einzelbildern einer
   ganzen Umdrehung, das erste ist der Ruhepunkt. Weitergeschaltet wird
   ueber background-position, je Einzelbild ein Fuenftel des Weges --
   bei sechsfacher Groesse laeuft der Weg von 0 auf 100 Prozent ueber
   fuenf Schritte je Richtung.

   Quadratisch und mittig statt inset: 0, weil die Flaeche auf mittleren
   Breiten 16 zu 9 flach ist -- ausgefuellt waeren die Einzelbilder dort
   in die Breite gezogen. Breite und Hoechsthoehe zusammen mit dem
   Seitenverhaeltnis wirken wie object-fit: contain. */
/* Auch die Leinwand, die js/main.js fuer das Video darueber legt: sie
   ist ein ersetztes Element mit eigenem Seitenverhaeltnis und wurde in
   die Breite gezogen, sobald die Flaeche nicht quadratisch war -- die
   Muenze sass dann als Ellipse da. */
.kopfvideo__leinwand,
.kopfvideo__lauf {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  max-height: 100%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Das Blatt selbst haengt js/main.js an -- und nur dort, wo die
   Bilderfolge auch dreht. Stand es hier, holte jeder Schreibtisch die
   377 Kilobyte, obwohl dort das Video laeuft. */
.kopfvideo__lauf {
  background-repeat: no-repeat;
  background-size: 600% 600%;
  background-position: 0% 0%;
  opacity: 0;
}

.kopfvideo.ist-am-drehen .kopfvideo__lauf { opacity: 1; }

/* Das Video am Schreibtisch: verborgen, bis js/main.js seinen Alphakanal
   bestaetigt hat (Klasse hat-alpha); gezeigt wird es dann ueber eine
   Leinwand, die das Skript daneben legt. Standbild und Bilderfolge
   treten in dem Fall zurueck. */
.kopfvideo video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
}

.kopfvideo.hat-alpha video { opacity: 1; }
.kopfvideo.hat-alpha .kopfvideo__standbild { visibility: hidden; }
.kopfvideo.hat-alpha .kopfvideo__lauf { display: none; }

/* Verborgen, nicht entfernt: das Bild haelt die Flaeche weiter auf. */
.kopfvideo.ist-am-drehen .kopfvideo__standbild { visibility: hidden; }

/* Unter 900 Pixeln nimmt die Flaeche die ganze Rasterbreite ein --
   quadratisch waere sie damit ueber 800 Pixel hoch. Darum begrenzt und
   rechts an die Textkante gestellt, statt wie zuvor auf 16 zu 9 flach
   gedrueckt: flach blieb die Muenze klein und verlor viel Luft, und die
   Leinwand darin liess sich nur mit Muehe davon abhalten, sich mit zu
   verziehen. Das Mass folgt der Bildhoehe, damit der Kopf auch in
   flachen Fenstern ganz ins Bild passt. */
@media (max-width: 960px) {
  .kopfvideo { grid-column: 1 / span 12; margin: 28px 0 0 auto; }
}


/* Fenster in Terminal-Optik --------------------------------------------
   Neben einer Seitenueberschrift. Nachgebaut, nicht abgebildet: reiner
   Text bleibt in jeder Groesse scharf, laesst sich vorlesen und wiegt
   nichts. Die Farben sind dieselben dunklen Toene wie in Stil 3, damit
   der Kasten nicht wie ein Fremdkoerper wirkt. */
.fenster {
  --fe-grund: #1c1c1f;
  --fe-leiste: #2b2b30;
  --fe-schrift: #e6e4df;
  --fe-leise: #8b8a85;
  --fe-gut: #7fb98a;
  margin: 0;
  align-self: start;
  border-radius: 11px;
  overflow: hidden;
  background: var(--fe-grund);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18), 0 12px 32px rgba(0, 0, 0, .16);
}

/* Titelleiste mit den drei Knoepfen links, Titel mittig — die Knoepfe
   nehmen Platz weg, darum bekommt der Titel rechts denselben Abstand
   noch einmal, sonst saesse er zu weit rechts. */
.fenster__leiste {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  background: var(--fe-leiste);
  border-bottom: 1px solid rgba(0, 0, 0, .3);
}

.fenster__ampel { display: flex; gap: 6px; }

.fenster__licht {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #4a4a50;
  transition: background-color 0.22s ease;
}

/* Das rote Licht ist ein Knopf und schliesst das Fenster; die beiden
   anderen bleiben Zier. Er soll dabei aussehen wie sie, darum den
   eigenen Knopfaufzug abstellen. Die Trefferflaeche wird ueber ein
   Pseudoelement auf ein antippbares Mass gebracht, ohne den Punkt zu
   vergroessern. */
button.fenster__licht {
  position: relative;
  padding: 0;
  border: 0;
  appearance: none;
  cursor: pointer;
}

button.fenster__licht::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
}

/* Ganz leichtes Kreuz beim Zeigen -- angedeutet, nicht gezeichnet: es
   soll den Punkt als Knopf lesbar machen, ohne die Ampel zu einem
   Bedienfeld zu machen. */
button.fenster__licht::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Gezeichnet und nicht gesetzt: als Schriftzeichen sass das Kreuz je
     nach Schrift etwas hoch oder seitlich, weil die Zeichenkaesten
     nicht mittig sind. Die beiden Striche liegen im viewBox genau um
     die Mitte, damit sitzt es auf dem Punkt. */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3.3 3.3l5.4 5.4M8.7 3.3l-5.4 5.4' stroke='%23111111' stroke-width='1.4' stroke-linecap='round' opacity='.55'/%3E%3C/svg%3E")
    center / 100% 100% no-repeat;
  opacity: 0;
  transition: opacity .18s ease;
}

button.fenster__licht:hover:not(:disabled)::before,
button.fenster__licht:focus-visible::before { opacity: 1; }

button.fenster__licht:hover:not(:disabled) { filter: brightness(1.12); }

button.fenster__licht:focus-visible {
  outline: 2px solid #e6e4df;
  outline-offset: 2px;
}

/* Solange die Regel fuer das rote Licht noch nicht getippt ist, gibt es
   den Knopf auch nicht: das Fenster hat ihn sich ja noch nicht selbst
   gefaerbt. */
button.fenster__licht:disabled { cursor: default; }

.fenster__licht--rot { background: #ec6a5f; }
.fenster__licht--gelb { background: #f4bf50; }
.fenster__licht--grün { background: #61c554; }

/* Grau: entweder noch ungefaerbt — js/main.js nimmt es weg, sobald die
   Regel dazu getippt ist — oder nicht mehr vorn, sobald das zweite
   Fenster aufgeht. Steht nach den Farbregeln, damit es sie
   ueberschreibt, ohne dass es !important braucht. */
.fenster__licht.ist-aus { background: #4a4a50; }

.fenster__titel {
  flex: 1;
  margin-right: 45px;          /* so breit wie die Ampel samt Abstand */
  text-align: center;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--fe-leise);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fenster__inhalt {
  margin: 0;
  /* Ein Terminal setzt seinen Text nicht an die Kante: mit Luft nach
     aussen liest sich der Kasten ruhiger. */
  padding: 22px 26px 26px;
  font-family: var(--mono);
  font-size: 12px;
  /* Enger als im Fliesstext: ein Terminal setzt seine Zeilen dicht, und
     mit weitem Abstand liest sich der Kasten wie eine Liste statt wie
     eine Ausgabe. */
  line-height: 1.6;
  color: var(--fe-schrift);
  /* Lange Zeilen scrollen im Kasten, statt ihn aufzuspannen. */
  overflow-x: auto;
}

.fenster__inhalt .z { display: block; }

/* Farben fuer die gezeigte CSS. Die Farbwerte stehen in ihrer eigenen
   Farbe da — so laesst sich im Text nachsehen, welcher Knopf woher
   kommt. */
.fenster__inhalt .sel { color: #d7a1c8; }
.fenster__inhalt .eig { color: #7aa2c4; }
.fenster__inhalt .satz { color: var(--fe-leise); }
.fenster__inhalt .wert--rot { color: #ec6a5f; }
.fenster__inhalt .wert--gelb { color: #f4bf50; }
.fenster__inhalt .wert--grün { color: #61c554; }

.fenster__inhalt .pfad { color: #7aa2c4; }
.fenster__inhalt .zeichen { color: var(--fe-leise); }
.fenster__inhalt .befehl { color: var(--fe-schrift); }
.fenster__inhalt .nr { color: var(--fe-leise); margin-right: 8px; }
.fenster__inhalt .gut { color: var(--fe-gut); margin-right: 6px; }
.fenster__inhalt .leise { color: var(--fe-leise); }

/* Leerzeilen zwischen den Bloecken: sie sollen trennen, aber keine ganze
   Zeile kosten. Als Block mit fester Hoehe brechen sie die Zeile selbst,
   darum steht hinter ihnen im Quelltext kein Zeilenumbruch mehr. */
.fenster__inhalt .luecke {
  display: block;
  height: 1.6em;
}

/* Sprunglinks im Kasten: sie stehen als Ausgabe des zweiten Befehls da.
   Weisser Grund, damit sie sich klar als anklickbar vom Code abheben;
   der Unterstrich bleibt und wird beim Zeigen kraeftiger. */
.fenster__inhalt .sprung {
  background: #ffffff;
  color: #1c1c1f;
  font-size: 16px;
  text-decoration: none;
  border-bottom: 1px solid rgba(28, 28, 31, 0.4);
  padding: 1px 5px;
}

.fenster__inhalt .sprung:hover,
.fenster__inhalt .sprung:focus-visible {
  border-bottom-color: currentColor;
}

/* Beim Zeigen rueckt der Pfeil in drei Schritten je ein Zeichen nach
   rechts und springt dann zurueck — wie ein Cursor, der weiterwandert.
   Der Platz dafuer ist fest reserviert, damit der zweite Link nicht
   mitwandert. */
.fenster__inhalt .sprung__pfeil {
  display: inline-block;
  width: 3ch;
}

.fenster__inhalt .sprung:hover .sprung__pfeil,
.fenster__inhalt .sprung:focus-visible .sprung__pfeil {
  animation: pfeil-ruecken 0.75s steps(1) infinite;
}

@keyframes pfeil-ruecken {
  0%   { transform: none; }
  33%  { transform: translateX(1ch); }
  66%  { transform: translateX(2ch); }
}

@media (prefers-reduced-motion: reduce) {
  .fenster__inhalt .sprung:hover .sprung__pfeil,
  .fenster__inhalt .sprung:focus-visible .sprung__pfeil { animation: none; }
}

/* Beim Aufbau werden die Zeilen nacheinander sichtbar. Verborgen wird
   ueber visibility und nicht ueber display: so steht die Hoehe des
   Kastens von Anfang an fest und der Titel daneben rutscht nicht. */
.fenster__inhalt[data-laeuft] [data-zeile] { visibility: hidden; }

/* Zwei Fenster uebereinander. Das zweite liegt versetzt darueber wie ein
   frisch geoeffnetes; der Stapel behaelt unten Luft, damit der Text
   darunter nicht angeschoben wird. */
.sec--head .grid { position: relative; }

/* Der Fliesstext neben dem Fensterstapel: seit der Stapel ausserhalb des
   Flusses steht, folgt er dicht auf die Ueberschrift. Etwas Abstand
   setzt ihn wieder auf die Hoehe des Fensters daneben. */
.lead--tief { margin-top: 120px; }

.fenster-stapel {
  /* Der Stapel steht ausserhalb des Flusses: so bestimmt die
     Ueberschrift allein, wie hoch die erste Rasterzeile wird, und der
     Fliesstext darunter rutscht hoch. Senkrecht sitzt er mittig
     zwischen der Unterkante der Navigation und der Trennlinie am Fuss
     des Seitenkopfs — die 12 Pixel gleichen aus, dass der Kopf oben 120
     und unten 96 Pixel Polster hat. Das Polster unten am Stapel gehoert
     zum zweiten Fenster, das so weit ueberhaengt. */
  position: absolute;
  /* Um 34 Pixel nach links gerueckt: das zweite Fenster liegt so weit
     versetzt und stiess sonst ueber die Inhaltskante hinaus. So endet
     der Stapel als Ganzes genau an ihr. */
  left: -34px;
  right: 34px;
  top: 50%;
  /* Mittig zwischen Unterkante der Navigation und Trennlinie am Fuss
     des Kopfs. Zwei Korrekturen stecken darin: minus 12, weil der Kopf
     oben 120 und unten 96 Pixel Polster hat, und plus 26 -- die Haelfte
     des Polsters unten, das den Ueberhang des zweiten Fensters
     aufnimmt. Ohne das zweite waere der Stapel um dieses halbe Polster
     zu hoch. */
  transform: translateY(calc(-50% - 12px + 26px));
  padding-bottom: 52px;
}

/* App-Starter vor dem Terminal ------------------------------------------
   Zu ist das Terminal nicht weg, sondern nur unsichtbar: die Fenster
   behalten ihren Platz im Stapel, damit beim Oeffnen nichts rutscht.
   Darueber liegt der Starter, mittig ueber der Flaeche des ersten
   Fensters -- die 52 Pixel unten sind das Polster, das den Ueberhang
   des zweiten Fensters aufnimmt und nicht zur Fensterflaeche gehoert. */
.fenster-stapel.ist-zu .fenster {
  opacity: 0;
  transform: scale(.94);
  pointer-events: none;
}

.fenster-stapel .fenster {
  transition: opacity .28s var(--ease), transform .28s var(--ease);
}

/* Aufgehen wie ein Programmfenster: aus der Mitte heraus, kurz ueber
   die Groesse hinaus und zurueck. Dieselbe Bewegung wie beim zweiten
   Fenster, hier fuer das erste. */
.fenster[data-fenster="eins"].ist-auf {
  animation: fenster-auf .34s cubic-bezier(.2, .9, .3, 1.2) backwards;
}

/* Der Knopf ist nur so gross wie Symbol und Beschriftung -- er liegt
   mittig auf der Fensterflaeche, deckt sie aber nicht ab: sonst faengt
   er Klicks weit neben dem Symbol. Die 26 Pixel sind die Haelfte des
   Polsters unten, das nicht zur Fensterflaeche gehoert. Verkleinert
   wird beim Start ueber scale und nicht ueber transform -- das
   transform haelt hier die Zentrierung. */
.app-start {
  position: absolute;
  left: 50%;
  top: calc(50% - 26px);
  transform: translate(-50%, -50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin: 0;
  padding: 6px 10px;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  transition: opacity .22s var(--ease), scale .22s var(--ease);
}

/* Die Kachel: dunkles Programmsymbol mit weicher Kante, wie auf einem
   Schreibtisch. Der Glanz oben ist ein flacher Verlauf, kein Bild. */
.app-start__kachel {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  border-radius: 22px;
  color: #7fb98a;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 52%),
    linear-gradient(165deg, #2b2b30, #1c1c1f);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .12),
    0 1px 2px rgba(17, 17, 17, .10),
    0 10px 22px -14px rgba(17, 17, 17, .24);
  transition: transform .22s var(--ease), box-shadow .22s var(--ease);
}

.app-start__kachel svg { width: 46px; height: 46px; }

/* Der Dateiname steht wie eine Beschriftung unter einem Programmsymbol
   auf dem Schreibtisch -- einzeilig, in der Schrift der Oberflaeche.

   Zur Schrift: -apple-system und BlinkMacSystemFont greifen auf Apple-
   Geraeten die eingebaute San Francisco ab, ohne dass die Seite eine
   Schriftdatei mitliefert. Genau so ist sie erlaubt: Apples Lizenz
   deckt die Nutzung der installierten Schrift auf Apple-Systemen, aber
   nicht das Weitergeben der Datei -- als Webfont eingebunden waere sie
   eine unerlaubte Verbreitung. Wer kein Apple-Geraet hat, bekommt die
   Oberflaechenschrift seines Systems (Segoe UI, Roboto) und damit
   dieselbe Wirkung. */
.app-start__name {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text',
               'Segoe UI', system-ui, Roboto, var(--font);
  font-size: 12.5px;
  letter-spacing: -.005em;
  color: var(--ink-3);
  text-wrap: nowrap;
}

.app-start:hover .app-start__kachel,
.app-start:focus-visible .app-start__kachel {
  transform: translateY(-3px) scale(1.03);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .14),
    0 1px 2px rgba(17, 17, 17, .10),
    0 14px 28px -14px rgba(17, 17, 17, .30);
}

.app-start:active .app-start__kachel { transform: translateY(0) scale(.97); }

.app-start:focus-visible { outline: none; }

.app-start:focus-visible .app-start__name {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Beim Start faellt der Starter in sich zusammen, waehrend das Fenster
   aufgeht -- beides gleichzeitig, darum die kurze Zeit. */
.app-start.ist-weg {
  opacity: 0;
  scale: .9;
  pointer-events: none;
}

.fenster--zwei {
  position: absolute;
  top: 52px;
  left: 34px;
  width: 100%;
  z-index: 1;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.34), 0 2px 6px rgba(0, 0, 0, 0.22);
}

/* Aufplopp: aus der Mitte heraus, kurz ueber die volle Groesse hinaus
   und zurueck — so oeffnen sich Fenster unter macOS. */
.fenster--zwei {
  opacity: 0;
  transform: scale(0.86);
  transform-origin: 50% 30%;
}

.fenster--zwei.ist-auf {
  animation: fenster-auf 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2) forwards;
}

@keyframes fenster-auf {
  from { opacity: 0; transform: scale(0.86); }
  to   { opacity: 1; transform: scale(1); }
}

/* Zugehen: gerader Weg zurueck, ohne das Ueberschwingen von oben. */
.fenster--zwei.ist-zu {
  animation: fenster-zu 0.24s ease-in forwards;
}

@keyframes fenster-zu {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.88); }
}

/* Der Hinweis, dass jetzt eine Taste dran ist. Er wird im Browser
   erzeugt und verschwindet beim ersten Tastendruck. */
.fenster__inhalt .hinweis {
  color: var(--fe-leise);
  animation: hinweis-atmen 1.4s ease-in-out infinite;
}

@keyframes hinweis-atmen {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.9; }
}

@media (prefers-reduced-motion: reduce) {
  .fenster--zwei.ist-auf { animation: none; opacity: 1; transform: none; }
  .fenster__inhalt .hinweis { animation: none; }
}
.fenster__inhalt [data-zeile].ist-da { visibility: visible; }

/* Blinkender Strich am Ende, wie er in einer Eingabezeile steht. */
.fenster__inhalt .strich {
  display: inline-block;
  width: 7px;
  height: 1.05em;
  vertical-align: -0.18em;
  background: var(--fe-schrift);
  animation: fenster-strich 1.1s steps(1) infinite;
}

/* Der Strich am Ende der Eingabe wird nach dem Tippen ueber das
   hidden-Attribut weggenommen. Ohne diese Zeile bliebe er stehen: die
   Regel oben setzt display auf inline-block und ist spezifischer als die
   eingebaute Regel des Browsers fuer hidden. */
.fenster__inhalt .strich[hidden] { display: none; }

@keyframes fenster-strich {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .fenster__inhalt .strich { animation: none; }
}

/* Auf schmalen Fenstern unter den Titel, wo er die ganze Breite hat.
   Die Grenze ist dieselbe, bei der die Spalten zusammenfallen (960):
   bei 900 blieb ein Band dazwischen, in dem die Ueberschrift schon die
   ganze Breite nahm, der Stapel aber noch frei darueber schwebte -- er
   lag dann auf der Ueberschrift. */
@media (max-width: 960px) {
  /* Schmal steht der Stapel ueber die volle Breite, und das zweite
     Fenster legt sich genau ueber das erste statt versetzt daneben —
     versetzt wuerde es seitlich aus der Seite ragen. */
  .fenster-stapel {
    grid-column: 1 / span 12;
    /* Im Fluss braucht das Fenster oben Luft zur Ueberschrift; unten
       hat es sie schon vom tiefen Vorspann. */
    margin-top: 56px;
    position: relative;
    left: auto;
    right: auto;
    top: 0;
    transform: none;
    padding-bottom: 0;
  }
  .fenster--zwei { top: 0; left: 0; }
  /* Ohne das Polster unten liegt die Mitte des Fensters auch in der
     Mitte des Stapels. */
  .app-start { top: 50%; }

  /* Zu nimmt der Stapel nur die Hoehe des Symbols mit etwas Luft: im
     Fluss stuende sonst eine leere Flaeche in Terminalgroesse ueber dem
     Vorspann. Die Fenster gehen dafuer aus dem Fluss -- gaenzlich
     ausbauen wuerde beim Oeffnen springen, weil ihre Hoehe erst nach
     dem Einbau feststeht. Beim Oeffnen und Schliessen faehrt die Hoehe
     zwischen beiden Staenden; die Werte setzt js/main.js, weil nur dort
     die Zielhoehe messbar ist. */
  .fenster-stapel.ist-zu {
    margin-top: 24px !important;
    height: 170px;
  }

  .fenster-stapel.ist-zu > .fenster {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
  }

  /* Waehrend das Fenster wachsend gezeigt wird, darf die Regel fuer den
     geschlossenen Zustand nicht dazwischenreden. Die Bewegung selbst
     laeuft ueber die Animations-Schnittstelle in js/main.js: als
     Klassenwechsel nahm der Browser den zuletzt gezeigten Wert als
     Anfang, und das Fenster wuchs von 0.94 statt von 0.16 -- also
     praktisch gar nicht. */
  .fenster-stapel.ist-zu > .fenster.laeuft-an { opacity: 1; }
}
