/* ===== Fonts ===== */
@font-face {
  font-family: "Instrument Sans";
  src: url("../assets/fonts/instrument-sans-variable.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../assets/fonts/jetbrains-mono-variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* ===== Design Tokens ===== */
/* Größen, Abstände, Zeilenlängen und Bewegung laufen ausschließlich über die
   Tokens in diesem Block. Keine neuen Einzelwerte im restlichen Stylesheet:
   Unterschiede, die niemand sehen kann, sind keine Entscheidungen. */
:root {
  --font-sans: "Instrument Sans", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
  --bg: #0d0e10;
  --bg-raised: #16181c;
  --bg-raised-2: #1e2126;
  --card-bg: rgba(238, 240, 242, 0.035);
  --card-border: #2b2f35;
  --text: #eef0f2;
  --text-dim: #8b9199;
  --text-faint: #888f9a;
  --accent: #a78bfa;
  --accent-strong: #6d28d9;
  --accent-ink: #0d0e10;
  --accent-soft: rgba(167, 139, 250, 0.12);
  --line: #2b2f35;
  --line-strong: #3a4048;
  --radius: 5px;
  --error: #f87171;

  /* Zeilenlänge. Ab etwa 75 Zeichen verliert das Auge beim Zeilensprung den
     Anschluss, was sich als "anstrengender Text" bemerkbar macht. */
  --measure-tight: 42ch; /* Überschriften, kurze Ledes */
  --measure-title: 55ch; /* zentrierte Titelkarte, siehe D.5 */
  --measure: 65ch;       /* Fließtext, Standard */
  --measure-wide: 75ch;  /* absolute Obergrenze */

  /* Typografische Staffel */
  --fs-2xs: 0.75rem;    /* Kicker, Labels, Badges */
  --fs-xs: 0.8125rem;   /* Fußnoten, Hilfstexte */
  --fs-sm: 0.875rem;    /* Listen und Text in Karten */
  --fs-base: 1rem;      /* Fließtext, Formularfelder */
  --fs-md: 1.125rem;    /* Lede, Kartenüberschriften */
  --fs-lg: 1.375rem;    /* H3 */
  --fs-xl: clamp(1.6rem, 3vw, 2.2rem); /* H2 */
  --fs-2xl: clamp(2.2rem, 6vw, 3.4rem); /* H1 */

  --lh-tight: 1.1;   /* große Headlines */
  --lh-snug: 1.3;    /* kleinere Überschriften */
  --lh-normal: 1.6;  /* Fließtext */

  /* Abstandsstaffel */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-9: 96px;

  /* Bewegung. Dauern nach design-library/animation-rules.md, Abschnitt
     "Dauern". Die Anker dort: unter 100ms wirkt eine Reaktion unmittelbar,
     ab 400ms bricht das Gefühl direkter Kontrolle, ab 1s reißt der
     Gedankenfluss. Raus ist rund 30 Prozent kürzer als rein. */
  --dur-fast: 150ms;       /* Hover, Fokus, Buttons (150–250) */
  --dur-nav: 220ms;        /* Navigation beim Scrollen */
  --dur-panel: 300ms;      /* Akkordeon auf (250–350) */
  --dur-panel-out: 200ms;  /* Akkordeon zu, 30 Prozent kürzer */
  --dur-media: 450ms;      /* Bildzoom auf Referenzkarten */
  --dur-reveal: 600ms;     /* Section-Reveal, hier der Ablauf-Stagger (500–700) */
  --dur-hero: 900ms;       /* Hero- und Bild-Reveal (700–1000) */
  --dur-spin: 700ms;       /* Dauerschleife des Lade-Spinners */
  --stagger: 70ms;         /* Versatz zwischen gestaffelten Elementen */
  /* Hausvorgabe für Reveals und Panels, damit die Seite eine Handschrift
     hat statt fünf. Niemals ease-in für etwas, das hereinkommt. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-inout: cubic-bezier(0.4, 0, 0.2, 1);

  /* Bauteilmaße. Bewusst getrennt von der Abstandsstaffel: das sind
     Eigengrößen von Elementen, keine Abstände zwischen ihnen. Hier stehen
     nur die Werte, die mehrfach vorkommen oder eine Regel abbilden.
     Einmalige Zeichenmaße (Icongrößen, SVG-Kantenlängen) bleiben als
     Literal an ihrer Stelle stehen, dafür lohnt kein Token. */
  --wrap-max: 1240px;  /* Breite der Inhaltsspalte */
  --nav-h: 60px;       /* Sticky-Nav, auch für scroll-margin-top und das Mobil-Menü */
  --nav-h-scrolled: 52px; /* dieselbe Nav ab 40px Scrollposition */
  --tap: 44px;         /* Mindestgröße einer Klickfläche auf Touchgeräten */
}

.grad-text {
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  /* Grundzeilenhöhe für alles, was keine eigene bekommt. Ohne diese Zeile
     fallen rund 60 Elemente auf den Browser-Standard `normal` zurück, und
     das ist faktisch eine vierte, ungesteuerte Zeilenhöhe. Betroffen waren
     unter anderem der Hero-Kicker und die Vertrauenszeile darunter, beide
     mehrzeilig. */
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}


a {
  color: inherit;
}

h1, h2, h3, h4 {
  font-family: inherit;
  font-weight: 400;
  line-height: var(--lh-snug);
  letter-spacing: -0.02em;
  margin: 0;
}

/* Display-Ebene: H1 und H2 stehen in Instrument Sans Bold, H3 und H4 bleiben
   bei 400. Ausgewählt über design/font-test.html aus acht Kandidaten.
   Ergebnis der Prüfung: keine zusätzliche Schriftdatei. Instrument Sans liegt
   ohnehin als Variable Font mit der Achse 300 bis 700 vor, das Gewicht 700
   kostet also kein einziges Byte mehr.
   Die zwei Kandidaten von Fontshare (Clash Display, Cabinet Grotesk) schieden
   zusätzlich aus Lizenzgründen aus, siehe design/fonts/LICENSE-fontshare-itf-ffl.txt */
h1,
h2,
.display {
  font-weight: 700;
}

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

.display {
  letter-spacing: -0.03em;
  line-height: var(--lh-tight);
  text-wrap: balance;
}

.display em,
.display .accent {
  font-style: normal;
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 500;
  max-width: var(--measure-wide);
  text-wrap: balance;
}

.wrap {
  max-width: var(--wrap-max);
  margin: 0 auto;
  padding: 0 var(--sp-6);
}

/* Sprunglink zum Hauptinhalt. Sitzt als erstes Element im Body und wird
   erst bei Tastaturfokus sichtbar. */
.skip-link {
  position: absolute;
  left: var(--sp-6);
  top: 0;
  z-index: 30;
  transform: translateY(-150%);
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--sp-5);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 var(--radius) var(--radius);
}
.skip-link:focus-visible {
  transform: translateY(0);
}

/* ===== Nav ===== */
nav.top {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  transition: background-color var(--dur-nav) var(--ease-inout);
}
/* Ab 40px Scrollposition: Hintergrund dichter, Nav etwas flacher. Die
   Transparenz mit Blur bleibt, sie ist Teil des Designs.
   Die Höhenänderung wird bewusst NICHT animiert: `height` löst Layout aus
   und steht im Hausregelwerk auf der Verbotsliste. Der Wechsel schaltet
   also hart, die Hintergrunddichte blendet über. Bei 8px Unterschied fällt
   das nicht auf, und es kostet keinen einzigen Layout-Durchlauf. */
nav.top.is-scrolled {
  background: color-mix(in srgb, var(--bg) 96%, transparent);
}
nav.top .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--nav-h);
}
nav.top.is-scrolled .wrap {
  height: var(--nav-h-scrolled);
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  color: inherit;
  text-decoration: none;
}
.brand .mark {
  width: 22px;
  height: 14px;
  position: relative;
  flex: none;
}
.brand .mark::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 60%;
  height: 1.5px;
  background: var(--text-faint);
}
.brand .mark::after {
  content: "";
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-faint);
  left: 15px;
  top: calc(60% - 2px);
}
.brand .word {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.brand .word b {
  font-weight: 700;
}
.navlinks {
  display: flex;
  gap: var(--sp-5);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}
/* Der Umbruch auf das Burger-Menü liegt bei 760px, Tablets in Hochkant
   sind breiter. Die Links müssen also auch als Touchziel taugen: 44px
   Höhe über die Klickfläche, ohne dass die Nav höher wird. */
.navlinks a {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  color: inherit;
  text-decoration: none;
}
.navlinks a {
  transition: color var(--dur-fast) var(--ease-out);
}
/* Aktiver Abschnitt. Nicht nur über Farbe: der Punkt darunter trägt die
   Information ein zweites Mal. */
.navlinks a.is-active {
  color: var(--text);
}
.navlinks a.is-active::after {
  content: "";
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--accent);
}
.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.nav-toggle {
  display: none;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text);
  width: var(--tap);
  height: var(--tap);
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after {
  content: "";
  display: block;
  width: 16px;
  height: 1.5px;
  background: var(--text);
  position: relative;
  transition: transform var(--dur-nav) var(--ease-inout), opacity var(--dur-nav) var(--ease-inout);
}
.nav-toggle span::before {
  position: absolute;
  top: -5px;
}
.nav-toggle span::after {
  position: absolute;
  top: 5px;
}

