/* ===================================================================
   HERO — homepage first viewport
   =================================================================== */

.hero {
  position: relative;
  height: 100svh;
  min-height: 32rem;
  overflow: hidden;
  background: var(--black);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 1;
  opacity: 0.9;
  /* close to the footage's real color now — the earlier 1.35 brighten
     plus the old 0.85 red wash together were washing it out entirely */
  filter: brightness(1.08) contrast(1.02);
}

/* The red video filter was removed entirely — red is gone from the
   site on the artist's instruction. The footage now plays in its own
   colour with no tint layer at all. The markup hook is kept inert so
   any leftover element in HTML renders nothing. */
.hero__redfilter { display: none; }

.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  /* top stop deepened to 0.58 — the nav mark sits in plain white here
     now (no more mix-blend-mode trick), so it needs guaranteed contrast
     even when the footage itself cycles through pale frames */
  background:
    linear-gradient(180deg, rgba(10,0,2,0.58) 0%, rgba(10,0,2,0.05) 22%, rgba(10,0,2,0.15) 62%, rgba(10,0,2,0.55) 100%);
}

/* the seam into the next section: fades the hero's dark red world into
   the page's own background color instead of cutting hard */
.hero__seam {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: min(30vh, 16rem);
  z-index: 6;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, var(--cream) 100%);
  pointer-events: none;
}
.hero__seam--black {
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, var(--black) 100%);
}

.hero__content {
  position: relative;
  z-index: 10;
  text-align: center;
  padding: var(--space-l) var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
}

/* Schwer und eng, statt leicht und gesperrt.

   Vorher: Gewicht 550, +0.01em gesperrt, 82% Deckkraft — ein Schriftzug,
   der sich bewusst zurücknahm und "sich in die Aufnahme einfügte". Die
   Referenz, an der diese Seite gebaut ist, setzt ihren eigenen Namen
   genau andersherum: sehr schwer, negativ gesperrt, volle Deckkraft.
   Das hier folgt dem.

   display/flex-wrap/gap und die Maskenkante auf .word stehen bereits in
   base.css unter [data-anim="wordmark"] und werden hier absichtlich
   NICHT wiederholt — doppelte Regeln für dieselbe Sache sind genau der
   Grund, warum die Eingangsanimation dieses Schriftzugs übersehen und
   versehentlich überschrieben wurde. */
.hero__wordmark {
  font-size: var(--size-wordmark);
  letter-spacing: -0.025em;
  line-height: 0.98;
  text-transform: uppercase;
  justify-content: center;
  opacity: 1;
  cursor: default;
}

/* Die Eingangsanimation kommt aus base.css: `char-rise`, gestaffelt über
   --i, das splitWordmark() pro Buchstabe setzt. Die gilt für jede
   [data-anim="wordmark"]-Überschrift und bleibt die einzige Quelle.

   Hier wird sie NICHT ersetzt, sondern nur nachgeschärft. Ein eigenes
   Keyframe an dieser Stelle hätte `char-rise` verdrängt — und mit ihr
   den opacity-Teil, der die Buchstaben von 0 auf 1 bringt. Übrig bliebe
   das `opacity: 0` aus der Basisregel ohne Gegenstück: ein Schriftzug,
   der im DOM einwandfrei aussieht und auf dem Bildschirm fehlt. Genau
   das ist hier einmal passiert.

   Nachgeschärft wird über die Variablen der bestehenden Animation:
   längerer Versatz zwischen den Buchstaben, damit der Lauf über den
   Namen als Bewegung lesbar wird statt als gleichzeitiges Auftauchen. */
.hero__wordmark .char {
  font-variation-settings: "wght" 860;
  transition: font-variation-settings 0.3s var(--ease-out);
  animation-duration: 0.9s;
  animation-delay: calc(var(--i, 0) * 46ms + 120ms);
}
.hero__wordmark .char:hover {
  font-variation-settings: "wght" 940;
}
@media (prefers-reduced-motion: reduce) {
  .hero__wordmark .char { transition: none; }
}

.hero__tagline {
  font-family: var(--font-body);
  font-weight: var(--w-semibold);
  font-size: var(--size-small);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  opacity: 0;
  transform: translateY(10px);
  animation: tagline-in 1s var(--ease-out) forwards;
  animation-delay: 1.05s;
}

@keyframes tagline-in {
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__wordmark .char { animation: none; opacity: 1; transform: none; }
  .hero__tagline { animation: none; opacity: 1; transform: none; }
}

/* Der Abschluss-Abschnitt der Startseite (Video, Claim, Get in touch).
   Die drei Werte standen vorher inline im HTML; siehe die Notiz dort,
   warum die Video-Deckkraft dort nicht bleiben durfte. */
