/* ==========================================================================
   never in time — neverintime.de
   Alle Werte stammen aus DESIGN.md. Nichts hier ohne Eintrag dort.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Schriften — selbst gehostet, kein Google-CDN (DSGVO, siehe datenschutz.html)
   Genau die vier Schnitte, die im Stylesheet vorkommen. Welche Dateien
   gebraucht werden und woher sie kommen: fonts/README.md
   Fehlen die Dateien, greifen die Fallbacks weiter unten — die Seite bleibt
   benutzbar, trifft aber die Skala aus DESIGN.md §4 nicht.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-900.woff2") format("woff2");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Fira Sans";
  src: url("../fonts/fira-sans-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Fira Mono";
  src: url("../fonts/fira-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Fira Mono";
  src: url("../fonts/fira-mono-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Farben — aus Video und Logo gemessen, siehe DESIGN.md §3 */
  --wall:  #D9D7D2;
  --void:  #0C0B0B;
  --blood: #78100A;
  --flare: #C81E10;
  --chalk: #EDEAE4;
  --dust:  #8A8580;

  /* Drittes Rot, ausschließlich für KLEINE rote Schrift auf --void.
     Notwendig, nicht kosmetisch: --blood erreicht dort 1,7:1 und --flare 3,4:1,
     beides unlesbar bei 13 px. Dieser Ton kommt auf 4,74:1 und erfüllt AA.
     Auf hellem Grund werden Labels stattdessen --blood (7,9:1). */
  --label: #E63A22;

  /* ------------------------------------------------------------------------
     --lit: Helligkeit des Seitengrundes. 0 = dunkel, 1 = hell.
     Das JS schreibt es fortlaufend aus der Scrollposition; die Abschnitte
     wechseln sich ab. Ausgangswert 1, weil der Hero an der hellen Wand
     beginnt — so stimmt schon der erste Frame, bevor JS läuft.

     Alles Farbige auf der Seite hängt an den vier Tokens darunter, nicht an
     den Rohfarben. Das ist der einzige Weg, bei wechselndem Grund keine
     unlesbaren Stellen zu bekommen: --dust auf Putz käme auf 2,5:1,
     --label gilt nur für dunklen Grund.
     ------------------------------------------------------------------------ */
  --lit: 1;

  --ground:      color-mix(in oklab, var(--void), var(--wall) calc(var(--lit) * 100%));
  --ink:         color-mix(in oklab, var(--chalk), var(--void) calc(var(--lit) * 100%));
  --ink-soft:    color-mix(in oklab, var(--dust), #5C5854 calc(var(--lit) * 100%));
  --accent-text: color-mix(in oklab, var(--label), var(--blood) calc(var(--lit) * 100%));
  --hairline:    color-mix(in oklab, #3A3634, #B4B0AA calc(var(--lit) * 100%));

  --font-display: "Archivo", "Arial Black", "Helvetica Neue", Helvetica, sans-serif;
  --font-body: "Fira Sans", "Segoe UI", system-ui, sans-serif;
  --font-mono: "Fira Mono", ui-monospace, Consolas, monospace;

  /* Typo-Skala — DESIGN.md §4 */
  --t-display-l:  clamp(2.25rem, 7vw, 6rem);
  --t-display-m:  clamp(1.5rem, 4vw, 3rem);
  --t-lead:       clamp(1.125rem, 1.6vw, 1.5rem);
  --t-body:       1.0625rem;
  --t-small:      0.9375rem;
  --t-meta:       0.8125rem;

  /* Raster — DESIGN.md §5 */
  --gutter: clamp(1.25rem, 5vw, 6rem);
  --maxw: 1440px;
  --section-y: clamp(6rem, 12vh, 12rem);

  /* Geometrie der Logo-Übergabe. Am Frame bei 2,300 s gemessen (DESIGN.md §8).
     Prozentwerte beziehen sich auf den Videorahmen. Kalibrierknopf: wenn der
     Crossfade sichtbar springt, hier justieren — nicht im JS. */
  --handoff-left: 33.90%;
  --handoff-top: 52.73%;
  --handoff-width: 41.61%;

  /* Zielzustand des fixierten Logos */
  --brand-width: clamp(120px, 14vw, 200px);
  --brand-top: 12px;

  /* Vom JS gesetzt: 0 = an der Wand, 1 = durch die Wand */
  --through: 0;

  /* Wachstum des Hero-Rahmens. Ausgangswert 1 (Endgröße), weil das ohne JS und
     in den Modi play/static der richtige Zustand ist. Nur der Scrub-Modus
     zieht ihn auf 0 herunter und wieder hoch — das setzt das JS inline am
     <html>, was diese Regel überstimmt. */
  --frame-grow: 1;
}

*, *::before, *::after { box-sizing: border-box; }

/* Folgt dem Grund wie der body. Vorher stand hier --wall: Beim Überscrollen
   am Seitenende zog man auf iOS den hellen Putz hinter den dunklen Footer. */
html {
  background: var(--ground);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  color: var(--ink);
  background: var(--ground);
  overflow-x: hidden;
}

/* Die Rechtsseiten haben keinen wechselnden Grund — sie stehen fest auf
   dunkel, damit sie nicht davon abhängen, ob ein Skript läuft. */
.ground-dark { --lit: 0; }

/* --------------------------------------------------------------------------
   Kleinschreibung des Fließtexts
   Bewusst über text-transform und NICHT in der Quelle: im Dokument bleibt
   „Emsland" großgeschrieben, damit Vorlesesoftware, Suchmaschinen und
   Kopieren-und-Einfügen korrektes Deutsch bekommen.
   Ausgenommen: Überschriften, Labels, Buttons, die Bandnamen im Repertoire
   (die stehen so, wie die Bands sich schreiben) — und die Rechtstexte.
   -------------------------------------------------------------------------- */

.invert__claim,
.invert__text p,
.lead,
.prose p,
.crew__line,
.steps__item p,
.dates__note,
.dates__empty,
.footer__band,
.footer__nav a { text-transform: lowercase; }

:focus-visible {
  outline: 2px solid var(--flare);
  outline-offset: 3px;
}

img, svg, video { display: block; max-width: 100%; }

/* ==========================================================================
   Fixiertes Logo
   ========================================================================== */

.masthead {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
}

.brand {
  display: block;
  width: var(--brand-width);
  margin-block-start: var(--brand-top);
  pointer-events: auto;
  /* Folgt dem Grund, nicht dem Hero: Oxblood auf hell, Chalk auf dunkel.
     Gilt genauso für den hellen Abschnitt 152. DESIGN.md §3 */
  color: color-mix(in oklab, var(--chalk), var(--blood) calc(var(--lit) * 100%));
}

.brand__mark {
  width: 100%;
  height: auto;
  fill: currentColor;
}

/* Das Logo bleibt immer an seinem Platz im Fluss — seine Ruhelage IST die
   Zielposition. Während der Übergabe verschiebt und skaliert es nur ein
   transform, das auf der Identität endet; der fixierte Zustand ist dadurch
   pixelscharf und nicht interpoliert. Kein Wechsel des Positionierungsmodus. */
.js .masthead[data-state="handoff"] .brand {
  transform-origin: 0 0;
  will-change: transform;
}

.js .masthead[data-state="hidden"] .brand { opacity: 0; }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  height: 100vh; /* ohne JS: ein Bildschirm, Poster steht */
}

