/* ============================================================
   VCI Design — Hero mit Sticky-Stack
   Pattern 3 aus Abschnitt 3 des Planungsdokuments.
   Nur auf der Startseite eingebunden.

   Grundsatz dieser Datei: der Ruhezustand im CSS ist der
   Endzustand der Animation. GSAP staucht die Flaeche fuer den
   Startpunkt erst zusammen. Faellt GSAP aus, steht hier ein
   korrekter Vollbild-Hero statt einer geschrumpften Flaeche.
   ============================================================ */

.hero {
  /* Startwert der Skalierung. Steht hier und nicht in hero.js,
     damit Flaeche und Textebene garantiert denselben Wert
     benutzen. js/hero.js liest ihn per getComputedStyle aus,
     genauso wie motion.js die Durations aus tokens.css liest. */
  --hero-start-scale: 0.72;
  /* Wie weit die Flaeche im Startzustand von jeder Kante
     einrueckt: die Haelfte dessen, was an Skalierung fehlt.

     Bewusst zwei Werte. Prozentuales padding rechnet in CSS auf
     BEIDEN Achsen gegen die Breite des Containers, auch im
     padding-block. Ein gemeinsamer Prozentwert waere vertikal
     also schlicht falsch. Die Y-Achse haengt deshalb an svh. */
  --hero-inset-x: calc((1 - var(--hero-start-scale)) / 2 * 100%);
  --hero-inset-y: calc((1 - var(--hero-start-scale)) / 2 * 100svh);
  /* Startwert der Eckenrundung, aus demselben Grund hier und
     nicht in hero.js: ein Wert, eine Quelle. js/hero.js liest ihn
     genauso aus wie --hero-start-scale und animiert ihn gegen 0.
     Fluid, damit die Rundung auf dem Handy nicht klobig wirkt. */
  --hero-radius: clamp(0.75rem, 0.5rem + 1vw, 1.75rem);

  position: relative;
  /* svh statt vh: die kleine Viewporthoehe aendert sich beim
     Ein- und Ausblenden der iOS-Adressleiste nicht mit. */
  min-height: 100svh;
  display: grid;
  place-items: center;
  isolation: isolate;
}

/* --- Die wachsende Flaeche ----------------------------------
   Liegt bereits auf voller Viewportgroesse und wird von GSAP
   nur heruntergerechnet. Dadurch ist der Zielwert konstant 1
   und muss bei keinem Resize neu ermittelt werden.

   Zur Eckenrundung: hier stand frueher die Entscheidung, bewusst
   ohne border-radius zu arbeiten, weil das Weganimieren eine
   Nicht-Transform-Eigenschaft braucht. Diese Entscheidung ist
   zurueckgenommen, die Rundung ist ausdruecklich gewuenscht.

   Der Einwand von damals bleibt richtig und wird hier beantwortet
   statt uebergangen: die Rundung waechst beim Skalieren optisch
   mit, deshalb loest js/hero.js sie im letzten Drittel des
   Scrollwegs gegen 0 auf. Im Vollbild steht also kein Radius mehr.

   Der Ruhezustand ist weiterhin der Endzustand: border-radius 0.
   Faellt GSAP aus, steht hier ein sauberer Vollbild-Hero ohne
   Rundung, nicht eine halbfertige Karte.
   ------------------------------------------------------------ */
.hero__surface {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--color-black);
  /* Ruhezustand gleich Endzustand, beides. */
  transform: scale(1);
  border-radius: 0;
  transform-origin: center center;
  will-change: transform;
}

/* --- Textebene ------------------------------------------------
   Kontraste gegen --color-black (#0a0a0a), gerechnet nach
   WCAG 2.1 inklusive der Deckkraft:
     Headline und CTA, volles Weiss   18.97:1
     Eyebrow bei opacity 0.6           7.04:1
     Scrollhinweis bei opacity 0.5     5.15:1
     Cyan-Linie als Grafikflaeche     12.61:1
   Hierarchie entsteht ueber Groesse, Laufweite und Deckkraft,
   nicht ueber zusaetzliche Farbtokens.
   ---------------------------------------------------------------- */
