/* ============================================================================
   Excalibur Hartberg — Design und Layout
   ----------------------------------------------------------------------------
   Uebernahme von disco-excalibur.at (WordPress, Elementor). Geruest vom
   System (baggi-hp, top10-singen-hp, cosmopolar-hp), Marke vom Original:  [Stil: cosmopolar.com]
   reines Schwarz als Grund, weisse Schrift, Poppins in zwei Schnitten,
   Cyan #70E6FE als einziger Akzent, Knoepfe als Pillen, Karten mit 20px
   Rundung. Alle Werte, die hier als „gemessen" stehen, kommen aus
   referenz/*.json (tools/messen.js).

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

/* **Poppins, zwei Schnitte — die Dateien des Originals.**

   Die Altseite laedt `Poppins-Regular-1.woff2` und `Poppins-Bold-1.woff2`
   und setzt Ueberschriften, Menue und Knoepfe mit `font-weight: 900`. Ein
   900er Schnitt ist nicht geladen; der Browser nimmt den naechstschwereren
   vorhandenen, also **700**. Gemessen: `document.fonts` meldet auf allen
   Seiten nur „Poppins 400" und „Poppins 700".

   **Seit 31.10.2026 ist der 900er geladen** (siehe unten): Alles Fette —
   Ueberschriften, Menue, Knoepfe, Etiketten, `strong` — steht auf 900.
   Damit ist die Seite fetter als das, was das Original zeigt; gegen
   referenz/ vergleicht tools/abgleich.py diese Stellen deshalb ohne
   Gewicht und Textbreite (Ausnahme mit Grund).

   Beide Dateien werden vorgeladen (alle Seiten und tools/build.py).
   Dieselben Dateien liegen Byte fuer Byte gleich in roxy-hp. */
@font-face {
  font-family: 'Poppins';
  src: url('../fonts/poppins-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

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

/* **Poppins Black (900)** — Betreiberwunsch 31.10.2026: „die bold
   Schriften muessen mehr bold". Das Original deklariert 900, laedt den
   Schnitt aber nicht; hier ist er da, und gezeigt wird, was das Original
   schreibt. Latin-Auszug von Fontsource (7,6 KB), deckt dieselben Zeichen
   wie der 700er (nachgeprueft mit fontTools). */
@font-face {
  font-family: 'Poppins';
  src: url('../fonts/poppins-900.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

/* **Inter fuer den Fliesstext** — Betreiberwunsch 31.10.2026. Poppins
   bleibt fuer Ueberschriften, Menue und Knoepfe (`--schrift-display`).
   Variable Datei aus der Vorlage baggi-hp, Latin-Auszug mit 230 Zeichen;
   gegen alle Seiten und Clubinio-Daten nachgezaehlt, es fehlt nur das
   Emoji ℹ, das ohnehin aus der Systemschrift kommt. */
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

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

:root {
  /* Flaechen. Die Werte stammen aus dem Elementor-Kit der Altseite
     (`--e-global-color-*`) und aus referenz/*.json. */
  --nacht:        #000000;   /* Seitengrund — gemessen, reines Schwarz */
  --box:          #161616;   /* Kit-Farbe c8133c1 */
  --box-hell:     #202020;   /* Kit-Farbe 9dec176 */
  --flaeche:      #0c0c0c;   /* Kit-Farbe 1a908f1 */
  --karte:        #111111;   /* Eventkarten — gemessen rgb(17,17,17) */
  --kopf:         #0c0c0c;   /* Kopfzeile und Fuss — gemessen rgb(12,12,12) */
  --linie:        #2a2a2a;   /* Trenner und Rahmen */

  /* Schrift: Poppins fuer Ueberschriften, Menue und Knoepfe, Inter fuer
     den Fliesstext [Betreiber 31.10.]. */
  --schrift-display: 'Poppins', system-ui, sans-serif;
  --schrift-text:    'Inter', system-ui, -apple-system, sans-serif;

  /* Schrift. **Fliesstext ist im Original weiss**, nicht gedaempft
     (gemessen an jedem <p>). `--tinte-leise` traegt deshalb Weiss; das
     Token bleibt, weil das System es an 30 Stellen fuer Fliesstext nutzt. */
  --tinte:        #ffffff;
  --tinte-leise:  #ffffff;
  --tinte-still:  #8a8a8a;
  --tinte-rgb:    255 255 255;

  /* Akzent der Marke: Kit-Farbe `accent` #70E6FE, gemessen an Menue,
     Datumszeilen, Knoepfen. **Nicht** das Clubinio-`#2563eb` — das steuert
     nur Widgets, die diese Seite nicht nutzt.

     Ein Wert fuer Flaeche und Schrift: Cyan auf Schwarz traegt 14,5:1,
     Schwarz auf Cyan ebenso. Anders als bei baggi braucht es kein
     angehobenes `--akzent-text`; das Token bleibt als Alias. */
  --akzent:       #70e6fe;
  --akzent-tinte: #000000;
  --akzent-rgb:   112 230 254;
  --akzent-text:  #70e6fe;

  /* **Zustandsfarben, getrennt vom Akzent.** In baggi war der Akzent rot
     und diente zugleich als Fehlerfarbe; mit Cyan ginge das nicht. Rot ist
     gemessen — die Pflichtsternchen der Altseite, rgb(225,29,72). Gruen
     ist der Erfolgston aus baggi (weisse Schrift darauf 5,13:1). */
  --fehler:       #e11d48;
  --fehler-rgb:   225 29 72;
  /* **Dasselbe Rot als Schrift — angehoben.** #e11d48 erreicht als 12–15px-
     Schrift 4,11:1 auf der Albenkarte (#0e0e0e) und 4,47:1 auf Schwarz,
     knapp unter den 4,5:1 von WCAG AA (tools/kontrast.js). Gleicher
     Farbton (346 statt 347 Grad), heller: 4,69:1 und 5,10:1. Flaechen und
     Rahmen behalten den Messwert. Dasselbe Vorgehen wie `--akzent-text`
     in baggi-hp. */
  --fehler-text:  #ec2f55;
  --erfolg:       #2e7d32;
  --erfolg-rgb:   46 125 50;

  /* Rundungen — gemessen. Knoepfe sind Pillen (20px bei 39px Hoehe),
     Eventkarten 20px, Formularfelder 2px, Albenbilder 8px. */
  --r-knopf:      20px;
  --r-feld:       2px;
  --r-karte:      20px;
  --r-klein:      8px;

  /* 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.
     Gemessen: Elementor `--overlay-opacity: 0.74` am Eventabschnitt. */
  --bild-schleier: 74%;

  /* Schleier ueber den Fotobannern der Unterseiten. **Nicht gemessen,
     sondern nach Kontrast eingestellt:** Die Unterzeile steht in 13–15px
     Cyan auf dem Foto und braucht 4,5:1 an jeder Stelle, die sie trifft
     (tools/bildkontrast.js). Gemessen, schwaechste Stelle: 50 % → 3,31:1,
     60 % → 4,65:1, 65 % → 5,57:1 (/kontakt/ bei 1440). 65 % fuer Luft. */
  --kopf-schleier: 65%;

  /* 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 bei 1440px.

     **Zwei Breiten, weil das Original zwei fuehrt.** Kopfzeile und Fuss
     setzen ihre Inhalte auf 1210px (Kante bei 115px), alle Inhaltsabschnitte
     auf 1140px (Kante bei 150px). Elementor stellt die Breite je Abschnitt
     ein; das System hat eine Huelle und ein Token fuer den Rahmen.
     `--breite` schliesst das Polster ein (`.huelle` ist border-box). */
  --breite:       calc(1140px + 2 * var(--gutter));
  --breite-rahmen: calc(1210px + 2 * var(--gutter));
  --breite-schmal: 760px;
  /* 20px Seitenrand auf jeder Breite — gemessen bei 390 und 768. */
  --gutter:       1.25rem;
  /* Hoehe der Kopfzeile: 100px auf dem Schreibtisch, 65px auf dem
     Telefon — gemessen. Hero, Menue und Ankersprung rechnen damit. */
  --kopf-hoehe:   82px;

  /* Typografie — gemessen bei 390 / 768 / 1440px:
       Hero-Titel           41 / 60 / 105px
       Abschnitt (h2)       40 / 50 / 50px   „EVENTS", „FOTOS"
       Fliesstext-h2        35 / 50 / 50px   „Willkommen im Excalibur – …"
       Kartentitel (h3)     25px
       Fliesstext           15px / 22,5px
     **Stufen, keine gleitenden Werte.** Elementor schaltet an 768 und 1025
     um; ein clamp() traf die Endpunkte, aber nicht 768 (gemessen 40 statt
     50px). Die Stufen stehen unten in den Medienabfragen. */
  --t-hero:   2.5625rem;
  --t-h2:     2.5rem;
  --t-h2-text: 2.1875rem;
  --t-h3:     1.5625rem;
  --t-text:   0.9375rem;
  --t-klein:  0.875rem;
}
@media (min-width: 768px) {
  :root { --t-hero: 3.75rem; --t-h2: 3.125rem; --t-h2-text: 3.125rem; }
}
@media (min-width: 1025px) {
  :root { --t-hero: 6.5625rem; }
}

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

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

/* Kein `padding-top` auf body: Die Kopfzeile klebt (`sticky`) und belegt
   ihren Platz im Fluss selbst. Hero und Bildkopf ziehen sich mit
   negativem Rand darunter (Cosmopolar, Betreiberwunsch 31.10.2026). [Stil: cosmopolar.com] */

/* 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);
  /* 15px/22,5px — gemessen an jedem <p> der Altseite. */
  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 — Betreiberwunsch „mehr bold", siehe @font-face oben. */
  font-weight: 900;
  /* Zeilenhoehe nach Aufgabe: Schlagworte stehen auf 1,0 („EVENTS"
     50/50px), Kartentitel auf 1,25 (25/31,25px). Der Grundwert ist die
     Kartenstufe; die grossen setzen ihn bei sich zurueck. */
  line-height: 1.25;
  text-transform: uppercase;
  /* Keine Sperrung — gemessen `letter-spacing: normal` an allen
     Ueberschriften. */
  letter-spacing: normal;
}

/* Fette Etiketten auf der Display-Schrift (Poppins), nicht im Fliesstext
   (Inter). Die Etiketten der Eventkarte stehen nicht mehr hier: Sie sind
   wie bei Cosmopolar in der Textschrift gesetzt. [Stil: cosmopolar.com] */
.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); }

/* `strong` im Fliesstext ebenso fett wie die Ueberschriften. */
strong, b { font-weight: 900; }

/* 15px zwischen Absaetzen — gemessen (Elementor-Vorgabe 0,9em). */
p { margin: 0 0 0.9375rem; }
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: 900;
}
.sprung:focus { left: 1rem; top: 1rem; }

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

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