/* Der Fokusring wird bewusst nicht animiert: er muss sofort da sein,
   sobald der Fokus umspringt. outline steht deshalb in keiner
   transition-Liste im Stylesheet. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* min-height 44px: Mindestgröße für Klickflächen auf Touchgeräten. Gilt
   auch für .btn.small, das sonst auf rund 34px käme. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  position: relative;
  background: linear-gradient(160deg, rgba(167, 139, 250, 0.62), rgba(109, 40, 217, 0.42));
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  color: #fff;
  font-weight: 500;
  font-size: var(--fs-sm);
  /* Formularelemente erben die Zeilenhöhe nicht vom body, der
     Browser-Standard setzt sie auf `normal`. Hier explizit nachziehen. */
  line-height: var(--lh-normal);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius);
  text-decoration: none;
  border: 1px solid rgba(255, 255, 255, 0.28);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    inset 0 -8px 16px -10px rgba(0, 0, 0, 0.25),
    0 10px 28px -12px rgba(109, 40, 217, 0.5);
  white-space: nowrap;
}
/* Ohne width/height im Markup rendert ein inline-SVG mit 300 × 150 px. Die
   Größe hier setzen statt an jeder Fundstelle, sonst sprengt das erste Icon
   im ersten Button die Zeile. */
.btn svg {
  width: 16px;
  height: 16px;
  flex: none;
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.btn.ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--line-strong);
}
.btn.small {
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-xs);
}
/* The sticky-nav CTA carries the full sentence on desktop. On mobile the
   long label, the wordmark and the burger together overflow the usable
   width and push the wordmark onto two lines, so a short label takes
   over there. */
.nav-cta-short {
  display: none;
}

/* ===== Hero ===== */
header.hero {
  position: relative;
  z-index: 1;
  padding: var(--sp-9) 0;
}
/* Seit 16.08.2026 bekommt die Bildspalte die groessere Haelfte. Vorher lag
   das Verhaeltnis bei 1.1 zu 0.9 zugunsten des Textes, das passte zu einer
   Textspalte mit Subline. Die ist raus, der Text braucht die Breite nicht
   mehr, und das Bild ist ohne Rahmen der Beleg auf dem ersten Bildschirm. */
header.hero .grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: var(--sp-8);
  align-items: center;
}
header.hero h1 {
  font-size: var(--fs-2xl);
  margin: var(--sp-5) 0 var(--sp-6);
}
header.hero .lede {
  font-size: var(--fs-md);
  color: var(--text-dim);
  max-width: var(--measure-tight);
  line-height: var(--lh-normal);
  margin: 0 0 var(--sp-6);
}
.hero-visual-col {
  display: flex;
  flex-direction: column;
}
header.hero .hero-visual-col .hero-experience {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  margin: var(--sp-5) 0 0;
}
header.hero .hero-experience svg {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  color: var(--text-faint);
}
header.hero .cta-row {
  display: flex;
  gap: var(--sp-4);
  align-items: center;
  flex-wrap: wrap;
}
header.hero .cta-note {
  font-size: var(--fs-xs);
  color: var(--text-faint);
  margin-top: var(--sp-4);
  max-width: var(--measure);
}

.hero-visual {
  position: relative;
  /* Der Bodenabstand von 11% hielt Platz fuer das ueberlappende
     Portraet-Badge frei. Das Badge ist raus, der Platz damit auch. Der
     Rechtsabstand von 6% hielt die Collage von der Rahmenkante weg. Auch
     der Rahmen ist raus, damit faellt der letzte Grund weg, das Bild
     schmaler zu machen als seine Spalte. */
}
/* Freischwebend seit 16.08.2026: keine Flaeche, kein Rahmen, kein
   Innenabstand. Laptop und Handy stehen direkt auf dem Seitenhintergrund.

   Das geht nur, weil die Collage einen echten Alphakanal hat, geprueft:
   mode=RGBA, Eckpixel (0,0,0,0). Bei einem Bild mit weisser oder dunkler
   Vollflaeche wuerde stattdessen ein Rechteck sichtbar, und dann waere der
   Rahmen die ehrlichere Loesung.

   Die feste aspect-ratio faellt damit ebenfalls weg: sie diente dem Kasten.
   Das Bild bringt sein Verhaeltnis ueber width/height selbst mit, der Platz
   wird also weiterhin vorab reserviert und es gibt keinen Layoutsprung. */
.hero-visual-main {
  position: relative;
}
.hero-visual-main img {
  width: 100%;
  height: auto;
  display: block;
}
/* ===== Sections (shared) ===== */
section,
header.hero {
  scroll-margin-top: var(--nav-h);
}
/* Sektionsabstand als eine Regel: --sp-9 ab Tablet, --sp-8 darunter
   (siehe Media Query am Dateiende). */
section {
  padding: var(--sp-9) 0;
  opacity: 1;
}
main section:nth-of-type(even) {
  background: var(--bg-raised);
}
section.tight {
  padding: var(--sp-8) 0;
}
/* Zentrierte Titelkarte je Sektion, linksbündiger Inhalt darunter.
   Zentriert wird nur, was überflogen wird und aus wenigen Zeilen besteht:
   Kicker, Überschrift, Einleitungssatz. Alles, was gelesen wird, bleibt
   links (siehe .prose, Karten, Tabellen, FAQ, Formular).
   Die Breitenbegrenzung ist Pflicht, nicht Kosmetik: ohne sie liefe der
   zentrierte Text bis zum Containerrand und wirkte verloren. Sie hält die
   Titelkarte außerdem deutlich schmaler als den Inhalt darunter, sonst
   wirkt die Stufe zwischen beiden wie ein Fehler statt wie Absicht.
   Der Wechsel wird durch den großzügigen Abstand darunter zur Absicht. */
/* ===== Lila Schein hinter den Headlines =====
   Ein weicher Lichtfleck hinter H1 und H2, damit die Überschrift aus dem
   Dunkel heraustritt statt darauf zu liegen.

   **Als background-image auf der Überschrift selbst, bewusst nicht als
   Pseudo-Element.** Die erste Fassung war ein ::before mit position:absolute
   und z-index:-1. Damit ein negativer z-index nicht hinter dem Hintergrund
   der Sektion verschwindet (jede zweite Sektion hat einen, siehe
   main section:nth-of-type(even)), brauchte es isolation:isolate auf der
   Überschrift. Genau das war der Fehler: isolation erzeugt einen
   Stacking-Kontext, die Überschrift wandert damit in die Ebene der
   positionierten Elemente und ihr Schein legte sich sichtbar über
   nachfolgende Karten.

   Ein Hintergrundbild wird am Rand der eigenen Box abgeschnitten. Es kann
   deshalb gar nicht über Nachbarelemente laufen, egal wie die Ebenen liegen.
   Der Verlauf ist so gesetzt, dass er lange vor der Kante ausgelaufen ist,
   sonst sähe man die Schnittkante.

   **Fassung drei, und diesmal stimmt die Ebenenlogik.** Als Hintergrundbild
   endete der Schein zwangsläufig an der Box der Überschrift. Bei einer
   einzeiligen H2 sind das 46 Pixel, der Verlauf wurde oben und unten hart
   abgeschnitten und sah aus wie ein Balken.

   Jetzt wieder ein Pseudo-Element, das über die Box hinausragen darf. Der
   Fehler von Fassung eins war nicht das Pseudo-Element, sondern **wo der
   Stacking-Kontext saß.** Damals lag er per isolation auf der Überschrift,
   die damit in die Ebene der positionierten Elemente rutschte und ihren
   Schein über nachfolgende Karten legte.

   Jetzt sitzt er eine Ebene höher, auf der Sektion:

   - `main section` und `.page-head` bekommen isolation. Damit ist die
     Sektion der Bezugsrahmen, und ein z-index: -1 darin landet **über** dem
     Sektionshintergrund, aber **unter** allem, was in der Sektion im Fluss
     steht, also unter allen Karten.
   - Die Überschrift bekommt nur position: relative, ausdrücklich **kein**
     z-index und **kein** isolation. Sonst entstünde wieder ein eigener
     Kontext und der Fehler von Fassung eins wäre zurück.
   - `header.hero` hat mit z-index: 1 längst einen eigenen Kontext, dort
     greift dasselbe ohne Zutun.

   Die Höhe steht in em, nicht in Prozent: Prozent bezieht sich auf die
   Boxhöhe, und die ist bei der H1 fünfmal so groß wie bei einer H2. In em
   skaliert der Schein mit der Schriftgröße und wirkt auf beiden gleich. */
