/* ============================================================================
   TOP10 Singen — Design und Layout
   ----------------------------------------------------------------------------
   Uebernahme der bestehenden WordPress-Seite: reines Schwarz als Grund,
   weisse Schrift, Montserrat in Versalien, Akzent in Rotorange (#ff330f).
   Knoepfe als abgerundete Rechtecke, nicht als Pille.

   Keine Inline-Styles. Die Content-Security-Policy fuehrt style-src 'self'
   ohne unsafe-inline; was aus der API kommt, wird als <img> oder
   textContent gesetzt, nie als style-Attribut.
   ========================================================================== */

/* ------------------------------------------------------------- Schriften -- */

/* **Zwei Familien mit klarer Aufgabenteilung**, beide variabel, zusammen
   105 KB.

   Montserrat ist als geometrische Display-Schrift gezeichnet und traegt
   grosse Versalien — Ueberschriften, Knoepfe, Navigation und die fetten
   Etiketten. Inter ist als Oberflaechenschrift gezeichnet und bleibt im
   Absatz ruhig; Montserrat wirkt dort auf Dauer unruhig, weil ihre runden
   Formen und weiten Punzen fuer grosse Grade gemacht sind.

   Die bestehende WordPress-Seite nennt im `body` die Familie „Titillium",
   laedt aber nie eine passende Datei — gerendert wird dort ueberall
   Montserrat, auch im Fliesstext.

   **Beide Dateien werden vorgeladen.** Fliesstext und Hero-Titel stehen
   gleichzeitig ueber der Falz; eine der beiden nachzuladen hiesse, dass
   genau dort umgebrochen wird. Wer die Familien tauscht, muss die
   `<link rel="preload">` in allen Seiten **und** in `tools/build.py`
   mitziehen — sonst laedt die Seite eine Datei vor, die sie nicht nutzt,
   und die, die sie braucht, erst spaet.

   Nicht enthalten sind Emoji; die kommen ohnehin aus der Systemschrift.
   Ebenso wenig der Pfeil U+2192, deshalb zeichnet das CSS ihn selbst
   (siehe `.knopf::after`). Kyrillisch fehlt in beiden Dateien gleichermassen
   — einzelne Eventtexte aus Clubinio fallen dort auf die Systemschrift,
   wie bisher schon. */
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/montserrat.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ----------------------------------------------------------------- Token -- */

:root {
  /* Flaechen. Die Werte stammen aus dem Elementor-Kit der bestehenden Seite. */
  /* Seitengrund. **Nicht reines Schwarz.** Die bestehende Seite fuehrt
     durchgehend ein sehr dunkles Grau; reines #000 wirkt besonders auf
     OLED-Displays wie ein Loch, weil die Pixel dort wirklich aus sind und
     es keinerlei Abstufung zum Inhalt gibt. Ein paar Punkte Helligkeit
     geben der Flaeche Tiefe, ohne sie aufzuhellen. */
  --nacht:        #141415;   /* dunkler Abschnittsgrund */
  --box:          #161616;   /* Karten, Kaesten */
  --box-hell:     #202020;   /* abgesetzte Flaeche in einer Box */
  --flaeche:      #181818;   /* Abschnittsgrund, wo er sich abheben soll */
  --karte:        #111111;   /* bleibt in BEIDEN Toenen dunkel */
  --kopf:         #0e0e0e;   /* Kopfzeile, sobald sie deckend wird */
  --linie:        #2a2a2a;   /* Trenner und Rahmen */

  /* **Grund des Abschnitts.** Voreinstellung ist der dunkle Ton; helle
     Abschnitte belegen ihn samt Schrift- und Linienfarbe neu (siehe
     `[data-ton='hell']`). Alles, was auf dem Abschnittsgrund sitzt, liest
     diese Token — damit kippt ein Abschnitt vollstaendig, ohne dass jede
     Regel eine helle Zweitfassung braucht. */
  --grund:        var(--nacht);

  /* Schrift: zwei Ebenen mit klarer Aufgabe. */
  --schrift-display: 'Montserrat', system-ui, sans-serif;
  --schrift-text:    'Inter', system-ui, -apple-system, sans-serif;

  /* Schrift. */
  --tinte:        #ffffff;
  --tinte-leise:  #b4b4b4;
  /* #7d7d7d verfehlte auf dem Infokasten (#181818) die Schwelle knapp
     (4,31:1). Drei Stufen heller genuegen fuer alle drei dunklen
     Flaechen: #181818, #141415 und #111111. */
  --tinte-still:  #838383;
  /* Dieselbe Tinte als reines Zahlentripel. Jede getoente Flaeche —
     Eingabefelder, Kaestchen, der gedaempfte Knopfrahmen — mischt sich aus
     der Tinte des Abschnitts mit Alpha. Nur so kippen sie im hellen Ton
     mit, ohne dass es von jeder Regel eine zweite Fassung braucht.
     Die bestehende Seite macht es genauso: Eingabefelder sind dort
     `rgba(2 1 1 / 6%)` auf Hell und waeren `rgb(255 255 255 / 6%)` auf
     Dunkel — gleiche 6 Prozent, andere Tinte. */
  --tinte-rgb:    255 255 255;
  /* Schrift auf einer Flaeche, die in BEIDEN Toenen dunkel bleibt:
     Eventkarte, Albumdeckblatt, Infokasten, Fussbereich. Dieses Token
     wird im hellen Ton bewusst **nicht** neu belegt. */
  --tinte-invers: #ffffff;

  /* Akzent der Marke. */
  --akzent:       #0000fe;
  /* Schrift auf dem Akzent. Weiss, weil das Blau mit 11 Prozent relativer
     Helligkeit dunkler ist als jede Schrift, die darauf tragen koennte. */
  --akzent-tinte: #ffffff;
  /* Derselbe Akzent als reines Zahlentripel. `rgb()` mit Alpha laesst sich
     nicht aus einem Hex-Token bauen — ohne das hier stuenden Verlaeufe und
     Fokusringe mit fest verdrahteter Farbe im Stylesheet und blieben beim
     naechsten Projekt gelbgruen stehen. */
  --akzent-rgb:   0 0 254;

  /* **Der Akzent als Schriftfarbe ist nicht derselbe wie als Flaeche.**

     #0000fe hat rund sieben Prozent relative Helligkeit. Als Knopffuellung
     mit weisser Schrift traegt das (Kontrast 8,6:1), als Schrift auf dem
     dunklen Grund dieser Seite nicht: 2,1:1, also unlesbar. Die Vorlage
     kam von cosmopolar, dessen Akzent ein helles Gelbgruen ist — dort fiel
     es nie auf.

     Darum zwei Werte: auf Dunkel ein aufgehellter Blauton (4,8:1), auf
     Hell der Markenton selbst (8,4:1). `--akzent` bleibt unveraendert und
     gilt weiter fuer Flaechen, Rahmen und Verlaeufe.
     Gemessen, nicht geschaetzt. */
  --akzent-text:  #5577ff;
  /* Derselbe aufgehellte Ton, aber als **feste** Groesse: fuer Flaechen,
     die in beiden Toenen dunkel bleiben. `--akzent-text` folgt dem Ton des
     Abschnitts — eine Eventkarte steht aber dunkel *innerhalb* eines
     hellen Abschnitts und bekaeme dort den hellen Wert. Genau das fiel auf
     /fotos/ auf: die Fotozahl stand in #0000fe auf #111.
     Siehe `--tinte-invers`, gleiches Muster. */
  --akzent-invers: #5577ff;
  /* Vollstaendiger Satz fuer dunkle Inseln. Dieselben Werte wie im dunklen
     Grundton, aber unter eigenem Namen — innerhalb einer Insel laese ein
     `var(--tinte-leise)` sonst den hellen Wert des umgebenden Abschnitts. */
  --tinte-leise-invers: #b4b4b4;
  --tinte-still-invers: #838383;
  --linie-invers:       #2a2a2a;

  /* Rundungen. Gestaffelt nach Flaechengroesse — ein einheitlicher Radius
     laesst kleine Elemente verspielt und grosse Flaechen hart wirken. */
  --r-knopf:      15px;     /* TOP10 nutzt abgerundete Rechtecke, keine Pille */
  --r-feld:       14px;     /* Eingabefelder */
  --r-karte:      18px;     /* Eventkarten, Kaesten */
  --r-klein:      10px;     /* Chips, Symbole, kleine Flaechen */
  /* Hoehe des Abschnitts unter der Perforation. Kerben und Trennlinie
     haengen beide daran — ein Wert, damit sie nicht auseinanderlaufen. */
  --abriss:       46px;

  /* Weiche Schatten statt Rahmen, wo etwas abheben soll. */
  --schatten:     0 1px 2px rgb(0 0 0 / 30%), 0 8px 24px rgb(0 0 0 / 35%);
  --schatten-hoch: 0 2px 4px rgb(0 0 0 / 35%), 0 16px 40px rgb(0 0 0 / 45%);

  /* Deckung des dunklen Schleiers ueber dem Bildabschnitt.

     **Projekteigen, weil das Foto es ist.** Die Regel in `.abschnitt-bild`
     ist in allen Projekten dieselbe; wie stark sie abdunkeln muss, haengt
     am Bild darunter und an der Farbe der Schrift darauf.
     Hoeher als bei Singen: Das Balinger Foto ist heller und bunter, und die Unterzeile steht hier in Blau statt in Rotorange. */
  --bild-schleier: 66%;

  /* Uebergang mit leichtem Ueberschwingen — nicht linear, nicht traege. */
  --kurve:        cubic-bezier(0.32, 0.72, 0, 1);

  /* Haken fuer die eigenen Kaestchen. Als data:-Adresse im Stylesheet und
     nicht als eigene Datei: 200 Byte sind keinen zweiten Abruf wert. */
  --haken: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round' d='M3.2 8.6l3.1 3.1 6.5-6.9'/%3E%3C/svg%3E");

  /* Masse. */
  --breite:       1200px;
  --breite-schmal: 760px;
  --gutter:       clamp(1rem, 4vw, 2.5rem);
  /* Hoehe der Kopfzeile. Hero, Bannerversatz, Menue und Ankersprung
     rechnen damit — weicht der Wert von der tatsaechlichen Hoehe ab,
     verschiebt sich der Inhalt um die Differenz.

     **Zwei Werte, weil die Zeile nicht ueberall gleich hoch ist.** Ihre
     Hoehe ergibt sich aus dem hoechsten Kind plus Polster: auf dem
     Schreibtisch das Logo (46px), auf dem Telefon der Menueknopf (44px).
     Mit einem einzigen Wert klaffte zwischen Kopfzeile und aufgeklapptem
     Menue eine Luecke von 2px, durch die das Bild schien.
     Nachgemessen: 82px / 80px. */
  --kopf-hoehe:   82px;

  /* Typografie. Die Skala ist die der bestehenden Seite (36/50/60/85 px),
     hier als clamp(), damit sie auf dem Telefon nicht ueberlaeuft. */
  --t-hero:   clamp(2.75rem, 9vw, 5.3125rem);   /* bis 85px */
  --t-h1:     clamp(2rem, 6vw, 3.75rem);        /* bis 60px */
  --t-h2:     clamp(1.75rem, 5vw, 3.125rem);    /* bis 50px */
  --t-h3:     clamp(1.25rem, 3vw, 1.5rem);
  --t-text:   0.9375rem;   /* 15px — Originalwert */
  --t-klein:  0.875rem;
}

