/* =============================================================================
   Online Marketing Beratung Hamburg — style.css
   Eine Datei für das gesamte Projekt. BEM-Naming, CSS Custom Properties.
   ============================================================================= */

/* -----------------------------------------------------------------------
   1) Fonts (lokal eingebettet, DSGVO-konform — kein Google Fonts CDN)
   ----------------------------------------------------------------------- */
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* -----------------------------------------------------------------------
   2) Design Tokens
   ----------------------------------------------------------------------- */
:root {
  /* Farben — Electric Blue + Butter Yellow */
  --color-primary: #2f6fed;
  --color-primary-deep: #1d4fc4;
  --color-primary-soft: #e8f0fe;
  --color-accent: #ffd666;
  --color-accent-deep: #f0b93a;
  --color-ink: #101828;
  --color-text: #2a3242;
  --color-text-muted: #626b7e;
  --color-bg: #f7f9fc;
  --color-bg-soft: #eef2f9;
  --color-surface: #ffffff;
  --color-border: #e2e6ef;
  --color-success: #1a7f4e;

  /* Glass-Header */
  --glass-bg: rgba(247, 249, 252, 0.72);
  --glass-border: rgba(16, 24, 40, 0.08);

  /* Typografie */
  --font-display: "Space Grotesk", "Segoe UI", sans-serif;
  --font-base: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Abstände */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;
  --space-3xl: 8rem;

  /* Sonstiges */
  --radius: 14px;
  --radius-sm: 8px;
  --radius-pill: 999px;
  --header-h: 76px;
  --nav-pill-h: 62px;
  --shadow-sm: 0 2px 8px rgba(20, 33, 61, 0.06);
  --shadow-md: 0 12px 32px rgba(20, 33, 61, 0.12);
  /* Karten auf der Kontaktseite (Eckdaten, Karte, Formular). Zwei
     gestaffelte Schatten statt eines einzelnen: der enge, dunklere legt
     die Kante an, der weite traegt die Flaeche - erst zusammen sieht die
     Karte aus, als laege sie ueber der Seite, statt nur einen grauen Saum
     zu haben. */
  --shadow-card: 0 1px 2px rgba(20, 33, 61, 0.06),
                 0 6px 16px rgba(20, 33, 61, 0.08),
                 0 18px 40px rgba(20, 33, 61, 0.10);
  --shadow-lg: 0 24px 64px rgba(20, 33, 61, 0.18);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --max-width: 1200px;
  /* Buehnen-Rand: der Abstand, mit dem die abgerundeten Sektionsflaechen
     ("Buehnen") vom Fensterrand und VONEINANDER wegstehen. Bewusst EIN
     Wert fuer alle Buehnen - vorher definierte jede ihren eigenen
     (0.5-1.25rem im Intro, 12-34px im Impact-Hero), wodurch die beiden
     untereinander liegenden Flaechen unterschiedlich breit waren und die
     Trennkante zwischen ihnen unsymmetrisch lief.
     Der gleiche Wert dient auch als vertikaler Abstand ZWISCHEN zwei
     Buehnen, damit die Fuge ringsum gleich breit ist. */
  --stage-inset: clamp(12px, 1.4vw, 20px);
  --stage-radius: clamp(18px, 2vw, 30px);

  /* Gemeinsamer Ton der beiden Hero-Buehnen: links dunkles Ink, nach
     rechts auf den hellen Seitenton aufgeblendet - exakt die Komposition,
     die .hero__fade auf der Impact-Buehne erzeugt (Ink-Grund, horizontal
     nach --color-bg aufgehellt; die Prozentwerte sind von dort
     uebernommen und muessen mit ihr synchron bleiben).
     Dient als Uebergangsflaeche zwischen den Buehnen (--exit-tone,
     Block 9e): der Vorhang trifft damit auf beiden Bildhaelften die
     Farbe, die dahinter ohnehin steht, statt beide durch ein
     gemeinsames Weiss zu schicken. */
  --stage-tone:
    linear-gradient(90deg,
      var(--color-ink) 0%,
      var(--color-ink) 22%,
      var(--color-bg) 68%,
      var(--color-bg) 100%);

  /* Seitenhintergrund HINTER den dunklen Buehnen (die Flaeche, die in der
     Fuge und seitlich neben den Platten sichtbar bleibt). Bewusst deutlich
     dunkler als der Plattenton --color-ink (16,24,40 -> 7,11,20): waere er
     gleich, verschwaende die Platte als eigenstaendige Flaeche und es
     stuende Grau auf Grau. So liegt sie sichtbar VOR ihrem Grund.
     Muss ein glatter Hex-Wert bleiben - initSurfaceTone (script.js) liest
     ihn aus und interpoliert ihn, ein Verlauf liesse sich nicht mischen. */
  --backdrop-dark: #070b14;
}

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

html {
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: var(--color-primary) var(--color-bg-soft);
}

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--color-bg-soft); }
::-webkit-scrollbar-thumb { background: var(--color-primary); border-radius: 4px; }

::-webkit-scrollbar-thumb:hover,
::-webkit-scrollbar-thumb:focus-visible { background: var(--color-primary-deep); }

body {
  font-family: var(--font-base);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

a { color: inherit; text-decoration: none; }

ul, ol { list-style: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

input, textarea, select { font: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--color-ink);
  font-weight: 600;
  line-height: 1.15;
}

/* -----------------------------------------------------------------------
   4) Accessibility: focus, skip-link
   ----------------------------------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--space-sm);
  background: var(--color-ink);
  color: #fff;
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-sm);
  z-index: 1000;
  transition: top 200ms var(--ease-out);
}
.skip-link:focus {
  top: var(--space-sm);
}

/* -----------------------------------------------------------------------
   5) Typografie-Umbruch (Schusterjungen/Hurenkinder)
   ----------------------------------------------------------------------- */
h1, h2, h3, h4,
.hero__title,
.section__title {
  text-wrap: balance;
  -webkit-hyphens: none;
  hyphens: none;
}

p, li,
.section__lead,
.prose {
  text-wrap: pretty;
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: break-word;
}

.hero__title { font-size: clamp(2.25rem, 4.5vw + 1rem, 4rem); line-height: 1.08; }
.section__title { font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); }
.section__lead { font-size: clamp(1.05rem, 1vw + 0.9rem, 1.25rem); line-height: 1.6; color: var(--color-text-muted); }

/* -----------------------------------------------------------------------
   6) Layout helpers
   ----------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--space-sm);
}

.section {
  /* position: relative als Basis, damit ein .scroll-cue auch in
     Sektionen OHNE .section--full (variable Hoehe, z.B. FAQ-Akkordeon)
     korrekt relativ zur Section statt zu einem entfernteren Vorfahren
     positioniert wird. */
  position: relative;
  padding-block: var(--space-2xl);
}

.section--tight { padding-block: var(--space-xl); }

/* Vollbild-Sektionen: fuellen mindestens die Viewport-Hoehe und lassen unten
   Platz fuer den Erkunden-Indikator. min-height statt height, damit lange
   Inhalte auf kleinen Schirmen nicht abgeschnitten werden. */
.section--full {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Oben Platz fuer die schwebende Kopfleiste (sonst rutscht der Sektionskopf
     beim Sprung darunter), unten Platz fuer den Erkunden-Indikator. */
  padding-block: calc(var(--nav-pill-h) + var(--space-sm)) var(--space-lg);
}
/* Der Nav-Abstand liegt jetzt INNERHALB der ersten Sektion (siehe Block 8,
   body:not(.has-dark-hero) > main > :first-child). Damit sie trotzdem
   genau einen Bildschirm hoch bleibt und nicht um den Abstand darueber
   hinauswaechst, rechnet border-box das Polster in die Hoehe hinein -
   sonst addierte es sich zu min-height:100svh. */
body:not(.has-dark-hero) main > :first-child {
  box-sizing: border-box;
}

/* Der Inhalt nimmt den freien Platz ein und zentriert sich darin. */
.section--full > .container {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Erkunden-Indikator: rechte untere Ecke der jeweiligen Section, links
   neben dem (bildschirmfixierten) To-Top-Button - beide teilen dieselbe
   bottom-Distanz (var(--space-md)), damit sie auf gleicher Hoehe sitzen.
   .to-top ist 48px breit und steht bei right: var(--space-md); der
   Scroll-Cue rueckt deshalb um 48px + einen zusaetzlichen Abstand weiter
   nach links. position: absolute zur Section (nicht fixed wie .to-top),
   er taucht also nur am jeweiligen Sektionsende auf, statt dauerhaft am
   Bildschirmrand zu kleben. Nur Desktop (siehe Mobile-Regel weiter unten
   in Block 20, .to-top-Nachbarschaft) - auf Mobile komplett ausgeblendet. */
.scroll-cue {
  position: absolute;
  right: calc(var(--space-md) + 48px + var(--space-sm));
  bottom: var(--space-md);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3xs);
  color: var(--color-text-muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: color 200ms var(--ease-out);
}
.scroll-cue:hover,
.scroll-cue:focus-visible { color: var(--color-primary); }

@media (max-width: 767px) {
  .scroll-cue { display: none; }

  /* Knoepfe auf volle Breite: nebeneinander bleibt auf dem Telefon fuer
     jeden zu wenig Platz (gemessen 189-268px bei 390px Schirm, je nach
     Textlaenge unterschiedlich breit). Untereinander und durchgehend
     gleich breit sind sie sicher zu treffen und stehen ruhig.

     AUSGENOMMEN: der Knopf in der Navigationsleiste und die Schalter im
     Cookie-Banner - die haben ihr eigenes, enges Layout. */
  .btn:not(.nav__cta),
  .cta-orbit:not(.nav__cta) {
    width: 100%;
    justify-content: center;
  }
  /* Der Cookie-Banner bringt sein eigenes, enges Layout mit. */
  .cookie-banner .btn { width: auto; }
  /* Die Knopfreihen stapeln entsprechend. */
  .v2-hero__actions,
  .v2-final__cta,
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
  }
}

.scroll-cue__icon {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: cue-bounce 2200ms ease-in-out infinite;
}
.scroll-cue__icon svg { width: 20px; height: 20px; }

.scroll-cue--light { color: rgba(255, 255, 255, 0.75); }
.scroll-cue--light:hover,
.scroll-cue--light:focus-visible { color: var(--color-accent); }

@keyframes cue-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(7px); }
}

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

.section--surface { background: var(--color-surface); }
.section--soft { background: var(--color-bg-soft); }

/* Wash-Wrapper fuer mehrere aufeinanderfolgende Sections, die als EIN
   zusammenhaengender Bereich wirken sollen statt als Kette einzelner
   Vollbild-Bloecke mit hartem Farbsprung dazwischen (siehe Prozess +
   Referenzen-Zitat + CTA-Band auf der Startseite). Ein einzelner
   Verlauf ueber die volle Wrapper-Hoehe ersetzt die vorherigen
   .section--soft/.section--surface-Kanten - die Kind-Sections selbst
   tragen keine eigene Hintergrundfarbe mehr. */
.section-flow {
  background: linear-gradient(180deg,
    var(--color-bg-soft) 0%,
    var(--color-bg-soft) 45%,
    var(--color-surface) 100%);
}

/* --- Mitwandernder Seitenhintergrund ---------------------------------
   Dieselbe Idee wie der Wash-Wrapper oben, eine Ebene tiefer: nicht die
   Sektionsflaechen, sondern der GRUND, auf dem sie liegen.

   Die Buehnen der Startseite sind gerundete Platten mit Rand ringsum
   (--stage-inset) - dazwischen und seitlich bleibt der Seitenhintergrund
   sichtbar. Der war konstant hell, waehrend die beiden Hero-Platten
   dunkel sind: an der Oberkante der Buehne stiess damit Weiss direkt auf
   Anthrazit, und beim Scrollen sprang die Farbe an der Sektionskante
   statt zu wechseln.

   Jeder Block, der einen eigenen Grundton mitbringt, wird hier mit
   data-surface-tone ausgezeichnet und legt ihn in --surface-tone ab.
   initSurfaceTone (script.js) blendet beim Scrollen zwischen den Toenen
   aufeinanderfolgender Bloecke ueber - der Farbwechsel passiert also
   kontinuierlich waehrend die Fuge durchs Bild laeuft, nicht an ihrer
   Kante. Ohne JavaScript bleibt der helle Standardwert von body stehen
   (der bisherige Zustand), es geht also nichts kaputt.

   --surface-tone muss ein glatter Hex-Wert sein, siehe --backdrop-dark. */
/* Zwei Stuetzstellen statt einer Farbe: --surface-tone ist der Ton am
   LINKEN Seitenrand, --surface-tone-r der am rechten. Die Hero-Buehnen
   sind horizontal verlaufende Platten (links Ink, rechts --color-bg,
   siehe --stage-tone/.hero__fade) - ein einfarbiger Grund konnte dem
   nicht folgen und stiess an der Fuge auf der hellen Bildhaelfte hart
   gegen die Platte. initSurfaceTone mischt beide Seiten getrennt und
   setzt einen linear-gradient mit denselben Stuetzstellen (22%/68%) wie
   --stage-tone, damit Grund und Platte an jeder x-Position denselben
   Helligkeitswert haben.
   Bloecke ohne eigenen rechten Ton erben ihn vom linken - fuer sie
   bleibt der Grund einfarbig wie bisher. */
[data-surface-tone] {
  --surface-tone: var(--color-bg);
  --surface-tone-r: var(--surface-tone);
}
.hero--intro[data-surface-tone],
.hero--impact[data-surface-tone] {
  --surface-tone: var(--backdrop-dark);
  --surface-tone-r: var(--color-bg);
}
.section--dark {
  background: var(--color-ink);
  color: rgba(255, 255, 255, 0.85);
}
.section--dark h1,
.section--dark h2,
.section--dark h3 { color: #fff; }

/* Dunkler Carbon-Hintergrund: feines Diagonal-Karo aus zwei ueberlagerten
   linearen Verlaeufen (kein Bild, kein Netzwerk-Request) statt reiner
   Flat-Farbe - liest sich als gebuerstete/gewebte Textur, sehr dezent,
   damit die hellen Karten davor der eigentliche Blickfang bleiben. */
.section--carbon {
  background-color: #0c1119;
  background-image:
    linear-gradient(135deg, rgba(255, 255, 255, 0.025) 25%, transparent 25%),
    linear-gradient(225deg, rgba(255, 255, 255, 0.025) 25%, transparent 25%),
    linear-gradient(45deg, rgba(255, 255, 255, 0.025) 25%, transparent 25%),
    linear-gradient(315deg, rgba(255, 255, 255, 0.025) 25%, #0c1119 25%);
  background-position: 10px 0, 10px 0, 0 0, 0 0;
  background-size: 20px 20px;
  background-repeat: repeat;
  color: rgba(255, 255, 255, 0.85);
}
.section--carbon h1,
.section--carbon h2,
.section--carbon h3 { color: #fff; }
.section--carbon .eyebrow { color: var(--color-accent); }

.section__head {
  max-width: 640px;
  margin-bottom: var(--space-lg);
}

/* Kopf mittig ueber der ganzen Sektionsbreite statt linksbuendig ueber
   der ersten Spalte. Fuer zweispaltige Sektionen (Kontaktseite: Infos
   links, Termin-App rechts) - dort sass der Titel sonst sichtbar aus der
   Achse geschoben ueber der linken Spalte. */
.section__head--center {
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
}

.eyebrow {
  display: inline-block;
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: var(--space-2xs);
}

.section--dark .eyebrow { color: var(--color-accent); }

@media (max-width: 1023px) {
  .section__head--center-mobile {
    text-align: center;
    margin-inline: auto;
  }
}

/* -----------------------------------------------------------------------
   7) Buttons
   ----------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: 48px;
  padding: 0.85rem 1.75rem;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 0.9375rem;
  transition: transform 200ms var(--ease-out), box-shadow 200ms var(--ease-out), background-color 200ms var(--ease-out), color 200ms var(--ease-out);
  white-space: nowrap;
}

.btn--primary {
  background: var(--color-accent);
  color: var(--color-ink);
  box-shadow: var(--shadow-sm);
}

.btn--primary:hover,
.btn--primary:focus-visible {
  background: var(--color-accent-deep);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.btn--primary:active { transform: translateY(0); }

.btn--secondary {
  background: transparent;
  color: var(--color-primary);
  border: 2px solid var(--color-primary);
}

.btn--secondary:hover,
.btn--secondary:focus-visible {
  background: var(--color-primary);
  color: #fff;
  transform: translateY(-2px);
}
.btn--secondary:active { transform: translateY(0); }

.btn--on-dark {
  border-color: rgba(255, 255, 255, 0.5);
  color: #fff;
}

.btn--on-dark:hover,
.btn--on-dark:focus-visible {
  background: #fff;
  color: var(--color-ink);
  border-color: #fff;
}

.btn--block { width: 100%; }

/* -----------------------------------------------------------------------
   7b) Lauflicht auf den Seiten-CTAs
   -----------------------------------------------------------------------
   Bisher trug nur der Kopfleisten-CTA das umlaufende Licht; die uebrigen
   Knoepfe auf Start- und Unterseiten waren flache Pillen. Damit alle CTAs
   dieselbe Bauform tragen, wird die Orbit-Optik hier auf .btn--primary
   und .btn--secondary gelegt - die FARBEN bleiben, wie sie waren.

   Zwei Dinge muessen dafuer je Variante gesetzt werden:
   - Die Fuellung (--orbit-fill), sonst waere jeder Knopf primaerblau.
   - Die Lichtfarbe (--orbit-light). Weiss traegt nur auf dunklem Grund:
     auf dem gelben --color-accent kam weisses Licht auf 1.10-1.27:1
     gegen den Knopf und war schlicht nicht zu sehen. Dort laeuft deshalb
     ein DUNKLES Licht (Ink) um, gemessen 3.64:1.

   Groesse und Innenabstand kommen weiterhin von .btn (min-height 48px,
   padding 0.85rem 1.75rem) - die Knoepfe behalten also ihre bisherigen
   Masse; .cta-orbit steuert hier nur die Ringbreite. */
.btn.cta-orbit {
  height: auto;
  min-height: 48px;
  padding: 0.85rem 1.75rem;
  font-size: 0.9375rem;
  /* border-box, damit der 2px-Rand der Sekundaervariante INNERHALB der
     Masse liegt: ohne das war sie 55px hoch gegen 51px beim gefuellten
     CTA, die Knoepfe standen also nicht mehr auf einer Linie. */
  box-sizing: border-box;
}

/* Gelber Haupt-CTA: Fuellung Akzentgelb, Schrift Ink, Licht dunkel. */
.btn--primary.cta-orbit {
  --orbit-fill: var(--color-accent);
  --orbit-fill-hover: var(--color-accent-deep);
  --orbit-light: 16, 24, 40;
  color: var(--color-ink);
  background: transparent;
  box-shadow: none;
}
.btn--primary.cta-orbit .cta-orbit__label { color: var(--color-ink); }
.btn--primary.cta-orbit:hover,
.btn--primary.cta-orbit:focus-visible { color: var(--color-ink); }
.btn--primary.cta-orbit:hover .cta-orbit__label,
.btn--primary.cta-orbit:focus-visible .cta-orbit__label { color: var(--color-ink); }
/* .btn--primary:hover hebt den Knopf an; beim Orbit-CTA bleibt er
   stehen, sonst wandert der Ring beim Hover sichtbar mit. */
.btn--primary.cta-orbit:hover { transform: none; box-shadow: none; }

/* Sekundaerer CTA: war eine Umriss-Pille ohne Fuellung. Der Lichtkegel
   braucht eine deckende Innenflaeche, sonst laeuft das Licht durch den
   Knopf hindurch statt am Rand entlang. Die Innenflaeche uebernimmt
   deshalb den Seitengrund, der Ring traegt die Kontur - optisch bleibt
   es eine umrandete Pille. */
.btn--secondary.cta-orbit {
  --orbit-fill: var(--color-surface);
  --orbit-fill-hover: var(--color-primary);
  --orbit-light: 47, 111, 237;
  --orbit-ring: 2px;
  color: var(--color-primary);
  /* Rand BLEIBT, nur transparent gesetzt: der Lichtkegel deckt den Rand
     nur waehrend seines hellsten Abschnitts ab. In seinem gedimmten
     Grundton (0.16) kam der blaue Ring auf weisser Flaeche nur auf
     1.23:1 - die Umriss-Pille verlor ueber den groessten Teil der
     Umdrehung sichtbar ihre Kontur. Der eigene Rand haelt sie durchgehend
     bei 4.55:1, das Licht laeuft darauf entlang. */
  border: 2px solid var(--color-primary);
  background: transparent;
}
/* Die Innenflaeche muss den Rand freilassen, sonst deckt sie ihn ab.
   inset:0 statt --orbit-ring: der Rand liegt bereits ausserhalb der
   Innenflaeche, ein zusaetzlicher Versatz erzeugte einen doppelten
   Saum. */
.btn--secondary.cta-orbit::after { inset: 0; }

.btn--secondary.cta-orbit:hover,
.btn--secondary.cta-orbit:focus-visible { border-color: var(--color-primary); }
.btn--secondary.cta-orbit .cta-orbit__label { color: var(--color-primary); }
.btn--secondary.cta-orbit:hover .cta-orbit__label,
.btn--secondary.cta-orbit:focus-visible .cta-orbit__label { color: #fff; }
.btn--secondary.cta-orbit:hover { transform: none; }

/* Auf dunklem Grund (Hero, Carbon-Sektionen) ist die helle Innenflaeche
   falsch - dort fuellt der Knopf mit dem Sektionston und das Licht bleibt
   weiss, wie beim Kopfleisten-CTA. */
.btn--secondary.btn--on-dark.cta-orbit {
  --orbit-fill: var(--color-ink);
  --orbit-fill-hover: #fff;
  --orbit-light: 255, 255, 255;
  color: #fff;
}
.btn--secondary.btn--on-dark.cta-orbit .cta-orbit__label { color: #fff; }
.btn--secondary.btn--on-dark.cta-orbit:hover .cta-orbit__label { color: var(--color-ink); }

/* Ausnahme Cookie-Banner: dort trifft der Nutzer eine bewusste
   Entscheidung zwischen zwei gleichrangigen Optionen. Ein umlaufendes
   Licht zieht den Blick auf eine der beiden und macht aus der Abfrage
   eine Empfehlung - deshalb bleiben diese Knoepfe ruhig. */
.cookie-banner .cta-orbit::before,
.cookie-overlay .cta-orbit::before { content: none; }
.cookie-banner .cta-orbit::after,
.cookie-overlay .cta-orbit::after { content: none; }
.cookie-banner .btn--primary.cta-orbit,
.cookie-overlay .btn--primary.cta-orbit {
  background: var(--color-accent);
  box-shadow: var(--shadow-sm);
}
.cookie-banner .btn--secondary.cta-orbit,
.cookie-overlay .btn--secondary.cta-orbit {
  background: transparent;
}

/* -----------------------------------------------------------------------
   8) Header / Navigation
   ----------------------------------------------------------------------- */
/* Schwebende Milchglas-Pille.
   Chamäleon-Prinzip: sehr transparente helle Fläche + starkes blur/saturate.
   Der Untergrund scheint durch und färbt die Leiste ein, wird zugleich so weit
   aufgehellt, dass die dunkle Schrift überall lesbar bleibt. */
.nav {
  position: fixed;
  top: var(--space-sm);
  left: 50%;
  transform: translateX(-50%);
  width: min(calc(100% - 1.5rem), var(--max-width));
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  height: var(--nav-pill-h);
  padding-inline: var(--space-md);
  border-radius: var(--radius-pill);
  /* Der weisse Grundton sichert den Textkontrast (gemessen 7,7:1 auf der
     dunkelsten Flaeche), saturate() laesst den Untergrund durchfaerben. */
  background: rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(22px) saturate(200%);
  -webkit-backdrop-filter: blur(22px) saturate(200%);
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: 0 10px 34px rgba(16, 24, 40, 0.14);
  transition: background-color 300ms var(--ease-out), box-shadow 300ms var(--ease-out), top 300ms var(--ease-out);
}

/* Nach dem Scrollen etwas dichter, damit die Leiste vor Fließtext ruhiger wirkt */
.nav.is-glass {
  background: rgba(255, 255, 255, 0.72);
  box-shadow: 0 12px 40px rgba(16, 24, 40, 0.18);
}

/* Seiten ohne dunklen Vollbild-Auftakt: Platz schaffen, damit der schwebende
   Balken nichts überdeckt. Hero-Seiten laufen bewusst darunter durch. */
/* Der Platz fuer die schwebende Kopfleiste lag frueher als padding-top am
   BODY. Damit stand er ausserhalb jeder Sektion - auf Seiten mit dunkler
   erster Sektion (Referenzen) schien dort der helle Body-Grund durch und
   erzeugte einen hellen Streifen unter der Kopfleiste (gemessen: 86px
   #f7f9fc ueber dem Carbon-Ton der Sektion).
   Der Abstand sitzt jetzt als padding-top INNERHALB der ersten Sektion:
   der Inhalt beginnt genauso weit unten wie vorher, aber der Sektions-
   hintergrund reicht bis unter die Kopfleiste. */
body:not(.has-dark-hero) > main > :first-child {
  /* ADDIERT zum eigenen Polster der Sektion, nicht an dessen Stelle:
     .section bringt bereits padding-block:var(--space-2xl) mit. Ein
     blosses padding-top ueberschrieb das und rueckte die Ueberschrift
     dicht unter die Kopfleiste (gemessen 8px Abstand auf agbs.html). */
  padding-top: calc(var(--space-2xl) + var(--nav-pill-h) + var(--space-md));
}

/* Bildmarke + Schriftzug sitzen auf einer gemeinsamen Mittelachse */
.nav__logo {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.15;
  color: var(--color-ink);
  letter-spacing: -0.01em;
  flex-shrink: 0;
  height: 100%;
}

.nav__logo-mark {
  height: 26px;
  width: auto;
  flex-shrink: 0;
}

.nav__logo-text { display: block; }

.nav__burger {
  position: relative;
  width: 44px;
  height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  z-index: 600;
}
.nav__burger span {
  width: 24px;
  height: 2px;
  background: var(--color-ink);
  border-radius: 2px;
  transition: transform 250ms var(--ease-out), opacity 250ms var(--ease-out);
}
.nav__burger[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.nav__menu {
  position: fixed;
  top: 0;
  height: 100svh;
  width: min(80vw, 320px);
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: calc(var(--header-h) + var(--space-lg)) var(--space-lg) var(--space-lg);
  right: 0;
  transform: translateX(100%);
  transition: transform 300ms var(--ease-out);
  z-index: 550;
}
.nav__menu.is-open { transform: translateX(0); }

.nav__menu a {
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--color-ink);
  padding-block: var(--space-2xs);
  border-bottom: 1px solid var(--color-border);
  transition: color 200ms var(--ease-out);
}
.nav__menu a:hover,
.nav__menu a:focus-visible { color: var(--color-primary); }

/* Mobile (aufgeklapptes Menue): flache gelbe Pille ohne Lichtkegel - im
   Menue steht der CTA in einer Liste untereinander, ein rotierender Rand
   waere dort unruhig. Die .cta-orbit-Bauform wird deshalb hier gezielt
   zurueckgenommen (der Desktop-Zweig aktiviert sie wieder). */
.nav__menu .nav__cta {
  margin-top: var(--space-2xs);
  border-bottom: none;
  background: var(--color-accent);
  color: var(--color-ink);
  text-align: center;
  padding: 0.85rem 1.5rem;
  border-radius: var(--radius-pill);
  height: auto;
  overflow: visible;
}
.nav__menu .nav__cta::before,
.nav__menu .nav__cta::after { content: none; }
.nav__menu .nav__cta .cta-orbit__label { color: var(--color-ink); }

.nav-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 33, 61, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms var(--ease-out);
  z-index: 499;
}
.nav-backdrop.is-open { opacity: 1; pointer-events: auto; }

/* Leistungen-Dropdown — Mobile: eingebettetes Untermenü */
.nav__dropdown-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2xs);
  width: 100%;
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--color-ink);
  padding-block: var(--space-2xs);
  border-bottom: 1px solid var(--color-border);
  min-height: 44px;
}
.nav__dropdown-toggle svg {
  width: 18px;
  height: 18px;
  transition: transform 200ms var(--ease-out);
  flex-shrink: 0;
}
.nav__dropdown[data-open="true"] .nav__dropdown-toggle svg { transform: rotate(180deg); }

.nav__dropdown-menu {
  display: flex;
  flex-direction: column;
  max-height: 0;
  overflow: hidden;
  transition: max-height 300ms var(--ease-out);
}
.nav__dropdown[data-open="true"] .nav__dropdown-menu { max-height: 400px; }

.nav__dropdown-menu a {
  font-size: 0.9375rem;
  font-weight: 500;
  padding-block: var(--space-2xs);
  padding-left: var(--space-sm);
  border-bottom: 1px solid var(--color-border);
}

@media (min-width: 1024px) {
  .nav__burger { display: none; }
  .nav-backdrop { display: none; }
  .nav__menu {
    position: static;
    height: auto;
    width: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--space-md);
    padding: 0;
    box-shadow: none;
    transform: none;
    background: transparent;
  }
  .nav__menu a {
    font-size: 0.9375rem;
    font-weight: 500;
    border-bottom: none;
    padding-block: 0;
    white-space: nowrap;
  }
  /* CTA in der Kopfleiste: sitzt auf derselben Mittelachse wie Logo und
     Menue. Die Optik (umlaufender Lichtkegel) kommt aus der gemeinsamen
     Klasse .cta-orbit in Block 8b - hier stehen nur noch die Abweichungen,
     die sich aus der Lage IN der Kopfleiste ergeben. Vorher lag die
     komplette Bauform hier drin und war im Hero nicht nutzbar. */
  .nav__menu .nav__cta {
    /* mobile Margin zuruecksetzen, sonst sitzt der CTA 4px tiefer */
    margin-top: 0;
    /* Die mobile Flach-Variante oben nimmt Hoehe, Fuellung und die beiden
       Pseudo-Elemente zurueck - hier wird die .cta-orbit-Bauform wieder
       aktiviert. */
    height: 44px;
    overflow: hidden;
    padding: 0 calc(5px + 1.15rem);
    background: transparent;
    color: #fff;
  }
  .nav__menu .nav__cta::before,
  .nav__menu .nav__cta::after { content: ""; }
  .nav__menu .nav__cta .cta-orbit__label { color: #fff; }

  .nav__dropdown { position: relative; }
  .nav__dropdown-toggle {
    width: auto;
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--color-ink);
    border-bottom: none;
    padding-block: 0;
    min-height: auto;
  }
  /* Unsichtbare Bruecke ueber die Luecke zwischen Schalter und Menue:
     ohne sie loest das Hinuebergleiten ein mouseleave aus. */
  .nav__dropdown-menu::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: calc(-1 * var(--space-sm));
    height: var(--space-sm);
  }
  .nav__dropdown-menu {
    position: absolute;
    top: calc(100% + var(--space-sm));
    left: 0;
    max-height: none;
    width: max-content;
    min-width: 220px;
    /* Deutlich dichter als die Leiste: das Dropdown liegt IN der Leiste,
       die selbst einen backdrop-filter hat - Chrome bildet daraus eine
       eigene Hintergrund-Wurzel, der Blur des Dropdowns sieht die Seite
       dahinter also gar nicht. Die Hero-Grossschrift schien deshalb
       scharf durch und lag teils quer ueber den Eintraegen. */
    background: rgba(255, 255, 255, 0.975);
    backdrop-filter: blur(22px) saturate(200%);
    -webkit-backdrop-filter: blur(22px) saturate(200%);
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: var(--radius);
    box-shadow: 0 12px 40px rgba(16, 24, 40, 0.18);
    padding: var(--space-2xs);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    translate: 0 -6px;
    transition: opacity 200ms var(--ease-out), visibility 200ms, translate 200ms var(--ease-out);
  }
  .nav__dropdown[data-open="true"] .nav__dropdown-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    translate: 0 0;
  }
  .nav__dropdown-menu a {
    padding: 0.6rem var(--space-sm);
    border-bottom: none;
    border-radius: var(--radius-sm);
  }
  /* Hover/Fokus in Kopfleiste und Dropdown (WCAG AA).
     Vorher: Primaerblau (#2f6fed) auf dem Milchglas. Das Glas nimmt die
     Farbe des Untergrunds auf und liegt ueber dunklen Sektionen bei etwa
     #8d9298 bis #bcc0c5 - Blau darauf kam nur auf rund 2.5-3.2:1. Jetzt
     bleibt die Schrift Ink (dunkel) und der Hover wird ueber eine HELLERE
     Glas-Pille gezeigt: das hebt den Hintergrund an, der Kontrast steigt
     beim Hover statt zu fallen. */
  .nav__menu > a:not(.nav__cta),
  .nav__dropdown-toggle {
    padding: 0.45rem 0.8rem;
    margin-inline: -0.8rem;
    border-radius: var(--radius-pill);
    transition: color 200ms var(--ease-out), background-color 200ms var(--ease-out);
  }
  .nav__menu > a:not(.nav__cta):hover,
  .nav__menu > a:not(.nav__cta):focus-visible,
  .nav__dropdown-toggle:hover,
  .nav__dropdown-toggle:focus-visible,
  .nav__dropdown[data-open="true"] .nav__dropdown-toggle {
    color: var(--color-ink);
    background: rgba(255, 255, 255, 0.78);
  }
  .nav__menu > a:not(.nav__cta):focus-visible,
  .nav__dropdown-toggle:focus-visible {
    outline: 2px solid var(--color-ink);
    outline-offset: 1px;
  }
  .nav__dropdown-menu a:hover,
  .nav__dropdown-menu a:focus-visible {
    /* Auf der hellen Flaeche taugt eine weisse Pille nicht als Hover -
       blauer Tint mit dunkler Schrift (gemessen > 10:1). */
    background: rgba(47, 111, 237, 0.16);
    color: var(--color-ink);
  }
  .nav__dropdown-menu a:focus-visible {
    outline: 2px solid var(--color-ink);
    outline-offset: -2px;
  }
}

/* -----------------------------------------------------------------------
   8b) CTA mit umlaufendem Lichtkegel (.cta-orbit)
   -----------------------------------------------------------------------
   Bauform des Kopfleisten-CTA ("Anfrage stellen"), herausgeloest als
   eigene Klasse, damit der Hero-CTA ("Kontakt aufnehmen") exakt dieselbe
   Optik traegt statt einer nachgebauten Naeherung. Aufbau:
     ::before  volle Flaeche, conic-gradient = Randgrundton + Lichtsegment
     ::after   inset:5px, deckt die Mitte ab -> nur der Rand leuchtet
     .cta-orbit__label  liegt per z-index darueber
   Der Element-Hintergrund bleibt transparent: er wuerde IMMER unter allen
   Pseudo-Elementen rendern und den Lichtkegel verdecken (auch bei
   negativem z-index).
   ----------------------------------------------------------------------- */