main section,
.page-head {
  position: relative;
  isolation: isolate;
}
.display,
.section-head h2,
.page-head h1 {
  position: relative;
}
.display::before,
.section-head h2::before,
.page-head h1::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 130%;
  max-width: 820px;
  height: 5.5em;
  transform: translate(-50%, -50%);
  background: radial-gradient(
    ellipse at center,
    color-mix(in srgb, var(--accent) 18%, transparent) 0%,
    transparent 70%
  );
  pointer-events: none;
}

.section-head {
  margin: 0 auto var(--sp-7);
  max-width: var(--measure-title);
  text-align: center;
}
.section-head h2 {
  font-size: var(--fs-xl);
  margin: var(--sp-2) 0 0;
  /* Gleichmäßige Umbrüche statt eines einzelnen Wortes in der letzten
     Zeile. Genau das trennt sauber zentriert von zufällig zentriert. */
  text-wrap: balance;
}
.section-head .eyebrow {
  max-width: none;
}

/* ===== Bewegung =====
   Auf der ganzen Seite gibt es genau ZWEI bewegte Momente, dazu
   funktionales Feedback (Hover, Fokus, FAQ, Formular). Grundlage ist
   design-library/animation-rules.md: "Zwei bis drei bewegte Momente pro
   Seite, nicht elf." Jede Section mit demselben Fade-Up ist dort
   ausdrücklich als Anti-Muster geführt.

   Moment 1: Hero-Entrance, siehe unten.
   Moment 2: Portrait-Reveal per clip-path in "Über mich".
   Moment 3: Ablauf-Stagger entlang der sieben Schritte.

   Ohne Bewegung bleiben unter anderem Preise, Kontakt, Vergleichstabelle,
   beide Kontrastpaare, "Kennst du das?" und "Nach dem Launch". */

/* --- Moment 1: Hero-Entrance ---
   Läuft beim Laden, ohne JavaScript. Der Hero steht im sichtbaren Bereich,
   ein IntersectionObserver wäre hier nur Umweg.
   Wichtig: Startzustand und Animation stehen zusammen in EINER Regel mit
   `forwards`. Unter prefers-reduced-motion wird die Dauer auf 0.01ms
   gesetzt, nicht die Animation entfernt, damit der Endzustand trotzdem
   greift und nichts unsichtbar hängen bleibt. */
.is-entrance .eyebrow,
.is-entrance h1,
.is-entrance .lede,
.is-entrance .cta-row,
.is-entrance .cta-note,
.is-entrance .hero-visual,
.is-entrance .hero-experience {
  animation: hero-in var(--dur-hero) var(--ease-out) both;
}
.is-entrance h1 { animation-delay: 60ms; }
.is-entrance .lede { animation-delay: 120ms; }
.is-entrance .cta-row { animation-delay: 180ms; }
.is-entrance .cta-note { animation-delay: 240ms; }
.is-entrance .hero-visual { animation-delay: 120ms; }
.is-entrance .hero-experience { animation-delay: 300ms; }

@keyframes hero-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
}

/* --- Moment 2: Portrait-Reveal in "Über mich" ---
   Das Bild wird aufgedeckt statt eingeblendet. clip-path ist im
   Hausregelwerk als erlaubte Ausnahme neben transform und opacity
   ausgewiesen. Wirkt hochwertiger als ein Fade und kostet dasselbe.
   Der Startzustand hängt an `.can-reveal`, gesetzt von js/main.js. Ohne
   JavaScript ist das Bild schlicht da. */
.about-photo.can-reveal img {
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--dur-hero) var(--ease-out);
}
.about-photo.can-reveal.is-in img {
  clip-path: inset(0 0 0 0);
}

/* --- Moment 3: Ablauf-Stagger ---
   70ms Versatz. Das Regelwerk begrenzt Stagger auf fünf bis sechs
   Elemente, der Ablauf hat sieben Schritte. Deshalb bewegen sich nur die
   großen Ziffern, nicht die Textblöcke: sie sind laut Regelwerk ohnehin
   der Anker, und Fließtext, der erst beim Erreichen erscheint, kostet nur
   Lesezeit.
   Der versteckte Startzustand hängt an `.can-stagger`, und diese Klasse
   setzt js/main.js. Stünde `opacity: 0` unbedingt im CSS, blieben die
   Ziffern ohne JavaScript dauerhaft unsichtbar. */
.process-row.flow.can-stagger .step-mark {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--dur-reveal) var(--ease-out) var(--step-delay, 0ms),
    transform var(--dur-reveal) var(--ease-out) var(--step-delay, 0ms);
}
.process-row.flow.can-stagger.is-in .step-mark {
  opacity: 1;
  transform: none;
}
/* Ab dem fünften Schritt läuft der Versatz nicht weiter hoch, sonst wartet
   man am Ende der Liste sichtbar auf Inhalt. */
.process-step:nth-of-type(2) .step-mark { --step-delay: calc(var(--stagger) * 1); }
.process-step:nth-of-type(3) .step-mark { --step-delay: calc(var(--stagger) * 2); }
.process-step:nth-of-type(4) .step-mark { --step-delay: calc(var(--stagger) * 3); }
.process-step:nth-of-type(n + 5) .step-mark { --step-delay: calc(var(--stagger) * 4); }

/* ===== About ===== */
.section-lede {
  font-size: var(--fs-base);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
  margin: var(--sp-3) auto 0;
  /* Verhindert Schusterjungen im zentrierten Einleitungssatz. */
  text-wrap: pretty;
}
.fit-heading + .section-lede {
  margin-bottom: var(--sp-5);
}
/* Einleitungsabsatz, der zu lang zum Zentrieren ist. Steht linksbündig
   unter der Titelkarte, mit Abstand zum folgenden Inhalt. */
.section-intro {
  margin-bottom: var(--sp-6);
}

/* Schmale Lesespalte für die textlastigen Sektionen (Kennst du das?, Über
   mich, Texte). */
.prose {
  max-width: var(--measure);
}
.prose p {
  font-size: var(--fs-base);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  margin: 0 0 var(--sp-4);
}
.prose p:last-child {
  margin-bottom: 0;
}
.prose p.lead {
  font-size: var(--fs-md);
  color: var(--text);
}
/* Zentrierte Variante, bewusst schmaler als die linksbündige: --measure-title
   (55ch) statt --measure (65ch). Zentrierter Text hat keine feste linke Kante,
   das Auge sucht bei jedem Zeilenwechsel den Zeilenanfang neu. Kurze Zeilen
   halten diesen Weg kurz, deshalb ist die schmalere Spalte hier kein
   Schönheitsmaß, sondern der Grund, warum es überhaupt lesbar bleibt.
   Absätze auf höchstens drei Zeilen halten, siehe MASSNAHMEN-LAYOUT.md D.1. */
.prose.centered {
  max-width: var(--measure-title);
  margin-inline: auto;
  text-align: center;
  text-wrap: pretty;
}
/* Hervorhebungen im Fließtext tragen die Textfarbe statt der gedämpften.
   Fett allein trägt auf dunklem Grund zu wenig, um als Betonung zu lesen. */
.prose strong {
  color: var(--text);
  font-weight: 600;
}

/* Über mich: Portrait, Fließtext und die "Was das für dich heißt"-Karte. */
.about-grid {
  display: grid;
  grid-template-columns: 0.7fr 1.35fr 1fr;
  gap: var(--sp-6);
  align-items: start;
  margin-bottom: var(--sp-6);
}