.js .hero { height: 300vh; }
.js .hero[data-mode="play"],
.js .hero[data-mode="static"] { height: 100vh; }

.hero__stage {
  position: sticky;
  inset-block-start: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(1.5rem, 4vh, 3rem);
  /* Der Putz wird zum Loch. Einziger Übergang hell -> dunkel auf der Seite. */
  background-color: color-mix(in oklab, var(--wall), var(--void) calc(var(--through) * 100%));
}

/* Der Rahmen wächst beim Scrollen — der Effekt von x2ycreative.com, hier mit
   Grund: Man kommt der Wand näher, bis sie bricht. --frame-grow setzt das JS
   in Phase A (0 -> 1).
   Obergrenze 1700 px: die Quelle ist 1178 px breit, darüber wird sichtbar
   weich. Wenn das Video jemals größer gerendert werden kann, hier anheben. */
.hero__frame {
  position: relative;
  width: min(calc(58vw + 34vw * var(--frame-grow)), 1700px);
  aspect-ratio: 1178 / 786;
  opacity: calc(1 - var(--through));
}

.hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Der Bandname steht als echter Text im Dokument, sichtbar nur ohne JS.
   Screenreader und Suchmaschinen finden ihn immer. */
.hero__name {
  position: absolute;
  inset-block-end: 6%;
  inset-inline: 0;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 5vw, 4rem);
  font-weight: 900;
  letter-spacing: -0.02em;
  line-height: 0.96;
  text-align: center;
  color: var(--blood);
}

