/* ============================================
   Max Judith – Portfolio
   Grundgerüst: Variablen, Layout, Komponenten
   ============================================ */

@font-face {
  font-family: "Archivo Black";
  src: url("assets/fonts/ArchivoBlack-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Archivo Narrow";
  src: url("assets/fonts/ArchivoNarrow-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Archivo Narrow";
  src: url("assets/fonts/ArchivoNarrow-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --color-bg: #000000;
  --color-text: #f2f0ef;
  --color-highlight: #ff3300;
  --color-bg-alt: #0a0a0a;

  --font-title: "Archivo Black", Arial, sans-serif; /* große Titel/Headlines */
  --font-base: "Archivo Narrow", Arial, sans-serif; /* Fließtext, Nav, Labels */
  --line-color: rgba(255, 255, 255, 0.45); /* dünne weiße Trennlinien/Rahmen, Kontaktabzug-Look */

  --nav-height: 84px;
  --gutter: 1.5rem;
  --max-width: 1400px;
  --edge-pad: clamp(20px, 4vw, 48px); /* Rand für bildschirmfüllende Sections (Letzte Projekte, Social) */

  --transition: 0.25s ease;
}

/* Reset */
* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-base);
  line-height: 1.5;
  overflow-x: hidden;
}

img, video { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

.container {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ============================================
   Navigation
   ============================================ */

.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--nav-height);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding-inline: var(--gutter);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* Weicher Übergang an der Unterkante der Menüleiste statt hartem Schnitt */
.site-nav::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 28px;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.35), transparent);
  pointer-events: none;
}

.site-nav__logo {
  grid-column: 1; /* explizit statt Auto-Placement, siehe Kommentar bei .site-nav__end */
  justify-self: start;
  display: flex;
}

.site-nav__logo img {
  /* Logo-Datei ist sehr breit (Seitenverhältnis ~7.5:1, 2008×268px).
     Bewusst über WIDTH gesteuert (nicht height:auto/width:auto wie vorher):
     wenn stattdessen height fest und width:auto gesetzt ist, kappt die
     globale "img { max-width:100% }"-Regel auf schmalen Screens nur die
     Breite, während die feste Höhe bestehen bleibt – das Logo wirkt
     seitlich gestaucht/verzerrt (per Playwright nachgestellt: bei
     height:30px kam auf 375px-Breite nur noch ein Seitenverhältnis von
     3.7 statt 7.5 heraus). Mit definierter width + height:auto + aspect-
     ratio berechnet der Browser die Höhe dagegen korrekt aus der
     tatsächlich gerenderten (ggf. gekappten) Breite mit – bestätigt
     korrekt (Seitenverhältnis bleibt 7.5) in beiden Fällen. */
  width: 225px; /* ergibt bei diesem Seitenverhältnis rechnerisch 30px Höhe, wie bisher */
  height: auto;
  aspect-ratio: 2008 / 268;
}

@media (max-width: 700px) {
  /* ~18px Höhe – lässt neben Sprachumschalter + Burger-Button auf schmalen
     Screens genug Platz, ohne dass max-width:100% eingreifen muss. */
  .site-nav__logo img { width: 135px; }
}

.site-nav__list {
  justify-self: center;
  list-style: none;
  display: flex;
  gap: 2.5rem;
  flex-wrap: wrap;
  justify-content: center;
}

.site-nav__link {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.85rem;
  color: var(--color-text);
  transition: color var(--transition);
}

.site-nav__link:hover,
.site-nav__link:focus-visible,
.site-nav__link:active {
  color: var(--color-highlight);
}

/* Aktuelle Seite: dauerhaft in der Highlight-Farbe (Orange) statt nur beim
   Hover/Klick – zeigt "du bist hier". */
.site-nav__link[aria-current="page"] {
  color: var(--color-highlight);
}

/* Rechter Grid-Block: Sprachumschalter + Rolle + Mobile-Toggle in einer
   Flex-Reihe, damit die Navbar unabhängig davon ein 3-Spalten-Grid bleibt,
   welches der drei Kind-Elemente per Media Query aus-/eingeblendet wird.
   Wichtig: grid-column ist absichtlich fest auf 3 gesetzt (nicht dem
   Auto-Placement überlassen) – auf Mobile wird .site-nav__list per
   position:fixed aus dem Grid-Fluss genommen (siehe dort), wodurch nur
   noch 2 In-Flow-Kinder übrig bleiben. Ohne explizites grid-column würden
   Logo und dieser Block dann automatisch in die Spalten 1+2 einsortiert
   (Spalte 3 bliebe leer) – der Burger-Button landete dadurch mittig statt
   am rechten Rand. */
.site-nav__end {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.lang-switch {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

.lang-switch__btn {
  width: 22px;
  height: 15px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: none;
  cursor: pointer;
  opacity: 0.45;
  filter: grayscale(70%);
  overflow: hidden;
  transition: opacity var(--transition), filter var(--transition);
}

.lang-switch__btn svg {
  width: 100%;
  height: 100%;
  display: block;
}

.lang-switch__btn:hover,
.lang-switch__btn:focus-visible {
  opacity: 0.8;
}

.lang-switch__btn.is-active {
  opacity: 1;
  filter: none;
  border-color: var(--color-highlight);
}

.site-nav__role {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.75rem;
  opacity: 0.8;
  white-space: nowrap;
}

/* Burger-Icon statt Text-Button: 3 dünne Linien, morphen beim Öffnen zu
   einem X (reine CSS-Transforms, keine zwei Icon-Sets nötig). Der Button
   selbst bleibt 44×44px als Tapfläche (WCAG-Empfehlung), die Linien darin
   sind optisch schmaler/zentriert. */
.site-nav__toggle {
  display: none;
  position: relative; /* eigene Stacking-Ebene, siehe z-index-Kommentar unten */
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  /* .site-nav__list (das Vollbild-Menü-Overlay) hat z-index:105 und deckt
     ohne dies den unpositionierten Button optisch zu – der Button war zwar
     technisch weiter klickbar, aber unsichtbar unter der schwarzen Fläche,
     das X zum Schließen war dadurch für Max nicht zu sehen/erreichen. */
  z-index: 110;
}

.site-nav__toggle-bars {
  position: relative;
  width: 26px;
  height: 18px;
}

.site-nav__toggle-bar {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--color-text);
  transition: transform 0.3s ease, opacity 0.2s ease, background 0.2s ease;
}

.site-nav__toggle-bar:nth-child(1) { top: 0; }
.site-nav__toggle-bar:nth-child(2) { top: 8px; }
.site-nav__toggle-bar:nth-child(3) { top: 16px; }

.site-nav__toggle:hover .site-nav__toggle-bar,
.site-nav__toggle:focus-visible .site-nav__toggle-bar {
  background: var(--color-highlight);
}

.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(1) {
  top: 8px;
  transform: rotate(45deg);
}

.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(2) {
  opacity: 0;
}

.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(3) {
  top: 8px;
  transform: rotate(-45deg);
}

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

@media (max-width: 700px) {
  .site-nav__end { gap: 0.75rem; }
  .site-nav__role { display: none; }
  .site-nav__toggle {
    display: flex;
    /* an den rechten Bildschirmrand ziehen, unabhängig vom normalen
       Nav-Innenabstand (--gutter) – gleicher Trick wie bei den
       Social-Icons (.social-rail), die ebenfalls dicht an der Kante sitzen. */
    margin-inline-end: calc(-1 * var(--gutter) + 0.75rem);
  }

  .site-nav__list {
    position: fixed;
    inset: 0;
    z-index: 105;
    justify-self: auto; /* überschreibt justify-self:center der Desktop-Grid-Regel,
                            sonst schrumpft die Fixed-Box auf Inhaltsbreite */
    flex-direction: column;
    align-items: center; /* horizontal mittig (li ist sonst block-breit und
                             linksbündig, siehe .site-nav__link darunter) */
    justify-content: center; /* vertikal mittig */
    gap: 2.25rem;
    width: 100%;
    height: 100vh;
    background: rgba(0, 0, 0, 0.92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    transform: translateX(100%);
    transition: transform var(--transition);
  }

  .site-nav__list.is-open { transform: translateX(0); }

  /* Deutlich größer als die 0.85rem-Desktop-Nav – hier ist es die einzige
     Aufgabe des Overlays, klar lesbare Tap-Ziele zu zeigen. */
  .site-nav__list .site-nav__link {
    font-size: clamp(1.75rem, 8vw, 2.75rem);
    letter-spacing: 0.06em;
  }
}

/* ============================================
   Social Sidebar (fixiert, rechter Rand)
   ============================================ */

.social-rail {
  position: fixed;
  right: 1.25rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.social-rail a {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text);
  transition: color var(--transition);
}

.social-rail a:hover,
.social-rail a:focus-visible {
  color: var(--color-highlight);
}

.social-rail svg { width: 20px; height: 20px; fill: currentColor; }

@media (max-width: 700px) {
  .social-rail {
    right: 0.75rem;
    gap: 1rem;
  }
  .social-rail svg { width: 18px; height: 18px; }
}

/* ============================================
   Back-to-top Button
   ============================================ */

.back-to-top {
  position: fixed;
  bottom: 2.5rem;
  left: 2rem;
  z-index: 90;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 2px solid var(--color-highlight);
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(6px);
  color: var(--color-highlight);
  font-size: 1.1rem;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition);
}

.back-to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* ============================================
   Hero (Vollformat-Video)
   ============================================ */

.hero {
  position: relative;
  height: 100svh;
  width: 100%;
  overflow: hidden;
}

.hero video,
.hero .media-placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* YouTube-Embed randlos ausfüllend (statt Letterboxing): klassischer
   "Fullscreen-Background-Video"-Trick, Video wird größer als der Hero
   skaliert und mittig zugeschnitten. Kein Klick möglich (rein dekorativ). */
.hero .hero__video {
  position: absolute;
  top: 50%;
  left: 50%;
  right: auto;
  bottom: auto;
  width: 100vw;
  height: 56.25vw; /* 16:9 */
  min-height: 100%;
  min-width: 177.78vh; /* 16:9 */
  max-width: none;
  transform: translate(-50%, -50%);
  pointer-events: none;
  border: 0;
}

.hero__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  text-align: center;
  padding-bottom: 6rem;
  background: linear-gradient(to top, rgba(0,0,0,0.75), transparent 40%);
  pointer-events: none; /* Klicks sollen zur Facade/zum Pause-Button durchgereicht werden */
}