.hero--abschluss {
  height: 60svh;
  min-height: 22rem;
}
.hero--abschluss .hero__bg {
  opacity: 0.55;
  /* derselbe Name wie das Video der Contact-Seite: beim Seitenübergang
     über "Get in touch" wächst das eine ins andere (components.css) */
  view-transition-name: kontakt-video;
}
/* Beim Klick auf "Get in touch" mit Seitenübergang: das Video wird hell,
   alles darauf tritt zurück, bis die Contact-Seite übernimmt. */
.hero.is-video-hell .hero__bg { opacity: 1; transition: opacity 240ms linear; }
.hero.is-video-hell .hero__scrim,
.hero.is-video-hell .hero__content,
.hero.is-video-hell .grain { opacity: 0; transition: opacity 200ms linear; pointer-events: none; }
/* Der Claim in diesem Abschnitt steht sofort, er hat keinen
   Auftritt wie der auf dem oberen Hero. */
.hero__tagline--statisch { animation: none; opacity: 1; transform: none; }

/* ── Übergang "Get in touch": Video tritt nach vorn ───────────────────
   Gesetzt von transition.js auf den Abschnitt, in dem der Link steht.
   Das Video verlässt seine Rolle als Hintergrund: volle Deckkraft
   (vorher 0.55), über den Inhalt gehoben, und leicht vergrößert. Scrim,
   Korn und Inhalt treten gleichzeitig zurück, sonst läge der Text auf
   dem heranfahrenden Bild.

   Nur transform und opacity, damit die Bewegung auf dem Compositor
   bleibt — und .hero hat ohnehin overflow: hidden, das Skalieren kann
   also nicht aus dem Abschnitt laufen. Die 620ms hier müssen zu
   VIDEO_ZOOM_DAUER in transition.js passen. */
.hero.is-video-zoom .hero__bg {
  z-index: 20;
  opacity: 1;
  transform: scale(1.18);
  transition: transform 620ms var(--ease-in-out), opacity 380ms linear;
}
.hero.is-video-zoom .hero__scrim,
.hero.is-video-zoom .hero__content,
.hero.is-video-zoom .grain {
  opacity: 0;
  transition: opacity 300ms linear;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  /* kein Heranfahren; der Abschnitt bleibt einfach stehen, bis
     navigiert wird */
  .hero.is-video-zoom .hero__bg { transform: none; transition: none; }
  .hero.is-video-zoom .hero__scrim,
  .hero.is-video-zoom .hero__content,
  .hero.is-video-zoom .grain { transition: none; }
}

/* ===================================================================
   PROJECT HERO — title lives inside the cover image, not a separate
   boxy section: the two are one piece, with a scrim that guarantees
   white-on-photo contrast regardless of the page's own theme color.
   =================================================================== */
.project-hero {
  position: relative;
  /* taller since the dissolving bottom edge was removed: the picture now
     ends where it ends, so it has to carry the top of the page on its
     own rather than trailing off */
  height: 94svh;
  min-height: 30rem;
  overflow: hidden;
  background: var(--black);
  color: var(--white);
}
.project-hero__media {
  position: absolute;
  inset: 0;
}
.project-hero__media img,
.project-hero__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  position: absolute;
  inset: 0;
  transition: opacity 1.1s var(--ease-in-out);
}
.project-hero__media img.is-hidden { opacity: 0; }

/* Eine Zeichnung als Titelbild wird nicht beschnitten.

   Der Rahmen ist ein 94svh hohes Querband; ein Foto darf darin per
   object-fit: cover angeschnitten werden, eine Illustration nicht — vom
   E-Bin-Würfel wäre auf dem Telefon sonst ein senkrechter Streifen
   Kabel zu sehen und nicht das Objekt. contain zeigt sie immer ganz,
   der Grund dahinter ist ihr eigenes Creme, damit kein schwarzer Rand
   entsteht.

   Gilt über den Dateityp, nicht über eine Projektklasse: jede
   Zeichnung, die hier je landet, soll so behandelt werden. */
.project-hero__media img[src$=".svg"] {
  object-fit: contain;
  background: var(--cream);
}

/* Ein freigestelltes Objekt auf Weiss als Titelbild (E-Bin, 02.10.).

   Der Kopf wird selbst weiss: kein dunkler Verlauf (der legte sich
   über Weiss als graues Band und stiess unten hart an die Seite),
   schwarze Schrift, und die Navigation bleibt schwarz (chrome.js nimmt
   diesen Kopf von den dunklen Flächen aus). Das Objekt steht ganz und
   mittig.

   Grösse (02.10.: "viel grösser"): Hochkant und auf schmalen Fenstern
   steht der Titel unter dem Würfel, das Objekt nutzt also die volle
   Breite und den ganzen Raum zwischen Navigation und Titelblock. */