.cta-orbit {
  /* Drei Stellschrauben, damit dieselbe Bauform auf jeder Knopffarbe
     funktioniert (siehe .btn.cta-orbit weiter unten):
       --orbit-fill   Fuellfarbe der Innenflaeche
       --orbit-light  Farbe des umlaufenden Lichts
       --orbit-ring   Breite des leuchtenden Randes
     Vorher standen Fuellung (Primaerblau) und Licht (Weiss) fest - auf
     dem gelben CTA war das weisse Licht dadurch praktisch unsichtbar
     (gemessen 1.10-1.27:1 gegen den gelben Grund). */
  --orbit-fill: var(--color-primary);
  --orbit-fill-hover: var(--color-primary-deep);
  --orbit-light: 255, 255, 255;
  --orbit-ring: 5px;

  position: relative;
  overflow: hidden;
  /* Eigener Stapelkontext + Beschnitt auf die Pille: ohne das ragte das
     rotierende ::before (Chrome, Rundung + overflow + animierte
     Transformation) als grauer Keil ueber den unteren Rand hinaus. */
  isolation: isolate;
  clip-path: inset(0 round var(--radius-pill));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  /* Ringbreite + echter Textabstand: ohne die Zugabe frisst der Ring den
     sichtbaren Abstand zwischen Randinnenkante und Schrift auf. */
  padding: 0 calc(var(--orbit-ring) + 1.15rem);
  background: transparent;
  border-radius: var(--radius-pill);
  color: #fff;
  font-family: var(--font-base);
  font-weight: 600;
  font-size: 0.9375rem;
  white-space: nowrap;
  cursor: pointer;
}
.cta-orbit::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  /* Lichtsegment in zwei Schritten verschmaelert: urspruenglich 190deg
     (210 bis 400), dann 95deg, jetzt 48deg (322 bis 370). Der Kopf liegt
     weiter bei 360deg, die Stufenfolge bleibt, nur die Abstaende davor
     und dahinter schrumpfen. */
  background: conic-gradient(
    rgba(var(--orbit-light), 0.16) 0deg,
    rgba(var(--orbit-light), 0.16) 322deg,
    rgba(var(--orbit-light), 0.30) 341deg,
    rgba(var(--orbit-light), 0.46) 352deg,
    rgba(var(--orbit-light), 0.60) 357deg,
    rgba(var(--orbit-light), 0.60) 360deg,
    rgba(var(--orbit-light), 0.16) 370deg
  );
  animation: cta-orbit 5.2s linear infinite;
}
.cta-orbit::after {
  content: "";
  position: absolute;
  inset: var(--orbit-ring);
  border-radius: inherit;
  background: var(--orbit-fill);
  transition: background-color 200ms var(--ease-out);
}
.cta-orbit__label {
  position: relative;
  z-index: 1;
  color: #fff;
}
.cta-orbit:hover,
.cta-orbit:focus-visible { color: #fff; }
.cta-orbit:hover .cta-orbit__label,
.cta-orbit:focus-visible .cta-orbit__label { color: #fff; }
.cta-orbit:hover::after,
.cta-orbit:focus-visible::after { background: var(--orbit-fill-hover); }

/* Tastaturfokus: der clip-path oben schneidet einen aussenliegenden
   Outline-Ring ab, deshalb sitzt er innen. */
.cta-orbit:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: -3px;
}

/* Farbvariante Cyan fuer die zweite Aktion auf dunklem Grund (Hero
   Startseite): gleiche Bauform und Masse wie der blaue Knopf, aber eigene
   Farbkombi aus dem Weltraum-Schema - dunkle Teal-Flaeche, helles Cyan als
   Lauflicht, Schrift #eaf6fb (gemessen > 10:1). Beim Hover kippt die
   Flaeche auf das helle Kern-Cyan, die Schrift auf Weltraum-Dunkel. */
.cta-orbit--cyan {
  --orbit-fill: #0e3f52;
  --orbit-fill-hover: #7fe3ff;
  --orbit-light: 127, 227, 255;
}
.cta-orbit--cyan .cta-orbit__label { color: #eaf6fb; }
.cta-orbit--cyan:hover .cta-orbit__label,
.cta-orbit--cyan:focus-visible .cta-orbit__label { color: #04101a; }
.cta-orbit--cyan:hover,
.cta-orbit--cyan:focus-visible { color: #04101a; }

/* Der Lichtkegel muss deutlich groesser als der Knopf sein, sonst
   entstehen an den Ecken Lucken beim Drehen - er rotiert um seinen
   eigenen Mittelpunkt. */
@keyframes cta-orbit {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .cta-orbit::before { animation: none; }
}

/* -----------------------------------------------------------------------
   9) Hero
   ----------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  background: var(--color-ink);
  overflow: hidden;
  /* Der Erkunden-Indikator (Kind der Section, nicht mehr der Variante)
     sitzt absolut am unteren Rand - gleiche Optik wie der Indikator im
     normalen Fluss der Folgesektionen (.section--full), da hier wegen
     der frei positionierten Hero-Layer (Foto/Chart/Content) kein
     einfacher Flex-Fluss moeglich ist. */
  padding-bottom: var(--space-lg);
  /* Zeitplan der Scroll-Choreografie: 5 Kurven (Sichtbarkeit -> Suchanfragen
     -> Markenwahrnehmung -> Reichweite -> Kundenvertrauen, siehe die
     [data-hero-sequence="go"]-Regeln bei .hero__chart-area/-line/.hero__kpi-
     float) und als Abschluss der Titel (Schritt 6). Als CSS-Variablen
     zentral gepflegt statt pro Layer einzeln, damit der Abstand zwischen
     den Schritten an einer Stelle nachjustierbar bleibt. Ausgeloest wird
     die Sequenz per initHeroScrollSequence (script.js) beim ersten
     Scroll-Impuls. */
  --hero-step-1: 0ms;
  --hero-step-2: 550ms;
  --hero-step-3: 1100ms;
  --hero-step-4: 1650ms;
  --hero-step-5: 2200ms;
  --hero-step-6: 2950ms;
}

.hero__variant {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
}

/* Feiner Grain-Layer ueber dem gesamten Hero: ein per SVG-<feTurbulence>
   erzeugtes Rauschmuster (kein externes Bild, kein Netzwerk-Request) in
   sehr niedriger Deckkraft - bricht die sonst komplett flache/glatte
   Farbflaechen-Optik dezent auf, ohne dass es bewusst wahrgenommen wird.
   z-index 3 liegt ueber Foto/Fade/Chart, aber unter dem eigentlichen
   Content (Titel etc. haben eigene hoehere z-index-Werte). */
.hero__grain {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

.hero__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding: calc(var(--nav-pill-h) + var(--space-2xl)) var(--space-sm) var(--space-xl);
  flex: 1;
  display: flex;
  align-items: flex-end;
}

.hero__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  color: #fff;
  max-width: 480px;
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 700;
  color: #fff;
  text-shadow: 0 2px 10px rgba(16, 24, 40, 0.55), 0 1px 3px rgba(16, 24, 40, 0.8);
}

.hero__stats {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding: 0 var(--space-sm) var(--space-xl);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-sm);
}

.hero__stat {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-sm);
  padding: var(--space-sm);
  color: #fff;
  backdrop-filter: blur(8px);
}
.hero__stat strong {
  display: flex;
  align-items: baseline;
  gap: 0.15em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 2vw + 1rem, 2.25rem);
  color: var(--color-accent);
}
.hero__stat .count__unit {
  font-size: 0.65em;
  font-weight: 600;
}
.hero__stat span.hero__stat-label {
  display: block;
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.75);
}

@media (min-width: 768px) {
  .hero__stats { grid-template-columns: repeat(4, 1fr); }
}

/* -----------------------------------------------------------------------
   9f) Hero 1 — Vorstellung Marvin de Vries
   -----------------------------------------------------------------------
   Erster Bildschirm der Startseite: ausschliesslich die Person. Portraet
   halblinks und vertikal zentriert, Text rechts daneben. Bewusst KEIN
   Vollbild-Foto - das uebernimmt die zweite Etappe (.hero--impact); hier
   soll das Portraet als abgegrenztes Objekt im Raum stehen, nicht als
   Hintergrund.
   ----------------------------------------------------------------------- */
.hero--intro {
  /* Erbt von .hero: position:relative, min-height:100svh, dunkler Grund,
     overflow:hidden. Der weiche Farbverlauf hebt den flachen Ink-Ton an
     und legt den Lichtschwerpunkt hinter das Portraet (links der Mitte),
     damit die Person freigestellt wirkt. */
  background:
    /* Tonbruecke zur Buehne darunter: die Impact-Buehne beginnt oben hell
       (der .hero__fade-Layer dort blendet nach --color-bg auf), waehrend
       diese Buehne im dunklen Ink endete - an der Fuge sprang die Farbe
       gemessen von (113,117,128) auf (241,243,246). Dieser Verlauf hebt
       die Flaeche kurz VOR der Unterkante auf denselben hellen Ton an,
       sodass beide Buehnen an der Naht ineinander laufen statt hart
       aufeinanderzustossen.
       Bewusst erst ab 88%: greift der Verlauf frueher (probiert mit 62%),
       hellt er das untere Drittel des ERSTEN Bildschirms mit auf und die
       Buehne wirkt dort ausgewaschen statt dunkel. Liegt VOR den beiden
       Lichtkegeln in der Liste und damit optisch ueber ihnen. */
    linear-gradient(180deg,
      rgba(247, 249, 252, 0) 88%,
      rgba(247, 249, 252, 0.35) 96%,
      rgba(247, 249, 252, 0.92) 100%),
    radial-gradient(60% 70% at 32% 45%, rgba(47, 111, 237, 0.20) 0%, rgba(47, 111, 237, 0) 70%),
    radial-gradient(55% 60% at 78% 78%, rgba(255, 214, 102, 0.10) 0%, rgba(255, 214, 102, 0) 70%),
    var(--color-ink);
  /* Die Kennzahlen-Reihe sass frueher als 5er-Kartenraster unter dem
     Vorstellungstext und hat den ersten Bildschirm ueberladen; sie laeuft
     jetzt als eine Zeile im Preloader mit (.preloader__facts). Dadurch
     traegt diese Sektion nur noch EIN Element - Foto plus Text - und darf
     wieder als echte Mitte gesetzt werden statt als Spalte mit Fussreihe.
     min-height:100svh erbt sie von .hero, place-content zentriert .intro
     darin vertikal wie horizontal. */
  /* grid-template-rows:1fr statt place-content:center: die Zeile fuellt
     damit die verfuegbare Hoehe (min-height minus padding) exakt aus,
     statt sich auf die Inhaltshoehe zu ziehen und das Polster oben drauf
     zu addieren. .intro zentriert seinen Inhalt selbst (align-items). */
  display: grid;
  grid-template-rows: 1fr;
  /* .hero bringt ein eigenes padding-bottom mit, das sich zu min-height
     100svh ADDIERT - die Sektion war dadurch immer 40px hoeher als der
     Viewport. Der Raum fuer den Erkunden-Indikator steckt hier bereits im
     padding-bottom von .intro, deshalb wird das Erbstueck neutralisiert.
     Ergebnis: exakt 100svh, wie fuer den ersten Bildschirm gefordert. */
  padding-bottom: 0;

  /* Praesentationsflaeche statt randlos durchlaufender Sektion: die
     Buehne steht als abgerundete Platte allseitig frei im Weiss der
     Seite (Vorbild: der Hero-Block mit Radius oben, unten und an beiden
     Seiten). Umgesetzt ueber margin + border-radius statt eines inneren
     Wrappers, damit Hintergrund, Lichtkegel und Inhalt weiterhin
     dieselbe Box teilen und nichts nachjustiert werden muss.
     Randbreite und Radius kommen aus den globalen Tokens --stage-inset /
     --stage-radius (Block 2), damit diese Buehne exakt so breit und so
     stark gerundet ist wie die folgende. */
  margin: var(--stage-inset);
  /* Die Fuge zur naechsten Buehne kommt VOLLSTAENDIG von hier, nicht je
     zur Haelfte von beiden Nachbarn: senkrechte Raender benachbarter
     Bloecke fallen zusammen (margin collapsing), aus zwei halben wurde
     also gemessen EIN halber (10px statt 20px). Ein voller Rand hier
     ergibt eine Fuge in derselben Breite wie die Luft an den Seiten. */
  margin-bottom: var(--stage-inset);
  /* Das margin zieht Breite UND Hoehe ab; ohne Korrektur ragte die
     Sektion um die Summe beider Raender ueber den Bildschirm hinaus und
     erzeugte einen Scroll-Rest von wenigen Pixeln. */
  min-height: calc(100svh - 2 * var(--stage-inset));
  width: auto;
  border-radius: var(--stage-radius);
  /* Feine Kante plus Schlagschatten - identisch zur Impact-Platte
     (.hero__variant--sticky). Seit der Seitengrund hinter den Buehnen
     mitdunkelt (--backdrop-dark), liegt hier dunkel auf dunkel: ohne
     diese Kante verloere die Platte ihre Silhouette und wuerde mit
     ihrem Grund verschwimmen. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08),
              0 24px 60px rgba(8, 12, 20, 0.28);
  /* .hero setzt bereits overflow:hidden - noetig, damit Lichtkegel und
     Portraet an der gerundeten Kante sauber abgeschnitten werden. */
  isolation: isolate;
  /* .hero setzt min-height:100svh UND padding-bottom - bei content-box
     addieren sich beide, die Sektion wurde also immer 40px hoeher als der
     Viewport. Fuer den ersten Bildschirm ist genau 100svh gefordert,
     deshalb hier border-box: das Polster liegt jetzt INNERHALB der
     Viewporthoehe (der Erkunden-Indikator braucht es weiterhin). */
  box-sizing: border-box;
}

.intro {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  /* Seitliches Padding jetzt identisch zu .container (var(--space-sm)
     beidseitig) statt des vorherigen asymmetrischen Ausweichraums fuer die
     global fixe Kontaktleiste rechts - die max-width haelt den Inhalt
     ohnehin vom aeussersten Rand fern, wo die Leiste schwebt. Oben bleibt
     der Platz fuer die schwebende Kopfleiste, unten der zusaetzliche
     Abstand zum Sektionsende. */
  padding: calc(var(--nav-pill-h) + var(--space-lg)) var(--space-sm) calc(var(--space-2xl) + var(--space-lg)) var(--space-sm);
  display: grid;
  /* Portraet bekommt eine feste, aber mitwachsende Spur; der Text nimmt
     den Rest. Nicht 1fr/1fr: der Text ist lang und braucht die groessere
     Haelfte, das Portraet wuerde bei gleicher Breite unnoetig gross. */
  grid-template-columns: minmax(240px, 0.62fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(var(--space-lg), 4vw, var(--space-2xl));
}

/* --- Lichtkegel hinter der Person ------------------------------------
   Das freigestellte Portraet hat keine eigene Kante mehr (kein Rahmen,
   kein Bildrechteck). Damit es nicht schwerelos vor der Flaeche haengt,
   liegt hinter ihm ein weicher Lichtschwerpunkt - dieselbe Rolle, die im
   Vorbild der farbige Scheinwerfer hinter dem Kopf uebernimmt. Er sitzt
   ueber der Sektionsmitte-links, also genau dort, wo das Portraet steht.
   z-index 0: ueber dem Sektionshintergrund, unter .intro (z-index 1). */
.intro__glow {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  left: 8%;
  top: 6%;
  width: min(52%, 720px);
  aspect-ratio: 1 / 1;
  background:
    radial-gradient(closest-side, rgba(47, 111, 237, 0.42) 0%, rgba(47, 111, 237, 0.16) 46%, rgba(47, 111, 237, 0) 72%),
    radial-gradient(closest-side at 62% 38%, rgba(255, 214, 102, 0.20) 0%, rgba(255, 214, 102, 0) 66%);
  filter: blur(6px);
}

/* --- Portraet (freigestellt) ------------------------------------------
   Frueher eine gerahmte 4:5-Kachel mit Schlagschatten und Bildausschnitt.
   Jetzt steht die Person ohne Rahmen direkt auf der Buehne: die Quelle
   ist ein Alpha-Freisteller, der Verlauf dahinter scheint durch. Damit
   entfallen Rahmen, overflow, object-fit-Ausschnitt und der frueher
   noetige Anbindungs-Verlauf ueber der unteren Bildhaelfte - ein
   freigestelltes Motiv braucht keine Kante, die es an den Grund bindet. */
/* Bildspalte: Portraet und Handlungsaufforderung als EIN Block. Sie
   werden gemeinsam auf dieselbe Mittelachse gelegt wie die Textspalte
   daneben (align-items:center am .intro-Raster) - vorher hing das Foto
   mit align-self:end am unteren Rand und sass dadurch sichtbar tiefer
   als der Text. */
.intro__figure {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  min-width: 0;
}

.intro__photo {
  position: relative;
  /* Kein aspect-ratio: das Bild bringt seine eigene Form mit und soll
     nicht in ein Rechteck gezwungen werden. Die Hoehendeckelung haelt
     den Kopf auf niedrigen Fenstern trotzdem im Bild. */
  display: flex;
  justify-content: center;
  width: 100%;
  /* Die untere Maske blendet den letzten Teil des Bildes aus. Dieser
     Streifen belegt im Layout aber weiterhin Hoehe - die SICHTBARE
     Person sass dadurch tiefer als der Text daneben, obwohl beide
     Spalten technisch auf derselben Mittelachse lagen. Der negative
     Rand zieht den unsichtbaren Anteil aus dem Fluss, sodass die
     Zentrierung auf das greift, was man tatsaechlich sieht.
     Er sitzt an der BILDBOX, nicht am <img>: haenge ihn ans Bild, rutscht
     der darunter folgende Knopf mit nach oben und liegt dann IM
     ausgeblendeten Streifen (gemessen: Knopfoberkante 53px ueber der
     Bildunterkante). So bleibt der Abstand zum Knopf erhalten. */
  margin: 0 0 -12%;
}
.intro__photo img {
  width: 100%;
  height: auto;
  max-height: min(78svh, 620px);
  object-fit: contain;

  /* Das Quellfoto ist eine enge Portraetaufnahme: der Oberkoerper laeuft
     unten und links aus dem Bild heraus (gemessen: die unterste Zeile
     ist zu 99% deckend). Nach dem Freistellen endet die Silhouette dort
     deshalb an einer schnurgeraden Kante - die Person stand als sichtbar
     rechteckiger Block auf der Buehne, also genau das, was hier vermieden
     werden soll. Ein zusaetzlicher drop-shadow machte es schlimmer, weil
     er dieselbe gerade Kante nachzeichnete; er ist deshalb entfallen.
     Stattdessen loest eine Maske den Anschnitt auf: unten laeuft der
     Oberkoerper weich in die Flaeche aus, links wird die angeschnittene
     Schulterkante abgeweicht. Oben und rechts folgt die Silhouette dem
     echten Freisteller und bleibt unangetastet scharf. */
  -webkit-mask-image:
    linear-gradient(to top, transparent 0%, rgba(0, 0, 0, 0.35) 7%, #000 24%),
    linear-gradient(to right, transparent 0%, rgba(0, 0, 0, 0.45) 4%, #000 14%);
  mask-image:
    linear-gradient(to top, transparent 0%, rgba(0, 0, 0, 0.35) 7%, #000 24%),
    linear-gradient(to right, transparent 0%, rgba(0, 0, 0, 0.45) 4%, #000 14%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;

}

/* --- Text ----------------------------------------------------------- */
.intro__body {
  color: rgba(255, 255, 255, 0.82);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
}

/* Die Standard-.eyebrow ist auf hellem Grund gedacht (Primaerblau) und
   waere hier zu dunkel. */
.eyebrow--onDark {
  color: var(--color-accent);
  margin-bottom: 0;
}

.intro__title {
  font-family: var(--font-display);
  font-weight: 700;
  color: #fff;
  /* Deutlich kleiner als eine uebliche Hero-Headline: das ist ein ganzer
     Einleitungssatz, kein Slogan. In Slogan-Groesse wuerde er vier bis
     fuenf Zeilen fuellen und den Text darunter erdruecken. */
  font-size: clamp(1.35rem, 1.1vw + 1.05rem, 1.85rem);
  line-height: 1.28;
  margin: 0;
  text-wrap: balance;
}

.intro__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  /* Lesbare Zeilenlaenge - ohne Deckel liefe der Text bei 1200px Container
     auf ueber 100 Zeichen pro Zeile. */
  max-width: 66ch;
}
.intro__text p {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.75;
  text-wrap: pretty;
}
/* Schlusssatz mit der Handlungsaufforderung: heller und eine Spur groesser
   als der Fliesstext, damit er sich vom Block abhebt und zum Button
   ueberleitet. */
.intro__cta-text {
  color: #fff;
  font-weight: 500;
}

/* Der Knopf traegt seine Optik komplett aus .cta-orbit (Block 8b) - hier
   steht nur noch seine Lage in der Bildspalte. */
.intro__cta {
  flex: none;
}

/* -----------------------------------------------------------------------
   9f-2) Hero 1 - Schriftvarianten (data-type am .hero--intro)
   -----------------------------------------------------------------------
   Drei durchgestaltete Saetze fuer dieselben vier Textebenen
   (Eyebrow / Titel / Fließtext / Schlusssatz). Umgeschaltet wird ueber
   data-type am Hero-Element, ohne Rebuild:
     a  redaktionell-ruhig      klassisch, serioes, lange Zeilen
     b  kontrastreich-modern    grosse Headline, klare Hierarchie (Standard)
     c  zurueckhaltend-elegant  leichte Schnitte, viel Weissraum
   Die Regeln oben (.intro__title, .intro__text ...) bleiben die
   gemeinsame Grundlage; hier stehen nur die Abweichungen je Variante.
   ----------------------------------------------------------------------- */

/* Der Titel besteht aus zwei Spans. In "a" und "c" laufen sie als EIN
   Satz durch (inline), in "b" bilden sie zwei Stufen (block). */
.intro__title-lead,
.intro__title-rest { display: inline; }

/* --- a) redaktionell-ruhig ------------------------------------------- */
.hero--intro[data-type="a"] .eyebrow--onDark {
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--color-accent);
}
.hero--intro[data-type="a"] .intro__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 1.1vw + 1.05rem, 1.85rem);
  line-height: 1.28;
  letter-spacing: 0;
  color: #fff;
}
.hero--intro[data-type="a"] .intro__title-rest { font-size: 1em; opacity: 1; }
.hero--intro[data-type="a"] .intro__text p {
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 0.9375rem;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.78);
}
.hero--intro[data-type="a"] .intro__cta-text {
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 1rem;
  color: #fff;
}

/* --- b) kontrastreich-modern (Standard) ------------------------------ */
/* Die Namensnennung traegt als eigene Stufe, der Rest des Satzes ordnet
   sich sichtbar unter - dadurch entsteht die Hierarchie, die im Vorbild
   die grosse Headline erzeugt, ohne den Satz zu kuerzen. */
.hero--intro[data-type="b"] .eyebrow--onDark {
  font-family: var(--font-base);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  color: var(--color-accent);
  /* Feiner Strich vor dem Label: setzt die Zeile als Rubrik ab, statt sie
     nur durch Farbe zu markieren. */
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}
.hero--intro[data-type="b"] .eyebrow--onDark::before {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: currentColor;
  opacity: 0.8;
}
.hero--intro[data-type="b"] .intro__title {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: #fff;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.hero--intro[data-type="b"] .intro__title-lead,
.hero--intro[data-type="b"] .intro__title-rest { display: block; }
.hero--intro[data-type="b"] .intro__title-lead {
  font-size: clamp(1.75rem, 1.9vw + 1.1rem, 2.9rem);
}
.hero--intro[data-type="b"] .intro__title-rest {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1rem, 0.5vw + 0.85rem, 1.15rem);
  line-height: 1.4;
  letter-spacing: 0;
  color: rgba(255, 255, 255, 0.82);
}
.hero--intro[data-type="b"] .intro__text p {
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 0.875rem;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.68);
}
.hero--intro[data-type="b"] .intro__cta-text {
  font-family: var(--font-base);
  font-weight: 600;
  font-size: 0.9375rem;
  color: #fff;
}

/* --- c) zurueckhaltend-elegant --------------------------------------- */
.hero--intro[data-type="c"] .eyebrow--onDark {
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  /* Kein Gelb: in dieser Variante traegt allein die Sperrung die
     Rubrik-Wirkung, Farbe waere hier ein Bruch. */
  color: rgba(255, 255, 255, 0.55);
  text-transform: uppercase;
}
.hero--intro[data-type="c"] .intro__title {
  font-family: var(--font-display);
  /* 500 statt 700: der Satz wirkt dadurch gesprochen statt plakatiert. */
  font-weight: 500;
  font-size: clamp(1.45rem, 1.3vw + 1.1rem, 2.1rem);
  line-height: 1.35;
  letter-spacing: 0;
  color: rgba(255, 255, 255, 0.95);
}
.hero--intro[data-type="c"] .intro__title-rest { font-size: 1em; }
.hero--intro[data-type="c"] .intro__text p {
  font-family: var(--font-base);
  /* 400, nicht 300: von Inter ist in diesem Projekt kein Light-Schnitt
     eingebunden (nur 400/500/600/700). Ein angefordertes 300 haette der
     Browser synthetisch verduennt oder auf 400 zurueckgesetzt - die
     Leichtigkeit dieser Variante kommt deshalb aus Zeilenabstand und
     Deckkraft statt aus dem Schnitt. */
  font-weight: 400;
  font-size: 0.9375rem;
  line-height: 1.85;
  color: rgba(255, 255, 255, 0.65);
}
.hero--intro[data-type="c"] .intro__cta-text {
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 0.9375rem;
  color: var(--color-accent);
}

/* Der Scroll-Indikator sitzt wie in allen anderen Sektionen unten rechts,
   auf derselben Grundlinie wie der To-Top-Button und um dessen Breite
   (48px) plus Abstand nach links versetzt - das erbt er unveraendert von
   .hero__scroll-cue, hier wird nur der Farbton angepasst. */
.hero__scroll-cue--intro {
  color: rgba(255, 255, 255, 0.6);
}

/* Niedrige Fenster (Laptops mit ~800-900px Innenhoehe): seit die
   Kennzahlen-Reihe in den Preloader gewandert ist, traegt diese Sektion
   nur noch Foto + Text und passt dort wieder ohne die frueheren
   Schrumpf-Kompromisse (0.875rem Fliesstext) auf einen Bildschirm.
   Geblieben ist nur die massvolle Enger-Setzung von Abstaenden, damit
   der Scroll-Hinweis am unteren Rand sicher frei bleibt. */
@media (min-width: 1024px) and (max-height: 860px) {
  .intro {
    padding-top: calc(var(--nav-pill-h) + var(--space-md));
    padding-bottom: calc(var(--space-2xl) + var(--space-md));
    gap: clamp(var(--space-md), 3vw, var(--space-xl));
  }
  .intro__text p {
    line-height: 1.65;
  }
}

/* Sehr flache Fenster (<=780px Innenhoehe, z.B. 1280x720-Laptops): dort
   reicht die Entlastung oben nicht - Fliesstext und Button liefen unter
   die Falz. Hier wird der Text zusaetzlich enger gesetzt und das Portraet
   in der Hoehe gedeckelt, damit Ueberschrift, Text UND der Kontakt-Button
   gemeinsam auf den einen Bildschirm passen. */
@media (min-width: 1024px) and (max-height: 780px) {
  .intro {
    padding-bottom: calc(var(--space-2xl) + var(--space-2xs));
    gap: var(--space-lg);
  }
  .intro__title {
    font-size: clamp(1.15rem, 0.85vw + 0.92rem, 1.45rem);
  }
  .intro__text {
    gap: var(--space-2xs);
  }
  .intro__text p {
    font-size: 0.875rem;
    line-height: 1.58;
  }
  /* Beim freigestellten Portraet steuert die Bildhoehe direkt, wie viel
     Platz die Person einnimmt - hier deutlich enger deckeln, damit
     Ueberschrift, Text und Button gemeinsam auf den flachen Bildschirm
     passen. */
  .intro__photo img {
    max-height: 62svh;
  }
}

/* Ab hier kein Nebeneinander mehr: bei zwei Spalten unter ~1024px bleiben
   fuer den langen Text keine lesbaren Zeilen mehr uebrig. Portraet oben,
   Text darunter - und die Sektion darf ueber 100svh hinauswachsen, sonst
   wuerde das overflow:hidden von .hero den Text abschneiden. */
@media (max-width: 1023px) {
  .hero--intro {
    /* Einspaltig darf die Buehne ueber den Bildschirm hinauswachsen -
       die 100svh-Kopplung der Desktop-Variante wird hier aufgehoben,
       Rundung und Randabstand bleiben. */
    min-height: auto;
    padding-bottom: var(--space-2xl);
  }
  /* Die Impact-Buehne bekommt Rand und Rundung erst ab 1024px (dort steckt
     ihre sticky-Bauform). Darunter stand sie randlos ueber die volle
     Breite, waehrend die Intro-Buehne darueber ihren Rand behielt - die
     beiden Flaechen waren also unterschiedlich breit. Hier dieselben
     Tokens, damit die Kante auch einspaltig symmetrisch laeuft. */
  .hero--impact {
    margin-inline: var(--stage-inset);
    border-radius: var(--stage-radius);
    overflow: hidden;
  }
  .intro__glow {
    /* Einspaltig sitzt das Portraet mittig oben statt links - der
       Lichtkegel wandert mit, sonst leuchtet er neben der Person. */
    left: 50%;
    top: 2%;
    width: min(88%, 460px);
    transform: translateX(-50%);
  }
  .intro {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    padding-inline: var(--space-md);
    gap: var(--space-lg);
  }
  /* Einspaltig: das freigestellte Portraet steht ueber dem Text und wird
     ueber die Bildbreite begrenzt (frueher ueber die Kachelmasse). */
  .intro__photo img {
    width: min(300px, 66vw);
    max-height: 46svh;
  }
  .intro__body {
    align-items: center;
  }
  .intro__text {
    text-align: left;
  }
  .hero__scroll-cue--intro { display: none; }
}

/* -----------------------------------------------------------------------
   Scroll-Buehne der Leistungs-Sequenz
   -----------------------------------------------------------------------
   Die Sektion bekommt Zusatzhoehe, ihr Inhalt (.hero__variant--sticky)
   klebt per position:sticky am Viewport. Der Nutzer scrollt normal und
   ohne jede Sperre durch diese Zusatzhoehe - der sichtbare Fortschritt der
   Sequenz (0..TOTAL_BEATS, siehe initHeroFieldSequence in script.js) ergibt
   sich direkt aus der Scrollposition innerhalb der Sektion, kein
   preventDefault/body-overflow-Abfangen mehr noetig. Ohne die Zusatzhoehe
   waere die Buehne nach einem einzigen Scroll-Frame schon durchgescrollt,
   bevor irgendeine Kurve gezeichnet ist.
   Nur ab 1024px: darunter sind die Icons ohnehin ausgeblendet und die
   Sequenz spielt keine Rolle - dort bleibt die Sektion normal hoch. */
@media (min-width: 1024px) {
  .hero--impact {
    /* Kein eigener oberer Rand: die Fuge zur Intro-Buehne traegt deren
       margin-bottom allein (siehe dort - senkrechte Raender wuerden sonst
       zusammenfallen statt sich zu addieren). */
    /* Buehnenhoehe = TOTAL_BEATS (7, siehe initHeroFieldSequence - Chatbot
       und Webdesign bekamen einen zusaetzlichen eigenen Beat statt sich
       einen zu teilen) x Strecke je Beat + 1 Bildschirmhoehe fuer die
       sticky Buehne selbst, die am Ende des letzten Beats stehen bleibt,
       bevor die naechste Sektion folgt. 90svh je Beat: genug Strecke, um
       jede Etappe (Icon einschweben, Kurve zeichnen, Badge andocken) in
       normalem Scrolltempo nachvollziehbar zu lesen, ohne dass die
       Sektion unnoetig lang wird. */
    min-height: calc(7 * 90svh + 100svh);
    /* overflow:hidden von .hero wuerde position:sticky im Inneren
       wirkungslos machen. */
    overflow: visible;
  }

  /* Nach dem einmaligen Durchlauf ist die Zusatzhoehe nur noch leere
     Scrollstrecke: die Choreografie laeuft nicht mehr (siehe
     sequenceDone in initHeroFieldSequence), das Bild steht fest, aber
     man musste weiterhin rund 4900px durchscrollen, um an der Sektion
     vorbeizukommen - vorwaerts wie rueckwaerts.
     Mit data-seq-collapsed schrumpft sie auf eine Bildschirmhoehe und
     verhaelt sich damit wie jede andere Sektion. Das sticky-Kleben
     entfaellt dabei von selbst, weil keine Reststrecke mehr da ist,
     an der es kleben koennte. */
  .hero--impact[data-seq-collapsed] {
    min-height: 100svh;
  }
  .hero--impact[data-seq-collapsed] .hero__variant--sticky {
    position: relative;
    top: auto;
  }
  .hero__variant--sticky {
    position: sticky;
    /* Buehne als gerahmte Flaeche statt randlos ueber den ganzen
       Bildschirm: etwas Luft ringsum und abgerundete Ecken lassen sie
       als eigenes "Fenster" lesen, in dem die Sequenz ablaeuft.
       top/height rechnen den Rand mit, damit sie weiterhin exakt in den
       sichtbaren Bereich passt und nicht ueber die Falz hinauswaechst. */
    /* Rand und Radius kommen aus denselben globalen Tokens wie die
       Intro-Buehne darueber (Block 2) - vorher hatte diese Buehne eigene
       Werte (12-34px statt 12-20px) und war dadurch sichtbar schmaler
       als die Flaeche direkt darueber. */
    top: var(--stage-inset);
    height: calc(100svh - 2 * var(--stage-inset));
    margin-inline: var(--stage-inset);
    border-radius: var(--stage-radius);
    overflow: hidden;
    /* Feine Kante, damit der Rahmen auch dort sichtbar bleibt, wo die
       Buehne farblich dicht am Seitenhintergrund liegt. */
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08),
                0 24px 60px rgba(8, 12, 20, 0.28);
  }
}

/* Eigenstaendiges Fade-Overlay ueber die GESAMTE Hero-Breite (nicht nur
   den Bild-Container): traegt den Uebergang von dunklem Foto-Bereich
   links zu hellem Seiten-Weiss rechts, wo der Chart verlaeuft. Liegt ueber
   dem Bild, aber unter Chart/Content (z-index 1, wie .hero__chart).
   Zweite (vertikale) Ebene haelt den UNTEREN Bereich (Titel, Flietext,
   Stats-Karten) dunkel genug fuer weisse Schrift, waehrend es oben/rechts
   hell und luftig um den Chart wird - sonst waere weisser Text auf dem
   hellen Fade unlesbar. */
.hero__fade {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg,
      rgba(16, 24, 40, 0) 0%,
      rgba(16, 24, 40, 0) 52%,
      rgba(16, 24, 40, 0.55) 78%,
      rgba(16, 24, 40, 0.82) 100%),
    linear-gradient(90deg,
      rgba(16, 24, 40, 0) 0%,
      rgba(16, 24, 40, 0) 22%,
      var(--color-bg) 68%,
      var(--color-bg) 100%);
}

/* Aktienkurs-Linie: startet links schwankend, laeuft zur Person, steigt
   danach sichtbar bis zum rechten Rand. viewBox 1440x900 = vh-Prozente
   direkt als y-Koordinaten (y=675 -> 75vh, y=225 -> 25vh). */
.hero__chart {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  /* Der Chart-Container selbst bleibt klickdurchlaessig (Text/Buttons
     darueber duerfen nicht blockiert werden) - nur die einzelnen
     Hit-Zonen-Pfade unten bekommen explizit pointer-events zurueck. */
  pointer-events: none;
}
.hero__chart-line {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 3;
  /* Gleiche Begruendung wie bei .hero__chart-contour. */
  stroke-linecap: butt;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 6px rgba(255, 214, 102, 0.5));
  /* "1000 5000" statt nur "1000": ein einzelner dasharray-Wert wird von
     SVG als sich wiederholendes Paar Strich/Luecke interpretiert (hier
     1000 Strich, 1000 Luecke). Die tatsaechliche Pfadlaenge (getTotalLength,
     abhaengig von der Geometrie) liegt oft ueber 1000 trotz pathLength="1000"
     (normalisiert nur die dashoffset-Einheiten, nicht die echte Laenge) -
     dadurch begann nach der ersten Luecke ein zweiter Strich-Zyklus und
     zeigte ein sichtbares Fragment am Pfadende, VOELLIG unabhaengig vom
     Zeichenfortschritt (stroke-dashoffset). Der lange zweite Wert (5000)
     stellt sicher, dass die Luecke garantiert laenger als jeder
     vorkommende Pfad ist - der Zyklus kann sich innerhalb des Pfads nie
     wiederholen. */
  stroke-dasharray: 1000 5000;
  stroke-dashoffset: 1000;
  /* Gleiche Begruendung wie bei .hero__chart-contour: der volle
     dashoffset allein laesst am Pfadende einen sichtbaren Rest stehen
     (runde Enden + Leuchtschatten). Sichtbar wird die Linie erst mit
     .is-drawing. */
  opacity: 0;
  transition: stroke-width 180ms var(--ease-out), filter 180ms var(--ease-out);
}
/* Hover-Hervorhebung (siehe setHoverHighlight in initChartHover): nur auf
   fertig gezeichneten (.is-live) Kurven wirksam - waehrend des Zeichnens
   selbst ist die Trefferzone noch nicht aktiv, siehe isLive() im JS. */