.js .hero__name {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Verschwindet mit der Wand. Kein Rot auf Schwarz stehen lassen — und
   ausgeblendete Links dürfen nicht mehr im Tab-Fokus liegen, deshalb
   schaltet das JS bei --through ≈ 1 zusätzlich die Sichtbarkeit ab. */
.hero__next {
  text-align: center;
  opacity: calc(1 - var(--through));
}

.hero[data-past="true"] .hero__stage { visibility: hidden; }

.hero__gig {
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(0.9375rem, 1.4vw, 1.125rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--blood);
}

.hero__gig-label { text-transform: uppercase; }
.hero__gig > span[aria-hidden] { padding-inline: 0.4em; }

.hero__more {
  display: inline-block;
  margin-block-start: 0.75rem;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.06em;
  color: var(--void);
  text-underline-offset: 0.3em;
  text-decoration-color: var(--blood);
}

.hero__more:hover,
.hero__more:focus-visible { color: var(--blood); }

/* ==========================================================================
   Abschnitte
   ========================================================================== */

/* Jede Sektion füllt nahezu den Bildschirm, Inhalt senkrecht zentriert.
   Längere Abschnitte wachsen darüber hinaus. Der Abstand zwischen den
   Sektionen bleibt konstant, egal wie viel Inhalt drin steht — deshalb sitzt
   er an genau einer Regel und nicht an den Sektionen selbst. DESIGN.md §5 */
.section {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100svh;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: var(--section-y);
}

.lead {
  max-width: 46ch;
  margin-block: clamp(2rem, 5vh, 3.5rem) 0;
  font-size: var(--t-lead);
  color: var(--ink-soft);
}

/* Auf kleinen Schirmen ist --section-y der Engpass, nicht der Inhalt: Mit
   96 px oben und unten passt „Die Truppe" (rund 569 px Inhalt) nicht in ein
   667-px-Fenster. Hier zurückgenommen, damit jede Sektion auf dem Handy ganz
   in den Blick passt. Innerhalb einer Bildschirmklasse bleiben die Abstände
   untereinander gleich — das war die Anforderung. */
@media (max-width: 767px) {
  :root { --section-y: clamp(2.5rem, 6vh, 4rem); }
}

/* ==========================================================================
   Bausteine der Abschnitte
   ========================================================================== */

/* Versalien. Bricht die frühere Kleinschreib-These des Manuals bewusst:
   Der Bandname flüstert klein, die Abschnitte schreien. line-height hier
   NICHT unter 1.02 — das Ü in „FÜR VERANSTALTER" sitzt über Versalhöhe und
   stößt sonst an die Zeile darüber. DESIGN.md §4 */
.section__title {
  margin: 0 0 clamp(1.5rem, 4vh, 2.5rem);
  font-family: var(--font-display);
  font-size: var(--t-display-l);
  font-weight: 900;
  line-height: 1.02;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  padding-block-start: 0.06em;
}

.subhead {
  margin: clamp(3rem, 7vh, 5rem) 0 1.25rem;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.prose { max-width: 62ch; }
.prose p { margin: 0 0 1.1em; }
.prose p:last-child { margin-block-end: 0; }

/* ==========================================================================
   Wer wir sind — angeheftet, Grund wechselt dunkel → hell → dunkel
   Der byraven-Effekt. --lit steuert Grund, Textfarbe und das fixierte Logo
   gemeinsam, damit nichts auseinanderläuft.
   ========================================================================== */

.invert { height: 200vh; }               /* Scrollweg für den Wechsel */
.invert:not(.js-ready) { height: auto; } /* ohne JS: normaler Abschnitt */

/* Grund und Textfarbe kommen jetzt vom body — dieser Abschnitt ist nur noch
   angeheftet, nicht mehr farblich eigenständig. */
.invert__stage {
  position: sticky;
  inset-block-start: 0;
  display: flex;
  align-items: center;
  min-height: 100svh;
}

/* Deutlich weniger senkrechter Abstand als bei den normalen Abschnitten:
   --section-y wären bis zu 192 px oben UND unten, damit wird der Block höher
   als der Bildschirm und `align-items: center` kann nichts mehr zentrieren. */
.invert__inner {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(2rem, 5vh, 3.5rem) var(--gutter);
}

/* Bild links, Text rechts, beide senkrecht mittig zueinander. */
.invert__cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}

.invert__figure { margin: 0; }
.invert__figure .photo { aspect-ratio: 16 / 9; }
.invert__figure .photo img { height: 100%; object-fit: cover; }

.invert__text { max-width: 34rem; }

/* Eine Größe für den ganzen Block — Anschlagzeile und Fließtext gleich groß.
   Die Überschrift ist trotzdem eine Überschrift, nur nicht größer. */
.invert__claim,
.invert__text p {
  margin: 0 0 1.1em;
  font-family: var(--font-body);
  font-size: var(--t-lead);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.005em;
}

/* ==========================================================================
   Sprungmarke zur nächsten Sektion — eine Klasse für alle
   ========================================================================== */

/* Umgekehrt zur üblichen Logik: in Ruhe gefüllt rot, beim Überfahren
   verschwindet die Fläche und nur der Rahmen bleibt.
   Füllung ist --flare, nicht --blood: Oxblood auf --void käme als Fläche auf
   1,7:1 gegen den Grund, der Knopf wäre auf dunklem Grund kaum als Fläche zu
   erkennen. --flare erreicht 3,4:1 auf dunkel und 4,0:1 auf hell und erfüllt
   damit die 3:1 für Bedienelemente. Chalk darauf: 4,8:1. */
.jump {
  display: inline-block;
  align-self: flex-start;
  margin-block-start: clamp(2rem, 5vh, 3rem);
  padding: 0.85rem 1.5rem;
  border: 1px solid var(--flare);
  background: var(--flare);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--chalk);
  transition: background-color 180ms ease, color 180ms ease;
}

