:root {
  --frame-color: #3B3B3B;
  --frame-thickness: 1px;
  --frame-length: 10px;
  --frame-tick-length: 30px; /* Länge des Mittelstrichs oben/unten (nur .frame, nicht .frame2) */
  --frame-padding: 0.6rem; /* Abstand Text <-> Rahmen */
  --body-font-size: clamp(1rem, 2vw, 1.75rem); /* einheitliche Textgröße für h2, h3 (auch in box4) */
  --page-bg: #ECECEC; /* Seitenhintergrund, auch für Footer-Boxen genutzt */
}

body{
  display: grid;
  margin: 0%;
border: 1%;
padding: 1%;
  padding-bottom: 4rem; /* Platz zur fixed Fußzeile, damit box4 nicht darunter verschwindet */
  row-gap: 10px;
  column-gap: 10px;
  grid-template-rows: repeat(5, fit-content(100%));
  grid-template-columns: repeat(3,minmax(0,1fr));
  background-color: var(--page-bg);
  transition: background-color 0.6s ease; /* sanfter Fade beim Wechsel des Farbschemas */
}

.h1{
  grid-row: 1 / span 1;
  grid-column: 1 / -1; /* spannt über alle 3 Spalten, wie beim Slider */
  font-size: 10vw; /* skaliert direkt proportional zur Breite des Viewports */
  color: var(--frame-color);
  font-family: "Scheherazade New", serif;
  font-weight: 400;
  font-style: normal;
  transform: translateY(calc(40dvh - 5px)) scale(0.92); /* Start: baut sich mittig im Viewport auf -- dvh statt vh, reagiert dynamisch auf Browser-Chrome (z.B. mehr/weniger Platz je nach Tab-Leiste), statt einen starren Wert anzunehmen */
  opacity: 0;
  transition: opacity 0.6s ease, transform 1.1s cubic-bezier(0.16, 1, 0.3, 1) 1.2s, color 0.6s ease; /* transform startet erst nach 1.2s Verzögerung -> h1 steht solange sichtbar zentriert */
  line-height: 70%;
  letter-spacing: 0.02em; /* war: 10% -> ungültiger Wert, letter-spacing akzeptiert keine Prozentangaben */
  white-space: nowrap;
  margin: 0;
  text-align:center;
  width: 100%;
  max-width: 100%;
  overflow: hidden; /* Sicherheitsnetz: schneidet ab statt über den Viewport hinauszuragen */
  box-sizing: border-box;
}

.h1.launch-in {
  transform: translateY(-5px) scale(1); /* Ziel: eigentliche Position (die -5px waren schon vorher Feintuning) */
  opacity: 1;
}

/* --- Launch-Animation: Elemente starten unsichtbar, JS blendet sie
       zeitversetzt nacheinander ein (siehe script.js). Reiner Opacity-Fade
       -- kein scaleY mehr, da das die Eckklammern der Kind-Frames
       mitverzerrt hat (sichtbares "Hakeln" während der Animation) --- */