.project-hero--freigestellt { background: var(--white); color: var(--black); }
.project-hero--freigestellt .project-hero__scrim { display: none; }
.project-hero--freigestellt .project-hero__media img {
  object-fit: contain;
  background: var(--white);
  box-sizing: border-box;
  padding: 4.75rem 0 clamp(10rem, 26svh, 15rem);
}
/* Im Querformat reicht das Objekt fast bis zur Unterkante. Das geht,
   weil der Würfel unten links ausläuft: ab 80% seiner Höhe ist die
   linke Bildecke leer, genau dort steht der Titel. Erst ab 3:2, darunter
   rückte der Würfel an das N von "E-BIN" heran (bei 1024x768 gemessen). */
@media (min-aspect-ratio: 3/2) {
  .project-hero--freigestellt .project-hero__media img {
    padding: 4.75rem var(--gutter) var(--space-m);
  }
}
.project-hero--freigestellt .project-hero__content .label,
.project-hero--freigestellt .project-hero__content .label--sub { color: rgba(0, 0, 0, 0.62); }
.project-hero--freigestellt .project-hero__content h1 { color: var(--black); text-shadow: none; }

/* Eine Buch-Titelseite als Titelbild (Publications, 16.10.: Momentom).

   hero.jpg ist die Titelseite, zugeschnitten auf "Between living and
   existing." (scripts/publications-titelbild.py): ohne Kopfzeile und
   ohne MOMENTOM, das neben dem Seitentitel PUBLICATIONS unstimmig stand.
   Der Zuschnitt ist 0.88 so hoch wie breit; der Untertitel steht bei
   75.3-79.2 % der Höhe und 42-82.4 % der Breite (Mitte 62.2 %), sein
   unterer Rand also 0.183 Bildbreiten über der Unterkante.

   Querformat: das Bild steht unten bündig. Es ist mindestens 219cqh
   breit (Einheiten des Kopfes, container-type unten), damit der
   Untertitel höchstens bei 60 % der Höhe endet, und mindestens 93rem,
   damit er auch in niedrigen Fenstern 17rem über der Unterkante bleibt:
   so viel braucht der Seitentitel samt Abstand (gemessen 16.10.,
   1280x700 bis 2560x1300). Ist das Bild breiter als der Kopf, steht der
   Untertitel bei 60 % der Breite, ohne dass ein Rand frei wird (clamp).

   Hochkant und auf schmalen Fenstern steht der Seitentitel im Fluss
   unten, das Bild füllt den Raum darüber (Flex). So endet es immer über
   dem Titel, wie gross der auch gesetzt ist; der Untertitel bleibt über
   object-position im Bild. Darunter das fast schwarze Blau vom unteren
   Rand der Titelseite. */
.project-hero--titelseite { background: #0f0e1e; container-type: size; }
@media (min-aspect-ratio: 1001/800) {
  .project-hero--titelseite .project-hero__media img {
    --breite: max(100cqw, 219cqh, 93rem);
    inset: auto auto 0 auto;
    width: var(--breite);
    max-width: none;
    height: auto;
    left: clamp(calc(100cqw - var(--breite)), calc(60cqw - 0.622 * var(--breite)), 0px);
  }
}
@media (max-aspect-ratio: 5/4) {
  .project-hero--titelseite { display: flex; flex-direction: column; }
  .project-hero--titelseite .project-hero__media { position: relative; flex: 1; min-height: 0; }
  .project-hero--titelseite .project-hero__content { position: relative; }
  .project-hero--titelseite .project-hero__media img { object-position: 80% 100%; }
}

.project-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  /* top stop deepened to 0.4 (was 0.05) — the nav sitting on top is
     now plain white with no blend-mode fallback, so it needs guaranteed
     contrast against whatever the cover image happens to show there */
  background: linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.05) 18%, rgba(0,0,0,0.05) 45%, rgba(0,0,0,0.78) 100%);
}
/* No seam. The project heroes used to dissolve their lower edge into
   the page with a blurred white gradient; it softened the picture
   instead of ending it, so it was removed on the artist's note. The
   heroes are taller now to make up the presence that fade was faking.
   (initHeroDefocus, which drove it, went with it.) */

.project-hero__content {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 5;
  padding: var(--space-l) var(--gutter);
}
.project-hero__content .label { color: rgba(255, 255, 255, 0.82); margin-bottom: var(--space-2xs); }
.project-hero__content h1 {
  font-size: var(--size-h1);
  text-transform: uppercase;
  color: var(--white);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.35);
}
.project-hero__content .label--sub { margin-top: var(--space-2xs); margin-bottom: 0; color: rgba(255, 255, 255, 0.7); }
