/* ==========================================================================
   CollabBase — Design-System
   Farben und Schriften folgen dem CI-Dokument (Cyan #5ce1e6 auf #020202).
   ========================================================================== */

@font-face {
  font-family: "Garet";
  src: url("assets/fonts/Garet-Book.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Garet";
  src: url("assets/fonts/Garet-Heavy.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Display";
  src: url("assets/fonts/Poppins-900.woff2") format("woff2");
  font-weight: 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Display";
  src: url("assets/fonts/Poppins-800.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}

:root {
  /* Farbe */
  --bg:        #020202;
  --bg-lift:   #0a0b0d;
  --bg-panel:  #101216;
  --line:      #1e2126;
  --line-soft: #16181c;
  /* Trennlinien duerfen leise sein, Bedienelemente nicht: Rahmen von Knoepfen
     und Eingabefeldern brauchen 3:1 zum Grund (WCAG 1.4.11). #1e2126 kommt auf
     rund 1,3:1 und ist damit nur Dekoration — dafuer gibt es diesen Ton. */
  --line-ui:   #5a6069;
  --line-ui-hover: #8b939d;
  --fg:        #ffffff;
  --fg-muted:  #9aa0a8;
  --fg-dim:    #7a8189;
  --accent:    #5ce1e6;
  --accent-ink:#01221f;
  --accent-glow: rgba(92, 225, 230, .22);

  /* Typografie */
  --font-display: "Display", "Helvetica Neue", Arial, sans-serif;
  --font-text: "Garet", ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;

  --step--1: clamp(.82rem, .80rem + .10vw, .90rem);
  --step-0:  clamp(1rem, .97rem + .16vw, 1.12rem);
  --step-1:  clamp(1.18rem, 1.10rem + .40vw, 1.45rem);
  --step-2:  clamp(1.45rem, 1.25rem + .95vw, 2.10rem);
  --step-3:  clamp(1.75rem, 1.32rem + 2.15vw, 3.30rem);
  --step-4:  clamp(2.15rem, 1.35rem + 4.20vw, 5.20rem);

  /* Raum */
  --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;
  --sp-4: 1rem;    --sp-5: 1.5rem;  --sp-6: 2rem;
  --sp-7: 3rem;    --sp-8: 4.5rem;  --sp-9: 7rem;
  --sp-10: 10rem;

  /* Form */
  --r-sm: 6px;
  --r-md: 12px;
  --r-lg: 20px;

  /* Bewegung */
  --ease: cubic-bezier(.22, .68, .30, 1);
  --ease-in: cubic-bezier(.65, 0, .85, .30);
  --t-fast: 170ms;
  --t-mid:  340ms;
  --t-slow: 620ms;

  --wrap: 1220px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
}

/* -------------------------------------------------------------- Grundlage */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Der Header liegt fest ueber dem Inhalt. Ohne diesen Abstand landen
     Ankersprunge (#camp, #team ...) unter der Leiste. */
  scroll-padding-top: clamp(84px, 12vh, 108px);
  /* Sagt dem Browser, dass die Seite dunkel ist — sonst bleiben Scrollleisten,
     Auswahlfelder und Formularelemente im hellen Systemlook. */
  color-scheme: dark;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg { display: block; max-width: 100%; }
img { height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }

/* Umbruchqualitaet: Ueberschriften auf moeglichst gleich lange Zeilen
   verteilen, Fliesstext ohne einzelnes Wort in der Schlusszeile. */
h1, h2, h3 { text-wrap: balance; }
p, li { text-wrap: pretty; }

/* Bedienflaechen mindestens 44px hoch. Die Zeilenhoehe allein reicht dafuer
   nicht — die Flaeche waechst ueber die Box, nicht ueber die Schriftgroesse. */
.nav a, .ftr__links a, .brand {
  display: inline-flex; align-items: center; min-height: 44px;
}

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: #0f8f96; color: #fff;
  padding: var(--sp-3) var(--sp-5); font-weight: 800;
}
.skip:focus { left: var(--sp-4); top: var(--sp-4); }

.wrap { width: min(var(--wrap), 100%); margin-inline: auto; padding-inline: var(--gutter); }

.eyebrow {
  display: flex; align-items: center; gap: var(--sp-3);
  font-weight: 800; font-size: var(--step--1);
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: ""; width: 26px; height: 2px; background: currentColor; flex: none;
}

.display {
  font-family: var(--font-display); font-weight: 900;
  text-transform: uppercase;
  line-height: .93; letter-spacing: -.02em;
  text-wrap: balance;
}
.display .hl { color: var(--accent); }
/* Auf der hellen Aufnahme erreicht Cyan in dieser Groesse keine 3:1.
   Der Markenakzent sitzt im Strich der Eyebrow und in den Buttons. */
.hero__title .hl { color: #fff; }
.hero__inner .eyebrow::before { background: var(--accent); }

/* -------------------------------------------------------------- Buttons */
.btn {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  min-height: 48px; padding: 0 var(--sp-5);
  border-radius: 999px;
  font-weight: 800; font-size: var(--step--1);
  letter-spacing: .10em; text-transform: uppercase;
  transition: transform var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              box-shadow var(--t-mid) var(--ease);
}
.btn svg { width: 15px; height: 15px; flex: none; }
/* Schrift auf den Markenflaechen ist weiss - so gewuenscht. Damit Weiss auf
   dem hellen Cyan ueberhaupt traegt, sitzt hinter dem Text ein leichter
   Farbverlauf ins Dunklere und ein feiner Schatten. */
/* Weisse Schrift auf der Markenflaeche - so gewuenscht. Beide Enden des
   Verlaufs sind nachgemessen: 4,65:1 oben, 5,39:1 unten. Der erste Versuch
   mit hellerem Cyan kam oben nur auf 3,1:1 - dort waere die Schrift bei
   Sonnenlicht weggebrochen. Erkennbar dieselbe Farbe, eine Spur tiefer. */
.btn--primary {
  background: linear-gradient(160deg, #0d8188 0%, #0a767c 100%);
  color: #fff;
  text-shadow: 0 1px 2px rgba(1, 34, 31, .35);
  box-shadow: 0 10px 30px -14px var(--accent);
}
.btn--primary:hover { transform: translateY(-2px); box-shadow: 0 16px 40px -14px var(--accent); }
/* Steht auch auf dem bewegten Hintergrund: eigener Grund, damit der Rahmen
   nicht im hellen Bildinhalt verschwindet. */
.btn--ghost {
  color: var(--fg);
  background: rgba(2, 2, 2, .38);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .45);
}
.btn--ghost:hover {
  background: rgba(2, 2, 2, .58);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .82);
}

/* -------------------------------------------------------------- Header */
.hdr {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  padding-block: var(--sp-4);
  transition: background-color var(--t-mid) var(--ease),
              border-color var(--t-mid) var(--ease);
  border-bottom: 1px solid transparent;
}
.hdr[data-stuck="true"] {
  background: rgba(2, 2, 2, .82);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom-color: var(--line-soft);
}
.hdr__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5); }
.brand { display: flex; align-items: center; flex: none; }
.brand img { width: clamp(150px, 15vw, 196px); height: auto; }
.nav { display: flex; gap: var(--sp-6); font-size: var(--step--1); }
.nav a {
  color: #fff; transition: opacity var(--t-fast);
  opacity: .82;
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.nav a:hover { opacity: 1; }
/* Sobald der Header seinen eigenen Grund hat, ist der Schatten unnoetig. */
.hdr[data-stuck="true"] .nav a { text-shadow: none; opacity: .7; }
.hdr[data-stuck="true"] .nav a:hover { opacity: 1; }

/* -------------------------------------------------- Menue auf dem Handy */
/* Bis 860px traten Navigation und Aufruf frueher ersatzlos ab — auf einem
   Telefon blieb dann nur das Logo. Jetzt uebernimmt ein ausklappbares Menue. */
.burger { display: none; }
.nav__grund { display: none; }

@media (min-width: 861px) {
  /* Muss .nav a schlagen (0,1,1) — sonst steht der Aufruf doppelt im Header. */
  .nav a.nav__cta { display: none; }
}

@media (max-width: 860px) {
  .hdr__cta { display: none; }

  .burger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 46px; height: 46px; flex: none;
    border-radius: var(--r-sm);
    color: var(--fg);
  }
  .burger__box {
    display: grid; gap: 5px; width: 22px;
  }
  .burger__strich {
    display: block; height: 2px; width: 100%;
    background: currentColor; border-radius: 2px;
    transition: transform var(--t-fast) var(--ease),
                opacity var(--t-fast) var(--ease);
  }
  .burger[aria-expanded="true"] .burger__strich:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .burger[aria-expanded="true"] .burger__strich:nth-child(2) { opacity: 0; }
  .burger[aria-expanded="true"] .burger__strich:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* Das Feld liegt unter dem Header und faehrt von oben herein. */
  .nav {
    position: fixed; inset: 0 0 auto 0;
    display: grid; gap: var(--sp-2);
    padding: calc(72px + var(--sp-5)) var(--gutter) var(--sp-6);
    background: rgba(4, 4, 5, .97);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--line);
    transform: translateY(-102%);
    transition: transform var(--t-mid) var(--ease-in),
                visibility 0s linear var(--t-mid);
    visibility: hidden;
    font-size: var(--step-1);
  }
  /* Logo und Knopf bleiben ueber dem herabfahrenden Feld bedienbar. */
  .brand, .burger { position: relative; z-index: 2; }
  .nav[data-offen="true"] {
    transform: none;
    visibility: visible;
    transition: transform var(--t-mid) var(--ease), visibility 0s;
  }
  .nav a {
    opacity: 1; text-shadow: none;
    padding-block: var(--sp-2);
    border-bottom: 1px solid var(--line-soft);
  }
  .nav a:last-of-type { border-bottom: 0; }
  .hdr[data-stuck="true"] .nav a { opacity: 1; }

  .nav a.nav__cta {
    display: flex; justify-content: center;
    margin-top: var(--sp-4);
    font-size: var(--step--1);
    border-bottom: 0;
  }

  /* Abdunklung hinter dem Feld: schliesst das Menue beim Antippen. */
  .nav__grund {
    display: block;
    position: fixed; inset: 0; z-index: 50;
    background: rgba(2, 2, 2, .62);
    opacity: 0; transition: opacity var(--t-mid) var(--ease);
  }
  .nav__grund[data-offen="true"] { opacity: 1; }
}

/* Diese beiden Zeilen sind keine Feinheit, sondern die Notbremse: das
   display:block oben schlaegt die Browservorgabe fuer [hidden]. Ohne sie liegt
   die Flaeche unsichtbar, aber anklickbar ueber der ganzen Seite, und auf dem
   Telefon ist nichts mehr zu bedienen - kein Knopf, kein Link, kein Formular.
   Die zweite Zeile faengt die 340 ms ab, in denen das Menue schon zu ist, das
   Attribut aber noch nicht wieder gesetzt wurde. Bewusst an data-offen="false"
   statt an :not([data-offen="true"]): beim Oeffnen setzt das Skript den Wert
   erst im naechsten Frame, und in einem verborgenen Tab kommt der nie. */
.nav__grund[hidden] { display: none; }
.nav__grund[data-offen="false"] { pointer-events: none; }

/* -------------------------------------------------------------- Hero */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: end;
  padding-block: clamp(5rem, 11vh, 7.5rem) clamp(5rem, 15vh, 10rem);
  overflow: hidden;
  isolation: isolate;
}