/* ----------------------------------------------------------- Heller Ton -- */

/* Die bestehende Seite wechselt zwischen hellen und dunklen Abschnitten:
   „Die groesste Partylocation" und „Get the Vibe" hell, „Next Events" und
   der Fuss dunkel.

   **Ein Abschnitt kippt, indem er dieselben Token neu belegt** — nicht,
   indem jede Regel darin eine helle Zweitfassung bekommt. Knoepfe,
   Formulare, Trenner und Fliesstext ziehen dadurch von selbst mit.

   **Ausgenommen sind die Karten.** `--karte` steht hier bewusst nicht:
   Eventkarten und Albumdeckblaetter bleiben in beiden Toenen dunkel, so wie
   im Original. Eine Karte, die auf hellem Grund mitkippt, verliert den
   Kontrast zum Flyer, der ohnehin dunkel ist. */
[data-ton='hell'] {
  --grund:        #fcfcfc;
  --tinte:        #141414;
  --tinte-leise:  #4a4a4a;
  /* #767676 ergaebe auf #fcfcfc nur 4,43:1 und verfehlte die Schwelle
     fuer kleine Schrift um Haaresbreite. Drei Stufen dunkler genuegen. */
  --tinte-still:  #737373;
  --linie:        #e4e4e4;
  --box:          #f1f1f1;
  --box-hell:     #ffffff;
  --tinte-rgb:    20 20 20;
  /* Auf hellem Grund traegt der Markenton selbst. */
  --akzent-text:  var(--akzent);
  /* `--flaeche` steht hier absichtlich nicht: Sie traegt nur den Grund des
     Seitenkopfs, und darueber liegt ohnehin ein dunkles Bannerbild.
     Ebenso fehlt `--karte` — siehe Hinweis oben. */
  /* Schatten tragen auf Hell nicht: dort muessen sie flacher und weicher
     sein, sonst wirken sie wie Schmutzraender. */
  --schatten:      0 1px 2px rgb(0 0 0 / 6%), 0 8px 24px rgb(0 0 0 / 8%);
  --schatten-hoch: 0 2px 6px rgb(0 0 0 / 8%), 0 18px 48px rgb(0 0 0 / 14%);
}

/* -------------------------------------------------------- Dunkle Inseln -- */

/* **Flaechen, die in beiden Toenen dunkel bleiben.**

   Eventkarte, Albumdeckblatt, Lounge-Kasten, Kopfzeile und Fuss. Sie
   liegen zum Teil *innerhalb* eines hellen Abschnitts — dort wuerde jedes `var(--tinte)`, `var(--linie)` oder
   `var(--akzent-text)` den hellen Wert liefern und dunkle Schrift auf
   dunklen Grund setzen.

   Darum belegen sie den Farbsatz noch einmal um, zurueck auf die dunklen
   Werte. **Eine Regel statt sechs** — so kann keine Insel die Umstellung
   verpassen, und eine neue traegt sie mit, sobald ihr Selektor hier steht.

   `--grund` steht bewusst nicht dabei: Jede Insel bringt ihre eigene
   Flaeche mit (`--karte`, `--kopf`, `--flaeche`), und die sind absichtlich
   verschieden. */
.karte,
.album-karte,
.lounge,
.kopf,
.fuss {
  --tinte:        var(--tinte-invers);
  --tinte-leise:  var(--tinte-leise-invers);
  --tinte-still:  var(--tinte-still-invers);
  --linie:        var(--linie-invers);
  --akzent-text:  var(--akzent-invers);
  color: var(--tinte);
}



/* --------------------------------------------------------------- Grundlage -- */

*, *::before, *::after { box-sizing: border-box; }

/* Sicherheitsnetz gegen seitliches Verschieben. Die randlose Bildstrecke
   rechnet die Scrollleiste bereits heraus (`--sb`); das hier faengt ab, was
   kuenftig dazukommt, ohne dass es jemandem auffaellt.

   `clip`, nicht `hidden`: `overflow: hidden` an einem Vorfahren setzt
   `position: sticky` ausser Kraft, und die Kopfzeile klebt. */
html, body { overflow-x: clip; }

/* `hidden` muss gewinnen. Der Browser setzt dafuer nur `display: none` mit
   schwacher Spezifitaet — jede eigene display-Regel schlaegt es. Genau das
   ist passiert: `.knopf { display: inline-flex }` hat ein `hidden` am
   Lounge-Knopf ueberstimmt, und der stand auf jeder Eventseite, obwohl ihn
   nichts eingeblendet hatte. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  /* Anker sollen nicht unter der festen Kopfzeile landen. */
  scroll-padding-top: calc(var(--kopf-hoehe) + 1rem);
}

/* Wer Bewegung abbestellt hat, bekommt auch kein sanftes Scrollen. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--nacht);
  color: var(--tinte);
  font-family: var(--schrift-text);
  font-size: var(--t-text);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* Menue offen oder Lightbox aktiv: der Hintergrund darf nicht mitscrollen. */
html.menu-offen, html.lb-aktiv { overflow: hidden; }

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

a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--akzent);
  outline-offset: 3px;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--schrift-display);
  font-weight: 900;
  line-height: 1.08;
  text-transform: uppercase;
  /* Montserrat laeuft breit, im schwersten Schnitt noch mehr. Ohne
     negative Sperrung zerfallen lange Versalueberschriften in
     Einzelbuchstaben. */
  letter-spacing: -0.02em;
}

/* **Fette Etiketten tragen ebenfalls Montserrat.**

   Die Ueberschriftenregel oben deckt nur h1 bis h4. Alles andere, was fett
   und in Versalien steht, haengt sonst am Fliesstext und faellt auf Inter —
   still, weil es weiter fett bleibt und nur die Formen wechseln.

   Betroffen waeren: der Abriss der Eventkarte samt Termin, die Datumszeile
   und der Infokasten der Eventseite, die FAQ-Frage, der Zurueck-Verweis,
   die Kennzahl der Fehlerseite und der Sprunglink. Alles kurze, laute
   Zeilen — genau das, wofuer Montserrat gezeichnet ist. */
.karte-abriss,
.karte-termin-gross,
.event-datum,
.infokasten dt,
.infokasten dd,
.faq summary,
.zurueck,
.fehlerseite .kennzahl,
.sprung {
  font-family: var(--schrift-display);
}

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

/* Nur fuer Lesegeraete — etwa die H1 der Startseite. */
.nur-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.sprung {
  position: absolute;
  left: -9999px;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--akzent);
  color: var(--akzent-tinte);
  font-weight: 700;
}
.sprung:focus { left: 1rem; top: 1rem; }

/* ---------------------------------------------------------------- Raster -- */

.huelle {
  width: 100%;
  max-width: var(--breite);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.huelle-schmal { max-width: var(--breite-schmal); }

.abschnitt {
  padding-block: clamp(3.5rem, 9vw, 7rem);
  /* **Jeder Abschnitt malt seinen Grund selbst**, statt den des `body`
     durchscheinen zu lassen. Nur dadurch kann ein einzelner Abschnitt auf
     Hell kippen, waehrend Kopfzeile, Hero und Fuss dunkel bleiben.
     Voreinstellung ist weiter der dunkle Ton. */
  background: var(--grund);
  color: var(--tinte);
}
.abschnitt-flaeche { background: var(--flaeche); }

/* Der Eventabschnitt liegt im Original auf einem Clubfoto mit dunklem
   Schleier (Deckung 0,48). Das Bild steht im CSS und nicht als <img> im
   Markup, weil es Zierde ist und keinen Inhalt traegt. */
.abschnitt-bild {
  position: relative;
  padding-block: clamp(3.5rem, 9vw, 6.25rem);
  background: url('../img/events-bg.webp') center center / cover no-repeat;
  isolation: isolate;
}
.abschnitt-bild::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(0 0 0 / var(--bild-schleier));
}

/* Abschnittskopf: Ueberschrift plus Unterzeile, zentriert. */
.kopfzeile { text-align: center; margin-bottom: clamp(2rem, 5vw, 3.5rem); }
.kopfzeile h2 { font-size: var(--t-h2); }
.kopfzeile p {
  margin: 0.75rem 0 0;
  color: var(--tinte-leise);
  text-transform: none;
}
/* Unterzeile unter einer Abschnittsueberschrift.

   **Auf der Startseite steht keine** — die bestehende Seite fuehrt unter
   „Next Events" und „Get the Vibe" nur die Ueberschrift. Die Regel bleibt
   fuer die Unterseiten, wo es sie gibt. */
.kopfzeile .unterzeile { color: var(--akzent-text); font-weight: 400; }

/* ---------------------------------------------------------------- Knoepfe -- */