.launch-fade {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.launch-fade.launch-in {
  opacity: 1;
}

/* --- .launch-row: zweistufiges Reveal -- der Rahmen (Klammern) erscheint
       zuerst, der Text/Inhalt kurz danach. Verhindert das "sprunghafte"
       Gleichzeitig-Erscheinen von Rahmen+Text. Der äußere Container
       selbst bleibt immer opacity:1 -- nur seine ::after-Klammern
       (frame-left/frame-right) bzw. .frame (box1) und der Text-Layer
       werden unabhängig voneinander gesteuert. --- */
.launch-row.frame-left::after,
.launch-row.frame-right::after {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.launch-row.frame-in.frame-left::after,
.launch-row.frame-in.frame-right::after {
  opacity: 1;
}

.launch-row .label-text {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.launch-row.text-in .label-text {
  opacity: 1;
}

.launch-row .frame {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.launch-row.frame-in .frame {
  opacity: 1;
}

.launch-row .frame > div {
  opacity: 0; /* überschreibt den sonstigen Standard (opacity:1) nur während der Launch-Phase */
  transition: opacity 0.4s ease;
}
.launch-row.text-in .frame > div {
  opacity: 1;
}

/* --- Slider: nur die Klammern (frame2::after) fahren hier über die
       Launch-Sequenz; das eigentliche Bilder-Fade läuft weiter über den
       bestehenden inline-style-Mechanismus in rebuildSlider() (siehe
       script.js), damit sich die beiden Systeme nicht in die Quere
       kommen -- JS triggert diesen einfach zur passenden Zeit. --- */
.slider-wrapper.frame2::after {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.slider-wrapper.frame2.frame-in::after {
  opacity: 1;
}

.h2{
  display: grid;
  grid-row: 2 / span 1;
  grid-column: 1 / span 1;
  font-family: "Scheherazade New", serif;
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.6s ease;
  font-weight: 500;
  font-size: var(--body-font-size); /* jetzt gleich groß wie h3 */
  justify-self: start; /* war: MIN (ungültig) */
}

.h3{
  font-family: "Scheherazade New", serif;
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.6s ease;
  font-weight: 500;
  font-size: var(--body-font-size); /* nie kleiner als 16px (iPhone), nie größer als 28px (Mac) */
  line-height: 150%;
}

/* Box4 und Info-Overlay: kompaktere Zeilenhöhe als der Rest (box1-3 bleiben bei 150%) */
.box4,
.info-overlay {
  line-height: 90%;
}

.projects{
  grid-row: 2 / span 1;
  grid-column: 1 / span 1;
  justify-self: start; /* war: MIN (ungültig) */
  cursor: pointer; /* Signal: Klick führt zurück zur Landing Page */
}
.photos{
  grid-row: 2 / span 1;
  grid-column: 3 / span 1;
  justify-self: end; /* war: MIN (ungültig) */
}

 
.frame {
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top center / var(--frame-tick-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom center / var(--frame-tick-length) var(--frame-thickness) no-repeat;
  padding: var(--frame-padding);
  position: relative;
  display: block;
  box-sizing: border-box; /* verhindert, dass padding die Breite über die Spalte hinaus vergrößert */
  width: 100%;
}

/* --- frame2: nur die 8 Eckklammern, KEIN Mittelstrich -> dezenter als .frame --- */
.frame2 {
  position: relative;
}

.frame2::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-thickness) var(--frame-length) no-repeat;
  pointer-events: none; /* Hover/Klicks gehen durch die Ecken hindurch */
  z-index: 2; /* liegt über den Slider-Bildern */
}

/* H1-Sonderfall: Rahmen erscheint erst, wenn h1 an ihrer finalen Position
   angekommen ist (nicht schon während sie zentriert im Viewport steht) */
.h1.frame2::after {
  opacity: 0;
  transition: opacity 0.4s ease 2.3s; /* 2.3s = H1_HOLD_MS + H1_SLIDE_MS aus script.js */
}

.h1.frame2.launch-in::after {
  opacity: 1;
}

/* --- frame-left / frame-right: je nur 2 Ecken (links bzw. rechts),
       damit .projects + .photos zusammen wie EINE große Klammer wirken,
       die den ganzen Zeilenbereich umschließt --- */
.frame-left,
.frame-right {
  position: relative;
  padding: var(--frame-padding);
  box-sizing: border-box;
}

.frame-left::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-thickness) var(--frame-length) no-repeat;
  pointer-events: none;
  z-index: 2;
}

.frame-right::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-thickness) var(--frame-length) no-repeat;
  pointer-events: none;
  z-index: 2;
}

/* Photodump ist jetzt klickbar (neue Unterseite) -> Signal wie bei box1 */
.photos {
  cursor: pointer;
}

.box1{
  display: grid;
  align-items: stretch; /* war: center -> jetzt Höhen-Pendant zu justify-items: stretch */
  justify-items: stretch; /* zwingt .frame auf volle Spaltenbreite */
  gap: 5px;
  grid-row: 3 / span 1;
  grid-column: 1 / span 1;
  justify-self: stretch;
}

.box2{
  display: grid;
  align-items: stretch; /* war: center -> jetzt Höhen-Pendant zu justify-items: stretch */
  justify-items: stretch; /* zwingt .frame auf volle Spaltenbreite */
  gap: 5px;
  grid-row: 3 / span 1;
  grid-column: 2 / span 1;
  justify-self: stretch;
}

.box3{
  display: grid;
  align-items: stretch; /* war: center -> jetzt Höhen-Pendant zu justify-items: stretch */
  justify-items: stretch; /* war: justify-content: flex-end -> dadurch schrumpfte .frame auf Inhaltsbreite */
  gap: 5px;
  grid-row: 3 / span 1;
  grid-column: 3 / span 1;
  justify-self: stretch;
}

.box4{
  display: grid;
  align-items: stretch; /* war: center -> jetzt Höhen-Pendant zu justify-items: stretch */
  justify-items: stretch; /* zwingt .frame auf volle Spaltenbreite */
  gap: 5px;
  grid-row: 5 / span 1; /* war: 4 -> Slider steht jetzt davor, wie auf Mobile */
  grid-column: 1 / -1; /* spannt jetzt über alle 3 Spalten, Aufteilung übernimmt column-count */
  justify-self: stretch;
}

/* --- Slider, About Me, Say Hi, Imprint: fest am unteren Viewport-Rand,
       raus aus dem Grid-Fluss -> erzeugt automatisch Whitespace darüber --- */