/* Pause/Stopp-Kontrolle für das autoplaufende Showreel (WCAG 2.2.2) */
.hero__pause {
  position: absolute;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 2;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-text);
  border-radius: 50%;
  background: rgba(0,0,0,0.4);
  color: var(--color-text);
  font-size: 0.7rem;
  cursor: pointer;
}

.hero__pause[hidden] { display: none; }

.hero__pause:hover,
.hero__pause:focus-visible {
  background: rgba(0,0,0,0.7);
}

/* ============================================
   YouTube-Facade: Vorschaubild + Play-Button statt
   automatisch ladendem Embed (DSGVO – kein Laden ohne Klick/Zustimmung)
   ============================================ */

.yt-facade {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 0.85rem;
  margin: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.yt-facade__thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.yt-facade:focus-visible {
  outline: 2px solid var(--color-highlight);
  outline-offset: -2px;
}

.yt-facade.is-loaded {
  display: none;
}

/* ============================================
   Cookie-/Consent-Banner: externe Inhalte (YouTube)
   werden erst nach Klick oder Zustimmung geladen
   ============================================ */

.consent-banner {
  position: fixed;
  left: 1rem;
  right: auto;
  bottom: 1rem;
  z-index: 500;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  max-width: 420px;
  padding: 1rem 1.25rem;
  background: #fff;
  color: #000;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
}

.consent-banner[hidden] {
  display: none;
}

.consent-banner__text {
  flex: 1 1 260px;
  font-size: 0.75rem;
  line-height: 1.5;
  color: #000;
}

.consent-banner__text a {
  color: #000;
  text-decoration: underline;
}

.consent-banner__actions {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
}

.consent-banner__btn {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
  padding: 0.55rem 1rem;
  border: 1px solid #000;
  background: #000;
  color: #fff;
  cursor: pointer;
}

.consent-banner__btn--accept {
  background: #000;
  border-color: #000;
  color: #fff;
}

.hero__name {
  font-family: var(--font-title);
  font-size: clamp(1.8rem, 5vw, 3.5rem);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* Desktop: eine Zeile "Director of Photography · Drone Operator · Content
   Creation" mit Mittelpunkt-Trennern, nebeneinander. Mobile (siehe
   @media max-width:700px weiter unten): als Liste untereinander statt
   nebeneinander, da nebeneinander auf schmalen Viewports zu eng wird. */
.hero__roles {
  list-style: none;
  margin-top: 0.6rem;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
}

.hero__roles li {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-highlight);
  font-size: clamp(0.8rem, 1.5vw, 1rem);
}

.hero__roles li:not(:last-child)::after {
  content: "\00B7";
  margin: 0 0.6em;
}

@media (max-width: 700px) {
  .hero__roles {
    flex-direction: column;
    gap: 0.35rem;
  }

  .hero__roles li:not(:last-child)::after {
    content: none;
  }
}

/* ============================================
   Platzhalter für Video/Foto (bis echte Medien da sind)
   ============================================ */

.media-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(
    45deg,
    var(--color-bg-alt),
    var(--color-bg-alt) 10px,
    #222 10px,
    #222 20px
  );
  border: 1px dashed var(--color-highlight);
  color: var(--color-text);
  font-size: 0.85rem;
  text-align: center;
  padding: 1rem;
  min-height: 220px;
}

/* Sobald echtes Medium eingebunden ist, nie den Platzhalter-Look
   (Streifen/gestrichelter Rand) durchscheinen lassen */
video.media-placeholder,
img.media-placeholder,
iframe.media-placeholder {
  background: none;
  border: 0;
  padding: 0;
}

/* ============================================
   Sections generell
   ============================================ */

/* Einheitliche Sektionsgröße: alle Sections sind gleich groß (min. 70vh,
   Inhalt vertikal zentriert), außer explizit anders definiert (z. B. Hero/
   Showreel mit voller Bildschirmhöhe). */
section {
  min-height: 70vh;
  padding-block: clamp(3rem, 8vw, 6rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.section-title {
  font-family: var(--font-title);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: clamp(1.4rem, 3vw, 2.2rem);
  margin-bottom: 1.5rem;
}

/* Trennlinie neben dem Titel (nicht mehr darunter), auf gleicher Höhe wie
   der Titeltext, in der Highlightfarbe. Bricht auf schmalen Viewports in
   eine zweite Zeile um, falls kein Platz mehr daneben ist. */
.section-title--divider {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(20px, 3vw, 40px);
}

.section-title--divider::after {
  content: "";
  display: block;
  width: clamp(300px, 25vw, 500px);
  height: 1px;
  background: var(--color-highlight);
}

/* About-Teaser (Startseite): Hintergrundbild, Text links */
.about-teaser {
  position: relative;
  min-height: 70vh;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  padding-block: 0;
}

.about-teaser .media-placeholder {
  position: absolute;
  inset: 0;
  min-height: unset;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.about-teaser::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.55) 45%, rgba(0,0,0,0.1) 100%);
}

.about-teaser__content {
  position: relative;
  z-index: 1;
  padding-block: clamp(2rem, 6vw, 4rem);
  /* Gleicher Titel-Startpunkt wie bei .container-Sections: bei schmalen
     Viewports einfach --gutter, bei breiten der linke Rand, den ein
     zentrierter Container mit --max-width dort hätte. Text füllt (wie
     alle anderen Sections) den Rest der Breite bis zum rechten Rand. */
  padding-inline-start: max(var(--gutter), calc((100% - var(--max-width)) / 2 + var(--gutter)));
  padding-inline-end: var(--gutter);
}

/* Breite an der Stelle gekappt, an der vorher die Jobbezeichnungen-Zeile
   endete – Text soll nicht über das Gesicht im Hintergrundbild laufen. */
.about-teaser__content p {
  margin-top: 1rem;
  max-width: 460px;
}
.about-teaser__content .section-title { margin-bottom: 0; }

.about-teaser__companies {
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--color-highlight);
}

.about-teaser__content a {
  display: inline-block;
  margin-top: 1.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--color-highlight);
}

/* Grid für Work/Photography/Best-of */
.media-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}

@media (min-width: 600px) {
  .media-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1000px) {
  .media-grid { grid-template-columns: repeat(3, 1fr); }
}

.media-grid__item .media-placeholder { min-height: 260px; }

/* Arbeiten (Startseite): bildschirmfüllend mit etwas Luft zum Rand,
   Kacheln im 16:9, dünne Trennlinien wie ein Kontaktabzug/Sucher-Overlay,
   Label pro Frame. */
.work-preview {
  padding-inline: var(--edge-pad);
}

/* Nur der Titel wird auf die gemeinsame Section-Titel-Position gerückt
   (gleiche Formel wie .about-teaser__content), der Rest der Section
   (Video-Grid) bleibt bildschirmfüllend/responsiv wie gehabt. */
.work-preview .section-title {
  margin-inline-start: calc(max(var(--gutter), calc((100vw - var(--max-width)) / 2 + var(--gutter))) - var(--edge-pad));
}

/* "Letzte Projekte": auf dem Desktop ein normales, formatfüllendes Grid
   (3 Spalten × 2 Zeilen, wie ursprünglich) – KEIN Slider. Erst auf schmalen
   (mobilen) Viewports wird daraus die per Wisch/Ziehen bedienbare
   horizontale Slideshow (siehe @media (max-width:700px) unten). Beide
   Zeilen (.work-preview__row) sind auf Desktop per display:contents
   "unsichtbar" fürs Layout – ihre 6 Kacheln landen direkt als Kinder im
   Grid von .work-preview__slideshow und ordnen sich automatisch zu
   3×2 an. Video-Auswahl läuft wie überall sonst auf der Seite über Klick
   auf Vorschaubild/Play-Button (initFacades()). */
.work-preview__slideshow-wrap {
  --wp-tile-width: clamp(220px, 26vw, 320px);
  position: relative;
  margin-top: 28px;
}

.work-preview__slideshow {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}

.work-preview__slideshow:focus-visible {
  outline: 2px solid var(--color-highlight);
  outline-offset: 2px;
}

.work-preview__row {
  display: contents;
}

.work-preview__veil {
  display: none;
}

/* Mobile: Grid weicht der horizontalen Drag-Slideshow (siehe
   initWorkPreviewSlideshow() in script.js). Bedienung: Trackpad/Shift+
   Mausrad funktioniert nativ über overflow-x; für normale Maus ohne
   Trackpad übernimmt initWorkPreviewSlideshow() Klick-Ziehen
   (Pointer-Events), Touch-Wischen funktioniert nativ. Links/rechts-Verlauf
   (.work-preview__veil) zeigt an, wenn noch mehr Inhalt in die jeweilige
   Richtung wartet. */