.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.75rem;
  border: 1.5px solid var(--akzent);
  border-radius: var(--r-knopf);
  background: var(--akzent);
  color: var(--akzent-tinte);
  font: inherit;
  font-family: var(--schrift-display);
  font-weight: 800;
  font-size: var(--t-klein);
  text-transform: uppercase;
  /* Weniger Sperrung als vorher: in der Pille wirkt enge Laufweite ruhiger. */
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: transform 0.25s var(--kurve), box-shadow 0.25s var(--kurve),
              background 0.2s ease, color 0.2s ease;
}
.knopf:hover {
  background: transparent;
  color: var(--akzent-text);
  transform: translateY(-1px);
  box-shadow: var(--schatten);
}
/* Beim Druecken wieder herunter — das macht den Knopf greifbar. */
.knopf:active { transform: translateY(0) scale(0.98); box-shadow: none; }

/* Pfeil am Ende, wie bei allen Knoepfen des Originals. Als ::after und nicht
   im Markup: eine Zierde gehoert nicht in den Quelltext, und Lesegeraete
   sollen „Alle Events ansehen" vorlesen, nicht „Alle Events ansehen Pfeil".

   **Gezeichnet, nicht gesetzt.** Inter fuehrt U+2192 nicht; als Textzeichen
   fiele der Pfeil auf die Systemschrift zurueck und passte in Strichstaerke
   und Groesse nicht zur Beschriftung daneben. Als Maske uebernimmt er
   `currentColor` und skaliert mit der Schriftgroesse. */
.knopf::after {
  content: '';
  width: 1em;
  height: 1em;
  flex: none;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h12.2l-4.6-4.6L14 6l6 6-6 6-1.4-1.4 4.6-4.6H5v-2Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h12.2l-4.6-4.6L14 6l6 6-6 6-1.4-1.4 4.6-4.6H5v-2Z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.knopf-ohne-pfeil::after { content: none; }

/* **Zwei Stufen unter dem Hauptknopf, nicht eine.**

   Vorher trugen beide Zweitknoepfe dieselbe getoente Akzentflaeche. Auf
   der hellen Eventseite standen „Lounge reservieren" und „U18-Formular"
   damit nebeneinander in demselben blassen Ton — als Flaeche zu schwach,
   als Umriss zu unruhig, und ununterscheidbar.

   Jetzt: grau gefuellt fuer die zweite Handlung, reiner Umriss fuer die
   dritte. Beide aus `--tinte-rgb`, also tonabhaengig — auf hellem Grund
   ein helles Grau, auf dunklem ein aufgehelltes. */
.knopf-leer {
  background: rgb(var(--tinte-rgb) / 7%);
  color: var(--tinte);
  border-color: rgb(var(--tinte-rgb) / 14%);
}
.knopf-leer:hover {
  background: rgb(var(--tinte-rgb) / 14%);
  color: var(--tinte);
  border-color: rgb(var(--tinte-rgb) / 28%);
}

/* Dritte Stufe: nur Umriss. Fuer Wege, die daneben stehen duerfen, ohne
   um Aufmerksamkeit zu werben — das U18-Formular etwa, das nur eine
   Minderheit der Gaeste braucht. */
.knopf-umriss {
  background: transparent;
  color: var(--tinte);
  border-color: rgb(var(--tinte-rgb) / 28%);
}
.knopf-umriss:hover {
  background: rgb(var(--tinte-rgb) / 7%);
  color: var(--tinte);
  border-color: rgb(var(--tinte-rgb) / 45%);
}

.knopf[disabled] { opacity: 0.5; cursor: not-allowed; }
.knopf[disabled]:hover { background: var(--akzent); color: var(--akzent-tinte); }

.knopf-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 0.875rem;
}

/* Die Absendeknoepfe laufen im Original ueber die volle Formularbreite. */
.form .knopf-reihe { display: block; }
.form .knopf-reihe .knopf { width: 100%; }

.icon { flex: none; }

/* ---------------------------------------------------------------- Kopf --- */

.kopf {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  isolation: isolate;
  transition: background 0.25s ease;
}

/* Ueber dem Hero steht die Zeile frei im Bild. Sobald gescrollt wird,
   bekommt sie einen Grund — darunter liegen Text und Karten, und ohne
   Grund staende die Schrift mitten darin.

   **Nur die Farbe aendert sich, nicht die Hoehe.** Eine klebende Zeile
   belegt weiterhin ihren Platz im Fluss; aenderte sich dabei die Hoehe,
   ruckte der gesamte Inhalt darunter. */