.slider-wrapper {
  position: relative; /* war: fixed -> jetzt normales Grid-Item, direkt nach box1-3 wie auf Mobile */
  grid-row: 4 / span 1; /* war: 5 -> steht jetzt VOR box4, einheitlich mit der Mobile-Reihenfolge */
  grid-column: 1 / -1;
  min-height: clamp(14rem, 30dvh, 24rem); /* skaliert jetzt mit der Viewport-Höhe -- verhindert, dass Slider+Box4 zusammen auf niedrigeren Bildschirmen ein Scrollen erzwingen */
}

/* --- slider-viewport: fixer, nicht-scrollender Container zwischen
       Wrapper und Track. Trägt overflow:hidden UND den statischen
       4-Kanten-Fade -- dadurch bleiben Maße/Position IMMER relativ zum
       sichtbaren Fenster, unabhängig davon, wie breit der scrollende
       Track tatsächlich ist oder wie weit er gerade verschoben wurde.
       Die Klammern (frame2::after) sitzen weiterhin auf .slider-wrapper
       und bleiben von alldem hier komplett unberührt. --- */

.slider-viewport {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden; /* schneidet den überstehenden Slide-Inhalt ab */
  /* Statischer, gleichmäßiger 4-Kanten-Fade -- ändert sich NIE, läuft
     komplett unabhängig von der Übergangs-Animation weiter (genau wie
     in der Vorversion) */
  mask-image:
    linear-gradient(to right, transparent 0%, black 4%, black 96%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, black 4%, black 96%, transparent 100%);
  mask-composite: intersect;
  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, black 4%, black 96%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, black 4%, black 96%, transparent 100%);
  -webkit-mask-composite: source-in;
}

/* --- slider-fog-mask: eigene, innere Ebene NUR für die animierte
       "Nebel"-Ellipse beim Übergang. Masken kombinieren sich bei
       Verschachtelung automatisch (nur wo BEIDE Masken durchlassen,
       ist etwas sichtbar) -- dadurch bleibt der statische 4-Kanten-
       Fade vom Viewport oben IMMER erhalten, unabhängig davon, was
       hier passiert. Im Ruhezustand ist die Ellipse riesig (kein
       spürbarer Effekt), beim Übergang zieht sie sich smooth zusammen. --- */
@property --vignette-inner {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 200%;
}
@property --vignette-outer {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 300%;
}

.slider-fog-mask {
  position: relative;
  width: 100%;
  height: 100%;
  --vignette-inner: 200%; /* Ruhezustand: riesige Ellipse -> kein spürbarer Effekt, nur der 4-Kanten-Fade vom Viewport bleibt sichtbar */
  --vignette-outer: 300%;
  mask-image: radial-gradient(ellipse 60% 70% at center, black var(--vignette-inner), transparent var(--vignette-outer));
  -webkit-mask-image: radial-gradient(ellipse 60% 70% at center, black var(--vignette-inner), transparent var(--vignette-outer));
  transition: --vignette-inner 0.6s cubic-bezier(0.65, 0, 0.35, 1), --vignette-outer 0.6s cubic-bezier(0.65, 0, 0.35, 1);
}

.slider-fog-mask.transitioning {
  /* Während des Übergangs zieht sich die Ellipse zusammen -> wird zur
     runden "Nebel"-Form, die sich smooth rein und wieder raus bewegt */
  --vignette-inner: 30%;
  --vignette-outer: 78%;
}

.slider-track {
  display: flex;
  width: max-content;
  transition: opacity 0.7s cubic-bezier(0.65, 0, 0.35, 1), filter 0.7s cubic-bezier(0.65, 0, 0.35, 1); /* sanftere ease-in-out Kurve statt Standard-"ease" -- wirkte vorher zu abgehakt */
  filter: blur(0) grayscale(0);
}

.slider-track.transitioning {
  /* Feste Werte -- keine JS-Zufallsvariation mehr (verursachte den Bug:
     per style.setProperty gesetzte Inline-Variablen wurden nie
     zurückgesetzt und blieben dauerhaft "hängen") */
  filter: blur(28px) grayscale(0.6);
}

/* --- Titel-Overlay: zeigt beim Projektwechsel kurz den Projektnamen
       groß über dem geblurrten Slider -- dieselbe typografische
       Sprache wie h1, damit der Wechsel sich wie ein Mini-"Launch"-
       Moment anfühlt. Ein einzelnes Fade in/out, kein Loop. --- */
.slider-title-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 1rem;
  font-family: "Scheherazade New", serif;
  font-weight: 400;
  color: var(--frame-color);
  letter-spacing: 0.04em; /* etwas mehr Laufweite, editorialer Look */
  line-height: 100%;
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
  z-index: 5; /* über den Bildern (z-index:1) und frame2::after (z-index:2) */
}

.slider-title-overlay.visible {
  opacity: 1;
}
 