/* Kurzfassung auf der Startseite: Foto plus vier Punkte, zweispaltig.
   Das Foto steht schmaler als in der Langfassung, es soll hier belegen und
   nicht dominieren. Der ausführliche Text liegt auf /ueber-mich.html. */
.about-short {
  display: grid;
  grid-template-columns: 0.55fr 1.45fr;
  gap: var(--sp-7);
  align-items: center;
  max-width: 900px;
  margin: 0 auto;
}
.about-short .about-photo {
  aspect-ratio: 3 / 4;
}
.about-short .about-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
}
.about-photo {
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg-raised-2);
}
.about-photo img {
  width: 100%;
  /* height: auto ist Pflicht, nicht Kosmetik: ohne sie gewinnt das
     height-Attribut aus dem Markup (1200) und aspect-ratio greift gar
     nicht, weil beide Achsen belegt sind. */
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center 20%;
  filter: grayscale(1);
}

/* Accent-tinted note block (Gründungsangebot, Pflege-Einordnung). */
.callout {
  padding: var(--sp-4) var(--sp-5);
  background: var(--accent-soft);
  border: 1px solid var(--card-border);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  margin: 0 0 var(--sp-6);
}
.callout p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.callout strong {
  color: var(--accent);
  font-weight: 600;
}
/* Gründungsangebot als sichtbares Badge, nicht als fett gesetztes Wort
   mitten im Fließtext. */
.callout .callout-badge {
  display: inline-block;
  margin: 0 0 var(--sp-3);
  padding: var(--sp-1) var(--sp-3);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  border-radius: 999px;
}

/* Full-width "In jedem Paket enthalten" band under the package cards. */
/* Bewusst ohne Fläche und ohne Rahmen. In #preise standen sechs Kacheln
   hintereinander, alle optisch gleich schwer. "In jedem Paket enthalten"
   ist aber keine Kachel, die man gegen die anderen abwägt, sondern eine
   Fußnote zu allen dreien. Ohne Kasten ordnet sie sich unter, statt als
   vierte Option mitzuspielen. */
.included {
  padding: var(--sp-5) 0 0;
  border-top: 1px solid var(--card-border);
  margin-bottom: var(--sp-6);
}
.included h3 {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 500;
  margin: 0 0 var(--sp-3);
}
/* "In jedem Paket enthalten": ab Tablet zweispaltig, darunter eine Spalte.
   Das Häkchen ist Dekoration, die Aussage steht im Listenpunkt selbst. */
.check-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3) var(--sp-5);
}
.check-grid li {
  position: relative;
  padding-left: var(--sp-5);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.check-grid li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: 700;
}

.stat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  /* Akzent bewusst nur auf den Icons, nicht auf der H2 darüber: färbt man
     Sektionsüberschriften mit, verliert die Hero-H1 ihren Sonderstatus. */
  color: var(--accent);
  margin-bottom: var(--sp-4);
}
.stat-icon svg {
  width: 20px;
  height: 20px;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
}
.stat-card {
  padding: var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
.stat-num {
  font-weight: 400;
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  margin: 0 0 var(--sp-2);
  letter-spacing: -0.01em;
}
.stat-label {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  margin: 0;
}

/* ===== USP ===== */
.fit-heading {
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 var(--sp-4);
}
.fit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
/* Three-up variant for the pricing packages and the care packages. */
.fit-grid.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}
/* Flex-Spalte, damit .pkg-foot bei unterschiedlich langen Bullet-Listen
   trotzdem auf einer Linie steht. */
.fit-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--sp-5) var(--sp-6);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
/* Highlighted package ("Meine Empfehlung" / the monthly care plan). */
.fit-card.is-recommended {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.pkg-badge {
  position: absolute;
  top: 0;
  right: var(--sp-5);
  transform: translateY(-50%);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  padding: var(--sp-1) var(--sp-3);
  border-radius: 999px;
  white-space: nowrap;
}
.pkg-for {
  font-weight: 600;
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  margin: 0 0 var(--sp-2);
}
.pkg-desc {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  margin: 0 0 var(--sp-3);
}
.pkg-desc:last-child {
  margin-bottom: 0;
}
/* Fußzeile der Paketkarte: Einordnung, keine Leistung. Steht deshalb
   abgesetzt unter den Bullets. */
.pkg-foot {
  margin: auto 0 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--card-border);
  font-size: var(--fs-xs);
  color: var(--text-faint);
  line-height: var(--lh-normal);
}
.fit-card h3 {
  font-size: var(--fs-lg);
  margin: var(--sp-2) 0 var(--sp-4);
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
}
.fit-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.fit-list li {
  position: relative;
  padding-left: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.fit-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.usp-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
}
.usp-card {
  padding: var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
.usp-card h3 {
  font-size: var(--fs-md);
  margin: 0 0 var(--sp-2);
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
}
.usp-card p {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  margin: 0;
}

/* ===== Vergleich: Baukasten gegen Carmis =====
   Semantisch bleibt es auf jeder Breite eine Tabelle mit <th scope="row">.
   Unterhalb Tablet wird jede Zeile zu einer eigenen Karte, siehe unten in
   der Media Query. Kein horizontales Scrollen, auch nicht als Notlösung. */
.vs-wrap {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  overflow: hidden;
}
.vs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.vs-table thead th {
  text-align: left;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--text-faint);
  width: 30%;
}
.vs-table tbody th {
  text-align: left;
  font-weight: 400;
  color: var(--text);
}
.vs-table th,
.vs-table td {
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--line);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  vertical-align: top;
}
.vs-table tbody tr:last-child th,
.vs-table tbody tr:last-child td {
  border-bottom: none;
}
/* Der jeweilige Vorteil. Trägt über Farbe UND Fettung, damit er auch in der
   Kartenansicht ohne Nebeneinander erkennbar bleibt. */
.vs-table .is-better {
  color: var(--accent);
  font-weight: 700;
}

/* Die Rechnung. Sie ist das eigentliche Argument und steht deshalb
   sichtbar unter der Tabelle, nicht in einer Fußnote. */
.vs-sum {
  margin: var(--sp-5) auto 0;
  padding: var(--sp-5);
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--text);
  line-height: var(--lh-normal);
  max-width: var(--measure);
  text-align: center;
  text-wrap: pretty;
}

/* Zwei Fließtextblöcke, bewusst schmaler als die Tabelle gesetzt, damit sie
   nicht wie eine Fortsetzung der Tabelle wirken. */
.vs-notes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-6);
  margin-top: var(--sp-7);
}
.vs-note {
  max-width: var(--measure);
}
.vs-note h3 {
  font-size: var(--fs-md);
  margin: 0 0 var(--sp-4);
}
.vs-note p {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
}
.vs-note p:last-child {
  margin-bottom: 0;
}
/* Fremde Aussage, klar als solche gekennzeichnet, mit Beleg. Das ist der
   Unterschied zwischen einer Behauptung und einem Zitat. */
.vs-quote {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-left: 2px solid var(--accent);
  background: var(--card-bg);
}
.vs-quote p {
  margin: 0;
  color: var(--text);
  font-style: italic;
}
.vs-quote cite {
  display: block;
  margin-top: var(--sp-2);
  font-size: var(--fs-2xs);
  font-style: normal;
  color: var(--text-faint);
}
.vs-quote cite a {
  color: inherit;
}

.vs-outro {
  margin: var(--sp-7) auto 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
  text-align: center;
  text-wrap: pretty;
}

/* Abschlussblock unter den Pflegepreisen. */
.exit-block {
  margin-top: var(--sp-6);
  padding: var(--sp-5) var(--sp-6);
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
}
.exit-block h3 {
  font-size: var(--fs-md);
  margin: 0 0 var(--sp-3);
}
.exit-block p {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--text);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.exit-block p:last-child {
  margin-bottom: 0;
}

/* ===== Kontrastpaare ("Von dir / Von mir", "Klare Ansage") =====
   Die Aussage darf nicht am Nebeneinander hängen: gestapelt auf dem Handy
   wären es sonst nur zwei Listen. Sie steckt deshalb im Symbol und in der
   Farbe des Listenpunkts plus in einer allein verständlichen Überschrift.
   Die Reihenfolge bleibt in beiden Layouts gleich: erst die Einschränkung,
   dann der Gewinn, damit der positive Teil zuletzt im Kopf bleibt. */