.jump:hover,
.jump:focus-visible {
  background: transparent;
  color: var(--ink);
}

/* Die Farbe kommt schon über --ink vom Grund; hier nur der engere Abstand. */
.invert__text .jump { margin-block-start: 1.5rem; }


/* Unter 900 px übereinander: Bild oben, Text darunter. */
@media (max-width: 900px) {
  .invert__cols { grid-template-columns: 1fr; gap: clamp(1.5rem, 4vh, 2.5rem); }
  .invert__text { max-width: none; }
}

/* ==========================================================================
   Bildbehandlung — DESIGN.md §6
   Vereinheitlicht die sieben Handy-Livefotos mit ihren völlig verschiedenen
   Bühnenlichtern zu einer Familie: schwarze Schatten, Putz in den Lichtern,
   ein Anflug Oxblood, Korn darüber.
   opacity-Werte an den echten Bildern justieren, das sind Startwerte.
   ========================================================================== */

.photo {
  position: relative;
  background: var(--wall);
  isolation: isolate; /* ohne das mischt das Bild mit dem Seitenhintergrund */
  overflow: hidden;
}

.photo img {
  width: 100%;
  height: auto;
  filter: grayscale(1) contrast(1.15);
  mix-blend-mode: multiply;
}

.photo::after {              /* Oxblood-Anflug */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--blood);
  mix-blend-mode: color;
  opacity: 0.18;
  pointer-events: none;
}