@media (max-width: 700px) {
  .work-preview__slideshow {
    display: flex;
    flex-direction: column;
    gap: 28px;
    padding-bottom: 14px; /* Platz für die dickere Scrollbar, siehe unten */
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    cursor: grab;
    -webkit-overflow-scrolling: touch;
    /* Sichtbare, gut lesbare Scrollbar statt komplett ausgeblendet (auf
       Max' Wunsch höher/deutlicher als der Browser-Standard) – gleiches
       Prinzip wie .shorts-slider, nur dicker. */
    scrollbar-width: auto;
    scrollbar-color: var(--color-highlight) rgba(255, 255, 255, 0.12);
  }

  .work-preview__slideshow::-webkit-scrollbar {
    height: 10px;
  }

  .work-preview__slideshow::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.12);
    border-radius: 5px;
  }

  .work-preview__slideshow::-webkit-scrollbar-thumb {
    background: var(--color-highlight);
    border-radius: 5px;
    border: 2px solid var(--color-bg); /* etwas "Luft" zum Track, wirkt schlanker/klarer */
  }

  .work-preview__slideshow::-webkit-scrollbar-thumb:hover {
    background: var(--color-text);
  }

  .work-preview__slideshow.is-dragging {
    cursor: grabbing;
    scroll-snap-type: none;
  }

  .work-preview__row {
    display: flex;
    gap: 28px;
  }

  /* Feste Kachelbreite statt 1fr-Grid-Spalten – notwendig, damit der Flex-
     Container horizontal überläuft (scrollbar wird) statt die Kacheln
     zusammenzuquetschen. scroll-snap-align:start, damit Kacheln beim
     Scrollen sauber am linken Rand einrasten. */
  .work-preview__row .media-grid__item {
    flex: 0 0 var(--wp-tile-width);
    width: var(--wp-tile-width);
    scroll-snap-align: start;
  }

  .work-preview__veil {
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    width: clamp(28px, 6vw, 90px);
    pointer-events: none;
    z-index: 2;
    opacity: 0;
    transition: opacity 0.3s ease;
  }

  .work-preview__veil--left {
    left: 0;
    background: linear-gradient(to right, var(--color-bg), transparent);
  }

  .work-preview__veil--right {
    right: 0;
    background: linear-gradient(to left, var(--color-bg), transparent);
  }

  .work-preview__veil.is-visible {
    opacity: 1;
  }
}

/* "Letzte Projekte"-Überschrift verlinkt zur Work-Seite. Bewusst OHNE
   permanenten border-bottom (wie bei .work-preview__more/"Mehr über mich"):
   .section-title--divider hat schon eine eigene Trennlinie (::after), die
   auf schmalen Screens mangels Platz UNTER den Titel umbricht (siehe
   Kommentar dort) – zusätzlich noch eine Underline direkt am Text hätte
   dort wie zwei Linien übereinander ausgesehen (von Max gemeldet). Nur
   Opacity-Fade bei Hover/Fokus als Klick-Hinweis, wie bei den Nav-Links. */
.work-preview__title-link {
  transition: opacity var(--transition);
}

.work-preview__title-link:hover,
.work-preview__title-link:focus-visible {
  opacity: 0.7;
}

/* "More Work"-Link: stand vorher absolut über dem unteren Verlauf der
   Section (die es seit der Slideshow-Umstellung nicht mehr gibt) – jetzt
   normal im Fluss, zentriert unter der Slideshow. */
.work-preview__more {
  display: block;
  width: fit-content;
  margin: 1.5rem auto 0;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--color-highlight);
}

.work-preview .media-grid__item {
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  position: relative;
}

/* Generisches Label (Nummer + Titel) – für Frame-Boxen überall im Stil
   wiederverwendbar, nicht nur im Arbeiten-Grid */
/* Frame Header = der Bereich zwischen der oberen Linie des Frame-Containers
   (.frame::after, oben) und der unteren Trennlinie des Frame-Headers
   (.frame-label::after). .frame selbst bringt schon 10px Padding mit (Regel:
   Inhalt hält überall mind. 10px Abstand zu den Linien), das oben also schon
   vor dem Label sitzt. Damit Titel/Play-Button unabhängig vom Inhalt exakt
   mittig zwischen BEIDEN Linien stehen (nicht nur innerhalb der Label-Box),
   wird das durch .frame vorgegebene obere Padding hier unten wieder
   abgezogen – padding-top + padding-bottom bleiben in Summe gleich, nur die
   Verteilung gleicht die 10px von oben aus. */
.frame-label {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: calc(1.2rem - 10px) 1rem 1.2rem;
  position: relative;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.8rem;
}

.frame-label::after {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 0;
  height: 1px;
  background: var(--line-color);
}

.frame-label__index { opacity: 0.5; }

/* Play-Icon im Frame-Header: als ganz normales Flex-Kind von .frame-label
   (align-items:center greift automatisch, kein Offset-Hack nötig) rechts
   ausgerichtet über margin-inline-start:auto. Rein dekorativ (aria-hidden)
   – die eigentliche Klickfläche bleibt das ganze Thumbnail (.yt-facade). */
.frame-label__play {
  margin-inline-start: auto;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--color-text);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}

/* Play-Dreieck (Standardzustand: Video läuft nicht) */
.frame-label__play::before {
  content: "";
  border-style: solid;
  border-width: 5px 0 5px 8px;
  border-color: transparent transparent transparent currentColor;
  margin-left: 2px;
}

/* Läuft das Video (per Klick auf Thumbnail oder diesen Button gestartet),
   zeigt der Button statt des Dreiecks ein Stopp-Quadrat und bleibt in der
   Highlightfarbe – ein weiterer Klick stoppt das Video wieder. */
.frame-label__play.is-active {
  color: var(--color-highlight);
  border-color: var(--color-highlight);
}

.frame-label__play.is-active::before {
  width: 10px;
  height: 10px;
  margin-left: 0;
  border: none;
  background: currentColor;
}

/* Button färbt sich in der Highlightfarbe, sobald die Maus über dem Video
   (dem ganzen Thumbnail-Klickbereich) steht, er selbst gehovert/fokussiert
   wird – nicht nur beim direkten Hover auf das Icon selbst. */
.frame-label__play:hover,
.frame-label__play:focus-visible,
.frame:has(.yt-facade:hover) .frame-label__play,
.frame:has(.yt-facade:focus-visible) .frame-label__play {
  color: var(--color-highlight);
  border-color: var(--color-highlight);
}

.frame-label__play:focus-visible {
  outline: 2px solid var(--color-highlight);
  outline-offset: 2px;
}

.work-preview .media-grid__item .media-placeholder {
  min-height: unset;
}

/* Innerer Video-Bereich einer Frame-Box – 16:9, direkt unter dem Label,
   durch dessen Trennlinie (.frame-label::after) vom Titel abgesetzt */
.frame-media {
  position: relative;
  aspect-ratio: 16 / 9;
}

/* Vollständiger Rahmen um eine Box (Video, Kontaktformular, …) – die vier
   Linien berühren sich an den Ecken nie, ~7px Abstand. Der Inhalt hält
   selbst mind. 10px Abstand zu den Linien (Padding auf .frame). */
.frame {
  position: relative;
  padding: 10px;
}

.frame::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(var(--line-color), var(--line-color)),
    linear-gradient(var(--line-color), var(--line-color)),
    linear-gradient(var(--line-color), var(--line-color)),
    linear-gradient(var(--line-color), var(--line-color));
  background-size:
    calc(100% - 14px) 1px,
    calc(100% - 14px) 1px,
    1px calc(100% - 14px),
    1px calc(100% - 14px);
  background-position:
    7px 0,
    7px 100%,
    0 7px,
    100% 7px;
}

.work-preview .media-grid__item video,
.work-preview .media-grid__item img,
.work-preview .media-grid__item iframe {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border: 0;
  background: none;
}

/* ============================================
   Social (Startseite): YouTube- und Instagram-Profilkarte,
   jede Spalte eigenständig gestaltet, eigenes Frame-Label.
   Bildschirmfüllend wie "Letzte Projekte" (nicht mehr .container),
   nur der Titel wird auf die gemeinsame Section-Titel-Position gerückt. */
.social-section {
  padding-inline: var(--edge-pad);
}

.social-section .section-title {
  margin-inline-start: calc(max(var(--gutter), calc((100vw - var(--max-width)) / 2 + var(--gutter))) - var(--edge-pad));
}

.social-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-top: 1.25rem;
  /* Jede Karte behält ihre eigene, vom Inhalt bestimmte Höhe – die
     Inhaltsgröße (Shorts-Bereich / Screenshot) wird stattdessen direkt
     über ein gemeinsames Seitenverhältnis angeglichen, siehe
     .shorts-slider-wrap weiter unten. */
  align-items: start;
}

/* Grid-Kinder schrumpfen ohne min-width:0 nicht unter die Inhaltsbreite
   ihrer Kinder – der horizontal scrollende Shorts-Slider würde sonst
   seine Spalte aufblähen und Instagram an den Rand drängen. */
.social-columns > .frame {
  min-width: 0;
}

@media (max-width: 700px) {
  .social-columns {
    grid-template-columns: 1fr;
  }
}

.social-card__body {
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
  padding: 0.85rem 1.75rem 2rem;
}

.frame.social-card {
  display: flex;
  flex-direction: column;
}

.social-card__profile {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: fit-content;
  transition: opacity var(--transition);
}

.social-card__profile:hover,
.social-card__profile:focus-visible {
  opacity: 0.75;
}

.social-card__profile:hover .social-card__handle,
.social-card__profile:focus-visible .social-card__handle {
  color: var(--color-highlight);
}

.social-card__icon {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  color: var(--color-text);
}

.social-card__icon svg { width: 100%; height: 100%; fill: currentColor; }

.social-card__handle {
  font-family: var(--font-base);
  font-weight: 700;
  letter-spacing: 0.03em;
  font-size: 1.05rem;
}

/* CTA-Button – gleiche Optik wie der Instagram-Button (Rahmen + Fläche
   statt reiner Unterstreichung) */
.social-card__cta {
  align-self: center;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.8rem;
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--color-text);
  background: rgba(0, 0, 0, 0.4);
  transition: border-color var(--transition), background var(--transition);
}

.social-card__cta:hover,
.social-card__cta:focus-visible {
  border-color: var(--color-highlight);
}

/* YouTube: horizontaler Shorts-Slider (9:16-Kacheln). Seitenverhältnis
   entspricht exakt dem des Instagram-Screenshots (1200×778), damit die
   Inhaltsgröße beider Felder bei gleicher Spaltenbreite immer gleich groß
   ist – unabhängig davon, wie viele Kacheln dabei ohne Scrollen sichtbar
   sind (auch wenn das nur 3 sind). */
.shorts-slider-wrap {
  position: relative;
  aspect-ratio: 1200 / 778;
  /* Hart gedeckelt: egal was der Inhalt (z. B. lange Video-Titel) an
     eigener Höhe verlangt, sichtbar bleibt exakt die Höhe, die sich aus
     dem Seitenverhältnis ergibt – identisch zur Höhe des IG-Screenshots. */
  overflow: hidden;
}