/* 100px oben und unten auf **jeder** Breite — gemessen bei 390, 768 und
   1440 an „Events" und „Fotos" der Startseite (Elementor
   `--padding-top: 100px`, keine Staffelung). */
.abschnitt { padding-block: 100px; }

/* 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;
  /* 100px oben und unten — gemessen (`--padding-top: 100px`). */
  padding-block: 100px;
  /* Dasselbe Foto wie der Seitenkopf von /events/ — eine Datei, zwei
     Verwendungen. Wer von der Startseite weitergeht, hat sie schon. */
  background: url('../img/banner/events.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. */
/* 35px vom Ende der Zierlinie bis zu den Karten — 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; }
/* Zierlinie wie unter der Ueber-uns-Ueberschrift, hier mittig und kurz:
   5 % der Breite, gemessen 71px bei 1440 und 19px bei 390. */
/* **Unterhalb der Ueberschrift, nicht in ihr.** Elementors Divider ist ein
   eigenes Element von 34px Hoehe; als Blockkind des h2 machte die Linie
   die Ueberschrift 19px hoeher (gemessen 69 statt 50). Absolut gesetzt und
   mit dem Platz als Rand darunter bleibt das h2 so hoch wie im Original. */
/* Platz fuer die Linie als **Polster** der Kopfzeile, nicht als Rand des
   h2: Der Rand fiele mit `margin-bottom` der Kopfzeile zusammen (Rand-
   kollaps) und 34px gingen verloren — gemessen. */
.kopfzeile h2 { position: relative; }
.kopfzeile:has(h2) { padding-bottom: 34px; }
/* Elementor setzt ueber jedes Ueberschrift-Widget 10px — gemessen:
   Abschnitt beginnt bei 1635, Polster 100, „EVENTS" bei 1745. */
.kopfzeile { padding-top: 10px; }
.kopfzeile h2::after {
  content: '';
  position: absolute;
  top: calc(100% + 15px);
  left: 50%;
  width: clamp(19px, 5vw, 71px);
  height: 4px;
  transform: translateX(-50%);
  background: var(--akzent);
}
.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;
  /* 5px zum Pfeil: Text 166px + 5 + Pfeil 15 + 2 x 24 Polster = 234px,
     gemessen an „Alle Events ansehen". */
  gap: 5px;
  /* **Kein Rahmen** — die Kante der helleren Varianten kommt als
     `box-shadow: inset`, damit alle Knoepfe einer Reihe gleich hoch sind.

     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. */
  /* 12px/24px Polster, 15px/15px Schrift, Pille — gemessen: 39px hoch. */
  padding: 0.75rem 1.5rem;
  border: 0;
  border-radius: var(--r-knopf);
  background: var(--akzent);
  color: var(--akzent-tinte);
  font: inherit;
  font-family: var(--schrift-display);
  /* **Nach `font: inherit`, nicht davor.** Die Kurzschreibweise setzt
     `line-height` mit zurueck (Auftrag, Abschnitt 3). */
  line-height: 15px;
  font-weight: 900;
  font-size: 0.9375rem;
  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%);
}

/* Ticketknopf der Eventseite: **eckig**, 18px/50px Polster, 1,5px
   Sperrung — gemessen (267 x 51px). Volle Spaltenbreite bleibt vom System:
   Die Eventseite folgt dem einspaltigen Systemmass (.auftrag.md). */
.knopf-ticket {
  width: 100%;
  padding: 18px 50px;
  border-radius: 0;
  letter-spacing: 1.5px;
}
@media (max-width: 767px) {
  .knopf-ticket { font-size: 0.875rem; letter-spacing: normal; }
}

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