.hero__chart-line.is-hovered {
  stroke-width: 5;
  filter: drop-shadow(0 0 10px rgba(255, 214, 102, 0.8));
}

/* Sichtbare, duenne Konturlinien der vier Hintergrundkurven (indigo/violet/
   green/cyan) - macht erkennbar, dass dort Kurven mit eigenen Messwerten
   liegen, statt reiner Farbflaechen ohne Kante. pointer-events:none: Hover
   bleibt exklusiv Aufgabe von .hero__chart-hitzone. Gleiches stroke-dasharray/
   -dashoffset-Prinzip wie .hero__chart-line, damit sie beim Erscheinen
   ebenfalls "gezeichnet" wirken statt einfach einzublenden. */
.hero__chart-contour {
  fill: none;
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  /* butt statt round: bei stroke-dasharray zeichnet ein runder Abschluss
     auch am noch NICHT gezeichneten Ende eine Kappe - auf einer langen,
     duennen Kurve erscheint die als loses Liniensegment am gegenueber-
     liegenden Bildrand, obwohl die Kurve dort noch gar nicht ist. Genau
     diese Fragmente. Ist die Kurve fertig (.is-live), schaltet sie auf
     runde Enden zurueck, wo sie optisch etwas weicher wirken. */
  stroke-linecap: butt;
  stroke-linejoin: round;
  pointer-events: none;
  /* Ruhezustand ist UNSICHTBAR (opacity 0), nicht 0.55: der volle
     stroke-dashoffset allein genuegt nicht - bei non-scaling-stroke und
     runden Enden bleiben am Pfadende sichtbare Reste stehen. Genau die
     standen als blasse Kurvenstuecke rechts oben im Bild, bevor die
     Sequenz ueberhaupt begonnen hatte. Die Deckkraft von 0.55 setzt erst
     die .is-drawing-Regel, gemeinsam mit dem Zeichnen. */
  opacity: 0;
  /* "1000 5000" statt nur "1000": ein einzelner dasharray-Wert wird von
     SVG als sich wiederholendes Paar Strich/Luecke interpretiert (hier
     1000 Strich, 1000 Luecke). Die tatsaechliche Pfadlaenge (getTotalLength)
     liegt bei diesen Kurven ueber 1000 (pathLength="1000" normalisiert nur
     die dashoffset-Einheiten, nicht die echte Geometrie-Laenge) - dadurch
     begann nach der ersten Luecke ein zweiter Strich-Zyklus und zeigte ein
     sichtbares Fragment am Pfadende, VOELLIG unabhaengig vom Zeichenfort-
     schritt (stroke-dashoffset) und von opacity:0 (das Fragment blieb auch
     dann sichtbar). Der lange zweite Wert (5000) stellt sicher, dass die
     Luecke garantiert laenger als jeder vorkommende Pfad ist. */
  stroke-dasharray: 1000 5000;
  stroke-dashoffset: 1000;
  /* Muss dieselbe Y-Verschiebung tragen wie die zugehoerige .hero__chart-
     area--* (--layer-y-rest, siehe dort): die Flaechen sind einzeln nach
     unten versetzt (Tiefenstaffelung), ohne diesen Versatz liegt die
     Konturlinie oberhalb der oberen Kante ihrer eigenen Flaeche - genau die
     sichtbaren Luecken zwischen Linie und Farbflaeche. */
  transform-box: fill-box;
  transform: translateY(var(--layer-y-rest, 0px));
  transition: stroke-width 180ms var(--ease-out), opacity 180ms var(--ease-out);
}
.hero__chart-contour.is-live { stroke-linecap: round; }
/* Hover-Hervorhebung (siehe setHoverHighlight in initChartHover): nur auf
   fertig gezeichneten (.is-live) Kurven wirksam, da die Trefferzone davor
   noch nicht aktiv ist (isLive() im JS). */
.hero__chart-contour.is-hovered { stroke-width: 4; opacity: 0.9; }
.hero__chart-contour--indigo { stroke: #8fa8e6; --layer-y-rest: 8px; }
.hero__chart-contour--violet { stroke: #b3a6ff; --layer-y-rest: 22px; }
.hero__chart-contour--green { stroke: #3ddc97; --layer-y-rest: 40px; }
.hero__chart-contour--cyan { stroke: #22d3ee; --layer-y-rest: 31px; }
.hero__chart-contour--amber { stroke: #e3c88e; --layer-y-rest: 0px; }

/* indigo/violet (Social Media/E-Mail) gehoeren jetzt zur neuen, JS-
   gesteuerten Einzel-Sequenz (initHeroFieldSequence): .is-drawing wird
   gezielt just-in-time gesetzt, statt per festem --hero-step-Delay parallel
   zu allem anderen zu starten. green/cyan bleiben unangetastet auf dem
   alten [data-hero-sequence="go"]-Mechanismus (keiner der 6 OMB-Leistungen
   zugeordnet, siehe Analyse - werden bewusst nicht in die neue Sequenz
   aufgenommen). */
/* Die Kurven werden nicht mehr per CSS-Animation gezeichnet: eine
   @keyframes-Animation laeuft nur vorwaerts und liesse sich beim
   Zurueckscrollen nicht zurueckdrehen. initHeroFieldSequence setzt
   stroke-dashoffset deshalb direkt aus der Scrollposition. Die Regeln
   hier bleiben als Endzustand fuer reduced motion. */
.hero__chart-contour--indigo.is-drawing,
.hero__chart-contour--violet.is-drawing {
  stroke-dashoffset: 0;
  opacity: 0.55;
}
/* green/cyan/amber (Chatbot/SEM/Webdesign) laufen seit der Erweiterung
   auf alle sechs Leistungsfelder ebenfalls ueber die JS-Sequenz - der
   frueher hier stehende feste --hero-step-Delay wuerde sie sonst schon
   zeichnen, bevor ihr Icon ueberhaupt angedockt ist. */
.hero__chart-contour--green.is-drawing,
.hero__chart-contour--cyan.is-drawing,
.hero__chart-contour--amber.is-drawing {
  stroke-dashoffset: 0;
  opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
  .hero__chart-contour { animation: none; stroke-dashoffset: 0; opacity: 0.55; }
}

/* Unsichtbare, breite Trefferflaeche entlang jeder Kurve: die duenne
   Hauptlinie (stroke-width 3) und die Konturen der Flaechenkurven waeren
   sonst kaum zuverlaessig zu hovern. vector-effect haelt die Trefferzone
   in Bildschirm-Pixeln konstant breit, unabhaengig von der SVG-Skalierung
   (viewBox 1440x900 wird responsiv gestreckt).
   Traegt denselben --layer-y-rest-Offset wie .hero__chart-area/-contour
   (ueber dieselben Modifier-Klassen unten), damit die Trefferflaeche exakt
   auf der sichtbar versetzten Kurve liegt statt auf den unverschobenen Roh-
   koordinaten - initChartHover() in script.js rechnet denselben Offset auf
   den per SVG-API berechneten Punkt drauf (CSS-transform wirkt nicht auf
   getPointAtLength/getTotalLength). */
.hero__chart-hitzone {
  fill: none;
  stroke: transparent;
  /* 11px Trefferbreite: seit die Kurvenenden auf die Badge-Positionen
     ausgerichtet sind, laufen indigo und cyan im rechten Bildteil dicht
     nebeneinander. Bei 18px verschluckte die zuletzt gezeichnete Zone
     (cyan) den Hover ihrer Nachbarin - der Tooltip zeigte dann deren
     Kennzahl. 16px bleibt bequem treffbar; die zuverlaessige Trennung
     uebernimmt der Messpunkt-Hover (siehe .hero__chart-dot), der als
     eigenes Element ueber den Zonen liegt und immer seine eigene Kurve
     meldet. */
  stroke-width: 16;
  vector-effect: non-scaling-stroke;
  pointer-events: stroke;
  cursor: crosshair;
  transform-box: fill-box;
  transform: translateY(var(--layer-y-rest, 0px));
}
.hero__chart-hitzone[data-metric="indigo"] { --layer-y-rest: 8px; }
.hero__chart-hitzone[data-metric="violet"] { --layer-y-rest: 22px; }
.hero__chart-hitzone[data-metric="green"] { --layer-y-rest: 40px; }
.hero__chart-hitzone[data-metric="cyan"] { --layer-y-rest: 31px; }
@media (max-width: 1023px) {
  /* Kein Hover-Konzept auf Touch-Geraeten - Trefferzonen aus dem
     Ereignisfluss nehmen, damit sie z.B. Scroll-Gesten nicht stoeren. */
  .hero__chart-hitzone { pointer-events: none; }
}

/* Tooltip: folgt dem Cursor beim Abfahren einer Kurve, zeigt Kanal-
   Bezeichnung + Beispielwert an der jeweiligen X-Position. */
.hero__chart-tip {
  position: absolute;
  z-index: 4;
  transform: translate(-50%, calc(-100% - 14px));
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  background: rgba(16, 24, 40, 0.92);
  color: #fff;
  font-size: 0.75rem;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 8px 20px rgba(16, 24, 40, 0.3);
}
.hero__chart-tip::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -5px;
  width: 10px;
  height: 10px;
  transform: translateX(-50%) rotate(45deg);
  background: inherit;
}
.hero__chart-tip-label {
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-size: 0.6875rem;
  color: rgba(255, 255, 255, 0.65);
}
.hero__chart-tip-value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--color-accent);
}
.hero__chart-tip[hidden] { display: none; }

/* Messpunkt-Marker auf der Kurve: Position (cx/cy) und Farbe (--point-color)
   werden in showTip() per JS auf die aktuelle Cursor-Projektion gesetzt,
   sichtbar wird er nur waehrend des Hovers (siehe .is-visible/hideTip). Ein
   dezenter Ring-Puls beim Erscheinen macht den Trefferpunkt greifbarer, als
   es der Tooltip allein leisten kann. vector-effect haelt Radius/Kontur beim
   Strecken des viewBox konstant. */
/* -----------------------------------------------------------------------
   Kennwert-Anzeigen (Chatbot / Webdesign)
   -----------------------------------------------------------------------
   Beide Leistungen liefern keine wachsende Zeitreihe, sondern Quoten bzw.
   Zustandswerte - ein Ring, der sich bis zu seinem Wert fuellt, bildet das
   ehrlicher ab als eine steigende Linie. Sitzt an derselben Stelle, an der
   sonst die Kurve entstuende: mittig rechts im Chart.
   ----------------------------------------------------------------------- */
.hero__gauge {
  position: absolute;
  top: var(--gauge-top, 50%);
  left: var(--gauge-left, 52%);
  z-index: 3;
  width: clamp(120px, 12vw, 168px);
  transform: translate(-50%, -50%) scale(0.92);
  opacity: 0;
  pointer-events: none;
  transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out);
}
.hero__gauge.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.hero__gauge svg {
  width: 100%;
  height: auto;
  /* -90deg: der Ring beginnt oben statt rechts. */
  transform: rotate(-90deg);
}

.hero__gauge-track {
  fill: none;
  stroke: rgba(255, 255, 255, 0.16);
  stroke-width: 9;
}

.hero__gauge-fill {
  fill: none;
  stroke: var(--gauge-color, var(--color-accent));
  stroke-width: 9;
  stroke-linecap: round;
  /* pathLength=100 im Markup: dasharray/-offset rechnen damit direkt in
     Prozent, unabhaengig vom tatsaechlichen Kreisumfang. "100 400" statt
     nur "100": gleiche Vorsichtsmassnahme wie bei .hero__chart-line/-contour
     (siehe dort) - ein einzelner dasharray-Wert wiederholt sich als
     Strich/Luecke-Muster, ein ausreichend grosser zweiter Wert verhindert
     einen zweiten Strich-Zyklus innerhalb des Kreisumfangs. */
  stroke-dasharray: 100 400;
  stroke-dashoffset: calc(100 - 100 * var(--gauge, 0));
  filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.25));
}

.hero__gauge--green { --gauge-color: #3ddc97; }
.hero__gauge--amber { --gauge-color: #e3c88e; }

.hero__gauge-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: #fff;
  font-size: clamp(0.7rem, 0.6vw + 0.55rem, 0.85rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 3px rgba(8, 12, 20, 0.7);
}

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

@media (max-width: 1023px) {
  .hero__gauge { display: none; }
}

/* Feste Messpunkte auf den Kurven (per JS erzeugt, siehe buildDots in
   initChartHover). Sie machen von sich aus sichtbar, dass hinter den
   Kurven Werte liegen - vorher musste man zufaellig darueberfahren, um
   das zu merken. Erscheinen erst, wenn ihre Kurve fertig gezeichnet ist
   (.is-visible wird aus .is-live der Kurve abgeleitet). */
.hero__chart-dots {
  pointer-events: none;
}

.hero__chart-dot {
  fill: var(--dot-color, var(--color-accent));
  stroke: rgba(16, 24, 40, 0.9);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  /* Trefferflaeche etwas grosszuegiger als der sichtbare Punkt: r=6 ist
     als Ziel fuer die Maus knapp, ohne dass der Punkt optisch klobig
     wirken soll. */
  r: 6;
  pointer-events: none;
  cursor: crosshair;
  transition: opacity 260ms var(--ease-out), r 160ms var(--ease-out);
}

.hero__chart-dot.is-visible {
  opacity: 0.9;
  pointer-events: auto;
}



.hero__chart-dot.is-visible:hover,
.hero__chart-dot.is-active,
.hero__chart-dot.is-visible:focus-visible {
  opacity: 1;
  r: 9;
}

@media (prefers-reduced-motion: reduce) {
  .hero__chart-dot { transition: none; }
}

/* Auf Touch-Geraeten gibt es kein Hover-Konzept - dort waeren die Punkte
   nur Dekoration, die die Kurven zusetzt. */
@media (max-width: 1023px) {
  .hero__chart-dots { display: none; }
}

.hero__chart-point {
  fill: var(--point-color, var(--color-accent));
  stroke: rgba(16, 24, 40, 0.85);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  pointer-events: none;
  filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.25));
  transition: opacity 120ms var(--ease-out);
}
.hero__chart-point.is-visible { opacity: 1; }

/* Einmaliger Hover-Hinweis (siehe initChartHint in script.js): ein kleiner
   Cursor + Beschriftung, der einmal ueber den Chart wandert, sobald die
   Kurven fertig gezeichnet sind, und danach von selbst verblasst. .is-active
   steuert Start/Ende der Bewegung, damit die Animation erst beginnt, wenn
   JS sie tatsaechlich ausloest (kein Autoplay beim Laden). */
.hero__chart-hint {
  position: absolute;
  z-index: 5;
  top: 58%;
  left: 8%;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.85rem 0.4rem 0.5rem;
  border-radius: var(--radius-pill);
  background: rgba(16, 24, 40, 0.9);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  box-shadow: 0 8px 20px rgba(16, 24, 40, 0.3);
}
.hero__chart-hint svg { width: 16px; height: 16px; flex: none; color: var(--color-accent); }
.hero__chart-hint[hidden] { display: none; }
.hero__chart-hint.is-active {
  animation: chart-hint-travel 3400ms var(--ease-out) forwards;
}