/* Verlauf an beiden Seiten, deutet weitere (bereits gescrollte/kommende)
   Shorts an – links in Schwarz, rechts in CI-Orange */
.shorts-slider-wrap::before,
.shorts-slider-wrap::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0.35rem;
  width: clamp(36px, 10vw, 90px);
  pointer-events: none;
  z-index: 1;
}

.shorts-slider-wrap::before {
  left: 0;
  background: linear-gradient(to right, var(--color-bg), transparent);
}

.shorts-slider-wrap::after {
  right: 0;
  background: linear-gradient(to left, var(--color-highlight), transparent);
}

.shorts-slider {
  display: flex;
  height: 100%;
  gap: 0.75rem;
  overflow-x: auto;
  padding-bottom: 0.35rem;
  scrollbar-width: thin;
  scrollbar-color: var(--color-highlight) transparent;
}

.shorts-slider::-webkit-scrollbar {
  height: 4px;
}

.shorts-slider::-webkit-scrollbar-track {
  background: transparent;
}

.shorts-slider::-webkit-scrollbar-thumb {
  background: var(--color-highlight);
  border-radius: 4px;
}

.shorts-slider::-webkit-scrollbar-thumb:hover {
  background: var(--color-text);
}

.shorts-slider__status {
  font-size: 0.85rem;
  opacity: 0.6;
}

.shorts-slider__item {
  flex: 0 0 auto;
  width: auto;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.shorts-slider__thumb-wrap {
  display: block;
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: auto;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: var(--color-bg-alt);
}

.shorts-slider__thumb-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.shorts-slider__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 0.4rem;
  font-size: 0.72rem;
  line-height: 1.3;
  opacity: 0.75;
}

/* Instagram: statischer Screenshot des Profils statt Live-Feed, verlinkt
   aufs echte Profil. Button sitzt jetzt darunter (.social-card__cta,
   gleiche Struktur wie beim YouTube-Feld), nicht mehr als Overlay auf dem
   Bild – so sind beide Spalten exakt gleich groß. */
.instagram-preview {
  display: block;
  overflow: hidden;
}

.instagram-preview__img {
  width: 100%;
  height: auto;
  display: block;
  filter: saturate(0.9);
  transition: transform var(--transition), filter var(--transition);
}

.instagram-preview:hover .instagram-preview__img,
.instagram-preview:focus-visible .instagram-preview__img {
  transform: scale(1.03);
  filter: saturate(1);
}

/* ============================================
   Katalog-Liste (Work/Photography): nummeriert,
   durch dünne helle Linien getrennt – Kontaktabzug-Look
   ============================================ */

.catalog {
  border-top: 1px solid var(--line-color);
}

.catalog__row {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  padding-block: 1.1rem;
  border-bottom: 1px solid var(--line-color);
  transition: opacity var(--transition);
}

.catalog__row:hover { opacity: 0.7; }

.catalog__index {
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.85rem;
  opacity: 0.5;
  width: 2rem;
  flex-shrink: 0;
}

.catalog__title {
  flex: 1;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: clamp(0.95rem, 2vw, 1.15rem);
}

.catalog__meta {
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.6;
  white-space: nowrap;
}

/* Utility: soft-focus/entsättigter "analoger" Look für echte Fotos,
   sobald sie eingebunden werden (auf <img> anwenden) */
.media-photo {
  filter: saturate(0.85) contrast(0.95);
}

/* ============================================
   About-Seite
   ============================================ */

/* Intro: gleiches Muster wie der Showreel-Hero auf der Startseite
   (.hero) – Vollformat 100svh, Bild/Video randlos, Verlauf + Titel unten
   zentriert. Aktuell ein Foto als Platzhalter (.about-hero__media);
   .media-photo sorgt schon für den entsättigten "analogen" Look. Sobald
   das Bilder-Video fertig geschnitten ist, wird hier aus dem <img> ein
   <iframe>/<video> nach dem gleichen Muster wie #video-showreel. */
.about-hero {
  position: relative;
  height: 100svh;
  width: 100%;
  overflow: hidden;
}

.about-hero__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about-hero__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  text-align: center;
  padding-bottom: 6rem;
  background: linear-gradient(to top, rgba(0,0,0,0.75), transparent 40%);
}