/* **Die Kopfzeile steht fest und ist immer deckend.**

   Die Geschwisterprojekte lassen sie ueber dem Hero frei im Bild stehen
   und erst beim Scrollen einen Grund bekommen. Die Altseite macht das
   nicht: Dort ist die Leiste von der ersten Bildschirmzeile an deckend
   rgb(12,12,12), 100px hoch (Tablet 85, Telefon 65) und bleibt beim
   Scrollen stehen — gemessen.

   `fixed` statt `sticky` bedeutet, dass sie keinen Platz im Fluss belegt —
   deshalb das `padding-top` auf `body` weiter unten. Beides gehoert
   zusammen; wer eines aendert, muss das andere mitziehen. */
/* **Kopfzeile im Stil von cosmopolar.com** (Betreiberwunsch 31.10.2026,  [Stil: cosmopolar.com]
   gemessen dort): klebt oben, ist ueber Hero und Bildkopf durchsichtig und
   bekommt erst beim Scrollen einen Grund — rgb(11 11 14 / 92 %) mit 10px
   Weichzeichner. Systembaustein aus cosmopolar-hp, Werte unveraendert. [Stil: cosmopolar.com] */
.kopf {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  isolation: isolate;
  transition: background 0.25s ease;
}
.kopf[data-fest='ja'] {
  background: rgb(11 11 14 / 92%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

/* **Der Weichzeichner muss aus, solange das Menue offen ist.**
   `backdrop-filter` erzeugt einen umgebenden Block fuer `position: fixed`;
   das Menue bezoege `inset` dann auf die Kopfzeile statt aufs Fenster. */

.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. */
/* Genau `--kopf-hoehe` hoch, Polster symmetrisch. Die Leiste hat oben wie
   unten denselben Grund — die Asymmetrie der Geschwisterprojekte war fuer
   eine frei im Bild stehende Zeile gedacht und wirkt auf einer Flaeche wie
   ein Fehler. */
/* 28px oben, 8px unten; beim Scrollen 18/18 — gemessen auf cosmopolar.com.  [Stil: cosmopolar.com]
   Inhaltskante bei 120px (1200px-Spalte), darunter 4 % der Breite. */
.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;
}
.kopf[data-fest='ja'] .kopf-innen {
  padding-top: 1.125rem;
  padding-bottom: 1.125rem;
}
.kopf-innen {
  max-width: none;
  padding-inline: max(clamp(1rem, 4vw, 2rem), calc((100% - 1200px) / 2));
}

.logo { display: flex; align-items: center; }
/* Auf dem Telefon deutlich kleiner — bei voller Groesse nimmt die Wortmarke
   dort die halbe Kopfzeile ein. */
/* 210 x 50px auf dem Schreibtisch, 105 x 25px auf dem Telefon — gemessen. */
/* 46px hoch, unter 900px 34px — Cosmopolars Logohoehe; die Wortmarke  [Stil: cosmopolar.com]
   von Excalibur wird dadurch breiter als Cosmopolars quadratisches Zeichen. [Stil: cosmopolar.com] */
.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); }

/* **Der Abstand steckt im Punkt, nicht zwischen den Punkten.**

   Gemessen am Original: „Home" ist 88px breit bei 55,7px reiner Schrift —
   also **16px** Polster je Seite — und zwischen zwei Punkten bleiben nur
   5px, in denen der Trennstrich sitzt. (Die Schriftbreite ist auf beiden
   Seiten dieselbe 55,7px; nachgemessen mit einem Range um den Textknoten,
   nicht aus der Kastenbreite geschaetzt.)

   Das ist nicht dasselbe wie eine grosse `gap`: Die Flaeche zum Anklicken
   reicht bis dicht an den Nachbarn, statt dass zwischen zwei Punkten ein
   toter Streifen liegt. Mit der `gap` der Vorlage (28px, plus 28px vor dem
   Strich) war unser Menue 43 Pixel breiter als das Original. */
/* 28px zwischen den Punkten, keine Trennstriche — Cosmopolar. [Stil: cosmopolar.com] */
.menu ul {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 1.75rem);
  margin: 0; padding: 0;
  list-style: none;
}

/* **Trennstriche zwischen den Punkten.**

   Die Geschwisterprojekte haben sie abgeschafft, weil ihre Kopfzeile eine
   schmale Pille ist, in der Striche den knappen Raum zerhacken. Hier ist
   die Leiste wieder ueber die volle Breite schwarz, und die bestehende
   Seite setzt die Striche — in einer langen Zeile geben sie den Punkten
   Halt.

   Als `::after` und nicht als Zeichen im Markup: ein Lesegeraet soll
   „Events" vorlesen und nicht „Events senkrechter Strich". */
@media (min-width: 900px) {
  .menu li { display: flex; align-items: center; }
}

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

   Der Menuefuss mit Anschrift und Social-Symbolen liegt im Markup
   innerhalb von `.menu`. Mit dem weiteren Selektor bekamen auch seine
   Verweise das Polster der Menuepunkte (8px/16px) — und weil die
   Symbolkreise 40px breit sind, blieben davon 8px Innenbreite uebrig.
   Das 20px-Symbol lief ueber, und Chrome setzte es wie beim Hero auf
   linksbuendig statt mittig: alle drei Zeichen sassen 6 Pixel zu weit
   rechts in ihrem Kreis.

   Derselbe Mechanismus, derselbe Tag — es lohnt, danach zu suchen, wenn
   etwas „verschoben" aussieht statt falsch bemessen. */
/* 20px/20px, 5px Polster oben und unten, keines seitlich — gemessen. */
/* 16px, Gewicht 900, Versalien, 0,04em gesperrt — Cosmopolar. [Stil: cosmopolar.com] */
.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;
}
/* Der aktive Punkt ist cyan **und unterstrichen** — die Altseite setzt
   einen 2px-Strich unter das Wort. */
.menu ul a:hover { color: var(--akzent-text); }
/* Aktiver Punkt nur in der Akzentfarbe, ohne Strich — Cosmopolar. [Stil: cosmopolar.com] */
.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. */

/* Klappmenue unter 900px, Leiste 80px hoch — Cosmopolar. [Stil: cosmopolar.com] */
@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. */
  /* Eng gestellt [Betreiber 31.10.: „deutlich weniger Abstand"]: kein
     Spalt, Zeilenhoehe 1,1 und 6px Polster — Abstand von Punkt zu Punkt
     44px statt 66px. Die Tippflaeche bleibt 43px hoch (WCAG 2.5.8: 24). */
  .menu ul {
    flex-direction: column;
    align-items: center;
    gap: 0;
  }
  .menu li { justify-content: center; }
  .menu ul a {
    font-size: clamp(1.75rem, 7vw, 2.25rem);
    line-height: 1.1;
    padding-block: 6px;
    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; }
  /* Wie Cosmopolar: Mail in fetten Versalien, Social frei in der  [Stil: cosmopolar.com]
     Akzentfarbe statt im Kreis. Dort kommt das ueber `.menu a`, das auch
     den Fuss trifft; hier gezielt, weil `.menu ul a` bewusst eingegrenzt
     ist (sonst liefen die Symbole ueber, siehe oben). */
  .menu-fuss a {
    font-family: var(--schrift-display);
    font-size: var(--t-klein);
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tinte-leise);
  }
  .menu-fuss .fuss-social { margin-top: 0.75rem; }
  .menu-fuss .fuss-social a {
    width: auto;
    height: auto;
    border-radius: 0;
    background: none;
    color: var(--akzent);
  }
  .menu-fuss .fuss-social a:hover { background: none; color: var(--tinte); }

  /* 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. */
  /* **Hero im Stil von cosmopolar.com** (Betreiberwunsch 31.10.2026):  [Stil: cosmopolar.com]
     71 % der Fensterhoehe zwischen 500 und 790px, unter die klebende
     Kopfzeile gezogen. Als `svh`, damit die Hoehe auf dem Telefon nicht
     springt, 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;
  /* Kein eigener Grund: Die Seite ist schwarz, und das Original setzt dem
     Hero keinen. */
  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;
  /* Verlauf statt Flaeche: oben dunkel fuer die Kopfzeile, in der Mitte
     heller, unten wieder dunkel — Cosmopolar. [Stil: cosmopolar.com] */
  background: linear-gradient(180deg, rgb(0 0 0 / 55%) 0%, rgb(0 0 0 / 35%) 45%, rgb(0 0 0 / 75%) 100%);
}

