/* =====================================================
   website-relaunch-pro: Basis-CSS
   In den Projektordner kopieren als assets/css/style.css.
   WICHTIG: <html lang="de" class="no-js"> setzen; main.js
   entfernt die Klasse, so bleibt alles ohne JS sichtbar.

   STRUKTUR ist hier fertig. TOKENS sind es NICHT.
   ===================================================== */

/* =====================================================
   TOKEN-BLOCK — KOMPLETT ERSETZEN, NICHT ÜBERNEHMEN

   Die Werte unten sind BEISPIELWERTE, damit die Datei
   allein lauffähig ist. Sie sind KEINE Vorlage.

   Der Agent setzt in Phase 3/4 JEDEN dieser Werte selbst,
   abgeleitet aus Marke, Branche und der in DESIGN.md
   gewählten Design-Richtung.

   Die QA prüft als BLOCKER, ob --fs-hero, --fs-h2,
   --section, --gutter, --radius und --ease sich von den
   Werten unten unterscheiden. Identische clamp-Werte über
   mehrere Projekte hinweg sind der Hauptgrund dafür, dass
   alle gebauten Websites gleich aussehen.

   Pflicht laut design-system.md:
   - mindestens FÜNF Untergrund-Abstufungen
   - --font-head/--font-body sind die vom Kunden gewählte
     Katalog-Schrift aus assets/fonts/<id>/ (Zeile SCHRIFT im
     Auftrag), NIEMALS eine System-Serife (R2)
   - --nav-h stimmt mit der echten Navigationshöhe überein,
     weil die Hero-Höhe darauf rechnet (R3)
   ===================================================== */

:root {
  /* FARBEN: fünf Untergrund-Stufen, nicht eine */
  --bg: #0b0c0e;
  --bg-2: #101216;
  --bg-3: #16181d;
  --surface: #141619;
  --surface-2: #1d2024;
  --text: #f4f5f7;
  --muted: #9aa1ab;
  --dim: #6b7280;
  --brand: #e0b352;
  --brand-ink: #101010;
  --brand-soft: rgba(224, 179, 82, .12);
  --brand-line: rgba(224, 179, 82, .38);
  --rare: #7aa2c2;                       /* Zweitakzent: maximal 2x auf der Seite */
  --line: rgba(255, 255, 255, .09);
  --line-2: rgba(255, 255, 255, .16);

  /* TYPO — Schrift aus der SCHRIFT-Zeile des Auftrags (assets/fonts/<id>/font.css vor dieser Datei laden), Skala projektspezifisch setzen */
  --font-head: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --fs-hero: clamp(2.6rem, 6.5vw, 4.8rem);
  --fs-h2: clamp(1.9rem, 3.6vw, 2.8rem);
  --fs-h3: clamp(1.2rem, 1.8vw, 1.45rem);
  --fs-body: clamp(1rem, 1.1vw, 1.125rem);
  --fs-label: .8rem;

  /* RHYTHMUS */
  --section: clamp(4.5rem, 10vw, 8rem);
  --container: 1200px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 20px 60px rgba(0, 0, 0, .35);
  --shadow-lg: 0 34px 84px rgba(0, 0, 0, .5);
  --ease: cubic-bezier(.2, .7, .2, 1);

  /* STAPEL-ORDNUNG (z-index): verbindliche Skala.
     EISERNE REGEL: Dekoration bekommt NIE einen hoeheren Wert als Inhalt.
     Keine rohen z-index-Zahlen im Projekt-CSS, immer diese Tokens.
     Der Fehler vom 28.07.2026 (Scroll-Kreis z-index 8 ueber Text z-index 7)
     ist mit dieser Skala nicht mehr baubar. */
  --z-media: 0;      /* Hero-Bild, Hintergrundmedium */
  --z-overlay: 1;    /* Vignette, Farbverlauf ueber dem Medium */
  --z-deco: 2;       /* Scroll-Pfeil, Ornamente, Muster */
  --z-content: 7;    /* JEDER lesbare Text und jeder Button */
  --z-nav: 100;      /* fixierte Navigation */
  --z-float: 90;     /* WhatsApp-Button */
  --z-modal: 300;    /* Zwei-Klick-Overlays, Dialoge */

  /* FARBFLÄCHEN-GESETZ (Fehler Nr. 4 vom 29.07.2026: grauer Untertext auf
     Markenblau). Auf Akzent-/Markenflächen existieren GENAU ZWEI Textfarben:
     --on-brand für Überschriften/Buttons, --on-brand-mute für den Untertext.
     --muted, --ink-mute, --ink-dim sind auf farbigen Flächen VERBOTEN, sie
     sind auf den neutralen Untergrund gerechnet und werden auf Farbe unlesbar.
     Projektspezifisch setzen (bei dunkler Markenfarbe i.d.R. Weiß-Töne): */
  --on-brand: #ffffff;
  --on-brand-mute: rgba(255, 255, 255, .85);

  /* Von main.js gemessen, niemals von Hand setzen:
     --nav-h  echte Hoehe der Navigation (unterscheidet sich mobil!)
     --sbw    Breite der Scrollleiste (fuer Vollbreite-Sektionen) */
  --sbw: 0px;

  /* NAVIGATIONSHÖHE — muss zur echten Leiste passen (R3) */
  --nav-h: 62px;
}
@media (min-width: 760px) { :root { --nav-h: 70px; } }

/* ---------- Scroll-Fortschrittsbalken (PFLICHT auf jeder Seite) ----------
   main.js setzt --p. 2px, .08s linear: ohne Übergang ruckelt er,
   ab 0.1s hinkt er nach. */
.progress { position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: calc(var(--z-nav) + 1); pointer-events: none; }
.progress span {
  display: block; height: 100%; width: var(--p, 0%);
  background: linear-gradient(90deg, var(--brand), var(--brand), var(--rare) 70%, var(--brand));
  box-shadow: 0 0 12px var(--brand-line);   /* HELLES THEME: stattdessen 0 1px 4px */
  transition: width .08s linear;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; background: none; border: 0; color: inherit; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 4px; }

/* ---------- Layout ---------- */
.container { max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section); }
.grid { display: grid; gap: 24px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
/* .split NUR für Inhaltssektionen, NIEMALS für den Hero (R1).
   Text links plus Bild rechts im Hero ist ein QA-Blocker. */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 6vw, 5rem); align-items: center; }

/* ---------- Typo ---------- */
h1, h2, h3 { font-family: var(--font-head); line-height: 1.1; letter-spacing: -.02em; text-wrap: balance; }
h1 { font-size: var(--fs-hero); font-weight: 800; }
h2 { font-size: var(--fs-h2); font-weight: 800; }
h3 { font-size: var(--fs-h3); font-weight: 700; }
p { max-width: 65ch; }
.muted { color: var(--muted); }
.kicker {
  display: inline-block; font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--brand); margin-bottom: 14px;
}
/* R1 ZENTRIERUNG: Sektionsköpfe sind IMMER zentriert. Kein Sonderfall. */
.section-head { text-align: center; max-width: 64ch; margin: 0 auto clamp(2rem, 5vw, 3.5rem); }
.section-head .kicker { display: inline-block; margin-bottom: 14px; }
.section-head h2 { margin: 0; }
.section-head p { margin: 12px auto 0; max-width: 58ch; color: var(--muted); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 28px; border-radius: 999px; font-weight: 700; line-height: 1;
  transition: transform .2s var(--ease), background .2s, border-color .2s, color .2s;
}
.btn:hover { transform: translateY(-2px); }
.btn-primary { background: var(--brand); color: var(--brand-ink); }
.btn-ghost { border: 1px solid var(--line); color: var(--text); }
.btn-ghost:hover { border-color: var(--brand); color: var(--brand); }