.about-hero__title {
  font-family: var(--font-title);
  font-size: clamp(1.8rem, 5vw, 3.5rem);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* Skill Tree: Hintergrund in diagonal geschnittene Spalten gesplittet,
   je eine Spalte = ein Skill. Jede Spalte ist ein absolut positioniertes
   Panel über die volle Fläche von .skilltree__panels, per clip-path auf
   ein Trapez zugeschnitten (--st/--et = Start/Ende oben, --sb/--eb =
   Start/Ende unten, in % der Breite) – so entstehen durchgängige, parallel
   verlaufende Diagonalen statt gerader Spaltengrenzen. Foto liegt in Ruhe
   oben, Video blendet sich beim Hover/Fokus ein und spielt nur so lange. */
.skilltree {
  padding-inline: var(--edge-pad);
}

.skilltree .section-title {
  margin-inline-start: calc(max(var(--gutter), calc((100vw - var(--max-width)) / 2 + var(--gutter))) - var(--edge-pad));
}

.skilltree__panels {
  position: relative;
  margin-top: 28px;
  /* Nochmal um ca. 1/4 größer (480/61.3vw/827px * 1.25), dann um ca. 1/8 reduziert
     (600/76.6vw/1034px * 0.875) – darf ruhig groß sein */
  height: clamp(525px, 67vw, 905px);
  isolation: isolate; /* eigener Stacking-Context, damit z-index beim Hover nicht mit anderen Sections kollidiert */
}

.skilltree__panel {
  position: absolute;
  inset: 0;
  clip-path: polygon(var(--st) 0%, var(--et) 0%, var(--eb) 100%, var(--sb) 100%);
  overflow: hidden;
  cursor: pointer;
  transform-origin: var(--tx, 50%) 50%;
  transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1), clip-path 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.skilltree__panel:hover,
.skilltree__panel:focus-within {
  transform: scale(1.06);
  z-index: 2;
}

/* Wichtig: Bild/Video wird NICHT über die volle Panels-Breite gelegt,
   sondern nur über die eigene Spalten-Box (--bx/--bw, in % der
   .skilltree__panels-Breite, siehe Inline-Style je Panel). Würde das Bild
   die volle Breite füllen, läge (bei object-fit:cover) jedes Foto 1:1 über
   allen 3 Spalten – der schräge clip-path der jeweiligen Spalte würde dann
   nur einen schmalen, meist willkürlichen Ausschnitt davon zeigen, und die
   Person darauf könnte in einer ganz anderen Spalte "landen" als gedacht.
   Über die eigene, schmalere Box greift object-fit:cover dagegen wie ein
   normaler Bildausschnitt dieser einen Spalte, und object-position (--ox/
   --oy) lässt sich sinnvoll nutzen, um die Person mittig ins Bild zu holen. */
.skilltree__img,
.skilltree__video {
  position: absolute;
  top: 0;
  left: var(--bx, 0%);
  width: var(--bw, 100%);
  height: 100%;
  object-fit: cover;
  object-position: var(--ox, 50%) var(--oy, 50%);
  filter: saturate(0.85) contrast(0.95);
}

.skilltree__video {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.skilltree__panel:hover .skilltree__video,
.skilltree__panel:focus-within .skilltree__video,
.skilltree__panel.is-playing .skilltree__video {
  opacity: 1;
}

/* Ein fixes "left" würde bei den schräg geschnittenen Spalten oft außerhalb
   des sichtbaren (clip-path) Bereichs landen und verschwinden. Stattdessen
   an --tx ausgerichtet: das ist bereits die horizontale Mitte der Spalte auf
   halber Panel-Höhe (siehe Inline-Style je Panel, gleiche Variable wie beim
   transform-origin fürs Hover-Scaling) – zusammen mit top:50% steht der Titel
   so mittig in seiner Spalte statt wie bisher unten. Alle drei Titel nutzen
   dieselbe Größe (einheitlich, unabhängig von der Textlänge); --label-size
   bleibt als optionales Pro-Panel-Override verfügbar, falls ein künftiger
   Titel zu lang für seine Spalte wird und einzeln verkleinert werden muss. */
.skilltree__label {
  position: absolute;
  top: 50%;
  left: var(--tx, 50%);
  transform: translate(-50%, -50%);
  z-index: 1;
  white-space: nowrap;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: var(--label-size, clamp(0.85rem, 1.75vw, 1.6rem));
  color: var(--color-text);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.85);
}

@media (max-width: 700px) {
  /* Panels werden gestapelt statt nebeneinander. Die diagonale Formsprache
     bleibt erhalten, nur um 90° gedreht: statt schräger linker/rechter
     Kanten (Spalten, Desktop) jetzt schräge oberer/unterer Kanten (Zeilen).
     --sk-slant bestimmt die Schräge relativ zur eigenen Panel-Höhe – ein
     einzelner, für alle vier Panels gleicher Wert (anders als die Desktop-
     --st/--et/--eb/--sb-Werte je Panel, die dort für nahtlos durchlaufende
     Diagonalen zwischen den Spalten sorgen; hier stehen die Panels ohnehin
     einzeln mit Gap dazwischen, ein durchgängiger Verlauf ist nicht nötig). */
  .skilltree__panels {
    height: auto;
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }

  .skilltree__panel {
    --sk-slant: 15%;
    position: relative;
    clip-path: polygon(0% var(--sk-slant), 100% 0%, 100% calc(100% - var(--sk-slant)), 0% 100%);
    height: 260px;
    transform-origin: center;
  }

  /* Titel bleibt mittig im Panel statt an --tx (das ist ein
     Desktop-Diagonalwert, hier ohne Bedeutung). */
  .skilltree__label {
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }

  /* Jedes Panel ist jetzt eine eigene, volle Breite (siehe Clip-Path oben) –
     Bild/Video soll hier wieder die ganze Breite füllen statt der schmalen
     Desktop-Spalten-Box. */
  .skilltree__img,
  .skilltree__video {
    left: 0;
    width: 100%;
  }

  /* Scroll-Trigger (siehe initSkillTreeScrollTrigger() in script.js) setzt
     dieselbe .is-playing-Klasse wie sonst der Hover – Opacity-Übergang für
     das Video ist bereits weiter oben (nicht Mobile-spezifisch) definiert. */
}

/* "Behind the Szenes"-Sektion: drei durchlaufende Filmstreifen-Reihen
   ("Marquee") aus BTS-Fotos, jede Kachel im echten Mittelformat-Dia-Rähmchen
   (Grafik: Mittelformt-Frame-Analog.png). Technik pro Kachel: Foto liegt
   unten (object-fit:cover, per inset auf das gemessene Grünfläche-Fenster
   der Rahmengrafik positioniert), die freigestellte Rahmengrafik (Grün per
   Chroma-Key zu transparent gemacht, siehe frame-analog-window.png) liegt
   als zweites <img> exakt darüber – so "verdeckt" das Foto nur die
   ehemalige Grünfläche, der Rest bleibt vom Rahmen maskiert.
   Jede Reihe verdoppelt ihre Kachel-Liste im Markup und animiert per
   transform: translateX(0 → -50% bzw. -50% → 0) – dadurch entsteht ein
   nahtloser Endlos-Loop ohne sichtbaren Sprung. Reihe 1+3 laufen links→
   rechts, Reihe 2 rechts→links (siehe Keyframes unten). */
.about-gallery {
  padding-inline: var(--edge-pad);
  min-height: unset;
  justify-content: flex-start;
}

.about-gallery .section-title {
  margin-inline-start: calc(max(var(--gutter), calc((100vw - var(--max-width)) / 2 + var(--gutter))) - var(--edge-pad));
}

.about-gallery__marquee {
  --row-h: clamp(120px, 12.5vw, 210px);
  margin-top: 28px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.about-gallery__row-track {
  overflow: hidden;
  width: 100%;
}

.about-gallery__row {
  display: flex;
  width: max-content;
  /* Drei Reihen bewusst unterschiedlich schnell (60s/95s/75s), damit die
     Bewegung nicht synchron wirkt, sondern organischer/zufälliger. */
  animation: bts-scroll-ltr 60s linear infinite;
}

.about-gallery__row--rtl {
  animation-name: bts-scroll-rtl;
  animation-duration: 95s;
}

.about-gallery__row--slow {
  animation-duration: 75s;
}

@keyframes bts-scroll-ltr {
  from { transform: translateX(-50%); }
  to { transform: translateX(0); }
}

@keyframes bts-scroll-rtl {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Bewusste Ausnahme von der sonst guten Praxis, Animationen bei
   "Bewegung reduzieren" abzuschalten: Max möchte, dass das BTS-Laufband
   auf allen Geräten immer läuft, unabhängig von dieser Systemeinstellung
   (auf seinen expliziten Wunsch, nach Rückfrage/Hinweis auf den
   Accessibility-Trade-off). */

.about-gallery__tile {
  position: relative;
  flex: none;
  height: var(--row-h);
  aspect-ratio: 540 / 360; /* Seitenverhältnis der Rahmengrafik */
}

.about-gallery__tile-photo {
  position: absolute;
  display: block;
  /* Inset = das per Chroma-Key vermessene Grünflächen-Fenster der
     Rahmengrafik (in % von Breite/Höhe der Grafik: 540×360px). */
  inset: 5.3% 7% 6.4% 9.1%;
  width: calc(100% - 9.1% - 7%);
  height: calc(100% - 5.3% - 6.4%);
  object-fit: cover;
  filter: saturate(0.85) contrast(0.95);
}

.about-gallery__tile-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}

/* Wiederverwendeter Text-Baustein für den Link – aktuell in
   .company-showcase__info verwendet (COU2IN/FrameFactory), Klassenname
   bewusst allgemein gehalten für weitere mögliche Wiederverwendung.
   (Die frühere .about-company__heading-Regel für die Firmennamen-Überschrift
   ist entfallen, seit die Überschriften entfernt wurden – das Logo
   übernimmt diese Funktion jetzt allein.) */
.about-company__link {
  display: inline-block;
  margin-top: 1.5rem;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--color-highlight);
}

/* Company Showcase (COU2IN / FrameFactory): eigene Vollformat-Sektion in
   Skill-Tree-Größe. Linkes/rechtes Drittel = schwarze Fläche mit Logo +
   Text, restliche 2/3 = Kachel-Mosaik aus Fotos. .company-showcase--reverse
   spiegelt die Seiten einfach über die Reihenfolge der beiden Panels im
   Markup (kein flex-direction:row-reverse nötig) – nur die Verlaufsrichtung
   des Übergangs muss dafür extra gespiegelt werden (siehe unten). */
.company-showcase {
  padding-inline: var(--edge-pad);
  min-height: unset;
  justify-content: flex-start;
}

.company-showcase__panels {
  display: flex;
  flex-wrap: wrap;
  /* gleiche Höhe wie .skilltree__panels, siehe dort (um 1/8 reduziert) */
  height: clamp(525px, 67vw, 905px);
  background: #000;
  isolation: isolate; /* eigener Stacking-Context, wie beim Skill Tree */
}

.company-showcase__info {
  flex: 1 1 33.333%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.25rem;
  padding: clamp(1.5rem, 4vw, 3rem);
  position: relative;
  z-index: 2;
}

.company-showcase__info p { margin-top: 1.25rem; max-width: 340px; }

/* Rollen-Zeile direkt unterm Logo (z. B. "Co-Founder & Videograf") – wie
   ein kleines Etikett, enger ans Logo gerückt als der Fließtext darunter.
   Selektor mit zwei Klassen bewusst, um die generische margin-top-Regel
   direkt darüber (.company-showcase__info p) gezielt zu überschreiben. */
.company-showcase__info .company-showcase__role {
  margin-top: 0.5rem;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
  color: var(--color-highlight);
  opacity: 0.9;
}

/* Kachel-Mosaik: 5 fest platzierte Kacheln über grid-template-areas (ein
   großes Feld links/rechts + 4 kleinere, siehe ASCII-Layout unten), sodass
   sie IMMER exakt die 5×6-Fläche füllen – keine Lücken, aber auch kein
   Überstand/Clipping über die Sektion hinaus (anders als die vorherige
   Auto-Flow-Variante). .company-showcase--reverse spiegelt die Areas
   horizontal, die Tile-Elemente selbst (grid-area: t1/t1b/t2/t3/t4) bleiben
   dabei unverändert im Markup. */
.company-showcase__tiles {
  flex: 1 1 66.666%;
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(6, 1fr);
  grid-template-areas:
    "t1  t1  t1  t2  t2"
    "t1  t1  t1  t2  t2"
    "t1  t1  t1  t3  t3"
    "t1  t1  t1  t3  t3"
    "t1b t1b t1b t4  t4"
    "t1b t1b t1b t4  t4";
  gap: 28px; /* wie .work-preview .media-grid – gleicher "Luft"-Wert wie bei
                den anderen Kachel-/Karten-Rastern der Seite */
}

/* FrameFactory: t1 (die Video-Kachel, siehe .company-showcase__tile--video
   weiter unten) soll exakt dieselbe Größe/Form wie COU2IN's t1 haben (3
   Spalten × 4 Zeilen), aber unten rechts statt oben links stehen – daher
   ist dieses Areas-Layout eine 180°-Drehung des COU2IN-Layouts (jede Zeile
   UND jede Spalte gespiegelt): t1b wandert von unten-links nach oben-rechts,
   t2/t3/t4 entsprechend mit. Ergebnis bleibt weiterhin lückenlos ohne
   Überstand, wirkt aber nicht wie eine reine Spiegelung der COU2IN-Sektion
   (die kleinen Kacheln liegen alle links statt alle rechts). */
.company-showcase--reverse .company-showcase__tiles {
  grid-template-areas:
    "t4  t4  t1b t1b t1b"
    "t4  t4  t1b t1b t1b"
    "t3  t3  t1  t1  t1"
    "t3  t3  t1  t1  t1"
    "t2  t2  t1  t1  t1"
    "t2  t2  t1  t1  t1";
}

/* Weicher Übergang von der schwarzen Logo-Fläche in die Kacheln, statt
   eines harten Schnitts – liegt über den Kacheln, nicht klickbar. */
.company-showcase__tiles::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(to right, #000 0%, transparent 45%);
}

/* Gespiegelt: Info-Panel liegt jetzt hinter (rechts von) den Kacheln im
   Markup, der Verlauf muss also von rechts statt von links kommen. */
.company-showcase--reverse .company-showcase__tiles::before {
  background: linear-gradient(to left, #000 0%, transparent 45%);
}

/* Jede Kachel ist jetzt zusätzlich eine .frame-Box (siehe frame-lines-
   design-pattern.md) mit eigenem Frame-Label (Index + Titel) – dafür intern
   auf Flex umgestellt: Label oben (feste Höhe), Medienbereich darunter
   füllt den Rest der Kachel. Die vier Rahmenlinien von .frame wachsen beim
   Hover mit, weil transform auf der ganzen Kachel inkl. .frame::after
   liegt. */
.company-showcase__tile {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform-origin: center;
  transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.company-showcase__tile:hover {
  transform: scale(1.05);
  z-index: 4;
}

/* .frame bringt sitzweit 10px Padding mit (Design-Pattern-Regel), das war
   der eigentliche Grund, warum der Titel trotz symmetrischem Label-Padding
   nicht mittig wirkte: der Abstand von der oberen Rahmenlinie bis zum Text
   war 10px(Frame) + Label-padding-top, der Abstand vom Text zur unteren
   Trennlinie aber nur Label-padding-bottom – deutlich weniger. Für diese
   sehr kompakten Kachel-Header wird das Frame-Padding hier gezielt auf 6px
   reduziert (nur für Company-Showcase-Kacheln, das globale .frame bleibt
   für Work-Preview/Kontaktformular bei 10px) und das Label-Padding hat
   dadurch oben 0, unten 6px – macht Frame-Padding + Label-Padding auf
   beiden Seiten gleich (6px/6px), Text sitzt jetzt wirklich mittig
   zwischen oberer Rahmenlinie und unterer Trennlinie. */
.company-showcase__tile.frame {
  padding: 6px;
}

.company-showcase__tile .frame-label {
  flex: none;
  z-index: 4; /* über dem ::before-Verlauf (z-index:3), sonst bei den
                 kachelnahen zum Logo hin kaum lesbar */
  align-items: center;
  padding: 0 0.85rem 6px;
  font-size: 0.6rem;
  line-height: 1;
}

/* Titel sauber mit Ellipsis abschneiden statt hart mitten im Wort (durch
   das overflow:hidden der Kachel), falls er auf schmalen Kacheln (v. a.
   Mobile) nicht mehr ganz reinpasst. */
.company-showcase__tile .frame-label__title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}

.company-showcase__tile-media {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  margin-top: 0.6rem; /* Luft zwischen Label-Trennlinie und Foto, sonst
                          klebt das Bild direkt an der Linie */
  overflow: hidden;
}

.company-showcase__tile-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--ox, 50%) var(--oy, 50%);
  filter: saturate(0.85) contrast(0.95);
}