/* **Variante: wechselnder Hintergrund** (neu, gehoert zurueck in die
   Vorlage). Die Altseite blendet vier Fotos nacheinander ein — Elementors
   Hintergrund-Diashow, 5 s Standzeit, 0,5 s Blende. Hier reines CSS: Die
   Bilder liegen uebereinander, jedes hat dieselbe Animation, versetzt um
   ein Viertel. Ohne Bewegungswunsch steht das erste allein. */
.hero--diashow .hero-medium img {
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: hero-diashow 20s linear infinite;
}
.hero--diashow .hero-medium img:first-child { opacity: 1; }
.hero--diashow .hero-medium img:nth-child(2) { animation-delay: 5s; }
.hero--diashow .hero-medium img:nth-child(3) { animation-delay: 10s; }
.hero--diashow .hero-medium img:nth-child(4) { animation-delay: 15s; }
@keyframes hero-diashow {
  0%     { opacity: 0; }
  2.5%   { opacity: 1; }
  25%    { opacity: 1; }
  27.5%  { opacity: 0; }
  100%   { opacity: 0; }
}
/* **`animation: none`, nicht nur kurz.** Die allgemeine Regel weiter oben
   kuerzt jede Animation auf 0,01 ms — sie liefe dann sofort bis 100 %
   durch und liesse auch das erste Bild auf Deckung 0 stehen. */
@media (prefers-reduced-motion: reduce) {
  .hero--diashow .hero-medium img { animation: none; }
}

/* Platz fuer die Kopfzeile, die ueber dem Hero liegt. */
.hero-text {
  position: relative;
  z-index: 2;
  padding-top: var(--kopf-hoehe);
}

/* Logo ueber der Ueberschrift. **Ueber die Hoehe, nicht die Breite wie bei
   Cosmopolar:** dort ein quadratisches Zeichen bei 8 % der Breite, hier  [Stil: cosmopolar.com]
   eine Wortmarke 4:1 — bei 8 % waere sie 22px hoch. 70px, auf dem
   Telefon und Tablet 55px. */
.hero-logo {
  height: 70px;
  width: auto;
  margin: 0 auto 1rem;
}
@media (max-width: 1024px) {
  .hero-logo { height: 55px; }
}
/* 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);
  /* 44px bis 85px, Gewicht 900, Zeilenhoehe 1,02 — Cosmopolar. [Stil: cosmopolar.com] */
  font-size: clamp(2.75rem, 9vw, 5.3125rem);
  font-weight: 900;
  line-height: 1.02;
  text-transform: uppercase;
  letter-spacing: 0;
}
.hero-titel span { display: block; }

/* Heroknopf 46px hoch, 13px — Cosmopolar. Zeilenhoehe nach `font`. [Stil: cosmopolar.com] */
.hero-text .knopf {
  padding: 0.7rem 1.4rem;
  font-size: 0.8125rem;
  line-height: 1.7;
}

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

/* 60px zwischen den Spalten und, einspaltig, zwischen Text und Bild —
   gemessen bei 1440 und 390. */
.ueber {
  display: grid;
  gap: 60px;
  align-items: center;
}
/* `minmax(0, 1fr)`, nicht `1fr`: Die Spalte darf nicht mit dem
   Mindestinhalt des Schiebereglers wachsen (gemessen 346 statt 324px bei
   768 — dieselbe Rasterfalle wie im Auftrag, Abschnitt 3). */