.contrast-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
}
.contrast-col {
  padding: var(--sp-5) var(--sp-6);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
.contrast-title {
  font-size: var(--fs-md);
  margin: 0 0 var(--sp-4);
}
.contrast-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.contrast-list li {
  position: relative;
  padding-left: var(--sp-5);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.contrast-list li::before {
  position: absolute;
  left: 0;
  font-weight: 700;
}
.contrast-list.is-cost li {
  color: var(--text-dim);
}
.contrast-list.is-cost li::before {
  content: "×";
  color: var(--text-faint);
}
.contrast-list.is-gain li {
  color: var(--text);
}
.contrast-list.is-gain li::before {
  content: "✓";
  color: var(--accent);
}
/* Abschlusszeile unter dem Kontrastpaar. Ein Satz, wird überflogen,
   darf deshalb zentriert stehen. Die Listen darüber bleiben links. */
.contrast-note {
  margin: var(--sp-5) auto 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
  text-align: center;
  text-wrap: pretty;
}

/* ===== Referenz ===== */
.ref-group {
  margin-top: var(--sp-7);
}
.ref-group:first-of-type {
  margin-top: 0;
}
.ref-group-heading {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--text-faint);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--sp-3);
  margin: 0 0 var(--sp-5);
}
.ref-group-heading span {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  font-size: var(--fs-xs);
  color: var(--text-faint);
}
.ref-card {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 0;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  overflow: hidden;
}
.ref-visual {
  position: relative;
  /* Bewusst --bg statt --bg-raised: die Gerätemockups haben eine fast
     schwarze Gehäusekante. Auf der helleren Kartenfläche zeichnete die sich
     als schwarzer Block ab, besonders an den abgerundeten Ecken. Über --bg
     verschwindet die Kante im Hintergrund und man sieht nur den Bildschirm.
     Gegengeprüft, indem die Mockups über beide Farben gerendert wurden. */
  background: var(--bg);
  aspect-ratio: 3 / 2;
  padding: var(--sp-3);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
}
.ref-visual img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  transition: transform var(--dur-media) var(--ease-out), filter var(--dur-media) var(--ease-out);
}
/* Das <picture> darf die Flex-Zentrierung nicht aushebeln, sonst hängt das
   Bild oben links statt in der Mitte des Containers. */
.ref-visual picture {
  display: contents;
}
/* Aufmacher einer Referenz-Detailseite: mobil kommt dort das Hochformat der
   Handy-Aufnahme, deshalb muss der Container mitdrehen. Die Grenze liegt auf
   derselben Breite wie die <source media>-Angabe im Markup, sonst steht das
   eine Format kurzzeitig im Rahmen des anderen. */
@media (max-width: 640px) {
  .ref-visual-hero {
    /* Exakt das Seitenverhältnis der Handy-Aufnahme (440 × 894), nicht ein
       gerundetes 3:4. object-fit: contain passt das Bild sonst an die
       kürzere Kante an: bei 3:4 wurde aus 302px Containerbreite ein 202px
       breites Bild, also wieder eine Briefmarke. Stimmt das Verhältnis,
       füllt das Bild den Rahmen ohne Balken. */
    aspect-ratio: 440 / 894;
  }
}
.ref-visual-hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: #fff;
  background: rgba(13, 14, 16, 0.35);
  opacity: 0;
  transition: opacity var(--dur-nav) var(--ease-out);
  pointer-events: none;
}
.ref-visual-hint svg {
  width: 16px;
  height: 16px;
}
.ref-visual:focus-visible .ref-visual-hint {
  opacity: 1;
}

.ref-copy {
  padding: var(--sp-6);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-3);
}
.ref-copy .eyebrow {
  color: var(--text-faint);
}
.ref-copy h3 {
  font-size: var(--fs-lg);
  margin: 0;
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
}
.ref-copy p {
  color: var(--text-dim);
  line-height: var(--lh-normal);
  font-size: var(--fs-sm);
  margin: 0;
  max-width: var(--measure);
}
.ref-meta {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}
.ref-meta-url {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3);
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.ref-meta-url svg {
  width: 12px;
  height: 12px;
  flex: none;
}
.ref-meta-tag {
  font-size: var(--fs-2xs);
  color: var(--text-faint);
  border: 1px solid var(--line-strong);
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius);
}
.ref-meta-tag.ref-meta-status {
  border-color: var(--line-strong);
}
.ref-meta-tag.ref-meta-status.live {
  background: var(--text);
  border-color: var(--text);
  color: var(--accent-ink);
  font-weight: 700;
}

.ref-quote {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-4);
  border-left: 2px solid var(--accent);
  font-size: var(--fs-sm);
  font-style: italic;
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}
.ref-quote cite {
  display: block;
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  font-style: normal;
  color: var(--text-faint);
}

/* ===== Leistungen ===== */
.price-logic-grid {
  margin-top: var(--sp-5);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
}
.price-logic {
  padding: var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
.price-logic h3 {
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 var(--sp-3);
  font-weight: 700;
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
}
.price-logic p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
}
.price-logic p.price-logic-note {
  margin-top: var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}
/* 30/70 als zweizeilige Tabelle statt als Absatz: der Prozentsatz und die
   Bedingung stehen dadurch nebeneinander statt hintereinander. */
.pay-table {
  width: 100%;
  border-collapse: collapse;
}
.pay-table th,
.pay-table td {
  text-align: left;
  vertical-align: baseline;
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  font-weight: 400;
}
.pay-table tr:last-child th,
.pay-table tr:last-child td {
  border-bottom: none;
}
.pay-table th {
  width: 4.5em;
  color: var(--accent);
  font-weight: 700;
  white-space: nowrap;
}
.pay-table td {
  color: var(--text-dim);
}

.budget-note {
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4) var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure);
}

/* ===== Prozess ===== */
.process-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-6);
}
/* The 7-step flow doesn't divide evenly into 3 columns. The 240px minimum
   caps it at 4 columns inside the 1240px wrap, so the steps break 4 + 3
   instead of a lopsided 5 + 2, and reflow to 1 column on narrow screens. */
.process-row.flow {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-5);
}
.process-step {
  padding: var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
}
.process-step .step-mark {
  display: block;
  font-weight: 400;
  font-size: var(--fs-xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  margin-bottom: var(--sp-3);
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.process-step h3 {
  font-size: var(--fs-md);
  margin: 0 0 var(--sp-2);
}
.process-step p {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  margin: 0;
  line-height: var(--lh-normal);
}
.process-step .process-time {
  margin-top: var(--sp-2);
  font-size: var(--fs-2xs);
  color: var(--accent);
  font-weight: 600;
}
/* Wiederholte Handlungsaufforderung: eine Zeile plus Button, kein Band.
   Steht am Ende von Ablauf, Referenzen und Preisen. */
.inline-cta {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  /* Zentriert statt an die Ränder geschoben. Umbricht auf schmalen
     Bildschirmen zu einer zentrierten Spalte. */
  justify-content: center;
  text-align: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
}
.inline-cta p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  max-width: var(--measure);
}

/* ===== FAQ ===== */
.faq-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.faq-item {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  overflow: hidden;
}
.faq-question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  background: none;
  border: none;
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  font-weight: 400;
  text-align: left;
  cursor: pointer;
}
.faq-question > span:first-child {
  max-width: var(--measure);
}
.faq-icon {
  flex-shrink: 0;
  position: relative;
  width: 16px;
  height: 16px;
}
.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  background: var(--text-faint);
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.faq-icon::before {
  width: 12px;
  height: 2px;
}
.faq-icon::after {
  width: 2px;
  height: 12px;
  transition: transform var(--dur-nav) var(--ease-inout);
}
.faq-question[aria-expanded="true"] .faq-icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
  opacity: 0;
}
/* Geschlossene Antworten tragen das hidden-Attribut, sind also weder
   sichtbar noch für Screenreader vorhanden. Das ersetzt die frühere
   Höhenanimation über grid-template-rows: die hielt die Antwort auf Höhe 0,
   ließ sie aber im Accessibility-Baum stehen, sodass Vorlesesoftware alle
   zwölf Antworten mitlas.
   Statt der Höhe wird jetzt beim Öffnen nur eingeblendet. Das läuft über
   eine Animation statt einer Transition, damit kein JavaScript auf
   transitionend warten muss. Unter prefers-reduced-motion greift die
   globale Regel am Dateiende und der Text erscheint einfach. */