.hero__content {
  position: relative;
  width: 100%;
  /* Die Textebene skaliert bewusst NICHT mit. Wuerde sie es,
     stuende die Headline im Startzustand bei 0.72 ihrer
     Token-Groesse und die Typo-Skala waere ausgehebelt, dazu
     kaeme unscharfer Text waehrend des Scrubs.

     Stattdessen rueckt sie um die Einzuege ein und liegt damit
     schon im Startzustand innerhalb der Flaeche. Waehrend die
     Flaeche aufzieht, bleibt der Satz ruhig stehen und der
     Rahmen oeffnet sich um ihn herum. */
  padding-inline: calc(var(--hero-inset-x) + var(--page-padding));
  /* Oben das Groessere von beidem statt der Summe: der Einzug
     deckt den klebenden Header meist schon ab, addieren wuerde
     den Satz unnoetig nach unten druecken. */
  padding-block: max(var(--hero-inset-y), var(--header-height))
                 calc(var(--hero-inset-y) + var(--space-l));
  /* Ohne dies waechst der Kasten ueber das Fenster hinaus. Als
     Grid-Kind hat er die automatische Mindestbreite auto, und die
     ist die Min-Content-Breite seines Inhalts. Die wird vom
     laengsten unteilbaren Wort der Headline bestimmt, und
     "Kompromisslos" ist bei 44px Grad 304 Pixel breit. Das
     overflow-wrap: break-word aus base.css hilft dagegen nicht:
     es erlaubt den Umbruch beim Setzen der Zeile, senkt aber die
     Min-Content-Breite nicht.

     Gemessen war der Kasten bei 320px Fensterbreite 344 Pixel
     breit, die Seite liess sich um 25 Pixel seitlich schieben. */
  min-width: 0;
  /* Bezugsgroesse fuer die Deckelung des Schriftgrads unten. */
  container-type: inline-size;
  color: var(--color-white);
  /* Zentriert. Damit steht der Satz auf derselben Achse wie die
     Flaeche, die um ihn herum aufzieht, und die Komposition hat
     eine Mitte statt einer Kante.

     text-align allein genuegt nicht: es zentriert nur den Inhalt
     von Textelementen. Die Linie ist ein Block mit fester Breite
     und die Headline ein Block mit max-width, beide Kaesten
     muessen zusaetzlich ueber margin-inline: auto in die Mitte.
     Der CTA ist inline-block und folgt text-align von selbst. */
  text-align: center;
}

.hero__eyebrow {
  font-size: var(--text-small);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  opacity: 0.6;
}

/* Cyan ausschliesslich als Flaeche, nie als Textfarbe. */
.hero__rule {
  display: block;
  width: var(--space-xl);
  height: 2px;
  margin-inline: auto;
  margin-block: var(--space-m) var(--space-l);
  background-color: var(--color-accent);
}

.hero__headline {
  /* Gedeckelt, weil die Textspalte im Hero deutlich schmaler ist
     als die Seite: sie rueckt um --hero-inset-x plus
     --page-padding ein, damit der Satz auch im Startzustand
     innerhalb der eingerueckten Flaeche steht. Bei 320px Fenster
     bleiben davon 239 Pixel uebrig, und in die passt
     "Kompromisslos" bei 44px Grad nicht.

     Gemessen ueber den ganzen Telefonbereich: das Wort passt,
     solange der Grad hoechstens 14,4 Prozent der Spaltenbreite
     betraegt. Bei 320px sind das 35,0px, bei 390px 43,4px, bei
     414px 46,3px. 14,2cqi laesst etwas Luft.

     cqi und nicht vw: gemeint ist ein Anteil der Textspalte, und
     die ist deutlich schmaler als das Fenster. vw wuerde auf dem
     Schreibtisch zusaetzlich die Breite der Bildlaufleiste
     mitzaehlen, die es dort gar nicht gibt.

     min() und nicht clamp(): oberhalb von rund 455px Fenster
     gewinnt der Token und die Skala gilt unveraendert weiter. Die
     Deckelung greift also ausschliesslich auf Telefonen.

     ACHTUNG bei neuer Headline-Copy: der Wert haengt an der
     Breite des laengsten Wortes. Neu messen, nicht schaetzen.
     Dieselbe Kopplung wie beim grossen Link in
     css/statement-cta.css. */
  font-size: min(var(--text-display-large), 14.2cqi);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--weight-semibold);
  /* Das Zeilenmass bleibt begrenzt, der Kasten selbst rueckt in
     die Mitte. Zusammen mit text-wrap: balance aus base.css
     ergibt das zwei etwa gleich schwere Zeilen auf einer Achse. */
  max-width: 18ch;
  margin-inline: auto;
  /* Raster fuer den Satzwechsel darunter: beide Saetze liegen in
     derselben Zelle. Die Hoehe richtet sich nach dem hoeheren, und
     beim Wechsel springt nichts. */
  display: grid;
}