.kopf[data-fest='ja'] {
  background: rgb(11 11 14 / 92%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

/* **Weichzeichner aus, solange das Menue offen ist.** Nicht aus Geschmack,
   sondern weil `backdrop-filter` — wie `transform`, `filter` und
   `perspective` — einen umgebenden Block fuer `position: fixed` erzeugt.
   `.menu` liegt im Markup innerhalb von `.kopf`; mit Weichzeichner bezieht
   sich sein `inset: var(--kopf-hoehe) 0 0` nicht mehr auf das Sichtfeld,
   sondern auf die 80 Pixel hohe Kopfzeile. Das Menue war dann 64 statt
   764 Pixel hoch und der Seiteninhalt schien darunter durch — aber nur im
   gescrollten Zustand, weil `data-fest` erst dort gesetzt wird.

   Die Zeile darueber gibt der Kopfzeile bei offenem Menue ohnehin eine
   deckende Flaeche; der Weichzeichner hat dann nichts mehr zu tun. */
.kopf[data-offen='ja'] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Die Leiste darunter ist halbdurchsichtig, damit das Bild durchscheint —
   deckend wuerde sie zusammen mit dem Streifen daruber einen dicken Block
   ergeben. */
/* Kein Grund, kein Schatten — die Zeile steht frei im Bild. Stattdessen
   Luft nach oben: Sie rueckt vom Fensterrand weg und bekommt Raum, statt
   sich mit einer Flaeche vom Bild abzusetzen.

   Oben mehr als unten, damit die Zeile optisch nicht klebt und der Blick
   trotzdem zuerst aufs Bild faellt. */
.kopf-innen {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 56px;
  padding-top: 1.75rem;
  padding-bottom: 0.5rem;
  transition: padding 0.25s ease;
}

/* Gescrollt sitzt die Schrift mittig in der Leiste statt tief darin. Oben
   steht sie frei im Bild und darf nach unten haengen; auf einem Grund
   wirkt dieselbe Asymmetrie wie ein Fehler.

   **Die Summe bleibt gleich** (28+8 oben, 18+18 gescrollt — beides 36px).
   Eine klebende Zeile belegt weiter ihren Platz im Fluss; aenderte sich
   die Hoehe, ruckte der gesamte Inhalt darunter beim Umschalten. */
.kopf[data-fest='ja'] .kopf-innen {
  padding-top: 1.125rem;
  padding-bottom: 1.125rem;
}

/* `.huelle` begrenzt die Breite, die Flaeche soll aber ueber die ganze
   Fensterbreite laufen. Statt der Begrenzung uebernimmt das Polster die
   Zentrierung: Es ist so breit wie der Rand neben der Inhaltsspalte, und
   faellt nie unter den Seitenabstand.

   **Ohne `+ var(--gutter)`.** Mit dem Zuschlag war die Leiste 80px
   schmaler als der Inhalt darunter — die Marke stand 40px weiter innen
   als alles auf der Seite und die Zeile wirkte verzogen. */
.kopf-innen {
  max-width: none;
  padding-inline: max(var(--gutter), calc((100% - var(--breite)) / 2));
}

.logo { display: flex; align-items: center; }
/* Auf dem Telefon deutlich kleiner — bei voller Groesse nimmt die Wortmarke
   dort die halbe Kopfzeile ein. */
.logo img { height: 46px; width: auto; }
@media (max-width: 899px) {
  .logo img { height: 34px; }
}

.menu-knopf {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 6px;
  /* 44px bleibt die Trefferflaeche — die Balken sind schmaler. Ohne eigene
     Breite zogen sie sich auf die vollen 44px und das Kreuz wirkte wie ein
     Scheibenwischer. */
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.menu-knopf span {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--tinte);
  transition: transform 0.28s var(--kurve), opacity 0.2s ease;
}
/* 8px = halbe Balkenhoehe plus Abstand — so treffen sich beide in der Mitte. */
.kopf[data-offen='ja'] .menu-knopf span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.kopf[data-offen='ja'] .menu-knopf span:nth-child(2) { opacity: 0; transform: scaleX(0.4); }
.kopf[data-offen='ja'] .menu-knopf span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

.menu ul {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
  margin: 0; padding: 0;
  list-style: none;
}

/* Keine Trennstriche. Sie stammen aus der fruheren Vollbreitenleiste, wo
   sie Ordnung in eine lange Zeile brachten. In der Pille zerhacken sie den
   knappen Raum — der Entwurf kommt ohne sie aus. */
@media (min-width: 900px) {
  /* Drei Spalten mit gleich breiten Aussenspalten — nur so stehen die
     Punkte wirklich mittig in der Pille. Mit `space-between` verteilten
     sie sich zwischen schmalem Logo und breitem Knopf und landeten
     rechts; die Marke wirkte dadurch eingequetscht.

     Die dritte Spalte bleibt leer: Sie haelt den Platz, den die Marke
     links einnimmt, und haelt damit die Mitte. */
  /* Punkte rechtsbuendig. Die Grundregel traegt das bereits
     (`justify-content: space-between` mit Marke und Navigation als
     einzigen Kindern) — hier stand vorher eine Rasterueberschreibung fuer
     die mittige Fassung. */
  .menu li { display: flex; align-items: center; }

}

.menu a {
  font-family: var(--schrift-display);
  font-size: 1rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-block: 0.5rem;
  transition: color 0.15s ease;
}
/* Keine Unterstreichung — weder fest noch beim Darueberfahren. Der aktive
   Punkt ist eingefaerbt, das genuegt als Signal. */
.menu a:hover { color: var(--akzent-text); }
.menu a[aria-current='page'] { color: var(--akzent-text); }

/* Der Menuefuss gehoert nur ins aufgeklappte Menue auf schmalen Geraeten.
   Ohne diese Zeile laeuft er auf dem Schreibtisch ungestaltet im Fluss
   unter den Punkten mit — dort gibt es kein Vollbildmenue, in das er
   gehoerte. Die Mobilabfrage schaltet ihn wieder ein. */
.menu-fuss { display: none; }

/* Schmale Geraete: das Menue fuellt den Bildschirm. */

@media (max-width: 899px) {
  :root { --kopf-hoehe: 80px; }

  /* Solange das Menue offen ist, muss die Kopfzeile decken. Auf der
     Startseite ist sie ueber dem Hero durchsichtig — ohne das hier stand
     ueber dem Menue ein Streifen, durch den das Hero-Video schien. */
  .kopf[data-offen='ja'] { background: var(--kopf); }

  .menu {
    position: fixed;
    inset: var(--kopf-hoehe) 0 0;
    background: var(--kopf);
    padding: 1rem var(--gutter) 3rem;
    /* Statt von rechts einzuschieben: aufblenden und leicht aufziehen. Das
       Einschieben liess den Inhalt dahinter kurz wandern. */
    opacity: 0;
    transform: scale(1.03);
    /* Geschlossen auch fuer Tastatur und Lesegeraet weg — sonst wandert der
       Fokus in Menuepunkte, die niemand sieht. */
    visibility: hidden;
    transition: opacity 0.28s ease, transform 0.35s var(--kurve),
                visibility 0.28s ease;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
  }
  /* Punkte und Fuss bilden einen Block, den die Flaeche mittig setzt.
     Vorher nahm die Liste per `flex: 1` den ganzen Raum und schob den Fuss
     an den unteren Rand — dazwischen klaffte ein Loch. */
  .menu { justify-content: center; }
  .menu ul { flex: none; }
  .kopf[data-offen='ja'] .menu {
    opacity: 1;
    transform: none;
    visibility: visible;
  }

  /* Punkte mittig, gross und untereinander — mit Platz, nicht gedraengt. */
  /* Punkte oben beginnen lassen, nicht im freien Raum zentrieren.
     Mit `flex: 1` nimmt die Liste die ganze Hoehe zwischen Kopfzeile und
     Fuss ein; zentriert darin rutschten die Punkte in die Mitte dieser
     Flaeche und standen dadurch weit unterhalb der Kopfzeile.

     `min-height: 100%` ist raus — zusammen mit `flex: 1` zog es die Liste
     zusaetzlich auf und verstaerkte den Effekt. */
  .menu ul {
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
  }
  .menu li { justify-content: center; }
  .menu a {
    font-size: clamp(1.75rem, 7vw, 2.25rem);
    letter-spacing: -0.01em;
  }
  /* U18 steht auf dem Telefon in der Kopfzeile neben der Marke, nicht im
     aufgeklappten Menue — es braucht dort also keine eigene Regel. */

  /* Fuss im aufgeklappten Menue: Anschrift und Symbole. Vier Punkte
     allein lassen die Vollbildflaeche leer wirken — hier steht, was man
     sonst erst im Seitenfuss findet. */
  .menu-fuss {
    margin-top: 2.5rem;
    display: grid;
    justify-items: center;
    gap: 0.35rem;
    text-align: center;
  }
  .menu-fuss p { color: var(--tinte-still); font-size: var(--t-klein); margin: 0; }
  .menu-fuss a { font-size: var(--t-klein); color: var(--tinte-leise); }
  .menu-fuss .fuss-social { margin-top: 0.75rem; }

  /* Ein sehr leiser Schein in der Markenfarbe nimmt der Flaeche das
     Tafelhafte, ohne sie einzufaerben. */
  .menu {
    background-image: radial-gradient(70% 40% at 50% 0%,
      rgb(var(--akzent-rgb) / 7%), transparent 70%);
  }

  /* Die Punkte laufen nacheinander ein, statt alle gleichzeitig
     aufzutauchen. Die Verzoegerung steht je Position im CSS, weil ein
     Inline-Style unter `style-src 'self'` nicht erlaubt ist. */
  .menu li {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.3s ease, transform 0.4s var(--kurve);
  }
  .kopf[data-offen='ja'] .menu li { opacity: 1; transform: none; }
  .kopf[data-offen='ja'] .menu li:nth-child(1) { transition-delay: 0.08s; }
  .kopf[data-offen='ja'] .menu li:nth-child(2) { transition-delay: 0.13s; }
  .kopf[data-offen='ja'] .menu li:nth-child(3) { transition-delay: 0.18s; }
  .kopf[data-offen='ja'] .menu li:nth-child(4) { transition-delay: 0.23s; }
  .kopf[data-offen='ja'] .menu li:nth-child(5) { transition-delay: 0.28s; }

  /* Wer Bewegung abbestellt hat, bekommt sie auch hier nicht. */
  @media (prefers-reduced-motion: reduce) {
    .menu li { opacity: 1; transform: none; transition: none; }
    .menu { transition: visibility 0.01s; transform: none; }
  }
}
@media (min-width: 900px) {
  .menu-knopf { display: none; }
}

/* ----------------------------------------------------------------- Hero -- */

.hero {
  position: relative;
  /* Feste Hoehe als `height`, nicht als `aspect-ratio` mit `max-height`:
     bei dieser Kombination zieht Chrome die Breite mit und laesst auf einem
     breiten, flachen Fenster rechts eine dunkle Flaeche stehen.
     Auch keine `vh`-Einheiten — sonst springt die Hoehe auf dem Telefon,
     wenn die Adressleiste ein- und ausfaehrt. */
  height: clamp(500px, 71svh, 790px);
  margin-top: calc(var(--kopf-hoehe) * -1);
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--nacht);
  text-align: center;
}

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

/* Schleier, damit die Schrift auf dem Video traegt. Dunkel, nicht hell —
   die bestehende Seite setzt weisse Schrift auf das Clubvideo. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgb(0 0 0 / 55%) 0%, rgb(0 0 0 / 35%) 45%, rgb(0 0 0 / 75%) 100%);
}

.hero-text {
  position: relative;
  z-index: 2;
  padding-top: var(--kopf-hoehe);
}

/* Logo ueber der Ueberschrift. Die Breiten sind die des Originals: 10 % der
   Spalte auf dem Schreibtisch, 28 % ab Tablet abwaerts. */
.hero-logo {
  width: 8%;
  min-width: 78px;
  margin: 0 auto 1rem;
}
@media (max-width: 1024px) {
  .hero-logo { width: 28%; }
}
/* Der Hero-Titel ist ein <p>, kein <h1> — die H1 der Seite steht statisch
   und fuer Lesegeraete unsichtbar im Markup. Sonst waeren es zwei. */
.hero-titel {
  margin: 0 0 1.25rem;
  font-family: var(--schrift-display);
  font-size: var(--t-hero);
  font-weight: 900;
  line-height: 1.02;
  text-transform: uppercase;
  letter-spacing: 0;
}
.hero-titel span { display: block; }

/* Knapper als die uebrigen Knoepfe. Die bestehende Seite macht es ebenso —
   im Hero steht der Knopf unter einer sehr grossen Ueberschrift und muss
   sie nicht noch einmal ueberbieten. */
.hero-text .knopf {
  padding: 0.7rem 1.4rem;
  font-size: 0.8125rem;
}

/* ------------------------------------------------------------- Ueber uns -- */

.ueber {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (min-width: 900px) {
  .ueber { grid-template-columns: 1fr 1fr; }
}

/* Logo ueber der Ueberschrift, linksbuendig — 20 % im Original. */
.ueber-logo { width: 20%; min-width: 80px; margin-bottom: 1.25rem; }
@media (max-width: 767px) { .ueber-logo { width: 21%; } }

.ueber-text h2 {
  /* Dieselbe Groesse wie „Next Events" und „Get the Vibe" — bis 50px.
     Vorher lief sie auf einer eigenen, kleineren Skala (bis 28px) und ging
     neben dem Fliesstext unter, obwohl sie der Einstieg in den Abschnitt
     ist. Die bestehende Balinger Seite fuehrt sie ebenfalls auf 50px. */
  font-size: var(--t-h2);
  margin-bottom: 1.25rem;
}
/* Blocksatz wie im Original. */
/* Kein Blocksatz. Auf schmalen Spalten reisst er Loecher zwischen die
   Woerter — auf dem Telefon bis zu 45 Pixel in einer Zeile. */
.ueber-text p { color: var(--tinte-leise); }
.ueber-text .knopf-reihe { margin-top: 2rem; }

/* **Auf dem Telefon richtet sich der Abschnitt nach den anderen.**

   Sobald `.ueber` einspaltig steht, sitzt diese Ueberschrift direkt ueber
   „Next Events" und „Get the Vibe" — und war mit 22px sichtbar kleiner als
   deren 28px. Auf der bestehenden Seite sind alle drei gleich gross
   (gemessen: je 35px bei 390px Breite).

   Der Knopf steht aus demselben Grund mittig: In den anderen Abschnitten
   macht das `[data-mitte]`, hier geht es nicht ueber das Markup, weil der
   Knopf auf dem Schreibtisch in der linken Spalte bleiben soll.

   Der Haltepunkt ist derselbe wie der des Rasters oben — zwei Werte, die
   zusammengehoeren. Wer einen aendert, muss den anderen mitziehen. */
@media (max-width: 899px) {
  .ueber-text .knopf-reihe { justify-content: center; }
}

/* --------------------------------------------------------------- Karten -- */

/* Drei Spalten, Abstand 20px — und ab Tablet abwaerts eine Spalte. Das
   Original schaltet bei 1024 px direkt auf einspaltig, nicht stufenweise. */
.karten {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 1024px) {
  .karten { grid-template-columns: 1fr; }
}

.karte {
  display: flex;
  flex-direction: column;
  /* Die Kerben sind **Aussparungen im Kartenhintergrund**, keine farbigen
     Kreise. Zwei Kreise in der Hintergrundfarbe waeren nur auf schwarzem
     Grund unsichtbar — der Eventabschnitt der Startseite liegt aber auf
     einem Foto, dort staenden sie als dunkle Punkte. So stanzen sie
     wirklich, und es zeigt sich, was immer dahinterliegt. */
  background:
    radial-gradient(circle 11px at 0 calc(100% - var(--abriss)),
      transparent 11px, var(--karte) 11.5px) left / 51% 100% no-repeat,
    radial-gradient(circle 11px at 100% calc(100% - var(--abriss)),
      transparent 11px, var(--karte) 11.5px) right / 51% 100% no-repeat;
  border-radius: var(--r-karte);
  /* Damit der Flyer die Rundung der Karte uebernimmt, ohne ihn einzeln zu
     runden — sonst steht an der Oberkante eine Ecke ueber. */
  overflow: hidden;
  box-shadow: var(--schatten);
  transition: transform 0.3s var(--kurve), box-shadow 0.3s var(--kurve);
}
.karte:hover {
  transform: translateY(-6px);
  box-shadow: var(--schatten-hoch);
}
.karte:active { transform: translateY(-2px); }

.karte-bild { background: var(--box-hell); }
/* Flyer sind 16:9 — ein quadratischer Beschnitt schneidet den Titel weg. */
.karte-bild img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.karte-text {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 0.875rem 0.9375rem 1rem;
  flex: 1;
}
/* Der Abschnitt unter der Perforation, wie bei einer Eintrittskarte:
   links Termin und Uhrzeit, rechts der Weg zur Veranstaltung.

   Feste Hoehe aus `--abriss`, damit die Trennlinie genau dort sitzt, wo die
   Kerben im Kartenhintergrund ausgespart sind. Waechst der Abschnitt mit
   seinem Inhalt, wandert die Linie und die Stanzung passt nicht mehr. */
.karte-abriss {
  display: flex;
  align-items: center;
  /* Nur noch ein Kind („Infos"). `space-between` schoebe es nach links und
     liesse rechts eine tote Flaeche — mittig liest es sich als Absicht. */
  justify-content: center;
  gap: 0.5rem;
  height: var(--abriss);
  margin: 0;
  padding-inline: 0.9375rem;
  border-top: 2px dashed var(--linie);
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.karte-infos {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  /* Weiss, nicht Akzent. Auf der Karte steht der Termin schon blau — ein
     zweites blaues Element im selben kleinen Feld laesst beide gleich
     wichtig wirken, obwohl der Termin die Angabe ist und „Infos" nur die
     Wegmarke.

     `--tinte` genuegt: Die Karte steht in der Sammelregel „Dunkle Inseln"
     und fuehrt dort die helle Tinte, auch wenn sie in einem hellen
     Abschnitt liegt. */
  color: var(--tinte);
  transition: gap 0.22s var(--kurve);
}
/* Der Pfeil rueckt beim Darueberfahren ein Stueck weiter — die Karte ist
   ein Link, und das zeigt sie damit. */
.karte:hover .karte-infos { gap: 0.6rem; }
.karte-titel {
  font-size: var(--t-h3);
  line-height: 1.2;
}
/* Termin unter dem Titel. Stand hier vorher der Ort, der bei allen
   Veranstaltungen gleich lautete — jetzt die Angabe, nach der man auf einer
   Eventkarte zuerst sucht, und entsprechend betont. */
.karte-termin-gross {
  margin: 0;
  color: var(--akzent-text);
  font-size: var(--t-klein);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Monatsueberschrift der Eventliste. */
/* Zentriert und weiss, ohne Trennlinie — wie im Original. */
.monat {
  /* Bis 32px wie auf der bestehenden Seite. `--t-h3` (bis 24px) war zu
     leise fuer eine Zeile, die eine ganze Kartengruppe eroeffnet. */
  font-size: clamp(1.5rem, 3.5vw, 2rem);
  color: var(--tinte);
  text-align: center;
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 1.5rem;
}
.monat:first-child { margin-top: 0; }

.leer {
  color: var(--tinte-leise);
  text-align: center;
  padding-block: 3rem;
}

/* ------------------------------------------------------- Schieberegler -- */

/* Ersetzt Swiper. Das Band wird verschoben, die Folien teilen sich die
   Breite — wie viele gleichzeitig zu sehen sind, sagt `data-zeigen`. */
.slider { position: relative; }

/* Die Spur umfasst **nur das Band**, nicht die Punktreihe. Daran haengen
   zwei Dinge: Das Beschneiden (frueher am Regler) und die senkrechte Mitte
   fuer die Pfeile — die sassen vorher auf der Mitte von Bild plus Punkten
   und damit zu tief.

   `touch-action: pan-y` gibt das senkrechte Scrollen an die Seite weiter
   und behaelt die waagerechte Geste fuer das Blaettern. Ohne das verschluckt
   der Browser entweder das Wischen oder das Scrollen. */
.slider-spur {
  position: relative;
  overflow: hidden;
  touch-action: pan-y;
}
.slider-band {
  display: flex;
  /* `transition` setzt slider.js, damit eine Strecke ohne JavaScript nicht
     erst leer dasteht und dann springt. */
}
.slider-band > figure {
  margin: 0;
  flex: 0 0 100%;
  padding-inline: 0.3125rem;
  box-sizing: border-box;
}
.slider-band img {
  width: 100%;
  object-fit: cover;
  background: var(--box);
  border-radius: var(--r-karte);
}
/* Die Einblick-Strecke zeigt Querformate und laesst sich vergroessern. */
/* An der Klasse, nicht an der Abschnitts-ID. Die ID heisst je Projekt
   anders (`einblick`, `fotos`); haengt die Regel daran, faellt sie beim
   Umbenennen lautlos aus — dann folgt die Folienbreite dem Bild statt der
   Spur und vom Nachbarbild schaut ein Streifen hervor. */
.slider-randlos .slider-band > figure { cursor: zoom-in; }
/* Jede Flaeche folgt ihrer eigenen Quelle, statt beide auf ein gemeinsames
   Mass zu zwingen und eine davon zu beschneiden.

   Gemessen an der bestehenden Seite:
     „Get the Vibe"  1350x1080 = 5:4 quer, angezeigt 480x384 — 5:4
     „Ueber uns"     1080x1350 = 4:5 hoch, angezeigt 510x638 — 4:5
   Beides ohne Beschnitt, weil Box und Quelle dasselbe Verhaeltnis haben. */
.slider-randlos .slider-band img { aspect-ratio: 5 / 4; }
.ueber .slider-band img { aspect-ratio: 4 / 5; }

.slider-pfeil {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  border: 0;
  border-radius: 50%;
  background: rgb(0 0 0 / 45%);
  backdrop-filter: blur(8px);
  color: var(--akzent-text);
  cursor: pointer;
  transition: background 0.15s ease;
}
.slider-pfeil:hover { background: rgb(0 0 0 / 75%); }
.slider-rueck { left: 0.3125rem; }
.slider-vor { right: 0.3125rem; }

.slider-punkte {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1rem;
}
.slider-punkt {
  width: 8px; height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  /* Im Original: aktiver Punkt in der Akzentfarbe, die uebrigen weiss. */
  background: var(--tinte);
  opacity: 0.45;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}
.slider-punkt[aria-current='true'] { background: var(--akzent); opacity: 1; }

/* Die Einblick-Strecke laeuft im Original randlos ueber die volle
   Fensterbreite. Sie steht im Markup trotzdem in der Huelle, damit die
   Ueberschrift darueber ausgerichtet bleibt — der negative Rand holt sie
   wieder heraus. `100vw` statt `100%`, weil die Huelle schmaler ist; der
   Ausgleich nach links ist die halbe Differenz. */
.slider-randlos {
  /* `--sb` ist die Breite der Scrollleiste, gesetzt von page-common.js.
     Ohne den Abzug ist die Flaeche auf dem Schreibtisch genau um diese
     Breite zu breit und die ganze Seite laesst sich quer schieben. */
  width: calc(100vw - var(--sb, 0px));
  margin-left: calc(50% - (100vw - var(--sb, 0px)) / 2);
}
.slider-randlos .slider-rueck { left: 0; }
.slider-randlos .slider-vor { right: 0; }

/* ------------------------------------------------------------ Lightbox -- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  place-items: center;
  background: rgb(0 0 0 / 92%);
  padding: clamp(1rem, 5vw, 3rem);
}
.lightbox[data-offen='ja'] { display: grid; }

.lb-bild {
  max-width: 100%;
  max-height: 82vh;
  object-fit: contain;
  border-radius: var(--r-karte);
}
.lb-zaehler {
  position: absolute;
  bottom: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  color: var(--tinte-still);
  font-size: var(--t-klein);
}

.lb-knopf {
  position: absolute;
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  border: 0;
  border-radius: 50%;
  background: rgb(255 255 255 / 10%);
  backdrop-filter: blur(8px);
  color: var(--tinte);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.lb-knopf:hover { background: var(--akzent); color: var(--akzent-tinte); }
.lb-zu    { top: 1rem; right: 1rem; }
.lb-rueck { left: 1rem;  top: 50%; transform: translateY(-50%); }
.lb-vor   { right: 1rem; top: 50%; transform: translateY(-50%); }

/* --------------------------------------------------------------- Anfahrt -- */

.anfahrt {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
}
@media (min-width: 760px) {
  .anfahrt { grid-template-columns: 1fr 1fr; }
}
.anfahrt h2 { font-size: var(--t-h3); margin-bottom: 1rem; }

.zeile {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
  color: var(--tinte-leise);
}
.zeile .icon { color: var(--akzent-text); margin-top: 0.2rem; }
.zeile a:hover { color: var(--akzent-text); }

/* ------------------------------------------------------- Seitenkopf (Unter) -- */

/* Feste Hoehe. Ohne sie richtet sich jeder Kopf nach der Laenge seines
   Einleitungssatzes und die Unterseiten stehen unterschiedlich hoch. */
/* Bildbanner der Unterseiten — im Original je Seite ein anderes Clubfoto,
   mit dunklem Schleier darueber. */
.seitenkopf-bild {
  position: relative;
  background-position: center center;
  background-size: cover;
  background-repeat: no-repeat;
  isolation: isolate;
}
.seitenkopf-bild::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(0 0 0 / 58%);
}
/* Die Ausschnitte sitzen mittig: Alle vier Motive sind Querformate aus der
   eigenen Fotostrecke und tragen kein Motiv am Rand, das der Beschnitt
   treffen koennte. */
.seitenkopf-bild[data-banner='events']  { background-image: url('../img/banner/events.webp'); }
.seitenkopf-bild[data-banner='fotos']   { background-image: url('../img/banner/fotos.webp'); }
.seitenkopf-bild[data-banner='jobs']    { background-image: url('../img/banner/jobs.webp'); }
.seitenkopf-bild[data-banner='kontakt'] { background-image: url('../img/banner/kontakt.webp'); }

.seitenkopf {
  /* Hoehe waechst mit der Fensterbreite, statt auf dem Telefon als flacher
     Streifen dazustehen, durch den das Bild stark beschnitten wird. */
  min-height: clamp(320px, 34vw, 460px);
  display: grid;
  align-content: center;
  /* Der Banner laeuft unter die Kopfzeile, damit die schwebende Leiste
     auch hier auf einem Bild sitzt und nicht auf leerer Flaeche.

     Negativer Rand **und** Polster gehoeren zusammen: Der Rand schiebt den
     Banner unter die Leiste, das Polster holt den Inhalt wieder in die
     sichtbare Flaeche. Eines ohne das andere drueckt ihn aus der Mitte —
     genau das war hier frueher der Fall, als das Polster ohne Gegenstueck
     stand. */
  margin-top: calc(var(--kopf-hoehe) * -1);
  padding-top: calc(var(--kopf-hoehe) + clamp(2.5rem, 7vw, 4rem));
  padding-bottom: clamp(2.5rem, 7vw, 4rem);
  /* `background-color`, nicht die Kurzschreibweise `background`. Das
     Element traegt beide Klassen (`seitenkopf seitenkopf-bild`), und die
     Kurzschreibweise setzt alle uebrigen background-Werte zurueck — damit
     fiel `background-size: cover` aus `.seitenkopf-bild` auf `auto`
     zurueck und das Bannerbild lag in Originalgroesse in der Flaeche,
     also dreifach vergroessert. Das Bild ueberlebte nur, weil die
     Banner-Regeln hoehere Spezifitaet haben. */
  background-color: var(--flaeche);
  border-bottom: 1px solid var(--linie);
  text-align: center;
}
/* Eigene Skala, nicht `--t-h1`: Die Bannerueberschrift steht allein auf
   einer grossen Flaeche und darf deutlich groesser anfangen als eine
   Ueberschrift im Fliesstext. */
/* Auf dem Telefon traegt die Ueberschrift den ganzen Banner — sie darf
   dort deutlich groesser anfangen. 13vw heisst rund 51px auf einem
   390px-Geraet statt der vorherigen 40px. */
/* **Drei Dinge zusammen, sonst wird der Titel abgeschnitten.**

   Ein langes Wort wie „DATENSCHUTZ" hat bei 13vw auf einem 390er Telefon
   eine Mindestbreite von 396 Pixeln. Die `.huelle` ist ein Rasterelement
   mit `min-width: auto` und kann deshalb nicht unter diese Mindestbreite
   schrumpfen — sie wurde 428 Pixel breit, und `overflow-x: clip` am
   Dokument schnitt den Ueberhang einfach ab. Sichtbar war das nur als
   fehlendes „Z".

   `min-width: 0` erlaubt dem Rasterelement zu schrumpfen, der kleinere
   Faktor laesst die vorkommenden Titel passen, und `overflow-wrap` faengt
   den Fall ab, dass spaeter ein noch laengeres Wort dazukommt: Dann bricht
   es um, statt zu verschwinden. */
.seitenkopf > .huelle { min-width: 0; }
.seitenkopf h1 {
  font-size: clamp(2.25rem, 11vw, 4.5rem);
  overflow-wrap: anywhere;
}
.seitenkopf p {
  margin: 1rem auto 0;
  max-width: 54ch;
  color: var(--tinte-leise);
  text-transform: none;
}
.seitenkopf .unterzeile {
  color: var(--akzent-text);
  font-weight: 400;
  font-size: clamp(0.9375rem, 2.6vw, 1.125rem);
}

/* Auf dem Telefon traegt der Banner ein festes Seitenverhaeltnis statt einer
   Mindesthoehe. Der Umweg ueber eigene Hochformat-Zuschnitte war falsch: Ein
   schmaler Ausschnitt aus einem Breitbild heisst staerker vergroessern, nicht
   schwaecher. Und eine feste Mindesthoehe bei schmaler Breite erzwingt genau
   diese Vergroesserung, weil `cover` die Hoehe fuellen muss.

   **3:2 statt 16:9 — gemessen, nicht geschaetzt.** Mit dem Verhaeltnis des
   Bildes (16:9, die Datei ist 1536x864) war das Band bei 390 Pixel Breite
   219 Pixel hoch. Davon gehen 80 fuer die schwebende Kopfzeile ab, es
   bleiben 139 fuer 96 Pixel Text: 21 Pixel Luft ueber der Ueberschrift,
   22 darunter. Die Schrift klebte oben an der Leiste und unten an der
   Kante — genau das wirkte gequetscht.

   Das Polster ist hier **nicht** der Hebel: `align-content: center`
   zentriert den Inhalt, sobald er die Inhaltsbox ueberlaeuft, und das tut
   er auf jeder Telefonbreite. Ein kleineres Polster verschiebt deshalb
   nichts. Nur mehr Hoehe hilft.

   3:2 ergibt 260 Pixel, also 180 nutzbare statt 139 — die Luft verdoppelt
   sich auf gut 40 Pixel. Der Preis sind rund 16 Prozent seitlicher
   Beschnitt. Das ist der Tausch: etwas weniger Bild gegen Text, der nicht
   zwischen zwei Kanten klemmt. */
@media (max-width: 759px) {
  .seitenkopf-bild {
    min-height: 0;
    aspect-ratio: 3 / 2;
    background-position: center center;
  }
}

/* ------------------------------------------------------------------ FAQ -- */

.kontakt-raster {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
@media (min-width: 900px) {
  .kontakt-raster { grid-template-columns: 1fr 1fr; }
  /* Ist die FAQ leer, faellt die linke Spalte weg und das Formular rueckt
     in die Mitte. */
  .kontakt-raster[data-ohne-faq='ja'] {
    grid-template-columns: minmax(0, 640px);
    justify-content: center;
  }
}

.faq {
  border-bottom: 1px solid var(--linie);
}
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.125rem 0;
  cursor: pointer;
  font-weight: 700;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
/* Das Pluszeichen dreht sich beim Aufklappen zum Minus. Als ::after und
   nicht als Symbol im Markup: eine Zierde gehoert nicht in den Quelltext. */
.faq summary::after {
  content: '';
  flex: none;
  width: 14px; height: 14px;
  background:
    linear-gradient(var(--akzent), var(--akzent)) center / 100% 2px no-repeat,
    linear-gradient(var(--akzent), var(--akzent)) center / 2px 100% no-repeat;
  transition: transform 0.2s ease;
}
.faq[open] summary::after { transform: rotate(45deg); }
.faq[open] summary { color: var(--akzent-text); }
.faq-text {
  padding-bottom: 1.25rem;
  color: var(--tinte-leise);
}
/* Die Antwort kommt als reiner Text aus Clubinio, mit Zeilenumbruechen —
   `page-kontakt.js` setzt sie als `textContent`. Ohne `pre-wrap` faltet CSS
   die Umbrueche zu Leerzeichen und aus einer gegliederten Antwort wird ein
   Block. Dieselbe Loesung wie bei der Eventbeschreibung weiter unten, aus
   demselben Grund: kein Markup aus einem Shopadmin-Feld interpretieren. */
.faq-text p { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------- Fotos -- */

/* Die Albenliste. Karten im Raster, Deckblatt oben, darunter Titel und
   Datum — dieselbe Form wie die Eventkarten, damit die Seite zusammengehoert. */
.alben-raster {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}
.album-karte {
  display: flex;
  flex-direction: column;
  border-radius: var(--r-karte);
  background: var(--karte);
  overflow: hidden;
  text-decoration: none;
  transition: transform 0.3s var(--kurve), box-shadow 0.3s var(--kurve);
}
.album-karte:hover { transform: translateY(-4px); box-shadow: var(--schatten-hoch); }
.album-karte:focus-visible { outline: 2px solid var(--akzent); outline-offset: 3px; }

/* Festes Seitenverhaeltnis: Die Deckblaetter kommen aus der API und haben
   unterschiedliche Formate — ohne das springen die Karten in der Hoehe. */
/* **2:3 hochkant — das Format der Dateien selbst.** Clubinio liefert die
   Deckblaetter als 1333x2000; in einer Querflaeche blieb davon ein Drittel
   uebrig, Koepfe und das Logo am unteren Rand fielen weg. So steht das
   Motiv vollstaendig da, genau wie im Shopadmin.

   Fest und nicht `auto`, damit die Karten im Raster gleich hoch bleiben —
   kaeme spaeter ein Querformat dazu, wuerde es beschnitten statt die Reihe
   zu zerreissen. */
.album-bild {
  aspect-ratio: 2 / 3;
  background: var(--box);
  /* **Positionierungsrahmen, nicht nur Verhaeltnis.** Ein `height: 100%` am
     Bild loest sich zu `auto` auf, solange die Elternhoehe selbst erst aus
     `aspect-ratio` entsteht — das Bild legt sich dann in seinem eigenen
     Format aus und zieht die Box mit. Ein hochformatiges Deckblatt machte
     aus 4:3 so ein 2:3. Absolut gesetzt kann es das nicht mehr. */
  position: relative;
  overflow: hidden;
}
.album-bild img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.55s var(--kurve);
}
.album-karte:hover .album-bild img { transform: scale(1.04); }

.album-text { padding: 1rem 1.125rem 1.25rem; }
.album-titel { font-size: var(--t-h3); margin-bottom: 0.4rem; }
.album-zeile {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  font-size: var(--t-klein);
  color: var(--tinte-leise);
}
.album-zahl { color: var(--akzent-text); white-space: nowrap; }

/* Die Bilder einer Strecke als **Mosaik**: Jedes behaelt sein eigenes
   Format, Hoch- und Querformat stehen nebeneinander.

   Spalten statt Raster, weil ein Raster feste Zeilenhoehen braucht und die
   Bilder dafuer beschnitten werden muessten. `break-inside: avoid` haelt
   ein Bild zusammen, sonst zerreisst es die Spaltenkante.

   Der Preis: Spalten laufen senkrecht, die Lesereihenfolge ist also
   spaltenweise statt zeilenweise. Fuer eine Fotowand ist das in Ordnung —
   fuer eine Liste waere es das nicht. */
.fotoraster {
  column-count: 2;
  column-gap: 0.5rem;
  margin-top: 1.5rem;
}
@media (min-width: 600px)  { .fotoraster { column-count: 3; } }
@media (min-width: 900px)  { .fotoraster { column-count: 4; } }
@media (min-width: 1200px) { .fotoraster { column-count: 5; } }

.fotoraster figure {
  margin: 0 0 0.5rem;
  break-inside: avoid;
  border-radius: var(--r-klein);
  overflow: hidden;
  background: var(--box);
  cursor: zoom-in;
}
.fotoraster img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform 0.4s var(--kurve), opacity 0.2s ease;
}
.fotoraster figure:hover img { transform: scale(1.05); }
.fotoraster figure:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }

/* Rueckweg aus einer Strecke. Steht ueber der Ueberschrift, nicht darunter:
   Wer zurueck will, sucht oben. */
.zurueck {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-bottom: 1rem;
  color: var(--tinte-leise);
  font-size: var(--t-klein);
  text-decoration: none;
}
.zurueck::before { content: '\2039'; font-size: 1.3em; line-height: 1; }
.zurueck:hover { color: var(--akzent-text); }

/* Die Kopfzeile einer Strecke steht links, nicht mittig wie die der
   Abschnitte auf der Startseite. */
.kopfzeile-links { text-align: left; }

/* ---------------------------------------------------------------- Jobs -- */

/* Im Original steht die Ansprache linksbuendig und in normaler Schriftlage,
   nicht als zentrierte Versalueberschrift. */
.abschnitt-oben { padding-block: clamp(2.5rem, 6vw, 4rem) 0; }
/* Ansprache und Formular gehoeren zusammen. Ohne das hier stossen zwei
   volle Abschnittspolster aneinander und reissen eine Luecke zwischen
   Einleitung und erstem Feld. Die zweite Zeile ueberspringt die
   ausgeblendeten Stellen. */
.abschnitt-oben + .abschnitt,
.abschnitt-oben + [hidden] + .abschnitt { padding-top: clamp(1.75rem, 4vw, 2.75rem); }
.jobs-ansprache {
  font-size: var(--t-h3);
  text-transform: none;
  margin-bottom: 1rem;
}
/* Keine Breitenbegrenzung: Das Formular darunter laeuft ueber die volle
   Huellenbreite, und eine auf 70 Zeichen gekappte Einleitung sah daneben
   aus wie ein Textblock, der versehentlich links klebt. */
.jobs-intro { color: var(--tinte-leise); }

/* -------------------------------------------------------------- Stellen -- */

.stelle {
  padding: 1.5rem;
  background: rgb(var(--tinte-rgb) / 5%);
  border: 1px solid rgb(var(--tinte-rgb) / 8%);
  border-radius: var(--r-karte);
  margin-bottom: 1rem;
}
.stelle h3 { font-size: var(--t-h3); margin-bottom: 0.5rem; }
/* `white-space` wie bei der FAQ-Antwort: `page-jobs.js` setzt die
   Beschreibung als reinen Text, die Umbrueche darin sollen stehen bleiben. */
.stelle p {
  color: var(--tinte-leise);
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ Formulare -- */

.form { display: grid; gap: 1.125rem; }

/* h2 traegt global keinen Abstand; ueber einem Formular braucht sie einen,
   sonst sitzt sie auf der ersten Feldbeschriftung. */
#kontaktformular h2 { margin-bottom: 1.5rem; }

/* Im Original stehen kurze Felder nebeneinander, nicht alle untereinander.
   `auto-fit` statt fester Spalten: unter ~420px je Feld bricht die Reihe
   von selbst um, ohne eigene Abfrage. */
.form-reihe {
  display: grid;
  gap: 1.125rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
}

.feld { display: grid; gap: 0.4rem; }
/* Im Original stehen die Beschriftungen in Normalschrift und gemischter
   Schreibung, nicht als fette Versalien. */
.feld > span {
  font-size: var(--t-klein);
  font-weight: 400;
  color: var(--tinte-leise);
}
.feld-pflicht { color: var(--akzent-text); }

input[type='text'], input[type='email'], input[type='tel'],
input[type='number'], input[type='file'], textarea, select {
  width: 100%;
  padding: 0.95rem 1.05rem;
  /* Kein Rahmen. Die Flaeche allein zeigt, wo geschrieben wird — eine Linie
     um jedes Feld zieht das Formular in Kaestchen auseinander. */
  border: 0;
  border-radius: var(--r-feld);
  background: rgb(var(--tinte-rgb) / 6%);
  color: var(--tinte);
  font: inherit;
  transition: box-shadow 0.2s ease, background 0.2s ease;
}
:is(input[type='text'], input[type='email'], input[type='tel'],
    input[type='number'], textarea, select):hover:not(:focus) {
  background: rgb(var(--tinte-rgb) / 8%);
}
textarea {
  min-height: 150px;
  resize: vertical;
  border-radius: var(--r-feld);
}
/* Fokus als schmaler Ring aussen. Er liegt ueber dem Rand, nicht darin,
   und verschiebt deshalb nichts. */
input:focus, textarea:focus, select:focus {
  outline: 0;
  background: rgb(var(--tinte-rgb) / 10%);
  box-shadow: 0 0 0 2px rgb(var(--akzent-rgb) / 45%);
}
::placeholder { color: var(--tinte-still); }

/* Das Dateifeld traegt keine eigene Flaeche: sonst steht ein Knopf in
   einem Kasten in einem Formular. Nur der Knopf bleibt sichtbar, der
   Dateiname steht daneben im Text. */
input[type='file'] {
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--t-klein);
  color: var(--tinte-leise);
}
input[type='file']:focus {
  background: none;
  box-shadow: none;
}
input[type='file']::file-selector-button {
  margin-right: 0.75rem;
  padding: 0.6rem 1.2rem;
  border: 0;
  border-radius: var(--r-knopf);
  background: rgb(var(--tinte-rgb) / 10%);
  color: var(--tinte);
  font: inherit;
  font-size: var(--t-klein);
  cursor: pointer;
  transition: background 0.2s ease;
}
input[type='file']::file-selector-button:hover {
  background: rgb(var(--tinte-rgb) / 16%);
}
input[type='file']:focus-visible::file-selector-button {
  outline: 2px solid var(--akzent);
  outline-offset: 2px;
}

/* Mehrfachauswahl der Bereiche auf der Jobseite. Keine Pillen mehr: sieben
   Umrisse mit je einem Kreis darin ergeben eine Wand aus Rahmen. Hier steht
   nur das Kaestchen und der Text daneben, in Spalten gesetzt, damit die
   unterschiedlich langen Bezeichnungen untereinander ausgerichtet bleiben. */
.auswahl {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  gap: 0.9rem 1.5rem;
  margin-top: 0.3rem;
}
.auswahl label {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--tinte-leise);
  cursor: pointer;
  transition: color 0.2s ease;
}
.auswahl label:hover,
.auswahl label:has(input:checked) { color: var(--tinte); }

/* Das Fieldset traegt im Original keinen Rahmen — nur die Beschriftung
   darueber, wie bei jedem anderen Feld. */
fieldset.feld {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}
fieldset.feld legend { padding: 0; }

.zustimmung {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  font-size: var(--t-klein);
  color: var(--tinte-leise);
}
.zustimmung input { margin-top: 0.1rem; }

/* Ein eigenes Kaestchen fuer beide Stellen. Das Systemkaestchen ist ein
   weisses Quadrat und passt zu nichts hier; gefuellt statt umrandet spricht
   es dieselbe Sprache wie die Eingabefelder. */
.auswahl input, .zustimmung input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 20px; height: 20px;
  border: 0;
  border-radius: 7px;
  background: rgb(var(--tinte-rgb) / 10%);
  cursor: pointer;
  transition: background 0.2s ease;
}
.auswahl label:hover input:not(:checked),
.zustimmung:hover input:not(:checked) { background: rgb(var(--tinte-rgb) / 16%); }
.auswahl input:checked, .zustimmung input:checked {
  background: var(--haken) var(--akzent) center / 13px 13px no-repeat;
}
.auswahl input:focus-visible, .zustimmung input:focus-visible {
  outline: 2px solid var(--akzent);
  outline-offset: 2px;
}
.zustimmung a { color: var(--akzent-text); text-decoration: underline; }