/* Die Einblendung hängt an `.is-enhanced`, und diese Klasse setzt
   js/main.js. Ohne JavaScript sind alle zwölf Antworten offen, und sie
   sollen dann einfach dastehen statt beim Laden alle gleichzeitig
   aufzublenden. Nebeneffekt: ohne JavaScript gibt es keinen Zustand mehr,
   in dem eine Antwort auf opacity 0 warten könnte. */
.faq-list.is-enhanced .faq-answer:not([hidden]) {
  animation: faq-open var(--dur-panel) var(--ease-out);
}
@keyframes faq-open {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}
.faq-answer p {
  margin: 0;
  padding: 0 var(--sp-5) var(--sp-5);
  max-width: var(--measure);
  color: var(--text-dim);
  font-size: var(--fs-base);
  line-height: var(--lh-normal);
}

/* Die Überschrift trägt nur die Semantik, das Aussehen macht der Button. */
.faq-heading {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
}

/* Damit ein Direktlink auf eine Frage nicht unter der Sticky-Nav landet. */
.faq-item {
  scroll-margin-top: calc(var(--nav-h) + var(--sp-4));
}

/* ===== Kontakt ===== */
.contact-panel {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: var(--sp-7);
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: var(--sp-7);
}

/* ===== Platzhalter-Geräte neben dem Formular =====
   Zwei angedeutete Geräte aus reinem CSS, gestrichelte Kontur in der
   Akzentfarbe. Die gestrichelte Linie ist die eigentliche Aussage: hier
   ist noch nichts, hier könnte deins stehen. Eine durchgezogene Kontur
   sähe nach fertigem Produkt aus. */
.site-placeholder {
  position: relative;
  margin-top: var(--sp-6);
  max-width: 380px;
  padding-right: 12%;
}
.site-placeholder-laptop {
  position: relative;
}
.site-placeholder-screen {
  aspect-ratio: 16 / 10;
  border: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: var(--radius);
  background: var(--bg);
  display: grid;
  place-items: center;
  padding: var(--sp-4);
  text-align: center;
}
.site-placeholder-screen span {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--accent);
}
/* Standfuß, damit der Kasten als Laptop lesbar wird und nicht als Rahmen. */
.site-placeholder-base {
  display: block;
  width: 116%;
  height: 6px;
  margin: 5px 0 0 -8%;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--card-border);
}
.site-placeholder-phone {
  position: absolute;
  right: 0;
  bottom: 8%;
  width: 24%;
  aspect-ratio: 1 / 2;
  border: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: calc(var(--radius) * 1.6);
  background: var(--bg);
}
.contact-panel h2 {
  margin: var(--sp-2) 0;
  font-size: var(--fs-xl);
}
.contact-panel p {
  margin: 0;
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure-tight);
}
.contact-panel p + p {
  margin-top: var(--sp-3);
}
.contact-panel .note {
  margin-top: var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.field label {
  font-size: var(--fs-xs);
  color: var(--text-dim);
  font-weight: 600;
}
/* --fs-base ist hier Pflicht, nicht Geschmack: unter 16px zoomt iOS Safari
   beim Fokus ins Feld hinein. */
.field input,
.field textarea,
.field select {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text);
  font-size: var(--fs-base);
  font-family: inherit;
  line-height: var(--lh-normal);
  padding: var(--sp-3);
}
.field input,
.field select {
  min-height: var(--tap);
}
/* Beim Fokussieren scrollt der Browser das Feld in den Sichtbereich. Ohne
   diesen Abstand landet es unter der Sticky-Nav, auf dem Handy zusammen
   mit der eingeblendeten Tastatur die häufigste Stelle, an der ein Feld
   verdeckt wird. */
.field input,
.field textarea,
.field select {
  scroll-margin-top: calc(var(--nav-h) + var(--sp-4));
}
.field textarea {
  resize: vertical;
  min-height: 92px;
}
/* Der Rahmen wechselt bei Fokus die Farbe. Das outline darf dabei NICHT
   pauschal weg: .field input:focus ist spezifischer als die globale
   :focus-visible-Regel und hat den Fokusring vorher auch bei
   Tastaturbedienung geschluckt. Jetzt fällt er nur bei Mausklick weg. */
.field input:focus,
.field textarea:focus,
.field select:focus {
  border-color: var(--accent);
}
.field input:focus:not(:focus-visible),
.field textarea:focus:not(:focus-visible),
.field select:focus:not(:focus-visible) {
  outline: none;
}

/* Fehlerzustand. Rot allein reicht nicht: der Rahmen wechselt die Farbe,
   die Meldung steht als Klartext direkt unter dem betroffenen Feld und
   trägt zusätzlich ein Symbol. */
.field.has-error input,
.field.has-error textarea,
.field.has-error select {
  border-color: var(--error);
}
.field-error {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--error);
}
.field-error::before {
  content: "!";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15em;
  height: 1.15em;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-weight: 700;
  transform: translateY(0.15em);
}

/* Der Satz, der an der letzten Hürde steht, direkt über dem Absendeknopf. */
.form-reassure {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* Ladezustand des Absendeknopfs. Verhindert Doppelabsendungen. */
.btn-spinner {
  display: none;
  width: 0.9em;
  height: 0.9em;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: btn-spin var(--dur-spin) linear infinite;
}
.btn.is-busy .btn-spinner {
  display: inline-block;
}
@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Erfolgs- und Fehlermeldung des Formulars. Erscheint an Ort und Stelle,
   kein Seitenwechsel. Bekommt nach dem Absenden den Tastaturfokus. */
.form-status {
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--accent);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent-soft);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--text);
}
.form-status.is-error {
  border-color: var(--error);
  border-left-color: var(--error);
  background: rgba(248, 113, 113, 0.1);
}
.form-status:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.contact-form .row2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
}
.contact-form button.btn {
  align-self: flex-start;
  border: none;
  cursor: pointer;
  font-family: inherit;
  margin-top: var(--sp-1);
}
.form-privacy {
  font-size: var(--fs-2xs);
  color: var(--text-faint);
}
.form-privacy a {
  color: var(--text-dim);
}

/* ===== Footer ===== */
footer {
  padding: var(--sp-5) 0;
}
footer .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}
footer a {
  color: var(--text-faint);
  text-decoration: none;
}
footer .flinks {
  display: flex;
  gap: var(--sp-4);
}
/* Eigenständige Links, keine Links im Fließtext: brauchen 44px Klickfläche. */
footer .flinks a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

/* ===== Legal pages ===== */
/* ===== Sekundäraktion: Textlink mit einfahrendem Unterstrich =====
   Die zweite Ebene neben .btn. Überall dort, wo ein gekürzter Abschnitt auf
   seine Detailseite zeigt. Bewusst kein zweiter Kasten: zwei Buttons
   nebeneinander konkurrieren, ein Textlink ordnet sich unter und lässt dem
   eigentlichen CTA den Vortritt.

   Der Unterstrich fährt von links ein, dieselbe Bewegung wie bei den
   Textlinks im Fließtext. Umgesetzt über scaleX auf einem Pseudo-Element,
   nicht über width oder border: nur transform und opacity sind laut
   design-library/animation-rules.md erlaubt, alles andere löst Layout aus. */
.link-more {
  margin: var(--sp-6) 0 0;
  font-size: var(--fs-sm);
}
.link-more a,
a.link-more {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  position: relative;
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
}
.link-more a::after,
a.link-more::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 8px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-fast) var(--ease-out);
}
.link-more a:focus-visible::after,
a.link-more:focus-visible::after {
  transform: scaleX(1);
}
.link-more svg {
  width: 15px;
  height: 15px;
  flex: none;
  transition: transform var(--dur-fast) var(--ease-out);
}

/* ===== Kopf einer Unterseite =====
   Gegenstück zum Hero der Startseite, links ausgerichtet wie dieser, damit
   die Seiten als dieselbe Marke lesbar bleiben. Ein Button steht hier nur
   auf den Referenzseiten: dort ist die Live-Adresse des Kundenprojekts der
   eigentliche Beleg und gehört über den Falz, nicht in eine Fußzeile. Die
   übrigen Unterseiten tragen nur den Rücksprung. */