@media (min-width: 900px) {
  .ueber { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
/* **Abschnittsbreiten der Startseite.** Elementor stellt die Breite je
   Abschnitt ein: „Willkommen" 1080px (zwei Spalten zu 510px, 60px
   Luecke), „Events" 1200px, alles andere 1140px (`--breite`). Gemessen
   bei 1440px. Zwei Spalten schon ab 768px — dort 324px je Spalte. */
.ueber {
  /* 30px Seitenrand statt 20 — dieser Abschnitt ist im Original auf
     jeder Breite weiter eingerueckt (x = 30 bei 390 und 768). Lokal
     umgesetzt, damit `.huelle` und die Hoechstbreite mitziehen. */
  --gutter: 30px;
  max-width: calc(1080px + 2 * var(--gutter));
  column-gap: 60px;
}
#ueber { padding-block: 80px; }
@media (min-width: 768px) and (max-width: 899px) {
  .ueber { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
#events .huelle { max-width: calc(1200px + 2 * var(--gutter)); }
/* Auf dem Tablet mit 45px Rand (Karte 678px bei 768) und 64px bis zum
   Knopf — gemessen. */
@media (min-width: 768px) and (max-width: 1024px) {
  #events .huelle { padding-inline: 45px; }
  #events .knopf-reihe[data-mitte] { margin-top: 64px; }
}
/* Fotostreifen: 30px von der Zierlinie bis zu den Bildern, die Punkte
   eng darunter (Bildkante bis Knopf 57px) — gemessen. */
#einblick .kopfzeile { margin-bottom: 30px; }
#einblick .slider-punkte { margin-top: 5px; padding-bottom: 5px; }
/* Bildformat der Strecke: 510 x 638px, also 4:5 — gemessen. */
#ueber .slider-band img { aspect-ratio: 4 / 5; }
/* Karten auf dem Bildabschnitt sind dunkler als auf /events/ — gemessen
   rgb(12,12,12) gegen rgb(17,17,17), Flyerflaeche rgb(10,10,10). */
.abschnitt-bild .karte { background: var(--flaeche); }

.ueber-text h2 {
  font-size: var(--t-h2-text);
  line-height: 1;
  letter-spacing: normal;
}
/* **Zierlinie unter der Ueberschrift** — Elementors Divider im Original:
   4px Cyan, 38 % der Spaltenbreite, mittig in einem 34px hohen Block
   (gemessen 194 x 4px bei 510px Spalte). Als ::after, weil es Zierde ist. */
/* 20px Luft, 34px Linienblock, 20px Luft — wie Elementor zwischen
   Ueberschrift, Divider und Text (gemessen 74px). */
.ueber-text h2 { position: relative; margin-bottom: 74px; }
.ueber-text h2::after {
  content: '';
  position: absolute;
  top: calc(100% + 35px);
  left: 0;
  width: 38%;
  height: 4px;
  background: var(--akzent);
}
/* 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); }
/* 20px zwischen letztem Absatz und Knopf — gemessen. */
.ueber-text .knopf-reihe { margin-top: 20px; }

/* Der Knopf bleibt auch auf dem Telefon links unter dem Text — gemessen
   (x = 30px bei 390). baggi zentrierte ihn dort. */

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

/* **Eventkarte im Stil von cosmopolar.com** (Betreiber, 01.11.2026). [Stil: cosmopolar.com]
   Wie eine Eintrittskarte: Flyer, Titel und Ort, darunter hinter einer
   gestrichelten Reisslinie Termin und „Infos". Werte aus cosmopolar-hp, [Stil: cosmopolar.com]
   Farben und Rundung von Excalibur.

   Die Kerben sind **Aussparungen im Kartenhintergrund**, keine farbigen
   Kreise — auf dem Fotoabschnitt der Startseite staenden Kreise in der
   Kartenfarbe als dunkle Punkte. So stanzen sie wirklich. */
.karte {
  --abriss: 46px;
  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-karte);
  /* Der Flyer uebernimmt die Rundung, ohne einzeln gerundet zu werden. */
  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: #0a0a0a; }
/* Flyer sind 16:9 — ein quadratischer Beschnitt schneidet den Titel weg.
   **Oben buendig beschnitten** wie im Original: Hochformatige Flyer
   verlieren unten, nicht oben. */
.karte-bild img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: top;
}

.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;
  letter-spacing: -0.02em;
}
/* Ort in der Akzentfarbe, Versalien, leicht gesperrt. */
.karte-ort {
  margin: 0;
  color: var(--akzent-text);
  font-size: var(--t-klein);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Abschnitt hinter der Perforation: links Termin, rechts der Weg zum
   Event. **Feste Hoehe** aus `--abriss`, damit die Reisslinie genau auf
   Hoehe der ausgesparten Kerben sitzt. */
.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: 900;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.karte-termin { color: var(--tinte-still); white-space: nowrap; }
.karte-infos {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--akzent-text);
  transition: gap 0.22s var(--kurve);
}
/* Der Pfeil rueckt beim Darueberfahren ein Stueck weiter. */
.karte:hover .karte-infos { gap: 0.6rem; }

/* Monatsueberschrift der Eventliste. */
/* Zentriert und weiss, ohne Trennlinie — wie im Original. */
.monat {
  /* 32px/38,4px, 1px gesperrt; 41px Luft ueber, 20px unter der Zeile —
     gemessen. */
  font-size: 2rem;
  line-height: 1.2;
  letter-spacing: 1px;
  color: var(--tinte);
  text-align: center;
  margin: 41px 0 20px;
}
.monat:first-child { margin-top: 30px; }

.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. */
}
/* **Ohne Seitenpolster.** Die Altseite setzt die Bilder beider Strecken
   bündig aneinander (gemessen: 3 x 480px bei 1440, Kante bei 0). */
.slider-band > figure {
  margin: 0;
  flex: 0 0 100%;
  box-sizing: border-box;
}
/* Scharfe Ecken und kein Platzhaltergrund — die Altseite setzt beide
   Strecken randlos auf Schwarz (gemessen `border-radius: 0`). */
.slider-band img {
  width: 100%;
  object-fit: cover;
}
/* 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; }
/* 16:9 — das Format der Dateien im Streifen (1400x788). Die Deckblaetter
   auf /fotos/ tragen 2:3, weil ihre Quellen Hochformate sind: Jede Flaeche
   folgt ihrer eigenen Quelle, statt beide auf ein gemeinsames Mass zu
   zwingen und eine davon zu beschneiden. */
.slider-randlos .slider-band img { aspect-ratio: 16 / 9; }

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

/* Punktreihe 37px unter dem Bild gerechnet bis zu ihrer Unterkante —
   so hoch ist Swipers Leiste im Original (Mitte des Textblocks daneben
   liegt auf der Mitte von Bild plus Leiste, gemessen). */
.slider-punkte {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1rem;
  padding-bottom: 13px;
}
.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%); }

/* Kein Anfahrtsblock (`.anfahrt`, `.zeile`): Die Altseite nennt die
   Anschrift weder im Fuss noch auf /kontakt/. Systembaustein, hier
   ungenutzt (docs/README.md, Vokabularabgleich). */

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

   Gemessen: 60 % oben, 40 % bei 40 % Hoehe, deckend am Fuss. */
.seitenkopf-bild::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Flacher Schleier — kein Verlauf. Deckung siehe `--kopf-schleier`. */
  background: rgb(0 0 0 / var(--kopf-schleier));
}
/* 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='jobs']    { background-image: url('../img/banner/jobs.webp'); }
.seitenkopf-bild[data-banner='kontakt'] { background-image: url('../img/banner/kontakt.webp'); }
.seitenkopf-bild[data-banner='fotos']   { background-image: url('../img/banner/fotos.webp'); }

.seitenkopf {
  /* Hoehe waechst mit der Fensterbreite, statt auf dem Telefon als flacher
     Streifen dazustehen, durch den das Bild stark beschnitten wird. */
  /* **Bildkopf im Stil von cosmopolar.com** (Betreiberwunsch 31.10.2026):  [Stil: cosmopolar.com]
     320 bis 460px, unter die Kopfzeile gezogen, Linie unten. */
  min-height: clamp(320px, 34vw, 460px);
  display: grid;
  align-content: center;
  margin-top: calc(var(--kopf-hoehe) * -1);
  border-bottom: 1px solid var(--linie);
  /* 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. */
  /* **Kein negativer Rand mehr.** Die Leiste ist hier deckend schwarz;
     einen Banner darunter zu schieben hiesse, oben 80 Pixel Foto
     wegzuwerfen. Das Original setzt `padding: 128px 0` und faengt unter
     der Leiste an. */
  padding-top: calc(var(--kopf-hoehe) + clamp(2.5rem, 7vw, 4rem));
  padding-bottom: clamp(2.5rem, 7vw, 4rem);
  /* **Kein eigener Grund.** Der Bildkopf ist im Original durchsichtig
     (nur Foto und Schleier, gemessen), der Kopf der Rechtstexte ebenso.
     Falls hier je ein Grund noetig wird: `background-color`, nie die
     Kurzschreibweise `background` — die setzte `background-size: cover`
     aus `.seitenkopf-bild` zurueck (in baggi passiert). */
  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; }

/* 48 bis 72px, Gewicht 900, leicht zusammengezogen — Cosmopolar. [Stil: cosmopolar.com] */
.seitenkopf h1 {
  font-size: clamp(3rem, 13vw, 4.5rem);
  font-weight: 900;
  line-height: 1.08;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}
.seitenkopf p {
  margin: 1rem auto 0;
  max-width: 54ch;
  color: var(--tinte-leise);
  text-transform: none;
}
/* Unterzeile in der Akzentfarbe, 15 bis 18px — Cosmopolar. [Stil: cosmopolar.com] */
.seitenkopf .unterzeile {
  color: var(--akzent-text);
  font-weight: 400;
  font-size: clamp(0.9375rem, 2.6vw, 1.125rem);
}