/* ---------- POLISH-FUNDAMENT: Press-Feedback ---------- ═══ GESPERRT ═══
   NICHT ENTFERNEN (Eiserne Regel 12, QA Pass 4). Feedback kommt beim
   RUNTERDRUECKEN, nicht erst beim Loslassen — der Unterschied zwischen
   "reagiert sofort" und "fuehlt sich tot an". Kurze .1s, damit es knackt.
   Auf Maus-Geraeten mischt main.js den Druck in den Magnet-Transform;
   diese Regeln greifen auf Touch und ueberall ohne JS.
   Neue eigene Komponenten bekommen ihre EIGENE :active-Regel dazu. */
.btn:active { transform: translateY(0) scale(.97); transition-duration: .1s; }
.tile:active { transform: perspective(900px) scale(.98); transition-duration: .1s; }
.card:active { transform: translateY(-1px) scale(.99); transition-duration: .1s; }
.nav-links a:active, .footer a:active, .faq-q:active { color: var(--brand); }
.burger:active span { background: var(--brand); }
.theme-toggle:active, .wa-float:active, .scroll-down:active { transform: scale(.94); transition-duration: .1s; }

/* ---------- Navigation ---------- */
.nav {
  position: fixed; inset-inline: 0; top: 0; z-index: var(--z-nav);
  transition: background .3s, border-color .3s;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}
/* ---------- BURGER-BUGFIX 13.08.2026 ---------- ═══ GESPERRT ═══
   Offenes Mobil-Menü: backdrop-filter der Leiste MUSS aus sein.
   Ein backdrop-filter (oder filter/transform) auf .nav macht .nav zum
   Containing Block für position:fixed-Kinder — das Vollbild-Overlay
   .nav-links saß dann in der ~70px-Leiste statt im Viewport: nach dem
   Scrollen (.scrolled aktiv) waren die oberen Menüpunkte unerreichbar
   (Kundenbug vt-marl.de, 13.08.2026). !important, damit auch spätere
   gleich-spezifische Regeln (.nav.scrolled, Projekt-CSS) das nie wieder
   einschalten. Solider Hintergrund: die Leiste verschmilzt mit dem
   Overlay darunter. Auf Desktop existiert .open nicht (Burger versteckt). */
.nav.open {
  background: var(--bg);
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
}
/* Das Overlay ist ein NACHFAHRE der Leiste — deren Hintergrund kann eigene
   Kinder nicht verdecken. Deshalb blendet eine Maske auf dem Overlay (im
   Mobil-Block unten) alles aus, was beim Scrollen unter die Leiste wandert. */
/* Niemals transform/filter auf .nav legen — gleicher Containing-Block-Bug. */
/* 3-Zonen-Leiste: Logo links, Links EXAKT mittig, Aktionen rechts.
   ═══ GESPERRT ═══ Dieses Grid NIEMALS im Projekt-CSS umdefinieren.
   "auto minmax(0,1fr) auto" oder Flex mit space-between schiebt die
   Linkgruppe aus der Mitte — Fehler Nr. 2 vom 29.07.2026, wird vom
   Prüfskript als NAVMITTE/STRUKTUR gemessen. Nur 1fr auto 1fr zentriert
   die Links auf die BILDSCHIRM-Mitte, unabhängig von Logo-Breite. */
.nav-inner { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 24px; padding-block: 14px; }
.nav-inner > .nav-logo, .nav-inner > .logo { justify-self: start; }
.nav-inner > nav { justify-self: center; }
.nav-actions { justify-self: end; display: flex; align-items: center; gap: 12px; }
.nav-logo img { height: 40px; width: auto; }
.nav-links { display: flex; align-items: center; gap: 28px; list-style: none; }
.nav-links a { font-weight: 600; font-size: .95rem; transition: color .2s; }
.nav-links a:hover, .nav-links a.active { color: var(--brand); }
.nav-cta { padding: 11px 22px; }
.burger { display: none; flex-direction: column; gap: 5px; padding: 10px; }
.burger span { width: 24px; height: 2px; background: var(--text); transition: transform .3s var(--ease), opacity .2s; }

/* ---------- Theme-Umschalter (optional) ----------
   Standard-Theme in :root. Gegen-Theme hier als Override,
   Attribut auf <html data-theme="...">. Beispiel für helles
   Gegen-Theme, Werte projektspezifisch setzen: */
[data-theme="light"] {
  --bg: #faf9f7;
  --surface: #ffffff;
  --surface-2: #f1efeb;
  --text: #17181a;
  --muted: #5c6470;
  --line: rgba(0, 0, 0, .1);
  --shadow: 0 20px 60px rgba(0, 0, 0, .1);
}
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line);
  color: var(--text); transition: border-color .2s, color .2s;
}
.theme-toggle:hover { border-color: var(--brand); color: var(--brand); }
.theme-toggle svg { width: 18px; height: 18px; }


/* ---------- ANKER-LANDUNG (Pflicht) ---------- ═══ GESPERRT ═══
   Die Navigation ist fixiert und deckt die oberen --nav-h Pixel ab.
   Ohne die beiden Regeln landet JEDER #anker-Sprung und jeder Klick auf
   den Scroll-Pfeil so, dass die Kopfzeile der Zielsektion unter der
   Navigation verschwindet. Genau das ist der Eindruck "die Ebenen sind
   schlecht geschnitten". 18px Zugabe, damit die Sektion sichtbar atmet. */
html { scroll-padding-top: calc(var(--nav-h) + 18px); }
/* ACHTUNG (Messung 29.07.2026): scroll-padding-top und scroll-margin-top
   ADDIEREN sich im Browser. Beides zu setzen laesst jeden Sprung ~100px zu
   tief landen. Deshalb NUR scroll-padding-top — [id]{scroll-margin-top}
   bleibt 0 und wird NICHT gesetzt. */

/* ---------- HERO ---------- ═══ GESPERRT (Höhe, Anschluss, Ausbruch) ═══
   R1 + R3: IMMER zentriert, IMMER exakte Höhe. Es gibt keine
   linksbündige und keine ungefähre Variante mehr. Der Hero beginnt
   Pixel an Pixel an der Nav-Unterkante (margin-top: var(--nav-h)) —
   ein leeres Band dazwischen war Fehler Nr. 1 vom 29.07.2026 (LEERBLOCK). */