/* Honigtopf. Fuer Menschen unsichtbar, fuer Skripte verlockend.
   Nicht `display: none` — manche Skripte ueberspringen genau das. */
.honigtopf {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.rueckmeldung {
  margin: 0;
  font-size: var(--t-klein);
  min-height: 1.4em;
}
.rueckmeldung[data-state='ok']      { color: var(--akzent-text); }
.rueckmeldung[data-state='fehler']  { color: #ff6b5e; }
.rueckmeldung[data-state='laeuft']  { color: var(--tinte-still); }

/* ------------------------------------------------------------- Eventseite -- */

/* Inhaltsspalte ~820px und Titel ~40px — Originalwerte. */
.event { max-width: 820px; margin-inline: auto; }
.event h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); }

.event-flyer {
  width: 100%;
  border-radius: var(--r-karte);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--box);
  margin-bottom: 1.75rem;
}

.event .knopf-reihe { margin-bottom: 2rem; }
.event .knopf-reihe .knopf { flex: 1 1 260px; }

/* Der U18-Knopf laeuft ueber dieselbe Breite wie der Ticketknopf. Als
   schmaler Knopf unter einem breiten stand er auf dem Schreibtisch
   verloren in der Flaeche. */
.event .knopf-reihe-u18 .knopf { width: 100%; }