@keyframes chart-hint-travel {
  0%   { opacity: 0; left: 6%; }
  12%  { opacity: 1; }
  80%  { opacity: 1; left: 70%; }
  100% { opacity: 0; left: 78%; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__chart-hint.is-active { animation: none; opacity: 0; }
}

/* Leistungsfeld-Icon (aktuell nur SEO): erscheint links neben dem Chart,
   auf Hoehe des Startpunkts der zugehoerigen Kurve. --icon-top wird je
   Icon inline gesetzt (analog zu --kpi-top bei den KPI-Badges).
   Timing: --hero-step-1 der organic-Kurve liegt bei 0ms (Sequenzstart) -
   eine spaetere CSS-Animation kann nicht "davor" beginnen, da das
   [data-hero-sequence="go"]-Attribut selbst erst den Start markiert. Das
   Icon bekommt daher eine kurze 350ms-Fade-in-Dauer direkt bei 0ms, die
   abgeschlossen ist, bevor die 900ms lange chart-draw-Animation der Kurve
   sichtbaren Fortschritt zeigt - dadurch wirkt das Icon als "zuerst da,
   dann folgt die Kurve" statt beide gleichzeitig einzublenden. */
.hero__field-icon {
  /* top sitzt auf DIESEM Container (relativ zu .hero__variant, derselben
     Bezugsflaeche wie das Chart-SVG) - --icon-top ist ein Prozentsatz von
     dessen Hoehe. Wuerde top stattdessen auf dem SVG-Kind gesetzt, waere
     es relativ zur (impliziten, hier 0) Hoehe DIESES Containers und damit
     wirkungslos - das war der eigentliche Fehler in der Vorversion. Das
     SVG bekommt nur noch die reine Zentrierungs-/Skalierungs-Transform. */
  position: absolute;
  z-index: 3;
  top: var(--icon-top, 50%);
  /* --icon-left ueberschreibbar (Default 1.5%, am Chart-Rand): wenn zwei
     Icons auf eng beieinanderliegenden Kurven landen (z.B. Social Media/
     E-Mail nur 6 Prozentpunkte Chart-Hoehe auseinander), ruecke das juengere
     der beiden Icons per inline --icon-left weiter nach rechts, statt beide
     exakt uebereinander zu stapeln - bleibt weiterhin auf seiner eigenen
     Kurvenachse (--icon-top) zentriert, nur horizontal leicht gestaffelt. */
  left: var(--icon-left, 1.5%);
  /* Feste Breite noetig, nicht nur Kosmetik: der globale Reset
     "img, picture, svg { max-width: 100%; }" (Zeile ~137) rechnet sonst
     100% von der sonst impliziten Container-Breite 0 aus und kappt das
     SVG unsichtbar auf 0px, egal welches width das SVG selbst traegt.
     56px (statt urspruenglich 84px): mit mehreren Icons auf eng
     beieinanderliegenden Kurven (z.B. Social Media/E-Mail nur 6
     Prozentpunkte Chart-Hoehe auseinander) ueberlappten sich Label und
     naechstes Icon bei der groesseren Groesse sichtbar. */
  width: 56px;
  /* Sichtbarkeit wird ueber data-icon-state/.is-hidden gesteuert (siehe
     die [data-icon-state="..."]-Regeln unten), nicht mehr ueber eine
     initiale opacity:0 + Fade-in-Animation. */
  opacity: 1;
  pointer-events: none;
  filter: drop-shadow(0 4px 10px rgba(8, 12, 20, 0.35));
}
.hero__field-icon svg {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 56px;
  height: 56px;
  /* scale(1) als Basis: Icons sind jetzt von Anfang an im "gather"-
     Zustand sichtbar (kein Pop-in-Einblenden aus scale(0.7) mehr noetig -
     initHeroFieldSequence steuert Sichtbarkeit ueber data-icon-state/
     is-hidden, nicht mehr ueber eine Grow-in-Animation). */
  transform: translateY(-50%) scale(1);
}
.hero__field-icon-label {
  /* Gleiche Typo-Konvention wie .eyebrow (font-base, 700, 0.08em, uppercase),
     nur in Weiss statt --color-primary wegen des dunklen Hero-Hintergrunds.
     Absolut ueber dem Icon platziert (nicht im Fluss davor), damit sie
     dessen vertikale Zentrierung auf der Kurvenachse nicht verschiebt.
     left/right statt fixer width: laengere Labels ("Social Media") duerfen
     ueber die 56px breite Icon-Flaeche hinausragen, ohne umzubrechen -
     nowrap + zentrierter Ueberhang nach beiden Seiten via negativem Inset. */
  position: absolute;
  top: calc(-28px - 0.4rem);
  /* Ueberhang nach links begrenzt, nach rechts grosszuegig: die Icons
     sitzen alle am LINKEN Chart-Rand, ein symmetrischer Ueberhang schob
     lange Namen ("Social Media Marketing") aus dem Bild. Linksbuendig ab
     der Icon-Kante laeuft der Text stattdessen ins freie Chart hinein. */
  left: 0;
  right: auto;
  min-width: 56px;
  text-align: left;
  white-space: nowrap;
  font-family: var(--font-base);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 8px rgba(8, 12, 20, 0.6);
}

/* Opacity auf dem Container (faedet Label + Icon gemeinsam ein), der
   Scale-Pop dagegen auf dem SVG selbst (siehe .hero__field-icon svg oben) -
   der Container traegt keine eigene Groesse/Zentrierung mehr, auf ihm
   wuerde ein transform hier nichts sichtbar bewegen. Generische Regel fuer
   ALLE .hero__field-icon (nicht mehr auf --seo beschraenkt): --icon-delay
   wird je Icon inline gesetzt (0ms Default = Sequenzstart wie beim SEO-
   Icon; spaetere Icons wie Social Media setzen einen positiven Delay, der
   kurz VOR dem Start ihrer jeweiligen Kurve liegt). */
/* ---- Neue Sequenz-Zustaende (initHeroFieldSequence, script.js) --------
   data-icon-state="gather": zentriert in einer Reihe in der Bildschirm-
     mitte (--gather-order steuert die horizontale Reihenfolge/den
     Versatz), mit Auf-ab-Pulsieren. Ausgangszustand beim Sektionseintritt.
   .is-hidden (zusaetzlich zu "gather"): fuer die Icons, die gerade NICHT
     fokussiert sind - blenden aus, sobald ein Icon in den Fokus geht.
   data-icon-state="placed": wandert von der Gather-Position (Mitte) zur
     finalen Position (--icon-top/--icon-left, Kurvenachse) per CSS-
     transition statt Animation, damit JS per transitionend zuverlaessig
     erkennt, wann die Bewegung fertig ist (Voraussetzung fuer "Kurve
     startet ERST wenn Icon angekommen ist"). ------------------------- */
/* --seq-move: Dauer der Icon-Wanderbewegung (Gather-Position -> finale
   Position). Bei kontinuierlichem Scroll-Scrubbing (siehe initHeroField-
   Sequence) ist der sichtbare Fortschritt direkt an die Scrollposition
   gekoppelt, diese Transition sorgt nur noch fuer ein weiches Nachziehen
   zwischen zwei Scroll-Frames statt fuer echtes Zeit-Timing. */
.hero__field-icon {
  transition: top var(--seq-move, 420ms) var(--ease-out),
              left var(--seq-move, 420ms) var(--ease-out),
              opacity 400ms var(--ease-out);
}
/* Zentrierung der Sammel-Reihe: --gather-count haelt fest, wie viele
   Icons nebeneinander stehen (sechs seit der Erweiterung auf alle
   Leistungsfelder). Der Versatz nach links betraegt die halbe Reihen-
   breite, damit die Reihe unabhaengig von der Anzahl mittig sitzt -
   frueher war die "-76px" fest auf drei Icons gerechnet und die Reihe
   waere bei sechs Icons sichtbar nach rechts gerutscht.
   Auf schmaleren Fenstern werden die Icons enger gesetzt (siehe
   Media Query unten), sonst reicht die Reihe ueber den Chart hinaus. */
/* Labels sind in der Sammel-Phase ausgeblendet: sechs Namen, darunter
   "Suchmaschinenmarketing" und "E-Mail-Kampagnen", sind deutlich breiter
   als der Icon-Abstand und liefen zu einem unlesbaren Textbrei
   ineinander. Sobald ein Icon in den Fokus geht und an der Kurve andockt
   (state="placed"), steht es allein - dort ist das Label lesbar und wird
   wieder eingeblendet. */
/* Im Sammel-Zustand ausgeblendet (siehe Begruendung oben) UND aus dem
   Weg geschoben: das Label sitzt auf halber Icon-Hoehe ueber dem Icon,
   berechnet fuer die Normalgroesse. Im vergroesserten Zustand (Faktor
   1.5) waechst das Icon nach oben darueber hinaus, sodass Schrift und
   Grafik sichtbar uebereinander lagen, sobald ein Icon zur Kurve flog. */
.hero__field-icon[data-icon-state="gather"] .hero__field-icon-label {
  opacity: 0;
  transform: translateY(-16px);
}
.hero__field-icon .hero__field-icon-label {
  transition: opacity 300ms var(--ease-out);
}

/* ---- Zustaende der scroll-getriebenen Sequenz ----------------------
   Jeder Zustand entspricht einem Schritt im Storyboard; --t (0..1, von
   JS gesetzt) ist der Fortschritt INNERHALB des jeweiligen Schritts.
   Weil jeder Zustand seine Zielwerte selbst kennt, ergibt sich die
   Bewegung allein aus dem Zustandswechsel - und laeuft beim
   Zurueckscrollen genauso rueckwaerts.

   hidden -> noch nicht vorgestellt, unsichtbar
   intro  -> gross in der Bildmitte, voller Name darunter
   row    -> Platz in der 6er-Reihe (Bildmitte), Kuerzel
   park   -> Reihe geschrumpft, hoehere Warteposition, pulsiert
   step   -> tritt aus dem Platzhalter hervor, gross in die Mitte
   placed -> finale Position an der eigenen Kurve
   ------------------------------------------------------------------- */

/* Gemeinsame Grundlage: die Bewegung zwischen zwei Zustaenden laeuft als
   CSS-Transition. Kurz genug, dass sie dem Scrollen folgt statt
   hinterherzulaufen. */
.hero__field-icon[data-icon-state] {
  transition: top 420ms var(--ease-out), left 420ms var(--ease-out),
              opacity 300ms var(--ease-out);
}

/* ---- hidden ---- */
.hero__field-icon[data-icon-state="hidden"] {
  top: 50%;
  left: 50%;
  margin-left: -28px;
  opacity: 0;
  pointer-events: none;
}
.hero__field-icon[data-icon-state="hidden"] svg {
  transform: translateY(-50%) scale(0.6);
}

/* ---- intro: gross mittig, voller Name ---- */
.hero__field-icon[data-icon-state="intro"] {
  top: 50%;
  left: 50%;
  margin-left: -28px;
  z-index: 6;
  opacity: var(--t, 1);
}
.hero__field-icon[data-icon-state="intro"] svg {
  transform: translateY(-50%) scale(calc(2.6 * (0.72 + 0.28 * var(--t, 1))));
  transition: none;
}
.hero__field-icon[data-icon-state="intro"] .hero__field-icon-label {
  top: auto;
  bottom: -104px;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: max-content;
  text-align: center;
  font-size: clamp(1rem, 1.1vw + 0.75rem, 1.35rem);
  letter-spacing: 0.04em;
  opacity: var(--t, 1);
}

/* ---- row: Platz in der 6er-Reihe, Bildmitte ---- */
.hero__field-icon[data-icon-state="row"] {
  --row-gap: clamp(76px, 7.6vw, 112px);
  /* 21% statt urspruenglich 50%: sobald die erste Kurve zeichnet, laeuft
     sie von links unten nach rechts oben quer durch die Bildmitte und
     ueberzeichnete die dort wartenden Icons. Im X-Band der Reihe steigt
     die hoechste Kurve (organic/SEO) bis auf 31% der Fensterhoehe -
     gemessen, nicht geschaetzt. Mit 21% Mittellinie steht die Reihe
     samt Beschriftung (~65px hoch) vollstaendig darueber. */
  top: 21%;
  left: calc(50% + var(--block-order, 0) * var(--row-gap)
             - 2.5 * var(--row-gap) - 28px);
  margin-left: 0;
  opacity: 1;
  z-index: 4;
}
/* Kuerzel unter dem Icon der 6er-Reihe. Ohne eigene Regel griff die
   breite Standard-Beschriftung, wodurch "Social Media" und "Chatbot"
   ineinander liefen. Knapper als der Icon-Abstand, Rest bricht um. */
.hero__field-icon[data-icon-state="row"] .hero__field-icon-label {
  opacity: 1;
  top: auto;
  bottom: -40px;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(var(--row-gap) - 12px);
  text-align: center;
  white-space: normal;
  font-size: 0.58rem;
  line-height: 1.2;
  letter-spacing: 0.03em;
}

.hero__field-icon[data-icon-state="row"] svg {
  transform: translateY(-50%) scale(1.15);
}

/* ---- park: geschrumpft, hoehere Warteposition, pulsierend ----
   Nach der Vorstellung ruecken alle sechs als kleine Reihe nach oben und
   warten dort sichtbar - von hier tritt in Akt 2 eines nach dem anderen
   hervor. Das Pulsieren zeigt, dass die Reihe "aktiv" wartet. */
.hero__field-icon[data-icon-state="park"] {
  --row-gap: clamp(58px, 5.6vw, 82px);
  /* Auf derselben Hoehe wie "row": beide sind Warteplaetze oberhalb des
     Kurvenbands. Im aktuellen 7-Beat-Ablauf wird "park" nicht mehr
     angesteuert - der Wert bleibt bewusst gleich, damit die beiden nicht
     auseinanderlaufen, falls der Zustand wieder gebraucht wird. */
  top: 21%;
  left: calc(50% + var(--block-order, 0) * var(--row-gap)
             - 2.5 * var(--row-gap) - 28px);
  margin-left: 0;
  opacity: 1;
  z-index: 4;
}
.hero__field-icon[data-icon-state="park"] svg {
  animation: hero-field-icon-pulse 2600ms ease-in-out
             calc(var(--block-order, 0) * 200ms) infinite;
}
.hero__field-icon[data-icon-state="park"] .hero__field-icon-label {
  opacity: 0;
}

/* ---- docked: haftet linksseitig/halb ueberlappend an der
   Prozessbeschreibung-Karte (.hero__field-text) ----
   Zwischenstation auf dem Weg aus der Reihe: die Karte steht immer
   zentriert bei 50%/50% mit Breite min(90%, 560px) (siehe .hero__field-
   text) - min(45%, 280px) ist exakt ihre halbe Breite, damit landet das
   Icon zentriert auf ihrer linken Kante. Von hier wandert es erst weiter,
   wenn die Karte wieder verschwindet (siehe initHeroFieldSequence). */
.hero__field-icon[data-icon-state="docked"] {
  top: 50%;
  left: calc(50% - min(45%, 280px) - 28px);
  margin-left: 0;
  opacity: 1;
  z-index: 5;
}
.hero__field-icon[data-icon-state="docked"] svg {
  transform: translateY(-50%) scale(1);
}

/* ---- gauge-badge: Endposition bei Chatbot/Webdesign -----------------
   Statt an eine Kurvenachse zu wandern, landet das Icon als Badge links
   auf/an seinem Tacho (.hero__gauge) - Zielkoordinaten kommen als
   --badge-top/--badge-left inline vom jeweiligen Icon (siehe Markup),
   analog zu --icon-top/--icon-left bei "placed". */
.hero__field-icon[data-icon-state="gauge-badge"] {
  top: var(--badge-top, 50%);
  left: var(--badge-left, 50%);
  margin-left: 0;
  opacity: 1;
  z-index: 5;
}
.hero__field-icon[data-icon-state="gauge-badge"] svg {
  transform: translateY(-50%) scale(1);
}

.hero__field-icon[data-icon-state="gather"] {
  --gather-count: 6;
  /* Groesserer Abstand als zuvor: die Icons sind im Sammel-Zustand um 50%
     vergroessert (siehe --gather-scale unten), bei den alten 52-76px
     wuerden sie sich beruehren. */
  --gather-gap: clamp(76px, 7.6vw, 112px);
  /* Ausgangszustand bewusst gross: die sechs Icons sind hier der einzige
     Inhalt im Bild und sollen als eigenstaendige Buehne wirken, nicht wie
     eine Miniatur-Legende. Beim Andocken an die Kurve schrumpfen sie
     wieder auf ihre Normalgroesse (kein --gather-scale im Zustand
     "placed"), was die Bewegung zur Linie zusaetzlich lesbar macht. */
  --gather-scale: 1.5;
  top: 50%;
  /* Zusaetzlich die halbe Icon-Breite (56px) abziehen: "left" setzt die
     LINKE Kante, ohne diese Korrektur sitzt die ganze Reihe um ein halbes
     Icon nach rechts versetzt. */
  left: calc(
    50%
    + var(--gather-order, 0) * var(--gather-gap)
    - (var(--gather-count) - 1) * var(--gather-gap) / 2
    - 28px
  );
  opacity: 1;
}
.hero__field-icon[data-icon-state="gather"].is-hidden {
  opacity: 0;
}
.hero__field-icon[data-icon-state="placed"] {
  top: var(--icon-top, 50%);
  left: var(--icon-left, 1.5%);
  opacity: 1;
}
.hero__field-icon svg {
  transition: transform 300ms var(--ease-out);
}
/* Ohne laufende Pulse-Animation (z.B. reduced motion oder direkt nach dem
   Zustandswechsel) traegt der Basiszustand die Vergroesserung. */
[data-icon-state="gather"] svg {
  transform: translateY(-50%) scale(var(--gather-scale, 1));
}
/* Pulsieren auf dem SVG (nicht dem Container): traegt bereits die
   vertikale Basis-Zentrierung translateY(-50%) - die Pulse-Keyframes
   bauen relativ dazu auf (-50% -+4px), statt sie zu ueberschreiben.
   Nur im "gather"-Zustand aktiv, in "placed" steht das Icon still. */
[data-icon-state="gather"]:not(.is-hidden) svg {
  animation: hero-field-icon-pulse 2600ms ease-in-out calc(var(--gather-order, 0) * 220ms) infinite;
}

/* Wabern: vertikaler Hub plus leichte Groessen-Atmung. Der Versatz je
   Icon (--gather-order * 220ms) laesst die Reihe wie eine Welle wirken
   statt im Gleichtakt zu huepfen. --gather-scale wird mitmultipliziert,
   damit das Pulsieren im vergroesserten Zustand gleich stark aussieht. */
@keyframes hero-field-icon-pulse {
  0%, 100% {
    transform: translateY(calc(-50% - 7px)) scale(calc(var(--gather-scale, 1) * 0.96));
  }
  50% {
    transform: translateY(calc(-50% + 7px)) scale(calc(var(--gather-scale, 1) * 1.04));
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__field-icon { transition: none; }
  .hero__field-icon svg { transition: none; }
  [data-icon-state="gather"]:not(.is-hidden) svg { animation: none; }
}

@media (max-width: 1023px) {
  /* Gleiche Begruendung wie bei .hero__kpi-float weiter oben: auf
     mittleren/schmalen Screens ist links neben dem Chart kein verlaesslich
     freier Bereich mehr vorhanden. */
  .hero__field-icon { display: none; }
}

/* Scroll-gekoppelte Fortsetzung: sobald der Nutzer den Hero zu verlassen
   beginnt, verstaerkt sich der Leuchtschein der Linie und sie schiebt
   sich minimal nach oben - liest sich wie ein "Weiterlaufen" der Kurve,
   angetrieben vom Scroll-Fortschritt selbst statt von einer festen Zeit.
   animation-timeline: scroll() ist eine native CSS-Scroll-Driven-
   Animation (kein JS/Scroll-Listener noetig); Browser ohne Support
   ignorieren die Regel einfach und behalten die Basis-Animation. */
@supports (animation-timeline: scroll()) {
  /* Zwei Animationen in fester Reihenfolge: 1) die per JS ausgeloeste
     Zeichen-Animation (.is-drawing, kein fester --hero-step-Delay mehr),
     2) die scroll-gebundene Fortsetzung. animation-timeline/-range greifen
     positionsweise in derselben Reihenfolge - "auto" laesst Animation 1
     wie gehabt zeitbasiert laufen, scroll(root block) bindet Animation 2
     an den Scroll-Fortschritt der Seite. */
  .hero__chart-line.is-live { stroke-linecap: round; }
.hero__chart-line.is-drawing {
    opacity: 1;
    animation: chart-draw 900ms var(--ease-out) forwards,
               chart-line-scroll-continue linear both;
    animation-timeline: auto, scroll(root block);
    animation-range: normal, 0% 60%;
  }
}

@keyframes chart-line-scroll-continue {
  from {
    filter: drop-shadow(0 0 6px rgba(255, 214, 102, 0.5));
    transform: translateY(0);
  }
  to {
    filter: drop-shadow(0 0 16px rgba(255, 214, 102, 0.85));
    transform: translateY(-14px);
  }
}

/* Geschichtete Flaechenkurven im Hintergrund (angelehnt an mehrfarbige
   SEO-Traffic-Charts): jede Ebene faehrt beim Einblenden aus einem
   SICHTBAR unterschiedlichen Y-Versatz in ihre Endposition und behaelt
   einen eigenen, nach Ebene gestaffelten Schlagschatten - dadurch wirkt
   es wie mehrere separate, transluzente Karten, die uebereinanderliegen
   und Abstand zur Ebene darunter haben, statt wie eine einzelne flache
   Illustration. (Reines translateZ/preserve-3d wurde bewusst NICHT
   verwendet: CSS-3D-Transforms auf verschachtelten SVG-<path>-Elementen
   rendern browseruebergreifend zu inkonsistent/schwach fuer einen
   verlaesslich sichtbaren Effekt - der 2D-Ansatz hier funktioniert
   ueberall gleich.) Deutet die Mehrdimensionalität der Analyse an
   ("mehrere Ebenen fuehren zu mehr Sichtbarkeit/Erfolg"), statt eine
   einzelne flache Kurve zu zeigen. */
/* Scroll-choreografierte Reveal-Sequenz (Kurven + Badges + Titel): alle
   Layer starten UNSICHTBAR und OHNE laufende Animation. Erst wenn die
   Hero-Section das Attribut [data-hero-sequence="go"] traegt (per JS beim
   ersten Scroll-Impuls gesetzt, siehe initHeroScrollSequence in
   script.js), feuert je Layer die passende Animation mit eigenem
   Delay - dadurch zeichnen sich die 5 Kurven in fester Reihenfolge
   (Sichtbarkeit -> Suchanfragen -> Markenwahrnehmung -> Reichweite ->
   Kundenvertrauen, identisch zur vertikalen Badge-Reihenfolge) nacheinander,
   bevor zuletzt der zentrale Titel einfadet. Vorher (ohne das Attribut)
   bleiben alle Layer im Ruhezustand - kein Zeit-/Preloader-gekoppeltes
   Auto-Play mehr. */
.hero__chart-area {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center bottom;
  transform: translateY(var(--layer-y-from, 0px));
  filter: drop-shadow(0 var(--layer-shadow-y, 0px) var(--layer-shadow-blur, 0px) rgba(8, 12, 20, var(--layer-shadow-a, 0)));
}
/* KEINE globale [data-hero-sequence="go"]-Regel mehr: seit alle sechs
   Leistungsfelder ueber initHeroFieldSequence laufen, zeichnet JEDE Kurve
   ausschliesslich dann, wenn ihr Icon angedockt ist und das JS .is-drawing
   setzt. Die frueher hier stehende Regel nahm nur organic/indigo/violet
   per :not() aus - green, cyan und (neu) amber blendeten dadurch schon
   beim ersten Scroll-Impuls ein und standen als sichtbare Kurven-Relikte
   rechts im Bild, bevor die Sequenz ueberhaupt bei ihnen war. */
.hero__chart-area.is-drawing {
  opacity: 1;
  transform: translateY(var(--layer-y-rest, 0px));
}
/* Reihenfolge der Flaechen-Layer folgt der Badge-Reihenfolge von oben nach
   unten (organic/Sichtbarkeit zeichnet zuerst mit, violet/Suchanfragen als
   naechstes usw.) statt der vorherigen rein optischen Tiefenstaffelung. */
.hero__chart-area--organic {
  --layer-y-from: 10px;
  --layer-y-rest: 4px;
  --layer-shadow-y: 4px;
  --layer-shadow-blur: 10px;
  --layer-shadow-a: 0.22;
}

.hero__chart-area--indigo {
  --layer-y-from: 14px;
  --layer-y-rest: 8px;
  --layer-shadow-y: 6px;
  --layer-shadow-blur: 14px;
  --layer-shadow-a: 0.28;
}

.hero__chart-area--violet {
  --layer-y-from: 34px;
  --layer-y-rest: 22px;
  --layer-shadow-y: 16px;
  --layer-shadow-blur: 28px;
  --layer-shadow-a: 0.34;
}

.hero__chart-area--green {
  --layer-y-from: 60px;
  --layer-y-rest: 40px;
  --layer-shadow-y: 30px;
  --layer-shadow-blur: 44px;
  --layer-shadow-a: 0.4;
}
/* .hero__chart-area--green: Delay entfernt, zeichnet jetzt per .is-drawing
   aus der JS-Sequenz (siehe FIELD_SEQUENCE in script.js). */

.hero__chart-area--amber {
  --layer-y-from: 52px;
  --layer-y-rest: 0px;
  --layer-shadow-y: 22px;
  --layer-shadow-blur: 36px;
  --layer-shadow-a: 0.30;
}

.hero__chart-area--cyan {
  --layer-y-from: 48px;
  --layer-y-rest: 31px;
  --layer-shadow-y: 24px;
  --layer-shadow-blur: 38px;
  --layer-shadow-a: 0.37;
}
/* .hero__chart-area--cyan: Delay entfernt, zeichnet jetzt per .is-drawing
   aus der JS-Sequenz (siehe FIELD_SEQUENCE in script.js). */

/* Goldene Hauptlinie (organic/Sichtbarkeit): Teil der neuen Einzel-
   Sequenz, zeichnet nur noch wenn initHeroFieldSequence per JS .is-drawing
   setzt - nicht mehr automatisch mit dem globalen data-hero-sequence. */
.hero__chart-line.is-drawing {
  stroke-dashoffset: 0;
  opacity: 1;
}

@keyframes chart-area-in {
  to { opacity: 1; transform: translateY(var(--layer-y-rest, 0px)); }
}

@keyframes chart-draw {
  to { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__chart-line { animation: none; stroke-dashoffset: 0; opacity: 1; }
  .hero__chart-area {
    animation: none;
    opacity: 1;
    transform: translateY(var(--layer-y-rest, 0px));
  }
}

/* Schwebende KPI-Badges: je eines pro Kurve, an deren jeweiliger
   Endposition am rechten Rand platziert (--kpi-top wird inline je Badge
   gesetzt, siehe HTML) - liest sich dadurch wie eine Beschriftung "an
   der Kurve entlang" statt wie ein einzelner, isolierter Wert oben
   rechts. Jedes Badge feuert zusammen mit seiner Kurve als Teil der
   Scroll-Sequenz (siehe [data-hero-sequence="go"] .hero__kpi-float--*
   weiter unten). */
.hero__kpi-float {
  position: absolute;
  top: var(--kpi-top, 12%);
  /* Rechter Abstand haelt jetzt zusaetzlich die vertikale Kontaktleiste
     frei (--contact-bar-w). Vorher stiessen die Badges unter die Leiste
     und wurden am Fensterrand angeschnitten - sichtbar, seit alle sechs
     Leistungsfelder ein Badge tragen und die Spalte dichter belegt ist. */
  right: calc(var(--contact-bar-w) + var(--space-lg));
  max-width: min(15rem, 34vw);
  /* Die Badge-Spalte beginnt unterhalb der schwebenden Kopfleiste: das
     oberste Badge (--kpi-top: 8%) lag sonst zur Haelfte darunter. */
  margin-top: var(--nav-pill-h);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  gap: 0.1em;
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  box-shadow: 0 12px 32px rgba(20, 33, 61, 0.14);
  opacity: 0;
  transform: translateY(-10px) scale(0.94);
}
/* Badge feuert exakt zusammen mit seiner Kurve: gleiche --hero-step-N-
   Variable wie die zugehoerige .hero__chart-area/-line oben, plus ein
   kleiner Nachlauf (+150ms), damit das Badge sichtbar NACH der Kurve
   "ankommt" statt exakt zeitgleich aufzupoppen. */
/* organic/violet/indigo: Teil der neuen Einzel-Sequenz, erscheinen erst
   wenn initHeroFieldSequence per JS .is-visible setzt (nachdem die
   zugehoerige Kurve fertig gezeichnet ist) statt per festem --hero-step-
   Delay. cyan/green bleiben auf dem alten globalen Mechanismus. */
.hero__kpi-float--organic.is-visible,
.hero__kpi-float--violet.is-visible,
.hero__kpi-float--indigo.is-visible,
.hero__kpi-float--cyan.is-visible,
.hero__kpi-float--green.is-visible,
.hero__kpi-float--amber.is-visible {
  animation: hero-kpi-float-in 600ms var(--ease-out) forwards;
}
/* cyan/green/amber erscheinen wie die uebrigen Badges erst, wenn ihre
   Kurve fertig gezeichnet ist (.is-visible aus der JS-Sequenz). */
/* Hover-Hervorhebung (siehe setHoverHighlight in initChartHover): Rand
   in der Kanalfarbe (--point-color je Modifier-Klasse unten) statt dem
   neutralen Weiss, plus leichter Zoom. transition statt animation, damit
   es unabhaengig von der hero-kpi-float-in-Einblendanimation greift -
   die ist nach 600ms laengst abgeschlossen, bevor ein Hover ueberhaupt
   moeglich ist (Badge erscheint erst wenn die Kurve fertig/.is-live ist). */
.hero__kpi-float.is-visible {
  transition: transform 180ms var(--ease-out), border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}
/* animation-fill-mode:forwards haelt den Endzustand der Einblend-
   Animation fest - und ein laufender/gefuellter Animationswert schlaegt
   in der Kaskade JEDE normale Deklaration, auch !important. Der Zoom
   stand hier zwar schon, kam aber nie an: gemessen blieb der Transform
   nach dem Hover auf scale(1).
   Deshalb wird die Animation im Hover-Zustand abgeschaltet. Ihr
   Endzustand (opacity:1, translateY(0)) wird hier gleich mitgesetzt,
   damit das Badge beim Abschalten nicht auf seine Startwerte
   (opacity:0, -10px) zurueckspringt. */
.hero__kpi-float.is-visible.is-hovered {
  animation: none;
  opacity: 1;
  transform: translateY(0) scale(1.12);
  border-color: var(--hover-color, rgba(255, 255, 255, 0.9));
  box-shadow: 0 0 0 2px var(--hover-color, transparent), 0 18px 40px rgba(20, 33, 61, 0.24);
  /* Der Zoom soll die Nachbarbadges ueberlagern, nicht unter ihnen
     verschwinden. */
  z-index: 3;
}
.hero__kpi-float--organic { --hover-color: #ffd666; }
.hero__kpi-float--indigo { --hover-color: #8fa8e6; }
.hero__kpi-float--violet { --hover-color: #b3a6ff; }
.hero__kpi-float--cyan { --hover-color: #22d3ee; }
.hero__kpi-float--green { --hover-color: #3ddc97; }
.hero__kpi-float--amber { --hover-color: #e3c88e; }
.hero__kpi-float-value {
  display: flex;
  align-items: baseline;
  gap: 0.1em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 2.1vw + 1.1rem, 2.5rem);
  /* Gold als Basisfarbe, je Kurve per Modifier ueberschrieben (siehe
     .hero__kpi-float--* unten) - haengt die Zahl optisch an die Farbe
     ihrer Kurve statt alle Badges gleich einzufaerben. */
  color: var(--color-accent-deep);
  line-height: 1;
}
.hero__kpi-float-value .count__unit {
  /* Vorher 0.55em: das "%"/"×"-Zeichen war auf einem 24"-Monitor kaum
     lesbar, auf Mobile erst recht nicht - naeher an die Zahlengroesse
     herangeholt, damit die Einheit nicht wie eine Fussnote wirkt. */
  font-size: 0.8em;
  font-weight: 600;
}
.hero__kpi-float-label {
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-text-muted);
}

/* Je Kurve eine eigene Akzentfarbe fuer die Zahl - haengt das Badge
   visuell an seine Kurve, statt dass alle fuenf gleich golden wirken. */
.hero__kpi-float--violet .hero__kpi-float-value { color: #7c6df2; }
.hero__kpi-float--indigo .hero__kpi-float-value { color: #c8462d; }
.hero__kpi-float--green .hero__kpi-float-value { color: #1fae78; }
.hero__kpi-float--cyan .hero__kpi-float-value { color: #0891b2; }

/* Claim-Badges ohne Zahlen-Value (Markenwahrnehmung/Kundenvertrauen
   lassen sich nicht seriös als einzelne Kennzahl beziffern): das Label
   ruecken diese beiden groesser/kraeftiger in die Value-Rolle, statt wie
   eine blasse Unterzeile unter einer fehlenden Zahl zu wirken. */
.hero__kpi-float-label--claim {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.5vw + 0.75rem, 1.625rem);
  color: var(--color-ink);
}
.hero__kpi-float--cyan .hero__kpi-float-label--claim { color: #0891b2; }
.hero__kpi-float--amber .hero__kpi-float-label--claim { color: #b8770c; }
.hero__kpi-float--green .hero__kpi-float-label--claim { color: #1fae78; }

@keyframes hero-kpi-float-in {
  to { opacity: 1; transform: translateY(0) scale(1); }
}

@media (max-width: 1023px) {
  /* Auf mittleren/schmalen Screens ist der freie Bereich oben rechts zu
     knapp fuer ein zusaetzliches Element neben Nav und Chart. */
  .hero__kpi-float { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__kpi-float { animation: none; opacity: 1; transform: none; }
}

/* Beschreibungstext waehrend jede Kurve zeichnet (initHeroFieldSequence):
   zentriert an derselben Stelle wie der spaetere Abschluss-Titel
   (#hero-outro-title), damit der Blick nicht zwischen zwei Positionen
   springt - Text und Titel teilen sich diese Flaeche zeitlich nacheinander
   statt gleichzeitig zu konkurrieren. pointer-events:none aus demselben
   Grund wie .hero__inner--v2: darf Kurven-Hover nicht blockieren. */
/* Bereichstitel der Sequenz, oben links in der Buehne - er benennt die
   Sektion waehrend der GESAMTEN Choreografie, nicht nur in deren erstem
   Akt. Vorher stand hier blasses Weiss (55%), das ab data-seq-act="2"
   zusaetzlich ganz ausblendete: die Buehne lief den mit Abstand
   groessten Teil der Sequenz voellig unbeschriftet.

   Optik jetzt wie die Rubrikzeile im Intro (.eyebrow--onDark, "IHR
   BERATER"): Akzentton plus feiner Strich davor. Damit ist er deutlich
   praesenter, bleibt aber eine Rubrik am Rand und tritt nicht in
   Konkurrenz zum Erklaertext in der Bildmitte. */
.hero__seq-eyebrow {
  position: absolute;
  top: calc(var(--nav-pill-h) + var(--space-md));
  left: clamp(var(--space-md), 3vw, var(--space-xl));
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-base);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-accent);
  /* Die Buehne hellt waehrend der Sequenz nach rechts auf und die Kurven
     laufen unter dem Marker durch - der weiche Schatten haelt ihn auf
     jedem Untergrund lesbar, ohne eine sichtbare Plakette zu setzen. */
  text-shadow: 0 1px 14px rgba(8, 12, 20, 0.65),
               0 0 3px rgba(8, 12, 20, 0.45);
  pointer-events: none;
  transition: opacity 500ms var(--ease-out);
}

/* Feiner Strich vor dem Label - dieselbe Rubrik-Auszeichnung wie im
   Intro, siehe .hero--intro[data-type="b"] .eyebrow--onDark::before. */
.hero__seq-eyebrow::before {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: currentColor;
  opacity: 0.85;
}

@media (max-width: 1023px) {
  .hero__seq-eyebrow { display: none; }
}

/* -----------------------------------------------------------------------
   Fortschrittsanzeige der Leistungs-Sequenz
   -----------------------------------------------------------------------
   Sitzt zwischen Kopfleiste und der 6er-Icon-Reihe. Der Balken ist voll,
   solange alle sechs Leistungen noch in der Reihe stehen, und verliert
   mit jedem Icon, das sie verlaesst, ein Sechstel - er zeigt also an,
   wie viel von der Sequenz noch kommt. --fill (0..1) setzt das JS.
   Unter 1024px ausgeblendet: dort laeuft die Sequenz ohnehin nicht.
   ----------------------------------------------------------------------- */

/* Erscheint erst, wenn die Vorstellung der sechs Leistungen komplett
   durchgelaufen ist (.is-ready setzt initHeroFieldSequence) - vorher
   waere er ein Balken ohne Bezug, weil die Reihe, deren Restbestand er
   anzeigt, noch gar nicht steht. Faedet weich ein, damit er nicht
   uebergangslos ins Bild springt. */

@media (prefers-reduced-motion: reduce) {

}

@media (max-width: 1023px) {

}

.hero__field-text {
  position: absolute;
  z-index: 2;
  /* Zentral in der Bildschirmmitte, fuer JEDES Feld an derselben Stelle -
     vorher stand die Karte je Leistung bei ihrer eigenen Kurve bzw.
     ihrem Icon (sechs verschiedene Positionen ueber die Buehne verteilt).
     Das sprang beim Weiterscrollen sichtbar von Punkt zu Punkt statt an
     einer festen Stelle zu bleiben, an die man den Blick einmal
     gewoehnt. Jetzt immer 50%/50%. */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) translateY(10px);
  width: min(90%, 560px);
  text-align: center;
  /* Eigene Trageflaeche statt nur Textschatten: der Text steht ueber dem
     Chart, dessen rechte Haelfte fast weiss ist - weisse Schrift war dort
     praktisch unlesbar, und die Kurven liefen zusaetzlich mitten durch die
     Zeilen. Ein Schatten kann das nicht auffangen, weil er den Untergrund
     nicht abdeckt. Die dunkle, leicht durchscheinende Karte trennt den Text
     sauber vom Chart, laesst die Kurve dahinter aber noch erahnen. */
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius);
  background: rgba(16, 24, 40, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  box-shadow: 0 14px 40px rgba(8, 12, 20, 0.42);
  color: #fff;
  font-size: clamp(1rem, 1vw + 0.85rem, 1.1875rem);
  line-height: 1.6;
  text-shadow: 0 1px 2px rgba(8, 12, 20, 0.6);
  text-wrap: balance;
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out);
}
.hero__field-text.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .hero__field-text { transition: none; }
}

.hero__inner--v2 {
  /* Der Container nimmt volle Breite/Hoehe ein (geerbt von .hero__inner),
     obwohl der eigentliche Text (.hero__content--v2) nur mittig ca. 620px
     einnimmt - dadurch blockierte die leere Restflaeche bislang die Maus-
     Hover-Events auf den darunterliegenden Chart-Kurven (.hero__chart-
     hitzone), auch weit ausserhalb des sichtbaren Textes. Enthaelt hier
     keine Links/Buttons (nur die Ueberschrift), daher unbedenklich fuer
     den gesamten Container abzuschalten - die Maus "faellt durch" bis zu
     den Kurven.
     Titel steht vertikal UND horizontal zentriert im Hero - eigenes Flex-
     Zentrum unabhaengig von KPIs/Lead-Card/Buttons, die alle absolut
     positioniert sind und keinen Platz im Fluss beanspruchen.
     min-height: 0 ist noetig, damit dieses Flex-Kind bei Bedarf UNTER
     seine Content-Groesse schrumpfen kann statt den Eltern-Flexcontainer
     ueber die Bildschirmhoehe hinaus aufzublaehen (Standard-Flex-Verhalten
     waere min-height:auto = mindestens Content-Groesse).
     Padding nur noch so hoch wie die Kopfleiste selbst (statt zusaetzlich
     + space-2xl): bei zentriertem Titel ist kein grosser Sicherheitsabstand
     mehr noetig, ein zu hohes festes Padding blaeht sonst bei knappen
     Viewport-Hoehen den Flex-Container ueber 100svh hinaus auf und laesst
     den (an .hero verankerten) Erkunden-Button unter overflow:hidden
     verschwinden. */
  pointer-events: none;
  align-items: center;
  justify-content: center;
  padding-top: var(--nav-pill-h);
  padding-bottom: 0;
  min-height: 0;
}
.hero__content--v2 {
  max-width: 620px;
  text-align: center;
  gap: var(--space-sm);
}
.hero__title--v2 {
  /* +25% gegenueber der vorherigen Groesse (1.9rem/2.9rem -> 2.375rem/3.625rem). */
  font-size: clamp(2.375rem, 4vw + 1.25rem, 3.625rem);
  line-height: 1.12;
  display: flex;
  flex-direction: column;
  /* Abschluss der Scroll-Sequenz: der GESAMTE Titel (nicht nur das Wort
     "Sichtbarkeit") bleibt unsichtbar, bis die Kurven-Sequenz durchgelaufen
     ist, und fadet dann zentral als letzter Schritt ein (siehe
     --hero-step-6 in initHeroScrollSequence, script.js). Ersetzt die
     vorherige, sofort beim Laden startende Buchstaben-Einflug-Animation
     von .lc2 (siehe unten), die jetzt erst mit dem Titel zusammen feuert. */
  opacity: 0;
  transform: translateY(10px);
}
/* Erscheint jetzt erst NACHDEM initHeroFieldSequence alle Leistungen
   durchlaufen hat (per JS .is-visible auf #hero-outro-title gesetzt),
   statt automatisch nach fester Zeit mit dem Rest der Sequenz. */
#hero-outro-title.is-visible .hero__title--v2 {
  animation: hero-title-in 800ms var(--ease-out) forwards;
}

/* Sternenglanz am Abschluss der Sequenz: die Seite traegt bereits eine
   feine Rausch-/Glanztextur (.hero__grain). Hier wird sie fuer den
   Schlusstitel aufgegriffen und in Bewegung versetzt - einzelne
   Lichtpunkte, die langsam heller und dunkler werden, plus ein
   Glanzstreifen, der ueber die Schrift wandert. Beides liegt HINTER dem
   Text (z-index/-1) bzw. als Blendmodus darauf, damit die Lesbarkeit
   nicht leidet. */
#hero-outro-title.is-visible .hero__content--v2 {
  position: relative;
}

#hero-outro-title.is-visible .hero__content--v2::before {
  content: "";
  position: absolute;
  inset: -18% -12%;
  z-index: -1;
  pointer-events: none;
  /* Sternenfeld: mehrere radiale Verlaeufe in unterschiedlichen Groessen
     und Positionen - ergibt ein unregelmaessiges Funkeln statt eines
     sichtbaren Rasters. */
  background-image:
    radial-gradient(2px 2px at 12% 22%, rgba(255, 255, 255, 0.9), transparent 60%),
    radial-gradient(2px 2px at 82% 16%, rgba(255, 214, 102, 0.85), transparent 60%),
    radial-gradient(1.5px 1.5px at 28% 78%, rgba(255, 255, 255, 0.8), transparent 60%),
    radial-gradient(2.5px 2.5px at 66% 68%, rgba(255, 255, 255, 0.75), transparent 60%),
    radial-gradient(1.5px 1.5px at 46% 34%, rgba(255, 214, 102, 0.9), transparent 60%),
    radial-gradient(2px 2px at 92% 56%, rgba(255, 255, 255, 0.7), transparent 60%),
    radial-gradient(1.5px 1.5px at 6% 58%, rgba(255, 214, 102, 0.7), transparent 60%),
    radial-gradient(2px 2px at 56% 88%, rgba(255, 255, 255, 0.65), transparent 60%),
    radial-gradient(2px 2px at 34% 12%, rgba(255, 214, 102, 0.85), transparent 60%),
    radial-gradient(2.5px 2.5px at 74% 40%, rgba(255, 255, 255, 0.9), transparent 60%),
    radial-gradient(2px 2px at 18% 46%, rgba(255, 255, 255, 0.8), transparent 60%),
    radial-gradient(2.5px 2.5px at 88% 84%, rgba(255, 214, 102, 0.8), transparent 60%);
  /* Leuchthof: ohne ihn wirken die Punkte auf dem hellen Chart-Bereich
     wie Staub statt wie Licht. */
  filter: drop-shadow(0 0 7px rgba(255, 214, 102, 0.6));
  animation: outro-stars 4200ms ease-in-out infinite;
}

/* Pulsieren: die Lichtpunkte atmen gemeinsam, aber nicht im Gleichtakt
   mit dem Glanzstreifen - dadurch wirkt es lebendig statt getaktet. */
@keyframes outro-stars {
  0%, 100% { opacity: 0.35; transform: scale(0.98); }
  50% { opacity: 1; transform: scale(1.06); }
}

/* Glanzstreifen: liegt als eigene Ebene GENAU auf den Buchstaben jeder
   Titelzeile, nicht als rechteckiger Streifen ueber dem ganzen Container.
   content:attr(data-shine) dupliziert den sichtbaren Zeilentext auf einem
   Pseudo-Element, das exakt deckungsgleich ueber der echten Zeile liegt
   (.hero__title-line ist dafuer position:relative, das Pseudo-Element
   inset:0). Die Gradient-Flaeche wird per background-clip:text auf die
   Buchstabenform dieses Duplikats zugeschnitten - ausserhalb der Glyphen
   bleibt sie vollstaendig transparent, es entsteht also nie ein
   sichtbarer Rahmen/Kasten. color:transparent ist der Fallback fuer
   Browser ohne background-clip:text (kein Kasten, nur unsichtbarer
   Text) - der eigentliche Titel darunter bleibt in jedem Fall normal
   lesbar, der Glanz ist reine Zugabe. mix-blend-mode:overlay laesst ihn
   nur dort sichtbar aufleuchten, wo er gerade ueber die echte Schrift
   wandert. */
.hero__title-line { position: relative; }
#hero-outro-title.is-visible .hero__title-line::after {
  content: attr(data-shine);
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  white-space: nowrap;
  mix-blend-mode: overlay;
  background-image: linear-gradient(105deg,
    transparent 40%,
    rgba(255, 255, 255, 0.9) 48%,
    rgba(255, 214, 102, 0.95) 52%,
    transparent 60%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: outro-shine 5200ms ease-in-out 900ms infinite;
}

@keyframes outro-shine {
  0% { background-position: 130% 0; }
  55%, 100% { background-position: -30% 0; }
}

@media (prefers-reduced-motion: reduce) {
  #hero-outro-title.is-visible .hero__content--v2::before { animation: none; opacity: 0.7; }
  #hero-outro-title.is-visible .hero__title-line::after { animation: none; opacity: 0; }
}
@keyframes hero-title-in {
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .hero__title--v2 { opacity: 1; transform: none; }
}

/* Zeile 1 sitzt knapp UEBER der Kurslinie (negativer Versatz nach oben),
   Zeile 2 knapp UNTER der Linie (positiver Versatz nach unten) - die
   Linie verlaeuft dadurch optisch zwischen beiden Textzeilen hindurch. */
.hero__title-line { display: block; }
.hero__title-line--above { margin-bottom: 0.85em; }
.hero__title-line--below { margin-top: 0.85em; }

/* "Sichtbarkeit" wird zusammen mit dem gesamten Titel als Block eingefadet
   (siehe .hero__title--v2/hero-title-in oben) statt wie zuvor per Buchstabe
   einzeln einzufliegen - der Titel ist jetzt der ABSCHLUSS der Scroll-
   Sequenz statt das sofort beim Laden sichtbare erste Element, ein
   zusaetzlicher Buchstaben-Einflug obendrauf wirkte optisch doppelt
   gemoppelt. .lc2 bleibt als einfacher Inline-
   Wrapper ohne eigene Animation stehen. */
.hero__reveal2 {
  display: inline-block;
  white-space: nowrap;
}
.lc2 {
  display: inline-block;
  color: var(--color-accent);
}

/* KPIs in Variante 2: horizontale Reihe direkt am unteren Sektionsrand,
   horizontal zentriert, auf derselben bottom-Distanz (var(--space-md))
   wie Erkunden-Indikator und To-Top-Button - liegt aber UNTER diesen
   (z-index 1 statt 2/400). Die Lead-Card sitzt unabhaengig davon links
   auf derselben Baseline. */
.hero__stats--v2 {
  /* Im normalen Fluss als letztes Element der Flex-Spalte von
     .hero--intro, NICHT absolut am unteren Sektionsrand: absolut
     positioniert legte sich die Reihe bei niedrigen Fenstern ueber den
     Vorstellungstext (der Schlusssatz und der CTA-Button verschwanden
     darunter). Im Fluss schiebt sie den Text stattdessen nach oben.
     Frueher stand sie in der zweiten Etappe ueber dem Chart, dort war die
     absolute Verankerung richtig - seit dem Umzug ist sie es nicht mehr. */
  position: relative;
  margin-inline: auto;
  margin-bottom: var(--space-lg);
  display: grid;
  /* Bento-Raster statt gleicher Spalten: 6 schmale Spuren, die
     hervorgehobene Karte (.hero__stat--feature) spannt zwei davon, die
     vier Standardkarten (inkl. "Alles aus einer Hand") je eine -
     wirkt dadurch bewusst asymmetrisch/editorial statt wie ein
     generisches Vorlagen-Raster aus identischen Kacheln. */
  grid-template-columns: repeat(6, 1fr);
  /* Rechter Platzbedarf fuer Erkunden- + To-Top-Button (je 48px + Abstand)
     bleibt als Sicherheitsabstand erhalten, damit die zentrierte Reihe bei
     schmaleren Viewports nicht unter die Buttons rutscht. */
  width: min(880px, calc(100% - 2 * (2 * (48px + var(--space-sm)))));
  gap: var(--space-2xs);
  padding: 0;
  z-index: 1;
}
/* Eigener, kraeftigerer Kartenhintergrund: die Karten sitzen im hellen
   Fade-Bereich (nicht mehr auf dunklem Vollbild-Foto wie in Var 1), der
   duenne rgba(255,255,255,0.08)-Grundstil waere dort kaum lesbar. */
.hero__stats--v2 .hero__stat {
  /* Etwas heller als die Basis: die Karten sitzen jetzt auf dem dunklen
     Ink-Grund des Vorstellungs-Heros (frueher im hellen Fade-Bereich der
     zweiten Etappe) - dort war ein abdunkelnder Ton richtig, hier braucht
     es einen aufhellenden, damit sie sich ueberhaupt abheben. */
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.16);
  /* Kompakter als frueher: die Reihe laeuft nicht mehr frei ueber einem
     Chart, sondern teilt sich die Sektionshoehe mit einem langen
     Vorstellungstext. In der alten Groesse schob sie den Hero ueber
     100svh hinaus. */
  padding: var(--space-xs) var(--space-sm);
}
.hero__stats--v2 .hero__stat strong {
  font-size: clamp(1.25rem, 1.1vw + 0.85rem, 1.75rem);
  line-height: 1.15;
}
.hero__stats--v2 .hero__stat-label {
  font-size: 0.75rem;
  line-height: 1.35;
}
/* Hervorgehobene Kachel: spannt zwei der fuenf Spuren und bekommt einen
   kraeftigeren Akzent-Rahmen + eigene, groessere Zahlengroesse, damit
   sie sich sichtbar von den drei kompakten Nachbarn absetzt. */
.hero__stat--feature {
  grid-column: span 2;
  border-color: rgba(255, 214, 102, 0.55);
  background: rgba(16, 24, 40, 0.68);
}
.hero__stats--v2 .hero__stat--feature strong {
  font-size: clamp(1.5rem, 1.5vw + 1rem, 2.15rem);
}

@media (max-width: 1023px) {
  /* Ohne Spalten-Spannung der Feature-Karte belegen die 5 Karten nur 5 der
     6 Spuren - die sechste bliebe als Loch stehen. Unterhalb von 1024px
     deshalb ein glattes 3er-Raster (3 + 2), das ist bei dieser Breite auch
     lesbarer als fuenf sehr schmale Spalten nebeneinander. */
  .hero__stat--feature { grid-column: auto; }
  .hero__stats--v2 {
    grid-template-columns: repeat(3, 1fr);
    width: min(640px, calc(100% - 2 * var(--space-md)));
  }
}

/* Erkunden-Indikator: jetzt Kind von .hero (nicht mehr der Variante),
   rechte untere Sektionsecke, links neben dem To-Top-Button - optisch
   identisch zur Position des Indikators in den Folgesektionen (siehe
   .scroll-cue). Rueckt zusaetzlich an der vertikalen Kontakt-Leiste
   vorbei, die denselben rechten Rand belegt. */
.hero__scroll-cue {
  position: absolute;
  right: calc(var(--space-md) + 48px + var(--space-sm));
  bottom: var(--space-md);
  z-index: 2;
  color: rgba(255, 255, 255, 0.75);
}
.hero__scroll-cue:hover,
.hero__scroll-cue:focus-visible { color: var(--color-accent); }

/* -----------------------------------------------------------------------
   9c) Vertikale Kontakt-Leiste (global, rechter Rand)
   ----------------------------------------------------------------------- */
:root {
  /* Von den Hero-KPIs referenziert (9a), damit deren zentrierte Breite der
     Leiste ausweicht - auf Mobile faellt die Leiste auf eine schmale
     eingeklappte Spalte zurueck, siehe Media-Query unten. */
  --contact-bar-w: 56px;
}

.contact-bar {
  /* fixed statt absolute: die Leiste haengt seit dem Umzug auf body-Ebene
     und soll auf jeder Seite und in jeder Sektion am rechten Rand stehen
     bleiben. Als absolut positioniertes Kind des Heros war sie nur dort -
     und nur auf der Startseite - sichtbar.
     z-index 40 bleibt unter Kopfleiste (500), Cookie-Banner (900) und
     Preloader, aber ueber allen Sektionsinhalten. */
  position: fixed;
  top: 50%;
  right: var(--space-md);
  transform: translateY(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.contact-bar__toggle {
  display: none;
}

/* Drei Erscheinungsbilder statt eines festen Tons: die Leiste liegt ueber
   der gesamten Seite und damit sowohl ueber dunklen Flaechen (beide
   Hero-Sektionen, Footer, das Referenzen-Grid) als auch ueber hellen
   (praktisch alle uebrigen Sektionen), und an jeder Sektionskante eine
   Weile ueber BEIDEN gleichzeitig. Ein einzelner fester Ton war auf einem
   der Untergruende zwangslaeufig ein Kompromiss.

   Den Ton setzt initContactBarTone (script.js) an data-tone:
     (ohne)  dunkler Grund  -> helles Glas, weisse Icons
     light   heller Grund   -> dunkles Glas, Ink-Icons
     split   auf der Kante  -> mitteldunkles Glas, weisse Icons

   Wichtig fuer den Grundzustand: auf dunklem Grund steht hier bewusst
   HELLES Glas. Die frueher gesetzte dunkle Flaeche (0.82 Ink) kam auf dem
   Hero-Grund nur auf 1.07:1 Flaechenkontrast - sie verschmolz also mit
   dem Untergrund, statt sich als eigenes Bedienelement abzusetzen. */
.contact-bar__list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs);
  /* Grundzustand = dunkler Untergrund. Hier steht bewusst eine HELLE
     Glasflaeche, nicht die frueher gesetzte dunkle (0.82 Ink):
     gemessen kam die dunkle Pille auf dem Hero-Grund nur auf 1.07:1
     Flaechenkontrast - sie verschmolz also praktisch mit dem Untergrund
     und war als eigenes Bedienelement kaum auszumachen (genau der
     Eindruck, der im Hero gestoert hat). Aufgehelltes Glas kehrt das um:
     1.77:1 gegen den Grund, waehrend die weissen Icons darauf 9.31:1
     behalten - die Leiste liest sich als schwebende Flaeche, ohne dass
     die Icons an Kontrast verlieren. */
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.30);
  border-radius: var(--radius-pill);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  /* Dunkler Schlagschatten setzt die helle Flaeche zusaetzlich ab. */
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.38);
  transition: background-color 200ms var(--ease-out), border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
}
.contact-bar[data-tone="light"] .contact-bar__list {
  /* 0.14 dunkles Glas auf hellem Grund: gemessen 11-14:1 ueber alle drei
     hellen Sektionstoene (Weiss, --color-bg, --color-bg-soft) - deutlich
     ueber der 4.5:1-Textgrenze, aber hell genug, um wie eine eigene
     Variante statt einer nur abgedunkelten Kopie zu wirken. */
  background: rgba(16, 24, 40, 0.14);
  border-color: rgba(16, 24, 40, 0.12);
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.14);
}

/* Kantenfall: die Leiste ist ~300px hoch und steht an jedem
   Sektionswechsel kurzzeitig HALB auf hell und HALB auf dunkel (siehe
   initContactBarTone in script.js). Ein einzelner Flaechenton waere
   dann auf einer der beiden Haelften zwangslaeufig falsch. Deshalb hier
   ein Ton, der auf BEIDEN Untergruenden traegt: 0.72 dunkles Glas traegt
   die weissen Icons mit 7.07:1 ueber der hellsten Sektion (Weiss) und
   mit 17.75:1 ueber dem dunklen Footer - beide Haelften also klar ueber
   der 4.5:1-Grenze (nachgerechnet, sRGB-Relativluminanz). Der hellere
   Rand haelt die Pille zugleich gegen den Footer als eigene Flaeche. */
.contact-bar[data-tone="split"] .contact-bar__list {
  background: rgba(16, 24, 40, 0.72);
  /* Kraeftigerer Rand als in den beiden Ruhezustaenden: die Flaeche selbst
     kommt ueber der HELLEN Haelfte auf 7.07:1, ueber der dunklen Haelfte
     (Footer) aber nur auf 1.00:1 - dort traegt allein der helle Rand die
     Kontur der Pille. Ohne ihn verschwaende die untere Haelfte der Leiste
     im Footer, waehrend die obere noch sichtbar waere. */
  border-color: rgba(255, 255, 255, 0.38);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.32);
}

/* Unvorhersehbarer Untergrund (data-surface="mixed", z.B. das
   Referenzen-Grid: dort laufen Produktfotos in beliebigen Farben unter
   der Leiste durch). Eine durchscheinende Glasflaeche kann dort nicht
   funktionieren - gemessen fiel das weisse Icon ueber einer grossflaechig
   hellgruenen Karte auf 2.06:1. Deshalb hier als Einziges eine DECKENDE
   Flaeche: der Untergrund spielt damit keine Rolle mehr, das weisse Icon
   liegt fest auf Ink (17.4:1). Kein backdrop-filter noetig, es scheint
   ohnehin nichts durch. */
.contact-bar[data-tone="opaque"] .contact-bar__list {
  background: rgb(16, 24, 40);
  border-color: rgba(255, 255, 255, 0.28);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}
.contact-bar[data-tone="opaque"] .contact-bar__link,
.contact-bar__link[data-tone="opaque"] { color: #fff; }
/* Auf der deckenden Flaeche braucht kein einzelnes Icon mehr seine eigene
   Scheibe (die ist nur fuer die durchscheinenden Zustaende gedacht). */
.contact-bar[data-tone="opaque"] .contact-bar__link[data-tone="split"] {
  background: none;
  box-shadow: none;
}

.contact-bar__sep {
  width: 22px;
  height: 1px;
  margin-block: 0.2rem;
  /* 0.45 statt 0.22: seit die Flaeche im Grundzustand HELLES Glas ist,
     hebt sich ein schwach deckender weisser Strich kaum noch ab - 0.22
     kam nur auf 1.86:1, 0.45 erreicht 3.29:1 und damit den Richtwert fuer
     grafische Elemente. */
  background: rgba(255, 255, 255, 0.45);
}
/* Auf der hellen Flaeche ist ein weisser Trenner unsichtbar - dort
   dunkel setzen, damit die Gruppierung (Kontakt / Social) erhalten
   bleibt. 0.55 statt der gespiegelten 0.22: als grafisches Element gilt
   der 3:1-Richtwert, und 0.22 kam gegen die helle Glasflaeche nur auf
   1.57:1; 0.55 ergibt 3.51:1. Auf der Split-Flaeche bleibt er hell wie
   die Icons. */
.contact-bar[data-tone="light"] .contact-bar__sep {
  background: rgba(16, 24, 40, 0.55);
}

.contact-bar__link {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out), transform 200ms var(--ease-out);
}
/* Icon-Ton ELEMENTWEISE, nicht pro Leiste: an der Sektionskante misst
   jedes Icon seinen eigenen Untergrund (initContactBarTone in script.js
   setzt data-tone am Link selbst). Vorher galt ein Ton fuer die ganze
   Leiste - am Uebergang zum dunklen Footer standen die unteren Icons
   dadurch dunkel auf dunkel und waren unlesbar.
   Weiss auf der 0.72/0.82-Glasflaeche: >= 7.07:1. Ink auf der hellen
   0.14-Flaeche: >= 11.87:1. Beide klar ueber der 4.5:1-Grenze. */
.contact-bar__link[data-tone="dark"] { color: #fff; }
.contact-bar__link[data-tone="light"] { color: var(--color-ink); }
/* Auf der Kante liegt hinter einem hell gemessenen Icon die dunklere
   Split-Flaeche (0.72) - Ink darauf kaeme nur auf 2.4:1. Dort bleiben
   deshalb alle Icons weiss: 7.07:1 auf der hellen, 17.75:1 auf der
   dunklen Haelfte. */
.contact-bar[data-tone="split"] .contact-bar__link { color: #fff; }

/* Eine Sektionskante kann auch MITTEN durch ein einzelnes Icon laufen -
   dann melden dessen beide Messpunkte Unterschiedliches und es bekommt
   selbst data-tone="split" (siehe initContactBarTone). Weder weiss noch
   Ink traegt auf so einem Icon durchgehend, deshalb bekommt es hier eine
   eigene, DECKENDE Scheibe untergelegt: darauf gilt wieder ein
   definierter Grund (Ink, 15.9:1 fuer das weisse Icon) statt des
   durchscheinenden Verlaufs. */
.contact-bar__link[data-tone="split"] {
  color: #fff;
  background: rgba(16, 24, 40, 0.88);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22);
}
.contact-bar__link svg { width: 18px; height: 18px; }
.contact-bar__link:hover,
.contact-bar__link:focus-visible {
  background: var(--color-accent);
  color: var(--color-ink);
  transform: translateY(-2px);
}
/* "Folgt in Kuerze" (Facebook): bewusst zurueckgenommen, aber nicht
   unsichtbar. 0.4 ergab gemessen nur 2.38:1 gegen die Glasflaeche - als
   deaktiviertes Bedienelement zwar von WCAG 1.4.3 ausgenommen, praktisch
   aber kaum noch erkennbar. 0.62 hebt es auf ~4.6:1 und haelt es damit
   auch fuer sich genommen lesbar, bleibt gegenueber den aktiven Icons
   aber klar abgesetzt. */
.contact-bar__link--soon {
  opacity: 0.62;
  cursor: default;
  pointer-events: none;
}

/* Tooltip: erscheint links neben dem Icon bei Hover/Focus, sonst per
   .visually-hidden-aehnlicher Technik unsichtbar (aber im DOM fuer
   Screenreader lesbar, da aria-label bereits am Link selbst liegt -
   der Tooltip-Text ist rein visuelles Zusatzfeedback, daher aria-hidden). */
.contact-bar__tip {
  position: absolute;
  right: calc(100% + 0.6rem);
  top: 50%;
  transform: translateY(-50%) translateX(4px);
  white-space: nowrap;
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius-sm);
  background: rgba(16, 24, 40, 0.92);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.contact-bar__link:hover .contact-bar__tip,
.contact-bar__link:focus-visible .contact-bar__tip {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Geoeffnetes Popover (Telefon, Adresse): der Hinweis daneben verschwindet sofort, ohne Ausblend-Animation */
.contact-bar__link[aria-expanded="true"] .contact-bar__tip {
  opacity: 0;
  transition: none;
}

/* OSM-Consent-Popover: oeffnet links neben der Leiste, Karte laedt erst
   nach explizitem Klick (siehe initContactBar in script.js). */
.contact-bar__map-popover {
  position: absolute;
  right: calc(100% + var(--space-sm));
  top: 50%;
  transform: translateY(-50%);
  width: min(320px, 80vw);
  z-index: 4;
}
.contact-bar__map-popover[hidden] { display: none; }
.contact-bar__map-popover-inner {
  position: relative;
  background: rgba(16, 24, 40, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--radius);
  padding: var(--space-md);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: 0 18px 44px rgba(16, 24, 40, 0.4);
  color: #fff;
}
.contact-bar__map-close {
  position: absolute;
  top: var(--space-2xs);
  right: var(--space-2xs);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.75);
}
.contact-bar__map-close:hover,
.contact-bar__map-close:focus-visible { background: rgba(255, 255, 255, 0.12); color: #fff; }
.contact-bar__map-close svg { width: 16px; height: 16px; }

/* Telefon-Popover am Rechner: nur die Nummer, einzeilig, auf Hoehe des Telefon-Symbols (script.js, initContactBar) */
.contact-bar__phone-popover { width: auto; }
.contact-bar__phone-popover .contact-bar__map-popover-inner { padding: var(--space-xs) var(--space-md); border-radius: 999px; }
.contact-bar__phone-number {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  user-select: all;
  color: #fff;
}

.contact-bar__map-address {
  margin: 0 var(--space-lg) var(--space-sm) 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.85);
}

.contact-bar__map-popover .map-consent__text {
  color: rgba(255, 255, 255, 0.75);
}
.contact-bar__map-popover .map-consent__link {
  color: rgba(255, 255, 255, 0.75);
}

.contact-bar__map-popover .map-consent__link:hover,
.contact-bar__map-popover .map-consent__link:focus-visible { color: #fff; }

#contact-bar-map-iframe {
  display: block;
  width: 100%;
  height: 220px;
  border: 0;
  border-radius: var(--radius-sm);
}

@media (max-width: 900px), (max-height: 520px) and (orientation: landscape) {
  /* Auf Mobile (auch im Querformat am Handy) klappt die Leiste standardmaessig ein: nur der runde
     Toggle-Button ist sichtbar, die Liste faehrt darueber aus. Statt
     vertikal mittig sitzt sie unten rechts - dort ist sie mit dem Daumen
     erreichbar und verdeckt keinen Sektionsinhalt. */
  .contact-bar {
    top: auto;
    /* UEBER dem To-Top-Button, nicht daneben: beide sind fixed und lagen
       vorher praktisch uebereinander (To-Top 48px ab right:1.5rem, Toggle
       44px ab right:1rem). Gleiche rechte Kante, gestapelt - 48px Hoehe
       des Buttons plus Abstand. Der To-Top erscheint erst nach dem ersten
       Scrollen; der Toggle bleibt dadurch an fester Stelle statt zu
       springen. */
    bottom: calc(var(--space-md) + 48px + var(--space-2xs));
    right: var(--space-md);
    transform: none;
  }
  .contact-bar__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    /* Gleiche Ton-Logik wie .contact-bar__list (siehe dort): passt sich
       per data-tone="light" der Sektion an, ueber der der Button gerade
       liegt, statt fest dunkel zu bleiben. */
    background: rgba(16, 24, 40, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.28);
    color: #fff;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 8px 24px rgba(16, 24, 40, 0.3);
    transition: background-color 200ms var(--ease-out), border-color 200ms var(--ease-out), color 200ms var(--ease-out);
  }
  /* Wie bei den Icons elementweise (siehe Block 9c oben): der Toggle
     misst seinen eigenen Untergrund und kippt allein, auch wenn die
     aufgeklappte Liste darueber schon auf der anderen Sektion liegt. */
  .contact-bar__toggle[data-tone="light"]:not([aria-expanded="true"]) {
    background: rgba(16, 24, 40, 0.14);
    border-color: rgba(16, 24, 40, 0.12);
    color: var(--color-ink);
  }
  .contact-bar__toggle[data-tone="dark"]:not([aria-expanded="true"]) {
    background: rgba(16, 24, 40, 0.82);
    border-color: rgba(255, 255, 255, 0.28);
    color: #fff;
  }
  .contact-bar__toggle svg { width: 20px; height: 20px; }
  .contact-bar__toggle[aria-expanded="true"] { background: var(--color-accent); color: var(--color-ink); }

  .contact-bar__list {
    position: absolute;
    bottom: calc(100% + var(--space-2xs));
    right: 0;
    flex-direction: column;
    max-height: 0;
    padding-block: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-height 260ms var(--ease-out), opacity 200ms var(--ease-out), padding-block 260ms var(--ease-out);
  }
  .contact-bar[data-open="true"] .contact-bar__list {
    max-height: 60vh;
    padding-block: var(--space-2xs);
    opacity: 1;
  }
  .contact-bar__tip { display: none; }
  .contact-bar__map-popover { right: calc(100% - 40px); left: auto; }
}

@media (max-width: 767px) {
  /* Stats werden 2-spaltig hoeher UND der Titel bricht auf mehr Zeilen um -
     zusammen reicht 100svh oft nicht mehr. Die Sektion darf hier deshalb
     ueber 100svh hinaus wachsen (min-height statt starrer Hoehe), damit
     nichts vom overflow:hidden der Sektion abgeschnitten wird. */
  .hero__variant { min-height: auto; }
  /* Die horizontale Haelfte des Fades teilt die Buehne in dunkel links /
     hell rechts - das ergibt nur neben einem Inhalt rechts Sinn. Auf
     Mobile laeuft der Inhalt ueber die volle Breite, hier bleibt allein
     der vertikale Verlauf (dunkler Fuss unter den Stat-Karten). */
  .hero__fade {
    background: linear-gradient(180deg,
      rgba(16, 24, 40, 0) 0%,
      rgba(16, 24, 40, 0) 52%,
      rgba(16, 24, 40, 0.55) 78%,
      rgba(16, 24, 40, 0.82) 100%);
  }
  .hero__content--v2 { margin-left: 0; margin-right: 0; max-width: 100%; }
  .hero__inner--v2 { padding-bottom: 0; }
  .hero__title-line--above { margin-bottom: 0.3em; }
  .hero__title-line--below { margin-top: 0.3em; }

  /* Auf Mobile ist keine Breite fuer eine 4-spaltige Reihe - zurueck in
     den normalen Textfluss als 2x2-Raster. */
  .hero__stats--v2 {
    position: static;
    transform: none;
    grid-template-columns: repeat(2, 1fr);
    width: auto;
    margin-inline: var(--space-sm);
    margin-top: var(--space-lg);
  }

  .hero__scroll-cue { display: none; }
}

/* -----------------------------------------------------------------------
   9e) Scroll-Exit-Fade ("Dissolve on scroll")
   -----------------------------------------------------------------------
   Beim Herausscrollen loest sich die Sektion auf, statt hart nach oben
   wegzuwandern: Deckkraft faellt, der Inhalt zieht sich minimal zurueck
   (scale) und wird weich gezeichnet - dadurch entsteht Tiefe und ein
   weicher Uebergang in die Folgesektion, deren helle Flaeche waehrend-
   dessen durchscheint (body-Hintergrund).

   Zwei Umsetzungswege mit identischer Optik:
   a) Scroll-Driven Animation - laeuft im Compositor, komplett ohne
      JavaScript. Chrome/Edge 116+, Safari 26+.
   b) Fallback ueber die Custom Property --exit (0..1), die
      initSectionExitFade (script.js) beim Scrollen setzt. Nur aktiv, wenn
      (a) nicht unterstuetzt wird (aktuell Firefox, aeltere Safari).

   Zwei Ebenen, weil beide Teile unterschiedliche Elemente brauchen:
   - [data-exit-fade]  = die Sektion, traegt nur die Deckkraft. Ein scale()
     auf ihr wuerde sie schmaler als den Viewport machen und links/rechts
     sowie unten den hellen Seitenhintergrund als harte Kante freilegen.
   - [data-exit-inner] = deckungsgleicher innerer Layer, traegt scale/blur.
     Bewusst per Attribut ausgezeichnet statt per "> *": an der Hero-Sektion
     haengen auch Kontaktleiste und Scroll-Indikator, die bereits eigene
     transform-Werte (translateY(-50%)) tragen und die ein generisches
     scale() ueberschreiben wuerde. Beide blenden ueber die Deckkraft der
     Sektion mit aus - das genuegt.

   Der Effekt haengt an Attributen, laesst sich also ohne CSS-Aenderung auf
   weitere Sektionen uebertragen.
   ----------------------------------------------------------------------- */
[data-exit-fade] {
  --exit: 0;
  will-change: opacity;
}
[data-exit-inner] {
  /* Fluchtpunkt leicht oberhalb der Mitte: der Blick liegt beim Hero auf
     Foto und Kurve, nicht auf den Stat-Karten am unteren Rand. */
  transform-origin: 50% 35%;
}

/* Weg (b): direkt aus der Variablen gerechnet. Steht bewusst VOR dem
   @supports-Block, damit Weg (a) diese Werte ueberschreiben kann. */
[data-exit-fade] {
  opacity: calc(1 - var(--exit));
}
[data-exit-fade] [data-exit-inner] {
  transform: scale(calc(1 - var(--exit) * 0.05));
  filter: blur(calc(var(--exit) * 4px));
}

@keyframes sectionExitFade {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* --- Variante "Vorhang": Aus-/Einblenden ueber einen Farbton -------------
   Die Deckkraft-Variante oben laesst die Sektion TRANSPARENT werden - was
   dahinter liegt (der helle body-Grund), mischt sich dabei mit dem dunklen
   Sektionsgrund zu einem stumpfen Grau (gemessen #989CA5 auf halbem Weg).
   Bei dunklen Sektionen sieht das nach Schmutz aus, nicht nach Aufloesung.

   Stattdessen legt sich hier ein Vorhang im Zielton UEBER die Sektion. Der
   Verlauf geht damit direkt von der Sektionsfarbe in --exit-tone, ohne
   Graustufen dazwischen. Weil derselbe Ton auch die Folgesektion einblendet
   ([data-enter-fade]), laeuft der Uebergang sauber durch EINE gemeinsame
   Flaeche. */
[data-exit-fade="curtain"],
[data-enter-fade] {
  --exit-tone: var(--color-bg);
}

/* Ausnahme fuer die beiden Hero-Buehnen: der helle Standardton ist hier
   falsch. Die Impact-Buehne ist auf ihrer linken Haelfte dunkles Ink -
   ein Vorhang in --color-bg lief dort sichtbar von Weiss auf Anthrazit,
   also genau der harte Bruch, den der Vorhang eigentlich vermeiden soll.
   Dass es lange nicht auffiel, liegt daran, dass --color-bg zugleich der
   Seitenhintergrund ist: der Vorhang las sich als "Platte loest sich in
   die Seite auf" statt als Farbflaeche.

   Beide Buehnen gehen deshalb durch --stage-tone ineinander ueber (links
   dunkel, rechts hell - die Komposition der Impact-Buehne selbst, siehe
   Block 2). Der Vorhang trifft damit auf beiden Bildhaelften die Farbe,
   die dahinter ohnehin steht, und der Uebergang blendet weich durch,
   statt ueber Weiss zu springen.

   WICHTIG: ein vom Seitenton abweichender Vorhang darf nicht mehr ueber
   die sichtbare Platte hinausragen - siehe die Umleitung auf
   .hero__variant--sticky::after weiter unten. */
.hero--intro[data-exit-fade],
.hero--impact[data-enter-fade] {
  --exit-tone: var(--stage-tone);
}

[data-exit-fade="curtain"]::after,
[data-enter-fade]::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Ueber allem Sektionsinhalt (Inhalt liegt bei z-index 1-3), aber
     innerhalb der Sektion - die fixierte Kontaktleiste (z-index 40, auf
     body-Ebene) bleibt dadurch sichtbar und bedienbar. */
  z-index: 5;
  pointer-events: none;
  background: var(--exit-tone);
}

/* Weg (b), aus der Variablen gerechnet (siehe oben). */
[data-exit-fade="curtain"]::after { opacity: var(--exit); }

[data-enter-fade]::before { opacity: calc(1 - var(--enter, 1)); }

/* Die Sektion selbst bleibt undurchsichtig - sonst liefe zusaetzlich zum
   Vorhang noch das Grau-Mischen der Deckkraft-Variante. */
[data-exit-fade="curtain"] { opacity: 1; }

/* --- Enter-Vorhang der Impact-Buehne: auf die Platte umgeleitet --------
   Ab 1024px ist die Impact-SEKTION rund sieben Bildschirme hoch, traegt
   overflow:visible (sonst wuerde position:sticky im Inneren nicht
   funktionieren) und hat keinen Radius. Die sichtbare Platte ist das
   sticky .hero__variant--sticky darin.

   Ein Vorhang auf der Sektion (inset:0) deckt deshalb ein rechteckiges
   Feld ab, das weit ueber die Platte hinausragt - ueber die Fuge zur
   Buehne darueber, ueber die seitliche Luft und ohne die gerundeten
   Ecken. Solange der Vorhangton exakt dem Seitenhintergrund entsprach,
   fiel das nicht auf. Mit --stage-tone waere es ein sichtbares Rechteck
   mit harten Kanten quer ueber die Seite.

   Der Vorhang zieht deshalb in die Platte um: dort beschneiden ihn deren
   border-radius und overflow:hidden auf exakt die Flaeche, um die es
   geht. --enter erbt er ueber die Custom Property von der Sektion, die
   View-Timeline ueber deren timeline-scope (siehe @supports unten).
   Unter 1024px bleibt alles wie gehabt - dort traegt die Sektion selbst
   Rand, Rundung und overflow:hidden, der Vorhang sitzt also schon
   richtig. */
@media (min-width: 1024px) {
  .hero--impact[data-enter-fade]::before { content: none; }

  .hero--impact .hero__variant--sticky::after {
    content: "";
    position: absolute;
    inset: 0;
    /* Ueber der gesamten Choreografie: Chart liegt bei 1, Inhalt bei 2-3,
       der Bereichstitel bei 5. Die sticky Platte bildet einen eigenen
       Stapelkontext, die fixierte Kontaktleiste (z-index 40 auf
       body-Ebene) bleibt daher weiterhin darueber. */
    z-index: 6;
    pointer-events: none;
    background: var(--exit-tone);
    /* Weg (b), analog zu [data-enter-fade]::before oben. */
    opacity: calc(1 - var(--enter, 1));
  }
}

@keyframes sectionCurtainOut {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes sectionCurtainIn {
  from { opacity: 1; }
  to   { opacity: 0; }
}
@keyframes sectionExitRecede {
  from { transform: scale(1);    filter: blur(0); }
  to   { transform: scale(0.95); filter: blur(4px); }
}

/* Weg (a). Die Timeline wird BENANNT (view-timeline-name) statt per
   anonymem view() am inneren Layer aufgesetzt: view() bezoege sich auf den
   naechsten Scroll-Container des Elements - und .hero ist wegen
   overflow:hidden selbst einer. Der innere Layer bekaeme dort eine
   Timeline, die nie laeuft. Die Sektion definiert deshalb die Timeline
   (ihr Scroll-Container ist das Dokument) und gibt sie per timeline-scope
   an ihre Nachfahren weiter.

   "exit" laeuft von dem Moment, in dem die Oberkante der Sektion die
   Oberkante des Viewports erreicht, bis die Sektion vollstaendig oben
   herausgescrollt ist. 30%..92% davon: die ersten 30% bleibt der Hero
   unveraendert stehen (ein sofortiges Ausblenden ab dem ersten
   Scroll-Pixel wirkt nervoes), und die Aufloesung ist abgeschlossen,
   solange die Sektion noch ein Stueck sichtbar ist - sonst faende der
   letzte Teil des Effekts ausserhalb des Bildschirms statt. */
@supports (animation-timeline: view()) and (timeline-scope: --x) {
  /* EINE Timeline fuer Ein- und Austritt. Zwei getrennte Namen (frueher
     --section-exit und --section-enter) waren ein Fehler: view-timeline-name
     ist keine Liste, die sich ueber mehrere Regeln aufsammelt. Auf einer
     Sektion mit BEIDEN Attributen gewann die spaeter notierte Regel, der
     andere Name blieb undefiniert - die zugehoerige Animation hing an einer
     Timeline, die es nicht gab, und liess die Sektion dauerhaft auf
     Deckkraft 0 stehen. Beide brauchen ohnehin dieselbe Timeline: "entry"
     und "exit" sind nur zwei Bereiche derselben View-Progress-Achse. */
  [data-exit-fade],
  [data-enter-fade] {
    view-timeline-name: --section-view;
    timeline-scope: --section-view;
  }

  [data-exit-fade] {
    opacity: 1;
    animation: sectionExitFade linear both;
    animation-timeline: --section-view;
    animation-range: exit 30% exit 92%;
  }
  [data-exit-fade] [data-exit-inner] {
    transform: none;
    filter: none;
    animation: sectionExitRecede linear both;
    animation-timeline: --section-view;
    animation-range: exit 30% exit 92%;
  }

  /* Vorhang-Variante: die Sektion selbst bekommt KEINE Deckkraft-Animation
     (sonst Grau-Mischung, siehe oben), nur der Vorhang darueber. */
  [data-exit-fade="curtain"] {
    opacity: 1;
    animation: none;
  }
  [data-exit-fade="curtain"]::after {
    opacity: 0;
    /* ease-out statt linear: eine lineare Blende zwischen dunklem Grund und
       hellem Ton verbringt die halbe Strecke in einem stumpfen Grau
       (gemessen #989CA5). Mit ease-out ist der Vorhang schon nach einem
       Drittel des Wegs weitgehend geschlossen - der Uebergang liegt damit
       sichtbar IM hellen Ton statt im Graubereich dazwischen. */
    animation: sectionCurtainOut ease-out both;
    animation-timeline: --section-view;
    animation-range: exit 30% exit 92%;
  }

  /* Einblenden aus demselben Ton. "entry" laeuft von dem Moment, in dem
     die Oberkante der Sektion unten in den Viewport tritt, bis sie oben
     ankommt - bei gleich hohen, aufeinanderfolgenden Sektionen also exakt
     synchron zum "exit" der vorherigen. Derselbe 30%..92%-Bereich sorgt
     dafuer, dass beide Vorhaenge deckungsgleich laufen: die eine Sektion
     verschwindet genau in dem Ton, aus dem die naechste auftaucht. */
  [data-enter-fade]::before {
    opacity: 1;
    /* Gegenstueck zu ease-out oben: ease-in haelt den Vorhang lange
       geschlossen und gibt die Sektion erst spaet frei. Zusammen liegen
       beide Sektionen in der Mitte des Uebergangs gleichzeitig im
       gemeinsamen Ton - der Bildschirm laeuft sichtbar durch diese eine
       Flaeche, statt dass eine dunkle Kante von unten hochschiebt. */
    animation: sectionCurtainIn ease-in both;
    animation-timeline: --section-view;
    animation-range: entry 30% entry 92%;
  }

  /* Umgeleiteter Enter-Vorhang der Impact-Buehne (siehe Begruendung
     weiter oben). Er haengt an derselben Timeline wie das Original: der
     Name --section-view ist ueber timeline-scope auf der Sektion auch
     fuer deren Nachfahren sichtbar. */
  @media (min-width: 1024px) {
    .hero--impact .hero__variant--sticky::after {
      opacity: 1;
      animation: sectionCurtainIn ease-in both;
      animation-timeline: --section-view;
      animation-range: entry 30% entry 92%;
    }
  }
}

/* Der Effekt ist reine Dekoration - wer reduzierte Bewegung angefordert
   hat, bekommt die Sektion unveraendert (auch kein Ausblenden, sonst
   verschwaende Inhalt ohne erkennbaren Grund). */
@media (prefers-reduced-motion: reduce) {
  [data-exit-fade],
  [data-exit-fade] [data-exit-inner] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    animation: none !important;
  }
  [data-exit-fade="curtain"]::after,
  [data-enter-fade]::before,
  .hero--impact .hero__variant--sticky::after {
    opacity: 0 !important;
    animation: none !important;
  }
}

/* -----------------------------------------------------------------------
   9f) Referenzen-Vorhang ("halbhoher Titel-Vorhang faehrt beim Scrollen ein")
   -----------------------------------------------------------------------
   referenzen.html: Titel + Lead-Text liegen NICHT mehr in einer eigenen
   Sektion vor dem Karten-Grid, sondern als halbhoher Vorhang UEBER dem
   Grid, das von der ersten Sekunde an sichtbar ist (die Seite wirkt damit
   sofort wie eine Referenz-Uebersicht, nicht wie ein Text-Screen mit dem
   Grid erst nach dem Scrollen). Der Vorhang bleibt beim Laden stehen -
   das Grid ist im oberen Bereich also anfangs verdeckt - und faehrt beim
   Herunterscrollen nach OBEN in seine eigene Hoehe ein (translateY nach
   negativ), bis er komplett verschwunden ist und den vollen Blick aufs
   Grid freigibt.

   "Einfahren" ist hier bewusst eine Bewegung, kein Verblassen (anders als
   9e/9f-alt): ein Vorhang faehrt weg, er loest sich nicht auf. Deckkraft
   bleibt deshalb konstant bei 1, nur transform:translateY aendert sich.

   Zwei Umsetzungswege wie bei den anderen Bloecken:
   a) Scroll-Driven Animation ueber eine BENANNTE Timeline auf einem
      eigenen, unsichtbaren Trigger-Element (.ref-curtain-trigger, siehe
      HTML) statt des generischen view(). Erster Versuch war view() mit
      animation-range: cover - das schlug fehl: "cover" misst ab dem
      Moment, in dem irgendein Pixel der (sehr hohen, das ganze Grid
      enthaltenden) Sektion ueberhaupt sichtbar wird. Bei einer Sektion,
      die schon beim Laden der Seite komplett im Viewport steht, ist
      "cover 0%" also NICHT "Seite gerade geladen", sondern bereits ein
      Wert weit im Bereich - der Vorhang stand dadurch von Anfang an
      eingefahren, nicht sichtbar.
      Der Trigger loest das: ein 60svh hohes, unsichtbares Element direkt
      am Sektionsanfang, dessen "exit"-Bereich (Oberkante verlaesst den
      Viewport oben) exakt den ersten 60svh Scroll-Weg entspricht -
      unabhaengig davon, wie hoch das Grid darunter insgesamt ist.
   b) Fallback per Scroll-Listener (initRefCurtain, script.js). */
.ref-curtain-trigger {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 60svh;
  pointer-events: none;
  view-timeline-name: --ref-curtain-progress;
}

.ref-curtain {
  position: sticky;
  top: 0;
  z-index: 2;
  /* Deckt beim Laden den oberen Teil des Viewports ab, der obere Rand des
     Grids ist bereits als Ankuendigung sichtbar.
     38% statt der frueheren 50%: Titel und Zweizeiler brauchen die halbe
     Bildschirmhoehe nicht - darunter stand sichtbar leere Flaeche, bevor
     die erste Kachel begann. */
  min-height: calc(38svh - var(--nav-pill-h));
  display: flex;
  align-items: center;
  /* Eigener Grund + Blur: der Vorhang liegt UEBER dem Grid (z-index 2 vs.
     0), braucht also eine deckende Flaeche, sonst schimmern die
     Bildkacheln durch den Text. Rein dunkel (kein Verlauf) haette gegen
     .section--carbon einen sichtbaren Farbsprung erzeugt - der Verlauf
     blendet stattdessen weich in den Carbon-Ton der Sektion aus. */
  background: linear-gradient(180deg, #0c1119 0%, #0c1119 75%, rgba(12, 17, 25, 0) 100%);
  --curtain-shift: 0px;
  transform: translateY(var(--curtain-shift));
  will-change: transform;
}

@supports (animation-timeline: view()) and (timeline-scope: --x) {
  /* timeline-scope MUSS auf einem gemeinsamen VORFAHREN von Trigger und
     Vorhang sitzen, nicht auf dem Trigger selbst - Trigger und
     .ref-curtain sind Geschwister (beide direkte Kinder der Section),
     keine Eltern-Kind-Beziehung. Ohne diese Korrektur bekam .ref-curtain
     den Namen --ref-curtain-progress gar nicht zu sehen, seine Animation
     lief ins Leere und blieb auf dem "both"-Endzustand haengen - der
     Vorhang stand von der ersten Sekunde an eingefahren.
     Eigenes Attribut [data-ref-curtain-scope] statt der generischen
     .section--carbon-Klasse: falls diese Klasse spaeter fuer eine andere
     Sektion ohne Vorhang wiederverwendet wird, soll dort keine ungenutzte
     Timeline mitgeschleppt werden. */
  [data-ref-curtain-scope] { timeline-scope: --ref-curtain-progress; }
  .ref-curtain {
    animation: refCurtainRetract linear both;
    animation-timeline: --ref-curtain-progress;
    /* "exit" des Triggers: 0% = seine Oberkante beruehrt die
       Viewport-Oberkante (praktisch der Seitenanfang, da der Trigger auf
       top:0 der Sektion sitzt), 100% = seine Oberkante hat den Viewport
       oben komplett verlassen - also exakt 60svh Scroll-Weg, seine
       eigene Hoehe. */
    animation-range: exit 0% exit 100%;
  }
}
@keyframes refCurtainRetract {
  from { transform: translateY(0); }
  /* -60svh statt -100%: der Vorhang ist "position: sticky", %-Werte bei
     transform beziehen sich auf seine eigene (halbe Viewport-)Hoehe -
     -100% wuerde ihn nur um seine eigene Hoehe verschieben, also gerade
     eben aus dem Bild. -60svh schiebt ihn sicher darueber hinaus, auch
     wenn min-height durch den Inhalt (langer Lead-Text) etwas waechst. */
  to   { transform: translateY(-60svh); }
}

@media (prefers-reduced-motion: reduce) {
  .ref-curtain {
    position: static;
    transform: none !important;
    animation: none !important;
  }
}

/* -----------------------------------------------------------------------
   9b) Leistungen — Full-Viewport-Sektionen (leistungen.html)
   ----------------------------------------------------------------------- */
.lst {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  scroll-margin-top: calc(var(--nav-pill-h) + var(--space-md));
}

.lst__intro-content,
.lst__content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 760px;
  padding-block: var(--space-2xl);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
}

.lst--intro .lst__intro-content {
  align-items: center;
  text-align: center;
  max-width: 640px;
}

.lst__index {
  font-family: var(--font-display);
  font-size: clamp(3rem, 7vw, 5rem);
  line-height: 1;
  color: rgba(255, 255, 255, 0.18);
  -webkit-text-stroke: 1.5px rgba(255, 255, 255, 0.5);
}

.lst__title {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.5vw + 1rem, 3.25rem);
  line-height: 1.1;
  color: inherit;
}

.lst__lead {
  font-size: clamp(1.05rem, 1vw + 0.95rem, 1.25rem);
  line-height: 1.6;
  max-width: 56ch;
  text-wrap: pretty;
  opacity: 0.9;
}

.lst__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-2xs);
}