.hero {
  position: relative; overflow: hidden; isolation: isolate;
  /* Vollbreite-Ausbruch. --sbw ist die Scrollleisten-Breite, die main.js
     misst. Ohne sie ist die Sektion genau um die Scrollleiste zu breit
     und die ganze Seite scrollt seitlich (auf Windows immer sichtbar). */
  width: calc(100vw - var(--sbw));
  margin-left: calc(50% - (100vw - var(--sbw)) / 2);
  margin-right: calc(50% - (100vw - var(--sbw)) / 2);
  /* R3: genau Viewport minus Navigationshöhe. min-height statt height,
     mit voller Absicht: bei exakter Höhe plus overflow:hidden wird Hero-Text
     auf kleinen Handys ABGESCHNITTEN. Ein Hero, der im Ausnahmefall 40px
     mitwächst, ist ein Schönheitsfehler. Abgeschnittene Schrift ist ein
     verlorener Kunde. Im Normalfall greift die Höhe exakt wie vorher,
     weil das Text-Budget aus dem Design-System eingehalten wird. */
  min-height: calc(100vh - var(--nav-h));
  min-height: calc(100dvh - var(--nav-h));
  /* Die Navigation ist fixiert und liegt UEBER dem Inhalt. Ohne diesen
     Versatz beginnt das Hero unter der Leiste und der Hero-Text laeuft in
     sie hinein. Auf kleinen Handys verschwindet dadurch die halbe
     Ueberschrift. Der Versatz gehoert ins Fundament, nicht in jedes
     Projekt-CSS von Hand. */
  margin-top: var(--nav-h);
  display: flex; align-items: center; justify-content: center;
}
/* Sehr flache Fenster: 520px Mindesthöhe wuerde hier ueber den Bildschirm
   hinausragen, deshalb bewusst nur dort, wo genug Platz ist. */
@media (min-height: 560px) { .hero { min-height: max(520px, calc(100dvh - var(--nav-h))); } }
.hero .hero-content {
  position: relative; z-index: var(--z-content);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  width: 100%; max-width: var(--container); margin-inline: auto;
  padding-inline: var(--gutter);
}
.hero .hero-content h1 { margin-inline: auto; max-width: 15ch; }
.hero .hero-content p.lead { margin-inline: auto; }
.hero .hero-actions { justify-content: center; align-self: center; }

/* R4 VIGNETTE: Pflicht, sobald Text über einem Bild liegt.
   Immer ZWEI Verläufe, nie einer. Variante je nach Lichtwelt. */
.hero-veil { position: absolute; inset: 0; z-index: var(--z-overlay); pointer-events: none; }
.hero-veil.dark {
  background:
    radial-gradient(ellipse at center, transparent 35%, rgba(0,0,0,.55) 78%, rgba(0,0,0,.95) 100%),
    linear-gradient(180deg, rgba(0,0,0,.55) 0%, transparent 22%, transparent 58%, rgba(0,0,0,.95) 100%);
}
/* Helle Variante: Projektfarbe für BG einsetzen (rgba des --bg-Werts). */
.hero-veil.light {
  background:
    radial-gradient(ellipse 76% 62% at 50% 48%,
      rgba(255,255,255,.94) 0%, rgba(255,255,255,.86) 34%,
      rgba(255,255,255,.52) 62%, rgba(255,255,255,0) 88%),
    linear-gradient(180deg, rgba(255,255,255,.88) 0%, transparent 18%, transparent 72%, rgba(255,255,255,.94) 100%);
}

/* Scroll-Pfeil: ersetzt Buttons im Hero. Drei Animationen mit
   UNTERSCHIEDLICHEN Laufzeiten, sonst entsteht ein Gleichtakt. */
.scroll-down {
  margin-top: 40px; align-self: center;
  width: 58px; height: 58px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-soft); border: 1.5px solid var(--brand); color: var(--brand);
  position: relative; cursor: pointer;
  transition: background .3s ease, transform .3s ease, box-shadow .3s ease, color .3s ease;
  animation: sdBounce 2.4s ease-in-out infinite;
}
.scroll-down::before {
  content: ""; position: absolute; inset: -1.5px; border-radius: 50%;
  border: 1.5px solid var(--brand); opacity: 0; pointer-events: none;
  animation: sdRing 2.4s ease-out infinite;
}
.scroll-down svg { width: 22px; height: 22px; animation: sdSlide 1.8s ease-in-out infinite; }
.scroll-down:hover {
  background: var(--brand); color: var(--brand-ink); transform: scale(1.08);
  animation-play-state: paused;
}
@keyframes sdBounce { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(8px) } }
@keyframes sdSlide  { 0%, 100% { transform: translateY(-2px); opacity: .85 } 50% { transform: translateY(3px); opacity: 1 } }
@keyframes sdRing   { 0% { opacity: .5; transform: scale(1) } 100% { opacity: 0; transform: scale(1.7) } }
/* ACHTUNG, TEURER FEHLER: Der Scroll-Pfeil steht im FLUSS (margin-top oben),
   nicht absolut am unteren Rand. Wer ihn auf
      position: absolute; bottom: 30px; z-index: 8
   umbaut, erzeugt den Fehler "Kreis liegt auf der Schrift", sobald der Hero-
   Text eine Zeile laenger wird oder das Fenster flacher ist. Genau so ist es
   am 28.07.2026 auf einer ausgelieferten Kundenseite passiert. Nicht aendern. */
.hero > .scroll-down, .hero .hero-content > .scroll-down { position: relative; z-index: var(--z-deco); }
.scroll-hint {
  position: relative; z-index: var(--z-deco);
  margin-top: 40px; align-self: center;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  min-width: 44px; min-height: 44px;
  color: var(--muted); font-size: .75rem; letter-spacing: .18em; text-transform: uppercase;
}
.scroll-hint::after {
  content: ""; width: 1px; height: 44px;
  background: linear-gradient(to bottom, var(--brand), transparent);
  animation: scrollhint 2s var(--ease) infinite;
}
@keyframes scrollhint {
  0% { transform: scaleY(0); transform-origin: top; }
  45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}
.hero-media, .hero-media img, .hero-media video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: var(--z-media);
}
.hero-overlay {
  position: absolute; inset: 0; z-index: var(--z-overlay); pointer-events: none;
  background: linear-gradient(to top, var(--bg) 4%, color-mix(in srgb, var(--bg) 55%, transparent) 45%, color-mix(in srgb, var(--bg) 25%, transparent) 100%);
}
.hero-content { position: relative; z-index: var(--z-content); padding-block: clamp(2rem, 6vh, 4rem); }
.hero-content p.lead { font-size: clamp(1.05rem, 1.5vw, 1.3rem); color: var(--muted); margin-top: 18px; max-width: 55ch; }
/* Button-Paare: exakt gleich breit (1fr-Spalten am breitesten Kind) */
.hero-actions { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 14px; margin-top: 32px; }
@media (max-width: 560px) {
  .hero-actions { grid-auto-flow: row; width: 100%; }
}

/* ---------- Cards ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 32px; display: flex; flex-direction: column; gap: 14px;
  transition: transform .25s var(--ease), border-color .25s, background .25s;
}
.card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--brand) 55%, var(--line)); background: var(--surface-2); }
.card .icon {
  width: 52px; height: 52px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand);
}
.card .icon svg { width: 26px; height: 26px; }
.card p { color: var(--muted); font-size: .98rem; }
/* R1: Karteninhalte zentriert. */
.card { text-align: center; align-items: center; }
.card .more { align-self: center; }
.card .more { margin-top: auto; font-weight: 700; color: var(--brand); display: inline-flex; gap: 8px; align-items: center; }

/* ---------- Bildkacheln mit Tempo-Kontrast ----------
   Das langsame Bild (1.6s) gegen die schnellen Details (0.25s) ist
   der wirksamste Luxus-Effekt. Gleiche Geschwindigkeiten wirken billig. */