.photo::before {             /* Korn. Feste Pixelgröße, sonst sieht es
                                wie Kompressionsartefakte aus. */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  mix-blend-mode: overlay;
  opacity: 0.4;
  pointer-events: none;
}

/* ==========================================================================
   170 — Der Sound: Bands statt Songtitel
   ========================================================================== */

.repertoire {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: clamp(2.5rem, 6vh, 4rem) clamp(2rem, 4vw, 4rem);
  margin-block-start: clamp(3rem, 8vh, 5rem);
}

.repertoire__label {
  margin: 0 0 1.25rem;
  padding-block-end: 0.75rem;
  border-block-end: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.repertoire__bands {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Fünfzehn bekannte Bandnamen, groß gesetzt — der stärkste typografische
   Block der Seite, und für einen Veranstalter das schnellste Argument. */
.repertoire__bands li {
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 2.4vw, 2rem);
  font-weight: 900;
  line-height: 1.14;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* ==========================================================================
   184 — Die Truppe
   ========================================================================== */

/* Ohne JS: einfaches Raster mit allen fünf Texten. Ein Coverflow ohne
   Skript wäre unbedienbar, also gibt es dann gar keinen. */
.crew__stage {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-block-start: clamp(2rem, 5vh, 3rem);
}

.crew__photo { aspect-ratio: 3 / 4; }
.crew__photo img { height: 100%; object-fit: cover; }

.crew__name {
  margin: 1.25rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.6vw, 2.125rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.crew__role {
  margin: 0.4rem 0 0.9rem;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.crew__line { margin: 0; font-size: var(--t-small); color: var(--ink-soft); }

/* --- Coverflow, sobald JS läuft -------------------------------------------
   Die Karten liegen übereinander und werden per --off (Abstand zur aktiven
   Karte) auseinandergefahren. Kein Seitwärtsscrollen, gesteuert über die
   Pfeilknöpfe, die Pfeiltasten und Klick auf eine Nachbarkarte. */

/* Kartenbreite an einer Stelle — die Stapelhöhe leitet sich daraus ab.
   Vorher war die Höhe ein eigener clamp und dadurch bis zu 120 px größer als
   die Karten: genau der Leerraum, der Bild und Name auseinandergerissen hat. */
.crew.is-flow { --card-w: clamp(200px, 26vw, 300px); }

.crew.is-flow .crew__stage {
  position: relative;
  display: block;
  height: calc(var(--card-w) * 4 / 3);   /* Portraits sind 3:4 */
  margin-block-start: clamp(1.5rem, 4vh, 2.5rem);
  perspective: 1400px;
  transform-style: preserve-3d;
}

.crew.is-flow .crew__card {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 50%;
  width: var(--card-w);
  margin-inline-start: calc(var(--card-w) / -2);
  /* --off und --dist setzt das JS pro Karte. Rückfallwerte, damit der Stapel
     auch im Bruchteil vor dem ersten paint() nicht auseinanderfliegt. */
  transform:
    translateX(calc(var(--off, 0) * clamp(120px, 15vw, 190px)))
    translateZ(calc(var(--dist, 0) * -220px))
    scale(calc(1 - var(--dist, 0) * 0.12));
  opacity: calc(1 - var(--dist, 0) * 0.42);
  z-index: calc(10 - var(--dist, 0));
  transition: transform 520ms cubic-bezier(.22,.7,.2,1), opacity 520ms ease;
}

.crew.is-flow .crew__card[data-hidden="true"] { opacity: 0; pointer-events: none; }

.crew.is-flow .crew__photo { height: 100%; }
.crew.is-flow .crew__text { display: none; }

/* Nur die aktive Karte zeigt volle Farbe, die Nachbarn treten zurück. */
.crew.is-flow .crew__card[data-dist="0"] .crew__photo::after { opacity: 0.08; }

/* Nur diese Sektion ist mittig — die Ausrichtung folgt dem Inhalt, und
   Karussell wie Personentext stehen zentriert. Die übrigen Sektionen haben
   linksbündigen Inhalt und behalten linksbündige Überschriften. */
#truppe { align-items: center; text-align: center; }
#truppe .section__title { align-self: center; }
#truppe .crew { width: 100%; }

.crew__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  margin-block-start: clamp(1.25rem, 3vh, 2rem);
}

.crew__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  background: var(--flare);
  color: var(--chalk);
  font-size: 1.125rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color 180ms ease;
}

/* Wird beim Überfahren dunkler statt leer: Ein Pfeil ohne Fläche wäre auf
   hellem Grund nicht mehr zu sehen — anders als bei den Textknöpfen. */
.crew__btn:hover, .crew__btn:focus-visible { background: var(--blood); }

.crew__counter {
  margin: 0;
  min-width: 4.5em;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

/* Knapper Abstand zum Karussell: Bild und Name sollen erkennbar
   zusammengehören, und die Sektion muss auf dem Handy ganz in den Blick passen. */
.crew__active {
  max-width: 44ch;
  margin: clamp(0.5rem, 1.2vh, 0.75rem) auto 0;
  text-align: center;
}

.crew__active .crew__name { margin-block-start: 0; }

@media (prefers-reduced-motion: reduce) {
  .crew.is-flow .crew__card { transition: none; }
}

/* ==========================================================================
   Bisherige Abrisse
   ========================================================================== */

.played { margin: 0; padding: 0; list-style: none; }

.played li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  align-items: baseline;
  padding-block: 1.1rem;
  border-block-start: 1px solid var(--hairline);
}

.played li:last-child { border-block-end: 1px solid var(--hairline); }

.played__name {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-weight: 900;
  letter-spacing: -0.015em;
}

/* Gleicher Grad wie der Veranstaltungsname, in Rot. --label und nicht --flare:
   Zwei fast gleich große rote Textelemente auf einer Seite sollen nicht zwei
   verschiedene Rottöne haben. */
.played__year {
  margin-inline-start: auto;
  font-family: var(--font-mono);
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}

/* ==========================================================================
   Termine
   ========================================================================== */

.dates { margin: 0; padding: 0; list-style: none; }

.dates__item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  align-items: baseline;
  padding-block: 1.4rem;
  border-block: 1px solid var(--hairline);
}

.dates__item + .dates__item { border-block-start: 0; }

.dates__date {
  font-family: var(--font-mono);
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}

.dates__event {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-weight: 900;
  letter-spacing: -0.015em;
  text-transform: uppercase;
}

/* Genau wie .played__year formatiert. */
.dates__place {
  margin-inline-start: auto;
  font-family: var(--font-mono);
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}

/* Leerzustand ohne JavaScript: bleibt die Liste leer, verschwindet sie und
   der Hinweis erscheint. Autorenregel schlägt das [hidden] des Browsers. */
.dates:empty { display: none; }

.dates:empty + .dates__empty {
  display: block;
  max-width: 46ch;
  margin: 0;
  padding-block: 1.4rem;
  border-block: 1px solid var(--hairline);
  font-size: var(--t-lead);
}

.dates__note { margin-block-start: 1.5rem; font-size: var(--t-small); color: var(--ink-soft); }

.dates__note a, .dates__empty a { color: var(--ink); text-underline-offset: 0.2em; }
.dates__note a:hover, .dates__empty a:hover,
.dates__note a:focus-visible, .dates__empty a:focus-visible { color: var(--flare); }

/* ==========================================================================
   206 — Für Veranstalter
   ========================================================================== */

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(2rem, 4vw, 3rem);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}

