/* ============================================================================
   OVERDRIVE — Design und Layout
   ----------------------------------------------------------------------------
   Übernahme von shop-overdrive.de (WordPress + Elementor) auf den
   Clubinio-Stack. Gerüst vom System (Vorlage baggi-hp, Hero, Eventkarte und
   Fuß aus dem Systemkanon cosmopolar/top10-singen), Marke vom Original:
   Farben, Schriften und Größen sind an der laufenden Seite gemessen
   (referenz/), nicht aus dem Elementor-Kit abgeschrieben.

   Schwarzer Grund, weiße Schrift, Microgramma in Versalien für alles, was
   laut ist, Inter für den Fließtext, ein Rot (#f3150f). Durchgehend
   scharfe Ecken.

   Keine Inline-Styles. Die Content-Security-Policy führt 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**, zusammen 84 KB.

   Microgramma trägt alles in Versalien — Überschriften, Knöpfe, Menü.
   **Es gibt nur den Schnitt Bold (700).** Das Original fordert 900 an;
   der Browser nimmt dann die 700er Datei, ohne künstlich zu verfetten
   (er verfettet nur, wenn gar kein fetter Schnitt da ist). Deshalb steht
   hier 700 und in den Regeln 900 — gemessen wird das über die Textbreite,
   nicht über den Zahlenwert (Phase E).

   Inter trägt den Fließtext, eine variable Datei für alle Gewichte.
   Vom Betreiber gewählt (31.10.); das Original setzt Titillium Web.

   **Lizenz:** Inter steht unter der SIL OFL. Microgramma ist eine
   kommerzielle Schrift; die Datei liegt auf der bestehenden Seite des
   Betreibers und zieht mit ihr auf dieselbe Domain um. Siehe
   assets/fonts/LIZENZEN.md.

   **Beide Dateien, die über der Falz stehen, werden vorgeladen**
   (Inter, Microgramma). Wer die Familien tauscht, muss die
   `<link rel="preload">` in allen Seiten **und** in `tools/build.py`
   mitziehen. */
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Microgramma';
  src: url('../fonts/microgramma-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

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

:root {
  /* Flächen. Gemessen auf shop-overdrive.de; das Elementor-Kit führt
     dieselben Werte (#0C0C0C, #161616, #202020). */
  /* Seitengrund **reines Schwarz** — gemessen am body des Originals.
     Kopf, Fuß und Eventkarten heben sich mit #0c0c0c kaum merklich ab;
     das ist der Charakter der Seite, nicht ein Messfehler. */
  --nacht:        #000000;   /* Seitengrund */
  --box:          #161616;   /* Kästen */
  --box-hell:     #202020;   /* abgesetzte Fläche in einer Box */
  --flaeche:      #0c0c0c;   /* Abschnittsgrund, wo er sich abheben soll */
  /* Eventkarten. **#161616 statt der gemessenen #0c0c0c:** Die Karte hat
     jetzt die Form von cosmopolar (Betreiber, 31.10.) — gerundet, gestanzt,
     mit Schatten. Auf reinem Schwarz verschwand #0c0c0c samt Kerben; das
     Kastengrau der Marke setzt sie so weit ab wie dort #181818 auf #0b0b0e. */
  --karte:        #161616;
  --kopf:         #0c0c0c;   /* Kopfzeile und Fuß — gemessen */
  --linie:        #2a2a2a;   /* Trenner und Rahmen */

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

  /* Schrift. */
  --tinte:        #ffffff;
  /* Das Original setzt Fließtext durchgehend in reinem Weiß, auch dort,
     wo die Vorlage abstuft. Nur die Fußnote „zzgl. Systemgebühr" ist
     gedämpft: 47 % Weiß, auf Schwarz #878787. */
  --tinte-leise:  #ffffff;
  --tinte-still:  #878787;
  /* Dieselbe Tinte als Zahlentripel. Getoente Flaechen — der graue
     Zweitknopf, Eingabefelder — mischen sich daraus mit Alpha, statt
     festes Weiss zu nennen. Dieselbe Rolle wie in top10-balingen-hp. */
  --tinte-rgb:    255 255 255;

  /* Akzent der Marke. */
  /* **Zwei Rottöne im Bestand, eine Stufe auseinander.** Clubinio führt
     `#f3140f`, das Elementor-Kit und jede gemessene Fläche `#f3150f`. Hier
     gilt der gemessene Wert, weil er das ist, was ein Gast sieht. */
  --akzent:       #f3150f;
  --akzent-tinte: #ffffff;
  /* **Fläche unter weißer Schrift: eine Spur dunkler.** Weiß auf #f3150f
     misst 4,26:1 — unter den 4,5:1, die WCAG AA für die 15px-Knopfschrift
     und das 11px-„Read more" verlangt. Das Original hat denselben Wert.
     Gleicher Farbton, 7 Stufen dunkler: 4,51:1. Entscheidung des
     Betreibers (31.10.). Nur Knöpfe und Flächen mit weißem Zeichen darauf;
     Schrift, Linien und Symbole bleiben #f3150f. */
  --akzent-flaeche: #ec120c;
  /* Derselbe Akzent als Zahlentripel, für Verläufe und Fokusringe mit
     Alpha. */
  --akzent-rgb:   243 21 15;
  /* Akzent als Schriftfarbe. **Hier derselbe Wert wie die Fläche:**
     `#f3150f` auf Schwarz misst 4,94:1, auf dem Fuß (#0c0c0c) 4,60:1 —
     beides über den 4,5:1 für Fließtext. Die Vorlage brauchte an dieser
     Stelle einen angehobenen Ton; dieses Rot nicht. */
  --akzent-text:  #f3150f;
  /* **Akzent als Schrift auf der Eventkarte** (#161616). Dort misst
     #f3150f nur 4,24:1. Gleicher Farbton, 4 Stufen heller: 4,53:1.
     Nötig, seit die Karte die Form von cosmopolar (Betreiber, 31.10.)
     trägt und ihre Fläche heller wurde. */
  --akzent-text-karte: #f42d27;

  /* Rundungen. Gestaffelt nach Flaechengroesse — ein einheitlicher Radius
     laesst kleine Elemente verspielt und grosse Flaechen hart wirken. */
  /* **Scharfe Ecken, durchgehend.** Die bestehende Seite setzt ueberall
     `border-radius: 0` — Knoepfe, Eventkarten, Eingabefelder. Das ist kein
     Versehen, sondern der Charakter der Marke: kantig statt freundlich.
     Die Token bleiben trotzdem stehen, damit eine spaetere Rundung an
     einer Stelle entschieden wird und nicht an fuenfzig. */
  --r-knopf:      0;
  --r-feld:       0;
  --r-karte:      0;
  --r-klein:      0;
  /* **Ausnahme: die Eventkarte.** Ihre Form kommt von
     cosmopolar (Betreiber, 31.10.), und dort ist die Rundung Teil der Eintrittskarte. */
  --r-eventkarte: 18px;
  /* 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.
     Hier **keiner**: Das Original legt das Bild unverdunkelt hinter
     „Upcoming" (Elementor-Overlay transparent). */
  --bild-schleier: 0%;

  /* Erfolgsmeldung der Formulare. Grün, nicht im Akzent — das Rot wäre
     vom Fehlerfall nicht zu unterscheiden. Weiß darauf 5,13:1.
     (Hieß in der Vorlage `--gruen-partner` und fiel mit deren
     Business-Farben weg, obwohl die Rückmeldung es weiter brauchte.) */
  --erfolg:       #2e7d32;

  /* Weißes Leuchten um die großen Überschriften — Hero, Seitenkopf,
     Abschnittsköpfe. Wert aus dem Elementor-CSS der bestehenden Seite. */
  --leuchten:     0 0 10px rgb(255 255 255 / 86%);

  /* 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. */
  /* Gegenstueck zum Haken, fuer die Fehlermeldung. */
  --ausruf: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23ffffff' d='M7 2h2v7H7zM7 11h2v2H7z'/%3E%3C/svg%3E");
  --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. */
  /* **Gemessen, nicht übernommen.** Die linke Inhaltskante liegt im
     Original bei 115px (1440er Fenster) und 20px (390er). Mit dem Gutter
     unten ergibt das eine Hülle von 1274px: (1440 − 1274) / 2 + 32 = 115. */
  --breite:       1274px;
  --breite-schmal: 760px;
  /* Seitenrand: 32px ab 1025px, 38px auf dem Tablet, 20px am Telefon —
     gemessen (Logo und Fuß bei x = 115 / 38 / 20). Stufen wie die Schrift,
     siehe unten. */
  --gutter:       32px;
  /* Höhe der Kopfzeile. Hero, Bannerversatz, Menü und Ankersprung
     rechnen damit — weicht der Wert von der tatsächlichen Höhe ab,
     verschiebt sich der Inhalt um die Differenz.
     **Kopf und Menü in der Form von cosmopolar (Betreiber, 31.10.):**
     82px, unter 900px 80px (siehe Menü). Die gemessenen 100/85/65px des
     Originals gelten nicht mehr. */
  --kopf-hoehe:   82px;

  /* Typografie. **In Stufen, nicht fließend.** Das Original schaltet an
     den Elementor-Grenzen 767px und 1024px um; ein clamp() träfe die
     gemessenen Werte nur an einer Stelle. Werte für ≥ 1025px hier, die
     Stufen darunter am Ende dieses Abschnitts.
     Gemessen (390 / 768 / 1440):
       Hero 36 / 60 / 66 · Seitenkopf 35 / 55 / 55 · Abschnitt 40 / 50 / 50
       Über-Überschrift 36 / 50 / 50 · Kartentitel 25 · Fließtext 15
       Fußtext 14 / 14 / 16 · Fußverweise 11 / 15 / 15 */
  --t-hero:   4.125rem;     /* 66px */
  --t-h1:     3.4375rem;    /* 55px */
  --t-h2:     3.125rem;     /* 50px */
  --t-h2-text: 3.125rem;    /* 50px — Über-Überschrift */
  --t-h3:     1.5625rem;    /* 25px — Kartentitel */
  --t-text:   0.9375rem;    /* 15px */
  --t-klein:  0.875rem;
  --t-fuss:   1rem;         /* 16px */
  --t-fuss-recht: 0.9375rem;
}

@media (max-width: 1024px) {
  :root {
    --gutter:     38px;
    --t-hero:     3.75rem;  /* 60px */
    --t-fuss:     0.875rem; /* 14px */
  }
}

@media (max-width: 767px) {
  :root {
    --gutter:     20px;
    --t-hero:     2.25rem;  /* 36px */
    --t-h1:       2.1875rem;/* 35px */
    --t-h2:       2.5rem;   /* 40px */
    --t-h2-text:  2.25rem;  /* 36px */
    --t-fuss-recht: 0.6875rem; /* 11px */
  }
}

/* --------------------------------------------------------------- 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);
  /* 22,5px auf 15px — gemessen. */
  line-height: 1.5;
  -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);
  /* 900 angefordert wie im Original; geladen ist nur der 700er Schnitt
     (siehe @font-face). Gemessen wird das über die Textbreite. */
  font-weight: 900;
  /* Zeilenhöhe = Schriftgröße, keine Sperrung — gemessen an allen
     Überschriften des Originals (66/66, 50/50, 55/55). */
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: normal;
}