/* Drohnenaufnahme als Hintergrund. Das Standbild liegt fest darunter, damit
   auch ohne Video (Datensparmodus, reduzierte Bewegung) ein Bild steht. */
.hero__bg {
  position: absolute; inset: 0; z-index: -1;
  background: url("assets/img/hero-poster.webp") center 58% / cover no-repeat, var(--bg);
}
.hero__video {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 58%;
  opacity: 0;
  transition: opacity 900ms var(--ease);
}
.hero__video.is-ready { opacity: 1; }
/* Kurz vor und nach dem Loop-Punkt abdunkeln (siehe script.js). */
.hero__video.is-turning { opacity: .34; transition-duration: 550ms; }

/* Die Aufnahme laeuft in voller Helligkeit. Was den Text traegt, ist allein
   der Verlauf darunter (.hero__scrim) — so bleibt das Motiv unangetastet und
   die Schrift steht trotzdem sicher. */
.hero__bg { filter: none; }

/* Nur ein flacher Verlauf von unten: er traegt Fliesstext und Buttons und
   laeuft ueber die volle Breite, sitzt also nicht sichtbar hinter der Schrift. */
.hero__scrim {
  position: absolute; inset: 0;
  background:
    /* oben: traegt die Navigation */
    linear-gradient(to bottom, rgba(2,2,2,.72) 0%, rgba(2,2,2,.30) 11%, transparent 20%),
    /* unten: traegt Ueberschrift, Fliesstext und Buttons */
    linear-gradient(to top, rgba(2,2,2,.90) 0%, rgba(2,2,2,.86) 30%,
                            rgba(2,2,2,.68) 55%, rgba(2,2,2,.48) 78%,
                            rgba(2,2,2,.26) 100%);
}
@media (max-width: 860px) {
  .hero__scrim {
    background:
      linear-gradient(to bottom, rgba(2,2,2,.72) 0%, rgba(2,2,2,.30) 12%, transparent 22%),
      linear-gradient(to top, rgba(2,2,2,.93) 0%, rgba(2,2,2,.88) 26%,
                              rgba(2,2,2,.68) 50%, rgba(2,2,2,.52) 76%,
                              rgba(2,2,2,.30) 100%);
  }
}

