/* ═══════════════════════════ hero.css ═══════════════════════════
   Hero-Box, Name, Foto-/Canvas-Positionierung, Einblendung.

   Zur Einblendung am Ende der Datei: Sie ist umgedreht worden.
   Vorher hielt CSS den Hero auf opacity:0, und erst eine Klasse aus JS
   machte ihn sichtbar. Blieb JS aus, blieb der Hero unsichtbar. Jetzt
   ist der sichtbare Zustand der Grundzustand, und die Klasse löst nur
   noch eine Animation aus. Ohne JS erscheint der Hero sofort und ohne
   Animation; kaputt geht dabei nichts.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────── Hero (#home) ─────────────────────────
   Section bleibt auf normaler Seiten-Hintergrundfarbe. Die eigentliche
   Gestaltung sitzt in .hero-box, die als eigenständige „Karte" schwebt.

   Name und Foto teilen sich dieselbe Grid-Fläche (siehe .hero-box).
   Auf schmalen Screens trennt sie align-self sauber (Name oben, Foto
   unten). Ab 1241px rücken beide auf "center" zusammen: der Name
   liegt gross im Hintergrund (z-index 1), das freigestellte Foto davor
   (z-index 2). Wo das Foto transparent ist (praktisch überall ausser
   der Silhouette selbst) bleibt der Name lesbar; nur der Teil hinter
   dem Körper wird wirklich verdeckt. */
#home{
  display:flex;align-items:flex-start;justify-content:center;
  /* Oben --hero-top (Herleitung in css/tokens.css), seitlich und unten
     der Gutter. Die Box sitzt damit optisch gleich weit von allen vier
     Kanten entfernt, statt rechnerisch gleich weit, was oben wegen der
     hohen, überwiegend leeren Navbar deutlich mehr aussah. */
  padding:var(--hero-top) var(--gutter) var(--gutter);
}

.hero-box{
  position:relative;overflow:hidden;
  /* Kein max-width. Sonst wächst auf breiten Screens nur der Seitenrand,
     während der Abstand oben konstant klein bleibt. */
  width:100%;
  /* Füllt die Resthöhe unter der Navbar, sodass unten derselbe Gutter
     bleibt wie oben und an den Seiten. svh statt vh wegen der ein- und
     ausfahrenden Browserleisten auf Mobile. */
  min-height:var(--hero-box-h);
  border-radius:var(--radius-card);
  background:var(--hero-bg);
  border:1px solid var(--hero-border,transparent);
  box-shadow:var(--shadow-xl);
  /* Grid statt Flex: Name und Foto liegen in DERSELBEN Zelle (eine Zeile,
     eine Spalte) und damit zwangsläufig übereinander. z-index entscheidet,
     wer vorne liegt. align-self an den Kindern (nicht hier) steuert, ob
     sie sich (schmal) an den Rändern trennen oder (breit) in der Mitte
     überlappen. */
  display:grid;
  justify-items:center;
  text-align:center;
  padding:var(--hero-pad-v) var(--hero-pad-h);
}

/* ──────────────────── Hintergrund-Ebene ──────────────────────────
   Ohne sie liest sich die Parallaxe nur als "Bild verschiebt sich":
   eine einzelne Ebene, die sich vor einem starr stehenden Rechteck
   bewegt, gibt dem Auge keinen Vergleich, an dem es "Tiefe" ablesen
   könnte. Echte Tiefenwahrnehmung braucht mindestens zwei Ebenen, die
   sich UNTERSCHIEDLICH bewegen. Das Foto ist ein Freisteller ohne
   echten Hintergrund, es gibt also kein Bildmaterial für eine zweite
   Ebene. Ein weicher, unscharfer Glow in der Akzentfarbe übernimmt
   diese Rolle stellvertretend.

   Bewusst kein echtes Bild, keine feste Form: Ein Glow bleibt bei jeder
   Fotogrösse und jedem Seitenverhältnis plausibel, ein zweites Motiv
   müsste exakt passen.

   Kein filter:blur: eine ausreichend weiche radial-gradient-Kurve
   erreicht denselben Effekt ohne den Compositing-Overhead eines
   Blur-Filters (dieselbe Überlegung wie im Rest der Seite: möglichst
   nur transform/translate bewegen, siehe hero-photo weiter unten).

   position:absolute statt Grid-Zelle: Die Ebene braucht keinen Platz
   im Layout, nur eine Position hinter allem anderen. Ein dritter
   Grid-Bereich wäre hier mehr Komplexität ohne Nutzen. Als erstes Kind
   von .hero-box ohne z-index bereits hinter .hero-name-wrap (z-index 1)
   und .hero-photo (z-index 2), explizit gesetzt, damit das beim
   Umsortieren nicht stillschweigend kippt. */