/* **Kurze, laute Zeilen tragen die Displayschrift** (Microgramma), nicht
   nur h1 bis h4: die Datumszeile der Eventseite, die Beschriftung im
   Infokasten, die FAQ-Frage, der Zurück-Verweis, die Kennzahl der
   Fehlerseite, der Sprunglink. Die Werte im Infokasten (`dd`) bleiben in
   der Textschrift — das sind ganze Wörter, keine Etiketten. */
.event-datum,
.infokasten dt,
.faq summary,
.zurueck,
.fehlerseite .kennzahl,
.sprung {
  font-family: var(--schrift-display);
}

/* Gegenstueck dazu: Der Infokasten erbt seine Schrift sonst vom Etikett
   darueber, sobald jemand die Liste oben wieder ergaenzt. */
.infokasten dd { font-family: var(--schrift-text); }

/* 20px zwischen Absaetzen — gemessen. Die Vorlage fuhr 16px; bei drei
   Absaetzen untereinander summiert sich das sichtbar. */
p { margin: 0 0 1.25rem; }
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-flaeche);
  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);
}

/* 80px oben und unten — gemessen am Über-Abschnitt. Das Original setzt
   je Abschnitt eigene Werte; die Abweichungen stehen als Varianten unten,
   nicht als Seitenregeln. */
.abschnitt { padding-block: 80px; }

/* Erster Abschnitt unter dem Seitenkopf: schließt an, unten ohne Polster.
   **Stand in der Vorlage im Abschnitt „Jobs"** und ging beim benannten
   Löschen dieses Abschnitts mit verloren — samt der Korrektur darunter
   (baggi-hp 3b79591). Hier ins Raster zurückgeholt, wo es hingehört. */
/* 35px unter dem Seitenkopf — gemessen auf /events/ und /kontakt/. */
.abschnitt-oben { padding-block: 35px 0; }