.page-head {
  padding: var(--sp-9) 0 var(--sp-7);
  border-bottom: 1px solid var(--card-border);
}
.page-head h1 {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: var(--lh-tight);
  margin: var(--sp-2) 0 var(--sp-4);
  max-width: var(--measure-tight);
}
.page-head .lede {
  max-width: var(--measure);
  color: var(--text-dim);
  font-size: var(--fs-md);
  margin: 0;
}
.page-head-back,
.page-head-actions {
  margin: var(--sp-5) 0 0;
  font-size: var(--fs-sm);
}
.page-head-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
}
/* Der Rücksprung ist auf einer Unterseite echte Navigation und muss deshalb
   die Mindest-Klickfläche einhalten. Gemessen auf 390px lag er vorher je nach
   Seite bei 17, 22 und 39px, also durchweg darunter: als reiner Inline-Link
   ist ein Link nur so hoch wie seine Zeile. inline-flex gibt ihm eine eigene
   Box, ohne dass er dabei über die Textbreite hinauswächst. */
.page-head-back a,
.page-head-actions a:not(.btn) {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

/* ===== Scroll-Videos auf den Referenz-Detailseiten =====
   Desktop- und Mobilaufnahme nebeneinander statt eine Fassung je Breite.
   Auf einer Fallstudie ist beides der Punkt: so sieht die Seite am Rechner
   aus, so am Telefon. Die Spalten sind nach dem Seitenverhältnis der Clips
   gewichtet, sonst steht das Hochkantvideo winzig neben dem Querformat. */
.media-pair {
  display: grid;
  grid-template-columns: 1.75fr 1fr;
  gap: var(--sp-6);
  align-items: end;
}
.media-video {
  position: relative;
  margin: 0;
  /* --bg statt einer helleren Fläche, gleiche Begründung wie bei
     .ref-visual: die Gehäusekante der Aufnahmen ist fast schwarz. */
  background: var(--bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: var(--sp-3);
  overflow: hidden;
}
.media-video video {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 3px;
}
.media-caption {
  margin: var(--sp-3) 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
/* Der Knopf liegt über der ganzen Fläche, damit ein Tipp irgendwo auf dem
   Video pausiert. Die Pille bleibt dauerhaft sichtbar: auf dem Handy gibt
   es keinen Hover, ein Hinweis der erst dabei erscheint ist keiner. */
.media-toggle {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  padding: var(--sp-4);
  background: none;
  border: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.media-toggle-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  padding: 0 var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid var(--card-border);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(6px);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.media-toggle svg {
  width: 15px;
  height: 15px;
  flex: none;
}
.media-toggle .icon-play {
  display: none;
}
.media-toggle.is-paused .icon-pause {
  display: none;
}
.media-toggle.is-paused .icon-play {
  display: block;
}
.media-toggle:focus-visible .media-toggle-pill {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ===== Messwerte auf einer Referenzseite =====
   Die Zahl trägt den Block, die Erläuterung steht klein darunter. Bewusst
   ohne Kacheln mit Fläche: sechs gerahmte Kästen nebeneinander lesen sich
   als Werbebanner, und der Punkt hier ist, dass die Zahlen nachprüfbar
   sind, nicht dass sie laut sind. */
.metric-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-6);
  margin: 0;
  border-top: 1px solid var(--card-border);
  padding-top: var(--sp-6);
}
/* Auf dem Handy fällt auto-fit knapp auf eine Spalte zurück: 2 × 150px plus
   32px Abstand sind 332px und damit mehr als die 326px Inhaltsbreite auf
   390px Geräten. Fünf gestapelte Werte sind aber gut ein ganzer Bildschirm,
   und einzeln untereinander verlieren die Zahlen genau das, was sie
   überzeugend macht: dass man sie als Block auf einen Blick erfasst.
   Zweispaltig erzwungen spart gemessen 217px (555 → 338), und die Labels
   passen weiterhin einzeilig in die 151px, „BARRIEREFREIHEIT" eingeschlossen. */
@media (max-width: 480px) {
  .metric-row {
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-5);
  }
}
.metric dt {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.metric dd {
  margin: var(--sp-2) 0 0;
}
.metric dd b {
  display: block;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--accent);
  line-height: 1.15;
}
.metric dd span {
  display: block;
  margin-top: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}
.metric-note {
  margin: var(--sp-6) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* ===== Faktenleiste auf einer Referenzseite ===== */
.fact-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-5);
  border-top: 1px solid var(--card-border);
  padding-top: var(--sp-5);
}
.fact-row dt {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.fact-row dd {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-md);
  color: var(--text);
}

@media (max-width: 760px) {
  .media-pair {
    grid-template-columns: 1fr;
    gap: var(--sp-5);
  }
}

/* ===== Themengruppen auf der Hilfeseite ===== */
.help-groups {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}
.help-group-title {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}
.help-group-lede {
  color: var(--text-dim);
  margin: var(--sp-2) 0 var(--sp-5);
  max-width: var(--measure);
}

@media (max-width: 760px) {
  .page-head {
    padding: var(--sp-8) 0 var(--sp-6);
  }
  .help-groups {
    gap: var(--sp-7);
  }
}

.legal-page {
  padding: var(--sp-8) 0;
  max-width: var(--measure-wide);
}
.legal-page h1 {
  font-size: var(--fs-xl);
  margin-bottom: var(--sp-5);
}
.legal-page h2 {
  font-size: var(--fs-lg);
  margin-top: var(--sp-6);
}
.legal-page p {
  color: var(--text-dim);
  line-height: var(--lh-normal);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ===== 404 ===== */
.error-page {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: var(--sp-8) 0;
}
.error-page h1 {
  font-size: var(--fs-2xl);
  line-height: var(--lh-tight);
  margin: var(--sp-4) 0;
}
.error-lede {
  font-size: var(--fs-md);
  color: var(--text-dim);
  line-height: var(--lh-normal);
  max-width: var(--measure-tight);
  margin: 0 0 var(--sp-6);
}
.error-page .cta-row {
  display: flex;
  gap: var(--sp-4);
  align-items: center;
  flex-wrap: wrap;
}

/* Der zweispaltige Hero wird zwischen 760 und 900px zu eng: die Textspalte
   ist dort nur noch rund 350px breit und die Headline bricht auf sechs
   Zeilen. Deshalb schon oberhalb des Mobil-Umbruchs einspaltig. */
@media (max-width: 900px) {
  header.hero .grid {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
}

@media (max-width: 760px) {
  /* Die kleinste Schriftstufe entfällt auf dem Handy und fällt mit --fs-xs
     zusammen. 12px trägt am Bildschirm eines Telefons nicht mehr, besonders
     nicht bei den Eyebrows: die stehen in Versalien, in einer Monospace und
     mit aufgezogener Laufweite, also in genau der Kombination, die klein am
     schlechtesten lesbar ist. Betrifft gemessen 38 Textelemente.
     Auf dem Desktop bleibt die Stufe erhalten, dort funktioniert sie. */
  :root {
    --fs-2xs: 0.8125rem;
  }

  /* Sektionsabstand eine Stufe kleiner, als eine Regel für alle Sektionen. */
  section {
    padding: var(--sp-8) 0;
  }
  section.tight {
    padding: var(--sp-7) 0;
  }
  .navlinks {
    display: none;
    position: absolute;
    top: var(--nav-h);
    left: 0;
    right: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    flex-direction: column;
    gap: 0;
    padding: var(--sp-2) 0;
  }
  .navlinks.is-open {
    display: flex;
  }
  .navlinks a {
    justify-content: flex-start;
    padding: var(--sp-3) var(--sp-6);
  }
  .nav-toggle {
    display: inline-flex;
  }
  .nav-cta-long {
    display: none;
  }
  .nav-cta-short {
    display: inline;
  }
  .brand .word {
    white-space: nowrap;
  }
  header.hero {
    padding: var(--sp-7) 0;
  }
  header.hero .grid {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
  /* Der Rechtsabstand von 9% ist am 16.08.2026 raus, gleiche Begruendung
     wie bei der Desktop-Regel: er hielt die Collage von der Rahmenkante
     weg, und der Rahmen ist weg. Er kostete mobil 29 von 326px Breite,
     also fast ein Zehntel des Bildes, ohne dass noch etwas da waere,
     wovon abgeruckt werden muesste. */
  /* Die vier Kacheln lagen hier bis August 2026 in einem horizontalen
     Slider. Rausgebaut, aus drei Gründen: der Inhalt sind Kernargumente
     und keine Beigabe, horizontales Wischen wird auf Seiten regelmäßig
     übersehen, und der Slider war per Tastatur gar nicht bedienbar (kein
     tabindex, Scrollleiste ausgeblendet, keine fokussierbaren Elemente in
     den Karten). Gestapelt kostet es rund 500px Scrollstrecke und löst
     alle drei Punkte auf einmal. */
  .stat-grid,
  .usp-grid {
    grid-template-columns: 1fr;
  }
  .price-logic-grid {
    grid-template-columns: 1fr;
  }
  .fit-grid,
  .fit-grid.cols-3 {
    grid-template-columns: 1fr;
  }
  .about-grid,
  .about-short {
    grid-template-columns: 1fr;
    gap: var(--sp-5);
  }
  /* Auf dem Handy steht das Foto über den Punkten und wird flacher, sonst
     füllt ein Hochkantbild allein den halben Bildschirm. */
  .about-short .about-photo {
    aspect-ratio: 4 / 3;
  }
  .contrast-pair,
  .check-grid,
  .vs-notes {
    grid-template-columns: 1fr;
  }

  /* Vergleichstabelle wird zur Kartenliste. Eine dreispaltige Tabelle ist
     auf 390px unlesbar, und horizontal scrollen soll sie ausdrücklich
     nicht. Jede Zeile wird eine Karte: Zeilenbeschriftung als Überschrift,
     darunter die beiden Werte untereinander, jeweils mit der
     Spaltenbezeichnung davor. Semantisch bleibt es eine Tabelle. */
  .vs-wrap {
    background: none;
    border: none;
    border-radius: 0;
    overflow: visible;
  }
  .vs-table,
  .vs-table tbody,
  .vs-table tbody tr,
  .vs-table tbody th,
  .vs-table tbody td {
    display: block;
    width: auto;
  }
  /* Die Spaltenköpfe stehen ab hier vor jedem Wert, die Kopfzeile selbst
     wird dadurch überflüssig. */
  .vs-table thead {
    display: none;
  }
  .vs-table tbody tr {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
    padding: var(--sp-4) var(--sp-5);
    margin-bottom: var(--sp-3);
  }
  .vs-table tbody tr:last-child {
    margin-bottom: 0;
  }
  .vs-table tbody th {
    padding: 0 0 var(--sp-3);
    border-bottom: 1px solid var(--line);
    margin-bottom: var(--sp-3);
    font-weight: 600;
  }
  .vs-table tbody td {
    padding: 0;
    border-bottom: none;
  }
  .vs-table tbody td + td {
    margin-top: var(--sp-2);
  }
  .vs-table tbody td::before {
    content: attr(data-col) ": ";
    color: var(--text-faint);
    font-weight: 400;
  }
  .vs-notes {
    gap: var(--sp-7);
  }
  /* Auf dem Handy scrollt man relativ zum Bildschirm schneller, lange
     Einblendungen wirken dort träge. */
  .fade-in,
  .slide-in {
    transition-duration: var(--dur-nav);
  }
  .ref-card {
    grid-template-columns: 1fr;
  }
  .process-row,
  .process-row.flow {
    grid-template-columns: 1fr;
  }
  .contact-panel {
    grid-template-columns: 1fr;
    padding: var(--sp-5);
    gap: var(--sp-6);
  }
  .contact-form .row2 {
    grid-template-columns: 1fr;
  }
}

/* ===== Hover =====
   Alle Hover-Regeln stehen gekapselt in (hover: hover). Auf Touchgeräten
   bleibt ein Hover-Zustand sonst nach dem Antippen kleben, bis man
   woanders hintippt.
   Die Listenpunkte in den Kontrastpaaren bekommen bewusst keinen Hover,
   sie sind nicht klickbar. */
@media (hover: hover) {
  .navlinks a:hover {
    color: var(--text);
  }

  /* Buttons hellen nur auf, sie heben sich nicht mehr an. Grund: das
     Abnahmekriterium verlangt für Preise und Kontakt "keinerlei Bewegung",
     und dort stehen die wichtigsten Buttons der Seite. Ein Aufhellen in
     150ms ist weiterhin eine spürbare Reaktion, verschiebt aber nichts.
     Deshalb steht `transform` auch nicht mehr in der transition-Liste. */
  .btn {
    transition:
      background var(--dur-fast) var(--ease-out),
      box-shadow var(--dur-fast) var(--ease-out),
      border-color var(--dur-fast) var(--ease-out),
      color var(--dur-fast) var(--ease-out);
  }
  .btn:hover {
    background: linear-gradient(160deg, rgba(167, 139, 250, 0.75), rgba(109, 40, 217, 0.55));
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.45),
      inset 0 -8px 16px -10px rgba(0, 0, 0, 0.25),
      0 14px 34px -12px rgba(109, 40, 217, 0.6);
  }
  .btn.ghost:hover {
    border-color: var(--accent);
    color: var(--accent);
  }

  /* Die Paketkarten hatten hier eine Hover-Anhebung. Raus, laut
     Hausregelwerk bekommen Preise gar keine Bewegung: "Hier wird
     gerechnet, nicht bewundert. Bewegung liest sich als Verkaufsdruck."
     Dasselbe gilt für die Pflegekarten unter "Nach dem Launch", das ist
     ebenfalls Preisinformation. */

  .ref-visual:hover img {
    transform: scale(1.04);
  }
  .ref-visual:hover .ref-visual-hint {
    opacity: 1;
  }
  .ref-meta-url:hover {
    color: var(--accent);
    border-color: var(--accent);
  }

  /* Sekundäraktion: Unterstrich fährt ein, Pfeil rückt nach. */
  .link-more a:hover::after,
  a.link-more:hover::after {
    transform: scaleX(1);
  }
  .link-more a:hover svg,
  a.link-more:hover svg {
    transform: translateX(3px);
  }
  .media-toggle:hover .media-toggle-pill {
    color: var(--accent);
    border-color: var(--accent);
  }

  /* Textlinks: die Unterstreichung fährt von links ein. */
  .prose a,
  .contact-panel .note a,
  .form-privacy a,
  .legal-page a,
  footer .flinks a {
    text-decoration: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 1px;
    transition: background-size var(--dur-nav) var(--ease-out), color var(--dur-fast) var(--ease-out);
  }
  .prose a:hover,
  .contact-panel .note a:hover,
  .form-privacy a:hover,
  .legal-page a:hover,
  footer .flinks a:hover {
    background-size: 100% 1px;
  }
  footer .flinks a:hover {
    color: var(--accent);
  }
}

/* Auf Touchgeräten bleibt die Unterstreichung dauerhaft sichtbar, sonst
   wäre dort gar nicht zu erkennen, dass es ein Link ist. */
@media (hover: none) {
  .prose a,
  .contact-panel .note a,
  .form-privacy a,
  .legal-page a {
    text-decoration: underline;
  }
}

/* ===== Seitenwechsel =====
   Impressum, Datenschutz und 404 blenden weich über statt hart
   umzuschalten. Eine Zeile, 0 KB, kein Router. Browser ohne Unterstützung
   ignorieren die Regel, es bricht also nichts.
   Zählt nicht als bewegter Moment im Sinne der Zwei-bis-drei-Regel: der
   Übergang betrifft den Wechsel zwischen Seiten, nicht eine Sektion. */
@view-transition {
  navigation: auto;
}

/* ===== Bewegung abschalten =====
   Wortlaut aus dem Hausregelwerk. Die Dauer wird auf 0.01ms gesetzt statt
   die Animation zu entfernen, und `animation-iteration-count: 1` stoppt
   Dauerschleifen wie den Lade-Spinner.

   Wichtiger als die Wahl zwischen beiden Varianten ist eine Regel, die
   nachgemessen wurde: Der versteckte Startzustand gehört in die Keyframes,
   NICHT in die Basisregel des Elements. Steht `opacity: 0` in der
   Basisregel, bleibt das Element auf 0 hängen, und zwar bei `animation:
   none` genauso wie bei einer auf 0.01ms verkürzten Dauer. Der
   Hero-Entrance ist deshalb so gebaut, dass die 0 ausschließlich im
   `from`-Block steht. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Ohne Transition würde die Unterstreichung nie erscheinen. */
  .prose a,
  .contact-panel .note a,
  .form-privacy a,
  .legal-page a {
    background-size: 100% 1px;
  }
}

/* View-Transition-Animationen laufen außerhalb des Blocks oben und werden
   davon NICHT erfasst. Sie brauchen eine eigene Regel. Hier ist
   `animation: none` richtig: die Vorgabe ist ein Überblenden, ohne das
   schaltet die Seite einfach direkt um, es bleibt nichts unsichtbar. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}