.tile { position: relative; display: block; overflow: hidden; border-radius: calc(var(--radius) + 6px);
        min-height: 380px; border: 1px solid var(--line); background: var(--surface);
        isolation: isolate; transform-style: preserve-3d; will-change: transform;
        transform: perspective(900px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
        transition: transform .5s var(--ease), border-color .35s, box-shadow .35s; }
.tile:hover { border-color: var(--brand-line); box-shadow: var(--shadow-lg); }
.tile-bg { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center;
           transform: scale(1.06); filter: saturate(.55) contrast(1.02);
           transition: transform 1.6s ease, filter .6s ease; }
.tile:hover .tile-bg { transform: scale(1.14); filter: saturate(1) contrast(1.06); }
.tile-veil { position: absolute; inset: 0; z-index: 1;
             background: linear-gradient(180deg, rgba(0,0,0,.10) 0%, rgba(0,0,0,.60) 55%, rgba(0,0,0,.95) 100%); }
/* R1: Kachelinhalt zentriert, unten sitzend. */
.tile-content { position: relative; z-index: 2; min-height: 380px; padding: 28px 26px 30px;
                display: flex; flex-direction: column; justify-content: flex-end;
                align-items: center; text-align: center; }
.tile-link { display: inline-flex; align-items: center; gap: 8px; align-self: center;
             font-weight: 700; padding-bottom: 6px; border-bottom: 1px solid transparent;
             transition: border-color .25s, color .25s, gap .25s; }
.tile:hover .tile-link { color: var(--brand); border-color: var(--brand); gap: 14px; }

/* ---------- Stats ---------- */
.stats { border-block: 1px solid var(--line); }
.stat { text-align: center; padding-block: 8px; }
.stat .num { font-size: clamp(2.2rem, 5vw, 3.6rem); font-weight: 800; letter-spacing: -.02em; color: var(--brand); }
.stat .label { color: var(--muted); font-size: .9rem; margin-top: 6px; }

/* ---------- FAQ ---------- */
.faq-item { border-bottom: 1px solid var(--line); }
.faq-q { width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 16px; padding-block: 22px; font-weight: 700; text-align: left; }
.faq-q::after { content: "+"; font-size: 1.4rem; color: var(--brand); transition: transform .3s var(--ease); }
.faq-item.open .faq-q::after { transform: rotate(45deg); }
.faq-a { max-height: 0; overflow: hidden; transition: max-height .35s var(--ease); }
.faq-a p { padding-bottom: 22px; color: var(--muted); }

/* ---------- CTA-Band ----------
   Als volle Markenfläche (Clever-Formel Block 7): background auf var(--brand)
   setzen — dann greift automatisch das Farbflächen-Gesetz unten. */
.cta-band { background: var(--surface); border-block: 1px solid var(--line); text-align: center; }
.cta-band .hero-actions { justify-content: center; }

/* FARBFLÄCHEN-GESETZ, technisch erzwungen: auf einer Markenfläche werden alle
   Grau-Töne auf die On-Brand-Farben umgebogen. .band-brand an die Sektion. */
.band-brand { background: var(--brand); border-block: 0; }
.band-brand h1, .band-brand h2, .band-brand h3, .band-brand .kicker { color: var(--on-brand); }
.band-brand p, .band-brand .muted, .band-brand .lead, .band-brand li { color: var(--on-brand-mute); }
.band-brand .btn-primary { background: var(--on-brand); color: var(--brand); }
.band-brand .btn-ghost { border-color: var(--on-brand-mute); color: var(--on-brand); }
.band-brand .btn-ghost:hover { border-color: var(--on-brand); color: var(--on-brand); }

/* ---------- Kontakt ---------- */
.contact-item { display: flex; gap: 16px; align-items: flex-start; padding: 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.contact-item strong { display: block; margin-bottom: 4px; }
.contact-item a:hover { color: var(--brand); }

/* ---------- Zwei-Klick-Consent (Karte/Video) ---------- */
.consent-box {
  position: relative; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); min-height: 340px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; text-align: center; padding: 32px; overflow: hidden;
}
.consent-box p { color: var(--muted); font-size: .92rem; max-width: 46ch; }
.consent-box iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------- Footer ---------- */
.footer { border-top: 1px solid var(--line); padding-block: clamp(3rem, 6vw, 4.5rem) 2rem; }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; }
.footer h4 { font-size: .85rem; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin-bottom: 16px; }
.footer ul { list-style: none; display: grid; gap: 10px; }
.footer a:hover { color: var(--brand); }
.footer-bottom { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; color: var(--muted); font-size: .88rem; }

/* ---------- MOBIL-KOMPOSITION: Bausteine, die nur auf dem Handy erscheinen ----------
   ═══ GESPERRT ═══ (01.09.2026, Tim: "99% schauen mobil, es muss beides perfekt sein")
   .hero-cta    = GENAU EIN Primaer-Knopf im Hero (tel: oder wa.me), sitzt mobil
                  unter dem Untertext. Auf dem Desktop unsichtbar (dort bleibt
                  die Clever-Formel: kein Button, der Pfeil ist der CTA).
   .mobile-bar  = feste Kontaktleiste am unteren Rand (Daumenzone): Anrufen +
                  WhatsApp/E-Mail. Erscheint, sobald der Hero nach oben
                  weggescrollt ist (main.js setzt .on). Desktop: nie sichtbar.
   Beide Bausteine sind PFLICHT im Markup jeder Startseite (SKILL.md Phase 4)
   und werden mechanisch gemessen (gelernte Checks mobil-hero-komposition,
   mobil-cta). */
.hero-cta { display: none; }
.mobile-bar { display: none; }

/* ---------- AKZENTWORT im Hero: lebendiges Gold statt matschiger Verlauf ----------
   ═══ GESPERRT ═══ (10.09.2026, Tim: "haessliche Farbe, mach das mit einem
   animierten Fade schoener, Gold das funkelt").
   Gilt fuer das EINE Akzentwort der H1 (Clever-Formel), egal wie das Projekt
   die Klasse nennt (.grad ist der Standard aus SKILL.md). Farben kommen aus
   dem Projekt (--acc/--acc-2 bzw. --brand/--brand-2), base.css legt nur
   Lichtlauf und Glanz darueber: ein heller Lichtstreifen (Akzent + Weiss)
   wandert alle 6 s einmal durch das Wort, dazu ein weicher Schein in der
   Akzentfarbe. text-shadow ist hier hart AUS: bei background-clip:text
   scheint ein Textschatten DURCH die transparenten Buchstaben und macht
   jeden Verlauf braun/matschig (genau Tims Befund auf der HHS-Vorschau). */