/* Variante: Formularseite — endet 35px unter dem Absendeknopf, gemessen
   auf /kontakt/. */
.abschnitt-oben.abschnitt--formular:last-of-type { padding-bottom: 35px; }

/* Variante: 50px statt 80px — die Rechtsseiten, gemessen. */
.abschnitt--knapp { padding-block: 50px; }

/* **Als letzter Abschnitt braucht er sein Polster zurück** — sonst stößt
   der Inhalt an die Fußkante (baggi-hp 3b79591, /kontakt/ und /events/).
   Zielgenau auf diese Klasse, nicht auf `section:last-of-type`: Die
   allgemeine Regel hätte alle anderen Seiten mit verändert.
   80px — gemessen auf /events/ (Karten bis Fuß). */
.abschnitt-oben:last-of-type { padding-bottom: 80px; }

/* 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;
  /* 110px oben, 100px unten — gemessen. */
  padding-block: 110px 100px;
  /* Dasselbe Foto wie der Seitenkopf der Unterseiten — eine Datei, drei
     Verwendungen. */
  background: url('../img/banner/seitenkopf.webp') center center / cover no-repeat;
  isolation: isolate;
}
/* Ab 1025px schwarz statt Bild — so im Original (Elementor setzt dort
   einen Verlauf #000 → #000 über das Hintergrundbild). */
@media (min-width: 1025px) {
  .abschnitt-bild { background: linear-gradient(var(--nacht), var(--nacht)); }
}
.abschnitt-bild::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(0 0 0 / var(--bild-schleier));
}

/* Abschnittskopf: Ueberschrift plus Unterzeile, zentriert. */
/* 35px bis zu den Karten, am Telefon 40px — gemessen. */
.kopfzeile { text-align: center; margin-bottom: 35px; }
@media (max-width: 767px) { .kopfzeile { margin-bottom: 40px; } }
.kopfzeile h2 { font-size: var(--t-h2); line-height: 1; text-shadow: var(--leuchten); }
.kopfzeile p {
  margin: 0.75rem 0 0;
  color: var(--tinte-leise);
  text-transform: none;
}
/* Die Unterzeilen unter „Next Events" und „Einblick" stehen im Original in
   der Akzentfarbe, nicht gedaempft. */
.kopfzeile .unterzeile { color: var(--akzent-text); font-weight: 400; }

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

.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Pfeil 15px + 5px Abstand = 20px — gemessen (205 − 137 Text − 48 Polster). */
  gap: 5px;
  /* 12px/24px Polster, Zeilenhöhe 15px, **kein Rahmen** — alles gemessen.
     Zusammen ergibt das die 39px Höhe des Originals.

     Die beiden helleren Varianten unten brauchen trotzdem eine Kante. Die
     bekommen sie als `box-shadow: inset` statt als `border` — ein Rahmen
     wuerde sie wieder hoeher machen als den gefuellten Knopf daneben, und
     dann stehen zwei Knoepfe einer Reihe nicht mehr auf einer Linie. */
  padding: 0.75rem 1.5rem;
  border: 0;
  border-radius: var(--r-knopf);
  background: var(--akzent-flaeche);
  color: var(--akzent-tinte);
  font: inherit;
  font-family: var(--schrift-display);
  /* **Nach `font: inherit`, nicht davor.** Die Kurzschreibweise setzt
     `line-height` mit zurück — davor notiert, erbte der Knopf die
     Zeilenhöhe des Fließtexts. */
  font-size: 0.9375rem;      /* 15px — gemessen */
  line-height: 15px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: normal;
  cursor: pointer;
  transition: transform 0.25s var(--kurve), box-shadow 0.25s var(--kurve),
              background 0.2s ease, color 0.2s ease;
}
/* **Beim Ueberfahren nur abdunkeln, nicht entleeren.**

   Die Vorlage nimmt dem Knopf die Fuellung und laesst einen Umriss
   stehen. Auf dieser durchgehend dunklen Seite heisst das: Aus einem
   roten Knopf wird fast-schwarz mit duennem Rand — der Betreiber hat es
   als „grau auf grau" beschrieben, und das trifft es.

   Die bestehende Seite setzt `hover:bg-accent/90`, dunkelt also
   dieselbe Farbe leicht ab. `filter: brightness(0.9)` macht genau das
   und gilt zugleich fuer alle Spielarten — rot, gruen, weiss —, ohne
   dass jede ihren eigenen Hoverwert braucht.

   Die beiden helleren Varianten bringen ihre eigenen Regeln mit: Auf
   einer fast durchsichtigen Flaeche richtet Abdunkeln nichts aus. */