.slider-track img,
.slider-track video {
  height: clamp(14rem, 30dvh, 24rem); /* skaliert mit der Viewport-Höhe (vorher starr 24rem) -- Breite bleibt proportional (width: auto) */
  width: auto; /* Breite ergibt sich automatisch aus dem Original-Seitenverhältnis -> kein Zuschneiden/Verzerren */
  margin-right: 10px;
  position: relative;
  z-index: 1; /* liegt unter dem frame2::after */
  cursor: pointer; /* Signal: Klick öffnet die Lightbox */
}

/* --- Text-Ticker im Slider (z.B. "IN WORK" bei Zwischenstand):
       läuft im selben Loop-Mechanismus wie die Bilder, nur als
       Outline-Schriftzug (transparente Füllung, nur Kontur) statt
       Fläche -- dezenter, wirkt wie ein Wasserzeichen/Laufband statt
       den Platz einfach mit Text zuzukleistern. Höhe entspricht der
       Bild-/Video-Höhe, damit der Slider insgesamt gleich hoch bleibt. --- */
.slider-text-item {
  display: flex;
  align-items: center;
  height: clamp(14rem, 30dvh, 24rem);
  margin-right: 10px;
  font-family: "Scheherazade New", serif;
  font-weight: 700;
  font-size: clamp(2.5rem, 6vw, 7rem);
  letter-spacing: 0.03em;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--frame-color);
  text-stroke: 1.5px var(--frame-color); /* Fallback, falls je unterstützt -- -webkit-Variante ist aktuell die einzig relevante */
  user-select: none; /* kein versehentliches Markieren beim Wischen/Ziehen */
}

 
.bottom{
  color: var(--frame-color);
  font-family: "Scheherazade New", serif;
  font-weight: 600;
  font-style: normal;
}
 
/* --- Box1: immer alle Inhalte sichtbar, normaler Textfluss --- */
.box1 .frame > div {
  cursor: pointer; /* Signal, dass hier gehovert werden kann */
  opacity: 1;
  transition: opacity 0.3s ease;
}
 
/* --- Box2 & Box3: Inhalte standardmäßig unsichtbar, übereinander gestapelt --- */
.box2 .frame,
.box3 .frame {
  position: relative;
  min-height: 1.4em; /* verhindert Kollaps, da Kinder aus dem Fluss genommen werden */
}
 
.box2 .frame > div,
.box3 .frame > div {
  position: absolute;
  top: var(--frame-padding);   /* = Frame-Padding, damit Text an gleicher Stelle wie sonst sitzt */
  left: var(--frame-padding);
  right: var(--frame-padding);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease; /* sorgt für Fade-in UND Fade-out */
}
 
/* --- Kopplung: aktives Projekt (per Klick gesetzt) blendet passendes
       box2/box3-Element ein. Ersetzt die alte :hover-Lösung, da Klick/Tap
       auf Touch-Geräten nötig ist und der Zustand dauerhaft bleiben muss --- */
body[data-active-project="trauma"] .trauma2,
body[data-active-project="trauma"] .trauma3 {
  opacity: 1;
}
 
body[data-active-project="campus"] .campus2,
body[data-active-project="campus"] .campus3 {
  opacity: 1;
}
 
body[data-active-project="film"] .film2,
body[data-active-project="film"] .film3 {
  opacity: 1;
}
 
body[data-active-project="ba"] .BA2,
body[data-active-project="ba"] .BA3 {
  opacity: 1;
}
 
/* --- Aktives Projekt in Box1 markieren: statt Ausgrauen der anderen
       (dynamisch, hat sich unpassend angefühlt) jetzt ein statisches
       "+" hinter dem AKTIVEN Titel -- Box1 bleibt dadurch komplett
       ruhig/statisch, der Slider bleibt das einzige dynamische
       Element der Seite. --- */
body[data-active-project="trauma"] .box1 .trauma::after,
body[data-active-project="campus"] .box1 .campus::after,
body[data-active-project="film"] .box1 .film::after,
body[data-active-project="ba"] .box1 .BA::after {
  content: " +";
}

/* Hover-Vorschau: das + erscheint schon beim Hovern (nicht erst nach
   Klick), verschwindet aber wieder, sobald man wegbewegt UND das
   Projekt nicht tatsächlich aktiv ist (die Regel oben gewinnt dann
   automatisch weiter). Nur auf Geräten mit echtem Hover. */
@media (hover: hover) and (pointer: fine) {
  .box1 .frame > div:hover::after {
    content: " +";
  }
}

/* --- Dasselbe + Prinzip auch für "PROJECTS" (aktiv = home) und
       "PHOTO LIBRARY" (aktiv = photodump). Wichtig: das + hängt am
       .label-text-Span, NICHT an .projects/.photos selbst -- deren
       eigenes ::after ist schon für die Eckklammern (frame-left/
       frame-right) belegt. Bei "PHOTO LIBRARY" (rechtsbündig) kommt
       das + VOR den Text (::before), sonst "springt" das Label beim
       Erscheinen nach links, weil es rechts verankert ist. --- */