/* Rechte untere Ecke der Section, links neben dem (bildschirmfixierten)
   To-Top-Button - dieselbe bottom-Distanz wie .scroll-cue/.to-top, damit
   alle drei auf gleicher Hoehe stehen. Nur Desktop, siehe Media-Query. */
.lst__scroll-btn {
  position: absolute;
  right: calc(var(--space-md) + 48px + var(--space-sm));
  bottom: var(--space-md);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.4);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 200ms var(--ease-out), background-color 200ms var(--ease-out), border-color 200ms var(--ease-out);
  animation: lst-bounce 2200ms ease-in-out infinite;
}

.lst__scroll-btn:hover,
.lst__scroll-btn:focus-visible {
  background: rgba(255, 255, 255, 0.12);
  transform: translateY(4px);
}
.lst__scroll-btn svg { width: 22px; height: 22px; }

.lst__scroll-btn--light {
  border-color: rgba(20, 33, 61, 0.35);
  color: var(--color-ink);
}

.lst__scroll-btn--light:hover,
.lst__scroll-btn--light:focus-visible { background: rgba(20, 33, 61, 0.08); }

@keyframes lst-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(8px); }
}

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

@media (max-width: 767px) {
  .lst__scroll-btn { display: none; }
}

/* -----------------------------------------------------------------------
   10) Leistungen / Services grid
   ----------------------------------------------------------------------- */