.hero h1 .grad, .hero h1 .accent, .hero h1 .accent-word, .hero h1 .akzent, .hero h1 .highlight, .hero h1 [class*="grad"] {
  --aw-a: var(--acc, var(--brand));
  --aw-b: var(--acc-2, var(--brand-2, var(--acc, var(--brand))));
  --aw-hi: color-mix(in srgb, var(--aw-a) 42%, #fff);
  display: inline-block; position: relative;
  background-image: linear-gradient(100deg,
    var(--aw-a) 0%, var(--aw-b) 14%, var(--aw-a) 30%,
    var(--aw-hi) 42%, var(--aw-a) 54%, var(--aw-b) 72%, var(--aw-a) 100%);
  background-size: 320% 100%; background-position: 100% 50%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  text-shadow: none !important;
  filter: drop-shadow(0 0 16px color-mix(in srgb, var(--aw-a) 38%, transparent));
  animation: awShimmer 6s linear infinite;
  /* UNTERLAENGEN (14.09.2026, Tim attraversiamo.lu: das g von "Magie" war unten
     abrasiert; gelernter Check unterlaengen-komplett): background-clip:text malt
     nur innerhalb der Elementbox, g/j/p/q/y ragen bei line-height 1.1 darunter.
     Padding gibt der Fahne Raum, der negative Margin haelt das Layout exakt. */
  padding-bottom: .18em; margin-bottom: -.18em; padding-top: .08em; margin-top: -.08em;
}
@keyframes awShimmer { 0% { background-position: 100% 50% } 100% { background-position: -100% 50% } }
@media (prefers-reduced-motion: reduce) {
  .hero h1 .grad, .hero h1 .accent, .hero h1 .accent-word, .hero h1 .akzent, .hero h1 .highlight, .hero h1 [class*="grad"] { animation: none; background-position: 50% 50%; }
}
/* Pillen (eyebrow/pill/badge): Grossbuchstaben ohne Unterlaengen sitzen mit
   normaler Zeilenhoehe optisch zu HOCH in der Bubble (unten bleibt der
   Unterlaengen-Raum leer, Tim 10.09.). line-height 1 + ein Hauch Luft oben
   zentriert die Versalien wirklich. */
.hero .eyebrow, .hero .pill, .hero .badge { line-height: 1; padding-top: calc(.68em + 1px); padding-bottom: .68em; }

/* ---------- WhatsApp-Float ---------- */
.wa-float {
  position: fixed; right: 20px; bottom: 20px; z-index: var(--z-float);
  width: 58px; height: 58px; border-radius: 50%; background: #25d366;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .3); transition: transform .2s var(--ease);
}
.wa-float:hover { transform: scale(1.07); }
.wa-float svg { width: 30px; height: 30px; fill: #fff; }

/* ---------- Rechtsseiten ---------- */
.legal { max-width: 75ch; }
.legal h1 { font-size: clamp(2rem, 4vw, 3rem); margin-bottom: 1.5rem; }
.legal h2 { font-size: 1.35rem; margin: 2.2rem 0 .8rem; }
.legal h3 { font-size: 1.1rem; margin: 1.6rem 0 .6rem; }
.legal p, .legal li { color: var(--muted); margin-bottom: .8rem; }
.legal ul { padding-left: 1.2rem; }
.legal a { color: var(--brand); }
.placeholder-block {
  border: 1px dashed var(--brand); border-radius: var(--radius-sm);
  padding: 18px; color: var(--brand); font-weight: 600; margin-block: 1rem;
}

/* ---------- Theme-Medien: Stills je Theme ----------
   Zwei <img> nebeneinander, CSS blendet je Theme genau eins ein. */
.img-light { display: none; }
[data-theme="light"] .img-dark { display: none; }
[data-theme="light"] .img-light { display: block; }

/* ---------- Reveal (JS setzt .in) ---------- */
/* Werte laut design-system.md Abschnitt 5: 28px und 0.9s.
   Kürzer wirkt hektisch, weiter wirkt träge. */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- POLISH-FUNDAMENT: die zwei anderen Bedienungs-Signale ----------
   ═══ GESPERRT ═══ NICHT ENTFERNEN (Eiserne Regel 12, QA Pass 4).
   prefers-reduced-motion steht direkt darueber; diese zwei gehoeren dazu.
   Sie aendern im Normalfall NICHTS am Design, sie greifen nur, wenn der
   Besucher es in seinem System so eingestellt hat. */
@media (prefers-reduced-transparency: reduce) {
  .nav.scrolled { background: var(--bg); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  body { --muted: color-mix(in srgb, var(--text) 80%, var(--bg)); }
  .btn-ghost, .theme-toggle { border-width: 2px; border-color: currentColor; }
  .btn-primary { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text); }
  .card, .tile, .contact-item, .consent-box { border-color: var(--line-2); }
}

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
  /* ---------- Mobil-Menü (Vollbild-Overlay) ---------- ═══ GESPERRT ═══
     BURGER-BUGFIX + REDESIGN 13.08.2026. Zwei Regeln, die bleiben MÜSSEN:
     1) KEIN justify-content:center auf .nav-links — bei vielen Menüpunkten
        schiebt Zentrieren die oberen Punkte über den Viewport-Rand hinaus,
        wo kein Scrollen sie erreicht. Stattdessen: flex-start + overflow-y
        + auto-Margins auf erstem/letztem li (zentriert, solange es passt,
        scrollt, sobald es nicht mehr passt).
     2) Der Containing-Block-Fix (.nav.open weiter oben) gehört dazu.
     Projekt-CSS darf Schriftgröße/Abstände/Farben anpassen, aber NIE
     position/justify-content/overflow dieses Blocks umdefinieren. */
  .nav-links {
    position: fixed; inset: 0; z-index: -1;
    flex-direction: column; align-items: center; justify-content: flex-start;
    gap: clamp(16px, 3.6vh, 30px);
    padding: calc(var(--nav-h, 76px) + 14px) 28px calc(26px + env(safe-area-inset-bottom, 0px));
    background: var(--bg); font-size: 1.4rem;
    overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
    /* Maske: Menüpunkte, die im Overlay unter die Leiste scrollen, lösen sich
       dort auf, statt durch Logo/Schließen-Kreuz zu scheinen (das Overlay ist
       ein Nachfahre der Leiste, deren Hintergrund kann es nicht verdecken). */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, transparent calc(var(--nav-h, 76px) - 30px), #000 calc(var(--nav-h, 76px) - 2px));
    mask-image: linear-gradient(to bottom, transparent 0, transparent calc(var(--nav-h, 76px) - 30px), #000 calc(var(--nav-h, 76px) - 2px));
    opacity: 0; pointer-events: none; visibility: hidden;
    transition: opacity .28s var(--ease), visibility 0s .28s;
  }
  .nav-links li:first-child { margin-top: auto; }
  .nav-links li:last-child { margin-bottom: auto; }
  .nav-links a { display: block; padding: 6px 18px; text-align: center; }
  /* Gestaffelte Einblendung: Punkte gleiten nacheinander hoch. */
  .nav-links li { opacity: 0; transform: translateY(14px); transition: opacity .3s var(--ease), transform .3s var(--ease); }
  .nav.open .nav-links {
    opacity: 1; pointer-events: auto; visibility: visible;
    transition: opacity .28s var(--ease);
    z-index: 0;
  }
  /* ═══ GESPERRT ═══ MENUE-X-FIX 01.09.2026 (Kundenbug tina-site, von Tim):
     Das Overlay ist ein NACHFAHRE der Leiste (.nav = eigener Stacking-Context).
     Sein z-index zaehlt darum nur gegen Logo, CTA und Burger. Der fruehere
     Wert calc(var(--z-nav) - 1) = 99 legte das Overlay UEBER Burger und Logo:
     das X war sichtbar, aber jeder Tipp traf das Overlay. Kunde kam aus dem
     Menue nicht mehr raus. Deshalb: Overlay auf 0, Leisteninhalt auf 1.
     Ein z-index auf .nav-inner reicht NICHT (das Overlay steckt darin).
     Wird vom Pruefskript gemessen (gelernter Check menue-x-klickbar). */
  .nav-inner > .nav-logo, .nav-inner > .logo, .nav-actions, .burger { position: relative; z-index: 1; }
  .nav.open .nav-links li { opacity: 1; transform: none; }
  .nav.open .nav-links li:nth-child(1) { transition-delay: .05s; }
  .nav.open .nav-links li:nth-child(2) { transition-delay: .09s; }
  .nav.open .nav-links li:nth-child(3) { transition-delay: .13s; }
  .nav.open .nav-links li:nth-child(4) { transition-delay: .17s; }
  .nav.open .nav-links li:nth-child(5) { transition-delay: .21s; }
  .nav.open .nav-links li:nth-child(6) { transition-delay: .25s; }
  .nav.open .nav-links li:nth-child(7) { transition-delay: .29s; }
  .nav.open .nav-links li:nth-child(8) { transition-delay: .33s; }
  .nav.open .nav-links li:nth-child(n+9) { transition-delay: .37s; }
  .nav.open .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav.open .burger span:nth-child(2) { opacity: 0; }
  .nav.open .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  .burger { display: flex; }
  .nav-cta { display: none; }
  .split, .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }

  /* =====================================================================
     MOBIL-KOMPOSITION ═══ GESPERRT ═══ (01.09.2026, Tims Mobil-Audit)
     Befund auf vier ausgelieferten Vorschauen: Querformat-Bilder wurden auf
     Hochkant gezogen, das Motiv lag GENAU unter dem zentrierten Text (nur
     noch dunkle Tapete), der 58px-Kreis-Pfeil stand mitten auf den Menschen,
     kein Anruf-Knopf im ersten Screen, naechste Ueberschrift ragte
     angeschnitten ins Bild. Ergebnis: "sieht billig aus, deshalb kauft
     keiner". Deshalb hat das Handy ab jetzt eine EIGENE Komposition, die
     nichts am Desktop aendert (alles in diesem Media-Block). Skizze und
     Regeln der aktuellen Fassung (V5, 10.09.2026: Bild = ganze Buehne,
     Text auf dem Verlauf) stehen direkt beim .hero-Block weiter unten.
       ...
       [ Anrufen | WhatsApp ]  .mobile-bar, fest unten, ab dem 2. Screen

     Messbar gemacht: Hero-Hoehe = Viewport, Bild deckt die Buehne, Text
     startet in der unteren Haelfte, Nav <= 76px, CTA im ersten Screen.
     Projekt-CSS darf Farben/Schrift/Abstaende feinjustieren, aber NIE
     position/height/display dieser Regeln umdefinieren.
     ===================================================================== */
  :root { --section: clamp(3.75rem, 12vw, 5rem); }
  .nav-inner { padding-block: 10px; gap: 12px; }
  .nav-logo img { height: 36px; }
  h2 { font-size: clamp(1.7rem, 7.4vw, 2.3rem); }
  .section-head { margin-bottom: clamp(1.5rem, 6vw, 2.25rem); }

  /* V5 (10.09.2026, Tim, Vorschau FunFair): "Das Bild muss mobil ueber das
     GANZE Ding laufen, der schwarze Abschnitt sieht abgehakt aus, die Schrift
     muss hoeher." Die geteilte Buehne (Bild oben / Text auf schwarzem Band,
     V1-V4 vom 01./02.09.) ist damit Geschichte. Neue Komposition:

       +--------------+
       | Navigation   |  ~65px, deckend
       +--------------+
       |              |
       |  BILD        |  deckt den KOMPLETTEN Hero (position:absolute, cover),
       |  (Motiv oben)|  Motiv laut --hero-focus im oberen Viertel, ab ~16 %
       |  ~ Verlauf ~ |  loest ein Verlauf das Bild nach unten in --bg auf
       | Pille        |  Text beginnt bei ~32 % der Bildschirmhoehe, AUF dem
       | H1 (2-3 Z.)  |  Verlauf (dort ist das Bild schon zur Haelfte gedeckt)
       | Untertext    |
       |   (Pfeil)    |  klein, mittig in der Restluft
       | [ Anrufen ]  |  .hero-cta, 52px, Daumenzone
       +--------------+  = exakt eine Bildschirmhoehe (svh)

     Schaerfe: Das Handy bekommt sein EIGENES Hochkant-Bild (hero-mobile.jpg,
     1080x1920, <picture><source media="(max-width:768px)">), damit nichts
     hochskaliert oder blind beschnitten wird. Fehlt es, wird das Querformat
     per cover beschnitten (Zuschnitt, kein Qualitaetsverlust; der Check
     meldet es als Hinweis). Gemessen von mobil-hero-komposition: Bild deckt
     die Buehne, Textstart in [24 %, 42 %] der Hoehe, Verlauf vorhanden,
     Hero = Viewport, Bild nie ueber nativ vergroessert. */
  .hero {
    min-height: calc(100vh - var(--nav-h));
    min-height: calc(100svh - var(--nav-h));
    flex-direction: column; align-items: stretch; justify-content: flex-end;
  }
  /* Bild: die ganze Buehne. object-position aus --hero-focus-m (Hochkant-
     Bild) bzw. --hero-focus (Querformat-Fallback), Standard 50% 22% =
     Motiv im oberen Viertel, unten bleibt Raum fuer den Text. */
  .hero-media {
    position: absolute; inset: 0; z-index: var(--z-media);
    width: 100%; height: 100%; overflow: hidden;
  }
  .hero-media img, .hero-media video { object-position: var(--hero-focus-m, var(--hero-focus, 50% 22%)); }
  /* Verlauf: oben bleibt das Motiv unberuehrt, ab 16 % loest sich das Bild
     in den Seitenhintergrund auf (hell UND dunkel, weil --bg). Bei 32 %
     (Textstart, Tim 10.09. zweite Runde: "immer noch zu tief") ist der
     Untergrund zu 60 % gedeckt, bei 50 % zu 86 %: Text bleibt lesbar, das
     Bild bleibt trotzdem bis ganz unten sichtbar (kein "abgehacktes" Band). */
  .hero-media::after {
    content: ""; position: absolute; inset: 0; z-index: var(--z-overlay); pointer-events: none;
    background: linear-gradient(to bottom,
      color-mix(in srgb, var(--bg) 0%, transparent) 0%,
      color-mix(in srgb, var(--bg) 0%, transparent) 16%,
      color-mix(in srgb, var(--bg) 60%, transparent) 32%,
      color-mix(in srgb, var(--bg) 86%, transparent) 50%,
      color-mix(in srgb, var(--bg) 96%, transparent) 70%,
      var(--bg) 100%);
  }
  /* Desktop-Vignetten sind fuer die Desktop-Textlage gebaut; mobil macht
     der Verlauf oben die Arbeit. */
  .hero-veil, .hero-overlay { display: none; }
  /* Text: liegt AUF dem Verlauf, beginnt bei ~32 % der Bildschirmhoehe
     (min-height 68svh vom unteren Rand aus gerechnet, flach 72svh). Darunter Pfeil
     (mittig in der Restluft) und als Letztes der Knopf. */
  .hero .hero-content {
    position: relative; z-index: var(--z-content);
    margin-top: 0; flex: 0 0 auto; min-height: 68svh;
    display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
    padding-block: 0 clamp(.7rem, 2svh, 1.1rem);
  }
  /* Flache Handys (iPhone SE 667px, Android 740px): Text etwas hoeher, damit
     Pille, H1, zwei Zeilen Untertext, Pfeil und Knopf ohne Wachsen passen. */
  @media (max-height: 760px) { .hero .hero-content { min-height: 72svh; } .hero-content p.lead { margin-bottom: 10px; } }
  .hero-content p.lead { margin-bottom: 14px; }
  /* Ohne Bild (Farbflaechen-Hero): Restluft oben UND unten teilen. */
  .hero:not(:has(.hero-media)) .hero-content { min-height: 0; flex: 1 1 auto; }
  .hero:not(:has(.hero-media)) .hero-content > :first-child { margin-top: auto; }
  .hero .hero-content h1 { font-size: clamp(2.05rem, 9vw, 2.8rem); max-width: 14ch; }
  .hero-content p.lead { font-size: clamp(1rem, 4.1vw, 1.1rem); margin-top: 12px; max-width: 36ch; }
  /* Text auf dem Verlauf: Untertext nicht in --muted (zu wenig Kontrast auf
     Bild), dazu ein hauchduenner Schatten in Hintergrundfarbe als Reserve. */
  .hero:has(.hero-media) .hero-content p.lead { color: color-mix(in srgb, var(--text) 90%, var(--bg)); }
  .hero:has(.hero-media) .hero-content h1,
  .hero:has(.hero-media) .hero-content p.lead,
  .hero:has(.hero-media) .hero-content .eyebrow { text-shadow: 0 1px 2px color-mix(in srgb, var(--bg) 55%, transparent); }
  /* Scroll-Hinweis (Textvariante) und Vertrauenszeile: auf dem Handy weg. */
  .scroll-hint, .hero .trust { display: none; }
  /* Pfeil MITTIG in der Luecke zwischen Untertext und Knopf (auto-Margins
     oben UND unten), der Knopf ist das Letzte im Screen (V3/V4 02.09.).
     Gemessen: Luft oben == Luft unten (mobil-hero-komposition). */
  .scroll-down { width: 44px; height: 44px; margin-top: auto; margin-bottom: auto; order: 98; min-height: 44px; }
  .scroll-down svg { width: 18px; height: 18px; }
  /* Kachel-Links bleiben einzeilig, Pfeil klein (Befund HHS: "Mehr / erfahren"
     zweizeilig neben einem riesigen Pfeil). */
  .tile-link { white-space: nowrap; gap: 8px; }
  .tile-link svg { width: 20px; height: 20px; flex: 0 0 auto; }
  /* Pille bleibt IMMER einzeilig (gelernte Regel 31.08.): lieber gekuerzt,
     und mit Luft zur H1 (E2E-Befund 02.09.: Pille klebte an der Headline). */
  .hero .eyebrow, .hero .pill, .hero .badge { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 16px; }
  /* Der eine Knopf im ersten Screen: das Letzte im Screen, unter dem Pfeil. */
  .hero-cta {
    display: inline-flex; margin-top: 0; min-height: 52px; padding-inline: 28px;
    width: min(100%, 340px); font-size: 1.02rem; order: 99;
  }
  /* Ohne Pfeil im Markup nimmt der Knopf die Restluft selbst. */
  .hero-content:not(:has(.scroll-down)) .hero-cta { margin-top: auto; }
  /* Button-Paare im Hero gibt es mobil nicht: der eine .hero-cta reicht. */
  .hero .hero-actions { display: none; }

  /* Kontaktleiste unten (Daumenzone). WhatsApp-Float wird von ihr ersetzt. */
  .mobile-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-float);
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 10px;
    padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--bg) 90%, transparent);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
    transform: translateY(110%); transition: transform .35s var(--ease);
  }
  .mobile-bar.on { transform: none; }
  .mobile-bar .btn { min-height: 50px; padding-inline: 14px; width: 100%; white-space: nowrap; }
  body.bar-on { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
  .wa-float { display: none; }
}
@media (max-width: 480px) {
  .grid-4, .footer-grid { grid-template-columns: 1fr; }
  .hero-actions .btn { width: 100%; }
}