/* Einzelne, ausgewählte Kacheln können zusätzlich ein Hover-Video bekommen
   (aktuell nur die große COU2IN-Kachel t1, Modifier-Klasse
   .company-showcase__tile--video) – gleiches Prinzip wie beim Skill Tree:
   Foto liegt in Ruhe, Video blendet per Hover/Fokus ein und spielt nur so
   lange (siehe initHoverVideoPanels() in script.js, dieselbe Funktion
   bedient jetzt Skill-Tree-Panels UND diese Kacheln – Selektor dort um
   ".company-showcase__tile--video" erweitert). */
.company-showcase__tile-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.85) contrast(0.95);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.company-showcase__tile--video:hover .company-showcase__tile-video,
.company-showcase__tile--video:focus-within .company-showcase__tile-video,
.company-showcase__tile--video.is-playing .company-showcase__tile-video {
  opacity: 1;
}

/* Frame-Rahmenfarbe ist pro Kachel überschreibbar, ohne .frame::after
   anzufassen: --line-color ist eine CSS-Variable, die per Inline-Style auf
   einer einzelnen .frame-Box gesetzt werden kann (siehe die COU2IN-Video-
   Kachel in about.html: --line-color: var(--color-highlight)). Default
   bleibt für alle anderen Frames das sitzweite Weiß aus --line-color. */

.company-showcase__logo {
  height: clamp(80px, 12vw, 180px);
  width: auto;
  margin-bottom: 1.5rem;
}

/* Die FrameFactory-Datei ist ein fast quadratisches Signet mit viel
   Weißraum/Rahmen um die eigentliche Bildmarke (F-Symbol + Schriftzug),
   während die COU2IN-Datei eng auf den Schriftzug zugeschnitten ist –
   bei gleicher CSS-Höhe wirkt FrameFactory dadurch deutlich kleiner.
   Kompensiert über eine größere Zielhöhe, bis beide optisch etwa gleich
   schwer wirken. */
#framefactory .company-showcase__logo {
  height: clamp(120px, 17vw, 260px);
}

@media (max-width: 700px) {
  /* Wie beim Skill Tree: das Nebeneinander von schmaler Logo-Fläche und
     Kachel-Mosaik braucht Breite. Auf Mobile stattdessen gestapelt – Logo/
     Text immer zuerst, unabhängig von --reverse, danach die Kacheln in
     derselben 5×6-Aufteilung, nur mit fester, kleinerer Höhe. */
  .company-showcase__panels {
    flex-direction: column;
    height: auto;
  }

  .company-showcase--reverse .company-showcase__panels {
    flex-direction: column;
  }

  .company-showcase--reverse .company-showcase__info { order: 1; }
  .company-showcase--reverse .company-showcase__tiles { order: 2; }

  .company-showcase__info {
    flex: none;
    padding: 2rem clamp(1.25rem, 4vw, 2rem);
  }

  .company-showcase__logo {
    height: clamp(64px, 22vw, 110px);
  }

  .company-showcase__tiles {
    flex: none;
    height: clamp(360px, 90vw, 480px);
    gap: 10px; /* der große Desktop-Abstand (28px) frisst auf schmalen
                  Viewports zu viel von der ohnehin knappen Breite */
  }

  /* Verlauf ist nur beim Nebeneinander sinnvoll, im gestapelten Layout
     einfach ausblenden statt unpassend über die Kacheln zu legen. */
  .company-showcase__tiles::before,
  .company-showcase--reverse .company-showcase__tiles::before {
    background: none;
  }
}

/* ============================================
   Kontaktformular
   ============================================ */

.contact {
  background: var(--color-bg-alt);
  padding-inline: 20px;
}

.contact-frame {
  width: 100%;
  max-width: 1160px;
  margin-inline: auto;
  padding: 0.5rem clamp(1.25rem, 4vw, 2.25rem) clamp(1.5rem, 4vw, 2.25rem);
}

/* Name/E-Mail/Nachricht und der Connect-Textblock beginnen/enden exakt dort,
   wo die Trennlinie unter dem Frame-Label beginnt/endet (.frame-label::after
   ist 14px von der Frame-Label-Box eingerückt – gleiche 14px hier). */
.contact-columns {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
  padding-top: 1.25rem;
  padding-inline: 14px;
}

@media (max-width: 700px) {
  .contact-columns {
    grid-template-columns: 1fr;
  }
}

.contact-form {
  display: grid;
  gap: 0.85rem;
}

.contact-info {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  align-self: center;
  gap: 0.75rem;
  padding-top: 0.4rem;
  text-align: right;
}

.contact-info__heading {
  font-family: var(--font-title);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: clamp(1.3rem, 2.6vw, 1.8rem);
  margin-bottom: 0.5rem;
  color: var(--color-highlight);
}

.contact-info__link {
  font-family: var(--font-base);
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  color: var(--color-text);
  border-bottom: 1px solid transparent;
  width: fit-content;
  transition: border-color var(--transition);
}

.contact-info__link:hover,
.contact-info__link:focus-visible {
  border-color: var(--color-highlight);
}

.contact-form label {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.contact-form input,
.contact-form textarea {
  width: 100%;
  background: transparent;
  border: 1px solid var(--color-text);
  color: var(--color-text);
  padding: 0.55rem 0.65rem;
  font-family: inherit;
  font-size: 0.9rem;
}

.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--color-highlight);
}

.contact-form button {
  justify-self: start;
  background: var(--color-highlight);
  color: var(--color-bg);
  border: none;
  padding: 0.65rem 1.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: opacity var(--transition);
}

.contact-form button:hover { opacity: 0.85; }

.contact-form__status { font-size: 0.9rem; }
.contact-form__status[data-state="success"] { color: #7fd97f; }
.contact-form__status[data-state="error"] { color: #ff6b6b; }

/* Honeypot-Feld: für Menschen unsichtbar, Bots tappen rein */
.contact-form__hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ============================================
   Footer
   ============================================ */

.site-footer {
  padding-block: 2.5rem;
  border-top: 1px solid #2a2a2a;
  font-size: 0.85rem;
}

/* Drei Spalten nebeneinander (Info / Social / Gehört zu mir) – bewusst
   auch auf Mobile, nicht nur ab Tablet-Breite (vorher hier gestapelt,
   Max wollte die gleiche Aufteilung wie am Desktop). Auf ganz schmalen
   Screens schrumpft der Gap entsprechend mit. */
.site-footer__columns {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: clamp(0.75rem, 4vw, 5rem);
  margin-bottom: 2rem;
}

/* Info ganz links, Social mittig (auch die Links zentriert), Gehört zu
   mir ganz rechts (rechtsbündig) – auf allen Breiten gleich. */
.site-footer__col:nth-child(1) {
  align-items: flex-start;
  text-align: left;
}

.site-footer__col:nth-child(2) {
  align-items: center;
  text-align: center;
}

.site-footer__col:nth-child(3) {
  align-items: flex-end;
  text-align: right;
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
}

.site-footer__heading {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
  color: var(--color-highlight);
  margin-bottom: 0.4rem;
}

.site-footer__col a { opacity: 0.8; }
.site-footer__col a:hover { opacity: 1; color: var(--color-highlight); }

.site-footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line-color);
}