.services-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}

@media (min-width: 640px) {
  .services-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .services-grid { grid-template-columns: repeat(3, 1fr); }
}

.service-card {
  position: relative;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-lg) var(--space-md) var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  transition: transform 250ms var(--ease-out), box-shadow 250ms var(--ease-out), border-color 250ms var(--ease-out);
}
.service-card:hover,
.service-card:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
}

.service-card__icon {
  width: 52px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}
.service-card__icon svg { width: 26px; height: 26px; }

.service-card__title {
  font-size: 1.15rem;
}

.service-card__text {
  color: var(--color-text-muted);
  font-size: 0.9375rem;
}

.service-card__link {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--color-primary);
  padding-top: var(--space-2xs);
}
.service-card__link svg {
  width: 16px;
  height: 16px;
  transition: transform 200ms var(--ease-out);
}
.service-card__link:hover svg,
.service-card__link:focus-visible svg { transform: translateX(3px); }

/* -----------------------------------------------------------------------
   10b) Leistungen-Slideshow (Startseite) — horizontal scrollbar, Hover-Teaser + Modal
   ----------------------------------------------------------------------- */
/* Breiter als der Textcontainer: aus dem Raster ausbrechen und mittig stellen.
   Die Pfeile sitzen als eigene Flex-Spalten links und rechts neben dem Track. */
.svc-slideshow {
  position: relative;
  width: min(calc(100vw - 3rem), 1560px);
  margin-left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.svc-track {
  flex: 1;
  min-width: 0; /* erlaubt dem Flex-Kind zu schrumpfen und zu scrollen */
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  /* Luft fuer die auf 110% vergroesserte Hover-Karte: overflow-x:auto
     beschneidet sonst auch oben und unten */
  padding-block: 22px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-primary) var(--color-bg-soft);
}
.svc-track::-webkit-scrollbar { height: 8px; }
.svc-track::-webkit-scrollbar-track { background: var(--color-bg-soft); border-radius: 4px; }
.svc-track::-webkit-scrollbar-thumb { background: var(--color-primary); border-radius: 4px; }

/* Pfeil-Buttons */
.svc-nav {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-sm);
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out),
              transform 200ms var(--ease-out), opacity 200ms var(--ease-out);
}
.svc-nav svg { width: 22px; height: 22px; }

.svc-nav:hover:not(:disabled),
.svc-nav:focus-visible:not(:disabled) {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
  transform: scale(1.06);
}
.svc-nav:active:not(:disabled) { transform: scale(1); }
.svc-nav:disabled { opacity: 0.35; cursor: not-allowed; }

.svc-slideshow__cta {
  margin-top: var(--space-sm);
  text-align: center;
}

/* Auf schmalen Geraeten wird gewischt statt geklickt */
@media (max-width: 767px) {
  .svc-slideshow {
    width: auto;
    margin-left: 0;
    transform: none;
  }
  .svc-nav { display: none; }
  .svc-track {
    padding-inline: var(--space-sm);
    margin-inline: calc(var(--space-sm) * -1);
  }
}

.svc-card {
  position: relative;
  flex: 0 0 auto;
  width: min(78vw, 320px);
  aspect-ratio: 3 / 4;
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  background: var(--color-ink);
  transition: transform 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}

/* Gehoverte Karte waechst um 10% und legt sich ueber die Nachbarn */
.svc-card:hover,
.svc-card:focus-within {
  transform: scale(1.1);
  z-index: 2;
  box-shadow: 0 22px 48px rgba(16, 24, 40, 0.32);
}

@media (prefers-reduced-motion: reduce) {
  .svc-card:hover,
  .svc-card:focus-within { transform: none; }
}
@media (min-width: 640px) {
  .svc-card { width: min(42vw, 320px); }
}
@media (min-width: 1024px) {
  /* etwas flacher als 3/4, damit Sektionskopf, Karten, CTA und der
     Erkunden-Indikator zusammen in eine Bildschirmhoehe passen */
  .svc-card { width: 300px; aspect-ratio: 6 / 7; }
}

.svc-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
.svc-card:hover .svc-card__img,
.svc-card:focus-within .svc-card__img { transform: scale(1.06); }

.svc-card__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(16, 24, 40, 0.05) 0%, rgba(16, 24, 40, 0.75) 100%);
}

.svc-card__badge {
  position: absolute;
  top: var(--space-sm);
  left: var(--space-sm);
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(6px);
  color: #fff;
  border-radius: var(--radius-pill);
  padding: 0.35rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
}

.svc-card__info {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(6px);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.svc-card__info:hover,
.svc-card__info:focus-visible {
  background: var(--color-accent);
  color: var(--color-ink);
  transform: scale(1.08);
}
.svc-card__info svg { width: 18px; height: 18px; }

.svc-card__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-md);
  color: #fff;
}

.svc-card__title {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 700;
  color: #fff;
}

.svc-card__teaser {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.85);
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 300ms var(--ease-out), opacity 250ms var(--ease-out), margin-top 300ms var(--ease-out);
}
.svc-card:hover .svc-card__teaser,
.svc-card:focus-within .svc-card__teaser {
  max-height: 100px;
  opacity: 1;
  margin-top: var(--space-2xs);
}

/* Leistungen-Modal */
.service-modal {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms var(--ease-out);
}
.service-modal.is-open { opacity: 1; pointer-events: auto; }

.service-modal__overlay {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, 0.6);
}

.service-modal__panel {
  position: relative;
  width: min(100%, 880px);
  max-height: 88svh;
  overflow-y: auto;
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  display: grid;
  grid-template-columns: 1fr;
  transform: scale(0.96);
  transition: transform 250ms var(--ease-out);
}
.service-modal.is-open .service-modal__panel { transform: scale(1); }

@media (min-width: 768px) {
  .service-modal__panel { grid-template-columns: 1fr 1.1fr; max-height: 640px; }
}

.service-modal__image {
  min-height: 220px;
  background-size: cover;
  background-position: center;
  background-color: var(--color-primary-soft);
}

.service-modal__content {
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.service-modal__title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
}

.service-modal__desc {
  color: var(--color-text-muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.service-modal__price {
  font-weight: 700;
  color: var(--color-primary);
  font-size: 0.9375rem;
}

.service-modal__actions {
  margin-top: auto;
  padding-top: var(--space-sm);
}

.service-modal__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-bg-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  transition: background-color 200ms var(--ease-out);
}

.service-modal__close:hover,
.service-modal__close:focus-visible { background: var(--color-border); }
.service-modal__close svg { width: 18px; height: 18px; }

/* -----------------------------------------------------------------------
   11) Prozess / Steps
   ----------------------------------------------------------------------- */
.process {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 768px) {
  .process { grid-template-columns: repeat(3, 1fr); }
}

.process__card {
  position: relative;
  height: 380px;
  border-radius: var(--radius-lg, 16px);
  perspective: 1400px;
}

.process__card-face {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: linear-gradient(180deg, rgba(10, 14, 20, 0.15) 0%, rgba(10, 14, 20, 0.75) 100%), var(--process-img);
  background-size: cover;
  background-position: center;
  color: #fff;
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transition: transform 500ms ease;
  box-shadow: 0 10px 30px rgba(10, 14, 20, 0.18);
}

.process__card-face--front { transform: rotateY(0deg); }
.process__card-face--back  { transform: rotateY(180deg); }

.process__card:hover .process__card-face--front { transform: rotateY(180deg); }
.process__card:hover .process__card-face--back  { transform: rotateY(360deg); }

.process__num {
  font-family: var(--font-display);
  font-size: 2.25rem;
  line-height: 1;
  color: #fff;
  opacity: 0.85;
  display: block;
  margin-bottom: var(--space-3xs);
}

.process__card-face h3 { font-size: 1.15rem; margin-bottom: var(--space-3xs); color: #fff; }
.process__card-face--back p { color: rgba(255, 255, 255, 0.88); font-size: 0.9375rem; margin: 0; }

/* -----------------------------------------------------------------------
   12) Cards / Referenzen
   ----------------------------------------------------------------------- */
/* Eigener, breiterer Wrapper statt .container (das auf max-width:1200px
   begrenzt ist): die Sektion soll die Bildschirmbreite fast vollstaendig
   ausnutzen, nur ein schmaler Rand (max 5vw, nach oben hin bei var(--space-lg)
   gedeckelt) bleibt als Luft zum Viewport-Rand. */
/* Abstand zwischen Galerie und der Handlungsaufforderung darunter. Die
   beiden stehen jetzt in DERSELBEN Sektion (frueher hatte der CTA eine
   eigene .section--full und damit eine reservierte Bildschirmhoehe fuer
   einen Textblock), der Carbon-Grund laeuft also einfach weiter. */
/* Einladungs-Kachel als Abschluss der Galerie.
   Sie ersetzt das frueher darunter stehende CTA-Band: dessen Flaeche trug
   praktisch denselben Carbon-Ton wie der Sektionsgrund und hob sich kaum
   ab - ein Kasten, den man nur am Rand erkannte. Als Kachel steht die
   Aussage dort, wo der Blick nach der letzten Referenz ohnehin hinlaeuft.

   Schmaler als die beiden Referenzen daneben (0.62fr gegen 1fr): sie
   soll als Abschluss lesbar sein, nicht als sechstes Projekt. */
.ref-card--invite {
  --card-accent: var(--color-accent);
  /* Etwas kleiner als die echten Referenzkarten, aber ueber einen
     gleichmaessigen Rand auf allen vier Seiten statt ueber eine eigene,
     schmalere Grid-/Flex-Zelle (siehe .ref-grid__row-2 weiter oben) -
     dadurch bleibt die Zeile bei gleich grossen Zellen, die Kachel wirkt
     innerhalb ihrer Zelle aber sichtbar zurueckgesetzt/abschliessend. */
  margin: var(--space-sm);
}
@media (max-width: 639px) {
  /* Auf Mobile stehen alle Karten einspaltig im normalen Fluss (siehe
     .ref-grid__row-2 display:contents weiter oben) - der Rand soll dort
     nicht die volle Breite kappen. */
  .ref-card--invite { margin: 0; }
}
/* Das Bild ist ein Platzhalter, kein echter Screenshot - es tritt
   deshalb hinter den Text zurueck, waehrend die Referenzbilder selbst
   die Aussage tragen. */
.ref-card--invite .ref-card__media {
  opacity: 0.62;
  transform: none;
  /* Der Platzhalter zeigt oben den Desktop, unten das Smartphone - der
     obere Ausschnitt allein waere nur eine Browserleiste. */
  object-position: center 28%;
}
.ref-card--invite:hover .ref-card__media,
.ref-card--invite:focus-within .ref-card__media {
  opacity: 0.72;
  transform: scale(1.03);
}
/* Kraeftigerer Verlauf als bei den Referenzkarten: hier steht mehr Text
   ueber dem Bild, und er soll durchgehend gut lesbar sein. */
.ref-card--invite .ref-card__body::before {
  opacity: 1;
}
.ref-card--invite .ref-card__title {
  font-size: clamp(1.05rem, 0.7vw + 0.9rem, 1.35rem);
}
.ref-card--invite .ref-card__text--full {
  color: rgba(255, 255, 255, 0.86);
  font-size: 0.875rem;
}
/* Sichtbarer Knopf statt eines blossen Links: die Kachel ist als Ganzes
   klickbar (.ref-card__link darueber), der Knopf zeigt das an. */
.ref-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  align-self: flex-start;
  margin-top: var(--space-2xs);
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-ink);
  font-size: 0.875rem;
  font-weight: 700;
  transition: background-color 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.ref-card__cta svg { width: 16px; height: 16px; }
.ref-card--invite:hover .ref-card__cta,
.ref-card--invite:focus-within .ref-card__cta {
  background: var(--color-accent-deep);
  transform: translateX(3px);
}

.ref-wrap {
  width: 100%;
  padding-inline: min(5vw, var(--space-lg));
}

/* Dicht gepacktes Raster: sehr schmaler Gap (space-3xs statt -sm), damit
   die Karten wie in der Vorlage fast nahtlos aneinanderstossen statt
   als einzelne, luftig getrennte Kacheln zu wirken. */
.ref-grid {
  display: grid;
  grid-template-columns: 1fr;
  /* Etwas grosszuegiger als der vorherige space-3xs: bei fuenf statt
     sechs Karten (Faminvest entfernt) wirkte der sehr enge Abstand
     zusammen mit der unvollstaendigen letzten Zeile schnell wie ein
     Layoutfehler statt wie eine bewusste Bildkachel-Aneinanderreihung. */
  gap: var(--space-2xs);
}
@media (min-width: 640px) {
  .ref-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  /* Bleibt bei 3 Spalten (statt z.B. 4): passend zur Kachelbreite der
     ersten Zeile (Kilbad/Urbankunst/Ibons). Die zweite Zeile (Abviris,
     BS13 - Faminvest entfernt) haette hier sonst 2 von 3 Spalten
     linksbuendig belegt, mit einer Luecke rechts. Siehe .ref-grid__row-2
     unten fuer die Zentrierung dieser unvollstaendigen letzten Zeile. */
  .ref-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Wrapper NUR um die zwei Karten der unvollstaendigen letzten Zeile
   (Abviris, BS13) - eigenes HTML-Element statt eines CSS-Tricks auf den
   .ref-card-Kindern selbst: eine einzelne Karte als Flex-Container fuer
   ihre Schwesterkarte umzudefinieren waere strukturell schief (beide sind
   Geschwister im Grid, keine Eltern-Kind-Beziehung). Der Wrapper spannt
   ueber die volle Grid-Breite (grid-column: 1/-1 in allen Breakpoints, da
   .ref-grid durchgehend eine einzige Spalten-Definition pro Breakpoint
   hat) und zentriert seinen Inhalt selbst per Flex - unabhaengig davon,
   ob das aeussere Grid gerade 1, 2 oder 3 Spalten hat. */
.ref-grid__row-2 {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}
/* Kartenbreite = EINE Grid-Spaltenbreite (nicht 50% des Wrappers!). Der
   Wrapper spannt die volle Grid-Breite, 50% davon waere in einem
   3-spaltigen Grid deutlich breiter als eine echte Spalte und liesse die
   Reihe sichtbar in die naechste Zeile hineinlaufen (genau das ist beim
   ersten Anlauf passiert). --ref-cols/--ref-gaps steuern die Formel pro
   Breakpoint, damit die Kartenbreite exakt der jeweiligen Spaltenzahl des
   umgebenden Grids entspricht: bei n Spalten und (n-1) Gaps dazwischen
   ist eine Spalte (100% - (n-1)*gap) / n breit. */
.ref-grid__row-2 {
  --ref-cols: 2;
}
@media (min-width: 1024px) {
  .ref-grid__row-2 { --ref-cols: 3; }
}
.ref-grid__row-2 .ref-card {
  flex: 0 0 calc((100% - (var(--ref-cols) - 1) * var(--space-2xs)) / var(--ref-cols));
  max-width: calc((100% - (var(--ref-cols) - 1) * var(--space-2xs)) / var(--ref-cols));
}
/* Alle fuenf Referenzkarten teilen sich dieselbe Zellengroesse (siehe
   .ref-grid__row-2 .ref-card oben) - die Einladungs-Kachel bekommt ihre
   kleinere, abschliessende Wirkung nicht mehr durch eine schmalere Zelle
   (das liess die Reihe zuvor asymmetrisch wirken), sondern durch einen
   gleichmaessigen Rand auf allen vier Seiten INNERHALB ihrer gleich
   grossen Zelle (siehe .ref-card--invite margin weiter oben). Die
   Zell-AUSSENKANTE (Inhalt + Rand) bleibt dabei exakt so breit wie bei
   den echten Referenzkarten - deshalb hier die Flex-Basis um den
   doppelten Rand (links+rechts) reduziert, sonst wuerde die Zeile durch
   den zusaetzlichen Rand umbrechen. */
.ref-grid__row-2 .ref-card--invite {
  flex-basis: calc((100% - (var(--ref-cols) - 1) * var(--space-2xs)) / var(--ref-cols) - 2 * var(--space-sm));
  max-width: calc((100% - (var(--ref-cols) - 1) * var(--space-2xs)) / var(--ref-cols) - 2 * var(--space-sm));
}
@media (max-width: 639px) {
  /* Einspaltiges Mobile-Layout: der Wrapper soll dort NICHT zentrieren
     oder nebeneinander anordnen, sondern wie jede andere Karte einfach
     im Fluss stehen - sonst wuerden Abviris/BS13 auf schmalen Screens
     nebeneinander gequetscht statt wie alle anderen volle Breite zu
     nutzen. */
  .ref-grid__row-2 { display: contents; }
  /* Die Breitenvorgabe des Wrappers muss hier mit zurueckgesetzt werden.
     Mit display:contents verschwindet zwar der Wrapper als Box, die
     Regel greift aber weiterhin auf seine Kinder - sie standen dadurch
     auf calc(50% - 4px) in einer einspaltigen Grid-Spalte und waren
     gemessen nur 172px breit: Text lief aus der Karte, der Knopf brach
     auf drei Zeilen um. */
  .ref-grid__row-2 .ref-card,
  .ref-grid__row-2 .ref-card--invite,
  .ref-grid__row-2 .ref-card:not(.ref-card--invite) {
    flex: initial;
    max-width: none;
  }
}

/* Karte = vollflaechiges Hintergrundbild, Text liegt als Overlay direkt
   darauf (kein separater heller Body-Block mehr darunter) - naeher an
   der Vorlage, wirkt wie eine Bildkachel statt wie eine klassische
   Content-Karte. Kein eigener border-radius mehr: die Karten sollen
   wie in der Vorlage kantig aneinanderstossen. */
.ref-card {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--color-ink);
  /* Grundton, falls eine Karte einmal keinen eigenen bekommt. */
  --card-accent: rgba(255, 255, 255, 0.7);
  transition: transform 250ms var(--ease-out), box-shadow 250ms var(--ease-out);
}

/* Farbiger Rand beim Hovern, je Karte im Ton ihres eigenen Bildes.
   Bisher hatte KEINE Karte einen Rand - was bei Ibons wie einer aussah,
   war schlicht deren gruener Seiten-Screenshot, der bis an die Kante
   lief. Das Prinzip ist hier bewusst gebaut statt zufaellig: die Farben
   sind aus den fuenf Bildern ausgezaehlt (haeufigster kraeftiger Ton,
   Schwarz/Weiss-Bereiche ausgenommen) und so weit aufgehellt, dass sie
   auf dem Carbon-Grund tragen - gemessen 6.0:1 bis 8.9:1, deutlich ueber
   dem 3:1-Richtwert fuer grafische Elemente.

   Als Pseudo-Element statt border/outline: ein echter Rahmen wuerde die
   Kartenmasse veraendern und damit das Grid verschieben; outline haette
   die abgerundete Ecke der Randkarten nicht mitgenommen. */
.ref-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border: 2px solid transparent;
  border-radius: inherit;
  transition: border-color 250ms var(--ease-out), box-shadow 250ms var(--ease-out);
}
.ref-card:hover,
.ref-card:focus-within {
  transform: scale(1.015);
  box-shadow: 0 20px 48px rgba(0, 0, 0, 0.55);
  z-index: 2;
}
.ref-card:hover::after,
.ref-card:focus-within::after {
  border-color: var(--card-accent);
  /* Zwei Schichten:
     - der Schein nach innen laesst den Rand leuchten, statt ihn nur als
       harte Linie auf das Bild zu legen;
     - der duenne dunkle Saum DAVOR trennt ihn von hellen Bildbereichen.
       Ohne ihn verschwand der Rand dort, wo das Bild selbst hell ist -
       bei Kilbad (Badezimmer in Beton und Grau) kam er gegen die helle
       Flaeche nur auf 1.1:1. Gegen den Saum sind es 3.71:1, damit auch
       auf der hellsten Karte ueber dem 3:1-Richtwert - unabhaengig
       davon, was im Bild darunter liegt. */
  box-shadow: inset 0 0 0 3px rgba(8, 12, 20, 0.65),
              inset 0 0 22px -6px var(--card-accent);
}

/* Je Karte der Ton ihres Bildes (ausgezaehlt, siehe oben). */
/* Kilbad ist als einziges Bild fast farblos (gemessen 0.8% kraeftige
   Toene - eine Badezimmer-Aufnahme in Beton und Grau). Ein saturierter
   Ton daraus gaebe es nur im roten "SALES %" der Navigationsleiste - das
   waere eine Farbe des Screenshots, nicht des Projekts. Deshalb der
   warme Grundton des Bildes selbst. */
.ref-card--kilbad     { --card-accent: #c4a684; }  /* Beton/Warmgrau */
.ref-card--urbankunst { --card-accent: #f09660; }  /* Orange des Posters */
.ref-card--ibons      { --card-accent: #60c848; }  /* Verpackungsgruen */
.ref-card--abviris    { --card-accent: #4096e0; }  /* Medizin-Blau */
.ref-card--bs13       { --card-accent: #40b0a8; }  /* Petrol der Bento-Kachel */

/* Deckt die gesamte Karte ab und macht sie komplett klickbar. Sichtbarer
   Fokusring kommt vom Link selbst, nicht von der Karte, damit
   Tastaturnutzer den echten Link umrandet sehen. */
.ref-card__link {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.ref-card__link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* Vollflaechiges Hintergrundbild der Karte. object-position ist absichtlich
   je Variante unterschiedlich (siehe --pos-* Modifier unten) - so wirkt
   das Grid abwechslungsreich (mal ganze Startseite, mal reingezoomter
   Ausschnitt) statt sechsmal dasselbe Schema zu wiederholen. Dezenter
   Hover-Zoom aufs Bild selbst (zusaetzlich zum Karten-Scale), damit die
   Bewegung beim Hover mehrschichtig statt flach wirkt. */
.ref-card__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  transition: transform 400ms var(--ease-out);
}
.ref-card:hover .ref-card__media,
.ref-card:focus-within .ref-card__media {
  transform: scale(1.05);
}
/* Platzhalter-Variante (noch kein echtes Bild vorhanden): Farbflaeche
   mit zentriertem Kuerzel statt <img>, damit eine Karte im Grid nicht
   leer bleibt, bis ein Foto nachgereicht wird. Aktuell ungenutzt (die
   fruehere Faminvest-Karte, die diese Variante brauchte, wurde entfernt)
   - bleibt fuer das naechste Projekt ohne Bildmaterial erhalten. */
.ref-card__media--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-family: var(--font-display);
  font-size: 1.75rem;
}

/* Drei Crop-Varianten fuer Bildvarianz im Grid: ganze Seite oben
   ausgerichtet (Default), mittig gezoomter Ausschnitt, und unten
   ausgerichtet - ersetzt echte Mockup-Fotos (Laptop auf Tisch etc.),
   solange dafuer kein Bildmaterial vorliegt. */
.ref-card__media--top { object-position: top center; }
.ref-card__media--zoom { object-position: center 30%; }
.ref-card__media--bottom { object-position: bottom center; }
/* BS13-Screenshot zeigt ein Bento-Kachel-Raster - zoomt gezielt auf die
   mittlere Kachel (Gebaeudefoto mit bs13-Schriftzug) statt das ganze
   Raster verkleinert zu zeigen. */
.ref-card__media--bs13 {
  object-position: 58% 22%;
  transform: scale(1.6);
}
.ref-card:hover .ref-card__media--bs13,
.ref-card:focus-within .ref-card__media--bs13 {
  transform: scale(1.68);
}

/* Text-Overlay: liegt direkt auf dem Bild, unten in der Karte. Eigener
   Blur-Hintergrund (kein Volltonhintergrund) fuer Lesbarkeit ueber jedem
   beliebigen Foto, ohne das Bild komplett zu verdecken - siehe Vorlage. */
.ref-card__body {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 1;
  padding: var(--space-sm) var(--space-md);
  padding-top: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: linear-gradient(to top, rgba(6, 8, 13, 0.92) 0%, rgba(6, 8, 13, 0.75) 55%, transparent 100%);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.ref-card__tag {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
}

.ref-card__title { font-size: 1.05rem; color: #fff; }
.ref-card__text {
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.875rem;
  /* Beschreibung standardmaessig geklemmt auf 2 Zeilen, damit die Karten
     im Grid trotz unterschiedlich langer Texte gleich hoch bleiben - der
     Bild-Anteil soll nicht je nach Textlaenge schrumpfen/wachsen. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Vollstaendiger Projekttext aus dem Original, unter der Kurzzeile.
   Ohne eigene Regel haette ihn die 2-Zeilen-Klemme oben abgeschnitten -
   genau die Kuerzung, die hier vermieden werden soll. Deshalb Klemme
   aufheben und den Absatz optisch als Fliesstext absetzen: eine Spur
   kleiner und ruhiger als die Kurzzeile, mit etwas Luft darueber. */
.ref-card__text--full {
  display: block;
  -webkit-line-clamp: none;
  overflow: visible;
  margin-top: var(--space-2xs);
  font-size: 0.8125rem;
  line-height: 1.65;
  color: rgba(255, 255, 255, 0.62);
  text-wrap: pretty;
}

/* -----------------------------------------------------------------------
   13) Testimonial / Quote
   ----------------------------------------------------------------------- */
.quote {
  position: relative;
  background: var(--color-primary);
  color: #fff;
  border-radius: var(--radius);
  padding: var(--space-xl) var(--space-lg);
  overflow: hidden;
}
.quote::before {
  content: "\201C";
  position: absolute;
  top: -0.4em;
  left: var(--space-md);
  font-family: var(--font-display);
  font-size: 10rem;
  color: rgba(255, 255, 255, 0.1);
  line-height: 1;
}
.quote__text {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2vw + 1rem, 1.75rem);
  font-weight: 500;
  line-height: 1.4;
  max-width: 60ch;
}
.quote__author {
  position: relative;
  margin-top: var(--space-md);
  font-weight: 600;
  color: var(--color-accent);
}
.quote__author span {
  display: block;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.875rem;
}

/* -----------------------------------------------------------------------
   14) CTA-Band
   ----------------------------------------------------------------------- */
.cta-band {
  background: var(--color-ink);
  color: #fff;
  border-radius: var(--radius);
  padding: var(--space-xl) var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  align-items: flex-start;
}
.cta-band h2 { color: #fff; }
.cta-band p { color: rgba(255, 255, 255, 0.75); max-width: 60ch; }

@media (min-width: 768px) {
  .cta-band {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* -----------------------------------------------------------------------
   15) Kontakt-Seite
   ----------------------------------------------------------------------- */
/* -----------------------------------------------------------------------
   Termin-App auf der Kontaktseite (.booking) + Beleg (.doc)
   -----------------------------------------------------------------------
   Ersetzt das einfache Kontaktformular durch einen vierschrittigen
   Ablauf. Sichtbar ist immer nur ein Schritt (hidden wird per JS
   umgesetzt, siehe initContactForm); die uebrigen bleiben im DOM, damit
   die bereits eingegebenen Werte beim Zurueckspringen erhalten bleiben.
   ----------------------------------------------------------------------- */
.booking {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  /* min-width:0 auf BEIDEN Ebenen noetig: das Formular ist Grid-Item von
     .contact-grid (Vorgabe dort ist min-width:auto) und enthaelt
     <fieldset>, deren Browser-Default min-width:min-content ist. Ohne
     beides zog der breiteste Inhalt - die Slot-Spalten - das Formular
     auf 458px in einer 358px breiten Spalte; gemessen lief die Seite
     dadurch auf Mobil um 84px ueber. */
  min-width: 0;
}

/* Die Schritte sind <fieldset> - deren Browser-Default (Rahmen, Padding,
   min-width:min-content) wuerde das Raster darin sprengen. */
.booking__step {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
/* display:flex oben schlaegt die Browser-Regel [hidden]{display:none} -
   ohne diese Zeile blieben ausgeblendete Schritte im Layout stehen
   (gemessen 707px Hoehe trotz hidden=true), sodass alle vier Schritte
   untereinander sichtbar waren. */
.booking__step[hidden] { display: none; }

.booking__legend {
  padding: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.125rem;
  color: var(--color-ink);
}

/* --- Fortschrittsanzeige ---------------------------------------------- */
.booking__progress {
  display: flex;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.booking__progress li {
  flex: 1;
  padding-top: var(--space-2xs);
  border-top: 3px solid var(--color-border);
  transition: color 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
.booking__progress li.is-done { border-top-color: var(--color-primary); color: var(--color-text); }
.booking__progress li.is-current { border-top-color: var(--color-primary); color: var(--color-primary); }

/* --- Schritt 1: Terminarten ------------------------------------------- */
.booking__types {
  display: grid;
  gap: var(--space-2xs);
}

/* Das Radio selbst ist ausgeblendet, aber NICHT display:none - es muss
   fokussierbar bleiben, damit die Auswahl per Tastatur funktioniert.
   Der sichtbare Zustand haengt an :checked / :focus-visible der Karte. */
.booking-type {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  cursor: pointer;
  transition: border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out), background-color 180ms var(--ease-out);
}

.booking-type:hover,
.booking-type:focus-visible { border-color: var(--color-primary); }
.booking-type input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.booking-type:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  box-shadow: 0 0 0 1px var(--color-primary);
}
.booking-type:has(input:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Farbpunkt je Terminart - uebernimmt die Farbcodierung des Originals,
   damit die Arten auch ohne Lesen unterscheidbar bleiben. */
.booking-type__dot {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 0.15rem;
  border-radius: 50%;
  background: var(--type-color, var(--color-primary));
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.9), 0 0 0 4px rgba(16, 24, 40, 0.08);
}
.booking-type__body { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.booking-type__name { font-weight: 700; color: var(--color-ink); }
.booking-type__meta { font-size: 0.8125rem; color: var(--color-primary); font-weight: 600; }
.booking-type__desc { font-size: 0.875rem; color: var(--color-text-muted); }

/* --- Schritt 2: Kalender ---------------------------------------------- */
.booking__cal {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-sm);
  background: var(--color-surface);
}
.booking__cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2xs);
  margin-bottom: var(--space-xs);
  font-family: var(--font-display);
  color: var(--color-ink);
}
.booking__cal-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--color-primary);
  transition: background-color 160ms var(--ease-out);
}

.booking__cal-nav:hover,
.booking__cal-nav:focus-visible { background: var(--color-primary-soft); }
.booking__cal-nav svg { width: 18px; height: 18px; }

.booking__cal-dow,
.booking__cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.booking__cal-dow {
  margin-bottom: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  text-align: center;
}
.booking__cal-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-text);
  transition: background-color 160ms var(--ease-out), color 160ms var(--ease-out);
}

.booking__cal-day:not(:disabled):hover,
.booking__cal-day:not(:disabled):focus-visible { background: var(--color-primary-soft); color: var(--color-primary); }
/* Nicht buchbare Tage (Wochenende, Vergangenheit) bleiben sichtbar, aber
   klar zurueckgenommen - ganz ausblenden wuerde das Monatsraster
   zerreissen. 0.35 statt disabled-Grau: der Tag soll als Datum lesbar
   bleiben, nur eben nicht als Angebot. */
.booking__cal-day:disabled { opacity: 0.35; cursor: default; }
.booking__cal-day.is-selected {
  background: var(--color-primary);
  color: #fff;
}
.booking__cal-pad { aspect-ratio: 1; }

/* --- Schritt 2: Uhrzeiten --------------------------------------------- */
.booking__slots-title {
  margin: 0;
  font-weight: 700;
  color: var(--color-ink);
}
.booking__slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: var(--space-2xs);
}
.booking__slot {
  padding: 0.6rem 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--color-text);
  transition: border-color 160ms var(--ease-out), background-color 160ms var(--ease-out), color 160ms var(--ease-out);
}

.booking__slot:hover,
.booking__slot:focus-visible { border-color: var(--color-primary); color: var(--color-primary); }
.booking__slot.is-selected {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}
.booking__hint {
  margin: 0;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.booking__summary {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border-left: 3px solid var(--color-primary);
  background: var(--color-primary-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-weight: 600;
  color: var(--color-ink);
}

.booking__nav {
  display: flex;
  gap: var(--space-2xs);
  flex-wrap: wrap;
}
.booking__nav .btn { flex: 1 1 auto; }

/* --- Schritt 4: Beleg in Dokumentoptik --------------------------------
   Bewusst anders gesetzt als der Rest der Seite: heller Bogen, feste
   Zeilenstruktur, Absender oben, Fusszeile unten. Das Formular soll am
   Ende etwas ausgeben, das wie ein Beleg aussieht und sich ausdrucken
   laesst - nicht nur eine gruene Erfolgsmeldung.
   ----------------------------------------------------------------------- */
.doc {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.doc__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-md) var(--space-sm);
  border-bottom: 2px solid var(--color-ink);
}
.doc__issuer {
  margin: 0 0 0.15rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.doc__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.4vw + 1rem, 1.6rem);
  color: var(--color-ink);
}
/* Stempel: leicht gedreht, damit er wie aufgebracht wirkt statt wie ein
   weiteres Bedienelement. Sagt bewusst "Angefragt" - verbindlich wird
   der Termin erst mit der Rueckmeldung. */
.doc__stamp {
  flex: none;
  padding: 0.35rem 0.75rem;
  border: 2px solid var(--color-accent-deep);
  border-radius: var(--radius-sm);
  transform: rotate(-4deg);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-deep);
}

.doc__rows {
  margin: 0;
  padding: var(--space-sm) var(--space-md);
  display: flex;
  flex-direction: column;
  gap: 0;
}
.doc__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.1rem;
  padding: 0.6rem 0;
  border-bottom: 1px dashed var(--color-border);
}
.doc__row:last-child { border-bottom: 0; }
.doc__row dt {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.doc__row dd {
  margin: 0;
  font-weight: 600;
  color: var(--color-ink);
  overflow-wrap: anywhere;
}
@media (min-width: 480px) {
  .doc__row {
    grid-template-columns: 40% 1fr;
    align-items: baseline;
    gap: var(--space-sm);
  }
}

.doc__note {
  margin: 0;
  padding: var(--space-sm) var(--space-md);
  background: var(--color-bg);
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--color-text);
}
.doc__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem var(--space-sm);
  justify-content: space-between;
  padding: var(--space-xs) var(--space-md);
  border-top: 1px solid var(--color-border);
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* Druck: nur der Beleg. Alles andere (Navigation, Kontaktspalte, die
   uebrigen Schritte, Schaltflaechen) faellt weg - gedruckt wird das
   Dokument, nicht die Seite darum. */
@media print {
  body * { visibility: hidden; }
  .booking__done, .booking__done * { visibility: visible; }
  .booking__done {
    position: absolute;
    inset: 0 auto auto 0;
    width: 100%;
  }
  .booking__nav--done { display: none; }
  .doc { border: 1px solid #999; box-shadow: none; }
}

.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xl);
}
@media (min-width: 1024px) {
  /* Zwei gleich breite Spalten, die oben auf derselben Linie beginnen.
     align-items:start statt der Vorgabe stretch: sonst zieht die
     kuerzere Spalte ihre Kinder auf die Hoehe der laengeren, und die
     Karte unter den Kontaktdaten wuchs mit der Termin-App mit. */
  .contact-grid {
    grid-template-columns: 1fr 1fr;
    /* stretch statt start: die Kontaktspalte muss die volle Zeilenhoehe
       bekommen, damit die Karte darin bis zur Unterkante der Termin-App
       wachsen kann. Vorher stand hier start, damit die Karte NICHT
       mitwaechst - jetzt ist genau das gewuenscht. */
    align-items: stretch;
    gap: var(--space-2xl);
  }
}