/* --- Satzwechsel ------------------------------------------------
   Auftakt und Kernsatz uebereinander. Beide sind Rasterkinder und
   damit Bloecke, text-wrap: balance aus base.css wirkt in jedem
   Satz fuer sich.

   Ruhezustand gleich Endzustand, wie ueberall in dieser Datei: im
   CSS steht nur der Kernsatz. Den Startzustand mit sichtbarem
   Auftakt setzt erst die Klasse hero--satzwechsel, und die vergibt
   js/hero.js nur, wenn es selbst laeuft und GSAP da ist. Faellt
   eins davon aus, steht "Kompromisslos bis ins Detail" wie bisher.
   Bei reduzierter Bewegung greift die Regel gar nicht erst.

   Der Kernsatz wird ueber opacity verborgen, nicht ueber display:
   er muss seinen Platz in der Zelle behalten, sonst waere die
   Zeile beim Wechsel ploetzlich hoeher oder niedriger. */
.hero__satz {
  grid-area: 1 / 1;
  align-self: center;
}

.hero__satz--auftakt {
  display: none;
}

@media (prefers-reduced-motion: no-preference) {
  .hero--satzwechsel .hero__satz--auftakt {
    display: block;
  }

  .hero--satzwechsel .hero__satz--kern {
    opacity: 0;
  }
}

.hero__cta {
  display: inline-block;
  margin-top: var(--space-xl);
  padding-bottom: var(--space-xs);
  font-size: var(--text-small);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: 2px solid var(--color-accent);
  transition: transform var(--duration-short) var(--ease-base);
}

.hero__cta:hover {
  /* Nur transform, damit die Bewegung auf der GPU bleibt.

     Nach oben statt zur Seite: ein seitliches Rutschen bricht bei
     einer zentrierten Komposition die Achse, auf der alles
     darueber steht. Das Heben laesst sie stehen.

     Sichtbar wird das nur, wenn der Magnet aus js/magnetic.js
     nicht fuehrt, also bei reduzierter Bewegung und ohne
     JavaScript. Auf Touch gibt es ohnehin kein Hover. */
  transform: translateY(calc(var(--space-xs) * -1));
}

/* Der Fokus-Ring aus base.css nutzt --color-focus und waere auf
   Schwarz zu dunkel. Auf der Flaeche uebernimmt Weiss. */
.hero :focus-visible {
  outline-color: var(--color-white);
}

/* --- Scrollhinweis --------------------------------------------- */
.hero__hint {
  position: absolute;
  bottom: calc(var(--hero-inset-y) + var(--space-s));
  left: 50%;
  margin-left: -3rem;
  width: 6rem;
  text-align: center;
  /* --text-small, nicht --text-xx-small: der Hinweis ist kein
     Disclaimer, und genau darauf ist der kleinste Token in
     tokens.css ausdruecklich beschraenkt. 14px statt 12px ist
     zugleich der kleinstmoegliche Schritt innerhalb der Skala. */
  font-size: var(--text-small);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-white);
  opacity: 0.5;
}

/* --- Mobil ------------------------------------------------------
   Flacherer Startwert, weil ohne Pin deutlich weniger Scrollweg
   zur Verfuegung steht. Beide Einzuege folgen automatisch mit.
   Breakpoint deckungsgleich mit tokens.css und components.css.
   ---------------------------------------------------------------- */
@media (max-width: 768px) {
  .hero {
    --hero-start-scale: 0.88;
  }

  .hero__headline {
    max-width: none;
  }
}

/* --- Reduzierte Bewegung ----------------------------------------
   Greift auch dann, wenn GSAP gar nicht erst laedt. Die Flaeche
   steht ohnehin schon auf scale(1), hier wird nur zusaetzlich
   jede Restbewegung stillgelegt.
   ---------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .hero__surface {
    transform: scale(1);
  }

  .hero__content {
    transform: none;
  }

  .hero__cta:hover {
    transform: none;
  }
}