.hero-glow{
  position:absolute;
  z-index:0;
  pointer-events:none;
  left:50%;
  bottom:0;
  /* An --hero-photo-w bemessen, nicht an der Box: Die Box ist eine breite,
     flache Karte (deutlich breiter als hoch), .hero-photo aber schmal und
     hochformatig. Eine an der Box-Breite bemessene Kreisfläche würde bei
     diesem Seitenverhältnis riesig: so gross, dass fast der ganze Kreis
     ausserhalb der (durch overflow:hidden auf .hero-box begrenzten)
     sichtbaren Höhe läge und nur noch sein bereits fast transparenter
     äusserster Rand zu sehen wäre. Am Foto bemessen bleibt die Kreisfläche
     unabhängig vom Seitenverhältnis der Box plausibel gross. */
  width:calc(var(--hero-photo-w) * 2.2);
  aspect-ratio:1;
  /* transform statt translate für die Zentrierung: dieselbe Trennung wie
     bei .hero-photo (siehe dort): heroScene.js schreibt die Parallaxe
     auf `translate`, eine Zentrierung dort würde bei jedem Frame
     überschrieben statt sich mit dem Versatz zu addieren. */
  transform:translateX(-50%);
  border-radius:50%;
  background:radial-gradient(circle,
    color-mix(in srgb, var(--accent-on-dark) 20%, transparent) 0%,
    color-mix(in srgb, var(--accent-on-dark) 8%, transparent) 40%,
    transparent 72%);
}

.hero-name-wrap{
  grid-area:1/1;
  align-self:start;
  display:flex;flex-direction:column;align-items:center;
  width:100%;
}

.hero-name{
  position:relative;z-index:1;
  /* h1 bringt vom Browser margin:0.67em mit. Bei grosser Schrift wären
     das etliche Pixel oben und unten. Das riss die rote Zeile vom Namen
     weg. */
  margin:0;
  display:flex;flex-direction:column;gap:2px;
  font-family:'Space Grotesk',ui-sans-serif,system-ui,sans-serif;font-weight:600;
  font-size:var(--hero-name-fs);
  line-height:.98;letter-spacing:-.02em;
  color:var(--hero-text);
}
.hero-name .accent{color:var(--accent-on-dark)}

.hero-role{
  margin:clamp(6px,.9vh,18px) 0 0;
  font-size:clamp(13px,3vw,20px);
  font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  /* Hellere Variante: siehe Begründung bei --accent-on-dark in tokens.css */
  color:var(--accent-on-dark);
}

/* ──────────────────── Foto-Container ────────────────────────────
   Die Fläche steht fest, bevor irgendein Byte Bilddaten da ist.
   Deshalb Breite + aspect-ratio statt „so gross wie der Inhalt": ein
   nachgeladenes Bild darf das Layout nicht mehr anfassen.

   Die Parallaxe schreibt JS auf die CSS-Eigenschaft `translate`,
   nicht auf `transform`. Beides sind getrennte Eigenschaften. So
   kollidiert die Cursor-Bewegung nicht mit dem transform, das die
   Einblend-Animation belegt.

   Liegt in derselben Grid-Zelle wie .hero-name-wrap (siehe .hero-box).
   align-self:end setzt es an die Unterkante der Box, bei jeder Breite:
   das Foto soll bis zum Boden reichen, nicht mittig schweben. Den
   Namen dahinter zentriert das trotzdem passend, weil .hero-name-wrap
   ihn unabhängig davon selbst zentriert (siehe dort).

   Das Foto endet oft mitten im T-Shirt mit einer geraden Kante; negative
   margin-bottom hebt das Innenabstand-Polster der Box auf, damit dieser
   Schnitt hinter der Boxkante statt davor verschwindet (overflow:hidden
   auf .hero-box schneidet ab). */
.hero-photo{
  grid-area:1/1;
  align-self:end;
  z-index:2;
  width:var(--hero-photo-w);
  aspect-ratio:var(--hero-photo-ratio-num);
  margin-bottom:calc(-1 * var(--hero-pad-v));
  /* Ohne dem hier ähnliches würde die Zelle das Foto in der Höhe
     zusammendrücken, sobald es eng wird, und weil die Breite fest ist,
     bräche dabei das Seitenverhältnis und der Canvas verzerrte das Bild.
     max-width fängt den Fall ab, dass --hero-photo-w die Boxbreite
     übersteigt. */
  max-width:100%;
  pointer-events:none;
}
/* Nur wenn der Shader tatsächlich läuft, schreibt js/hero/heroScene.js
   jeden Frame auf `translate`. Vorher angemeldet, hätte will-change für
   jeden Besucher eine eigene Compositing-Ebene reserviert, auch für
   die, bei denen sich hier nie etwas bewegt. */
.hero-photo.is-webgl{will-change:translate}