body[data-active-project="home"] .projects .label-text::after {
  content: " +";
}
body[data-active-project="photodump"] .photos .label-text::before {
  content: "+ ";
}

@media (hover: hover) and (pointer: fine) {
  .projects:hover .label-text::after {
    content: " +";
  }
  .photos:hover .label-text::before {
    content: "+ ";
  }
}
 
/* --- Box4: Rahmen-Hülle, permanent sichtbar, KEINE Transition/Fade
       -- Klammern bleiben beim Seitenwechsel unbeeinflusst. Nur
       #project-text (das Kind-Element mit dem eigentlichen Text)
       faded, wenn sich der Inhalt ändert. --- */
.box4 .frame {
  height: clamp(8rem, 18dvh, 12rem); /* skaliert mit der Viewport-Höhe (vorher starr 12rem) -- zusammen mit dem Slider oben der Haupthebel dafür, dass die Seite ohne Scrollen passt */
  position: relative;
  /* Nur die 8 Eckklammern, OHNE Mittelstrich (wie .frame2) -> der Mittelstrich
     säße sonst genau auf der mittleren Spaltengrenze und würde "zersprungen" wirken */
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top right / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left / var(--frame-thickness) var(--frame-length) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-length) var(--frame-thickness) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-thickness) var(--frame-length) no-repeat;
}

#project-text {
  height: 100%;
  overflow: hidden; /* war: overflow-y: auto -> kollidierte mit column-count (Overflow läuft horizontal, nicht vertikal) und sah "zersprungen" aus */
  column-count: 3;
  column-gap: 1.5rem;
  transition: opacity 0.7s ease; /* faded NUR der Text, nicht die Klammern von .frame */
}

.box4 .frame p {
  margin: 0 0 1em 0;
  break-inside: avoid; /* verhindert, dass ein Absatz mitten in der Spalte zerrissen wird */
  overflow-wrap: break-word; /* lange Wörter brechen sauber um, statt die schmale Spalte zu sprengen */
  hyphens: auto; /* zusätzlich mit Silbentrennung, falls verfügbar */
}

#project-text.fading {
  opacity: 0;
}

/* --- PLAY-Button in Box4: gleicher Look wie die Footer-Links
       (About Me/Say Hi/Imprint) -- eckige Klammern, h3-Größe. Auf
       Desktop oben, horizontal zentriert über der gesamten Box4-Row
       (bündig mit der obersten Textzeile). Nur sichtbar, wenn das
       aktive Projekt ein Video hinterlegt hat (siehe projectData.video
       in script.js), sonst per [hidden] ausgeblendet. Mobile-Version
       (unter dem Text, ebenfalls zentriert) siehe Media Query weiter
       unten. --- */
.project-play {
  position: absolute;
  top: var(--frame-padding);
  left: 83.3%; /* Mitte von Spalte 3 (rechtes Drittel) statt der ganzen Box4-Breite -- "einen rüber" von der Vollzentrierung */
  transform: translateX(-50%);
  cursor: pointer;
  font-family: "Scheherazade New", serif;
  font-weight: 500;
  font-size: var(--body-font-size);
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.7s ease; /* opacity-Dauer jetzt identisch zu #project-text (FADE_MS = 700ms in script.js) */
  z-index: 2; /* über dem fließenden #project-text */
  background: var(--page-bg); /* kleine Deckfläche, damit Text darunter nicht durchscheint/kollidiert */
  padding: 0 0.4em;
}

/* Wird von script.js (updatePlayButton) zeitgleich mit #project-text.fading
   gesetzt/entfernt -- Button und Text faden dadurch synchron ein/aus. */
.project-play.fading {
  opacity: 0;
}

.project-play[hidden] {
  display: none;
}

/* --- Box4 bleibt jetzt IMMER sichtbar (auch auf photodump), genau wie
       der Slider dauerhaft seinen Rahmen zeigt -- auf home/photodump
       eben mit leerem Text, passend zur Optik von box2/box3. --- */
 
 
.aboutme{
  position: fixed;
  left: 1%; /* war: 10px -> jetzt identisch zum Body-Padding, damit bündig mit box4s Klammer-Kante */
  bottom: 10px;
  cursor: pointer;
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.6s ease;
  z-index: 10; /* immer über den Footer-Detailboxen (z-index:3), sonst nicht mehr klickbar */
}

.cv-link {
  margin-left: 1.2em; /* war: 0.4em -- deutlich mehr Luft zu [ABOUT ME] */
}
 
.sayhi{
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 10px;
  cursor: pointer;
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.6s ease;
  z-index: 10;
}
 
.imprint{
  position: fixed;
  right: 1%; /* war: 10px -> jetzt identisch zum Body-Padding, damit bündig mit box4s Klammer-Kante */
  bottom: 10px;
  cursor: default; /* nicht mehr klickbar -- statisches © 2026 statt [IMPRINT]-Toggle */
  color: var(--frame-color);
  transition: color 0.6s ease, opacity 0.6s ease;
  z-index: 10;
}