/* Bildplatzhalter fuer das Portrait auf der Ueber-uns-Seite: gleiches
   Muster wie .ref-card__media (Farbflaeche + zentriertes Kuerzel), bis
   ein echtes Foto eingebunden wird. Ohne diese Regel schrumpft der Block
   auf reine Textgroesse statt als Bildflaeche zu wirken. */
.portrait-placeholder {
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  background: var(--color-primary-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 4vw, 3rem);
}

@media (min-width: 1024px) {
}

/* Eigene Flaeche um die vier Eckdaten - dieselbe Bauform wie das
   Formular daneben (heller Grund, Rand, Radius), damit beide Spalten als
   gleichwertige Karten gelesen werden. Erhoehung wie beim Formular, siehe
   --shadow-card weiter unten. */
.contact-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-lg);
  box-shadow: var(--shadow-card);
}

.contact-info {
  /* 2x2 statt einer Spalte: jeder Punkt traegt nur zwei Zeilen, als lange
     Liste fuellten die vier zusammen die halbe Spaltenhoehe und liessen
     der Karte darunter kaum Platz. Unter 560px (schmale Karte, Mobil)
     faellt das Raster auf eine Spalte zurueck - nebeneinander blieben dort
     nur noch abgehackte Zeilen uebrig. */
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 560px) {
  .contact-info { grid-template-columns: 1fr 1fr; }
}

.contact-info__item {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-start;
}
.contact-info__icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-soft);
  color: var(--color-primary);
  border-radius: var(--radius-sm);
}
.contact-info__icon svg { width: 22px; height: 22px; }
.contact-info__item h3 { font-size: 1rem; margin-bottom: var(--space-3xs); }
.contact-info__item a,
.contact-info__item p { color: var(--color-text-muted); font-size: 0.9375rem; }
/* In der schmalen 2er-Spalte brach "Maria-Louisen-Straße" am Bindestrich
   um ("Maria-Louisen-" / "Straße 2A") - der Strassenname ist eine Einheit
   und soll zusammenbleiben. Gleiches gilt fuer die Zeitspanne. */
.contact-info__item p { text-wrap: pretty; hyphens: none; }
.contact-info__item a { overflow-wrap: anywhere; }

.contact-info__item a:hover,
.contact-info__item a:focus-visible { color: var(--color-primary); }

.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-lg);
  box-shadow: var(--shadow-card);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 640px) {
  .form-row--split { grid-template-columns: 1fr 1fr; }
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}
.field label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-ink);
}
.field input,
.field textarea {
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  background: var(--color-bg);
  transition: border-color 200ms var(--ease-out);
  min-height: 48px;
}
.field textarea { min-height: 140px; resize: vertical; }
.field input:focus-visible,
.field textarea:focus-visible {
  border-color: var(--color-primary);
  outline: none;
}
.field__error {
  font-size: 0.8125rem;
  color: #c0392b;
  min-height: 1.1em;
}

.field--checkbox {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-2xs);
}
.field--checkbox input {
  min-height: auto;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--color-primary);
}
.field--checkbox label { font-weight: 400; font-size: 0.875rem; color: var(--color-text-muted); }

.field--honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form__status {
  font-size: 0.9375rem;
  font-weight: 600;
  min-height: 1.2em;
}
.form__status[data-state="success"] { color: var(--color-success); }
.form__status[data-state="error"] { color: #c0392b; }

/* Map consent */
/* Kontaktspalte als Flex-Spalte: die Karte darunter bekommt flex:1 und
   fuellt damit genau den Platz, der bis zur Unterkante der Nachbarspalte
   (Termin-App) bleibt - beide Spalten schliessen unten buendig ab.
   Voraussetzung ist align-items:stretch am .contact-grid; die Vorgabe
   dort ist align-items:start, deshalb wird sie ab 1024px zurueckgesetzt
   (siehe .contact-grid). */
.contact-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  height: 100%;
  min-height: 0;
}

.contact__map {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  /* Nimmt den restlichen Platz der Spalte ein. min-height haelt die Karte
     brauchbar gross, falls die Nachbarspalte einmal kuerzer ist als die
     Kontaktdaten (z. B. im letzten Schritt der Termin-App). */
  flex: 1;
  min-height: 320px;
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
}

/* Vergroessern-Knopf auf der Karte. Sitzt unten links, weil OSM seine
   eigenen Bedienelemente (Zoom) oben rechts und den Attributionstext
   unten rechts zeichnet - dort waere er im Weg. */
.contact__map-zoom {
  position: absolute;
  left: var(--space-2xs);
  bottom: var(--space-2xs);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid var(--color-border);
  box-shadow: 0 4px 14px rgba(20, 33, 61, 0.18);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color 160ms var(--ease-out), transform 160ms var(--ease-out);
}

.contact__map-zoom:hover,
.contact__map-zoom:focus-visible { background: #fff; transform: translateY(-1px); }
.contact__map-zoom svg { width: 15px; height: 15px; }
.contact__map-zoom[hidden] { display: none; }

/* Klickflaeche ueber der geladenen Karte.
   Ein Klick auf ein fremdes iframe erreicht die Seite NIE - das iframe
   verschluckt ihn (andere Herkunft). Gemessen lag an jeder Stelle der
   Karte das iframe selbst unter dem Zeiger, der Zuhoerer am Elternelement
   feuerte also nie. Diese durchsichtige Flaeche darueber faengt den Klick
   ab und oeffnet die Lightbox.
   Nebenwirkung, bewusst in Kauf genommen: die kleine Karte laesst sich
   dadurch nicht mehr direkt verschieben oder zoomen - genau dafuer ist
   die vergroesserte Ansicht da, und dort ist die Karte voll bedienbar. */
.contact__map::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  cursor: zoom-in;
}
/* Solange nur der Zustimmungshinweis steht, darf nichts darueberliegen -
   sonst waere der "Karte laden"-Knopf nicht klickbar. */
.contact__map:has(#map-consent)::after { content: none; }
.map-consent {
  /* Kein aspect-ratio mehr: das gab der Karte eine feste Proportion und
     verhinderte damit genau das buendige Abschliessen mit dem Formular.
     Die Hoehe kommt jetzt vom Elternelement. */
  height: 100%;
  background: var(--color-primary-soft);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding: var(--space-lg);
  text-align: center;
}
.map-consent__text { color: var(--color-text-muted); font-size: 0.875rem; max-width: 40ch; }
.map-consent__link { font-size: 0.8125rem; text-decoration: underline; color: var(--color-primary); }
.contact__map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* -----------------------------------------------------------------------
   15b) Karten-Lightbox (vergroesserte Karte + Routenplanung)
   ----------------------------------------------------------------------- */
.map-lightbox {
  position: fixed;
  inset: 0;
  z-index: 950;          /* ueber der Kontaktleiste (40), unter dem
                            Cookie-Banner (900+) bleibt bewusst frei:
                            der Banner muss immer oben liegen. */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
}
.map-lightbox[hidden] { display: none; }

.map-lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

.map-lightbox__panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: min(1040px, 100%);
  /* height statt nur max-height: max-height deckelt zwar, treibt die
     Flaeche aber nicht - der Dialog blieb dadurch auf Inhaltshoehe
     stehen (gemessen 452px), und die Karte darin bekam nur ihre
     Mindesthoehe von 300px. Mit einer Zielhoehe fuellt sie den Dialog. */
  height: min(78svh, 760px);
  max-height: 100%;
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: 0 24px 70px rgba(8, 12, 20, 0.45);
  overflow: hidden;
  animation: map-lightbox-in 220ms var(--ease-out);
}
@keyframes map-lightbox-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.map-lightbox__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid var(--color-border);
}
.map-lightbox__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.125rem;
  color: var(--color-ink);
}
.map-lightbox__address {
  margin: 0.15rem 0 0;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}
.map-lightbox__close {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: var(--color-text-muted);
  transition: background-color 160ms var(--ease-out), color 160ms var(--ease-out);
}

.map-lightbox__close:hover,
.map-lightbox__close:focus-visible { background: var(--color-bg-soft); color: var(--color-ink); }
.map-lightbox__close svg { width: 20px; height: 20px; }

/* Der Kartenbereich traegt die Hoehe: er waechst, der Rest bleibt fix.
   Selbst display:flex, damit das iframe darin die Hoehe wirklich fuellt -
   mit height:100% allein blieb es bei seiner Standardhoehe von 150px
   (gemessen), weil die Elternhoehe erst aus flex:1 entsteht und damit zum
   Zeitpunkt der Prozentrechnung noch nicht feststeht. */
.map-lightbox__map {
  flex: 1;
  min-height: 300px;
  background: var(--color-bg-soft);
  display: flex;
}
.map-lightbox__map iframe {
  flex: 1;
  width: 100%;
  border: 0;
  display: block;
}

.map-lightbox__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs) var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-top: 1px solid var(--color-border);
}
.map-lightbox__hint {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-muted);
}
.map-lightbox__route {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-primary);
  transition: background-color 160ms var(--ease-out), border-color 160ms var(--ease-out);
}

.map-lightbox__route:hover,
.map-lightbox__route:focus-visible {
  background: var(--color-primary-soft);
  border-color: var(--color-primary);
}
.map-lightbox__route svg { width: 16px; height: 16px; }

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

/* -----------------------------------------------------------------------
   16) FAQ
   ----------------------------------------------------------------------- */
.faq { display: flex; flex-direction: column; gap: var(--space-2xs); max-width: 760px; }
.faq-item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  overflow: hidden;
}
.faq-item__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  text-align: left;
  font-weight: 600;
  min-height: 44px;
}
.faq-item__q svg {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  transition: transform 250ms var(--ease-out);
}
.faq-item[data-open="true"] .faq-item__q svg { transform: rotate(45deg); }
.faq-item__a {
  padding: 0 var(--space-md);
  max-height: 0;
  overflow: hidden;
  color: var(--color-text-muted);
  font-size: 0.9375rem;
  transition: max-height 300ms var(--ease-out), padding 300ms var(--ease-out);
}
.faq-item[data-open="true"] .faq-item__a {
  padding-block: 0 var(--space-md);
  max-height: 400px;
}

/* -----------------------------------------------------------------------
   16a) Leistungen-Accordion (leistungen.html)
   Gleiche Mechanik wie .faq-item (max-height-Transition, exklusives
   Oeffnen per JS), eigenes Klassenpraefix, da inhaltlich und optisch
   ein anderer Baustein (Leistungsuebersicht statt FAQ).
   ----------------------------------------------------------------------- */
.svc-acc { display: flex; flex-direction: column; gap: var(--space-2xs); max-width: 820px; margin-inline: auto; }
.svc-acc-item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  overflow: hidden;
  scroll-margin-top: calc(var(--nav-pill-h) + var(--space-md));
}
.svc-acc-item[data-open="true"] {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-sm);
}
.svc-acc-item__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  text-align: left;
}
.svc-acc-item__q-text {
  display: flex;
  align-items: baseline;
  gap: var(--space-xs);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  color: var(--color-primary);
}
.svc-acc-item__num {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-muted);
  font-family: var(--font-body);
}
.svc-acc-item__q svg {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  color: var(--color-primary);
  transition: transform 250ms var(--ease-out);
}
.svc-acc-item[data-open="true"] .svc-acc-item__q svg { transform: rotate(135deg); }
.svc-acc-item__a {
  max-height: 0;
  overflow: hidden;
  transition: max-height 350ms var(--ease-out);
}
.svc-acc-item[data-open="true"] .svc-acc-item__a {
  max-height: 900px;
}
.svc-acc-item__a-inner {
  padding: 0 var(--space-md) var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.svc-acc-item__a-inner p {
  color: var(--color-text-muted);
  line-height: 1.65;
}
.svc-acc-item__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

/* -----------------------------------------------------------------------
   17) Legal pages (Impressum/Datenschutz)
   ----------------------------------------------------------------------- */
.legal {
  max-width: 760px;
}
.legal h2 { margin-top: var(--space-lg); margin-bottom: var(--space-2xs); font-size: 1.35rem; }
.legal h2:first-child { margin-top: 0; }
.legal p, .legal li { color: var(--color-text-muted); margin-bottom: var(--space-2xs); }
.legal ul { padding-left: 1.2rem; list-style: disc; }
.legal a { color: var(--color-primary); text-decoration: underline; }

/* -----------------------------------------------------------------------
   18) Error pages
   ----------------------------------------------------------------------- */
.error-page {
  min-height: calc(100svh - var(--nav-pill-h) - var(--space-2xl));
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-2xl) var(--space-sm);
}
.error-page__code {
  font-family: var(--font-display);
  font-size: clamp(4rem, 12vw, 8rem);
  color: var(--color-primary-soft);
  -webkit-text-stroke: 2px var(--color-primary);
  line-height: 1;
  margin-bottom: var(--space-sm);
}
.error-page__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  justify-content: center;
  margin-top: var(--space-md);
}

/* -----------------------------------------------------------------------
   19) Footer
   ----------------------------------------------------------------------- */
.footer {
  background: var(--color-ink);
  color: rgba(255, 255, 255, 0.7);
  padding-block: var(--space-2xl) var(--space-md);
}
.footer__inner {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--space-sm);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
  padding-bottom: var(--space-lg);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
@media (min-width: 640px) {
  .footer__inner { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  .footer__inner { grid-template-columns: 1.3fr 1fr 1fr 1fr 1fr; }
}
.footer__logo {
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: #fff;
  font-weight: 600;
}
.footer__claim { margin-top: var(--space-2xs); font-size: 0.9375rem; }

.footer__heading {
  color: #fff;
  font-family: var(--font-base);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
}
.footer__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  font-size: 0.9375rem;
  line-height: 1.5;
}
.footer__list a,
.footer__cookie-link {
  transition: color 200ms var(--ease-out);
  text-align: left;
  width: fit-content;
}
.footer__list a:hover,
.footer__list a:focus-visible,
.footer__cookie-link:hover,
.footer__cookie-link:focus-visible { color: var(--color-accent); }
.footer__copy {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--space-sm);
  padding-top: var(--space-md);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.5);
}

/* -----------------------------------------------------------------------
   20) To-top button
   ----------------------------------------------------------------------- */
.to-top {
  position: fixed;
  right: var(--space-md);
  /* Auf einer Mittellinie mit dem Erkunden-Kreis (.scroll-cue__icon):
     der ist 42px hoch und sitzt bei bottom:--space-md, seine Mitte liegt
     also --space-md + 21px ueber der Unterkante. Dieser Kreis ist 48px
     hoch - ohne die 3px-Korrektur laege seine Mitte 3px hoeher und die
     beiden Kreise staenden sichtbar versetzt nebeneinander.
     Hinweis: eine exakte Deckung ist nur moeglich, wo der Bezugsrahmen des
     Erkunden-Kreises (seine Sektion) buendig mit dem Fensterunterrand
     abschliesst - .to-top ist fixed, der Erkunden-Kreis absolut in seiner
     Sektion. Beim Hero (100svh) ist das der Fall. */
  bottom: calc(var(--space-md) - 3px);
  width: 48px;
  height: 48px;
  /* Kein Kreis mehr: die Rakete steht frei im Raum, passend zur
     Weltraum-Bildsprache der Startseite. Die 48px bleiben als
     Trefferflaeche erhalten (Fingergroesse), auch wenn optisch nur die
     Rakete darin sichtbar ist. */
  background: none;
  border: 0;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Kein Kastenschatten mehr - der gehoerte zur Kreisflaeche. Die
     Plastizitaet kommt jetzt aus dem SVG selbst. */
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  z-index: 400;
}
.to-top.is-visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
/* Waehrend die Rakete zuendet, bleibt der Knopf sichtbar - sonst verschwaende
   er beim Hochscrollen schon unter 300px, noch bevor man die Rakete sieht. Er
   blendet erst aus, wenn das JS das Zuenden beendet hat (kurz nach der Landung). */
.to-top.is-firing { opacity: 1; transform: translateY(0); }
/* Ruhezustand: runder Pfeil-Knopf (Glas auf dunklem Grund, hell umrandet -
   lesbar auf hellen wie dunklen Seiten). Beim Ueberfahren hebt sich der
   Pfeil leicht und der Rand nimmt den Akzent an. */
.to-top__disc {
  position: absolute;
  inset: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #fff;
  background: rgba(4, 16, 26, 0.72);
  border: 1.5px solid rgba(234, 246, 251, 0.6);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px rgba(4, 16, 26, 0.35);
  transition: opacity 160ms var(--ease-out), scale 320ms var(--ease-out), border-color 200ms var(--ease-out);
}
.to-top__disc svg { width: 20px; height: 20px; transition: translate 200ms var(--ease-out); }
.to-top:hover .to-top__disc { border-color: var(--color-accent); }
.to-top:hover .to-top__disc svg { translate: 0 -2px; }
/* Beim Zuenden verglueht der Knopf: er weitet sich kurz und blendet aus,
   an seiner Stelle steht die Rakete. */
.to-top.is-firing .to-top__disc { opacity: 0; scale: 1.35; }

/* Beim Ueberfahren rueckt die Rakete leicht an (nur waehrend sie da ist). */
.to-top.is-firing:hover .to-top__rocket { transform: translateY(-2px); }
.to-top:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 8px;
}

/* Die Rakete im Knopf. Traegt die Startbewegung, damit der Knopf selbst
   an seiner Stelle bleibt - eine wegfliegende Schaltflaeche waere beim
   Zurueckkommen nicht mehr da, wo der Finger sie erwartet. */
.to-top__rocket {
  position: relative;
  display: block;
  width: 24px;
  height: 34px;
  color: #fff;
  /* Ohne Kreisflaeche braucht die Rakete einen eigenen Schlagschatten,
     damit sie sich vom Hintergrund loest - sie steht auf jeder Seite
     ueber wechselnden Farben. */
  filter: drop-shadow(0 3px 6px rgba(4, 16, 26, 0.55));
  /* Ruhezustand: unsichtbar und klein - sie entsteht erst beim Zuenden
     (.is-firing) aus dem Pfeil-Knopf. */
  opacity: 0;
  scale: 0.35;
  rotate: -18deg;
  transition: opacity 220ms var(--ease-out), scale 380ms var(--ease-out), rotate 380ms var(--ease-out), transform 200ms var(--ease-out);
}
.to-top.is-firing .to-top__rocket { opacity: 1; scale: 1; rotate: 0deg; }
.to-top.is-firing .to-top__rocket {
  /* Leichtes Schweben, solange sie bereitsteht (bis die Startbewegung
     unten uebernimmt). */
  animation: to-top-hover 2.8s ease-in-out infinite;
}
.to-top__rocket svg { display: block; width: 100%; height: 100%; }

/* Triebwerksfahne. Im Ruhezustand nicht vorhanden (scaleY 0) - sie
   gehoert zum Zuenden, nicht zum Dastehen. */
.to-top__flame {
  position: absolute;
  /* An der Duese ansetzen, nicht am Fuss des SVG-Feldes: der Duesenring
     sitzt bei y=27 von 34, also rund 79% der Feldhoehe. Darunter stehen
     nur noch die Leitwerksspitzen - bei top:100% klaffte eine sichtbare
     Luecke zwischen Rakete und Fahne. */
  top: 79%;
  left: 50%;
  width: 10px;
  height: 18px;
  translate: -50% 0;
  border-radius: 50% 50% 46% 46% / 32% 32% 68% 68%;
  background: linear-gradient(180deg, #fff6d5 0%, #ffc93c 42%, #ff6a2c 78%, rgba(255,106,44,0) 100%);
  filter: blur(0.4px);
  transform-origin: 50% 0;
  scale: 1 0;
  opacity: 0;
  pointer-events: none;
}

/* ZUENDEN: setzt das JS beim Antippen fuer die Dauer des Hochscrollens
   (siehe initToTop in script.js). Die Rakete hebt sich leicht an und
   zittert, die Fahne schlaegt aus. */
.to-top.is-firing .to-top__rocket {
  animation: to-top-launch 0.5s var(--ease-out) forwards;
}
.to-top.is-firing .to-top__flame {
  opacity: 1;
  animation: to-top-flame 0.12s steps(2, end) infinite;
}

@keyframes to-top-hover {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-1.5px); }
}
@keyframes to-top-launch {
  0%   { transform: translateY(0); }
  22%  { transform: translateY(2px); }      /* kurz einfedern */
  100% { transform: translateY(-7px); }
}
@keyframes to-top-flame {
  0%   { scale: 1 1;      opacity: 1; }
  100% { scale: 0.78 0.7; opacity: 0.75; }
}

/* Ohne Bewegungswunsch: keine Schwebe-, keine Start-, keine
   Flackerbewegung. Die Fahne erscheint beim Zuenden trotzdem, nur eben
   ruhig - sie ist die Rueckmeldung auf den Tastendruck. */
@media (prefers-reduced-motion: reduce) {
  .to-top__rocket,
  .to-top.is-firing .to-top__rocket,
  .to-top.is-firing .to-top__flame { animation: none; }
  .to-top__rocket { scale: 1; rotate: 0deg; transition: opacity 120ms linear; }
  .to-top__disc, .to-top.is-firing .to-top__disc { scale: 1; transition: opacity 120ms linear; }
  .to-top.is-firing .to-top__flame { scale: 1 1; opacity: 1; }
}

/* -----------------------------------------------------------------------
   21) Cookie banner
   ----------------------------------------------------------------------- */
.cookie-overlay {
  position: fixed;
  inset: 0;
  background: rgba(20, 33, 61, 0.55);
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms var(--ease-out);
  z-index: 900;
}
.cookie-overlay.is-open { opacity: 1; pointer-events: auto; }

.cookie-banner {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  width: min(92vw, 480px);
  max-height: 90svh;
  overflow-y: auto;
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: var(--space-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms var(--ease-out), transform 250ms var(--ease-out);
  z-index: 950;
}
.cookie-banner.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}

.cookie-banner__title { font-size: 1.25rem; margin-bottom: var(--space-2xs); }
.cookie-banner__text { font-size: 0.9375rem; color: var(--color-text-muted); margin-bottom: var(--space-md); }
.cookie-banner__link { color: var(--color-primary); text-decoration: underline; }

.cookie-banner__options {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.cookie-option {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  cursor: pointer;
}
.cookie-option--disabled { cursor: default; opacity: 0.7; }
.cookie-option input { position: absolute; opacity: 0; width: 20px; height: 20px; }
.cookie-option__box {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border: 2px solid var(--color-border);
  border-radius: 6px;
  position: relative;
  transition: border-color 200ms var(--ease-out), background-color 200ms var(--ease-out);
}
.cookie-option input:checked + .cookie-option__box {
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.cookie-option input:checked + .cookie-option__box::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 6px;
  height: 11px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.cookie-option input:focus-visible + .cookie-option__box {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.cookie-option__label { font-size: 0.9375rem; font-weight: 600; }
.cookie-option__note { font-weight: 400; color: var(--color-text-muted); }

.cookie-banner__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

/* -----------------------------------------------------------------------
   21b) Anfrage-/Bestellformular (bestellung.html)
   ----------------------------------------------------------------------- */
.trustbar {
  background: var(--color-ink);
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8125rem;
}
.trustbar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding-block: 0.65rem;
  text-align: center;
}
.trustbar__inner span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
}
.trustbar__inner svg { width: 15px; height: 15px; flex-shrink: 0; }
.trustbar__inner strong { color: var(--color-accent); }
.trustbar__dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
}

.order {
  padding-block: var(--space-xl) var(--space-2xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

/* Einleitung + Beratungs-Card nebeneinander statt die Beratungs-Card
   mitten im Formular zwischen zwei Sektionen einzuschieben - beide
   stehen jetzt gemeinsam am Formularanfang. Auf schmalen Screens
   faellt das Grid auf eine Spalte zurueck (Reihenfolge bleibt: erst
   Einleitung, dann Beratungs-Hinweis). */
.order__intro-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
  align-items: start;
  margin-bottom: var(--space-lg);
}
@media (min-width: 900px) {
  .order__intro-grid { grid-template-columns: 1.6fr 1fr; }
}

.order__intro { max-width: 720px; }
.order__intro .accent { color: var(--color-primary); }

.order__block {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.order__block-title {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-size: 1.05rem;
  padding: var(--space-md);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg);
}
.order__block-title span:first-child {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-base);
  font-size: 0.875rem;
  font-weight: 700;
  flex-shrink: 0;
}
.order__block-title em {
  font-style: normal;
  font-weight: 400;
  color: var(--color-text-muted);
  font-size: 0.9375rem;
}

.order__block-body { padding: var(--space-md); }

.order__note {
  font-size: 0.875rem;
  color: var(--color-text-muted);
  margin-bottom: var(--space-md);
}

/* Leistungs-Auswahlkarten */
.svc-picker {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2xs);
}
@media (min-width: 768px) {
  .svc-picker { grid-template-columns: 1fr 1fr; }
}

.svc-pick {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-sm);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color 200ms var(--ease-out), background-color 200ms var(--ease-out);
}

.svc-pick:hover,
.svc-pick:focus-visible { border-color: var(--color-primary); }
.svc-pick input {
  position: absolute;
  opacity: 0;
  width: 22px;
  height: 22px;
}
.svc-pick__box {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  border: 2px solid var(--color-border);
  border-radius: 6px;
  position: relative;
  transition: border-color 200ms var(--ease-out), background-color 200ms var(--ease-out);
}
.svc-pick input:checked + .svc-pick__box {
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.svc-pick input:checked + .svc-pick__box::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 6px;
  height: 11px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.svc-pick input:focus-visible + .svc-pick__box {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.svc-pick:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}
.svc-pick__body { display: flex; flex-direction: column; gap: 2px; }
.svc-pick__title { font-weight: 600; font-size: 0.9375rem; color: var(--color-ink); }
.svc-pick__text { font-size: 0.8125rem; color: var(--color-text-muted); }

/* Budget-Optionen */
.budget-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2xs);
}
@media (min-width: 640px) {
  .budget-row { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .budget-row { grid-template-columns: repeat(4, 1fr); }
}

.budget-opt { position: relative; cursor: pointer; }
.budget-opt input { position: absolute; opacity: 0; }
.budget-opt span {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-sm);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.9375rem;
  text-align: center;
  transition: border-color 200ms var(--ease-out), background-color 200ms var(--ease-out);
}
.budget-opt span small {
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}
.budget-opt:hover span { border-color: var(--color-primary); }
.budget-opt input:checked + span {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}
.budget-opt input:focus-visible + span {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Beratungs-Hinweisbox */
.order__beratung {
  background: #fffaf0;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius);
  padding: var(--space-md);
}
.order__beratung-titel { font-weight: 700; color: var(--color-ink); margin-bottom: var(--space-3xs); }
.order__beratung-text { font-size: 0.9375rem; color: var(--color-text-muted); margin-bottom: var(--space-sm); }

.fields {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}
@media (min-width: 640px) {
  .fields { grid-template-columns: 1fr 1fr; }
}

.req { color: #c0392b; }

.field--check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
}
.field--check input {
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--color-primary);
  flex-shrink: 0;
}
.field--check label { font-size: 0.875rem; color: var(--color-text-muted); font-weight: 400; }
.field--check a { color: var(--color-primary); text-decoration: underline; }

/* Sticky Zusammenfassung — klebt am unteren Viewport-Rand */
.summe {
  position: sticky;
  bottom: var(--space-sm);
  background: var(--color-ink);
  color: #fff;
  border-radius: var(--radius);
  padding: var(--space-md);
  box-shadow: var(--shadow-lg);
  z-index: 300;
  margin-top: var(--space-sm);
}
.summe__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}
.summe__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  font-weight: 600;
  color: #fff;
  min-height: 44px;
}
.summe__toggle svg {
  width: 16px;
  height: 16px;
  transition: transform 250ms var(--ease-out);
}
.summe__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.summe__wert {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  color: var(--color-accent);
}
.summe__detail {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  padding-block: var(--space-sm);
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.8);
}
.summe__detail li { padding-left: 1.1em; position: relative; }
.summe__detail li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-accent);
}
.summe__hinweis {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.7);
  margin-block: var(--space-2xs);
}
.summe__cta { width: 100%; }
.btn--light {
  background: var(--color-accent);
  color: var(--color-ink);
}

.btn--light:hover:not(:disabled),
.btn--light:focus-visible:not(:disabled) { background: var(--color-accent-deep); transform: translateY(-2px); }
.btn--lg { min-height: 54px; font-size: 1rem; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.order__done {
  background: var(--color-surface);
  border: 2px solid var(--color-success);
  border-radius: var(--radius);
  padding: var(--space-lg);
  text-align: center;
}
.order__done h2 { color: var(--color-success); margin-bottom: var(--space-2xs); }
.order__done p { color: var(--color-text-muted); }

.order__legal {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  padding-bottom: var(--space-2xl);
  max-width: 760px;
}
.order__legal a { color: var(--color-primary); text-decoration: underline; }

/* -----------------------------------------------------------------------
   22) Utilities
   ----------------------------------------------------------------------- */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* -----------------------------------------------------------------------
   23) Animations & Transitions (global)
   ----------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* -----------------------------------------------------------------------
   24) Print
   ----------------------------------------------------------------------- */
@media print {
  .nav, .cookie-banner, .cookie-overlay, .btn, .to-top { display: none !important; }
  body { font-size: 12pt; color: #000; background: #fff; }
  a[href]::after { content: " (" attr(href) ")"; font-size: 10pt; color: #555; }
  h2, h3 { page-break-after: avoid; }
  img { max-width: 100%; page-break-inside: avoid; }
}

/* -----------------------------------------------------------------------
   25) Preloader (nur Startseite)
   ----------------------------------------------------------------------- */
/* Ablauf in vier Phasen, gesteuert ueber data-preloader-step am body
   (siehe initPreloader in script.js):
   "logo"  - Bildmarke (enthaelt bereits den "OMB"-Schriftzug) erscheint
             zentriert allein
   "text"  - "online marketing beratung" fliegt darunter ein
   "hold"  - kurze Pause, alles steht
   "open"  - Icon fliegt verkleinert zur echten Header-Position und
             verblasst dort in das echte Nav-Logo; gleichzeitig fliegt
             "online marketing beratung" nach unten aus dem Bild,
             waehrend zwei volle Panels (obere/untere Haelfte) wie ein
             Vorhang HORIZONTAL geteilt nach oben/unten auseinanderfahren. */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
}
[data-preloader-active] .preloader { pointer-events: auto; }

/* Edles Carbon-Muster (gleiche Diagonal-Karo-Textur wie .section--carbon)
   PLUS ein diagonaler Glanzstreifen, der einmal ueber den ganzen Screen
   laeuft - macht aus der vorher reinen Flachfarbe eine gebuerstete,
   changierende Flaeche statt einer toten schwarzen Wand. Beide Panels
   teilen sich denselben, ueber 100vh durchgehenden background-attachment:
   fixed-Verlauf, damit das Muster beim spaeteren Auseinanderfahren NICHT
   an der Naht zwischen oberer/unterer Haelfte springt (die Panels sehen
   dann aus wie ein einziges, an der Mitte geteiltes Stueck Material statt
   zwei einzeln gemusterten Kacheln). */
.preloader__panel {
  position: absolute;
  left: 0;
  width: 100%;
  height: 50%;
  background-color: #0c1119;
  background-image:
    linear-gradient(135deg, rgba(255, 255, 255, 0.03) 25%, transparent 25%),
    linear-gradient(225deg, rgba(255, 255, 255, 0.03) 25%, transparent 25%),
    linear-gradient(45deg, rgba(255, 255, 255, 0.03) 25%, transparent 25%),
    linear-gradient(315deg, rgba(255, 255, 255, 0.03) 25%, #0c1119 25%),
    linear-gradient(115deg,
      transparent 0%, transparent 38%,
      rgba(255, 214, 102, 0.05) 46%,
      rgba(255, 255, 255, 0.14) 50%,
      rgba(255, 214, 102, 0.05) 54%,
      transparent 62%, transparent 100%);
  background-position: 10px 0, 10px 0, 0 0, 0 0, 0 0;
  background-size: 20px 20px, 20px 20px, 20px 20px, 20px 20px, 320% 320%;
  background-repeat: repeat, repeat, repeat, repeat, no-repeat;
  background-attachment: fixed, fixed, fixed, fixed, fixed;
  /* Eigene, weichere Kurve statt --ease-out: startet gemaechlicher (0.65
     statt eines steilen Anfangs) und laeuft lang und sanft aus - wirkt
     dadurch mehr wie ein schwerer, gleitender Vorhang als wie ein
     mechanischer Schnitt. */
  transition: transform 1100ms cubic-bezier(0.65, 0, 0.15, 1), opacity 1100ms cubic-bezier(0.65, 0, 0.15, 1);
  animation: preloader-sheen 2600ms ease-in-out forwards;
}
.preloader__panel--top { top: 0; }
.preloader__panel--bottom {
  bottom: 0;
  /* Minimaler Versatz zum oberen Panel: beide starten nicht exakt
     synchron, das untere folgt hauchduenn verzoegert - wirkt organischer
     als ein starr symmetrisches Auseinanderfahren. */
  transition-delay: 60ms;
}
[data-preloader-step="open"] .preloader__panel--top { transform: translateY(-100%); opacity: 0.85; }
[data-preloader-step="open"] .preloader__panel--bottom { transform: translateY(100%); opacity: 0.85; }

/* Glanzstreifen laeuft einmal diagonal ueber die Flaeche, waehrend Logo/
   Text erscheinen - liest sich wie Licht, das ueber gebuerstetes Metall
   gleitet, statt einer starren Textur. */
@keyframes preloader-sheen {
  from { background-position: 10px 0, 10px 0, 0 0, 0 0, 130% -30%; }
  to   { background-position: 10px 0, 10px 0, 0 0, 0 0, -30% 130%; }
}
@media (prefers-reduced-motion: reduce) {
  .preloader__panel { animation: none; }
}

/* Buehne: haelt Icon + Textzeile zentriert UEBER den Panels (hoeherer
   z-index), damit sie beim Vorhang-Oeffnen sichtbar bleiben. Vertikal
   gestapelt: Icon oben, "online marketing beratung" darunter - beide
   fliegen beim Aufklappen unabhaengig voneinander weg (Icon zur Header-
   Position, Untertext nach unten), waehrend die Panels dahinter nach
   oben/unten wegfahren (horizontal geteilter Vorhang). */
.preloader__stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(0.5rem, 1.5vw, 1.25rem);
  pointer-events: none;
}

/* Phase 1: Logo erscheint allein, kurzer Fade+Scale-in. Bleibt danach
   die ganze Zeit sichtbar bis zum finalen Flug in den Header. */
.preloader__logo {
  height: clamp(64px, 9vw, 96px);
  width: auto;
  opacity: 0;
  transform: scale(0.85);
  /* Die Bildmarke ist dunkel gezeichnet (fuer den hellen Header-
     Hintergrund) - auf dem dunklen Preloader-Screen sonst kaum sichtbar.
     invert(1) dreht Schwarz zu Weiss; die Umkehr faellt beim Uebergang
     zum echten (dunklen) Logo im Header nicht auf, weil dort bereits
     [data-preloader-landed] das fliegende Logo ausblendet, bevor es
     sichtbar auf dem hellen Grund liegen wuerde. */
  filter: brightness(0) invert(1);
  transition: transform 1100ms cubic-bezier(0.65, 0, 0.15, 1), opacity 1100ms cubic-bezier(0.65, 0, 0.15, 1), left 1100ms cubic-bezier(0.65, 0, 0.15, 1), top 1100ms cubic-bezier(0.65, 0, 0.15, 1);
}
[data-preloader-step="logo"] .preloader__logo,
[data-preloader-step="text"] .preloader__logo,
[data-preloader-step="hold"] .preloader__logo,
[data-preloader-step="open"] .preloader__logo {
  opacity: 1;
  transform: scale(1);
}

/* Phase 4 (open): das Logo verlaesst die Buehnen-Zentrierung und fliegt
   zur echten Header-Position - Zielwerte (--fly-top/--fly-left/--fly-h)
   werden zur Laufzeit aus der Bounding-Box von .nav__logo-mark berechnet
   und per JS als Inline-Custom-Properties gesetzt (siehe initPreloader).
   position:fixed statt absolute, damit die Ziel-Koordinaten direkt in
   Viewport-Pixeln (wie getBoundingClientRect() sie liefert) passen. */
[data-preloader-step="open"] .preloader__logo {
  position: fixed;
  top: var(--fly-top, 50%);
  left: var(--fly-left, 50%);
  height: var(--fly-h, 26px);
  transform: none;
  /* Verschmelzen mit dem echten Logo: sobald es dort ankommt, blendet es
     sanft weg, waehrend das (immer schon vorhandene, aber unter dem
     Preloader verdeckte) echte Nav-Logo gleichzeitig sichtbar wird -
     siehe .nav__logo-mark/-text-Regeln unten. Dadurch entsteht ein
     Crossfade statt eines harten Umschaltens. */
  transition: top 1100ms cubic-bezier(0.65, 0, 0.15, 1), left 1100ms cubic-bezier(0.65, 0, 0.15, 1), height 1100ms cubic-bezier(0.65, 0, 0.15, 1), opacity 500ms linear 600ms;
}
[data-preloader-step="open"][data-preloader-landed] .preloader__logo { opacity: 0; }

/* Text sitzt in der Stage, unter dem Icon. Position: relative (statt
   absolute), damit die Zeile ganz normal im Flex-Stack der Stage steht
   und beim Aufklappen per transform/opacity nach unten wegfliegen kann. */
.preloader__word {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: var(--font-display);
  color: #fff;
  opacity: 0;
  transition: opacity 300ms var(--ease-out), transform 1100ms cubic-bezier(0.65, 0, 0.15, 1);
}
/* "online marketing beratung": ausgeschriebener Name unter dem Icon
   (das bereits die "OMB"-Wortmarke zeigt) - fliegt beim Oeffnen nach
   unten weg. */
.preloader__word--full {
  font-weight: 500;
}
.preloader__word--full .preloader__word-line {
  font-size: clamp(1rem, 1.6vw + 0.6rem, 1.5rem);
  letter-spacing: 0.02em;
}
[data-preloader-step="text"] .preloader__word,
[data-preloader-step="hold"] .preloader__word {
  opacity: 1;
}
/* Vorhang-Oeffnung: der Untertext fliegt nach unten aus dem Bild -
   unabhaengig vom Icon (das separat zur Header-Position fliegt) und
   unabhaengig von den Panels (die horizontal wegfahren). */
[data-preloader-step="open"] .preloader__word--full {
  transform: translateY(160%);
  opacity: 0;
}

.preloader__word-line {
  white-space: nowrap;
}

/* --- Kennzahlenzeile im Preloader ------------------------------------
   Die fuenf Eckdaten standen frueher als Kartenraster im Vorstellungs-
   Hero. Dort kosteten sie den halben ersten Bildschirm; hier laufen sie
   in der ohnehin vorhandenen Ruhephase des Preloaders mit, wo der Blick
   nichts anderes zu tun hat. Eine Zeile, mittig unter dem Schriftzug,
   durch duenne Trenner gegliedert.
   Erscheint gemeinsam mit dem Schriftzug (Schritt "text") und faehrt mit
   ihm zusammen nach unten aus dem Bild (Schritt "open"), siehe
   .preloader__word--full weiter oben. */
.preloader__facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(0.6rem, 1.6vw, 1.4rem);
  margin-top: clamp(1rem, 2.4vh, 1.9rem);
  padding-inline: var(--space-md);
  opacity: 0;
  transform: translateY(12px);
  /* Der Fliesstext-Anteil ("gegruendet in Hamburg", "Jahre Erfahrung",
     ...) verschwand auf der Carbon-Textur regelrecht: bei 0.72-0.88 Alpha
     liegt er farblich zu dicht am Muster, und die kleine Schrift hat kaum
     Flaeche, ueber die der Kontrast wirken koennte. Jetzt volle Deckkraft
     statt Transparenz, eine Spur groesser und mit kraeftigerem Schatten,
     der die Buchstaben vom gemusterten Grund abhebt. Die Unterscheidung
     Zahl/Text traegt allein das Fettgewicht (siehe .preloader__fact b),
     nicht mehr zusaetzlich die Helligkeit. */
  color: #fff;
  font-size: clamp(0.8rem, 0.5vw + 0.68rem, 0.98rem);
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.9),
    0 2px 16px rgba(0, 0, 0, 0.8);
  letter-spacing: 0.05em;
  text-align: center;
}