/* U18-Formular. Erscheint nur, wenn Minderjaehrige eingelassen werden —
   tools/build.py entscheidet das je Termin aus `ageRestriction`.

   Steht unter den Knoepfen und nicht daneben: Es ist kein gleichrangiger
   Weg zum Ticket, sondern eine Bedingung fuer einen Teil der Gaeste. Der
   Abstand nach oben ist deshalb negativ gegen den Abstand der Knopfreihe —
   Hinweis und Knopf gehoeren optisch zusammen, nicht zum Flyer darueber. */
/* Der Knopf steht direkt unter dem Ticketknopf, der Hinweis darunter: Die
   Handlung zuerst, die Erklaerung als Beschriftung dazu. Der negative
   Abstand nach oben arbeitet gegen den Abstand der Ticketreihe — beide
   Knoepfe gehoeren zusammen. */
.event .knopf-reihe-u18 { margin: -1rem 0 0.6rem; }
.u18-hinweis {
  margin: 0 0 2.5rem;
  color: var(--tinte-still);
  font-size: var(--t-klein);
}

.event-datum {
  color: var(--akzent-text);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.625rem;
}
.event h1 { margin-bottom: 1.5rem; }
/* Die Beschreibung steht auf der Eventseite fast allein auf der Flaeche.
   Eine leichte Absetzung gibt ihr eine Kante, statt sie im Grund
   verschwinden zu lassen — ohne sie als Kasten zu rahmen. */