/* .hero__inner traegt auch .wrap. Ein max-width hier wuerde den ganzen Block
   mittig setzen (margin-inline:auto) — die Textbreite wird deshalb an den
   Elementen selbst begrenzt, damit der Satz an derselben Kante wie alle
   anderen Sektionen beginnt. */
.hero__inner { position: relative; }
.hero__inner .eyebrow {
  /* Auf bewegtem Bild traegt Cyan in dieser kleinen Groesse nicht genug
     Kontrast — die Zeile wird weiss, der Akzent bleibt im Strich davor. */
  width: fit-content; color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.7), 0 2px 10px rgba(0,0,0,.5);
}
.hero__title {
  font-size: var(--step-4);
  margin-bottom: var(--sp-5);
  /* 16ch: breit genug fuer "zusammenkommen" am Stueck, schmal genug, dass die
     Zeilen im geschuetzten Bereich des Textschattens bleiben. */
  max-width: 16ch;
  /* Keine automatische Trennung — sie zerlegt "zusammenkommen" mitten im
     Wortstamm. Die einzig sinnvolle Trennstelle steht als &shy; im HTML. */
  hyphens: manual;
  overflow-wrap: break-word;
  text-shadow: 0 1px 2px rgba(0,0,0,.62), 0 3px 16px rgba(0,0,0,.42);
}
.hero__lead {
  color: #e6e9ec;
  font-size: var(--step-1);
  max-width: 46ch;
  margin-bottom: var(--sp-6);
  text-shadow: 0 1px 2px rgba(0,0,0,.66), 0 2px 12px rgba(0,0,0,.44);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--sp-4); }

/* Auf dem Handy stand die Eyebrow ohne jeden Abstand direkt an der
   Überschrift, und die Schrift war für die schmale Spalte zu groß - der
   Hero wirkte dadurch gedrängt. Beides hier zurückgenommen. */
@media (max-width: 620px) {
  .hero__inner .eyebrow { margin-bottom: var(--sp-5); }
  .hero__title {
    font-size: clamp(1.75rem, 8.2vw, 2.4rem);
    /* Volle Breite statt 16ch: der schmalere Satz zwang "zusammenkommen"
       in die Trennung und ergab vier Zeilen. So sind es drei, ungetrennt.
       pretty statt balance - balance gleicht die Zeilen aus und greift
       dafür ebenfalls zum Trennstrich. */
    max-width: 100%;
    text-wrap: pretty;
    margin-bottom: var(--sp-5);
  }
  .hero__lead { font-size: 1.06rem; }
}


/* -------------------------------------------------- Idee mit Bewegtbild */
/* Das Video liegt hinter dem Inhalt. Der Text steht darauf, deshalb wird die
   Aufnahme kräftig heruntergedimmt - siehe .idee__video und .idee__scrim. */