/* --- Info-Overlay (About Me/Say Hi/CV): EIN gemeinsamer
       Vollbild-Container statt vier separater Boxen -- genau wie die
       Bild-/Video-Lightbox (position:fixed, inset:0), nur mit z-index
       UNTER der fixed Fußzeile (z-index 10), damit About Me/Say Hi/
       Imprint/CV-Link immer anklickbar bleiben, auch während offen (die
       Fußzeile selbst bleibt dadurch immer scharf und antippbar).
       Fade wie die Bild-/Video-Lightbox: opacity+pointer-events statt
       display, damit ein weicher Übergang möglich ist. --- */
.info-overlay {
  position: fixed;
  inset: 0;
  z-index: 8;
  padding: 2rem 1.5rem;
  box-sizing: border-box;
  overflow-y: auto; /* scrollt intern bei langem Inhalt (v.a. CV) */
  background: rgba(236, 236, 236, 0.4); /* gleiche helle, frosted Optik wie die Bild-/Video-Lightbox */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease; /* gleiche Fade-Dauer wie .lightbox-overlay */
  line-height: 90%;
}

.info-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}

/* --- Einzelnes Panel: nur .active ist sichtbar, alle anderen per
       display:none komplett aus dem Fluss -- kein Höhen-Konflikt
       zwischen den Panels möglich, jedes hat so viel Platz wie es
       braucht. Typo: h3-Größe + derselbe Glow (text-shadow) wie die
       Lightbox-Captions, damit der Text über dem unscharfen
       Hintergrund gut lesbar bleibt. panel-fading: kurzer Cross-Fade,
       wenn man bei bereits offenem Overlay direkt zu einer ANDEREN
       Box wechselt (siehe showFooterBox in script.js) -- display:none
       kann nicht transitionen, deshalb erst opacity auf 0, per JS-Timeout
       NACH der Transition erst die Sichtbarkeit tauschen. --- */
.info-panel {
  display: none;
  opacity: 1;
  transition: opacity 0.2s ease;
  font-family: "Scheherazade New", serif;
  font-weight: 500;
  font-size: var(--body-font-size);
  color: var(--frame-color);
  text-shadow: 0 0 6px #fff, 0 0 12px #fff;
  line-height: 90%;
}

.info-panel.active {
  display: block;
}

.info-panel.panel-fading {
  opacity: 0;
}

.info-panel a {
  color: var(--frame-color);
}

/* --- CV-Panel: 3 Spalten wie im Referenzbeispiel (Experience/Education/
       Things I work with). Spaltentitel unterstrichen, Stationen als
       einzelne <p>-Blöcke darunter (siehe HTML-Kommentar in index.html
       für die genaue Textstruktur). --- */
.cv-columns {
  display: flex;
  gap: 3rem;
  flex-wrap: wrap;
}

.cv-col {
  flex: 1 1 12rem;
  min-width: 12rem;
}

.cv-col-title {
  text-decoration: underline;
  margin-bottom: 0.6em;
}

.cv-col p {
  margin: 0 0 1em 0;
}