/* Zwei Ebenen, deckungsgleich übereinander, Wechsel nur per opacity:
   kein Reflow.

   Das <img> ist der Grundzustand und ab dem ersten Frame SICHTBAR. Das
   war vorher umgekehrt: Es lag auf opacity:0 und wurde erst von JS über
   eine Klasse eingeblendet. Ohne JS blieb also auch das Foto weg. Jetzt
   verdeckt es ausschliesslich der Canvas, und der existiert nur, wenn der
   Shader tatsächlich läuft.

   Die gestrichelte Platzhalter-Silhouette ist entfallen. Sie war der
   Ladezustand, und den gibt es nicht mehr: Die Lade-Maske wartet mit
   img.decode() auf genau dieses Bild, bevor sich der Vorhang öffnet
   (js/preloader.js). Wenn der Hero sichtbar wird, ist das Foto da. */
.hero-photo-img,
.hero-canvas{
  position:absolute;inset:0;
  width:100%;height:100%;
  transition:opacity .5s ease;
}
.hero-photo-img{opacity:1;object-fit:contain;object-position:center;display:block}
.hero-canvas{opacity:0}

/* .is-webgl = Shader läuft und hat seine Texturen. Nur dann übernimmt
   der Canvas und das statische Bild tritt ab. */
.hero-photo.is-webgl .hero-canvas{opacity:1}
.hero-photo.is-webgl .hero-photo-img{opacity:0}

/* ─────────────── Überlapp-Layout ab 1241px ───────────────────────
   Genug Breite, dass der Name auch einzeilig neben dem grossen Foto
   noch links und rechts herausschaut. Unter dieser Grenze bräuchte
   „Amin Letaief." mehr Platz, als die Box in der Breite hergibt, ohne
   dass das Foto fast alles verdeckt. */
@media (min-width:1241px){
  /* align-items:flex-start statt center, UND width:auto statt 100%:
     .hero-name-wrap schrumpft dadurch auf die tatsächliche Breite des
     Namens, und die Rolle darunter richtet sich an dessen linker Kante
     aus. Die liegt exakt unter "Amin". Zentriert bliebe die Rolle sonst
     unter der Mitte der ganzen Zeile, meist genau dort, wo das Foto sie
     verdeckt. Als Block bleibt .hero-name-wrap trotzdem mittig in der
     Grid-Zelle (justify-items:center auf .hero-box wirkt weiter). */
  .hero-name-wrap{align-self:center;align-items:flex-start;width:auto}

  /* Einzeilig statt gestapelt: nur so ragt der Name seitlich unter dem
     Foto hervor, statt komplett dahinter zu verschwinden. Der Abstand
     zwischen den Wörtern war mit 0.2em praktisch keiner. Das Foto schnitt
     dadurch mitten in den Buchstaben statt in der Lücke zwischen den
     Wörtern. clamp() statt fixem em-Wert, damit die Lücke bei riesiger
     Schrift auf breiten Screens nicht unverhältnismässig mitwächst. */
  .hero-name{flex-direction:row;align-items:baseline;gap:clamp(80px,18vw,320px)}
}

/* ─────────────────────── Einblendung ───────────────────────────
   Grundzustand = sichtbar. #home.is-ready (gesetzt von js/main.js,
   sobald die Preloader-Maske aufgeht) startet nur die Animation.

   `both` als fill-mode: Während der Verzögerung gilt das from-Keyframe,
   danach der normale Zustand des Elements. Weil nur ein from-Keyframe
   existiert, ist das to-Keyframe implizit der Grundzustand. Deshalb
   braucht keines dieser Keyframes die Breakpoint-Unterschiede zu kennen.

   Reihenfolge folgt der Leserichtung: Name, Foto, Rolle. */
@keyframes hero-box-in  { from{opacity:0;transform:translateY(20px) scale(.985)} }
@keyframes hero-text-in { from{opacity:0;transform:translateY(14px)} }
@keyframes hero-photo-in{ from{opacity:0;transform:translateY(14px)} }

#home.is-ready .hero-box  {animation:hero-box-in   .80s var(--settle) both}
#home.is-ready .hero-name {animation:hero-text-in  .70s var(--settle) .10s both}
#home.is-ready .hero-photo{animation:hero-photo-in .70s var(--settle) .18s both}
#home.is-ready .hero-role {animation:hero-text-in  .70s var(--settle) .26s both}

/* Reduzierte Bewegung: nur einblenden, nicht verschieben.
   Die Regeln überschreiben den Universalselektor aus global.css über
   ihre höhere Spezifität. Eine echte Dauer bleibt also erhalten. */
@media (prefers-reduced-motion:reduce){
  @keyframes hero-fade-in{ from{opacity:0} }

  #home.is-ready .hero-box,
  #home.is-ready .hero-name,
  #home.is-ready .hero-photo,
  #home.is-ready .hero-role{
    animation:hero-fade-in .35s ease both!important;
  }
  /* Kein Rest-Versatz aus einer eventuell schon gesetzten Parallaxe.
     (js/main.js baut den Effekt bei reduzierter Bewegung ohnehin nicht,
     das hier ist die Absicherung für den Fall, dass die Einstellung
     mitten in der Sitzung umgestellt wird.) */
  .hero-photo,.hero-name,.hero-glow{translate:none!important}
}