/* ---------- INHALTS-BAUSTEINE (Session 2 der Inhalts-Ernte, 10.09.2026) ----------
   Markup kommt fertig aus tools/gen-inhalte-bloecke.mjs (_projekt/bloecke/*.html):
   Objekt-Karten, Zeiten-Tabelle, Speisekarte/Preisliste, Termine, Personen, Siegel.
   Nur Tokens der Schablone, kein eigener Look. Klaus setzt die Bloecke ein, schreibt sie
   nicht neu. Gesperrt wie der Rest des Fundaments. */
.tw-inhalt .tile-content { color: #fff; }
.tw-inhalt .tile-content h3 { margin: 0 0 8px; font-size: 1.15rem; line-height: 1.25; }
.tw-fakten { margin: 0 0 14px; font-weight: 700; font-size: .95rem; letter-spacing: .01em; opacity: .92; }
.tw-inhalt .card .tw-fakten { color: var(--brand); }
.tw-mehr { text-align: center; margin: clamp(1.6rem, 4vw, 2.6rem) 0 0; }

.tw-tabelle { width: min(100%, 560px); margin: 0 auto; border-collapse: collapse; font-size: 1.02rem; }
.tw-tabelle th, .tw-tabelle td { padding: 14px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.tw-tabelle th { font-weight: 700; white-space: nowrap; width: 42%; }
.tw-tabelle td { color: var(--muted); }
.tw-tabelle tr:last-child th, .tw-tabelle tr:last-child td { border-bottom: 0; }

.tw-karte { display: grid; gap: clamp(1.6rem, 4vw, 2.8rem); grid-template-columns: repeat(2, 1fr); max-width: 980px; margin: 0 auto; }
.tw-karte-gruppe h3 { margin: 0 0 6px; font-size: 1.1rem; color: var(--brand); text-transform: uppercase; letter-spacing: .06em; }
.tw-pos { display: flex; align-items: baseline; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.tw-pos-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.tw-pos-name { font-weight: 700; }
.tw-pos-text small { color: var(--muted); font-size: .9rem; margin-top: 2px; }
.tw-pos-preis { flex: 0 0 auto; font-weight: 800; color: var(--brand); white-space: nowrap; font-variant-numeric: tabular-nums; }
.tw-pos-preis small { font-weight: 500; color: var(--muted); }

.tw-termine { display: grid; gap: 12px; max-width: 760px; margin: 0 auto; }
.tw-termin { display: grid; grid-template-columns: 84px 1fr; gap: 18px; align-items: center; padding: 14px 18px;
             background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
             transition: transform .25s var(--ease), border-color .25s; }
.tw-termin:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--brand) 55%, var(--line)); }
.tw-termin-datum { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
                   padding: 10px 6px; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
.tw-termin-datum b { font-size: 1.15rem; line-height: 1.1; font-variant-numeric: tabular-nums; }
.tw-termin-datum small { font-size: .78rem; margin-top: 2px; }
.tw-termin-text { display: flex; flex-direction: column; min-width: 0; text-align: left; }
.tw-termin-text strong { font-size: 1.02rem; }
.tw-termin-text small { color: var(--muted); font-size: .9rem; }

.tw-person img { width: 148px; height: 148px; object-fit: cover; border-radius: 50%; border: 3px solid color-mix(in srgb, var(--brand) 40%, transparent); }
.tw-person-leer { width: 148px; height: 148px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 2rem;
                  background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
.tw-person h3 { margin: 6px 0 0; }
.tw-person p { margin: 0; }

.tw-siegel { display: flex; flex-wrap: wrap; gap: 28px 40px; justify-content: center; align-items: center; }
.tw-siegel img { height: 72px; width: auto; max-width: 180px; object-fit: contain; filter: grayscale(1); opacity: .8; transition: filter .3s, opacity .3s; }
.tw-siegel img:hover { filter: none; opacity: 1; }

@media (max-width: 760px) {
  .tw-karte { grid-template-columns: 1fr; }
  .tw-termin { grid-template-columns: 72px 1fr; gap: 14px; padding: 12px 14px; }
  .tw-tabelle th { width: 46%; }
}

/* =====================================================================
   BEWEGUNGS-KATALOG + FEINSCHLIFF (11.09.2026, Tim: "weniger ist mehr,
   aber an jeder Ecke nachdenken") ═══ GESPERRT ═══ NICHT ENTFERNEN.
   Destilliert aus Emil Kowalski (animations.dev), LottieFiles Motion
   Design und Jakub Krehels better-*-Skills, gefiltert gegen dieses
   Fundament. Regeln dazu: references/bewegung.md, references/feinschliff.md.
   Alles hier ist ZUSAETZLICH: kein Wert weiter oben wird veraendert.
   Bewegung jenseits der Pflichtwerte kommt NUR aus diesem Katalog
   (data-fx), nie aus eigenem Animations-JS oder Fremdbibliotheken.
   Gemessen: GELERNT [bewegung-sicher], GELERNT [bedienbar].
   ===================================================================== */
:root {
  --ease-ui: cubic-bezier(.23, 1, .32, 1);      /* starkes Ease-out fuer Reaktionen (100-300ms) */
  --ease-move: cubic-bezier(.77, 0, .175, 1);   /* starkes Ease-in-out fuer Bewegung auf der Flaeche */
  --fx-stagger: 70ms;                           /* Staffelung je Kind (Persoenlichkeit: 50-70ms) */
}

/* ---- HOVER NUR MIT MAUS. Touch feuert :hover beim Tippen und laesst den
   Zustand kleben (Emil, Krehel). Farbwechsel duerfen bleiben, Bewegung nicht. */
@media (hover: none) {
  .btn:hover, .card:hover, .wa-float:hover, .tw-termin:hover { transform: none; }
  .tile:hover .tile-bg { transform: scale(1.06); filter: saturate(.55) contrast(1.02); }
}

/* ---- stagger: jedes direkte Kind erscheint versetzt (main.js gibt .reveal + --i).
   Budget 500ms (LottieFiles): ab dem 8. Kind kein weiterer Versatz. !important,
   weil main.js den Versatz als Inline-Style setzt. */
[data-fx="stagger"] > .reveal { transition-delay: calc(var(--i, 0) * var(--fx-stagger)) !important; }
[data-fx="stagger"] > .reveal:nth-child(n+8) { transition-delay: calc(7 * var(--fx-stagger)) !important; }

/* ---- words: Ueberschrift Wort fuer Wort (main.js zerlegt in .fx-w).
   Die Ueberschrift selbst faded nicht, nur ihre Woerter. */
[data-fx="words"] .fx-w {
  display: inline-block; opacity: 0; transform: translateY(.4em);
  transition: opacity .6s var(--ease-ui), transform .6s var(--ease-ui);
  transition-delay: calc(var(--i, 0) * 40ms);
}
[data-fx="words"].fx-on .fx-w, [data-fx="words"].in .fx-w { opacity: 1; transform: none; }
[data-fx="words"].reveal { opacity: 1; transform: none; }

/* ---- mask: Bild wird von oben freigelegt statt von unten eingeblendet.
   Die Maske liegt auf den KINDERN (img/picture), nicht auf dem beobachteten
   Element: ein komplett weggeklipptes Element meldet dem IntersectionObserver
   nie "sichtbar" (gemessen 11.09.). */
[data-fx="mask"].reveal { opacity: 1; transform: none; }
[data-fx="mask"].reveal > * { clip-path: inset(0 0 100% 0); transition: clip-path .9s var(--ease-move); }
[data-fx="mask"].reveal.in > * { clip-path: inset(0 0 0 0); }

/* ---- zoom: scroll-getriebener Bild-Zoom 1.0 -> 1.06 (nur auf <img>/Flaechen in
   einem overflow:hidden-Container, NIE auf .tile-bg, das hat seinen Hover-Zoom).
   Ohne animation-timeline passiert schlicht nichts. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    [data-fx="zoom"] { animation: fxZoom linear both; animation-timeline: view(); animation-range: entry 0% exit 100%; will-change: transform; }
  }
}
@keyframes fxZoom { from { transform: scale(1); } to { transform: scale(1.06); } }

/* ---- parallax: das Hero-Bild bleibt beim Wegscrollen 32px zurueck. NUR Desktop,
   die Mobil-Komposition ist gesperrt. Leichte Skalierung, damit oben kein Spalt entsteht. */
@supports (animation-timeline: scroll()) {
  @media (min-width: 769px) and (prefers-reduced-motion: no-preference) {
    .hero-media[data-fx="parallax"] { animation: fxParallax linear both; animation-timeline: scroll(root); animation-range: 0 100vh; will-change: transform; }
  }
}
@keyframes fxParallax { from { transform: translateY(0) scale(1.08); } to { transform: translateY(32px) scale(1.08); } }

/* ---- float: EIN Badge schwebt +-6px in 4.5s (Ambient, LottieFiles: 5-15px, sinus). */
[data-fx="float"] { animation: fxFloat 4.5s ease-in-out infinite; }
@keyframes fxFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }

/* ---- pulse: sanfter Halo um den Anruf-Knopf, 2.6s, kein Layout. */
[data-fx="pulse"] { animation: fxPulse 2.6s ease-out infinite; }
@keyframes fxPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 45%, transparent); }
  70%  { box-shadow: 0 0 0 14px color-mix(in srgb, var(--brand) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 0%, transparent); }
}