.idee-sek {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.idee__bg { position: absolute; inset: 0; z-index: -1; background: var(--bg); }
.idee__video {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 30%;
  /* Die Aufnahme ist bereits schwarzweiß. Helligkeit und Schleier darunter
     sind ausgemessen, nicht geschätzt: an der hellsten Stelle hinter Text
     bleiben 5,7:1 für den grauen Fließtext - über den geforderten 4,5:1,
     mit Reserve. Heller ginge, dann kippt der Text unter die Grenze. */
  filter: brightness(.60) contrast(1.15);
}
/* Zusätzliche Ebene: fängt die hellen Stellen ab (Gesichter, Konfetti), die
   der Filter allein stehen lässt, und verdichtet zu den Rändern hin. */
.idee__scrim {
  position: absolute; inset: 0;
  background:
    /* Unten läuft der Schleier bis auf volle Deckung aus - so geht das
       Bewegtbild in den Grund der folgenden Sektion über, statt an einer
       Kante abzubrechen. */
    linear-gradient(to bottom, rgba(2,2,2,.70) 0%, rgba(2,2,2,.42) 26%,
                               rgba(2,2,2,.42) 62%, rgba(2,2,2,.80) 88%,
                               rgba(5,5,6,1) 100%),
    radial-gradient(ellipse 78% 62% at 50% 46%, rgba(2,2,2,.16), rgba(2,2,2,.52));
}
/* Auf dem Bewegtbild braucht der Fließtext mehr Helligkeit als auf dem
   ruhigen Seitengrund. */
.idee-sek .idea__body,
.idee-sek .sec-head__note { color: #c8ced6; }
.idee-sek .idea__claim,
.idee-sek .idea__body,
.idee-sek .sec-head h2,
.idee-sek .eyebrow { text-shadow: 0 1px 3px rgba(2, 2, 2, .75); }

/* -------------------------------------------------------------- Sections */
.section { padding-block: clamp(4.5rem, 11vh, 8rem); }
.section--edge { border-top: 1px solid var(--line-soft); }

/* Einheitlicher Sektionskopf: Eyebrow, Ueberschrift, optionaler Beisatz.
   Alle Sektionen nutzen dieselben Abstaende — keine Sonderwerte im HTML. */
.sec-head { max-width: 46ch; margin-bottom: var(--sp-8); display: grid; gap: var(--sp-4); }
/* Auf dem Handy summierten sich 72px nach jedem Kopf ueber acht Sektionen
   zu fast einer ganzen Bildschirmhoehe reinem Leerraum. */
@media (max-width: 700px) {
  .sec-head { margin-bottom: var(--sp-6); }
  .section { padding-block: clamp(3rem, 8vh, 4.5rem); }
}
/* Eigenes Zeilenmass fuer die Displayschrift: 34ch sind ein Fliesstext-Wert
   und zwingen 53px-Versalien in vier bis fuenf kurze Zeilen. */
.sec-head h2 { font-size: var(--step-3); max-width: 17ch; }
.sec-head__note { color: var(--fg-muted); max-width: 46ch; }

/* Idee: zwei ungleiche Spalten, Text bündig unten */
.idea { display: grid; gap: var(--sp-6); }
@media (min-width: 900px) {
  .idea { grid-template-columns: 1fr 1fr; gap: clamp(2rem, 6vw, 5rem); align-items: start; }
}
.idea__claim { font-size: var(--step-2); line-height: 1.28; text-wrap: pretty; }
.idea__claim b { color: var(--accent); font-weight: 800; }
.idea__body { color: var(--fg-muted); display: grid; gap: var(--sp-4); }

/* -------------------------------------------------------------- Camp */
/* Oben bewusst ohne Trennlinie: der Schleier der Idee-Sektion läuft genau in
   diesen Farbwert aus, der Wechsel bleibt dadurch unmerklich. */
.camp {
  border-bottom: 1px solid var(--line-soft);
  background: linear-gradient(to bottom, #050506 0%, #050506 70%, #030304 100%);
}
.camp__layout { display: grid; gap: var(--sp-6); }
@media (min-width: 1040px) {
  .camp__layout { grid-template-columns: minmax(0, 1.55fr) minmax(300px, .85fr); gap: var(--sp-7); }
}

/* Isometrische Szene - steht frei, ohne Rahmen und ohne eigene Flaeche.
   overflow bleibt sichtbar, damit die Beschriftung ueber Gebaeuden am oberen
   Rand nicht abgeschnitten wird. */
.scene {
  position: relative;
  overflow: visible;
  aspect-ratio: 351.3 / 220.7;
  perspective: 1300px;
}

/* Auf dem Handy wird die Szene NICHT vergroessert. Ein Versuch damit
   (640px breit, seitlich wischbar) machte die Gebaeude zwar antippbar,
   zerstoerte aber den ersten Eindruck: Man sah nur einen Ausschnitt und
   hielt das Camp fuer abgeschnitten. Die Uebersicht ist wichtiger - zum
   Anwaehlen dient die Bereichsleiste darunter, die 44px hohe Ziele hat. */
.scene__wisch { display: none; }

@media (max-width: 860px) {
  /* Auf Touch gibt es kein Ueberfahren - die Blase erschiene nie. */
  .scene__label { display: none; }
}
.scene__tilt {
  position: absolute; inset: 0;
  transition: transform var(--t-slow) var(--ease);
}
/* Die eigene Ebene nur anlegen, solange der Zeiger auf der Szene steht —
   dauerhaft gesetzt haelt will-change sonst grundlos Grafikspeicher fest. */
.scene:hover .scene__tilt { will-change: transform; }
.scene svg { width: 100%; height: 100%; display: block; }

/* Jedes Gebaeude ist eine Schaltflaeche */
.obj {
  cursor: pointer;
  transition: transform var(--t-mid) var(--ease), filter var(--t-mid) var(--ease);
  transform-box: fill-box;
  transform-origin: center;
}
/* Angefahren wird ueber die ruhende Trefferebene erkannt, nicht ueber :hover.
   Die Gebaeude bestehen aus vielen Einzelformen mit Luecken dazwischen, und
   das Anheben zoege das Ziel unter dem Zeiger weg — :hover wechselte dabei im
   Takt der Bildwiederholung. Siehe .obj-treffer in script.js. */
.obj.is-an, .obj:focus-visible {
  transform: translateY(-7px);
  filter: brightness(1.32) drop-shadow(0 10px 14px rgba(0,0,0,.7));
}
/* Sobald die Trefferebene steht, ist sie allein zustaendig. Ohne JavaScript
   bleibt es beim alten Verhalten, dort tut die Zeigerlogik ohnehin nichts. */
.scene[data-treffer] .obj { pointer-events: none; }
.obj__ziel { cursor: pointer; }
.obj:focus { outline: none; }
.obj:focus-visible { filter: brightness(1.32) drop-shadow(0 0 6px var(--accent)); }
/* Ausgewaehlt: bleibt hervorgehoben, alles andere tritt zurueck */
.scene[data-aktiv] .obj { opacity: .45; }
.scene[data-aktiv] .obj.is-on { opacity: 1; transform: translateY(-7px); filter: brightness(1.32); }
.scene[data-aktiv] .ground { opacity: .7; }
.ground, .obj { transition: opacity var(--t-mid) var(--ease); }

/* Beschriftung, die dem Zeiger folgt */
.scene__label {
  position: absolute; left: 0; top: 0;
  transform: translate(-50%, -140%);
  padding: 5px 11px; border-radius: 999px;
  font-size: var(--step--1); font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase;
  color: #fff; background: #0f8f96;
  white-space: nowrap;
  opacity: 0; pointer-events: none;
  z-index: 3;
  transition: opacity var(--t-fast) var(--ease);
}
.scene__label.is-on { opacity: 1; }

.scene__hint {
  position: absolute; left: var(--sp-4); bottom: var(--sp-4);
  font-size: var(--step--1); color: var(--fg-dim);
  letter-spacing: .10em; text-transform: uppercase;
  pointer-events: none;
  transition: opacity var(--t-mid);
}
.scene[data-aktiv] .scene__hint { opacity: 0; }
/* Bei flacher Buehne laege der Hinweis mitten im Motiv — dort fuehrt die
   Bereichsleiste darunter. */
@media (max-width: 760px) { .scene__hint { display: none; } }
/* Nur Touch bekommt einen Hinweis - mit Maus erklaert sich das Anfahren von
   selbst, und ein Hinweis mitten im Motiv waere blosses Rauschen. */
.hint--tap { display: none; }
@media (hover: none) {
  .hint--tap { display: inline; }
}

/* Bereichsleiste — zweiter Weg neben dem Anwaehlen im Bild, vor allem
   fuer Touch, wo die Gebaeude kleine Ziele sind. */
.zonennav { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.zonennav button {
  min-height: 44px; padding: 0 var(--sp-5);
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line-ui);
  color: var(--fg-muted);
  font-size: var(--step--1); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
  transition: color var(--t-fast), box-shadow var(--t-fast);
}
.zonennav button:hover { color: var(--fg); box-shadow: inset 0 0 0 1px var(--line-ui-hover); }
.zonennav button[aria-pressed="true"] {
  color: #fff; background: #0f8f96; box-shadow: none;
}

/* Info-Karte mit Foto */
.zoneinfo {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--bg-panel), var(--bg-lift));
  padding: var(--sp-5);
  display: grid; align-content: start;
}
.zoneinfo__kicker {
  font-size: var(--step--1); font-weight: 800; color: var(--accent);
  letter-spacing: .22em; text-transform: uppercase; margin-bottom: var(--sp-3);
}
.zoneinfo h3 {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  font-size: var(--step-2); line-height: .98; letter-spacing: -.015em;
  margin-bottom: var(--sp-4);
}
.zoneinfo p { color: var(--fg-muted); }
.zoneinfo__tags { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-5); }
.zoneinfo__tags li {
  font-size: var(--step--1); font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase;
  color: #fff;
  padding: 5px 11px; border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgba(92, 225, 230, .45);
}