.site-footer__copyright {
  opacity: 0.6;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.site-footer__logo {
  height: 20px;
  width: auto;
  opacity: 0.85;
}

/* Platzhalter-Hinweistext generell */
.placeholder-note {
  color: var(--color-highlight);
  font-size: 0.85rem;
}

/* ============================================
   Rechtstexte (Impressum/Datenschutz): reiner Fließtext-Aufbau, keine
   Frame-Boxen – Unterüberschriften in der technischen Schrift + dünner
   Trennlinie, angelehnt an den Linien-Look der Seite (siehe
   frame-lines-design-pattern), aber bewusst leichter für reinen Prosatext.
   ============================================ */
.legal-content {
  padding-bottom: 6rem;
}

.legal-content__meta p {
  margin-bottom: 0.75rem;
  line-height: 1.6;
}

.legal-content__meta a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-content h2 {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.9rem;
  margin-top: 2.75rem;
  margin-bottom: 0.85rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

.legal-content p {
  font-size: 0.92rem;
  line-height: 1.65;
  opacity: 0.85;
  margin-bottom: 1rem;
}

.legal-content ul {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}

.legal-content li {
  position: relative;
  padding-left: 1.1em;
  font-size: 0.92rem;
  line-height: 1.6;
  opacity: 0.85;
  margin-bottom: 0.35rem;
}

.legal-content li::before {
  content: "–";
  position: absolute;
  left: 0;
  opacity: 0.6;
}

/* Kompaktere Variante für sehr lange Rechtstexte (Datenschutzerklärung):
   kleinere Schrift, engere Abstände, zusätzlich Unterüberschriften-Ebene
   (h3, z. B. "a) Kontaktformular") unterhalb der nummerierten h2-Abschnitte. */
.legal-content--compact h2 {
  font-size: 0.8rem;
  margin-top: 2rem;
  margin-bottom: 0.6rem;
  padding-bottom: 0.45rem;
}

.legal-content--compact h3 {
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.75rem;
  opacity: 0.85;
  margin-top: 1.5rem;
  margin-bottom: 0.5rem;
}

.legal-content--compact p,
.legal-content--compact li {
  font-size: 0.8rem;
  line-height: 1.6;
}

/* ============================================
   Work-Seite: Katalog-Liste mit Vollbild-Hover-Video
   ============================================
   Aufbau: volle 100svh-Section, Hintergrundvideo per YouTube-Embed
   (gleicher Fullscreen-Cover-Trick wie .hero__video), das per Hover/Fokus
   auf eine Zeile eingeblendet wird und dabei die passende data-yt-id lädt
   (siehe initWorkCatalogVideoBg() in script.js). Die Zeilen selbst sitzen
   unten im Viewport in einer Box mit fester Höhe (--work-row-h * 3.8 =
   3 volle Zeilen + je eine teilweise sichtbare oben/unten), die per
   Scroll erreichbar sind. Die teilweise sichtbaren Zeilen "verschwinden"
   nicht hart, sondern blenden über zwei Blur-Veils aus (gleiche
   backdrop-filter-Technik wie die Navbar beim Scrollen, siehe oben in
   dieser Datei) – dadurch der gewünschte "läuft ins Unendliche im Blur"-
   Effekt. */
.work-hero {
  position: relative;
  height: 100svh;
  width: 100%;
  overflow: hidden;
  background: #000;
  /* Höhe einer Katalog-Zeile + Gesamthöhe der Katalog-Box (Play/Pause- und
     Vollbild-Button unten weiter unten brauchen diesen Wert, um sich knapp
     OBERHALB der Zeilenliste zu positionieren, statt sie zu überlappen –
     hier auf .work-hero definiert (statt nur lokal in .work-catalog-viewport),
     damit auch .work-hero__bg (Geschwister-Element) per Vererbung darauf
     zugreifen kann). */
  --work-row-h: clamp(38px, 4vw, 56px);
  /* Auf Max' Wunsch sitzt die ganze Katalog-Box (Zeilenliste mit Titel/
     Credits) nicht mehr direkt an der Bildschirmunterkante, sondern etwas
     angehoben – siehe .work-catalog-wrap weiter unten. */
  --work-catalog-lift: clamp(1.5rem, 5vw, 3.5rem);
  --work-catalog-h: calc(var(--work-row-h) * 3.8 + clamp(1.25rem, 3vw, 2.5rem) + var(--work-catalog-lift));
}

.work-hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Klick auf das sichtbare Hintergrundvideo (oberer Bereich des Hero, wo
   keine Zeile drüberliegt) pausiert/startet es – siehe
   initWorkCatalogVideoBg() in script.js. Vollbild gibt es nur noch über den
   eigenen Button unten rechts (.work-hero__fullscreen-btn). Cursor-Hinweis
   nur, solange wirklich ein Video läuft. */
.work-hero__bg:has(.work-hero__iframe.is-active) {
  cursor: pointer;
}

/* Play/Pause- und Vollbild-Button: gleiche Kreis-Optik wie .hero__pause auf
   der Startseite. Beide Kinder von .work-hero__bg, dadurch automatisch
   korrekt positioniert sowohl in der kleinen Vorschau (absolute, relativ zu
   .work-hero__bg) als auch im echten Vollbild-Zustand (.work-hero__bg wird
   dort selbst position:fixed über den ganzen Viewport, siehe weiter unten –
   die Kind-Buttons folgen dem automatisch, ohne eigene Fixed-Position-Logik
   und ohne von .work-heros overflow:hidden abgeschnitten zu werden, weil sie
   innerhalb des sich selbst neu positionierenden .work-hero__bg bleiben). */
.work-hero__pause,
.work-hero__fullscreen-btn {
  position: absolute;
  right: clamp(1rem, 3vw, 2rem);
  /* In der kleinen Vorschau: knapp oberhalb der Katalog-Zeilenliste, damit
     nichts überlappt. Im Vollbild (siehe .is-expanded weiter unten): echte
     Bildschirmecke wie bei YouTube. */
  bottom: calc(var(--work-catalog-h) + 1rem);
  z-index: 3;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-text);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  color: var(--color-text);
  font-size: 0.7rem;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, background 0.2s ease;
}

.work-hero__fullscreen-btn {
  right: calc(clamp(1rem, 3vw, 2rem) + 40px + 0.6rem);
}

.work-hero__pause:hover,
.work-hero__pause:focus-visible,
.work-hero__fullscreen-btn:hover,
.work-hero__fullscreen-btn:focus-visible {
  background: rgba(0, 0, 0, 0.7);
}

/* Nur sichtbar, sobald wirklich ein Video aktiv ist (gleiche :has()-Bedingung
   wie der Cursor-Hinweis oben). */
.work-hero__bg:has(.work-hero__iframe.is-active) .work-hero__pause,
.work-hero__bg:has(.work-hero__iframe.is-active) .work-hero__fullscreen-btn {
  opacity: 1;
  pointer-events: auto;
}

/* Im Vollbild: Pause-Button rutscht in die echte Bildschirmecke (die
   Katalogliste ist dort ohnehin unsichtbar drunter). Vollbild-Button
   verschwindet – Schließen übernimmt dort der bestehende X-Button. */
.work-hero__bg.is-expanded .work-hero__pause {
  bottom: clamp(1rem, 3vw, 2rem);
}

.work-hero__bg.is-expanded .work-hero__fullscreen-btn {
  display: none;
}

/* Gleicher Trick wie .hero .hero__video: Embed wird größer als die Box
   skaliert und mittig zugeschnitten, damit es randlos den ganzen
   Viewport füllt statt Letterboxing zu zeigen. */
.work-hero__iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100vw;
  height: 56.25vw; /* 16:9 */
  min-height: 100%;
  min-width: 177.78vh; /* 16:9 */
  max-width: none;
  transform: translate(-50%, -50%);
  pointer-events: none;
  border: 0;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.work-hero__iframe.is-active {
  opacity: 1;
}

/* Vollbild-Ansicht auf schmalen (mobilen) Viewports: die normale
   "Cover"-Regel oben (width/height + min-width/min-height) skaliert das
   16:9-Video hoch und schneidet links/rechts massiv ab, sobald es in einem
   Hochformat-Bildschirm landet – auf dem Handy sieht man dann quasi nur
   noch die Bildmitte. Im ausgeklappten Vollbild-Modus (.is-expanded) daher
   auf "Contain"/Letterboxing umschalten: min() sorgt dafür, dass die
   Box nie größer wird als der Viewport in beide Richtungen, das
   Seitenverhältnis aber exakt 16:9 bleibt – Ergebnis sind schwarze Balken
   oben/unten statt Beschnitt links/rechts, dafür ist das komplette Bild
   sichtbar (Originalformat). Die kleine Hintergrund-Vorschau (nicht
   expanded) behält bewusst weiterhin das randlose Cover-Verhalten. */
@media (max-width: 700px) {
  .work-hero__bg.is-expanded .work-hero__iframe {
    width: min(100vw, 177.78vh);
    height: min(56.25vw, 100vh);
    min-width: 0;
    min-height: 0;
  }
}

/* "Vollbild"-Ansicht per Klick auf eine Zeile: bewusst NICHT (nur) über
   die native Fullscreen-API gelöst (Element.requestFullscreen()), weil die
   sich als unzuverlässig erwiesen hat – auf manchen Browsern/Systemen
   lehnt sie den Aufruf ab ("Permissions check failed"), obwohl der Klick
   ganz normal vom Nutzer kam, und auf iOS Safari existiert sie für
   Iframes praktisch gar nicht. Ergebnis ohne diesen Fallback: nur ein
   winziges Video mit Ladespinner mitten im Screen, drumherum weiterhin
   Navbar/Titel/Zeilenliste sichtbar ("schwarzer Bildschirm"-Bug).
   Stattdessen schaltet .is-expanded den Hintergrund-Wrapper per CSS auf
   position:fixed über die gesamte Seite (inkl. über die Navbar), was in
   jedem Browser zuverlässig funktioniert. Die native Fullscreen-API wird
   zusätzlich weiter versucht (schön für den echten Browser-Vollbildmodus,
   wo verfügbar), ist aber nicht mehr Voraussetzung für die Optik. */
.work-hero__bg.is-expanded {
  position: fixed;
  inset: 0;
  z-index: 600;
  background: #000;
  cursor: pointer;
}

.work-fullscreen-close {
  position: fixed;
  top: var(--edge-pad);
  right: var(--edge-pad);
  z-index: 601;
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  color: #fff;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.work-fullscreen-close:hover,
.work-fullscreen-close:focus-visible {
  background: rgba(0, 0, 0, 0.65);
}

.work-fullscreen-close.is-visible {
  display: flex;
}

/* Eigener Ton-Button in der Vollbild-Ansicht: der Ton-Button pro Zeile
   (.work-row__sound) verschwindet optisch unter dem Vollbild-Overlay,
   darum ein zweiter, gleich funktionierender Button direkt neben dem
   Schließen-Button. Video startet seit dem Autoplay-Fix immer stumm und
   wird – falls Ton gewünscht – erst nach dem "onReady" der YouTube-API
   entstummt (siehe initWorkCatalogVideoBg() in script.js). */
.work-fullscreen-sound {
  position: fixed;
  top: var(--edge-pad);
  right: calc(var(--edge-pad) + 44px + 0.6rem);
  z-index: 601;
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  color: #fff;
  cursor: pointer;
}

.work-fullscreen-sound:hover,
.work-fullscreen-sound:focus-visible {
  background: rgba(0, 0, 0, 0.65);
}

.work-fullscreen-sound.is-visible {
  display: flex;
}

.work-fullscreen-sound-icon {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.work-fullscreen-sound-icon .work-fullscreen-sound-body {
  fill: currentColor;
  stroke: none;
}

.work-fullscreen-sound.is-muted .work-fullscreen-sound-wave {
  display: none;
}

.work-fullscreen-sound:not(.is-muted) .work-fullscreen-sound-mute {
  display: none;
}

.work-hero__gradient {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to top, rgba(0, 0, 0, 0.92) 0%, rgba(0, 0, 0, 0.55) 30%, rgba(0, 0, 0, 0.15) 55%, transparent 75%),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, transparent 30%);
  pointer-events: none;
}

.work-hero__intro {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  padding-top: calc(var(--nav-height) + clamp(1.5rem, 4vw, 3rem));
  padding-inline: var(--edge-pad);
}

.work-catalog-wrap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--work-catalog-lift);
  z-index: 2;
  padding-inline: var(--edge-pad);
  padding-bottom: clamp(1.25rem, 3vw, 2.5rem);
}