.knopf:hover {
  filter: brightness(0.9);
  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. */
/* **Deckend, nicht durchscheinend.** Gemessen am Lounge-Knopf der
   bestehenden Eventseite: `#1e1e1e` als volle Flaeche, Rahmen in
   derselben Farbe. Eine Flaeche aus 10 % Weiss nimmt die Farbe dessen
   an, was dahinter liegt — auf einem Flyerbild sah derselbe Knopf anders
   aus als auf dem Seitengrund.

   Die Kante kommt als `box-shadow: inset`, nicht als `border` — sonst
   waeren diese Knoepfe 3px hoeher als der gefuellte daneben. Siehe
   `.knopf`. */
.knopf-leer {
  background: #1e1e1e;
  color: var(--tinte);
  box-shadow: inset 0 0 0 1px rgb(var(--tinte-rgb) / 12%);
}
.knopf-leer:hover {
  filter: none;
  background: #2a2a2a;
  color: var(--tinte);
  box-shadow: inset 0 0 0 1px rgb(var(--tinte-rgb) / 24%);
}

/* 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);
  box-shadow: inset 0 0 0 1px rgb(var(--tinte-rgb) / 28%);
}
.knopf-umriss:hover {
  filter: none;
  background: rgb(var(--tinte-rgb) / 7%);
  color: var(--tinte);
  box-shadow: inset 0 0 0 1px rgb(var(--tinte-rgb) / 45%);
}

/* Knopf mit eigenem Symbol davor — dann entfaellt der Pfeil dahinter.
   Beides zusammen waere ein Knopf mit zwei Zeichen fuer eine Handlung. */
.knopf-ohne-pfeil::after { content: none; }

/* **Der Ticketknopf ist der einzige mit Rundung.**

   Gemessen auf der Eventseite der bestehenden Seite: volle Spaltenbreite,
   16px Polster oben und unten (52px hoch), `rounded-lg` = 8px, Sperrung
   0,1em. Die Klasse stand bisher im Markup, ohne dass irgendeine Regel
   daran hing — `tools/build.py` setzt sie seit jeher, das Stylesheet
   kannte sie nicht. */
.knopf-ticket {
  width: 100%;
  padding-block: 1rem;
  /* Scharfkantig wie jeder Knopf hier — die 8px stammten aus baggi-hp. */
  border-radius: var(--r-knopf);
  letter-spacing: 0.1em;
}

.knopf[disabled] { opacity: 0.5; cursor: not-allowed; }
.knopf[disabled]:hover { filter: none; background: var(--akzent-flaeche); 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 --- */

/* **Kopfzeile in der Form von cosmopolar (Betreiber, 31.10.).**

   Über dem Hero und den Bannern steht sie durchsichtig im Bild; sobald
   gescrollt wird, bekommt sie einen Grund — darunter liegen Text und
   Karten, und ohne Grund stünde die Schrift mitten darin. Das Original
   (shop-overdrive.de) setzte eine von Anfang an deckende Leiste; das gilt
   nicht mehr.

   `sticky` statt `fixed`: Die Zeile belegt ihren Platz im Fluss. Hero und
   Seitenkopf ziehen sich mit negativem Rand darunter (siehe dort); Seiten
   ohne Banner beginnen ganz normal unter ihr.

   **Nur die Farbe ändert sich, nicht die Höhe.** Eine klebende Zeile
   belegt weiterhin ihren Platz im Fluss; änderte sich dabei die Höhe,
   ruckte der gesamte Inhalt darunter. */
.kopf {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  isolation: isolate;
  transition: background 0.25s ease;
}
.kopf[data-fest='ja'] {
  background: rgb(12 12 12 / 92%);   /* --kopf mit Deckung */
  -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 — aber nur im gescrollten
   Zustand, weil `data-fest` erst dort gesetzt wird. */
.kopf[data-offen='ja'] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Oben mehr Luft als unten: Frei im Bild rückt die Zeile vom Fensterrand
   weg, statt sich mit einer Fläche abzusetzen. Gescrollt sitzt sie mittig
   in der Leiste — auf einem Grund wirkte die Asymmetrie wie ein Fehler.

   **Die Summe bleibt gleich** (28+8 oben, 18+18 gescrollt — beides 36px),
   sonst ruckte der Inhalt beim Umschalten. 36px plus das höchste Kind
   (Logokasten 46px, am Telefon der 44px-Menüknopf) ergibt
   `--kopf-hoehe`: 82 / 80px. */
.kopf-innen {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.75rem;
  padding-bottom: 0.5rem;
  transition: padding 0.25s ease;
}
.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.

   **Mit `+ var(--gutter)`** — Marke und Inhalt stehen auf derselben
   Kante. Das Vorbild rückt die Marke um den Seitenrand nach außen; hier
   hat die Hülle den Rand schon eingerechnet (siehe `--breite`). */
.kopf-innen {
  max-width: none;
  padding-inline: max(var(--gutter),
                      calc((100% - var(--breite)) / 2 + var(--gutter)));
}

/* Der Logokasten ist 46px hoch wie bei cosmopolar — er bestimmt die
   Kopfhöhe. Die Wortmarke darin kleiner: OVERDRIVE ist 5,6-mal so breit
   wie hoch, mit 46px stünde sie 260px breit in der Zeile. */
.logo { display: flex; align-items: center; height: 46px; }
.logo img { height: 34px; width: auto; }
@media (max-width: 899px) {
  .logo img { height: 26px; }
}

.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); }

/* **Menü in der Form von cosmopolar (Betreiber, 31.10.):** ohne
   Trennstriche, Abstand zwischen den Punkten statt Polster in ihnen, der
   aktive Punkt nur eingefärbt. */
.menu ul {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 1.75rem);
  margin: 0; padding: 0;
  list-style: none;
}
@media (min-width: 900px) {
  .menu li { display: flex; align-items: center; }
}

/* **`.menu ul a`, nicht `.menu a`.**

   Der Menuefuss mit den Social-Symbolen liegt im Markup innerhalb von
   `.menu`. Mit dem weiteren Selektor bekamen auch seine Verweise das
   Polster der Menuepunkte — und weil die Symbolkreise 40px breit sind,
   lief das 20px-Symbol ueber und sass 6 Pixel zu weit rechts. */
.menu ul 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 ul a:hover { color: var(--akzent-text); }
.menu ul 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) {
  /* Menügrenze und Kopfhöhe wie bei cosmopolar: unter 900px das
     Vollbildmenü, die Zeile dann 80px (Menüknopf 44 + 36). Vorher 767px
     nach dem Original. */
  :root { --kopf-hoehe: 80px; }

  /* Solange das Menue offen ist, muss die Kopfzeile decken. Ueber dem Hero
     ist sie 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 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. */
  /* Enger gesetzt (Betreiber, 31.10.): vorher 24px Lücke plus
     Zeilenhöhe 1,5, zusammen fast 80px je Punkt. Jetzt 44px am Telefon —
     genau die Mindestfläche für den Finger, das Polster sitzt im Verweis. */
  .menu ul {
    flex-direction: column;
    align-items: center;
    gap: 0;
  }
  .menu li { justify-content: center; }
  .menu ul a {
    display: block;
    font-size: clamp(1.75rem, 7vw, 2.25rem);
    line-height: 1.15;
    padding-block: 0.375rem;
    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. */
  /* **Form von cosmopolar (Betreiber, 31.10.):** mit dem Fenster
     wachsend und unter die durchsichtige Kopfzeile gezogen. Vorher 700px
     fest unter einer deckenden Leiste, wie im Original. */
  height: clamp(500px, 71svh, 790px);
  margin-top: calc(var(--kopf-hoehe) * -1);
  display: grid;
  place-items: center;
  overflow: hidden;
  /* Standbild hinter dem Video, wie im Original (dort quer-1-1.webp als
     Hintergrund des Containers). Steht, bis das Video läuft — und bleibt,
     wenn es nicht geladen wird. */
  background: url('../img/banner/seitenkopf.webp') center / cover no-repeat;
  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 wie bei cosmopolar: oben dunkler, damit die Kopfzeile trägt,
   unten am dunkelsten, damit der Hero in den schwarzen Abschnitt darunter
   übergeht. (Das Original legte keinen.) */
.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;
  /* 80 % der Breite ab 768px, darunter volle Breite mit 10px Rand —
     Elementor `content-width: 80%`, gemessen. */
  width: 80%;
  max-width: none;
  padding-inline: 0;
  /* Der Hero beginnt unter der Kopfzeile — der Text soll trotzdem in der
     sichtbaren Fläche mittig stehen. */
  padding-top: var(--kopf-hoehe);
}
@media (max-width: 767px) {
  .hero-text { width: 100%; padding-inline: 10px; }
}

/* 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: normal;
  text-shadow: var(--leuchten);
}
.hero-titel span { display: block; }

/* Knapper als die uebrigen Knoepfe, wie bei cosmopolar — 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;
  /* Eigene Inhaltsbreite: 1080px, zwei Spalten à 510 mit 60px Abstand —
     gemessen. Schmaler als die Hülle (1210); das Original setzt den
     Abschnitt enger als Kopf und Fuß. */
  max-width: 1080px;
  gap: 60px;
  align-items: center;
}
/* `minmax(0, 1fr)`, nicht `1fr`: Sonst zieht das längste Wort der 50px-
   Überschrift die Textspalte breiter (bei 768px 398 statt 324px). */