.camp__note {
  margin-top: var(--sp-5);
  color: var(--fg-dim); font-size: var(--step--1);
  max-width: 62ch;
}


/* -------------------------------------------------------------- Leistungen */
/* Fruehere Fassung: Kopf links klebend, daneben sieben Zeilen untereinander.
   Links blieb dadurch eine grosse leere Flaeche, rechts stand eine Textwand.
   Jetzt steht der Kopf oben und die Punkte verteilen sich in die Breite. */
.leistungen {
  display: grid; gap: var(--sp-5) clamp(1.5rem, 4vw, 3rem);
  counter-reset: l;
}
@media (min-width: 620px)  { .leistungen { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .leistungen { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.leistung {
  counter-increment: l;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}
.leistung::before {
  content: counter(l, decimal-leading-zero);
  display: block;
  font-family: var(--font-display); font-weight: 900;
  font-size: var(--step-2); line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1.1px var(--accent);
  paint-order: stroke fill;
  margin-bottom: var(--sp-4);
  opacity: .85;
}
@supports not (-webkit-text-stroke: 1px currentColor) {
  .leistung::before { color: var(--accent); opacity: .55; }
}
.leistung h3 {
  font-weight: 800; font-size: var(--step-1);
  margin-bottom: var(--sp-3); text-wrap: balance;
}
.leistung p { color: var(--fg-muted); }

/* -------------------------------------------------------------- Team */
.team { display: grid; gap: var(--sp-5); grid-template-columns: 1fr; }
/* Feste Stufen statt auto-fit: sonst bleibt bei vier Personen eine Einzelkarte uebrig.
   Schon auf dem Handy zweispaltig - vier Karten untereinander ergaben sonst
   fast drei Bildschirmhoehen nur fuer das Team. */
.team { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
@media (min-width: 560px)  { .team { gap: var(--sp-5); } }
@media (min-width: 1040px) { .team { grid-template-columns: repeat(4, 1fr); } }
.member {
  position: relative; overflow: hidden;
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: var(--bg-lift);
  /* Entspricht dem Zuschnitt der Portraits (720x960) — kein weiterer Beschnitt. */
  aspect-ratio: 3 / 4;
}
.member img {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(1) contrast(1.08);
  transition: transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
}
.member:hover img { transform: scale(1.035); filter: grayscale(.55) contrast(1.05); }
.member__cap {
  position: absolute; inset: auto 0 0 0; padding: var(--sp-5);
  background: linear-gradient(180deg, transparent, rgba(2,2,2,.88) 62%);
}
.member__name {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  font-size: var(--step-1); line-height: 1; letter-spacing: -.01em;
  margin-bottom: var(--sp-2);
}
.member__role {
  font-size: var(--step--1); font-weight: 800; color: var(--accent);
  letter-spacing: .12em; text-transform: uppercase;
}
/* In der zweispaltigen Ansicht auf dem Handy sind die Karten rund 163px
   breit - "Founder · Promotion" passt dort nicht in eine Zeile und lief
   ueber den Rand hinaus. Deshalb umbrechen statt abschneiden. */
@media (max-width: 620px) {
  .member__cap { padding: var(--sp-4); }
  .member__role { letter-spacing: .06em; line-height: 1.3; }
  .member__name { font-size: var(--step-0); }
}

/* -------------------------------------------------------------- Kontakt */
.contact {
  text-align: center;
  background: radial-gradient(ellipse 60% 70% at 50% 108%, var(--accent-glow), transparent 62%);
}
.contact .eyebrow { justify-content: center; }
/* Zentrierter Satz ueber vier Zeilen zwingt das Auge auf schmalem Schirm,
   jeden Zeilenanfang neu zu suchen - links steht er ruhiger. */
@media (max-width: 620px) {
  .contact { text-align: left; }
  .contact .eyebrow { justify-content: flex-start; }
  .contact .contact__lead, .contact__direkt { margin-inline: 0; }
}
.contact h2 { font-size: var(--step-3); margin-block: var(--sp-4) var(--sp-5); }
/* Gilt nur fuer den Einleitungssatz — die Absaetze im Formular haben eigene
   Regeln und duerfen davon nicht getroffen werden. */
.contact .contact__lead { max-width: 48ch; margin-inline: auto; }

/* -------------------------------------------------------------- Footer */
.ftr {
  border-top: 1px solid var(--line-soft);
  padding-block: var(--sp-6) var(--sp-5);
  color: var(--fg-dim); font-size: var(--step--1);
}
/* Zwei knappe Ebenen: oben drei Spalten - Marke, Kontakt, Aufruf -, unten eine
   schmale Zeile. Ein Footer soll abschliessen, nicht noch einmal auftragen.

   Die aeusseren Spalten teilen sich den Rest zu gleichen Teilen, damit der
   Kontaktblock tatsaechlich in der Mitte steht und nicht nur irgendwo
   dazwischen. Dass die Zwischenraeume dabei ungleich ausfallen, liegt an den
   Inhalten: die Marke ist breiter als der Knopf. Deshalb steht ihr Text unten
   auf einer knapperen Zeilenlaenge - sonst draengt sich links alles und rechts
   klafft eine Luecke. */
.ftr__oben {
  /* Hoehe des Logos. Sie ist die Bezugslinie fuer die oberste Zeile aller
     drei Spalten - Knopf und Aufruf werden weiter unten auf ihre Mitte
     gerueckt. */
  --ftr-kopf: 64px;

  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: var(--sp-5) clamp(1.5rem, 4vw, 3.5rem);
  padding-bottom: var(--sp-5);
}

.ftr__marke { display: grid; gap: var(--sp-3); justify-items: start; }
/* Ueber die Hoehe statt ueber die Breite bemasst: sie ist die Bezugslinie
   fuer die oberste Zeile der drei Spalten und soll eine glatte Zahl sein. */
.ftr__marke img { height: var(--ftr-kopf); width: auto; }
/* Knapper als die 44ch von frueher: sonst laeuft der Text bis an die
   Spaltenkante und der Kontaktblock in der Mitte rueckt ihm auf die Pelle. */
.ftr__marke p { max-width: 30ch; line-height: 1.55; }

/* Mittlere Spalte: die beiden Kontaktwege untereinander, das Profil zuerst.
   Die Adresse steht mittig unter dem Knopf - die Spalte ist so breit wie er,
   damit genuegt zentrieren. */
.ftr__kontakt {
  display: grid; justify-items: center;
  gap: var(--sp-3);
}

/* Der Verweis auf das Profil als beschrifteter Knopf statt als einzelnes
   Zeichen ohne Bezug. */
.ftr__ig {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  min-height: 44px; padding: 0 var(--sp-4);
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line-ui);
  color: var(--fg-muted); font-weight: 800;
  letter-spacing: .04em; white-space: nowrap;
  transition: color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
/* Auf die Mittelachse des Logos gerueckt, damit Marke, Profil und Aufruf in
   einer Linie beginnen. 44px ist die Hoehe des Knopfs. */
.ftr__ig { margin-top: calc((var(--ftr-kopf) - 44px) / 2); }
.ftr__ig svg { width: 18px; height: 18px; flex: none; }
.ftr__ig:hover { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* Ohne Innenabstand, damit die Adresse auf derselben Kante beginnt wie die
   Aussenkante des Knopfs darueber. Eine Einrueckung auf das Zeichen im Knopf
   haette eine zweite Kante in die Spalte gebracht. */
.ftr__mail {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--fg-muted); white-space: nowrap;
  transition: color var(--t-fast) var(--ease);
}
.ftr__mail:hover { color: var(--fg); }

/* Rechte Spalte: schliesst buendig mit dem rechten Satzspiegel ab und steht
   auf derselben Achse wie Logo und Profilknopf. 48px ist die Hoehe des Knopfs. */
.ftr__cta {
  white-space: nowrap; justify-self: end;
  margin-top: calc((var(--ftr-kopf) - 48px) / 2);
}
.ftr__cta:hover { color: #fff; }

/* Drei Spalten brauchen Platz. Darunter stehen sie untereinander, alle auf
   derselben linken Kante - eine mittig gesetzte Spalte wirkt im Stapel
   willkuerlich. */
@media (max-width: 900px) {
  .ftr__oben { grid-template-columns: 1fr; justify-items: start; }
  .ftr__cta { justify-self: start; }
  /* Untereinander gibt es keine gemeinsame Kopfzeile mehr, auf die zu ruecken
     waere - der Versatz waere hier nur ein krummer Abstand. */
  .ftr__ig, .ftr__cta { margin-top: 0; }
}

.ftr__unten {
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-6);
  justify-content: space-between; align-items: center;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line-soft);
}
.ftr__links { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
/* 44px, damit die Rechtslinks auf dem Handy sicher zu treffen sind. */
.ftr__links a { display: inline-flex; align-items: center; min-height: 44px; }
.ftr__links a:hover { color: var(--fg); }

/* -------------------------------------------------------------- Reveal */
[data-reveal] {
  opacity: 0; transform: translateY(18px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Gestaffelt statt gleichzeitig: erscheinen alle Karten einer Liste im selben
   Moment, wirkt es wie eine Vorlage. Nacheinander liest es sich als Rhythmus.
   Den Zaehler --i setzt script.js auf die Kinder. */
[data-staffel] > * {
  opacity: 0; transform: translateY(20px);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease);
  transition-delay: calc(var(--i, 0) * 65ms);
}
[data-staffel].is-in > * { opacity: 1; transform: none; }

/* Der Auftritt des Camps: die Gebaeude erscheinen von hinten nach vorn, in
   der Reihenfolge, in der sie im Bild uebereinanderliegen. Das ist der eine
   Moment der Seite, an dem Bewegung wirklich etwas erzaehlt. */
/* transition: none ist noetig - die Gebaeude haben fuer den Hover-Effekt
   eine Ueberblendung auf opacity, die sonst gegen den Aufbau arbeitet. */
.scene[data-aufbau="wartet"] .obj { opacity: 0; transition: none; }
.scene[data-aufbau="laeuft"] .obj {
  animation: gebaeudeAuf 540ms var(--ease) backwards;
  animation-delay: calc(var(--i, 0) * 55ms);
}
@keyframes gebaeudeAuf {
  from { opacity: 0; transform: translateY(16px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
/* Der Boden liegt vor den Gebaeuden da, damit die Szene nicht im Nichts steht. */
.scene[data-aufbau="wartet"] .ground,
.scene[data-aufbau="laeuft"] .ground { opacity: 1; }

/* -------------------------------------------------------------- Hilfsmittel */
/* Nur fuer Vorleseprogramme — sichtbar ist hier nichts. */
.nur-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Zeichenvorrat fuer <use>. Nimmt keinen Platz ein. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Bereichsdaten des Camps. Mit JavaScript uebernimmt die Infokarte, ohne
   JavaScript stehen sie als normale Liste da — der Rundgang bleibt lesbar. */
.zonen-quelle { display: none; }
.kein-js .zonen-quelle {
  display: grid; gap: var(--sp-5);
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line-soft);
}
@media (min-width: 760px) {
  .kein-js .zonen-quelle { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
  .kein-js .zonen-quelle__kopf { grid-column: 1 / -1; }
}
.kein-js .zonen-quelle__kopf {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  font-size: var(--step-2); line-height: .98;
}
.kein-js .zonen-quelle h4 {
  font-weight: 800; font-size: var(--step-1); margin-bottom: var(--sp-2);
}
.kein-js .zonen-quelle p { color: var(--fg-muted); }
.kein-js .zonen-quelle ul {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3);
}
.kein-js .zonen-quelle li {
  font-size: var(--step--1); font-weight: 800; color: #fff;
  letter-spacing: .08em; text-transform: uppercase;
  padding: 5px 11px; border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgba(92, 225, 230, .45);
}
/* Ohne JavaScript gibt es keine Bereichsleiste und keinen Zeigerhinweis. */
.kein-js .zonennav, .kein-js .scene__hint { display: none; }

/* ------------------------------------------------- Vorteile (Mit / Ohne) */
/* Gegenüberstellung wie in der Präsentation: links was mit dem Camp
   passiert, rechts der Zustand ohne. Auf schmalen Geräten stapeln sich die
   beiden Hälften, die Marken bleiben deshalb in jeder Zeile stehen. */
.gegen { display: grid; gap: var(--sp-5); }
.gegen__karte {
  display: grid; gap: var(--sp-4);
  padding-block: var(--sp-5);
  border-top: 1px solid var(--line-soft);
}
.gegen__karte:last-child { border-bottom: 1px solid var(--line-soft); }
@media (min-width: 900px) {
  .gegen__karte {
    grid-template-columns: 15ch minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
    gap: var(--sp-5) clamp(1.5rem, 4vw, 3rem);
  }
}
.gegen__karte h3 {
  font-weight: 800; font-size: var(--step-1);
  align-self: start;
}
.gegen__marke {
  display: block;
  font-size: var(--step--1); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  margin-bottom: var(--sp-2);
}
/* Die Seite mit Camp trägt den Akzent und das visuelle Gewicht. */
.gegen__mit {
  padding-left: var(--sp-4);
  border-left: 3px solid var(--accent);
  color: var(--fg);
}
.gegen__mit .gegen__marke { color: var(--accent); }
/* Die Gegenseite tritt zurueck - aber ueber Gewichtung, nicht ueber
   Deckkraft. Ein Versuch mit opacity .72 druckte den Text auf 3,2:1 und
   damit unter die Lesbarkeitsgrenze. Stattdessen bekommt die Camp-Seite
   mehr Gewicht: hellerer Text, kraeftigerer Balken. */
.gegen__ohne {
  padding-left: var(--sp-4);
  border-left: 2px solid var(--line);
  color: var(--fg-dim);
}
.gegen__ohne .gegen__marke { color: var(--fg-dim); }

/* -------------------------------------------------------------- Ablauf */
.schritte {
  display: grid; gap: var(--sp-5);
  counter-reset: s;
}
@media (min-width: 820px) {
  .schritte { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); }
}
.schritt {
  position: relative;
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--bg-panel), var(--bg-lift));
}
/* Weiss gefuellt, aussen ein duenner tuerkiser Rand. paint-order legt den
   Strich unter die Fuellung, damit das Weiss voll stehen bleibt und nur der
   Rand herausschaut. Der Rand atmet dauerhaft leicht. */
/* Muss .schritt p schlagen (0,1,1) - sonst bliebe die Ziffer grau. */
.schritt p.schritt__nr {
  font-family: var(--font-display); font-weight: 900;
  font-size: var(--step-3); line-height: .8;
  color: #fff;
  -webkit-text-stroke: 1.2px var(--accent);
  paint-order: stroke fill;
  margin-bottom: var(--sp-4);
  animation: ziffernrand 3.6s ease-in-out infinite;
}
/* Versetzt, damit die drei nicht im Gleichschritt pulsieren. */
.schritte .schritt:nth-child(2) .schritt__nr { animation-delay: -1.2s; }
.schritte .schritt:nth-child(3) .schritt__nr { animation-delay: -2.4s; }

@keyframes ziffernrand {
  0%, 100% {
    -webkit-text-stroke-width: 1px;
    filter: drop-shadow(0 0 0 rgba(92, 225, 230, 0));
  }
  50% {
    -webkit-text-stroke-width: 2.1px;
    filter: drop-shadow(0 0 7px rgba(92, 225, 230, .55));
  }
}
.schritt h3 { font-weight: 800; font-size: var(--step-1); margin-bottom: var(--sp-3); }
.schritt p { color: var(--fg-muted); }

/* -------------------------------------------------------------- Kontakt */
.contact__inner { display: grid; gap: var(--sp-7); }
.contact__kopf { max-width: 52ch; margin-inline: auto; }
.contact__lead { color: var(--fg-muted); font-size: var(--step-1); }
.contact__direkt { color: var(--fg-dim); font-size: var(--step--1); }
.contact__direkt a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

/* -------------------------------------------------------------- Formular */
.formular {
  display: grid; gap: var(--sp-5);
  width: min(720px, 100%); margin-inline: auto;
  text-align: left;
  padding: clamp(1.5rem, 4vw, 2.5rem);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--bg-panel), var(--bg-lift));
}
@media (min-width: 680px) {
  .formular { grid-template-columns: 1fr 1fr; }
  .feld--breit { grid-column: 1 / -1; }
}
.feld { display: grid; gap: var(--sp-2); align-content: start; }
.feld label {
  font-size: var(--step--1); font-weight: 800;
  letter-spacing: .10em; text-transform: uppercase;
  color: var(--fg-muted);
}
.feld__pflicht { color: var(--accent); }
.feld__opt { color: var(--fg-dim); font-weight: 400; letter-spacing: .04em; text-transform: none; }

.formular input, .formular textarea {
  width: 100%; min-height: 48px;
  padding: var(--sp-3) var(--sp-4);
  font: inherit; color: var(--fg);
  background: #08090b;
  border: 1px solid var(--line-ui);
  border-radius: var(--r-md);
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.formular textarea { min-height: 132px; resize: vertical; line-height: 1.55; }
/* 4,75:1 auf dem Feldgrund #08090b - der frühere Ton lag mit 4,15:1 knapp
   unter der Grenze und war auf hellen Bildschirmen kaum zu lesen. */
.formular input::placeholder, .formular textarea::placeholder { color: #767c85; }
.formular input:hover, .formular textarea:hover { border-color: var(--line-ui-hover); }
.formular input:focus, .formular textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
/* Fehlerhafte Felder werden nicht nur rot, sie bekommen auch Text darunter —
   Farbe allein waere kein ausreichender Hinweis. */
.formular [aria-invalid="true"] { border-color: #ff8080; }
.formular [aria-invalid="true"]:focus { box-shadow: 0 0 0 3px rgba(255, 128, 128, .22); }
.feld__fehler {
  font-size: var(--step--1); color: #ff9b9b;
  min-height: 0; margin: 0;
}
.feld__fehler:empty { display: none; }

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

.formular__fuss {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-4) var(--sp-5);
}
.formular__hinweis {
  flex: 1 1 22ch;
  font-size: var(--step--1); color: var(--fg-dim); line-height: 1.5;
}
.formular__hinweis a { color: var(--fg-muted); text-decoration: underline; text-underline-offset: 3px; }
.formular__hinweis a:hover { color: var(--fg); }

.formular__meldung {
  margin: 0; font-size: var(--step-0);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md);
  border: 1px solid var(--line-ui);
}
.formular__meldung:empty { display: none; }
.formular__meldung[data-art="ok"] {
  color: var(--accent); border-color: rgba(92, 225, 230, .45);
  background: rgba(92, 225, 230, .07);
}
.formular__meldung[data-art="fehler"] {
  color: #ffb4b4; border-color: rgba(255, 128, 128, .45);
  background: rgba(255, 128, 128, .07);
}
.formular[data-sendet="true"] { opacity: .6; pointer-events: none; }

/* -------------------------------------------------------------- Instagram */
.member__ig {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); min-height: 44px;
  font-size: var(--step--1); color: var(--fg-muted);
  transition: color var(--t-fast) var(--ease);
}
.member__ig svg { width: 17px; height: 17px; flex: none; }
/* min-width: 0 ist noetig, damit ein Flex-Kind ueberhaupt schrumpfen darf -
   ohne das greift text-overflow nicht und der Name lief aus der Karte. */
.member__ig { max-width: 100%; }
.member__ig span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.member__ig:hover { color: var(--accent); }

.ftr__social { display: flex; gap: var(--sp-2); }
.ftr__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 999px;
  color: var(--fg-dim);
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.ftr__social a:hover { color: var(--accent); background: rgba(92, 225, 230, .10); }
.ftr__social svg { width: 19px; height: 19px; }

/* -------------------------------------------------------------- Fehlerseite */
.fehlerseite {
  display: grid; align-content: center;
  min-height: 74svh;
  padding-block: clamp(6rem, 14vh, 9rem) clamp(3rem, 8vh, 5rem);
}
.fehlerseite__inner { max-width: 56ch; }
.fehlerseite h1 { font-size: var(--step-3); margin-block: var(--sp-4) var(--sp-5); }
.fehlerseite__text { color: var(--fg-muted); font-size: var(--step-1); margin-bottom: var(--sp-6); }
.fehlerseite__cta { display: flex; flex-wrap: wrap; gap: var(--sp-4); }

/* -------------------------------------------------------------- Rechtstexte */
.legal { padding-block: clamp(7rem, 16vh, 10rem) clamp(4rem, 9vh, 6rem); }
.legal__inner { max-width: 74ch; }
.legal h1 { font-size: var(--step-3); margin-block: var(--sp-4) var(--sp-6); }
.legal h2 {
  font-family: var(--font-display); font-weight: 800; text-transform: uppercase;
  font-size: var(--step-1); letter-spacing: -.01em;
  margin-block: var(--sp-7) var(--sp-4);
}
.legal p { color: var(--fg-muted); margin-bottom: var(--sp-4); }
.legal__lead { font-size: var(--step-1); color: var(--fg) !important; }
.legal a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.legal__list {
  color: var(--fg-muted); display: grid; gap: var(--sp-2);
  margin-bottom: var(--sp-4); padding-left: var(--sp-5);
  list-style: disc;
}
.legal__code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em; color: var(--fg);
}
.legal__stand { font-size: var(--step--1); color: var(--fg-dim); margin-top: var(--sp-7); }
.legal__zurueck { margin-top: var(--sp-6); }

/* Auffaellig, damit dieser Kasten nicht versehentlich live geht. */
.legal__todo {
  color: #ffd9a0 !important;
  background: rgba(255, 176, 102, .09);
  border: 1px dashed rgba(255, 176, 102, .55);
  border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-6);
  font-size: var(--step--1);
}
.legal__fill {
  color: #ffd9a0;
  background: rgba(255, 176, 102, .10);
  padding: 1px 6px; border-radius: var(--r-sm);
}

/* -------------------------------------------------------------- Motion off */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  [data-staffel] > * { opacity: 1; transform: none; transition-delay: 0s !important; }
  .scene[data-aufbau] .obj { opacity: 1 !important; animation: none !important; }
  .scene__tilt { transform: none !important; }
}