.event-text a { color: var(--akzent-text); }
.event-text {
  margin-top: 0.5rem;
  padding: 1.25rem 1.375rem;
  background: rgb(var(--tinte-rgb) / 3.5%);
  border-radius: var(--r-karte);
  color: var(--tinte-leise);
  line-height: 1.55;
  /* Die Beschreibung kommt als reiner Text aus Clubinio, mit Zeilenumbruechen
     und Emoji. `pre-wrap` erhaelt die Umbrueche, ohne dass dafuer Markup
     aus einem Shopadmin-Feld interpretiert werden muss. */
  white-space: pre-wrap;
  /* Lange Adressen haben keine Trennstelle — ohne das hier laufen sie aus
     dem Kasten heraus und werden am Rand abgeschnitten. `anywhere` statt
     `break-word`, weil es auch in die Mindestbreite einfliesst: Sonst zieht
     ein einziger langer Link den Kasten breiter als den Bildschirm. */
  overflow-wrap: anywhere;
}

.infokasten {
  margin-top: 2.5rem;
  padding: 1.75rem;
  background: rgb(var(--tinte-rgb) / 5%);
  border: 1px solid rgb(var(--tinte-rgb) / 8%);
  border-radius: var(--r-karte);
}
.infokasten h2 { font-size: var(--t-h3); margin-bottom: 1.25rem; }
/* Zwei Paare nebeneinander, Beschriftung ueber dem Wert — wie im Original.
   `dt`/`dd` stehen im Markup abwechselnd; das Raster setzt sie deshalb in
   eine eigene Zelle je Paar, indem jedes `dt` eine neue Zeile beginnt. */