/* ---- Reduced Motion: jeder Startzustand des Katalogs endet sichtbar.
   (Die globale Abschaltung oben nimmt Animationen/Transitions, das hier
   nimmt die Startzustaende.) */
@media (prefers-reduced-motion: reduce) {
  [data-fx="words"] .fx-w { opacity: 1; transform: none; }
  [data-fx="mask"].reveal > * { clip-path: none; }
  [data-fx="zoom"], .hero-media[data-fx="parallax"], [data-fx="float"], [data-fx="pulse"] { animation: none; transform: none; box-shadow: none; }
}
.no-js [data-fx="words"] .fx-w { opacity: 1; transform: none; }
.no-js [data-fx="mask"].reveal > * { clip-path: none; }

/* ---- Theme-Wechsel schnappt statt zu verschmieren (Krehel): main.js setzt
   .theme-snap fuer einen Frame auf <html>. */
.theme-snap *, .theme-snap *::before, .theme-snap *::after { transition: none !important; }

/* ---- FEINSCHLIFF Typografie (Krehel): kein einsames Wort in der letzten Zeile,
   Tabellenziffern wo Zahlen stehen, Bilder mit Haarlinie, Skip-Link. */
p, li, .lead, .section-head p, .card p, .tile-content p { text-wrap: pretty; }
time, .preis, .stat .num, [data-count], .tw-pos-preis, .tw-termin-datum, .tw-fakten { font-variant-numeric: tabular-nums; }
.card img, .tw-person img, .galerie img, figure img, .split img {
  outline: 1px solid color-mix(in srgb, var(--text) 10%, transparent); outline-offset: -1px;
}
.skip-link {
  position: absolute; left: 12px; top: -100px; z-index: var(--z-modal);
  padding: 12px 18px; border-radius: var(--radius-sm); background: var(--brand); color: var(--brand-ink);
  font-weight: 700; transition: top .15s var(--ease-ui);
}
.skip-link:focus-visible { top: 12px; outline-offset: 2px; }