/* **Rechtstexte ohne Bildkopf.** Impressum und Datenschutz tragen im
   Original nur eine Ueberschrift in Cyan (32px), linksbuendig ueber dem
   Text — kein Banner. Der Systemkopf ohne `-bild` wird deshalb hier
   schlicht gesetzt. */
.seitenkopf:not(.seitenkopf-bild) {
  min-height: 0;
  margin-top: 0;
  padding-block: 50px 0;
  border-bottom: 0;
  text-align: left;
}
/* Ohne Cosmopolars Bildkopfwerte: keine Sperrung, Zeilenhoehe 1 wie im  [Stil: cosmopolar.com]
   Original — der Cosmopolar-Kopf gilt nur fuer Seiten mit Foto. [Stil: cosmopolar.com] */
.seitenkopf:not(.seitenkopf-bild) h1 {
  font-size: 2rem;
  line-height: 1;
  letter-spacing: normal;
  color: var(--akzent-text);
}

/* 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. */
/* Unter 760px Seitenverhaeltnis 3:2 statt Mindesthoehe — Cosmopolar  [Stil: cosmopolar.com]
   (260px bei 390). Mehr Hoehe statt staerkerer Vergroesserung. */
@media (max-width: 759px) {
  .seitenkopf-bild {
    min-height: 0;
    aspect-ratio: 3 / 2;
  }
}

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

/* Zwei Spalten zu 550px mit 20px Luecke in 1120px — gemessen. */
.kontakt-raster {
  display: grid;
  /* 50px zwischen FAQ und Formular, wenn sie untereinander stehen. */
  gap: 50px;
  column-gap: 20px;
  max-width: 1120px;
  margin-inline: auto;
  align-items: start;
}
/* Spaltenueberschriften „FAQ" und „Kontakt": 32px/32px. 20px bis zur
   ersten Frage, 45px bis zur ersten Feldbeschriftung — gemessen. */