.steps__num {
  display: block;
  margin-block-end: 0.75rem;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  color: var(--accent-text);
}

.steps__name {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.125rem, 1.8vw, 1.5rem);
  font-weight: 900;
  letter-spacing: -0.015em;
  text-transform: uppercase;
}

.steps__item p { margin: 0; font-size: var(--t-small); color: var(--ink-soft); }

.contact {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-block-start: clamp(3rem, 7vh, 5rem);
}

/* Gleiche Umkehrung wie bei .jump */
.contact__button {
  display: inline-block;
  padding: 0.9rem 1.5rem;
  border: 1px solid var(--flare);
  background: var(--flare);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--chalk);
  transition: background-color 180ms ease, color 180ms ease;
}

.contact__button:hover,
.contact__button:focus-visible { background: transparent; color: var(--ink); }

/* ==========================================================================
   Einblendung der Abschnitte — einmalig, DESIGN.md §10
   ========================================================================== */

/* Die Klasse `reveal` setzt das JS erst, wenn IntersectionObserver wirklich
   vorhanden ist. Sonst blieben die Abschnitte unsichtbar — ein Ausblenden,
   das niemand wieder einschaltet, ist schlimmer als keine Einblendung. */
.reveal .section { opacity: 0; transform: translateY(16px); }