/* ============================================================
   Mobile Anpassung (iPhone & Co., ~<700px Breite)
   ============================================================
   3 schmale Spalten sind auf einem Handy nicht mehr lesbar
   (jede Box wäre nur ~120px breit). Deshalb: alles stapelt
   sich in einer Spalte, in sinnvoller Lesereihenfolge.
============================================================ */
@media (max-width: 700px) {
  body {
    grid-template-columns: 1fr 1fr; /* 2 schmale Spalten NUR für box2/box3-Kompression nötig */
    grid-template-rows: repeat(6, auto); /* Slider zählt im Grid-Fluss mit */
    padding-top: 1.5rem; /* mehr Luft oben, sonst kleben die h1-Klammern am Viewport-Rand */
    padding-bottom: 4rem; /* Platz, damit box4 nicht unter der fixed Fußzeile verschwindet */
    box-sizing: border-box; /* Padding zählt zur Höhenberechnung in script.js mit */
  }

  .h1 {
    font-size: clamp(2rem, 14vw, 4rem); /* eigene, etwas kleinere Skala für schmale Screens */
    white-space: normal; /* darf bei Bedarf umbrechen statt beschnitten zu werden */
  }

  /* Neue Mobile-Reihenfolge (oben -> unten): h1, box4 (Lesetext),
     Slider, Role & Jahr, Projekttitel, Projects/Photo Library.
     Lesbarer Content oben (wo der Blick zuerst hinfällt), tappbare
     Navigation unten (Daumenzone) -- umgekehrt zur Desktop-Reihenfolge. */
  .box4,
  .box1 {
    grid-column: 1 / -1;
  }

  .box4 {
    grid-row: 2;
    font-size: 1.1rem; /* moderate Erhöhung ggü. dem Klemm-Wert (16px) -- vorsichtiger als beim Info-Overlay, da Box4 bei Überlänge abschneidet statt zu scrollen; beim längsten Text (Film, 2 Absätze) bitte gegenchecken */
  }

  .slider-wrapper {
    grid-row: 3;
    min-height: var(--mobile-slider-height, 17rem); /* wird von script.js live auf den tatsächlich übrigen Platz gesetzt; 17rem nur als Fallback vor dem ersten JS-Durchlauf */
  }

  /* Info-Panel-Text auf Mobile größer als der normale Klemm-Wert
     (var(--body-font-size) landet bei 393px Breite exakt am unteren
     Klemm-Limit von 1rem/16px, da 2vw dort nur ~7.9px sind) -- hier
     ist freier Lesefluss statt enger Spalten, darf also ruhig größer
     sein. */
  .info-panel {
    font-size: 1.2rem;
  }

  /* Box2 & Box3 zeigen je nur EIN Wort/eine Zahl -> auf Mobile
     nebeneinander in eine gemeinsame Zeile statt 2 volle Zeilen */
  .box2,
  .box3 {
    grid-row: 4;
  }
  .box2 { grid-column: 1 / span 1; }
  .box3 { grid-column: 2 / span 1; }

  .box1 { grid-row: 5; }

  /* Rolle/Jahr (Box2/3) und Projektliste (Box1) auf Mobile zentriert
     statt linksbündig -- Desktop bleibt unverändert linksbündig. */
  .box2 .frame > div,
  .box3 .frame > div,
  .box1 .frame > div {
    text-align: center;
  }

  /* .projects & .photos: parallel in derselben Zeile, ganz unten
     -> Haupt-Navigation liegt jetzt im Daumen-erreichbaren Bereich */
  .projects { grid-row: 6; grid-column: 1 / span 1; justify-self: start; }
  .photos { grid-row: 6; grid-column: 2 / span 1; justify-self: end; }

  .frame {
    --frame-padding: 0.4rem; /* auf schmalen Screens nochmal enger; Box2/3-Text folgt automatisch mit */
  }

  .cv-columns {
    flex-direction: column;
    gap: 1.5rem;
  }

  /* Box2/3: Text lief auf schmalen Screens über 2 Zeilen und damit
     über den Rahmen hinaus, da die Box nur 1.4em hoch war.
     Kleinere Schrift + mehr Höhe als Sicherheitsnetz. */
  .box2,
  .box3 {
    font-size: 0.85rem;
  }

  .box2 .frame,
  .box3 .frame {
    min-height: 2.8em; /* Platz für bis zu 2 Textzeilen, statt nur 1.4em */
  }

  .box4 .frame {
    height: 8rem; /* auf schmalen Screens etwas kompakter als am Desktop */
    /* Flex-Column statt der Desktop-Absolute-Positionierung: Text oben
       (nimmt verfügbaren Platz, schrumpft bei Bedarf), Play-Button
       direkt darunter, zentriert -- passt sich der jeweiligen Textlänge
       an, statt an einer festen Ecke zu kleben. */
    display: flex;
    flex-direction: column;
  }

  #project-text {
    column-count: 1; /* auf Mobile nur 1 Spalte statt 3 */
    height: auto; /* überschreibt die Desktop-Regel (height:100%) -- Höhe ergibt sich jetzt aus dem Flex-Layout */
    flex: 1 1 auto;
    min-height: 0; /* erlaubt Schrumpfen/Scrollen innerhalb des Flex-Containers */
    overflow-y: auto; /* überschreibt Desktop-overflow:hidden -- Text wird gescrollt statt abgeschnitten */
  }

  /* --- Scroll-Blur-Kanten: wiederverwendbare Technik für scrollbare
         Textblöcke (aktuell Box4/Film & Co., später ggf. auch Box1 bei
         mehr Projekten). ::before/::after sitzen FEST am oberen/unteren
         Rand des Frames (nicht am scrollenden Text selbst) und blurren
         per backdrop-filter, WAS GERADE DAHINTER durchscrollt -- echte
         Unschärfe statt reinem Farbverlauf, wie beim Slider, nur ohne
         Farbe. mask-image lässt den Blur-Effekt selbst weich zur Mitte
         hin ausfaden (voll am äußeren Rand, transparent zur Textmitte),
         statt hart abzuschneiden -- sonst wirkt die Kante wie ein
         Rendering-Fehler statt ein bewusster Übergang. Sichtbarkeit wird
         per JS (updateScrollFadeEdges in script.js) an den tatsächlichen
         Scroll-Stand gekoppelt: oben nur sichtbar, NACHDEM runtergescrollt
         wurde; unten nur, SOLANGE noch mehr Text folgt. */
  .scroll-fade-edges::before,
  .scroll-fade-edges::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    height: 2.2em;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.25s ease;
    backdrop-filter: blur(5px);
    -webkit-backdrop-filter: blur(5px);
    z-index: 3;
  }

  .scroll-fade-edges::before {
    top: 0;
    mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
  }

  .scroll-fade-edges::after {
    bottom: 0;
    mask-image: linear-gradient(to top, black 0%, transparent 100%);
    -webkit-mask-image: linear-gradient(to top, black 0%, transparent 100%);
  }

  .scroll-fade-edges.show-top::before {
    opacity: 1;
  }

  .scroll-fade-edges.show-bottom::after {
    opacity: 1;
  }

  .project-play {
    /* Löst die Desktop-Absolute-Positionierung (oben-zentriert) ab:
       auf Mobile steht der Button im normalen Fluss direkt unter dem
       Text, statt fix in der Box4-Ecke zu kleben. */
    position: static;
    align-self: center;
    transform: none;
    flex: 0 0 auto;
    margin-top: 0.2rem;
    background: none;
    padding: 0;
  }

  /* Höhe kommt jetzt aus der CSS-Variable, die script.js live berechnet
     (übriger Platz nach Abzug aller anderen Rows) -- width:auto sorgt
     wie schon vorher dafür, dass das Seitenverhältnis erhalten bleibt,
     keine Verzerrung. Kein height:100%/Grid-1fr mehr, da das mit den
     Video-Eigenmaßen kollidierte (Video ohne definierte Bezugshöhe fiel
     auf seine native Auflösung zurück -> riesig + schwarz/verzerrt). */
  .slider-track img,
  .slider-track video {
    height: var(--mobile-slider-height, 17rem);
    width: auto;
  }

  .slider-text-item {
    height: var(--mobile-slider-height, 17rem);
    font-size: clamp(1.75rem, 10vw, 4rem); /* eigene, kleinere Skala für schmale Screens -- wie bei h1 */
  }

  .aboutme,
  .sayhi,
  .imprint {
    font-size: 0.9rem;
  }
}