.infokasten dl {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem 2.5rem;
  margin: 0;
}
@media (min-width: 620px) {
  .infokasten dl { grid-template-columns: 1fr 1fr; }
}
.infopaar dt { margin: 0; }
.infokasten dd {
  text-transform: uppercase;
  font-weight: 700;
  margin-top: 0.25rem;
}
.infokasten dt {
  color: var(--tinte-still);
  font-size: var(--t-klein);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.infokasten dd { margin: 0; }

.lounges {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
}
.lounge {
  background: var(--karte);
  border-radius: var(--r-karte);
  overflow: hidden;
  box-shadow: var(--schatten);
}
.lounge img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.lounge-text { padding: 1rem 1.125rem 1.25rem; }
.lounge-text h3 { font-size: 1.0625rem; margin-bottom: 0.375rem; }
.lounge-wert { margin: 0; color: var(--tinte-leise); font-size: var(--t-klein); }
.lounge-hinweis {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--tinte-still);
  font-size: var(--t-klein);
}

/* Zentriert mit Pfeil davor — wie im Original. Der Pfeil ist wie bei den
   Knoepfen gezeichnet, nicht gesetzt. */
.zurueck::before {
  content: '';
  width: 1em;
  height: 1em;
  flex: none;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 12H6.8l4.6-4.6L10 6l-6 6 6 6 1.4-1.4L6.8 12H19v-2Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 12H6.8l4.6-4.6L10 6l-6 6 6 6 1.4-1.4L6.8 12H19v-2Z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.zurueck {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  margin-top: 2.5rem;
  color: var(--tinte-leise);
  font-size: var(--t-klein);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.zurueck:hover { color: var(--akzent-text); }

/* ------------------------------------------------------------ Rechtstext -- */

.rechtstext { max-width: 72ch; }
.rechtstext h2 {
  font-size: var(--t-h3);
  margin: 2.5rem 0 0.875rem;
  text-transform: none;
}
.rechtstext h3 {
  font-size: 1.0625rem;
  margin: 1.75rem 0 0.5rem;
  text-transform: none;
}
.rechtstext p, .rechtstext li { color: var(--tinte-leise); }
.rechtstext a { color: var(--akzent-text); text-decoration: underline; }
.rechtstext ul { padding-left: 1.25rem; }
.rechtstext address { font-style: normal; margin-bottom: 1.5rem; }

/* ------------------------------------------------------------------ Fuss -- */

/* Zwei Spalten wie im Original: links Marke und Rechtslinks, rechts die
   Anfahrt samt Social-Symbolen und dem Clubinio-Zeichen. */
.fuss {
  background: var(--kopf);
  padding-block: clamp(2.5rem, 6vw, 4rem);
}
.fuss-raster {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 760px) {
  .fuss-raster { grid-template-columns: 1.4fr 1fr; }
}

/* Relativ zur Spalte, nicht als feste Pixelzahl — so macht es das
   Original (`width: 24%`). Feste 150px blieben auf dem Telefon gleich
   gross, waehrend die Spalte auf Fensterbreite schrumpfte, und das Zeichen
   nahm dort fast die ganze Breite ein.

   `clamp` statt reiner Prozente: nach unten gedeckelt, damit es auf sehr
   schmalen Geraeten nicht unleserlich klein wird, nach oben, damit es auf
   grossen Fenstern nicht aufblaeht. */
.fuss-logo {
  width: clamp(84px, 24%, 150px);
  margin-bottom: 1.25rem;
}

.fuss p, .fuss li { color: var(--tinte-leise); font-size: var(--t-klein); }
.fuss a:hover { color: var(--akzent-text); }

/* Impressum und Datenschutz stehen nebeneinander unter dem Text, in der
   Akzentfarbe — keine eigene Spalte mit Ueberschrift. */
.fuss-recht {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: 1.25rem;
}
.fuss-recht a { color: var(--akzent-text); }

.fuss-anfahrt h2 {
  font-size: var(--t-klein);
  letter-spacing: 0.08em;
  margin-bottom: 1rem;
  color: var(--akzent-text);
}

/* Symbole ohne Rahmen, in der Akzentfarbe. */
.fuss-social { display: flex; gap: 0.75rem; margin: 1.25rem 0; }
.fuss-social a { color: var(--akzent-text); }
.fuss-social a:hover { color: var(--tinte); }

.clubinio { display: inline-block; }
.clubinio img { height: 38px; width: auto; }

/* ------------------------------------------------------------- Bewegung -- */

/* **Alles haengt an `html.anim`.** Diese Klasse setzt `assets/js/anim.js`,
   und zwar nur, wenn das Modul wirklich laeuft und `prefers-reduced-motion`
   nicht gesetzt ist. Faellt das Skript aus, bleibt die Klasse weg — und
   damit auch jede Regel, die etwas unsichtbar macht. Die Seite steht dann
   vollstaendig da, nur ohne Bewegung.

   Bewegt wird ausschliesslich `transform` und `opacity`. Beides laeuft im
   Compositor; alles andere (Hoehe, Position, Filter) erzwingt eine
   Neuberechnung des Layouts und ruckelt auf dem Telefon. */

html.anim [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.55s ease, transform 0.75s var(--kurve);
}
html.anim [data-reveal][data-sichtbar='ja'] {
  opacity: 1;
  transform: none;
}

/* Karten laufen versetzt ein, statt als Block aufzutauchen. Die
   Verzoegerung steht je Position im CSS, weil ein Inline-Style unter
   `style-src 'self'` nicht erlaubt waere. */
html.anim .karten [data-reveal]:nth-child(2) { transition-delay: 0.09s; }
html.anim .karten [data-reveal]:nth-child(3) { transition-delay: 0.18s; }
html.anim .karten [data-reveal]:nth-child(4) { transition-delay: 0.27s; }
html.anim .karten [data-reveal]:nth-child(5) { transition-delay: 0.36s; }
html.anim .karten [data-reveal]:nth-child(6) { transition-delay: 0.45s; }

/* Der Flyer zieht beim Darueberfahren leicht an. Die Karte selbst hebt
   schon ab — zusammen wirkt es, als laege das Bild tiefer in der Karte. */
.karte-bild { overflow: hidden; }
.karte-bild img { transition: transform 0.55s var(--kurve); }
.karte:hover .karte-bild img { transform: scale(1.05); }

/* Der Hero laeuft beim Laden auf: Logo, Titel, Knopf nacheinander. Kein
   Scroll-Ausloeser noetig — er steht ohnehin sofort im Bild. */
@keyframes hero-auf {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}
html.anim .hero-logo,
html.anim .hero-titel,
html.anim .hero-text .knopf {
  animation: hero-auf 0.9s var(--kurve) both;
}
html.anim .hero-logo        { animation-delay: 0.08s; }
html.anim .hero-titel       { animation-delay: 0.22s; }
html.anim .hero-text .knopf { animation-delay: 0.40s; }

/* ---------------------------------------------------------------- Fehler -- */

.fehlerseite {
  min-height: 70svh;
  display: grid;
  place-items: center;
  text-align: center;
  padding-block: 4rem;
}
.fehlerseite .kennzahl {
  font-size: clamp(5rem, 18vw, 10rem);
  font-weight: 800;
  line-height: 1;
  color: var(--akzent-text);
}
/* Der Knopf unter einem Kartenblock steht mittig und mit Abstand — ohne
   das klebt er linksbuendig an der Unterkante der ersten Karte.

   **Ausdrueckliche Kennzeichnung im Markup, nicht ueber die Struktur.** An
   der Abschnitts-ID zu haengen war falsch (die heisst je Projekt anders),
   aber `.abschnitt > .huelle > .knopf-reihe` war zu weit: Auf den
   Eventseiten stehen die Knopfreihen in derselben Struktur und bekamen
   dadurch 44 Pixel Abstand nach oben — zwischen Ticket- und U18-Reihe klaffte
   eine Luecke, und das negative Mass an `.knopf-reihe-u18` war ueberschrieben. */
.knopf-reihe[data-mitte] {
  justify-content: center;
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
}