.reveal .section.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 500ms cubic-bezier(.2,.7,.2,1), transform 500ms cubic-bezier(.2,.7,.2,1);
}

@media (prefers-reduced-motion: reduce) {
  .reveal .section { opacity: 1; transform: none; }
}

/* Beim Drucken wird nicht gescrollt, der Observer feuert also nie — ohne diese
   Regel käme die Seite leer aus dem Drucker. Betrifft Veranstalter, die sich
   die Booking-Angaben ausdrucken. */
@media print {
  .reveal .section { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   Rechtstexte (Impressum, Datenschutz)
   ========================================================================== */

.legal {
  max-width: 72ch;
  margin-inline: auto;
  padding: clamp(5rem, 14vh, 9rem) var(--gutter) 0;
}

.legal__back {
  display: inline-block;
  margin-block-end: clamp(2rem, 6vh, 3.5rem);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.06em;
  color: var(--dust);
  text-underline-offset: 0.25em;
}

.legal__back:hover,
.legal__back:focus-visible { color: var(--chalk); }

.legal h1 {
  margin: 0 0 clamp(2rem, 5vh, 3rem);
  font-family: var(--font-display);
  font-size: var(--t-display-m);
  font-weight: 900;
  line-height: 0.98;
  letter-spacing: -0.02em;
  padding-block-start: 0.08em;
}

.legal h2 {
  margin: clamp(2.5rem, 6vh, 4rem) 0 0.75rem;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dust);
}

.legal p, .legal ul { margin: 0 0 1rem; }
.legal ul { padding-inline-start: 1.25rem; }
.legal li { margin-block-end: 0.35rem; }

.legal a { color: var(--chalk); text-decoration-color: var(--dust); text-underline-offset: 0.2em; }
.legal a:hover, .legal a:focus-visible { text-decoration-color: var(--flare); }

.legal address { font-style: normal; }

/* Offene Angabe, die noch eingesetzt werden muss. Fällt im Text auf — Absicht. */
.legal .todo {
  padding: 0.1em 0.35em;
  background: color-mix(in oklab, var(--void), var(--flare) 22%);
  color: var(--chalk);
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* ==========================================================================
   Abschlussbild
   Liegt fixiert hinter dem Inhalt und wird zum Seitenende weich eingeblendet.
   `contain`, damit es komplett zu sehen ist — `cover` würde beschneiden.
   Bewusst ein eigenes Element und nicht background-attachment: fixed, das
   ist auf iOS unbrauchbar.
   ========================================================================== */

.finale {
  position: fixed;
  inset: 0;
  z-index: 0;
  background-color: var(--void);
  background-image: url("../images/hero-1600.jpg");
  background-position: center;
  background-repeat: no-repeat;
  background-size: contain;
  opacity: var(--finale, 0);
  pointer-events: none;
}

/* Auf dem Handy sitzt das Bild unten am Rand und ist VOLLSTÄNDIG zu sehen:
   Das Element ist genau so hoch wie das Bild bei voller Breite (1600 × 938),
   also wird nichts beschnitten und es entsteht kein Balken um das Bild herum.
   Darüber liegt die dunkle Seite mit dem Logo — bei 375 × 812 sind das rund
   590 px. Das ist der Preis und er ist Rechnung, nicht Einstellung: Ein
   Querformat von 1,71 belegt bei voller Breite nur 27 % eines Hochformats.
   Beides gleichzeitig — vollständig und randlos — gibt es nicht. */
@media (max-width: 767px) {
  .finale {
    inset-block-start: auto;
    height: calc(100vw * 938 / 1600);
    background-size: 100% auto;
    background-position: center bottom;
  }

  /* Über dem Bild bleibt eine große dunkle Fläche — auf 375 × 812 rund 73 % des
     Bildschirms. Damit sie nicht wie ein Versehen wirkt, wandert das Logo zum
     Seitenende hinein und steht dort senkrecht mittig darin. Gesteuert von
     --finale, also derselben Größe, die das Bild einblendet: Logo und Bild
     kommen gemeinsam an.
     Der Weg ist reine Geometrie — Mitte der dunklen Fläche minus halbe
     Logohöhe minus Ruhelage. Das Logo hat das Seitenverhältnis 880 : 433. */
  .brand {
    --finale-img-h: calc(100vw * 938 / 1600);
    --brand-h: calc(var(--brand-width) * 433 / 880);
    --brand-drop: calc(
      (100svh - var(--finale-img-h) - var(--brand-h)) / 2 - var(--brand-top)
    );
    transform: translateY(calc(var(--brand-drop) * var(--finale, 0)));
  }

  /* Während der Hero-Übergabe schreibt das JS ein eigenes transform inline und
     überstimmt das hier. Das ist unkritisch: Dort ist --finale gleich 0, der
     Versatz also ohnehin null. */
}

/* Inhalt liegt über dem Bild, sonst verdeckt es die Seite.
   ACHTUNG: Der Masthead darf hier NICHT mit aufgeführt werden — er ist
   `position: fixed`, und `relative` hätte dieselbe Spezifität und würde ihn
   in den Fluss zurückholen. Genau das war der schwarze Balken am Seitenanfang
   und der Grund, warum das Logo verschwand. */
.hero, main, .footer { position: relative; z-index: 1; }

/* Der Footer steht ÜBER dem Bild, nicht darauf: eigener deckender Grund,
   damit das eingeblendete Bild nicht durchscheint. */
.footer--over { background: var(--ground); }

/* Danach nur noch das Bild. Diese Fläche gibt ihm den Scrollweg, in dem es
   allein im Bildschirm steht — sie ist leer und durchsichtig. */
.finale-space {
  position: relative;
  z-index: 0;
  height: 100svh;
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem clamp(1.5rem, 4vw, 3rem);
  align-items: baseline;
  max-width: var(--maxw);
  margin-inline: auto;
  /* Oben und unten gleich, und deutlich knapper als die Abschnitte:
     vorher standen hier --section-y (bis 192 px) gegen bis 96 px. */
  padding: clamp(1.5rem, 4vh, 2.25rem) var(--gutter);
  border-block-start: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  color: var(--ink-soft);
}

.footer__band { margin: 0; margin-inline-end: auto; }

.footer__nav { display: flex; gap: clamp(1rem, 3vw, 2rem); }

/* Trefferfläche: 13 px Schrift bei Zeilenhöhe 1,6 ergibt rund 21 px und
   verfehlt damit die 24 px aus WCAG 2.5.8 (AA). Der Innenabstand hebt alle
   kleinen Textlinks über die Grenze. */
.footer a,
.dates__note a,
.dates__empty a,
.legal__back {
  display: inline-block;
  padding-block: 0.35rem;
}

.footer a {
  color: var(--ink-soft);
  text-decoration-color: var(--hairline);
  text-underline-offset: 0.25em;
  transition: color 180ms ease, text-decoration-color 180ms ease;
}

.footer a:hover,
.footer a:focus-visible {
  color: var(--ink);
  text-decoration-color: var(--flare);
}

/* ==========================================================================
   Bewegung aus
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .js .hero { height: 100vh; }
  /* Nur die bewegten Eigenschaften stilllegen. Ein globaler Abriss aller
     Übergänge nähme auch das nützliche Feedback: Hover- und Fokusfarben
     würden hart umschalten. Reduzierte Bewegung heißt keine Bewegung,
     nicht keine Rückmeldung. Die Farbübergänge bleiben deshalb.
     CSS-Animationen gibt es in diesem Stylesheet keine. */
  .crew.is-flow .crew__card,
  .reveal .section { transition: none !important; }
}