#faq h2, #kontaktformular h2 { font-size: 2rem; line-height: 1; }
#faq h2 { margin-bottom: 20px; }
@media (min-width: 768px) {
  .kontakt-raster { grid-template-columns: minmax(0, 1fr) minmax(0, 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;
  }
}

/* **Plus links, keine Linie, normales Gewicht** — die Altseite (Elementor-
   Akkordeon): 44px je Frage, 16px/24px, Text 33px vom Rand, „+" weiss. */
.faq summary {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 24px;
  font-weight: 400;
  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;
  order: -1;
  width: 14px; height: 14px;
  background:
    linear-gradient(var(--tinte), var(--tinte)) center / 100% 2px no-repeat,
    linear-gradient(var(--tinte), var(--tinte)) 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: 0 10px 1.25rem 33px;
  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. */
/* Drei Spalten zu 360px mit 30px Luecke in 1140px — gemessen. 35px unter
   dem Seitenkopf statt der 45px der anderen Unterseiten. */
.alben-raster {
  display: grid;
  gap: 30px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  margin-top: -10px;
  /* Unter den Alben 130px bis zum Fuss, bis 1024px 230px — gemessen bei
     390, 768 und 1440 (80px davon traegt `.abschnitt-oben`). */
  margin-bottom: 50px;
}
@media (max-width: 1024px) { .alben-raster { margin-bottom: 150px; } }
/* Auf dem Telefon laufen Alben- und Eventkarten der Unterseiten bis 10px
   an den Rand (370px bei 390) — gemessen auf /fotos/ und /events/. Auf
   der Startseite nicht. Dort ist der Eventtitel auch 25px statt 24px. */
@media (max-width: 1024px) {
  .alben-raster,
  .abschnitt-oben .karten { margin-inline: -10px; }
  /* Bis 1024px eine Albenkarte je Zeile (748px bei 768) — gemessen. */
  .alben-raster { grid-template-columns: 1fr; }
}
@media (max-width: 767px) {
  .abschnitt-oben .karte-titel { font-size: 1.5rem; letter-spacing: -0.24px; }
}
.album-karte {
  display: flex;
  flex-direction: column;
  /* 14px Rundung, Grund #0e0e0e — gemessen (Plugin clubinio-fotos). */
  border-radius: 14px;
  background: #0e0e0e;
  overflow: hidden;
  color: inherit;
  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. */
/* Deckblatt 4:3 (360 x 270px), Grund #222 — gemessen. */
.album-bild {
  aspect-ratio: 4 / 3;
  background: #222222;
  /* **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); }

/* Text mit Streifen links (3px), Datum ueber dem Titel — wie im Plugin
   des Originals. Polster gemessen: 16px oben, 24px unten, 20px hinter dem
   Streifen, 18px rechts. **Farbe: Akzent statt Rot** — das Original hat
   hier Rot, der Betreiber will das Blau (31.10.). */
.album-text {
  display: grid;
  gap: 6px;
  padding: 16px 18px 24px 20px;
  border-left: 3px solid var(--akzent);
}
.album-titel { font-size: var(--t-h3); line-height: 1.2; margin: 0; }
/* 12px fett, 0,06em gesperrt — gemessen. Akzent statt Rot, siehe oben. */
.album-zeile {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  font-size: 0.75rem;
  line-height: 18px;
  font-weight: 900;
  letter-spacing: 0.06em;
  color: var(--akzent);
}

/* 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. */
/* Spaltenweise gefuellt wie im Original: vier Spalten zu 274px ab 1025px,
   drei zu 246px darunter, zwei auf dem Telefon; 15px Luecke — gemessen. */
.fotoraster {
  column-count: 3;
  column-gap: 15px;
  margin-top: 1.5rem;
}
/* Randlos bei 768 (3 x 246px ab x = 0), auf dem Telefon bis 10px an den
   Rand (3 x 113px) — gemessen. */
@media (max-width: 1024px) { .fotoraster { margin-inline: calc(-1 * var(--gutter)); } }
@media (max-width: 767px)  { .fotoraster { margin-inline: -10px; } }
@media (min-width: 1025px) { .fotoraster { column-count: 4; } }

/* Kopf der Albumseite: Titel 40px/48px (768: 32px, Telefon: 24px), nicht
   in Versalien, Angaben darunter weiss in 15,2px — gemessen. 33px unter
   der Kopfzeile. */
.seite-album .abschnitt-oben { padding-top: 33px; }
.seite-album .kopfzeile { padding: 0; margin-bottom: 0; }
.seite-album .kopfzeile h1 {
  font-size: 1.5rem;
  line-height: 1.2;
  text-transform: none;
}
@media (min-width: 768px)  { .seite-album .kopfzeile h1 { font-size: 2rem; } }
@media (min-width: 1025px) { .seite-album .kopfzeile h1 { font-size: 2.5rem; } }
.seite-album .unterzeile {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 24px;
  margin-top: 20px;
  color: var(--tinte);
  font-size: 0.95rem;
}
.seite-album .unterzeile .icon { margin-right: 5px; vertical-align: -3px; }
/* Bis 1024px untereinander — gemessen (390: 147/180px, 768: 176/209px). */
@media (max-width: 1024px) {
  .seite-album .unterzeile { flex-direction: column; align-items: center; }
}

/* Kachel: Grund rgb(23,26,33), 8px Rundung, 15px darunter — gemessen. */
.fotoraster figure {
  margin: 0 0 15px;
  break-inside: avoid;
  border-radius: var(--r-klein);
  overflow: hidden;
  background: #171a21;
  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); }

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

/* Im Original steht die Ansprache linksbuendig und in normaler Schriftlage,
   nicht als zentrierte Versalueberschrift. */
/* 45px unter dem Seitenkopf — gemessen auf /kontakt/ und /jobs/. */
.abschnitt-oben { padding-block: 45px 0; }

/* **Als letzter Abschnitt braucht er sein Polster zurueck.**

   Die Zeile darueber setzt es auf 0 — richtig fuer einen Abschnitt, der
   an den naechsten anschliesst, falsch fuer den letzten vor dem Fuss.
   Auf /kontakt/ stiessen die Social-Symbole direkt an die Fusskante, auf
   /events/ die letzte Kartenreihe.

   **Zielgenau auf diese Klasse, nicht auf `section:last-of-type`.** Mein
   erster Versuch war die allgemeine Regel — sie ist aber spezifischer
   als `.abschnitt` und haette auf den Unterseiten mit `.abschnitt`
   (/impressum/, /datenschutz/) das Polster von 100 auf 80 gesenkt. Vier Seiten
   veraendert, um zwei zu reparieren. `.abschnitt-oben` ist die einzige
   Klasse im Stylesheet, die unten auf 0 geht; damit ist der Fall
   vollstaendig abgedeckt.

   80px — gemessen am Original. */
.abschnitt-oben:last-of-type {
  padding-bottom: 80px;
}
/* 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: 45px; }

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

.stelle {
  padding: 1.5rem;
  background: rgb(255 255 255 / 5%);
  border: 1px solid rgb(255 255 255 / 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 -- */

/* 672px — gemessen, auf beiden Formularseiten gleich. Mittig in der
   Huelle, nicht ueber deren volle Breite. */
/* 22px zwischen Feldern — gemessen. */
.form {
  display: grid;
  gap: 22px;
  max-width: 672px;
  margin-inline: auto;
}
/* Das Namensfeld ist im Original 80 % breit (437 von 550px) — Elementors
   Spaltenbreite. */
[data-contact-form] > .feld:first-child { width: 80%; }

/* h2 traegt global keinen Abstand; ueber einem Formular braucht sie einen,
   sonst sitzt sie auf der ersten Feldbeschriftung. */
#kontaktformular h2 { margin-bottom: 45px; }
/* 90px vom Absendeknopf bis zum Fuss statt 80 — gemessen. */
#kontaktformular { padding-bottom: 10px; }
.kontakt-raster:not([data-ohne-faq]) .form { max-width: none; }

/* 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. */
/* 16px nebeneinander, 22px untereinander — wie alle Felder (gemessen). */
.form-reihe {
  display: grid;
  gap: 22px 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
}

/* ------------------------------------------------------- Jobs: Ansprache -- */

/* Systemklassen aus top10-singen-hp (in baggi verloren). Werte gemessen:
   32px/38,4px, Gewicht 500 im Original — ohne 500er Datei rendert der
   Browser den 400er Schnitt, hier steht deshalb 400. 20px bis zum
   Einleitungssatz. */
.jobs-ansprache {
  font-size: 2rem;
  line-height: 1.2;
  font-weight: 400;
  text-transform: none;
  margin-bottom: 20px;
}
.jobs-intro { color: var(--tinte-leise); }

/* Die Jobsseite laeuft ueber 1120px — Formular volle Breite, Name und
   Alter im Verhaeltnis 893 : 211px (gemessen). */
.seite-jobs .huelle { max-width: calc(1120px + 2 * var(--gutter)); }
.seite-jobs .form { max-width: none; }
/* Absendeknopf hier mit 3px Rundung, nicht als Pille, und nur 20px bis
   zum Fuss — gemessen, anders als auf /kontakt/. */
.seite-jobs .form .knopf-voll { border-radius: 3px; }
.seite-jobs #bewerbung { padding-bottom: 20px; }
@media (max-width: 767px) {
  .jobs-intro { font-size: 0.875rem; }
}
/* Elementors 80/20-Spalten mit je 8px Polster: Name = 80 % von (Breite +
   16px) − 16px, also `80 % − 3,2px` der Rasterbreite; Alter den Rest.
   Gegengerechnet: 893/211px bei 1440, 579/133px bei 768. */
.seite-jobs .form-reihe:first-child { grid-template-columns: calc(80% - 3.2px) minmax(0, 1fr); }
@media (max-width: 767px) {
  .seite-jobs .form-reihe:first-child { grid-template-columns: 1fr; }
}

/* **`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. */
/* Kein Rasterabstand: Die 13px zwischen Beschriftung und Feld traegt die
   Beschriftung selbst (siehe `.feld > span`). */
.feld {
  display: grid;
  gap: 0;
  align-content: start;
}
/* Beschriftung 15px, normal geschrieben, weiss — gemessen. */
.feld > span {
  /* 13px Luft zum Feld als Polster der Beschriftung — so misst Elementor
     sie (28px hoch), nicht als Abstand im Raster. So breit wie ihr Text. */
  justify-self: start;
  padding-bottom: 13px;
  font-size: 0.9375rem;
  line-height: 15px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--tinte);
}
/* „(optional)" steht im Original hinter dem Namen des Felds, statt dass
   die Pflichtfelder einen Stern tragen. Gedaempft, damit die Zeile nicht
   zweigeteilt wirkt. */
/* Rot wie im Original, als Schrift angehoben (`--fehler-text`). */
.feld-pflicht { color: var(--fehler-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 {
  /* 33px hoch: 4px/12px Polster, 15px/21px Schrift, 1px Rahmen
     rgb(82,82,82), 2px Rundung, durchsichtig — gemessen. */
  width: 100%;
  padding: 4px 12px;
  border: 1px solid #525252;
  border-radius: var(--r-feld);
  background: transparent;
  color: var(--tinte);
  font: inherit;
  font-size: 0.9375rem;
  /* **Nach `font: inherit`.** Die Kurzschreibweise setzt `line-height`
     zurueck — dieselbe Falle wie beim Knopf (Auftrag, Abschnitt 3). */
  line-height: 21px;
  min-height: 33px;
  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;
}
/* 94px hoch — gemessen. */
textarea {
  min-height: 94px;
  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;
  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. */
/* 29px hoch, 15px — gemessen. Die allgemeine Feldregel setzt 33px. */
input[type='file'] {
  min-height: 29px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: 0.9375rem;
  color: var(--tinte-leise);
}
input[type='file']:focus {
  background: none;
  box-shadow: none;
}
/* 4px/12px Polster, 19px Zeile: zusammen die 29px des Feldes. */
input[type='file']::file-selector-button {
  margin-right: 0.75rem;
  padding: 4px 12px;
  line-height: 19px;
  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;
}

/* 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. */
/* Bereiche nebeneinander in einer Zeile, 15px/15px — gemessen
   („Service / Theke" bei 177px, „Runner" bei 317px). */
.auswahl {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem 1.5rem;
}
/* 21px hoch wie im Original — das 20px-Kaestchen passt hinein. */
.auswahl label {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  height: 21px;
  font-size: 0.9375rem;
  line-height: 15px;
  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; }
/* Die Beschriftung der Bereiche wie jede andere: 15px/15px, 13px Polster. */
fieldset.feld legend > span {
  display: block;
  padding-bottom: 13px;
  font-size: 0.9375rem;
  line-height: 15px;
}

/* 15px/15px, Text 2px unter der Zeilenoberkante — gemessen (dort steht
   er in einer 21px-Zeile neben dem 13px-Kaestchen). Relativ versetzt,
   damit die Zeile selbst nicht hoeher wird. */
.zustimmung > span { position: relative; top: 2px; }
.zustimmung {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  font-size: 0.9375rem;
  line-height: 15px;
  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) 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 fuer Erfolg, Rot fuer Fehler — beide eigene Token, nicht der
   Akzent. */
.rueckmeldung[data-state='ok'] {
  background: rgb(var(--erfolg-rgb) / 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(var(--fehler-rgb) / 16%);
  box-shadow: inset 0 0 0 1px var(--fehler);
  color: var(--tinte);
}
.rueckmeldung[data-state='fehler']::before {
  background-color: var(--fehler);
  background-image: var(--ausruf);
}

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

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

/* Inhaltsspalte ~820px und Titel ~40px — Originalwerte. */
.event { max-width: 820px; margin-inline: auto; }
/* 43px/47,3px, auf dem Telefon 30px/33px — gemessen. */
.event h1 { font-size: 1.875rem; line-height: 1.1; }
@media (min-width: 768px) { .event h1 { font-size: 2.6875rem; } }

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


/* Kein U18-Formular (`.knopf-reihe-u18`, `.u18-hinweis`): deutsches
   Jugendschutzrecht, in der Steiermark nicht vorgesehen (tools/build.py). */

.event-datum {
  color: var(--akzent-text);
  font-weight: 900;
  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;
}

/* Grund #0c0c0c, 26px Polster, eckig — gemessen am Infokasten der
   Altseite (dort rechte Spalte). */
.infokasten {
  margin-top: 2.5rem;
  padding: 26px;
  background: var(--flaeche);
}
.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; }
/* Werte in normaler Schreibung, 16px, nicht fett — gemessen am
   Infokasten der Altseite („31. Oktober 2026 • 15:00", Poppins 500, das
   ohne 500er Datei als 400 rendert). baggi setzte Versalien in 700. */
.infokasten dd {
  font-size: 1rem;
  font-weight: 400;
  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; }

/* Keine Lounge-Liste (`.lounges`, `.lounge*`): Clubinio liefert fuer
   jeden Termin eine leere Liste; gebucht wird ueber den Shop
   (`?tab=lounges`). Die Altseite listete Lounges aus WordPress —
   docs/README.md, Offen. */

/* 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: 900;
  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, Satz und Rechtslinks, rechts
   Instagram und das Clubinio-Zeichen. Grund wie die Kopfzeile (#0c0c0c),
   72px Polster — gemessen. Breite wie die Kopfzeile (`--breite-rahmen`). */
.fuss {
  background: var(--kopf);
  padding-block: 72px;
}
/* Derselbe Rand wie die Kopfzeile: 5 % der Breite, ab 1210px die Spalte. */
.fuss .huelle {
  max-width: none;
  padding-inline: max(5vw, calc((100% - var(--breite-rahmen)) / 2 + var(--gutter)));
}
/* 847 : 363px bei 1210px — die rechte Spalte beginnt bei 962px. */
.fuss-raster {
  display: grid;
  gap: 2.5rem;
  grid-template-columns: 1fr;
}
@media (min-width: 1025px) {
  .fuss-raster { grid-template-columns: 7fr 3fr; gap: 0; }
}
/* Der Satz bricht nach 484px um — gemessen. */
.fuss-marke p { max-width: 484px; }

/* 106 x 25px, 28px Luft zum Satz — gemessen. */
.fuss-logo {
  height: 25px;
  width: auto;
  margin-bottom: 28px;
}

.fuss p { color: var(--tinte); font-size: 1rem; line-height: 1.5; }
.fuss a:hover { color: var(--tinte); }

/* Rechtslinks untereinander in Cyan, 15px/22,5px — gemessen. Im System
   nebeneinander; hier steht nur die Richtung anders. */
.fuss-recht {
  display: grid;
  gap: 0;
  max-width: 484px;
  margin-top: 1.25rem;
}
.fuss-recht a { color: var(--akzent-text); font-size: 0.9375rem; line-height: 1.5; }

/* **Runde Flaechen, nicht freie Symbole.**

   Der Kommentar hier behauptete das Gegenteil und stammte aus der
   Vorlage. An der bestehenden Seite gemessen: ein Kreis von 40px (im
   Fuss 36) mit Weiss bei 10 % Deckung, darin das Symbol in 20px (bzw.
   16) **weiss** — nicht in der Akzentfarbe. */
.fuss-social { display: flex; gap: 0.75rem; margin: 1.25rem 0; }
/* **Im Fuss ohne Kreis.** Das Original setzt das Instagram-Zeichen frei in
   Cyan, 23px (Telefon 18px), direkt ueber dem Clubinio-Zeichen. */
.fuss-social a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgb(var(--tinte-rgb) / 10%);
  color: var(--tinte);
  transition: background 0.2s ease;
}
.fuss-social a:hover { background: rgb(var(--tinte-rgb) / 20%); color: var(--tinte); }
.fuss-social svg { width: 20px; height: 20px; }

.fuss .fuss-social { margin: 0 0 20px; }

/* **Bis 1024px einspaltig und umgekehrt:** Instagram und Clubinio stehen
   dort ueber Logo und Text, Satz 14px/21px, Logo kleiner (99 x 24px bei
   768, 77 x 18px bei 390) — alles gemessen. */
@media (min-width: 768px) and (max-width: 1024px) {
  .fuss-marke p { max-width: 449px; }
}
@media (max-width: 1024px) {
  .fuss { padding-block: 61px; }
  .fuss-raster { grid-template-columns: 1fr; gap: 56px; }
  .fuss-raster > :last-child { order: -1; }
  .fuss p { font-size: 0.875rem; line-height: 1.5; }
  .fuss-logo { height: 24px; margin-bottom: 27px; }
  .fuss-recht { margin-top: 30px; }
}
@media (max-width: 767px) {
  .fuss { padding-block: 78px; }
  .fuss-raster { gap: 71px; }
  .fuss-logo { height: 18px; }
}
.fuss .fuss-social a {
  width: 23px;
  height: 23px;
  border-radius: 0;
  background: none;
  color: var(--akzent);
}
.fuss .fuss-social a:hover { background: none; color: var(--tinte); }
.fuss .fuss-social svg { width: 23px; height: 23px; }
@media (max-width: 1024px) {
  .fuss .fuss-social a, .fuss .fuss-social svg { width: 18px; height: 18px; }
}

/* 100 x 39px — gemessen. */
/* Als Block mit eigener Breite: Inline stuende das Zeichen auf der
   Grundlinie des umgebenden Zeilenkastens, und darunter bliebe Platz fuer
   Unterlaengen — 7px, gemessen am Abstand zum Logo. */
.clubinio { display: block; width: max-content; }
.clubinio img { height: 39px; 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: 900;
  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%; min-height: 40px; padding-block: 0; }

/* 39px unter Karten oder Bildstrecke — gemessen. */
.knopf-reihe[data-mitte] {
  justify-content: center;
  margin-top: 39px;
}
