/* Blue Heights — "Chronicle" V2
   Pinned About (left) + horizontal timeline reveal on vertical scroll,
   flowing into a horizontal image gallery, a historical archive and press.
   Off-white, soft black, blue accent. */

:root {
  --bg: #f3f2ee;
  --bg-sepia: #f1ead8; /* warm "archival" wash for the Archive section + its menu */
  --ink: #26262a;
  --mut: #9a9a9e;
  --acc: #738ec8;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --ease: cubic-bezier(0.55, 0, 0.1, 1);
  --pad: clamp(24px, 5vw, 90px);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { background: var(--bg); color: var(--ink); font-family: var(--sans); -webkit-font-smoothing: antialiased; }
/* Die Menueleiste ist fixiert UND deckend — ohne dieses Polster landet jeder
   Anker-Sprung dahinter. Gemessen 03.08.2026: die Ueberschrift von #news war
   auf 360x640 komplett verdeckt, bei #press auch auf dem Desktop (dort ist
   die Leiste 114px hoch). Wert = Leistenhoehe + etwas Luft. */
html { scroll-padding-top: 96px; }
@media (min-width: 821px) { html { scroll-padding-top: 126px; } }
body { overflow-x: hidden; } /* let the era word fly off-screen to the right */
a { color: inherit; text-decoration: none; }
img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* shared section eyebrow / lede (archive, press) */
.sec-eyebrow { display: block; font: 400 12px var(--mono); letter-spacing: 0.2em; text-transform: uppercase; color: var(--acc); margin-bottom: 18px; }
.sec-lede { font-size: clamp(20px, 1.65vw, 26px); line-height: 1.5; font-weight: 500; color: #3c3c40; max-width: 58ch; margin-top: 18px; }

/* ---------- hero ---------- */
.hero { position: relative; height: 100vh; overflow: hidden; background: #15151a; }
.hero-bg { position: absolute; inset: 0; z-index: 0; }
/* Die Wortmarke ist seit 05.08.2026 in eine <h1> gefasst (Seite hatte keine).
   Der Wrapper darf nichts verschieben: Standardabstand raus, und er bleibt
   statisch, damit .hero-logo weiter gegen .hero positioniert. */
.hero-title { margin: 0; }
/* logo moved to the top-right corner of the landing page */
.hero-logo {
  position: absolute; top: clamp(20px, 3vw, 40px); right: var(--pad); left: auto; transform: none;
  width: clamp(120px, 13vw, 200px); height: auto; z-index: 2;
}

/* ---------- pinned story ---------- */
.pin { position: relative; }
.is-pinned .pin__stage {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; align-items: stretch;
}
.pin__stage { display: block; }

/* About is the first station; it slides out left as Mission arrives.
   Its media is OPTIONAL and the type size follows it (the planned WP rule):
   no image → full-width display statement; image present → the standard
   phase grid applies and the statement steps down toward the section scale. */
.phase.phase--about:not(:has(.phase__media)) { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; padding: var(--pad); }
.about-text {
  font-size: clamp(32px, 5.2vw, 84px); line-height: 1.1; letter-spacing: -0.03em;
  font-weight: 500; color: var(--ink); max-width: min(76%, 1100px);
}
.phase.phase--about:has(.phase__media) .about-text {
  font-size: clamp(24px, 2.4vw, 42px); line-height: 1.22; letter-spacing: -0.02em; max-width: none;
}
.about-text .nowrap { white-space: nowrap; }
.about-more, .phase-more {
  display: inline-block; margin-top: clamp(22px, 3vh, 40px);
  font: 500 clamp(16px, 1.4vw, 22px) var(--sans); color: var(--acc);
  border-bottom: 2px solid transparent; padding-bottom: 3px; transition: border-color 0.3s var(--ease);
}
.about-more:hover, .phase-more:hover { border-color: var(--acc); }
.phase-more { margin-top: clamp(18px, 2.4vh, 30px); }

/* nav — appears once you are inside the story section */
.topnav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 80;
  display: flex; align-items: center; gap: clamp(14px, 1.6vw, 30px);
  padding: clamp(20px, 3vw, 40px) var(--pad);
  /* opaque backdrop so section headlines never bleed through the menu — light
     over the light sections, swapped to dark over Exhibitions (.on-dark) */
  background: var(--bg);
  /* whole bar slides DOWN from above the viewport when leaving the hero */
  transform: translateY(-100%); pointer-events: none;
  transition: transform 0.55s var(--ease), background 0.4s var(--ease);
}
.topnav.show { transform: translateY(0); pointer-events: auto; }

/* logo mark — the four "Blue Four" bars; clipped so each can slide in from the
   top. JS (story scroll progress) adds .in to one bar at a time, left to right. */
.nav-logo {
  display: inline-flex; align-items: flex-start; gap: clamp(6px, 0.7vw, 10px); flex: 0 0 auto;
  align-self: flex-start; height: clamp(48px, 5.5vw, 74px);
  /* lift the bars up through the menu's top padding so they reach the viewport top */
  margin-top: calc(-1 * clamp(20px, 3vw, 40px)); margin-right: clamp(16px, 1.5vw, 24px);
  overflow: hidden;
}
.nav-bar {
  width: clamp(5px, 0.5vw, 7px); height: 100%; background: var(--acc);
  transform: translateY(-130%); transition: transform 0.42s var(--ease);
}
/* the whole sequence fires together when About is reached; per-bar delay gives the
   left-to-right assemble (it's not tied to scroll position) */
.nav-bar:nth-child(1) { transition-delay: 0.28s; }
.nav-bar:nth-child(2) { transition-delay: 0.40s; }
.nav-bar:nth-child(3) { transition-delay: 0.52s; }
.nav-bar:nth-child(4) { transition-delay: 0.64s; }
.nav-bar.in { transform: translateY(0); }
body.is-reading .nav-logo { display: none; }
/* Rein eine Platzfrage — auf schmalen Schirmen braucht die Punktespur die
   Breite. (Der fruehere Kommentar "pin engine is off here" stimmte nicht:
   die Engine haengt an desktop() in app.js, also auch am Zeigergeraet, und
   ist auf einem 1024px-Tablet ebenfalls aus, waehrend das Logo dort steht.) */
@media (max-width: 820px) { .nav-logo { display: none; } }
/* Auf schmalen Schirmen passen sechs Punkte nicht nebeneinander. Gescrollt
   wird deshalb die SPUR (.nav-links), nicht die ganze Leiste — sonst wandert
   auch das Logo mit, und der Pfeil rechts haette keinen festen Platz.
   Bis 03.08.2026 lag der Ueberlauf an .topnav; der letzte Punkt war dann
   angeschnitten und nichts deutete darauf hin, dass es weitergeht. */
.nav-links {
  display: flex; align-items: center; gap: clamp(14px, 1.6vw, 30px);
  min-width: 0; overflow-x: auto;
  /* Luft nach oben/unten, die das Layout NICHT veraendert (negativer Rand
     zieht sie zurueck): Ein Scroll-Behaelter beschneidet an seiner
     Innenkante — ohne dieses Polster waere die vergroesserte Trefferflaeche
     der Punkte (::after unten) abgeschnitten und wirkungslos. */
  padding-block: 9px; margin-block: -9px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  /* Einrasten: nach Wisch und Autoscroll steht links immer ein GANZER
     Punkt, kein halb abgeschnittener. */
  scroll-snap-type: x proximity;
}
.nav-links::-webkit-scrollbar { display: none; }
/* Die Punkte sind nur ~27px hoch; die Trefferflaeche waechst per ::after auf
   Fingermass, ohne die Leiste hoeher zu machen oder den Unterstrich der
   aktiven Marke (border-bottom) zu verschieben. */
.nav-links > a { scroll-snap-align: start; position: relative; }
.nav-links > a::after { content: ""; position: absolute; left: 0; right: 0; top: -9px; bottom: -9px; }
/* Die Pfeile zeigen, dass die Spur weitergeht — sie stehen NEBEN ihr (nicht
   darueber), damit sie keinen Punkt verdecken: einer links, einer rechts.
   app.js setzt [hidden], solange gar nichts zu schieben ist (Desktop). */
.nav-arrow {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 30px; height: 44px;
  background: none; border: 0; padding: 0; cursor: pointer; color: var(--ink);
}
.nav-prev { margin-left: calc(-1 * var(--pad) / 3); }
.nav-more { margin-right: calc(-1 * var(--pad) / 3); }
.nav-arrow[hidden] { display: none; }
/* Am jeweiligen Ende wird ein Pfeil unsichtbar, BEHAELT aber seinen Platz —
   sonst ruckt die ganze Spur um seine Breite, genau in dem Moment, in dem
   man das Ende erreicht. Ganz entfernt (per [hidden]) werden sie nur, wenn
   es gar nichts zu schieben gibt (Desktop). */
.nav-arrow.is-off { visibility: hidden; pointer-events: none; }
.nav-arrow:hover { opacity: 0.6; }

/* Fingergerechte Trefferflaechen fuer die restlichen kleinen Bedienelemente
   (Review 03.08.2026: Slider-Pfeile ~16x20px, Newsletter-Knopf ~24x21px,
   "All news" ~23px hoch, der Zurueck-Knopf ~20px). Die Flaeche waechst per
   Pseudoelement — Schrift, Abstaende und Unterstriche bleiben unberuehrt.
   Nur auf Tippgeraeten, damit die Maus-Ansicht unveraendert bleibt. */
@media (pointer: coarse) {
  .prog-arrow, .nform button, .news-more, .nav-back { position: relative; }
  .prog-arrow::after, .nform button::after, .news-more::after, .nav-back::after {
    content: ""; position: absolute; left: 50%; top: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }
  /* Die beiden Slider-Pfeile stehen nur 18px auseinander — ihre Flaechen
     wuerden sich sonst ueberlappen und der linke den rechten verschlucken. */
  .prog-arrow::after { width: 40px; }
}
@media (prefers-reduced-motion: reduce) { .nav-links { scroll-behavior: auto; } }
.topnav.on-dark { background: #1a1a1c; }
/* .on-media (transparente Leiste ueber dem Vollbild-Streifen) ist mit dem
   Streifen am 02.08.2026 entfallen — ueber der Spalten-Galerie traegt die
   Leiste ihren normalen Grund. .on-sepia bleibt: sie greift, sobald die
   Galerie nach oben hinausgescrollt ist (Press/Contact). */
.topnav.on-sepia { background: var(--bg-sepia); }
/* slightly smaller than the 4-item version so six labels stay on one line */
.topnav a {
  font: 500 clamp(17px, 1.5vw, 25px) var(--sans); letter-spacing: 0; text-transform: none; color: var(--ink);
  padding-bottom: 4px; border-bottom: 2px solid transparent; white-space: nowrap;
}
.topnav a.on { border-color: var(--ink); }
.topnav a:hover { opacity: 0.6; }

/* Kein About-Untermenue mehr: Dropdown und Subnav-Leiste (beide 01.08.2026)
   wurden am selben Tag wieder verworfen — der Kapitelanzeiger ist der
   Breadcrumb oben rechts (.nav-era), der Weg zu den Unterseiten sind die
   CTA-Knoepfe der Sektionen. */

/* Back control — same type as the menu; takes the menu's place while reading */
.nav-back {
  display: none; background: none; border: 0; cursor: pointer; padding: 0;
  font: 500 clamp(17px, 1.5vw, 25px) var(--sans); color: var(--ink);
}
.nav-back:hover { opacity: 0.6; }
/* Beim Lesen tritt der Zurueck-Knopf an die Stelle des Menues — die ganze
   Spur samt Pfeil verschwindet (nicht nur die Links: sonst bliebe der Pfeil
   allein stehen). */
body.is-reading .nav-links,
body.is-reading .nav-arrow { display: none; }
body.is-reading .nav-back { display: inline-block; }
/* keep the bar visible while reading even if the menu hadn't revealed yet, and
   never tint it dark over the light reader.
   .on-sepia gehoert hier dazu (nachgezogen, der Zustand kam erst am
   02.08.2026): app.js schaltet die Klasse nach den Rechtecken von Galerie und
   News — beim Lesen steht der Seitenscroll, sie bliebe also stehen und legte
   einen warm getoenten Balken ueber den hellen Reader. */
body.is-reading .topnav { opacity: 1; transform: none; pointer-events: auto; }
body.is-reading .topnav.on-dark,
body.is-reading .topnav.on-sepia { background: var(--bg); }
/* Der Zurueck-Knopf braucht hier KEINE eigene Farbregel — und darf keine
   bekommen: Er ist nur sichtbar, waehrend gelesen wird, und dann hat die
   Leiste durch die Zeilen darueber immer den hellen Grund. Siehe die Notiz
   bei `.topnav.on-dark .nav-arrow` weiter unten. */

/* breadcrumb chapter indicator — top-right, flies off to the right on advance */
.nav-era {
  position: fixed; top: clamp(20px, 3vw, 40px); right: var(--pad); z-index: 80;
  height: 1.3em; min-width: 12ch; text-align: right; overflow: visible; pointer-events: none;
  opacity: 0; transition: opacity 0.5s var(--ease);
}
.nav-era.show { opacity: 1; }
/* Gleiche Groesse wie die Menue-Knoepfe (.topnav a) und OHNE Unterstrich
   (Benni 02.08.) — wer die eine clamp()-Stufe anfasst, zieht die andere nach. */
.nav-era__word {
  position: absolute; right: 0; top: 0; white-space: nowrap;
  font: 500 clamp(17px, 1.5vw, 25px) var(--sans); letter-spacing: 0; text-transform: none; color: var(--acc);
  opacity: 0; transform: translateX(-26px);
  transition: transform 0.7s var(--ease), opacity 0.7s var(--ease);
}
.nav-era__word.current { opacity: 1; transform: none; }
.nav-era__word.exited {
  opacity: 0; transform: translateX(120vw);
  transition: transform 0.32s cubic-bezier(0.4, 0, 0.85, 0.2), opacity 0.3s ease;
}

/* While reading, hide the top-right chapter word so it doesn't duplicate the
   reader heading ("The history." / "Our mission."). */
body.is-reading .nav-era { opacity: 0; }

/* phases viewport + track */
.phases-vp { flex: 1; position: relative; overflow: hidden; }
.phases { display: flex; height: 100%; width: 100%; will-change: transform; }
.phase-spacer { flex: 0 0 100%; }
.phase {
  flex: 0 0 100%; height: 100%;
  display: grid; grid-template-columns: 1fr 1fr; align-items: center;
  gap: clamp(28px, 4vw, 80px);
  padding: var(--pad) var(--pad) calc(var(--pad) + 30px);
}
.phase__media { position: relative; height: 74vh; overflow: hidden; clip-path: inset(0 0 100% 0); transition: clip-path 1s var(--ease); }
.phase.in .phase__media { clip-path: inset(0 0 0 0); }
.phase__era { display: block; font: 400 12px var(--mono); letter-spacing: 0.18em; text-transform: uppercase; color: var(--acc); margin-bottom: 14px; }
.phase__text h2 { font-size: clamp(24px, 2.6vw, 46px); line-height: 1.05; letter-spacing: -0.02em; font-weight: 500; color: var(--ink); margin-bottom: 18px; }
.phase__text p { font-size: clamp(20px, 1.65vw, 26px); line-height: 1.5; font-weight: 500; color: #3c3c40; max-width: 46ch; }
.phase__text > * { opacity: 0; transform: translateY(18px); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.phase.in .phase__text > * { opacity: 1; transform: none; }
.phase.in .phase__text h2 { transition-delay: 0.08s; }
.phase.in .phase__text p { transition-delay: 0.16s; }
.phase.in .phase__text .phase-more { transition-delay: 0.24s; }

/* ---------- gallery (zwei senkrechte Spalten: damals | heute) ---------- */
/* Seit 02.08.2026 nach raus.life-Vorbild: links das Archiv, rechts die
   Gegenwart. Beide Spalten starten OBEN BUENDIG und scrollen normal mit der
   Seite; app.js fuehrt die KUERZERE per leichter Parallaxe mit, sodass beide
   auch am Sektionsende buendig abschliessen — allein die Geschwindigkeit
   gleicht den Laengenunterschied aus. (Ein anfaenglicher 45vh-Versatz sah
   aus, als fehle oben ein Bild — am 02.08. nach einer Stunde wieder raus.) */
.gallery { padding: clamp(70px, 12vh, 170px) var(--pad); }
/* Gleiche Abstaende in BEIDE Richtungen (Benni 02.08.): unter jedem Bild ist
   eine feste Credit-Zeile reserviert (--gal-zone, als padding-bottom am
   .gal-item), der Credit liegt absolut darin und traegt nichts zur Hoehe bei.
   Senkrecht Bild->Bild = --gal-zone + --gal-gap; der Spalten-Abstand ist
   deshalb ebenfalls --gal-gap + --gal-zone — auch Bilder OHNE Credit halten
   so exakt denselben Abstand. */
.gal-cols {
  --gal-gap: clamp(18px, 3vw, 56px);
  --gal-zone: 28px; /* 5px Abstand + eine Zeile 15px/1.5 */
  display: grid; grid-template-columns: 1fr 1fr;
  gap: calc(var(--gal-gap) + var(--gal-zone));
}
.gal-col { position: relative; }
.gal-flow { display: flex; flex-direction: column; gap: var(--gal-gap); will-change: transform; }
.gal-item { position: relative; margin: 0; padding-bottom: var(--gal-zone); }
/* Schlaegt die globale img-Regel (width/height 100% + object-fit: cover
   ganz oben): hier bestimmt das Seitenverhaeltnis die Hoehe, kein Beschnitt. */
.gal-item img { width: 100%; height: auto; object-fit: unset; display: block; background: var(--bg-sepia); }
/* Der Sepia-Charakter des Archivs (frueher der warme Grund des Streifens)
   liegt jetzt als leichter Filter auf den Bildern selbst — vollbreite Bilder
   liessen vom Grund nichts mehr sehen. Ein Wert zum Stimmen. */
[data-era="archive"] .gal-item img { filter: sepia(0.3) contrast(0.97); }
/* Die Galerie zeigt NUR den Credit, keine Unterschrift — die Werte hat Benni
   im Inspektor gestimmt (02.08.: 500 15px/1.5, #343434). "Hidden"
   (bh_credit_mode) blendet ihn aus; die reservierte Zone bleibt, damit die
   Abstaende gleich bleiben. */
.gal-credit {
  position: absolute; left: 0; right: 0;
  top: calc(100% - var(--gal-zone) + 5px);
  text-align: left;
  font: 500 15px/1.5 var(--sans); letter-spacing: 0.01em;
  color: #343434;
}
.bh-credits-hidden .gal-credit { display: none; }
/* Handy: derselbe Zwei-Spalten-Look, nur enger; die langen Archiv-Credits
   brechen in den schmalen Spalten um — die Zone fasst zwei Zeilen. 11px war
   zu gross: die Pompidou-Credits liefen dreizeilig 6px ins naechste Bild
   (gemessen 02.08. bei 390px); bei 10px/1.4 bleiben alle zweizeilig. */
/* REINE BREITE, kein `pointer: coarse` (03.08.2026): Diese Werte beschreiben,
   wie schmal eine Spalte ist — nicht, womit man tippt. Mit dem alten
   `, (pointer: coarse)` bekam ein iPad Pro (1366px, Touch) die Handy-Metrik:
   10px Abstand und 10px-Credits auf ~594px breiten Spalten. */
@media (max-width: 820px) {
  .gal-cols { --gal-gap: 10px; --gal-zone: 31px; } /* 3px + 2 Zeilen 10px/1.4 */
  .gal-credit { top: calc(100% - var(--gal-zone) + 3px); font: 500 10px/1.4 var(--sans); }
}
/* Unter 390px wird die Spalte so schmal (360px Geraet -> 136px Spalte), dass
   der laengste Credit DREI Zeilen braucht und 4px ins naechste Bild lief
   (nachgemessen 03.08.2026). Die Zone fasst dort deshalb drei Zeilen; die
   Abstaende bleiben gleichmaessig, nur etwas luftiger. Die verbreiteten
   390px-Geraete bleiben unberuehrt. */
@media (max-width: 380px) {
  .gal-cols { --gal-zone: 45px; }
}

/* Lange Woerter und URLs umbrechen. Bennos Inhalte tragen absolute Adressen
   (sechs Beitraege mit …dokku.bcbas-Links); eine 46-Zeichen-URL ist bei 16px
   breiter als die Textspalte eines 360px-Handys. Weil `.reader` durch
   `overflow-y: auto` ein EIGENER Scroll-Behaelter ist, faengt das
   `overflow-x: hidden` am body solche Ueberlaeufe dort nicht ab — die
   Unterseite liesse sich seitwaerts ziehen (Review-Fund 03.08.2026). */
.reader__body, .prog-body, .bh-flow, .legal__body, .news-text, .press-body,
.reader__body p, .prog-body p, .bh-flow p { overflow-wrap: anywhere; }

/* ---------- news (Journal-Spalten auf Sepia, seit 02.08.2026) ----------
   Masonry per CSS columns nach Hobday-Vorbild: schlanke Karten mit
   Haarlinie, Mono-Datumszeile (Freitext, leer = keine Zeile), Titel,
   Kurztext, optional ein Bild in Kartenbreite. Der Sepia-Grund hebt die
   Sektion von den hellen Nachbarn ab (dieselbe Farbe wie das Archiv). */
.news { background: var(--bg-sepia); padding: clamp(48px, 8vh, 110px) var(--pad); }
.news-head h2 {
  font-size: clamp(30px, 3.9vw, 64px); line-height: 1.02;
  letter-spacing: -0.03em; font-weight: 500;
  margin-bottom: clamp(22px, 3.5vh, 44px);
}
.news-cols { columns: 3; column-gap: clamp(28px, 3.5vw, 64px); }
@media (max-width: 1180px) { .news-cols { columns: 2; } }
@media (max-width: 720px)  { .news-cols { columns: 1; } }
.news-card {
  display: block; break-inside: avoid;
  margin: 0 0 clamp(26px, 3.2vh, 40px);
  padding-top: 14px;
  border-top: 1px solid rgba(38, 38, 42, 0.25);
  color: inherit;
}
.news-date {
  display: block; font: 400 12px var(--mono); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--acc); margin-bottom: 8px;
}
.news-title { font: 500 clamp(17px, 1.5vw, 22px) var(--sans); letter-spacing: -0.01em; line-height: 1.3; color: var(--ink); margin: 0 0 8px; }
/* Schlaegt die globale img-Regel (height 100% + cover) ganz oben. */
.news-img { width: 100%; height: auto; object-fit: unset; display: block; margin: 4px 0 10px; }
.news-text { font: 400 14px/1.6 var(--sans); color: #3c3c40; margin: 0; }
.news-text a { font-weight: 500; border-bottom: 1px solid var(--acc); }
a.news-card:hover .news-title { color: var(--acc); }
/* Deckel: ab dem siebten Eintrag zu, der Knopf klappt auf (app.js). */
.news--capped .news-card:nth-child(n + 7) { display: none; }
.news-more {
  background: none; border: 0; border-bottom: 2px solid var(--acc);
  padding: 0 0 3px; margin-top: 4px; cursor: pointer;
  font: 500 16px var(--sans); color: var(--ink);
}
.news-more:hover { opacity: 0.6; }

/* ---------- press ---------- */
.press { padding: clamp(34px, 5.5vh, 78px) var(--pad) clamp(30px, 4.5vh, 60px); }
.press-head { margin-bottom: clamp(14px, 2.2vh, 26px); }
.press-head h2 { font-size: clamp(30px, 3.9vw, 64px); line-height: 1.02; letter-spacing: -0.03em; font-weight: 500; }
.press-group { margin-top: clamp(11px, 1.7vh, 20px); }
.press-group__label { font: 400 12px var(--mono); letter-spacing: 0.18em; text-transform: uppercase; color: var(--mut); margin-bottom: 5px; }
.press-list { list-style: none; }
.press-item {
  display: grid; grid-template-columns: minmax(110px, 0.45fr) 1fr; gap: clamp(18px, 3vw, 56px);
  align-items: baseline; padding: clamp(9px, 1.2vh, 14px) 0; border-top: 1px solid #d8d6cf;
}
.press-date { font: 500 clamp(15px, 1.2vw, 19px) var(--sans); letter-spacing: -0.01em; color: var(--acc); }
.press-body { display: flex; flex-direction: column; gap: 4px; }
.press-body a, .press-title-plain { font-size: clamp(18px, 1.6vw, 25px); line-height: 1.14; letter-spacing: -0.015em; font-weight: 500; color: var(--ink); max-width: 52ch; }
.press-body a { border-bottom: 1px solid transparent; align-self: flex-start; transition: border-color 0.3s var(--ease); }
.press-body a:hover { border-color: var(--ink); }
.press-meta { font-size: clamp(14px, 1.15vw, 18px); line-height: 1.45; color: var(--mut); max-width: 52ch; }

@media (max-width: 640px) {
  .press-item { grid-template-columns: 1fr; gap: 8px; }
}

/* ---------- contact ---------- */
.contact { padding: clamp(80px, 16vh, 200px) var(--pad); }
.contact .lbl { font: 400 11px var(--mono); letter-spacing: 0.2em; text-transform: uppercase; color: var(--acc); margin-bottom: 16px; display: block; }
.contact h2 { font-size: clamp(40px, 5vw, 92px); letter-spacing: -0.03em; font-weight: 500; margin-bottom: clamp(36px, 6vh, 72px); }

.contact-cols { display: grid; grid-template-columns: 0.9fr 1fr; gap: clamp(36px, 5vw, 96px); align-items: start; }
.contact-cols--noimg { grid-template-columns: 1fr; max-width: 620px; }
.contact-photo img { display: block; width: 100%; height: auto; }
.contact-main { display: flex; flex-direction: column; gap: clamp(26px, 4vh, 44px); }
.contact-meta { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.contact-meta a { font-size: clamp(15px, 1.3vw, 19px); border-bottom: 1px solid transparent; transition: border-color 0.3s var(--ease); }
.contact-meta a:hover { border-color: var(--acc); }
@media (max-width: 860px) { .contact-cols { grid-template-columns: 1fr; } }

/* contact form — big, underline fields */
/* Kompakter als in V1: Feldschrift lief bis 38px, dadurch wirkte der
   Kasten sehr gross. Benno wollte ihn kleiner. */
.cform .field { border-bottom: 1px solid #cfcfca; padding: clamp(10px, 1.4vh, 16px) 0; transition: border-color 0.3s var(--ease); }
.cform .field:focus-within { border-color: var(--ink); }
.cform label { display: block; font: 400 10px var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--mut); margin-bottom: 6px; }
.cform input, .cform textarea { width: 100%; border: 0; background: transparent; outline: none; font: 500 clamp(16px, 1.35vw, 21px) var(--sans); letter-spacing: -0.01em; color: var(--ink); }
.cform textarea { resize: none; line-height: 1.35; }
.cform input::placeholder, .cform textarea::placeholder { color: #c2c2bc; }
.cbtn { margin-top: clamp(16px, 2.2vh, 26px); border: 0; background: var(--ink); color: #f3f2ee; cursor: pointer; font: 500 clamp(14px, 1.1vw, 17px) var(--sans); padding: clamp(11px, 1.1vw, 14px) clamp(18px, 1.9vw, 26px); align-self: flex-start; transition: background 0.3s var(--ease); }
.cbtn:hover { background: var(--acc); }
.cbtn:disabled { background: #a8a7a2; cursor: default; }
/* Rueckmeldung unter dem Formular (app.js): senden / danke / Fehler.
   Dieselben Werte wie .nform-msg beim Newsletter — wer eine Zeile aendert,
   zieht die andere nach. */
.cform-msg { margin-top: 14px; font-size: 14px; line-height: 1.5; color: #3c3c40; max-width: 42ch; }
.cform-msg--error { color: #a03a2e; }
.cform-note { margin-top: 12px; font-size: 13px; line-height: 1.5; color: var(--mut); max-width: 42ch; }
.cform-note a { border-bottom: 1px solid var(--acc); }

/* newsletter + details (.newsletter hiess bis 02.08.2026 .news — der Name
   gehoert jetzt der News-Sektion weiter oben) */
.contact-side { display: flex; flex-direction: column; gap: clamp(32px, 5vh, 60px); }
/* Newsletter sitzt als eigener, leicht abgesetzter Block — er soll sich vom
   Kontaktformular abheben, ohne laut zu werden (kein Schatten, keine Radien). */
.newsletter { background: #eceae4; border-left: 2px solid var(--acc); padding: clamp(14px, 1.8vw, 20px) clamp(16px, 2vw, 22px); }
.news-label { font: 400 10px var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--mut); margin-bottom: 8px; }
.nform { display: flex; align-items: center; border-bottom: 1px solid #c8c6c0; transition: border-color 0.3s var(--ease); }
.nform:focus-within { border-color: var(--ink); }
/* MINDESTENS 16px: iOS Safari zoomt beim Antippen jedes Feld unter 16px
   automatisch ein, und der Besucher bleibt danach eingezoomt (der Viewport
   erlaubt bewusst Zoom, es gibt kein maximum-scale). Ausgerechnet das
   Anmeldefeld lag mit 15px darunter — .cform input stand schon richtig. */
.nform input { flex: 1; border: 0; background: transparent; outline: none; font: 500 clamp(16px, 1.25vw, 19px) var(--sans); color: var(--ink); padding: 7px 0; }
.nform input::placeholder { color: #b6b4ae; }
.nform button { border: 0; background: transparent; cursor: pointer; font-size: clamp(18px, 1.5vw, 22px); color: var(--acc); padding: 0 4px; }
/* Honeypot: fuer Menschen unsichtbar und per tabindex -1 unerreichbar —
   Bots fuellen es und verraten sich (inc/newsletter.php, inc/contact.php).
   Gilt fuer BEIDE Formulare. */
.nf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
/* Rueckmeldung unterm Feld (app.js): danke bzw. Fehler. */
.nform-msg { margin-top: 14px; font-size: 14px; line-height: 1.5; color: #3c3c40; max-width: 32ch; }
.nform-msg--error { color: #a03a2e; }
.news-note a { border-bottom: 1px solid var(--acc); }
/* Dezenter Pflicht-Link im Contact-Fuss (CalOPPA). */
.privacy-link { display: inline-block; margin-top: 10px; font-size: 13px; color: var(--mut); }
.privacy-link:hover { color: var(--ink); }

/* ---------- legal page (page.php, seit 02.08.2026) ----------
   Schlichte Textseite fuer die Datenschutzerklaerung: schmale Spalte,
   dieselbe Typografie wie der Unterseiten-Fliesstext. */
.legal { max-width: 760px; margin: 0 auto; padding: clamp(40px, 8vh, 90px) var(--pad) clamp(60px, 10vh, 120px); }
.legal__back { display: inline-block; font: 500 17px var(--sans); color: var(--ink); margin-bottom: clamp(28px, 5vh, 50px); }
.legal__back:hover { opacity: 0.6; }
.legal__title { font-size: clamp(30px, 3.9vw, 54px); line-height: 1.05; letter-spacing: -0.03em; font-weight: 500; margin-bottom: clamp(20px, 3.5vh, 36px); }
.legal__body p, .legal__body li { font-size: var(--wp--preset--font-size--medium, 16px); line-height: 1.6; font-weight: 400; color: #3c3c40; margin: 0 0 1.25em; }
.legal__body ul, .legal__body ol { padding-left: 1.2em; margin: 0 0 1.25em; }
.legal__body h2, .legal__body h3, .legal__body h4 { font: 500 clamp(17px, 1.5vw, 22px) var(--sans); letter-spacing: -0.01em; line-height: 1.3; color: var(--ink); margin: 1.5em 0 0.6em; }
.legal__body a { border-bottom: 1px solid var(--acc); }
.news-note { margin-top: 14px; font-size: 14px; line-height: 1.5; color: var(--mut); max-width: 32ch; }

.contact-grid { display: flex; flex-direction: column; gap: 12px; }
.contact-grid a { font-size: clamp(15px, 1.3vw, 19px); border-bottom: 1px solid transparent; align-self: flex-start; transition: border-color 0.3s var(--ease); }
.contact-grid a:hover { border-color: var(--acc); }
.addr { font: 400 11px/1.6 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut); }

/* Reine Breite: Ob zwei Spalten nebeneinander passen, entscheidet der Platz.
   (Mit `pointer: coarse` stand der Kontakt auf einem 1366px-Tablet einspaltig.) */
@media (max-width: 820px) {
  .contact-cols { grid-template-columns: 1fr; gap: clamp(40px, 8vh, 70px); }
}

/* ---------- mobile / vertical fallback ----------
   HIER ist `(pointer: coarse)` PFLICHT und kein Versehen: Diese Query muss
   Zeichen fuer Zeichen zu `desktop()` in app.js passen
   (`min-width: 821px and pointer: fine`). Sie raeumt den Pin-Zustand ab —
   laeuft die Engine nicht, die Regeln aber auch nicht, bliebe die Sektion
   mehrere Bildschirme hoch und die Stationen laegen unerreichbar
   nebeneinander. Wer eine Bedingung aendert, aendert beide.
   Die reinen LAYOUT-Umbrueche (Galerie, Kontakt, Programmzeilen) haengen
   dagegen seit 03.08.2026 allein an der Breite. */
@media (max-width: 820px), (pointer: coarse) {
  .pin { height: auto !important; }
  .pin__stage { height: auto; overflow: visible; }
  .nav-era { display: none; }
  .phases { flex-direction: column; width: auto; }
  .phase { flex: 0 0 auto; width: 100%; grid-template-columns: 1fr; gap: 28px; min-height: auto; padding: 56px var(--pad); }
  /* Der zweite Selektor traegt dieselbe Spezifitaet wie die Grundregel oben
     (`:not(:has(…))` erbt die seines Arguments, also (0,3,0)) — ohne ihn
     gewann dort das schmale `padding: var(--pad)`, und die Statement-Tafel
     ohne Bild startete mobil mit 24px statt 90px unter der fixierten
     Leiste (Review-Fund 03.08.2026). */
  .phase.phase--about,
  .phase.phase--about:not(:has(.phase__media)) { display: block; padding: 90px var(--pad) 30px; }
  .about-text { max-width: none; }
  .phase__media { height: 52vh; clip-path: none; }
  .phase__text > * { opacity: 1; transform: none; }
}

/* ---------- exhibitions (dark, tabular index) ---------- */
.exhibitions { background: #1a1a1c; color: #ece9e1; padding: clamp(70px, 12vh, 170px) var(--pad) clamp(80px, 14vh, 200px); }
.exh-inner { max-width: none; margin: 0; }

.exrow { position: relative; display: grid; grid-template-columns: 1.45fr 4fr; gap: clamp(28px, 4vw, 80px); align-items: center; padding: clamp(28px, 4.5vh, 60px) 0; }
/* no rules between rows — the only borders are the year-group brackets
   (.acc-year ::before/::after): a line above the first row and after the last */
.exrow__media { display: block; overflow: hidden; aspect-ratio: 4 / 3; background: #222; }
.exrow__media img { transition: transform 0.8s var(--ease); }
.exrow__media:hover img { transform: scale(1.04); }
.exrow__date { display: block; font-size: clamp(22px, 2.1vw, 34px); line-height: 1.08; letter-spacing: -0.015em; font-weight: 500; color: var(--acc); margin-bottom: 10px; }
.exrow__text h3 { font-size: clamp(22px, 2.1vw, 34px); line-height: 1.08; letter-spacing: -0.015em; font-weight: 500; color: #f4f2ea; margin-bottom: 16px; }
.exrow__text p { font-size: clamp(20px, 1.65vw, 26px); line-height: 1.5; color: #c4c1b7; max-width: none; }
.exrow__text a { color: var(--acc); }
/* Der Titel ist seit 06.08.2026 ein Link auf die Unterseite — die Zeile darueber
   faerbt aber JEDEN Link in der Zeile blau, und der Titel gehoert der h3.
   Gemessen: sonst rgb(115,142,200) statt der hellen Schrift. Der lange Selektor
   ist noetig, weil `.exrow__open` allein (0,1,0) gegen `.exrow__text a` (0,1,1)
   verliert. */
.exrow__text .exrow__open { color: inherit; }

.exh-past { margin-top: clamp(16px, 3vh, 40px); }
.exh-past__label { font-size: clamp(13px, 1vw, 15px); color: #9b988f; margin-bottom: 6px; }
.acc { position: relative; }
.acc-year { position: relative; }
.acc-year::after, .acc-year:first-child::before {
  content: ""; position: absolute; left: 0; right: 0; height: 2px;
  background: #f2f1ec; transform: scaleX(0); transform-origin: left;
  transition: transform 0.8s var(--ease); z-index: 1;
}
.acc-year::after { bottom: 0; }
.acc-year:first-child::before { top: 0; }
.acc-year.in::after, .acc-year.in:first-child::before { transform: scaleX(1); }
.acc-head { width: 100%; background: none; border: 0; cursor: pointer; display: flex; align-items: center; justify-content: space-between; padding: clamp(20px, 3vh, 38px) 0; text-align: left; }
.acc-yr { font-size: clamp(34px, 4vw, 72px); font-weight: 500; letter-spacing: -0.02em; color: #f4f2ea; line-height: 1; }
.acc-chev { width: 18px; height: 18px; position: relative; flex: 0 0 auto; }
.acc-chev::before, .acc-chev::after { content: ""; position: absolute; top: 50%; width: 11px; height: 2px; background: #f4f2ea; transition: transform 0.4s var(--ease); }
.acc-chev::before { left: 0; transform: rotate(45deg); }
.acc-chev::after { right: 0; transform: rotate(-45deg); }
.acc-year.open .acc-chev::before { transform: rotate(-45deg); }
.acc-year.open .acc-chev::after { transform: rotate(45deg); }
.acc-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.55s var(--ease); }
.acc-year.open .acc-body { grid-template-rows: 1fr; }
.acc-inner { overflow: hidden; }
.acc-inner .exrow:first-child { border-top: 0; }

/* fixed menu while over the dark exhibitions section */
.topnav.on-dark a { color: #f2f1ec; }
.topnav.on-dark a.on { border-color: #f2f1ec; }
/* Die Pfeile der Menuespur und der Zurueck-Knopf gehoeren dazu — sie tragen
   ihre Farbe selbst (color: var(--ink)) und blieben ueber dem dunklen
   Exhibitions-Grund sonst als schwarze Zeichen stehen. */
/* NUR der Pfeil, NICHT der Zurueck-Knopf.
   `.nav-back` stand bis zum 06.08.2026 mit in diesem Selektor — und war damit
   in jedem Fall falsch: Der Knopf erscheint ausschliesslich mit
   `body.is-reading`, und in dem Zustand bekommt die Leiste weiter oben
   ausdruecklich wieder `background: var(--bg)`. Die helle Schrift lag also
   immer auf hellem Grund. Gemessen auf der Live-Seite: Grund
   rgb(243,242,238), Schrift rgb(242,241,236) — ein Helligkeitsschritt von 1
   aus 255, der Knopf war unsichtbar. Aufgefallen ist es erst, als die
   Unterseiten eigene Adressen bekamen: Ueber die Uebersicht geoeffnet traegt
   die Leiste `.on-dark` (Knopf weg), direkt aufgerufen nicht (Knopf da) —
   derselbe Bildschirm, zwei Ergebnisse.
   Der Pfeil dagegen ist ohne `is-reading` sichtbar und braucht die Zeile. */
.topnav.on-dark .nav-arrow { color: #f2f1ec; }

/* Reine Breite: Der Umbruch auf eine Spalte samt 3:2-Bild ist eine
   Platzfrage. Mit `pointer: coarse` traf es auch grosse Tablets — auf einem
   iPad Pro (1366px) wurde jedes Programmbild ~1220x813px, eine einzige
   Zeile fuellte mehr als einen Bildschirm (Review-Fund 03.08.2026). */
@media (max-width: 820px) {
  .exrow { grid-template-columns: 1fr; gap: 14px; }
  .exrow__media { aspect-ratio: 3 / 2; }
}

.hero-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }

/* Im HOCHFORMAT wird aus `cover` ein extremer Zoom ins 16:9-Video (Benno,
   31.07.2026) — dort laeuft das Video stattdessen als Letterbox: ganzes
   Bild, mittig, dunkler Grund drumherum. `!important` am Hintergrund noetig,
   weil das Poster-JPG als Inline-Style an .hero-bg haengt und sonst hinter
   der Letterbox hervorschiene. */
@media (orientation: portrait) {
  .hero-video { object-fit: contain; }
  .hero-bg { background: #15151a !important; }
}

/* ====================================================================
   IN-PAGE READER — "Read the full story" (Mission / History)
   ==================================================================== */
/* Seit 06.08.2026 ist das ein <a> (jede Unterseite hat eine eigene Adresse) und
   kein <button> mehr. `display: inline-block` muss deshalb ausdruecklich hier
   stehen: Ein Knopf ist das von Haus aus, ein Link nicht — und an einer reinen
   inline-Box wirkt kein senkrechter Abstand. Gemessen am 06.08.: margin-top
   38px deklariert, real 3px Luecke, der Knopf klebte am Teaser. */
.reveal-btn {
  display: inline-block;
  background: none; border: none; cursor: pointer; padding: 0;
  margin-top: clamp(22px, 3vh, 38px); font: 500 clamp(15px, 1.15vw, 18px) var(--sans);
  color: var(--acc); border-bottom: 1px solid transparent; transition: border-color 0.3s var(--ease);
  position: relative;
}
/* Fingergerechte Trefferflaeche (der Knopf ist nur ~26px hoch). ::before,
   weil ::after in den Stationen die einfahrende Unterstreichung ist. */
.reveal-btn::before { content: ""; position: absolute; left: 0; right: 0; top: -10px; bottom: -10px; }
.reveal-btn:hover { border-color: var(--acc); }

/* Der Knopf zur Unterseite in den ABOUT-Stationen: groesser als die uebrigen
   reveal-Knoepfe, und die Unterstreichung zeichnet sich von links nach
   rechts, sobald die Station erreicht ist (.phase.in setzt die Pin-Engine;
   Bennis Wunsch vom 01.08.2026). Der Strich ersetzt hier die Hover-Border —
   beides uebereinander gaebe zwei Linien. */
.phase .reveal-btn {
  font-size: clamp(17px, 1.35vw, 22px);
  border-bottom: 0;
  position: relative;
  padding-bottom: 5px;
}
.phase .reveal-btn::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--acc);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.9s var(--ease) 0.35s;
}
.phase.in .reveal-btn::after { transform: scaleX(1); }
/* Ohne Pin (Touch/schmal) vergibt niemand .in — dort steht der Strich fest. */
/* Gehoert zum Pin-Fallback oben (gleiche Bedingung, gleicher Grund): Ohne
   laufende Engine kommt `.phase.in` nicht gestaffelt an, der Strich stuende
   sonst nie. */
@media (max-width: 820px), (pointer: coarse) {
  .phase .reveal-btn::after { transform: scaleX(1); transition: none; }
}

/* same page background, layered UNDER the fixed nav + era indicator (z-index 80) */
.reader {
  position: fixed; inset: 0; z-index: 70; background: var(--bg);
  overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.34s var(--ease), visibility 0.34s var(--ease);
  /* Auf dem Handy schaute unten die Seite durch (Bennis Screenshot 03.08.) —
     zwei Ursachen, beide hier abgestellt:
     1. `inset: 0` misst gegen den Layout-Viewport; klappen Safaris Leisten
        beim Scrollen ein, waechst der sichtbare Bereich, das Overlay nicht.
        `100dvh` folgt der Leiste (vh bleibt als Rueckfall fuer Alte).
     2. Am Scroll-Ende federt iOS ueber die Kante hinaus und gibt den Blick
        auf den Seitenhintergrund frei — `overscroll-behavior: none` haelt
        die Bewegung im Overlay (verhindert zugleich Scroll-Chaining auf die
        Seite darunter, die beim Lesen still steht). */
  height: 100vh;
  height: 100dvh;
  overscroll-behavior: none;
}
.reader.open { opacity: 1; visibility: visible; pointer-events: auto; }
.reader__inner {
  max-width: min(1340px, 94vw); margin: 0 auto;
  padding: clamp(92px, 12vh, 132px) var(--pad) clamp(48px, 8vh, 80px);
  transform: translateY(18px); transition: transform 0.4s var(--ease);
}
.reader.open .reader__inner { transform: none; }
/* Der grosse Seitentitel einer Unterseite.
   Auf den eigenstaendigen Seiten (single-*.php, seit 06.08.2026) ist er eine
   h1: Dort gibt es keinen Hero, und auf der Startseite traegt die Wortmarke im
   Hero die h1 — eine Seite ganz ohne h1 sagt Suchmaschinen nicht, worum sie
   geht. Im Overlay bleibt es eine h2, sonst haette die Startseite zwei h1.
   Beide Formen MUESSEN gleich aussehen, deshalb eine Regel.
   `>` bzw. `.prog-head` grenzen gegen Inhalts-Ueberschriften ab: die stehen in
   .reader__body / .prog-body und haben ihre eigene Stufe (prog-reader.css). */
.reader__inner h2,
.reader__inner > h1,
.prog-head > h1 {
  font-size: clamp(34px, 4.6vw, 64px); line-height: 0.98; letter-spacing: -0.03em;
  font-weight: 500; color: var(--ink); margin: 0 0 clamp(26px, 4.5vh, 48px);
}
/* up to three columns by viewport; balanced so the block fits the screen and
   only scrolls when the text genuinely cannot fit the available height */
/* Die Unterseite selbst ist seit 07/2026 ein normaler Blockfluss. Die Spalten
   traegt der Block bh/flowtext (.bh-flow) — vorher war die ganze Seite
   dreispaltig, wodurch ein Bild zwangslaeufig in eine Spalte rutschte statt
   daneben oder darueber zu stehen. */
/* Die Regeln zu .bh-flow stehen seit dem 26.07.2026 in assets/prog-reader.css.
   Grund: site.css laedt der Block-Editor NICHT. Solange sie hier standen, sah
   der Editor die Spalten des Blocks nicht — und editor-about.css hat sie
   ersatzweise ueber den ganzen Wurzel-Container gelegt, also auch ueber
   Bilder. prog-reader.css wird dagegen im Frontend UND im Editor geladen. */

/* Abstand zwischen den Bausteinen der Unterseite */
.reader__body > * + * { margin-top: clamp(24px, 3.5vh, 44px); }
/* … aber NICHT zwischen zwei Absaetzen: Fliesstext folgt dem Absatz-Abstand
   (1.25em wie im Programm-Reader), nur echte Bausteine (Bild, Galerie,
   Ueberschrift, Spalten) bekommen die grosse Luecke. Vorher las sich der
   About-Fliesstext durch die Blockabstaende wie eine andere Textsorte. */
.reader__body > p + p { margin-top: 0; }

/* Leere Absaetze verschwinden im FRONTEND: Benno setzt sie als
   Abstandshalter (31.07.2026: 20 Stueck quer durch alle Unterseiten) —
   mit dem festen Blockabstand oben ergaeben sie doppelte Luecken. Im
   Editor bleiben sie sichtbar (diese Datei laedt er nicht), sonst koennte
   man einen frisch angelegten Absatz nicht sehen. Die Datenbank bleibt
   unangetastet. */
.reader__body p:empty,
.prog-body p:empty,
.bh-flow p:empty { display: none; }

/* Die Optik der Programm-Unterseite steht seit 07/2026 in
   assets/prog-reader.css — dieselbe Datei liefert der Block-Editor aus,
   damit Vorschau und Frontend nicht auseinanderlaufen. */

/* ---------- Social-Icons (Hero + Contact) ---------- */
.social-icons { display: flex; gap: 14px; }
.social-icons a { display: inline-flex; opacity: 0.72; transition: opacity 0.3s var(--ease); position: relative; }
/* Die Symbole sind 20x20 — als Tippziel zu klein (Richtwert 44px). Die
   Trefferflaeche waechst deshalb per ::after ueber das Sichtbare hinaus,
   ohne das Layout anzufassen. Die 14px Abstand liegen zwischen den
   Flaechen, sie ueberlappen also nicht. */
.social-icons a::after { content: ""; position: absolute; left: -7px; right: -7px; top: -11px; bottom: -11px; }
.social-icons a:hover { opacity: 1; }
/* Unten links im Eck, auf einer Linie mit dem Scroll-Pfeil.
   fixed statt absolute, damit sie den Hero ueberdauern und in der
   About-Sektion weiter mitlaufen — dort wechseln sie auf die dunkle
   Textfarbe, weil der Hintergrund (--bg) hell ist. */
.social-icons--hero {
  position: fixed; z-index: 4; color: #fff;
  left: var(--pad); bottom: 30px;
  transition: opacity 0.4s var(--ease), color 0.4s var(--ease);
}
.social-icons--hero.on-light { color: var(--ink); }
.social-icons--hero.is-gone { opacity: 0; pointer-events: none; }
.social-icons--contact { color: inherit; }

/* ---------- Scroll-Hinweis ---------- */
/* fixed, nicht absolute: der Pfeil soll laut Benno auch in der About-Sektion
   noch dastehen (dort nur ohne Huepfen). Im Hero weiss, danach dunkel. */
.scroll-cue {
  position: fixed; left: 50%; bottom: 30px; z-index: 4; color: #fff; opacity: 0.7;
  transform: translateX(-50%); animation: bh-bob 1.9s var(--ease) infinite;
  transition: opacity 0.4s var(--ease), color 0.4s var(--ease);
}
.scroll-cue:hover { opacity: 1; }
.scroll-cue.is-still { animation: none; }
.scroll-cue.on-light { color: var(--ink); }
.scroll-cue.is-gone { opacity: 0; pointer-events: none; }
@keyframes bh-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 8px); }
}
@media (prefers-reduced-motion: reduce) { .scroll-cue { animation: none; } }

/* Programs: die ganze Zeile oeffnet das Overlay */
.exrow--open { cursor: pointer; }

/* ---------- Bildunterschriften aus dem Block-Editor ----------
   Gleiche Struktur wie die Galerie-Credits der Startseite (Benni 02.08.:
   "keine mono font und nicht grau"): Grundschrift, dunkel, klein — und
   kleiner als die 15px der Galerie, weil der Fliesstext der Unterseiten
   selbst kleiner ist. Der Slider (.prog-slide-caption/-credit) und der
   Editor (editor-base.css) spiegeln diese Werte. */
.wp-element-caption,
figure.wp-block-image figcaption,
figure.wp-block-gallery figcaption,
figure.wp-block-embed figcaption {
  font: 500 12px/1.5 var(--sans);
  letter-spacing: 0.01em;
  color: #343434;
  margin-top: 6px;
  text-align: left;
}
/* Cores GALERIE-Styles legen die figcaption jedes Galerie-Bilds als weisses
   Overlay AUFS Bild (position:absolute, 13px, Verlauf, zentriert) — genau
   die Optik, die Benni am 02.08. abgeraeumt hat. Selektor wortgleich wie
   Cores Regel (wp-block-gallery-inline-css); site.css laedt spaeter und
   gewinnt. Die Unterschrift fliesst damit wie ueberall UNTER das Bild. */
.wp-block-gallery.has-nested-images figure.wp-block-image figcaption {
  position: static;
  background: none;
  padding: 0;
  max-height: none;
  overflow: visible;
  width: 100%;
  font: 500 12px/1.5 var(--sans);
  letter-spacing: 0.01em;
  color: #343434;
  margin: 6px 0 0;
  text-align: left;
  text-shadow: none;
}
/* Beschnittene Galerien: festes Seitenverhaeltnis je Bild statt Cores
   "fuelle die Figur"-Crop. Cores Mechanik (img{height:100%; flex:1}) laesst
   die Unterschrift von der BILDhoehe abbeissen — seit sie im Fluss unter dem
   Bild steht, schrumpften die Bilder einer Reihe ungleich (gemessen 02.08.:
   223/279/224 nebeneinander). Festes Verhaeltnis: alle Bilder einer Reihe
   gleich hoch, die Unterschrift haengt frei darunter — dieselbe Struktur wie
   die Startseiten-Galerie. Ein im Editor GEWAEHLTES Verhaeltnis steht inline
   am <img> und gewinnt weiterhin. Selektor mit Cores :not(#…)-Trick, sonst
   verliert die Regel gegen Cores Crop-Regel. */
.wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#individual-image) img {
  height: auto;
  flex: 0 0 auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#individual-image) {
  align-self: flex-start;
}
/* Cores Scrim zur alten Overlay-Unterschrift: ein ::before mit
   backdrop-filter: blur an der Bildunterkante. Seit die Unterschrift UNTER
   dem Bild steht, blieb davon nur ein verschwommener Streifen uebrig
   (Bennis Screenshot 02.08.). Selektor wortgleich wie Cores Regel. */
.wp-block-gallery.has-nested-images figure.wp-block-image:has(figcaption)::before {
  content: none;
}
/* Fruehere Umbrueche (Benni 02.08.): Cores Standard haelt drei Spalten bis
   hinunter zu 600px — auf Tablets wird das zu eng, und auf dem Handy sollen
   die Bilder untereinander stehen. !important, weil Cores Breitenregeln je
   nach columns-N-Klasse unterschiedlich stark sind. */
@media (max-width: 1024px) {
  .wp-block-gallery.has-nested-images figure.wp-block-image:not(#individual-image) {
    width: calc(50% - (var(--wp--style--unstable-gallery-gap, 16px) / 2)) !important;
  }
}
@media (max-width: 640px) {
  .wp-block-gallery.has-nested-images figure.wp-block-image:not(#individual-image) {
    width: 100% !important;
  }
}

/* Bloecke im Fliesstext der About-Unterseiten */
.reader__body .wp-block-image,
.reader__body .wp-block-gallery,
.reader__body .wp-block-embed {
  margin: 1.6em 0;
}

.reader__body .wp-block-image img {
  width: 100%;
  height: auto;
}

/* Banner: das ERSTE Bild einer About-Unterseite laeuft einheitlich als
   Querformat ueber die volle Breite — mittig beschnitten, feste Hoehe.
   (Benno, 30.07.2026: Bilder oben "als Banner-Elemente mittig zentrieren
   und fixieren"; die Align-Wahl im Editor kam im Frontend nie an.)
   `!important` schlaegt die Inline-Groessen aus dem Editor (width:644px,
   aspect-ratio:…) — genau diese haendischen Masse sollen oben keine Rolle
   mehr spielen. Gegenstueck im Editor: assets/editor-about.css. */
.reader__body > .wp-block-image:first-child { margin-top: 0; width: 100%; }
.reader__body > .wp-block-image:first-child img {
  width: 100% !important;
  height: clamp(240px, 40vh, 440px) !important;
  aspect-ratio: auto !important;
  object-fit: cover;
  object-position: center;
}
/* Wahl je Seite (Block-Stil "Full height (no crop)", inc/blocks.php):
   volle Breite, aber natuerliche Hoehe statt Banner-Beschnitt. */
.reader__body > .wp-block-image.is-style-bh-full-height:first-child img {
  height: auto !important;
}

/* ---------- Bild-Credits ----------
   Der Credit haengt am Bild (Attachment-Meta), nicht an der Stelle. Er sitzt
   unten links IM Bild — auf dunklem Verlauf, damit er auf hellen wie dunklen
   Motiven lesbar bleibt. Zwei Betriebsarten, umschaltbar in den Galerien:
   sichtbar oder ganz ausgeblendet. */
.bh-shot { position: relative; margin: 0; }
.bh-shot img { display: block; width: 100%; height: auto; }
/* Inline-Variante fuer core/image (bh_credit_pos 'overlay'): ein <span> UM
   das <img> in der <figure>, damit der Credit auf dem Bild ankert und nie
   auf der Unterschrift liegt (siehe inc/credits.php).

   KEIN width:fit-content hier: Das war zirkulaer (Span folgt dem Bild, Bild
   ist 100% des Spans). Chrome loeste das gnaedig auf, Safari kollabierte
   auf Handbreite — auf dem iPhone fehlte das Mission-Banner komplett, nur
   der Credit-Gradient blieb als schmaler Streifen stehen (Bennos Screenshot
   vom 01.08.2026). Ein schlichter Block hat eine bestimmte Breite (die der
   Figure) und rechnet in jeder Engine gleich; bei von Hand verkleinerten
   Bildern kann der Gradient dadurch breiter sein als das Bild — sichtbar
   nur in der Randspalte, verschmerzbar gegen ein fehlendes Banner. */
.bh-shot--inline { display: block; position: relative; line-height: 0; }
/* In GALERIEN darf der Credit-Span die Crop-Mechanik von core nicht brechen:
   "Crop images to fit" setzt dort img{height:100%} — mit dem Span dazwischen
   lief das gegen dessen auto-Hoehe ins Leere, die Bilder blieben in ihrer
   natuerlichen Hoehe und jede Reihe sah zerrupft aus (Bennis Screenshot der
   History-Seite, 01.08.2026; Backend ohne Credit-Spans sah korrekt aus).
   Der Span fuellt deshalb die Figure und reicht die Hoehe ans Bild weiter.
   `:not(#individual-image)` ist Cores eigener Spezifitaets-Trick — ohne ihn
   verliert die Regel gegen Cores `img { height:auto }`. */
.wp-block-gallery.has-nested-images figure.wp-block-image:not(#individual-image) > .bh-shot--inline {
  display: flex;
  flex: 1 0 0%;
  width: 100%;
  align-self: stretch;
}
.wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#individual-image) > .bh-shot--inline img {
  height: 100%;
  width: 100%;
  flex: 1 0 0%;
  object-fit: cover;
}
.bh-credit {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 26px 14px 10px;
  font: 400 10px var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: #fff; text-align: left;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0));
  pointer-events: none;
}
/* 'hidden' blendet den Credit komplett aus. Bis 26.07.2026 gab es hier einen
   dritten Zustand (nur bei Hover sichtbar) — der entfaellt mit der
   Vereinheitlichung auf genau zwei Werte in bh_credit_mode() (inc/credits.php).
   Die Klasse setzt bh_wrap_credit() aus demselben Wert.

   Die Klasse am <body> ist der VERLAESSLICHE Schalter, nicht die am Bild:
   Credits erscheinen an drei verschiedenen Stellen, und nur eine davon geht
   durch bh_wrap_credit(). Bilder in Blockinhalten bekommen ihren Credit vom
   render_block-Filter direkt in WordPress' eigene <figure class="wp-block-image">
   gehaengt — dort gibt es kein .bh-shot--hidden, der Credit waere bei
   "Hidden" also sichtbar geblieben (26.07.2026 beim Nachmessen gefunden).
   Deshalb greift die Regel unten an ALLEN .bh-credit, egal wo sie sitzen. */
.bh-credits-hidden .bh-credit { display: none; }
.bh-shot--hidden .bh-credit { display: none; }

/* Bilder in Blockinhalten tragen ihren Credit als eigene ZEILE unter der
   Bildunterschrift, nicht als Ueberlagerung im Bild.

   Bis zum 27.07.2026 lag er dort als `.bh-credit` absolut auf dem Bild. Der
   Bezugsrahmen ist aber die ganze <figure> samt Bildunterschrift — sobald ein
   Bild eine hatte, rutschte der Credit auf sie darauf (gemessen: 2px
   Ueberlappung, Verlauf ueber der Bildkante). Unten ist ohnehin Platz; die
   Ueberlagerung braucht es nur, wo keiner ist (Stationsbilder, Streifen).

   Die Zeile erbt die Typografie der Bildunterschrift in VOLLER Farbe —
   die gedaempfte Deckkraft von frueher (0.7) las sich grau, und "nicht
   grau" war Bennis ausdrueckliche Ansage (02.08.). Das "Photo ©" im Text
   unterscheidet Credit und Unterschrift von selbst. */
.bh-credit-line { display: block; }
.bh-credit-only { margin-top: 6px; }
/* "Hidden" laesst sonst die leere Nur-Credit-figcaption samt Abstand stehen. */
.bh-credits-hidden .bh-credit-only { display: none; }
.bh-credits-hidden .bh-credit-line { display: none; }

/* ---------- YouTube-Vorschau (bh_yt_facade, functions.php) ----------
   Eigenes Standbild + Play-Knopf statt des YouTube-iframes; erst der Klick
   laedt den Player (app.js). hqdefault.jpg ist 4:3 mit schwarzen Balken —
   object-fit: cover beschneidet sie. Im responsive-Embed-Rahmen von
   WordPress uebernimmt der Knopf die absolute Lage des iframes. */
.bh-yt {
  position: relative; display: block; width: 100%; aspect-ratio: 16 / 9;
  padding: 0; border: 0; background: #15151a; cursor: pointer;
}
.wp-embed-responsive .wp-has-aspect-ratio .bh-yt {
  position: absolute; top: 0; left: 0; height: 100%; aspect-ratio: auto;
}
.bh-yt img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bh-yt__play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 64px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(21, 21, 26, 0.85); color: #fff;
}
.bh-yt__play svg { width: 26px; height: 26px; }
.bh-yt:hover .bh-yt__play,
.bh-yt:focus-visible .bh-yt__play { background: var(--acc); }

/* Der Credit zieht eine <figure> um das Bild. Bei den Stationsbildern der
   About-Sektion fuellt das Bild
   seinen Rahmen, der Credit sitzt darin unten links. */
.phase__media .bh-shot { height: 100%; }
.phase__media .bh-shot img { height: 100%; width: 100%; object-fit: cover; }