/* Delay von 520ms auf 260ms: die Zeile war frueher erst fertig
   eingeblendet, als die Ruhephase schon fast vorbei war. Sie startet
   jetzt, waehrend der Schriftzug noch seine letzten Buchstaben setzt,
   und steht dadurch die volle Ruhephase ueber ruhig im Bild. */
[data-preloader-step="text"] .preloader__facts,
[data-preloader-step="hold"] .preloader__facts {
  animation: preloader-facts-in 520ms var(--ease-out) 260ms forwards;
}

@keyframes preloader-facts-in {
  to { opacity: 1; transform: translateY(0); }
}

/* Faehrt mit dem Schriftzug nach unten weg, damit der Vorhang eine
   ruhige Flaeche oeffnet. */
[data-preloader-step="open"] .preloader__facts {
  animation: preloader-facts-out 520ms var(--ease-in, ease-in) forwards;
}

@keyframes preloader-facts-out {
  to { opacity: 0; transform: translateY(46px); }
}

/* Kennzahlen in Akzentgelb statt Weiss: hebt sie deutlicher aus der
   Zeile heraus als das Fettgewicht allein und nimmt die Markenfarbe auf,
   die auch die goldene Hauptkurve im Hero traegt. */
.preloader__fact b {
  color: var(--color-accent);
  font-weight: 800;
  letter-spacing: 0.02em;
  /* Feste Mindestbreite waehrend des Hochzaehlens waere hier falsch: die
     Zeile ist flex-zentriert, ein Breitensprung von "0" auf "100" wuerde
     die ganze Zeile ruckeln lassen. tabular-nums haelt die Ziffernbreite
     konstant, damit nur die Zahl selbst waechst. */
  font-variant-numeric: tabular-nums;
}

/* Etwas mehr Luft zwischen Zahl und zugehoerigem Wort als zwischen den
   Angaben untereinander waere falsch herum - die Angaben gehoeren jeweils
   zusammen. Deshalb bleibt der Wortabstand normal, getrennt wird nur ueber
   die Trennstriche und den groesseren Flex-Gap. */
.preloader__fact {
  white-space: nowrap;
}

/* Duenner senkrechter Trenner zwischen den Angaben. Eigenes Element
   statt border-left am Nachbarn: bei Umbruch auf Mobile verschwindet
   er per :last-child-Logik nicht sauber, als Element laesst er sich
   unter 700px schlicht ausblenden. */
.preloader__fact-sep {
  width: 1px;
  height: 0.85em;
  background: rgba(255, 255, 255, 0.45);
}

@media (max-width: 700px) {
  .preloader__facts {
    gap: 0.3rem 0.9rem;
    letter-spacing: 0.04em;
  }
  .preloader__fact-sep { display: none; }
}

/* Ohne Bewegungswunsch: sofort sichtbar, keine Ein-/Ausfahrt. */
@media (prefers-reduced-motion: reduce) {
  .preloader__facts {
    opacity: 1;
    transform: none;
    animation: none !important;
  }
}

.preloader__word .pc {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  animation-name: preloader-letter-in;
  animation-duration: 700ms;
  animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
  animation-fill-mode: both;
  animation-iteration-count: 1;
  animation-play-state: paused;
}
[data-preloader-step="text"] .pc,
[data-preloader-step="hold"] .pc { animation-play-state: running; }

@keyframes preloader-letter-in {
  from { opacity: 0; transform: translateY(0.5em); }
  to { opacity: 1; transform: translateY(0); }
}

/* "online marketing beratung" (24 Zeichen inkl. 2 Leerzeichen) fliegt
   buchstabenweise ein. */
.preloader__word--full .pc:nth-child(1)  { animation-delay: 0ms; }
.preloader__word--full .pc:nth-child(2)  { animation-delay: 20ms; }
.preloader__word--full .pc:nth-child(3)  { animation-delay: 40ms; }
.preloader__word--full .pc:nth-child(4)  { animation-delay: 60ms; }
.preloader__word--full .pc:nth-child(5)  { animation-delay: 80ms; }
.preloader__word--full .pc:nth-child(6)  { animation-delay: 100ms; }
.preloader__word--full .pc:nth-child(7)  { animation-delay: 120ms; }
.preloader__word--full .pc:nth-child(8)  { animation-delay: 140ms; }
.preloader__word--full .pc:nth-child(9)  { animation-delay: 160ms; }
.preloader__word--full .pc:nth-child(10) { animation-delay: 180ms; }
.preloader__word--full .pc:nth-child(11) { animation-delay: 200ms; }
.preloader__word--full .pc:nth-child(12) { animation-delay: 220ms; }
.preloader__word--full .pc:nth-child(13) { animation-delay: 240ms; }
.preloader__word--full .pc:nth-child(14) { animation-delay: 260ms; }
.preloader__word--full .pc:nth-child(15) { animation-delay: 280ms; }
.preloader__word--full .pc:nth-child(16) { animation-delay: 300ms; }
.preloader__word--full .pc:nth-child(17) { animation-delay: 320ms; }
.preloader__word--full .pc:nth-child(18) { animation-delay: 340ms; }
.preloader__word--full .pc:nth-child(19) { animation-delay: 360ms; }
.preloader__word--full .pc:nth-child(20) { animation-delay: 380ms; }
.preloader__word--full .pc:nth-child(21) { animation-delay: 400ms; }
.preloader__word--full .pc:nth-child(22) { animation-delay: 420ms; }
.preloader__word--full .pc:nth-child(23) { animation-delay: 440ms; }
.preloader__word--full .pc:nth-child(24) { animation-delay: 460ms; }

@media (prefers-reduced-motion: reduce) {
  .preloader { display: none; }
}

/* Solange der Preloader laeuft, ist die Seite nicht scrollbar -
   verhindert, dass man hinter dem noch geschlossenen Vorhang navigiert. */
body[data-preloader-active] { overflow: hidden; }

/* Nur die Bildmarke bleibt unsichtbar, bis das fliegende Preloader-Logo
   dort "landet" - sonst waeren kurzzeitig zwei Logos gleichzeitig zu
   sehen (das eigentliche im Header UND das noch fliegende). Der
   Schriftzug "Online Marketing Beratung" daneben ist davon bewusst
   AUSGENOMMEN und bleibt die ganze Zeit normal sichtbar/unanimiert -
   nur das Bildmarken-Icon fliegt und verschmilzt, der Text springt nicht
   mit ein. Erst wenn [data-preloader-landed] gesetzt wird, blendet die
   Bildmarke simultan zum Verschwinden des fliegenden Logos ein (siehe
   [data-preloader-step="open"][data-preloader-landed] .preloader__logo
   oben). */
body[data-preloader-active]:not([data-preloader-landed]) .nav__logo-mark {
  opacity: 0;
}
.nav__logo-mark {
  transition: opacity 500ms linear;
}

/* -----------------------------------------------------------------------
   11z) Seite "Marvin de Vries" (Agentur-Vorstellung)
   Eigene Klassen statt Inline-Styles: dieselben Werte, aber an EINER
   Stelle - sonst erbt keine andere Seite die Auszeichnung (siehe die
   frueheren style="..."-Notausgaenge auf leistungen.html).
   ----------------------------------------------------------------------- */

/* Fliesstext unter dem Lead im Intro. */
.mdv-text {
  margin-top: var(--space-md);
  color: var(--color-text-muted);
}

/* Der Claim des Originals ("Professionelle Online Marketing Beratung,
   perfekt auf Sie zugeschnitten!") - abgesetzt in der Display-Schrift,
   damit er als Zusage liest und nicht als weiterer Absatz. */
.mdv-claim {
  margin-top: var(--space-md);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.0625rem;
  color: var(--color-ink);
}

/* Freigestellte Person aus dem Telefon-Motiv der Vorlage.
   Bewusst OHNE Rahmen, Radius und Kartenschatten: das Motiv hat einen
   ausblendenden Alpharand (im Bild selbst angelegt) und soll in die
   Flaeche hineinlaufen, statt als Kachel darauf zu liegen. Ein
   box-shadow wuerde die unsichtbare Bounding-Box wieder sichtbar
   machen - stattdessen ein weicher drop-shadow, der der Silhouette
   folgt und das Motiv von der Flaeche abhebt.
   max-width statt width:100%: das Bild ist nur 270px breit, hochskaliert
   wuerde es weich. */
.mdv-portrait {
  display: block;
  width: 100%;
  max-width: 340px;
  height: auto;
  margin-inline: auto;
  filter: drop-shadow(0 18px 34px rgba(20, 33, 61, 0.22));
}
@media (min-width: 1024px) {
  /* Neben dem Text sitzt das Motiv am unteren Rand der Spalte auf, damit
     Kopfhoehe und Textanfang auf einer Linie liegen. */
  /* Linksbuendig am Spaltenanfang, damit der Block nicht nach rechts
     abrutscht. Die Quelle ist 270px breit; 420px skaliert sie um gut die
     Haelfte hoch - vertretbar, weil das Motiv durch den weichen
     Alpharand ohnehin keine harte Kante zeigt. */
  .mdv-portrait { max-width: 420px; margin-inline: 0 auto; }
}

/* CTA-Band in Primaerfarbe (bisher als Inline-Style auf dieser Seite und
   auf marvin-de-vries.html gesetzt). */
.cta-band--primary { background: var(--color-primary); }

/* Auf .section--dark liefe .service-card__text in --color-text-muted
   (Grau auf Anthrazit, praktisch unlesbar). Die Textfarben der dunklen
   Sektion gelten bisher nur fuer h1-h3, nicht fuer Absaetze. */
.section--dark .service-card__text {
  color: rgba(255, 255, 255, 0.72);
}
.section--dark .section__lead,
.mdv-lead-onDark {
  color: rgba(255, 255, 255, 0.85);
}

/* Intro-Spalten der Seite "Marvin de Vries": Text mittig zur
   Bildhoehe. (Vorher align-items:end - dadurch stand der kuerzere
   Textblock am unteren Rand der Bildspalte statt auf halber Hoehe.) */
@media (min-width: 1024px) {
  /* Bildspalte schmaler als die Textspalte: das freigestellte Motiv
     braucht weniger Breite als der Fliesstext, und der Text bekommt so
     laengere Zeilen statt frueh umzubrechen. */
  .mdv-intro-grid {
    grid-template-columns: 0.8fr 1.2fr;
    align-items: center;
  }
  /* Bild links, Text rechts. Umgestellt per order statt im Markup: im
     Quelltext steht die Textspalte mit der H1 zuerst, damit Vorlese-
     programme und die Dokumentstruktur die Ueberschrift vor dem Bild
     bekommen. Unter 1024px (einspaltig) bleibt es bei Text zuerst. */
  .mdv-intro-grid > :first-child { order: 2; }
  .mdv-intro-grid > :last-child  { order: 1; }
}

/* ---- Kopfleiste und Leistungen-Menue im Look der Statuskarten (alle Seiten) ----------- */
.nav {
  background:
    repeating-linear-gradient(0deg, rgba(127, 227, 255, 0.04) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, rgba(4, 24, 52, 0.88), rgba(1, 10, 26, 0.92));
  border: 1px solid rgba(127, 227, 255, 0.35);
  box-shadow: 0 0 0 1px rgba(2, 14, 32, 0.6), 0 8px 30px rgba(0, 8, 24, 0.55), inset 0 0 22px rgba(41, 140, 230, 0.2);
}
.nav.is-glass { background-color: rgba(1, 10, 26, 0.94); }
.nav__logo-mark { filter: brightness(0) invert(1) drop-shadow(0 0 6px rgba(127, 227, 255, 0.5)); }
.nav__logo-text { color: #eaf6fb; }
.nav__menu a:not(.nav__cta),
.nav__dropdown-toggle { color: #d6e8f5; }
.nav__burger span { background: #7fe3ff; }

/* Leistungen-Menue als Statuskarte */
.nav__dropdown-menu {
  background:
    repeating-linear-gradient(0deg, rgba(127, 227, 255, 0.045) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, rgba(4, 24, 52, 0.97), rgba(1, 10, 26, 0.98));
  border: 1px solid rgba(127, 227, 255, 0.4);
  border-radius: 6px;
  box-shadow: inset 0 0 26px rgba(41, 140, 230, 0.22), 0 14px 36px rgba(0, 8, 24, 0.6);
}
.nav__dropdown-menu::after {
  content: "";
  position: absolute;
  inset: -1px;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent, #7fe3ff, transparent) top / 60% 2px no-repeat,
    linear-gradient(#7fe3ff, #7fe3ff) right top / 14px 2px no-repeat,
    linear-gradient(#7fe3ff, #7fe3ff) right top / 2px 14px no-repeat,
    linear-gradient(#7fe3ff, #7fe3ff) left bottom / 14px 2px no-repeat,
    linear-gradient(#7fe3ff, #7fe3ff) left bottom / 2px 14px no-repeat;
  filter: drop-shadow(0 0 4px rgba(127, 227, 255, 0.7));
}
.nav__dropdown-menu a {
  color: #d6e8f5;
  font-family: var(--font-display, "Space Grotesk", sans-serif);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: 2px;
  transition: background-color 200ms ease, color 200ms ease, box-shadow 200ms ease, padding-left 200ms ease;
}
.nav__dropdown-menu a:hover,
.nav__dropdown-menu a:focus-visible {
  color: #fff;
  background: linear-gradient(90deg, rgba(127, 227, 255, 0.22), rgba(127, 227, 255, 0.04));
  box-shadow: inset 2px 0 0 #7fe3ff;
  padding-left: calc(var(--space-sm) + 4px);
}
.nav__dropdown-menu a:focus-visible { outline: 1px solid #7fe3ff; outline-offset: -1px; }

@media (min-width: 1024px) {
  .nav__menu > a:not(.nav__cta):hover,
  .nav__menu > a:not(.nav__cta):focus-visible,
  .nav__dropdown-toggle:hover,
  .nav__dropdown-toggle:focus-visible,
  .nav__dropdown[data-open="true"] .nav__dropdown-toggle {
    color: #fff;
    background: rgba(127, 227, 255, 0.14);
    box-shadow: inset 0 0 0 1px rgba(127, 227, 255, 0.45);
    text-shadow: 0 0 10px rgba(127, 227, 255, 0.8);
  }
  .nav__menu > a:not(.nav__cta):focus-visible,
  .nav__dropdown-toggle:focus-visible { outline: 1px solid #7fe3ff; }
}
/* Mobiles Menue-Panel ebenfalls dunkel */
@media (max-width: 1023px) {
  .nav__menu { background: #031124; border-left: 1px solid rgba(127, 227, 255, 0.35); }
  .nav__menu a,
  .nav__dropdown-toggle { border-bottom-color: rgba(127, 227, 255, 0.18); }
}

/* -----------------------------------------------------------------------
   CTA-Knoepfe im Statuskarten-Look (Hero-Aktionen und "Anfrage stellen" in der Kopfleiste)
   Schraege Kanten, Grossbuchstaben, duenne leuchtende Randlinie mit umlaufendem Lichtpunkt.
   Erste Aktion: gefuellt in Cyan. Zweite (--cyan): dunkles Glas, fuellt sich beim Hover.
   ----------------------------------------------------------------------- */
.v2-hero__actions .cta-orbit,
.nav__menu a.nav__cta {
  --orbit-ring: 2px;
  --orbit-light: 127, 227, 255;
  --orbit-fill: linear-gradient(90deg, #7fe3ff, #4db4ff);
  --orbit-fill-hover: linear-gradient(90deg, #c2f4ff, #8fd6ff);
  --hud-cut: 14px;
  border-radius: 0;
  clip-path: polygon(var(--hud-cut) 0, 100% 0, calc(100% - var(--hud-cut)) 100%, 0 100%);
  font-family: var(--font-display, "Space Grotesk", sans-serif);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding-inline: calc(var(--hud-cut) + 1.1rem);
  transition: filter 220ms ease, transform 220ms ease;
}
.v2-hero__actions .cta-orbit::before,
.nav__menu a.nav__cta::before { border-radius: 0; background: conic-gradient(rgba(127, 227, 255, 0.35) 0deg, rgba(127, 227, 255, 0.35) 300deg, #fff 355deg, rgba(127, 227, 255, 0.35) 360deg); }
.v2-hero__actions .cta-orbit::after,
.nav__menu a.nav__cta::after {
  border-radius: 0;
  clip-path: polygon(calc(var(--hud-cut) - 2px) 0, 100% 0, calc(100% - var(--hud-cut) + 2px) 100%, 0 100%);
  transition: filter 220ms ease;
}
.v2-hero__actions .cta-orbit .cta-orbit__label,
.nav__menu a.nav__cta .cta-orbit__label { color: #021226; transition: letter-spacing 220ms ease; }
.v2-hero__actions .cta-orbit:hover,
.v2-hero__actions .cta-orbit:focus-visible,
.nav__menu a.nav__cta:hover,
.nav__menu a.nav__cta:focus-visible { color: #021226; transform: translateY(-1px); filter: drop-shadow(0 0 10px rgba(127, 227, 255, 0.75)); }
.v2-hero__actions .cta-orbit:hover .cta-orbit__label,
.v2-hero__actions .cta-orbit:focus-visible .cta-orbit__label,
.nav__menu a.nav__cta:hover .cta-orbit__label,
.nav__menu a.nav__cta:focus-visible .cta-orbit__label { color: #021226; letter-spacing: 0.18em; }

/* zweite Aktion: dunkles Glas */
.v2-hero__actions .cta-orbit--cyan {
  --orbit-fill: linear-gradient(180deg, #073250, #031a2e);
  --orbit-fill-hover: linear-gradient(90deg, #7fe3ff, #4db4ff);
}
.v2-hero__actions .cta-orbit--cyan .cta-orbit__label { color: #eaf6fb; }
.v2-hero__actions .cta-orbit--cyan:hover .cta-orbit__label,
.v2-hero__actions .cta-orbit--cyan:focus-visible .cta-orbit__label { color: #021226; }


/* -----------------------------------------------------------------------
   Variantenwahl Hero Startseite (Var 1 / Var 2)
   Rechts auf Hoehe der Kopfleiste; wo die Leiste bis dorthin reicht
   (schmaler als 1560px), rutscht sie direkt darunter, damit sie nichts verdeckt.
   ----------------------------------------------------------------------- */
.var-switch {
  position: fixed;
  z-index: 520;
  top: calc(var(--space-sm) + (var(--nav-pill-h) - 36px) / 2);
  right: 1rem;
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: rgba(4, 16, 38, 0.82);
  border: 1px solid rgba(127, 227, 255, 0.34);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 8px 24px rgba(0, 8, 24, 0.35);
}
.var-switch__opt {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 0.85rem;
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 600;
  color: rgba(234, 246, 251, 0.82);
  white-space: nowrap;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}
.var-switch__opt:hover,
.var-switch__opt:focus-visible { color: #fff; background: rgba(127, 227, 255, 0.16); }
.var-switch__opt:focus-visible { outline: 2px solid #7fe3ff; outline-offset: 1px; }
.var-switch__opt[aria-current="page"] { background: #7fe3ff; color: #04101a; }
@media (max-width: 1559px) {
  .var-switch { top: calc(var(--space-sm) + var(--nav-pill-h) + 8px); }
}
@media print { .var-switch { display: none !important; } }


/* =============================================================================
   Kopfleiste und Kontakt-Seitenleiste als Statuskarten (alle Seiten und
   Unterseiten)
   Gleiche Sprache wie die Hero- und Referenz-Karten: dunkle Glasflaeche mit
   Scanlinien, Cyan-Linie, abgerundete Ecken und Eckmarken. Die
   Flaeche liegt in einem Pseudoelement, nicht auf dem Element selbst: ein
   Rundung samt Rand am Element selbst schnitte nichts ab, braucht aber die
   Flaeche hinter den Kindern (z-index -1), damit das Leistungen-Menue unter
   der Kopfleiste bzw. Tooltips und Kartenfenster neben der Leiste frei
   ueberstehen koennen.
   Die Leiste hatte bisher je nach Untergrund vier Tonstufen (hell/dunkel/
   geteilt/deckend) - die dunkle Karte traegt auf allen, die Tonstufen
   entfallen deshalb.
   ============================================================================= */
.nav,
.nav.is-glass {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.nav::before,
.contact-bar__list::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent, #7fe3ff, transparent) top / 60% 2px no-repeat,
    repeating-linear-gradient(0deg, rgba(127, 227, 255, 0.045) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, rgba(4, 24, 52, 0.9), rgba(1, 10, 26, 0.94));
  border: 1px solid rgba(127, 227, 255, 0.32);
  border-radius: var(--hud-radius);
  box-shadow: inset 0 0 28px rgba(41, 140, 230, 0.18);
}
/* Eckmarken als Bogen: dieselbe Rundung wie die Flaeche, nur oben rechts und
   unten links sichtbar (Maske), statt gerader Winkel an runden Ecken. */
.nav::after,
.contact-bar__list::after {
  content: "";
  position: absolute;
  inset: -1px;
  pointer-events: none;
  border: 2px solid #7fe3ff;
  border-radius: calc(var(--hud-radius) + 1px);
  -webkit-mask:
    linear-gradient(#000, #000) top right / 34px 34px no-repeat,
    linear-gradient(#000, #000) bottom left / 34px 34px no-repeat;
  mask:
    linear-gradient(#000, #000) top right / 34px 34px no-repeat,
    linear-gradient(#000, #000) bottom left / 34px 34px no-repeat;
  filter: drop-shadow(0 0 4px rgba(127, 227, 255, 0.7));
}
.nav { --hud-radius: 22px; }
.contact-bar__list { --hud-radius: 20px; }
/* Die Menue-Eintraege der Kopfleiste duerfen ueber den Marken liegen. */
.nav > * { position: relative; z-index: 1; }

/* Seitenleiste: Flaeche, Symbole und Trenner einheitlich, egal ueber welchem Grund */
.contact-bar .contact-bar__list,
.contact-bar[data-tone] .contact-bar__list {
  position: relative;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.contact-bar__list > * { position: relative; z-index: 1; }
.contact-bar .contact-bar__sep,
.contact-bar[data-tone] .contact-bar__sep { background: rgba(127, 227, 255, 0.4); }
.contact-bar .contact-bar__link,
.contact-bar[data-tone] .contact-bar__link,
.contact-bar .contact-bar__link[data-tone] {
  color: #eaf6fb;
  background: none;
  box-shadow: none;
  border-radius: 3px;
}
.contact-bar .contact-bar__link:hover,
.contact-bar .contact-bar__link:focus-visible,
.contact-bar[data-tone] .contact-bar__link:hover,
.contact-bar[data-tone] .contact-bar__link:focus-visible,
.contact-bar .contact-bar__link[data-tone]:hover,
.contact-bar .contact-bar__link[data-tone]:focus-visible {
  color: #fff;
  background: linear-gradient(90deg, rgba(127, 227, 255, 0.24), rgba(127, 227, 255, 0.06));
  box-shadow: inset 2px 0 0 #7fe3ff;
  transform: none;
}
.contact-bar__link:focus-visible { outline: 1px solid #7fe3ff; outline-offset: 1px; }
/* Tooltip und Kartenfenster im selben Ton */
.contact-bar__tip {
  background: rgba(2, 14, 32, 0.96);
  border: 1px solid rgba(127, 227, 255, 0.4);
  border-radius: 3px;
  color: #eaf6fb;
}
.contact-bar__map-popover-inner {
  background: rgba(2, 14, 32, 0.96);
  border: 1px solid rgba(127, 227, 255, 0.4);
  border-radius: 6px;
}
/* Einklapp-Knopf (schmale Bildschirme) */
.contact-bar .contact-bar__toggle,
.contact-bar .contact-bar__toggle[data-tone] {
  border-radius: 4px;
  background:
    repeating-linear-gradient(0deg, rgba(127, 227, 255, 0.045) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, rgba(4, 24, 52, 0.94), rgba(1, 10, 26, 0.96));
  border: 1px solid rgba(127, 227, 255, 0.4);
  color: #7fe3ff;
}
.contact-bar .contact-bar__toggle[aria-expanded="true"] {
  background: linear-gradient(90deg, rgba(127, 227, 255, 0.3), rgba(127, 227, 255, 0.1));
  color: #fff;
}

/* Aktuelle Seite im Header (gesetzt von initNavCurrent in script.js) */
.nav__menu > a[aria-current="page"]:not(.nav__cta),
.nav__dropdown-toggle[aria-current="page"] {
  color: #7fe3ff;
  text-shadow: 0 0 12px rgba(127, 227, 255, 0.55);
  text-decoration: underline 2px #7fe3ff;
  text-underline-offset: 0.5em;
}
.nav__cta[aria-current="page"] { box-shadow: 0 0 0 2px #7fe3ff, 0 0 18px rgba(127, 227, 255, 0.55); }

/* Handy-Menue (Burger oben rechts): ein Glas-Panel unter der Kopfzeile statt eines Seitenschubs; ".nav > *" hatte es auf position: relative gesetzt */
@media (max-width: 1023px) {
  .nav > .nav__menu {
    position: fixed; top: calc(var(--header-h, 72px) + 14px); right: 12px; left: 12px; bottom: auto; width: auto; height: auto; max-height: calc(100svh - var(--header-h, 72px) - 28px);
    overflow-y: auto; padding: 1.1rem 1.2rem 1.3rem; gap: .35rem; border-radius: 14px;
    transform: translateY(-12px) scale(0.98); opacity: 0; visibility: hidden; pointer-events: none;
    transition: transform 240ms ease, opacity 240ms ease, visibility 0s linear 240ms;
    background: linear-gradient(115deg, rgba(120, 190, 255, 0.16) 0%, rgba(40, 90, 170, 0.07) 40%, rgba(10, 30, 70, 0.12) 100%), rgba(4, 14, 32, 0.9);
    border: 1px solid rgba(150, 215, 255, 0.5);
    box-shadow: 0 0 32px rgba(79, 180, 255, 0.28), inset 0 0 50px rgba(79, 180, 255, 0.1), inset 0 -3px 0 -1px rgba(159, 220, 255, 0.95);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  }
  .nav > .nav__menu.is-open { transform: none; opacity: 1; visibility: visible; pointer-events: auto; transition-delay: 0s; }
  .nav__menu a, .nav__menu .nav__dropdown-toggle { color: #e8f4ff; font-size: 1rem; padding: .7rem .2rem; border-bottom: 1px solid rgba(150, 215, 255, 0.14); }
  .nav__menu .nav__dropdown-menu { position: static; box-shadow: none; background: transparent; border: 0; padding-left: .8rem; }
  .nav__menu .nav__cta { margin-top: .6rem; text-align: center; }
}

/* Kontaktleiste auf dem Handy: der Telefon-Knopf bleibt beim Aufklappen an seiner Stelle (unten), die Liste faehrt darueber aus. ".contact-bar .contact-bar__list" (Cockpit-Block) setzt position: relative und hatte die absolute Positionierung der Mobilregel uebertrumpft, die Leiste wuchs dadurch nach oben und der Knopf rutschte mit. */
@media (max-width: 767px) {
  .contact-bar .contact-bar__list,
  .contact-bar[data-tone] .contact-bar__list {
    position: absolute;
    bottom: calc(100% + var(--space-2xs));
    right: 0;
  }
}

/* Footer auf dem Handy: kompakt statt eine lange Spalte. Marke und Kontakt ueber die volle Breite, Leistungen und Infos nebeneinander,
   die rechtlichen Links als eine Reihe; unten Platz fuer den Telefon-Knopf */
@media (max-width: 639px) {
  .footer { padding-bottom: 4.5rem; }
  .footer__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-md) var(--space-sm); }
  .footer__list a, .footer__list li { overflow-wrap: anywhere; }
  .footer__col--brand,
  .footer__inner > .footer__col:nth-child(2),
  .footer__inner > .footer__col:last-child { grid-column: 1 / -1; }
  .footer__inner > .footer__col:nth-child(3) .footer__list,
  .footer__inner > .footer__col:nth-child(4) .footer__list { font-size: 0.875rem; hyphens: auto; }
  .footer__heading { margin-bottom: var(--space-xs); }
  /* Kontakt: Telefon, Mail und Web in einer Reihe, Adresse darunter */
  .footer__inner > .footer__col:nth-child(2) .footer__list { flex-direction: row; flex-wrap: wrap; gap: var(--space-2xs) var(--space-md); }
  .footer__inner > .footer__col:nth-child(2) .footer__list li:last-child { flex-basis: 100%; }
  .footer__inner > .footer__col:last-child .footer__list { flex-direction: row; flex-wrap: wrap; gap: var(--space-2xs) var(--space-md); }
  .footer__list a, .footer__cookie-link { padding-block: 0.2rem; }
}

/* Schleier unter der Kopfzeile: nichts laeuft sichtbar unter der Leiste durch (nur Handy, Seiten im Weltraum-Look) */
.header-veil { display: none; }
@media (max-width: 1023px) {
  .header-veil {
    display: block;
    position: fixed;
    inset: 0 0 auto 0;
    height: calc(var(--header-h) + 22px);
    z-index: 490;
    pointer-events: none;
    --veil: var(--color-bg, #fff);
    background: linear-gradient(180deg, var(--veil) 0, var(--veil) calc(100% - 20px), transparent 100%);
  }
}
@media (max-width: 1023px) { body.v2 .header-veil { --veil: var(--v2-void, #02040b); } }

/* Sehr schmale Handys (320 px): Kopfzeile bleibt im Bild, Logo und Schriftzug werden etwas kleiner */
@media (max-width: 349px) {
  .nav__logo { font-size: 0.82rem; gap: 0.3rem; }
  .nav__logo-mark { height: 22px; }
}

/* Kontakt auf 320 px: die Spalte darf schmaler als ihr Inhalt werden */
@media (max-width: 1023px) { .contact-grid { grid-template-columns: minmax(0, 1fr); } }
.contact-grid > * { min-width: 0; }

/* Rechtstexte: lange Woerter in Ueberschriften brechen um, statt die Seite zu verbreitern */
.legal h1, .legal h2, .legal h3, .legal .section__title { overflow-wrap: anywhere; hyphens: auto; }

/* Unterseiten am Handy (Rechtstexte, Fehlerseiten u. a.): der Inhalt beginnt direkt unter der Kopfleiste. Die erste Sektion trug 182 px
   Polster oben (Sektionspolster + Kopfleiste + Abstand) und liess einen leeren Streifen. */
@media (max-width: 900px) {
  body:not(.has-dark-hero) > main > :first-child {
    padding-top: calc(var(--nav-pill-h) + 1.5rem);
  }
}

/* Datenschutz: Tabelle der gespeicherten Informationen (am Handy seitlich scrollbar) */
.legal h3 { margin: var(--space-md, 1.5rem) 0 var(--space-2xs, 0.5rem); font-size: 1.1rem; }
.legal-table-wrap { overflow-x: auto; margin: 0 0 var(--space-md, 1.5rem); -webkit-overflow-scrolling: touch; }
.legal-table { width: 100%; min-width: 34rem; border-collapse: collapse; font-size: 0.9rem; line-height: 1.45; }
.legal-table th, .legal-table td { padding: 0.6rem 0.75rem; text-align: left; vertical-align: top; border-bottom: 1px solid rgba(120, 130, 150, 0.3); }
.legal-table th { font-weight: 700; color: inherit; border-bottom-color: rgba(120, 130, 150, 0.6); }