/* ============================================================
   Lightbox
   ============================================================
   Öffnet sich beim Klick auf ein Slider-Bild/-Video, zeigt es groß
   und scharf (bewusst OHNE Blur/Vignette -- soll ja gerade zum
   ungetrübten Sichten der Arbeiten dienen). Pinch-Zoom funktioniert
   hier automatisch vom Browser, da es ein normales, nicht gesten-
   gesteuertes Overlay ist.
============================================================ */
.lightbox-overlay {
  position: fixed;
  inset: 0;
  background: rgba(236, 236, 236, 0.4); /* etwas weniger Trübung, damit dahinter noch was erahnbar bleibt */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, background-color 0.3s ease;
}

.lightbox-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}

/* --- Dunkler Modus: für den PLAY-Button (Film mit Ton) -- deutlich
       abgedunkelter Hintergrund statt der hellen, frosted Variante,
       die für die normale Bild-/Video-Galerie genutzt wird. --- */
.lightbox-overlay.dark {
  background: rgba(0, 0, 0, 0.85);
}

.lightbox-content {
  max-width: 92vw;
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
}

.lightbox-caption {
  text-align: center;
  text-shadow: 0 0 6px #fff, 0 0 12px #fff; /* weicher, heller Glow -- heller als --page-bg (#ECECEC) */
}

/* Strukturiertes Format: Titel / Rolle / Jahr nebeneinander, je mit
   kleinem Tick-Mark darüber -- passend zur Klammern-Optik der Seite */
.lightbox-caption-columns {
  display: flex;
  gap: 4rem;
  justify-content: center;
  flex-wrap: wrap;
}

.lightbox-caption-col {
  position: relative;
}

.lightbox-content img,
.lightbox-content video {
  max-width: 92vw;
  max-height: 84dvh; /* etwas reduziert, damit unter dem Bild noch Platz für die Caption bleibt */
  width: auto;
  height: auto;
  object-fit: contain;
  cursor: pointer; /* Signal: erneutes Tippen schließt die Lightbox wieder */
  /* kein filter/mask hier -- bewusst scharf und unverfälscht */
}

.lightbox-content video[controls] {
  cursor: default; /* Klick bedient hier die Video-Controls, schließt nicht mehr die Lightbox */
}

/* --- YouTube-Embed (PLAY-Button): kein Caption-Text darunter, darf
       also näher an den vollen Bildschirm gehen als die normale
       Bildergalerie. 16:9 wird über aspect-ratio erzwungen; die beiden
       min()-Werte sorgen dafür, dass sowohl die Breiten- als auch die
       Höhen-Grenze eingehalten wird, je nachdem was zuerst greift. */
.lightbox-content iframe.lightbox-youtube {
  border: none;
  aspect-ratio: 16 / 9;
  width: min(94vw, calc(90dvh * 16 / 9));
  height: min(90dvh, calc(94vw * 9 / 16));
  cursor: default; /* Klick bedient den YouTube-Player, schließt nicht die Lightbox */
}