@media (min-width: 768px) {
  .ueber { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
/* Rand: keiner ab 1025px (1080 = Inhalt), darunter 30px — gemessen. Die
   Hülle bringt ihren eigenen Gutter mit; der wird hier ersetzt. */
.ueber { padding-inline: 0; }
@media (max-width: 1024px) {
  .ueber { padding-inline: 30px; }
}

/* Rotes Logo über der Überschrift, 148px breit (155px am Telefon).
   **Auf dem Tablet ausgeblendet** — so im Original (Elementor-Schalter
   „auf Tablet verbergen"), nachgemessen bei 768px. */
.ueber-logo { width: 148px; margin-bottom: 1.25rem; }
@media (max-width: 767px) { .ueber-logo { width: 155px; } }
@media (min-width: 768px) and (max-width: 1024px) { .ueber-logo { display: none; } }

.ueber-text h2 {
  font-size: var(--t-h2-text);
  text-shadow: var(--leuchten);
  margin-bottom: 1.25rem;    /* 20px — gemessen */
}
/* Absätze mit 15px Abstand, Knopf 19px darunter — gemessen. */
.ueber-text p { margin: 0 0 15px; color: var(--tinte-leise); }
/* Kein Blocksatz, obwohl das Original ihn setzt: Auf schmalen Spalten
   reißt er Löcher zwischen die Wörter (in der Vorlage bis zu 45px am
   Telefon). Entscheidung im Bericht vorgelegt. */
.ueber-text .knopf-reihe { margin-top: 19px; }

/* Der Knopf bleibt links, auch einspaltig — gemessen (x = 30 bei 390px). */

/* --------------------------------------------------------------- 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));
}
/* Ab Tablet abwärts eine Spalte, **höchstens 400px breit und mittig** —
   gemessen: 400px bei 768, volle Breite bei 390. */
/* **Variante: die Eventliste.** Auf /events/ ist das Raster schmaler als
   auf der Startseite — 3 × 367 + 2 × 20 = 1141px ab x = 150 —, am Telefon
   dagegen breiter (10px Rand statt 20), und der Kartentitel misst dort
   24 statt 25px. Gemessen; das Original setzt beide Raster getrennt.
   (Die eigene Kartenfläche #111 der Liste entfiel mit der neuen Kartenform —
   beide Raster tragen jetzt `--karte`.) */
@media (min-width: 1025px) {
  .karten.karten--liste { max-width: 1141px; }
}
@media (max-width: 767px) {
  .karten.karten--liste { margin-inline: -10px; grid-template-columns: minmax(0, 1fr); }
  .karten--liste .karte-titel { font-size: 1.5rem; }
}

/* 3 × 387 + 2 × 20 = 1201px, mittig — gemessen. Schmaler als die Hülle. */
@media (min-width: 1025px) {
  .karten { max-width: 1201px; margin-inline: auto; }
}
@media (max-width: 1024px) {
  .karten { grid-template-columns: minmax(0, 400px); justify-content: center; }
}

/* **Form von cosmopolar (Betreiber, 31.10.):** eine Eintrittskarte —
   gerundet, mit Schatten, unten ein Abriss hinter einer Perforation mit
   zwei Kerben. Das Original (shop-overdrive.de) setzte eine schlichte,
   scharfkantige Fläche; Inhalt und Belegung bleiben die von OVERDRIVE
   (Ort, Preis, „Read more"), siehe cards.js.

   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 am Telefon
   auf einem Foto, dort staenden sie als dunkle Punkte. */
.karte {
  display: flex;
  flex-direction: column;
  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-eventkarte);
  /* 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;
}
.karte-titel {
  font-size: var(--t-h3);
  line-height: 1.2;
}
/* Ortszeile unter dem Titel, in der Akzentfarbe und versal. */
.karte-ort {
  margin: 0;
  color: var(--akzent-text-karte);
  font-size: var(--t-klein);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* **Einstiegspreis** — beim Vorbild nicht auf der Karte, hier Inhalt
   von OVERDRIVE. Er steht im Text, weil der Abriss Termin und Weg trägt.
   Fehlt ein kaufbares Ticket, entfällt die Zeile (siehe cards.js). */
.karte-preis {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 6px;
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 700;
}
.karte-preis small {
  font-size: 0.6875rem;
  font-weight: 400;
  color: var(--tinte-still);
}

/* Der Abschnitt unter der Perforation: 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;
  justify-content: space-between;
  gap: 0.5rem;
  height: var(--abriss);
  margin: 0;
  padding-inline: 0.9375rem;
  border-top: 2px dashed var(--linie);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.karte-termin { color: var(--tinte-still); white-space: nowrap; }
/* „Read more" als Schrift in der Akzentfarbe, nicht als Fläche — die
   Karte ist als Ganzes ein Link, ein Knopf darin waere fuer Lesegeraete
   ein doppelter Eintrag. Der Pfeil rueckt beim Darueberfahren weiter. */
.karte-infos {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--akzent-text-karte);
  white-space: nowrap;
  transition: gap 0.22s var(--kurve);
}
.karte:hover .karte-infos { gap: 0.6rem; }

/* Monatsueberschrift der Eventliste. */
/* Zentriert und weiss, ohne Trennlinie — wie im Original. */
.monat {
  /* Bis 32px. `--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. */
/* Die Über-uns-Strecke zeigt Hochformate 4:5 (Quellen 1080×1350), Folien
   ohne Zwischenraum — gemessen: 510×638, Abstand von Folie zu Folie genau
   510px. */
#ueber .slider-band img { aspect-ratio: 4 / 5; }
#ueber .slider-band > figure { padding-inline: 0; }
/* Ohne Platzhaltergrund: Das Original zeigt keinen, und die Fläche hinter
   einem geladenen Bild sieht ohnehin niemand. */
#ueber .slider-band img { background: none; }
/* Punktreihe 28px unter dem Bild — gemessen über die Mitte der Textspalte,
   die das Raster an der Höhe von Bild plus Punkten ausrichtet. */
#ueber .slider-punkte { margin-top: 28px; }

.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; }

/* ------------------------------------------------------- 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;
}
/* **Verlauf statt gleichmaessigem Schleier.**

   Ein flacher Schleier liess das Foto oben noch kraeftig durchschlagen und
   endete unten mit einer sichtbaren Kante zum Abschnitt darunter. Das
   Original legt stattdessen einen Verlauf aus dem Seitengrund darueber, der
   nach unten in volle Deckung laeuft: Der Banner geht in die Seite ueber,
   statt an ihr abzubrechen.

   Hier gleichmäßig, wie bei cosmopolar mit 58 % (Betreiber,
   31.10.). Das Original legte 77 % darüber — das Bild war kaum zu sehen. */
.seitenkopf-bild::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(0 0 0 / 58%);
}
/* Ein Motiv für alle Unterseiten, wie im Original (quer-1-1.webp). Die
   Zuordnung je `data-banner` bleibt, damit eine Seite ein eigenes Bild
   bekommen kann, ohne das Markup anzufassen. */
.seitenkopf-bild[data-banner='events'],
.seitenkopf-bild[data-banner='kontakt'] { background-image: url('../img/banner/seitenkopf.webp'); }

.seitenkopf {
  /* Hoehe waechst mit der Fensterbreite, statt auf dem Telefon als flacher
     Streifen dazustehen, durch den das Bild stark beschnitten wird. */
  /* **Form von cosmopolar (Betreiber, 31.10.).** Vorher 245 / 172px
     nach dem Original. */
  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 {
  line-height: 1;
  /* Eigene Skala wie bei cosmopolar: Die Ueberschrift steht allein auf
     einer grossen Flaeche. 13vw am Telefon — „DATENSCHUTZ" steht nicht
     in einem Banner, die laengsten Titel hier sind „KONTAKT" und „EVENTS". */
  font-size: clamp(3rem, 13vw, 4.5rem);
  text-shadow: var(--leuchten);
  overflow-wrap: anywhere;
}
.seitenkopf p {
  margin: 1rem auto 0;
  max-width: 54ch;
  color: var(--tinte-leise);
  text-transform: none;
}
/* Unterzeile rot, mit Abstand unter dem Titel — wie bei cosmopolar. */
.seitenkopf .unterzeile {
  color: var(--akzent-text);
  font-weight: 400;
  font-size: clamp(0.9375rem, 2.6vw, 1.125rem);
}

/* Auf dem Telefon ein festes Seitenverhaeltnis statt der Mindesthoehe —
   wie bei cosmopolar, wo es nachgemessen ist: 3:2 laesst bei 390px nach
   Abzug der Kopfzeile rund 180px fuer den Text, 16:9 nur 139. Eine
   Mindesthoehe bei schmaler Breite zwaenge `cover` zum Vergroessern. */
@media (max-width: 759px) {
  .seitenkopf-bild {
    min-height: 0;
    aspect-ratio: 3 / 2;
  }
}

/* ------------------------------------------------------------------ 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. */
  /* 672px — gemessen; die Vorlage fuehrt 640. */
  .kontakt-raster[data-ohne-faq='ja'] {
    grid-template-columns: minmax(0, 672px);
    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; }

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

/* 672px — gemessen, auf beiden Formularseiten gleich. Mittig in der
   Huelle, nicht ueber deren volle Breite. */
.form {
  display: grid;
  gap: 1.125rem;
  max-width: 672px;
  margin-inline: auto;
}

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

/* **`align-content: start` ist nicht kosmetisch.**

   Die Felder einer Reihe sind Rasterzellen und werden auf gleiche Hoehe
   gestreckt. Ohne diese Zeile wachsen die Zeilen darin mit — und weil
   das Altersfeld einen Hinweis darunter traegt (drei Zeilen) und das
   Namensfeld nicht (zwei), verteilte sich der Ueberschuss links auf
   Beschriftung und Eingabefeld: Das linke Feld war **60px hoch statt
   46** und begann 13px tiefer als das rechte.

   Mit `start` behalten die Zeilen ihre Inhaltshoehe, und der Ueberschuss
   bleibt unten stehen, wo er niemanden stoert. */
.feld {
  display: grid;
  gap: 0.5rem;
  align-content: start;
}
/* Systemwert der Feldbeschriftung (Versalien, 12px). Die Marke überschreibt
   ihn unten im Abschnitt „Marke: Formular". */
.feld > span {
  font-size: 0.75rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tinte);
}
/* Pflichtfelder tragen einen roten Stern — wie im Original. */
.feld-pflicht { color: var(--akzent-text); }

/* **Rahmen, Rundung und eine deckende Flaeche** — alles an der
   bestehenden Seite gemessen: `#212121` mit `1px solid #383838`, Radius
   8px, 12/16 Polster, 46px hoch. Die Vorlage faehrt rahmenlose, fast
   durchsichtige Felder; der Kommentar dazu stand hier noch und ist jetzt
   falsch, deshalb weg.

   Die 8px sind dieselbe Ausnahme wie beim Ticketknopf und den
   Bereichskacheln — `--r-feld` bleibt 0, sonst wandert die Rundung
   durchs ganze Projekt. */
input[type='text'], input[type='email'], input[type='tel'],
input[type='number'], input[type='file'], textarea, select {
  width: 100%;
  padding: 0.75rem 1rem;
  border: 1px solid #383838;
  border-radius: 8px;
  background: #212121;
  color: var(--tinte);
  font: inherit;
  /* **Nach `font: inherit`.** Die Kurzschreibweise setzt `line-height`
     zurueck — dieselbe Falle wie beim Knopf. 12+20+12 plus Rahmen ergibt
     die 46px des Originals; mit der geerbten Zeilenhoehe des Fliesstexts
     waren es 66. */
  line-height: 20px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
:is(input[type='text'], input[type='email'], input[type='tel'],
    input[type='number'], textarea, select):hover:not(:focus) {
  border-color: #4a4a4a;
}
textarea {
  min-height: 150px;
  resize: vertical;
  border-radius: 8px;
}
/* Fokus als schmaler Ring aussen. Er liegt ueber dem Rand, nicht darin,
   und verschiebt deshalb nichts. */
input:focus, textarea:focus, select:focus {
  outline: 0;
  border-color: var(--akzent);
  box-shadow: 0 0 0 2px rgb(var(--akzent-rgb) / 45%);
}
/* **Eigener Wert, nicht `--tinte-still`.** Die Eingabefelder haben jetzt
   einen helleren Grund (`#212121` statt fast durchsichtig); darauf
   erreicht das stille Grau nur 3,91:1. `#8a8a8a` traegt mit 4,66:1 und
   bleibt trotzdem erkennbar leiser als der eingegebene Text. */
::placeholder { color: #8a8a8a; opacity: 1; }

/* 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;
  border-radius: 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(255 255 255 / 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(255 255 255 / 16%);
}
input[type='file']:focus-visible::file-selector-button {
  outline: 2px solid var(--akzent);
  outline-offset: 2px;
}

/* 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: var(--r-klein);
  background: rgb(255 255 255 / 10%);
  cursor: pointer;
  transition: background 0.2s ease;
}
.auswahl label:hover input:not(:checked),
.zustimmung:hover input:not(:checked) { background: rgb(255 255 255 / 16%); }
.auswahl input:checked, .zustimmung input:checked {
  background: var(--haken) var(--akzent-flaeche) 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;
}

/* **Die Erfolgsmeldung war eine rote Textzeile.**

   Rot ist auf dieser Seite die Akzentfarbe — und zugleich die Farbe, in
   der jeder Fehler steht. Wer eine Bewerbung abgeschickt hatte, las
   „Danke! Wir haben deine Bewerbung" in derselben Farbe wie „Bitte
   stimme der Datenschutzerklaerung zu", in derselben Groesse, an
   derselben Stelle. Das ist im besten Fall uebersehbar und im
   schlechteren beunruhigend.

   Jetzt ein eigener Kasten mit Flaeche, Rahmen und Zeichen. Eine
   Einsendung ist der Moment, in dem jemand etwas aus der Hand gibt —
   dort gehoert die deutlichste Rueckmeldung der ganzen Seite hin, nicht
   die leiseste.

   Im Ruhezustand nimmt die Meldung keinen Platz ein: `min-height` auf
   einer leeren Zeile haette sonst dauerhaft eine Luecke ueber dem Knopf
   hinterlassen. */
.rueckmeldung {
  margin: 0;
  font-size: var(--t-klein);
}
.rueckmeldung:empty { display: none; }

.rueckmeldung[data-state='ok'],
.rueckmeldung[data-state='fehler'] {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.875rem;
  align-items: center;
  padding: 1.125rem 1.25rem;
  border-radius: 8px;
  font-size: 1rem;
  line-height: 1.5;
}
/* Das Zeichen als ::before, damit es nicht vorgelesen wird — der Text
   sagt bereits, was los ist. */
.rueckmeldung[data-state='ok']::before,
.rueckmeldung[data-state='fehler']::before {
  content: '';
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 15px 15px;
}

/* Gruen, nicht in der Akzentfarbe: Der Akzent ist hier rot und waere
   vom Fehlerfall nicht zu unterscheiden. #2e7d32 traegt weisse Schrift
   mit 5,13:1 (Token `--erfolg`). */
.rueckmeldung[data-state='ok'] {
  background: rgb(46 125 50 / 18%);
  box-shadow: inset 0 0 0 1px var(--erfolg);
  color: var(--tinte);
  font-weight: 500;
}
.rueckmeldung[data-state='ok']::before {
  background-color: var(--erfolg);
  background-image: var(--haken);
}

.rueckmeldung[data-state='fehler'] {
  background: rgb(204 32 38 / 16%);
  box-shadow: inset 0 0 0 1px var(--akzent);
  color: var(--tinte);
}
.rueckmeldung[data-state='fehler']::before {
  background-color: var(--akzent-flaeche);
  background-image: var(--ausruf);
}

.rueckmeldung[data-state='laeuft'] { color: var(--tinte-still); }

/* --- Marke: Formular von shop-overdrive.de ---------------------------------
   Werte am Original abgelesen (Kontaktformular, Elementor Pro). Die
   Systemregeln oben bleiben; hier stehen nur die Abweichungen der Marke. */

/* Spalte 550px ab 1025px; darunter volle Breite mit 10px Rand zum
   Fenster (748px bei 768, 370px bei 390) — also über die Hülle hinaus.
   Der Ticket-Hinweis steht 10px weiter innen. 35px zusätzlich über dem
   Hinweis: 70px unter dem Seitenkopf. Alles gemessen. */
.kontakt-raster[data-ohne-faq='ja'] { grid-template-columns: minmax(0, 550px); }
#kontaktformular { padding-top: 35px; }
#kontaktformular > :is(h2, p, .knopf-reihe) { margin-inline: 10px; }
@media (max-width: 1024px) {
  .kontakt-raster[data-ohne-faq='ja'] { grid-template-columns: minmax(0, 1fr); }
  #kontaktformular { margin-inline: calc(10px - var(--gutter)); }
}
#kontaktformular > h2 {
  margin-bottom: 20px;
  color: var(--akzent-text);
  font-size: 1.625rem;       /* 26px — gemessen */
  line-height: 1;
}
#kontaktformular > p { margin: 0 0 20px; }
/* 55px vom Hinweis bis zur ersten Beschriftung. */
#kontaktformular > .knopf-reihe { margin-bottom: 55px; }

/* 22px zwischen den Feldern, Beschriftung 15px mit 13px darunter. */
.form { max-width: none; gap: 22px; }
.feld { gap: 0; }
/* So breit wie ihr Text, nicht spaltenbreit — gemessen. */
.feld > span {
  justify-self: start;
  padding-bottom: 13px;
  font-size: var(--t-text);
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
}
/* Name und E-Mail auf 80 % — das Original setzt den Namen so; die
   E-Mail stand dort halb breit neben dem Telefon, das hier entfällt. */
.form .feld:has(> input[type='text'], > input[type='email']) { width: 80%; }
@media (max-width: 767px) {
  .form .feld:has(> input[type='text'], > input[type='email']) { width: 100%; }
}
input[type='text'], input[type='email'], input[type='tel'], textarea, select {
  /* 33px hoch: 21 Zeile + 2 × 5 Polster + 2 × 1 Rahmen — gemessen. */
  padding: 5px 12px;
  border: 1px solid #525252;
  border-radius: 2px;
  background: transparent;
  line-height: 21px;
}
textarea { min-height: 94px; height: 94px; border-radius: 2px; }
.zustimmung { font-size: var(--t-text); color: var(--tinte); }
/* Absendeknopf: volle Breite, 40px, Radius 3px — gemessen. */
.form .knopf-voll {
  width: 100%;
  height: 40px;
  padding-block: 0;
  border-radius: 3px;
}

/* ------------------------------------------------------------- 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;
}

/* **Untereinander, jeder ueber die volle Breite.**

   Die Vorlage legt Ticket- und Lounge-Knopf nebeneinander (`flex: 1 1
   260px`). Die bestehende Seite stapelt sie: beide 896 Pixel breit, der
   Lounge-Knopf unter dem Ticketknopf. Das ist auch die richtige
   Rangfolge — der zweite Knopf ist kein gleichwertiger Weg, sondern ein
   Zusatz fuer einen Teil der Gaeste, und nebeneinander lesen sie sich
   als Alternative. */
.event .knopf-reihe {
  flex-direction: column;
  margin-bottom: 2rem;
}
.event .knopf-reihe .knopf { width: 100%; }

/* 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: 700;
  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(255 255 255 / 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(255 255 255 / 5%);
  border: 1px solid rgb(255 255 255 / 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; }

/* 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 -- */

/* Rechtsseiten wie im Original: 1140px Spalte, Titel rot und links, kein
   Seitenkopf-Balken. Zwischenüberschriften in der Textschrift, fett —
   die erste Ebene unterstrichen (gemessen im Impressum). */
.rechtstext { max-width: calc(1140px + 2 * var(--gutter)); }
/* 20px Rand unter 1025px, auch auf dem Tablet — gemessen. */
@media (max-width: 1024px) { .rechtstext { padding-inline: 20px; } }
.rechtstext h1 {
  margin-bottom: 20px;
  font-weight: 600;          /* so angefordert; gerendert wie 900 (ein Schnitt) */
  color: var(--akzent-text);
  font-size: 2rem;           /* 32px — gemessen */
}
.rechtstext h2,
.rechtstext h3 {
  font-family: var(--schrift-text);
  font-size: var(--t-text);
  font-weight: 700;
  line-height: 1.5;
  text-transform: none;
}
.rechtstext h2 { margin: 2rem 0 0; text-decoration: underline; }
.rechtstext h3 { margin: 1.25rem 0 0; }
.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 -- */

/* Systemfuß (cosmopolar/top10-singen): links Marke und Rechtsverweise,
   rechts Social und Clubinio-Zeichen. Die Vorlage baggi-hp hatte hier
   einen eigenen Fuß mit „Quick Links" und Schlusszeile — der Aufbau des
   Originals entspricht aber dem Kanon.
   Gemessen: Grund #0c0c0c, Polster 72px (61px Tablet, 78px Telefon). */
.fuss {
  background: var(--kopf);
  padding-block: 72px;
}
@media (max-width: 1024px) { .fuss { padding-block: 61px; } }
@media (max-width: 767px)  { .fuss { padding-block: 78px; } }

/* 70/30 ab 1025px — die rechte Spalte beginnt bei 962px im 1440er
   Fenster. Darunter eine Spalte, **Social und Clubinio zuerst**: so stapelt
   das Original (gemessen bei 768 und 390). */
.fuss-raster {
  display: grid;
  gap: 56px;
  grid-template-columns: 1fr;
}
@media (min-width: 1025px) {
  .fuss-raster { grid-template-columns: 7fr 3fr; gap: 0; }
}
@media (max-width: 1024px) {
  .fuss-anfahrt { order: -1; }
}
@media (max-width: 767px) { .fuss-raster { gap: 70px; } }

/* Logo 194px breit (180 Tablet, 140 Telefon) — gemessen. */
.fuss-logo { width: 194px; margin-bottom: 26px; }
@media (max-width: 1024px) { .fuss-logo { width: 180px; } }
@media (max-width: 767px)  { .fuss-logo { width: 140px; margin-bottom: 6px; } }

.fuss-marke p {
  max-width: 484px;
  margin: 0;
  color: var(--tinte-leise);
  font-size: var(--t-fuss);
  line-height: 1.5;
}
@media (max-width: 1024px) { .fuss-marke p { max-width: 449px; } }

/* Rechtsverweise untereinander, rot — gemessen 15px/22,5px (11px am
   Telefon), 20px unter dem Text. */
.fuss .fuss-recht {
  display: flex;
  flex-direction: column;
  max-width: 484px;
  margin-top: 20px;
  font-size: var(--t-fuss-recht);
}
/* Ab Tablet abwärts 30px unter dem Text; am Telefon so breit wie der
   längste Verweis (160px), nicht spaltenbreit — gemessen. */
@media (max-width: 1024px) { .fuss .fuss-recht { max-width: 449px; margin-top: 30px; } }
@media (max-width: 767px)  { .fuss .fuss-recht { width: max-content; } }
.fuss-recht a { color: var(--akzent-text); }
.fuss a:hover { color: var(--tinte); }

/* Symbole frei, rot, 23px (18px unter 1025px), 20px Abstand — so stehen
   sie im Original. */
.fuss-social { display: flex; gap: 20px; margin: 0 0 20px; }
.fuss-social a { display: grid; place-items: center; color: var(--akzent); }
.fuss-social a:hover { color: var(--tinte); }
.fuss-social svg { width: 23px; height: 23px; }
@media (max-width: 1024px) { .fuss-social svg { width: 18px; height: 18px; } }

/* `flex`, nicht `inline-block`: Als Zeileninhalt hängt das Bild sonst 6px
   Unterlänge unter sich an (gemessen bei 768px). */
.clubinio { display: flex; width: max-content; }
.clubinio img { width: 100px; height: 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-titel,
html.anim .hero-text .knopf {
  animation: hero-auf 0.9s var(--kurve) both;
}
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: 700;
  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. */
/* **Die beiden Formulare handhaben ihren Absendeknopf verschieden.**

   Gemessen: Auf /kontakt/ steht er links und nur so breit wie sein Text
   (242px), auf /jobs/ laeuft er ueber die volle Formularbreite (672px).
   Das ist kein Versehen des Originals — das Bewerbungsformular ist
   laenger, und ein schmaler Knopf am Ende einer langen Spalte wird
   uebersehen. Deshalb zwei Faelle statt einer Regel. */
.form .knopf-reihe { justify-content: flex-start; }
.form .knopf-reihe .knopf { width: auto; }
.form .knopf-reihe .knopf-voll { width: 100%; }

.knopf-reihe[data-mitte] {
  justify-content: center;
  margin-top: 40px;          /* gemessen: Karten bis „All Events" */
}
/* Auf dem Tablet 65px — eine Elementor-Stufe, gemessen bei 768px. */
@media (min-width: 768px) and (max-width: 1024px) {
  .knopf-reihe[data-mitte] { margin-top: 65px; }
}