.work-catalog-viewport {
  /* --work-row-h wird von .work-hero geerbt (siehe dort) – hier nicht mehr
     neu definiert, damit es nur eine Quelle der Wahrheit gibt (auch für die
     Play/Pause-/Vollbild-Buttons, die --work-catalog-h daraus berechnen). */
  position: relative;
  height: calc(var(--work-row-h) * 3.8);
  overflow: hidden;
}

.work-catalog {
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  border-top: 1px solid var(--line-color);
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Padding oben/unten = (Viewport-Höhe - eine Zeilenhöhe) / 2, also
     (3.8 - 1) / 2 = 1.4 Zeilenhöhen. Dadurch startet Zeile 01 beim Laden
     schon mittig im Viewport (statt an der Oberkante vom Blur-Veil
     angeschnitten zu sein), und die letzte Zeile lässt sich genauso bis in
     die Mitte scrollen, statt am unteren Rand hängen zu bleiben. */
  padding-block: calc(var(--work-row-h) * 1.4);
}

.work-catalog::-webkit-scrollbar {
  display: none;
}

/* .work-row ist bewusst ein <div>, kein <a>: der Sound-Button braucht ein
   eigenständig klickbares <button>, und ein <button> darf laut HTML-Spec
   nicht in einem <a> verschachtelt sein. Stattdessen übernimmt
   .work-row__link als unsichtbarer, über die ganze Zeile gestreckter Link
   die Klick-/Tab-Navigation ("Stretched-Link"-Muster) und liegt im
   Stacking hinter dem Sound-Button, der per position:relative + z-index
   darüber liegt und so unabhängig klickbar bleibt.

   Wichtig: weil .work-row ein Flex-Container ist, werden alle Flex-Kinder
   (Index/Heading/Crew/Rolle) vom Browser fürs Stacking wie position:relative
   behandelt – landen also auf derselben Stack-Ebene 0 wie der absolut
   positionierte Link (z-index:0) und gewinnen dort per Dokumentreihenfolge
   (sie stehen im HTML NACH dem Link). Ohne explizites z-index auf dem Link
   fängt z. B. die breite Crew-Spalte in der Zeilenmitte die Klicks ab und
   der Link reagiert dort gar nicht. z-index:1 hebt den Link zuverlässig
   über alle Flex-Kinder, bleibt aber unter dem Sound-Button (ebenfalls
   z-index:1, gewinnt die Krawatte per Dokumentreihenfolge, da er im HTML
   nach dem Link steht). */
.work-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 1.25vw, 1rem);
  height: var(--work-row-h);
  border-bottom: 1px solid var(--line-color);
  color: var(--color-text);
}

.work-row__link {
  position: absolute;
  inset: 0;
  z-index: 1;
  text-decoration: none;
}

/* Hover-Highlight: der Titel der gehoverten/fokussierten/mittig
   gescrollten Zeile wechselt in die Akzentfarbe (--color-highlight) statt
   die ganze Zeile zu dimmen – liest sich zusammen mit dem einblendenden
   Hintergrundvideo klarer als ein pauschales opacity-Dimming der ganzen
   Zeile. .is-centered wird per JS gesetzt, sobald eine Zeile in der
   Play-Leiste (.work-catalog__playzone) steht, siehe initWorkCatalogVideoBg()
   in script.js. */
.work-row:hover .work-row__title,
.work-row:focus-within .work-row__title,
.work-row.is-centered .work-row__title {
  color: var(--color-highlight);
}

.work-row__index {
  flex: 0 0 auto;
  width: 1.5rem;
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.7rem;
  opacity: 0.5;
}

/* Sound-Button: standardmäßig läuft der Ton des Hintergrundvideos mit
   (siehe initWorkCatalogVideoBg() in script.js) – dieser Button pro Zeile
   ist die vom Nutzer jederzeit erreichbare Stumm/Ton-an-Kontrolle dazu
   (WCAG 1.4.2/2.2.2-Gedanke, gleiches Prinzip wie .hero__pause). Sitzt
   bewusst direkt hinter der Zahl. position:relative + z-index:1 hebt ihn
   über den gestreckten .work-row__link, damit er unabhängig klickbar
   bleibt statt die Zeilen-Navigation auszulösen. */
.work-row__sound {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text);
  opacity: 0.5;
  cursor: pointer;
  transition: opacity var(--transition), color var(--transition);
}

.work-row__sound:hover,
.work-row__sound:focus-visible {
  opacity: 1;
  color: var(--color-highlight);
}

.work-row__sound.is-muted {
  opacity: 0.35;
}

.work-row__sound-icon {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.work-row__sound-icon .work-row__sound-body {
  fill: currentColor;
  stroke: none;
}

.work-row__sound.is-muted .work-row__sound-wave {
  display: none;
}

.work-row__sound:not(.is-muted) .work-row__sound-mute {
  display: none;
}

/* Titel + Kategorie/Kunde stehen jetzt einzeilig zusammen ganz links
   (".work-row__heading"): "TITEL / Kategorie" (z. B. "On the Court /
   Personal Work"), durch einen schmalen Schrägstrich getrennt (siehe
   .work-row__category::before). Der gestapelte Zweizeiler aus der Vorversion
   sah laut Max nicht gut aus. Die Crew-Liste (".work-row__crew") füllt
   danach die mittlere, flexible Zone bis zur Rolle. */
.work-row__heading {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 0.5em;
}

.work-row__title {
  max-width: 26vw;
  min-width: 0;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(0.7rem, 1.7vw, 1.3rem);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color var(--transition);
}

/* Kategorie/Kunde ist NIE abgeschnitten (Max' Vorgabe, dass dieser Teil
   nicht fehlen darf) – deshalb kein max-width/ellipsis wie beim Titel. Der
   Schrägstrich davor kommt per ::before, damit er nicht Teil des reinen
   Textinhalts ist (z. B. fürs title-Tooltip an anderer Stelle unnötig). */
.work-row__category {
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.75;
  white-space: nowrap;
}

.work-row__category::before {
  content: "/";
  margin-right: 0.5em;
  opacity: 0.5;
}

.work-row__crew {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-base);
  font-size: 0.64rem;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.5;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.work-row__role {
  flex: 0 0 auto;
  min-width: 8rem;
  margin-left: auto;
  text-align: right;
  font-family: var(--font-base);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.85;
  white-space: nowrap;
}

/* Blur-Veils oben/unten: gleiche backdrop-filter-Technik wie die Navbar
   (siehe .site-header beim Scrollen), zusätzlich per mask-image so
   ausgeblendet, dass die Unschärfe direkt an der Kante am stärksten ist
   und zur Zeilen-Mitte hin ausläuft ("ins Unendliche im Blur"). */
.work-catalog__veil {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 3;
  height: calc(var(--work-row-h) * 0.85);
  pointer-events: none;
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
}

.work-catalog__veil--top {
  top: 0;
  mask-image: linear-gradient(to bottom, black, transparent);
  -webkit-mask-image: linear-gradient(to bottom, black, transparent);
}

.work-catalog__veil--bottom {
  bottom: 0;
  mask-image: linear-gradient(to top, black, transparent);
  -webkit-mask-image: linear-gradient(to top, black, transparent);
}

/* Play-Leiste: markiert die Zone in der vertikalen Mitte der Zeilenliste,
   in die man seine gewünschte Zeile scrollt, damit deren Hintergrundvideo
   startet – Scrollen ersetzt hier komplett das frühere Hover-Verhalten
   (siehe initWorkCatalogVideoBg() in script.js). Zwei dünne horizontale
   Linien ober-/unterhalb der mittleren Zeilenhöhe, passend zum reduzierten
   Linien-Stil der Seite (gleiches Prinzip wie .work-preview__playzone,
   das inzwischen wieder entfernte Pendant auf der Startseite). Liegt
   zwischen den beiden Blur-Veils (die bei top:0/bottom:0 enden, bevor die
   Mitte erreicht ist), rein dekorativ und daher pointer-events:none. */
.work-catalog__playzone {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--work-row-h);
  transform: translateY(-50%);
  pointer-events: none;
  z-index: 4;
  border-top: 1px solid var(--color-highlight);
  border-bottom: 1px solid var(--color-highlight);
}

@media (max-width: 700px) {
  .work-hero {
    --work-row-h: 42px;
  }

  .work-row {
    gap: 0.4rem;
  }

  .work-row__title {
    font-size: 0.85rem;
    max-width: 60vw;
  }

  /* Zu wenig Platz für vier/fünf Spalten auf schmalen Viewports – Kategorie
     und Crew weichen zuerst, Rolle bleibt (wichtigste Zusatzinfo neben dem
     Titel). */
  .work-row__category,
  .work-row__crew {
    display: none;
  }

  .work-row__role {
    min-width: auto;
    font-size: 0.65rem;
  }
}

/* ============================================
   Clients-Sektion (Work-Seite): reine Textliste, keine Logos
   ============================================ */
.clients {
  padding-block: clamp(3rem, 8vw, 6rem);
  border-top: 1px solid var(--line-color);
}

.clients__list {
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  row-gap: 0.9em;
  text-align: center;
  font-family: var(--font-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: clamp(0.8rem, 1.5vw, 1.05rem);
  color: var(--color-text);
  opacity: 0.6;
}

.clients__item {
  white-space: nowrap;
}

.clients__item::after {
  content: "·";
  display: inline-block;
  margin-inline: 0.8em;
  opacity: 0.5;
}

.clients__item:last-child::after {
  content: none;
}
