/* ==========================================================================
   Bewegung
   Grundregel: Inhalt ist per Default sichtbar. Der versteckte Ausgangs-
   zustand greift NUR, wenn JS die Klasse .js am <html> gesetzt hat. Ohne JS,
   bei JS-Fehler oder im headless-Renderer ist die Seite vollstaendig lesbar.
   ========================================================================== */

/* --- Scroll-Reveal -------------------------------------------------------- */
html.js .zeig {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dauer-lang) var(--ease-aus),
              transform var(--dauer-lang) var(--ease-aus);
  will-change: opacity, transform;
}
html.js .zeig.sichtbar { opacity: 1; transform: none; }

/* Staffelung innerhalb EINER Gruppe (nicht als Reflex ueber jede Sektion) */
html.js .staffel > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dauer) var(--ease-aus),
              transform var(--dauer) var(--ease-aus);
  transition-delay: calc(var(--i, 0) * 70ms);
}
html.js .staffel.sichtbar > * { opacity: 1; transform: none; }

/* --- Hero: Zeilen steigen einzeln aus ihrer Maske ------------------------- */
html.js .hero__zeile { display: block; overflow: hidden; }
html.js .hero__zeile > span {
  display: block;
  transform: translateY(105%);
  transition: transform 900ms var(--ease-aus);
  transition-delay: calc(var(--i, 0) * 110ms);
}
html.js .hero.geladen .hero__zeile > span { transform: none; }

html.js .hero__nach {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dauer-lang) var(--ease-aus) 480ms,
              transform var(--dauer-lang) var(--ease-aus) 480ms;
}
html.js .hero.geladen .hero__nach { opacity: 1; transform: none; }

/* --- Balken-Wipe ---------------------------------------------------------
   Bewusst rein transform-basiert: ein schraeg beschnittenes Pseudo-Element
   faehrt durch. Kein clip-path- oder width-Keyframing (das wuerde bei jedem
   Frame neu rastern).
   ------------------------------------------------------------------------- */
.wipe { position: relative; overflow: hidden; }
html.js .wipe::before {
  content: "";
  position: absolute; inset: -2px -60% -2px -60%;
  background: color-mix(in oklab, var(--cd-weiss) 22%, var(--cd-blau));
  clip-path: polygon(0 0, 100% 0, calc(100% - 12vh) 100%, 0 100%);
  transform: translateX(-140%);
  transition: transform 820ms var(--ease-aus), visibility 0s linear 820ms;
  z-index: 3;
  pointer-events: none;
  visibility: visible;
}
/* Nach dem Durchlauf komplett aus dem Weg — sonst bleibt am Rand ein Rest
   stehen, der wie ein Layout-Fehler aussieht. */
html.js .wipe.sichtbar::before { transform: translateX(140%); visibility: hidden; }

/* --- Menue-Overlay: Flaeche blendet auf, Inhalt kommt von rechts ----------
   Das Panel wird ueber das hidden-Attribut geschaltet, und hidden setzt
   display:none — eine Eigenschaft, die sich normalerweise nicht ueberblenden
   laesst. Deshalb `transition-behavior: allow-discrete` zusammen mit
   @starting-style: Der Browser haelt display so lange, bis die Ueberblendung
   durch ist, und kennt beim Einblenden einen Startzustand.

   Faellt beides aus (aelterer Browser), erscheint das Menue schlagartig und
   vollstaendig — derselbe Zustand wie ohne diese Datei, also nie ein leeres
   Overlay. Deshalb steht der Endzustand in der normalen Deklaration und nur
   der Startzustand in @starting-style.
   ------------------------------------------------------------------------- */
@media (max-width: 82rem) {
  html.js .nav {
    opacity: 1;
    transition: opacity var(--dauer) var(--ease-aus),
                display var(--dauer) allow-discrete;
  }
  html.js .nav[hidden] { opacity: 0; }
  @starting-style {
    html.js .nav { opacity: 0; }
  }

  /* Die Punkte fahren gestaffelt von rechts ein. Die Verzoegerung steht nur am
     offenen Zustand — beim Schliessen greift die 0s-Regel unten, sonst liefe
     das Menue rueckwaerts wieder gestaffelt aus und fuehlte sich zaeh an. */
  html.js .nav li,
  html.js .nav .knopf {
    opacity: 1;
    transform: none;
    transition: opacity var(--dauer) var(--ease-aus),
                transform var(--dauer) var(--ease-aus);
    transition-delay: calc(var(--i, 0) * 55ms + 70ms);
  }
  html.js .nav[hidden] li,
  html.js .nav[hidden] .knopf {
    opacity: 0;
    transform: translateX(28px);
    transition-delay: 0s;
  }
  @starting-style {
    html.js .nav li,
    html.js .nav .knopf { opacity: 0; transform: translateX(28px); }
  }
  html.js .nav li:nth-child(1) { --i: 0; }
  html.js .nav li:nth-child(2) { --i: 1; }
  html.js .nav li:nth-child(3) { --i: 2; }
  html.js .nav li:nth-child(4) { --i: 3; }
  html.js .nav li:nth-child(5) { --i: 4; }
  html.js .nav li:nth-child(6) { --i: 5; }
  html.js .nav .knopf { --i: 6; }

  @media (prefers-reduced-motion: reduce) {
    html.js .nav li,
    html.js .nav .knopf {
      transform: none !important;
      transition-delay: 0s !important;
    }
  }
}

/* --- Zaehler: reserviert Platz, damit beim Hochzaehlen nichts springt ----- */
.zahl { font-variant-numeric: tabular-nums; }

/* --- Bewegungsreduzierung ------------------------------------------------
   Nicht „weniger Bewegung", sondern keine: Endzustand sofort.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html.js .zeig,
  html.js .staffel > *,
  html.js .hero__nach {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  html.js .hero__zeile > span { transform: none !important; transition: none !important; }
  html.js .wipe::before { display: none; }
  .bild--zoom img { transition: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Innenseiten-Hero: Textgruppe faehrt beim Laden ein --------------------
   Bewusst eine Animation, kein Klassen-Toggle: eine Transition, die auf eine
   per JS gesetzte Klasse wartet, laesst den Text stehen, wenn das Skript
   fehlt, spaet kommt oder der Tab im Hintergrund liegt. Die Animation laeuft
   von selbst und endet garantiert sichtbar (both). Ohne JS ist --i gleich 0,
   dann startet alles gemeinsam statt versetzt.
   Kein Zeilen-Stagger wie auf der Startseite: die Innen-H1 sind lange
   Komposita, die je nach Breite anders umbrechen.                          */
@keyframes seitenkopf-ein {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
html.js .seitenkopf__innen > .krumen,
html.js .seitenkopf__text > * {
  animation: seitenkopf-ein var(--dauer-lang) var(--ease-aus) both;
  animation-delay: calc(var(--i, 0) * 70ms);
}
@media (prefers-reduced-motion: reduce) {
  html.js .seitenkopf__innen > .krumen,
  html.js .seitenkopf__text > * { animation: none; }
}

/* --- Stimmen: das Blau oeffnet sich zur Person ----------------------------
   Ruhezustand ist das Duotone der uebrigen Seite; sobald die Karte ins Bild
   scrollt, blendet die Farbebene darueber auf. Animiert wird nur opacity —
   mix-blend-mode ist nicht animierbar und wuerde hart umschalten.

   Kein Sicherheitsnetz noetig: Das Foto ist auch in Blau vollstaendig da.
   Deshalb bekommt die Klasse farbe-an einen eigenen Beobachter ohne den
   2,5-Sekunden-Watchdog aus reveal() — der haette alle Karten eingefaerbt,
   lange bevor jemand sie zu sehen bekommt.
   ------------------------------------------------------------------------- */
.stimme__farbe {
  transition: opacity 900ms var(--ease-aus);
  /* --i laeuft 0,1,2,0,1,2: so staffelt sich jede sichtbare Dreiergruppe,
     egal wie weit die Schiene gescrollt ist. */
  transition-delay: calc(var(--i, 0) * 90ms);
}
.stimme.farbe-an .stimme__farbe { opacity: 1; }

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

/* --- Grabenprofil: der Aufbau laeuft von unten nach oben ------------------
   So, wie er auf der Baustelle entsteht: Boden, Sandbett, Rohr, Verfuellung,
   dann die Fahrbahn darueber. Jede Schicht waechst aus ihrer eigenen
   Unterkante (transform-origin unten), das Rohr setzt sich aus der Mitte.

   Animiert wird ausschliesslich transform. Das Hervorheben per Legende
   arbeitet mit opacity, und eine laufende Animation mit fill-mode both
   wuerde jede normale opacity-Deklaration ueberstimmen.
   ------------------------------------------------------------------------- */
@keyframes pr-auf    { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes pr-setzen { from { transform: scale(0); }  to { transform: scale(1); } }
@keyframes pr-legende { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }

html.js .profil .pr-schicht {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transform: scaleY(0);
}
html.js .profil .pr-rohr { transform-origin: 50% 50%; transform: scale(0); }
html.js .profil .profil__legende li { opacity: 0; }

html.js .haltung.sichtbar .pr-schicht { animation: pr-auf 380ms var(--ease-aus) both; }
html.js .haltung.sichtbar .pr-boden  { animation-delay: 0ms; }
html.js .haltung.sichtbar .pr-sand   { animation-delay: 160ms; }
html.js .haltung.sichtbar .pr-fuell  { animation-delay: 400ms; }
html.js .haltung.sichtbar .pr-frost  { animation-delay: 520ms; }
html.js .haltung.sichtbar .pr-trag   { animation-delay: 620ms; }
html.js .haltung.sichtbar .pr-deck   { animation-delay: 720ms; }
html.js .haltung.sichtbar .pr-rohr   { animation: pr-setzen 340ms var(--ease-aus) 280ms both; }

/* Die Legende zieht in derselben Reihenfolge nach wie die Zeichnung — also
   von unten nach oben, der letzte Eintrag zuerst.                          */
html.js .haltung.sichtbar .profil__legende li { animation: pr-legende 320ms var(--ease-aus) both; }
html.js .haltung.sichtbar .profil__legende li:nth-child(5) { animation-delay: 500ms; }
html.js .haltung.sichtbar .profil__legende li:nth-child(4) { animation-delay: 620ms; }
html.js .haltung.sichtbar .profil__legende li:nth-child(3) { animation-delay: 740ms; }
html.js .haltung.sichtbar .profil__legende li:nth-child(2) { animation-delay: 840ms; }
html.js .haltung.sichtbar .profil__legende li:nth-child(1) { animation-delay: 940ms; }

@media (prefers-reduced-motion: reduce) {
  html.js .profil .pr-schicht,
  html.js .profil .pr-rohr { transform: none !important; animation: none !important; }
  html.js .profil .profil__legende li { opacity: 1 !important; animation: none !important; }
}
