/* ═══════════════════════════════════════════════════════════════════════
   CLUBZ & BEATZ — CLUB-PANEL: LAYOUT UND KOMPONENTEN

   🔴 KEIN einziger Farbwert, Schriftname oder Abstands-Literal in dieser
      Datei. Alles kommt aus tokens.css über var(--...). Wer hier einen
      Hex-Code einträgt, bricht die Design-Prüfung (Testanweisung Punkt 23).

   Übernommen aus dem früheren Inline-CSS in `views/venuePortalPages.ts`
   (Basis) und `views/venueDashboardPage.ts` (Dashboard). Die Regeln sind
   inhaltlich unverändert — nur die Werte sind jetzt Tokens. Die Kommentare
   sind mitgewandert: sie erklären, warum eine Zahl so ist, wie sie ist, und
   genau das geht beim Umbau sonst als Erstes verloren.
   ═══════════════════════════════════════════════════════════════════════ */

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  line-height: 1.6;
}

.wrap {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--space-2xl) var(--space-xl) var(--space-4xl);
}

/* Die Token-Seiten (Anmelden, Übernehmen) bleiben schmal — ein Formular mit
   vier Feldern auf 1080 px sieht verloren aus. */
.wrap--narrow {
  max-width: 560px;
  padding: var(--space-4xl) var(--space-xl) var(--space-4xl);
}

/* Echtes Wortmarken-Logo statt getipptem Markennamen; der Zusatz "Clubz & Beatz"
   bleibt als Text daneben stehen, damit klar ist, in welchem Bereich man ist. */
.brand {
  display: flex;
  align-items: center;
  gap: var(--space-sm-plus);
  margin-bottom: var(--space-3xl);
}
.brand img {
  height: 26px;
  width: auto;
  display: block;
}
.brand span {
  font-size: var(--text-sm);
  letter-spacing: 2px;
  color: var(--accent-text);
  font-weight: 700;
  text-transform: uppercase;
}

h1 {
  font-size: var(--text-2xl);
  line-height: 1.25;
  margin: 0 0 var(--space-md);
  font-weight: 700;
}

p {
  color: var(--text-muted);
  margin: 0 0 var(--space-lg-plus);
}

ul {
  color: var(--text-muted);
  padding-left: var(--space-xl);
  margin: 0 0 var(--space-lg-plus);
}
li {
  margin-bottom: var(--space-sm);
}

/* Links tragen die Akzentfarbe von sich aus. Vorher stand an jedem einzelnen
   Link ein `style="color:#FF7800"` — zehnmal derselbe Wert, und im Light-Mode
   wäre jeder davon unlesbar geworden (Orange auf Creme = 2.07:1). */
a {
  color: var(--accent-text);
}

/* Textzeile, die sich vom umgebenden Fließtext abheben soll. Ersetzt
   `style="color:#fff"` — im Light-Mode wäre Weiß auf Creme unsichtbar. */
.text-strong {
  color: var(--text);
  font-weight: 600;
}

/* Bild-Vorschau in Formularen (Titelbild, Logo). Die Maße bleiben am Element,
   weil sie sich je Verwendung unterscheiden; Rahmen und Radius sind hier. */
.img-preview {
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  /* 🔴 --space-xl, NICHT --space-md (Fabi 01.09.2026: „kein Abstand oben,
     unten ist Abstand"). Unter dem Bild folgt immer eine `.btn-row`, und die
     traegt `margin-top: var(--space-xl)` = 20px. Zwischen Geschwistern
     kollabieren Raender zum groesseren Wert — mit 12px oben stand das Bild
     deshalb 12px unter der Ueberschrift, aber 20px ueber den Knoepfen.
     Gleicher Token auf beiden Seiten heisst: sichtbar gleicher Abstand. */
  margin: var(--space-xl) 0;
  display: block;
}

/* Statuszeile unter einer Handlung. `.is-error` färbt sie um, ohne dass das
   Skript eine Farbe kennen muss — genau dafür sind Klassen da. */
.hint-line {
  color: var(--text-muted);
}
.hint-line.is-error {
  color: var(--danger);
}

/* ── Formularelemente ──────────────────────────────────────────────────── */

label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
  margin: var(--space-lg) 0 var(--space-xs-plus);
}

input,
textarea,
select {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  /* 🔴 16px, nicht kleiner: Safari auf iOS zoomt in JEDES Feld darunter hinein,
     und der Betreiber landet in einer verschobenen Seite. Gilt genauso für
     Datums- und Zeitfelder weiter unten. */
  font-size: var(--control-font);
  font-family: inherit;
}

input {
  padding: var(--space-md-plus) var(--space-lg);
}

/* 🔴 Dieselbe Höhe und Schriftgröße wie ein Eingabefeld. Vorher standen
   Auswahl- und Eingabefelder im Profil-Formular mit 46px gegen 51px
   nebeneinander — das sieht nach Versehen aus. */
select {
  padding: var(--space-md-plus);
  min-height: var(--control-height);
  max-width: 100%;
}
select:disabled {
  opacity: 0.5;
}

textarea {
  padding: var(--space-md) var(--space-md-plus);
  min-height: 110px;
  resize: vertical;
  line-height: 1.45;
}

input:focus,
textarea:focus,
select:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

input[type='date'],
input[type='time'] {
  font-size: var(--control-font);
  min-height: var(--tap-min);
}

/* Datum und Uhrzeit nebeneinander. Die Uhrzeit braucht weniger Platz, darf aber
   nicht so schmal werden, dass die Stunden-/Minuten-Felder abgeschnitten sind. */
.dt-pair {
  display: flex;
  gap: var(--space-sm);
}
.dt-pair input[type='date'] {
  flex: 1 1 auto;
  min-width: 0;
}
.dt-pair input[type='time'] {
  flex: 0 0 118px;
}
@media (max-width: 400px) {
  .dt-pair input[type='time'] {
    flex: 0 0 104px;
  }
}

/* ── Schaltflächen ─────────────────────────────────────────────────────── */

button {
  width: 100%;
  background: var(--accent);
  color: var(--on-accent);
  border: 0;
  border-radius: 10px;
  padding: var(--space-lg);
  font-size: var(--control-font);
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  margin-top: var(--space-2xl);
  min-height: 52px;
}
button:hover:not(:disabled) {
  background: var(--accent-hover);
}
button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
/* Sichtbarer Tastatur-Fokus auf ALLEM, was man bedienen kann. Ohne diese Regel
   ist das Panel per Tastatur zwar bedienbar, aber blind — man sieht nicht, wo
   man steht.

   Ersetzt die frühere Einzelregel `.tile-link:focus-visible`: die Kacheln sind
   <button>-Elemente und werden hier mitgefasst, mit demselben Rahmen wie zuvor.
   Statt jede fokussierbare Komponente einzeln zu bedenken (und die nächste zu
   vergessen), gilt die Regel jetzt für alle. */
button:focus-visible,
a:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Zweitrangige Handlung (Anmeldelink als Notfalltür): sichtbar, aber nicht in
   Konkurrenz zum orangen Hauptknopf — sonst wirken beide gleich wichtig und
   der Betreiber nimmt wieder den Mail-Weg. */
.btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  margin-top: 0;
}
.btn-secondary:hover:not(:disabled) {
  background: var(--surface-3);
}

.btn-ghost {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: var(--space-md) var(--space-lg);
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  min-height: var(--tap-min);
  width: auto;
  margin: 0;
}
.btn-ghost:hover:not(:disabled) {
  background: var(--surface-3);
}

.btn-danger {
  color: var(--accent-hover);
}
/* Zweistufige Bestätigung: erst der Klick, dann die rote Fläche. Ein
   destruktiver Knopf, der beim ersten Antippen ausführt, ist eine Falle. */
.btn-danger.armed {
  background: var(--danger);
  color: var(--text);
  border-color: var(--danger);
}

.btn-row {
  display: flex;
  gap: var(--space-sm-plus);
  flex-wrap: wrap;
  margin-top: var(--space-xl);
}
.btn-row button {
  margin-top: 0;
  width: auto;
  flex: 0 0 auto;
}

.chip {
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  padding: var(--space-sm) var(--space-lg);
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  min-height: var(--tap-min);
  width: auto;
  margin: 0;
}
.chip.active {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}
.chip:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.chips {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-bottom: var(--space-xl);
}

/* ── Topbar ───────────────────────────────────────────────────────────── */

.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.topbar-inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--space-md-plus) var(--space-xl);
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  flex-wrap: wrap;
}
/* Das Logo ist im Dashboard ein Link zurück auf die Übersicht — Unterstreichung
   und Link-Farbe der Basis-Styles dürfen dabei nicht durchschlagen. */
.topbar .brand {
  margin: 0;
  flex: 0 0 auto;
  text-decoration: none;
}
.topbar-spacer {
  flex: 1 1 auto;
}

/* ── Segment-Schalter (Sprache, Darstellung) ──────────────────────────────
   Zwei bis drei Möglichkeiten, alle gleichzeitig sichtbar — kein Aufklappmenü.
   Ein Betreiber, der die Sprache sucht, findet sie so beim Hinsehen statt
   hinter einem Zahnrad.

   🔴 Volle Antippfläche (--tap-min) trotz der kleinen Schrift: die Leiste wird
   am Handy bedient, und 30px hohe Schalter nebeneinander sind dort ein
   Glücksspiel. */
.seg {
  display: inline-flex;
  flex: 0 0 auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-2);
}
.seg-btn {
  background: transparent;
  color: var(--text-muted);
  border: 0;
  border-radius: 0;
  padding: var(--space-sm) var(--space-md);
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  min-height: var(--tap-min);
  width: auto;
  margin: 0;
  white-space: nowrap;
}
/* Trennstrich zwischen den Feldern statt Abstand: die Gruppe soll als EIN
   Schalter lesbar bleiben, nicht als drei lose Knöpfe. */
.seg-btn + .seg-btn {
  border-left: 1px solid var(--border);
}
.seg-btn:hover:not(.on) {
  background: var(--surface-3);
  color: var(--text);
}
.seg-btn.on {
  background: var(--accent);
  color: var(--on-accent);
}

.venue-head {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--space-3xl) var(--space-xl) 0;
}
/* 🔴 Boldonse NUR hier — dem Clubnamen als Seitentitel. Die Marken-Schrift ist
   blockig und in Versalien gesetzt; über Kacheln, Formularen und Tabellen
   angewandt macht sie ein Dashboard laut und schlecht lesbar. An genau einer
   Stelle eingesetzt bringt sie die Wiedererkennung aus der App, ohne die
   Arbeitsflächen zu stören.

   Die Zeilenhöhe MUSS ≥1.95× der Schriftgröße sein, sonst wird die Oberkante
   der Versalien abgeschnitten — dieselbe Metrik, für die es in der App
   `titleFont()` gibt. */
/* Das Logo steht anstelle der Namenszeile, sobald eines hinterlegt ist.
   Hoehe fest, Breite frei — Clublogos sind mal quadratisch, mal ein
   langer Schriftzug; eine feste Breite wuerde beide verzerren. */
.venue-logo {
  display: block;
  height: 56px;
  width: auto;
  max-width: 320px;
  object-fit: contain;
  margin: 0 0 var(--space-xs);
}

.venue-head h1 {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: var(--line-display);
  letter-spacing: -0.5px;
  text-transform: uppercase;
}
.venue-head .sub {
  color: var(--text-subtle);
  font-size: 14px;
  margin: 0;
}

/* ── Abzeichen ────────────────────────────────────────────────────────── */

.badge {
  display: inline-block;
  border-radius: var(--radius-full);
  padding: var(--space-xs) var(--space-md);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.4px;
  white-space: nowrap;
}
.badge-pro {
  background: var(--accent);
  color: var(--on-accent);
}
.badge-free {
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
}
/* 🔴 Orange mit Verlauf statt gruen (Fabi 21.08.2026: „die pill
   Veröffentlich machen wie orang mit verlauf"). Die Textfarbe ist
   `--on-accent` (#161616) — dieselbe wie auf dem Kauf-Knopf. Weisse Schrift
   haette auf dem hellen Ende des Verlaufs (#FF9A2E) nur rund 2:1 Kontrast;
   das dunkle Grau kommt auf ueber 7:1 und bleibt auch am dunklen Ende
   (#D96400) lesbar. */
.badge-published {
  background: var(--accent-gradient);
  color: var(--on-accent);
  border: 1px solid transparent;
}
.badge-pending_venue {
  background: var(--warn-soft);
  color: var(--accent-hover);
  border: 1px solid var(--accent-dark);
}
.badge-cancelled {
  background: var(--danger-soft);
  color: var(--text);
  border: 1px solid var(--danger);
}
.badge-draft,
.badge-pending_join {
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

/* ── Reiter ───────────────────────────────────────────────────────────── */

.tabs {
  position: sticky;
  /* Sitzt direkt unter der Topbar. Der Wert ist deren gemessene Höhe
     (14px Polsterung oben + 26px Logo + 14px unten + 1px Linie + 6px Zeile). */
  top: 61px;
  z-index: var(--z-sticky);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  margin-top: var(--space-xl);
}
.tabs-inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--space-xl);
  display: flex;
  gap: var(--space-xs);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.tab {
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-subtle);
  font-size: var(--text-base);
  font-weight: 600;
  font-family: inherit;
  padding: var(--space-lg) var(--space-md-plus);
  cursor: pointer;
  white-space: nowrap;
  margin: 0;
  width: auto;
  min-height: 52px;
  border-radius: 0;
}
.tab:hover:not(:disabled) {
  background: none;
  color: var(--text);
}
.tab.active {
  color: var(--accent-text);
  border-bottom-color: var(--accent);
}

/* ── Karten und Raster ────────────────────────────────────────────────── */

/* 🔴 Der Verlauf liegt auf JEDER Karte (Fabi 22.08.2026: „den will ich in
   allen boxen im panel"). Er kommt aus der Ecke unten links und laeuft nach
   72 % vollstaendig aus — auf einer hohen Karte bleibt der obere Teil also
   ruhig, statt die ganze Flaeche einzufaerben.

   Die Reihenfolge ist wichtig: Verlauf ZUERST, Flaeche dahinter. Umgekehrt
   deckt `--surface-1` als spaeterer Layer den Verlauf zu und man sieht
   nichts. */
.card {
  background: var(--lage-glanz), var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-2xl);
  margin: var(--space-2xl) 0;
}
.card h2 {
  font-size: 17px;
  margin: 0 0 var(--space-xs-plus);
  font-weight: 700;
}
.card > p:last-child {
  margin-bottom: 0;
}

.venue-name {
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--text);
  margin: 0 0 var(--space-xs);
}
.venue-meta {
  font-size: 14px;
  color: var(--text-subtle);
  margin: 0;
}

.muted {
  color: var(--text-muted);
  font-size: var(--text-base);
}
.warn {
  color: var(--accent-hover);
  font-size: 14px;
  margin-top: var(--space-sm-plus);
}

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-md);
}
.tile {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 14px;
  /* 🔴 MUSS hier stehen, auch wenn es ueberfluessig aussieht. Eine Kachel ist
     oft ein <button>, und die Grundregel `button` (oben) setzt
     `color: var(--on-accent)` — die Farbe fuer Text AUF orangem Grund. Die
     Kachel ueberschreibt zwar den Hintergrund auf --surface-1, erbte aber
     weiter das dunkle #161616: gemessen am 01.09.2026 ergab die grosse
     Kennzahl damit 1,07:1 und war praktisch unsichtbar. Mit --text sind es
     16,9:1 (dunkel) bzw. 17,9:1 (hell).
     `.tile-link` hatte denselben Fix schon; `.tile--klickbar` fehlte er. */
  color: var(--text);
  /* 🔴 Enger als zuvor (18px). Eine Kennzahlkachel enthält eine Zahl und ein
     Wort; mit großzügiger Polsterung wird daraus ein 130px hoher Kasten, und
     drei davon nebeneinander schieben alles Weitere unter die Falz. Ein
     Dashboard lebt davon, dass viel gleichzeitig sichtbar ist. */
  padding: var(--space-md-plus) var(--space-lg);
}
.tile-value {
  font-size: 30px;
  font-weight: 700;
  line-height: 1.15;
}
.tile-label {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-xs);
}
/* Vergleich zum Vorzeitraum unter der Kennzahl.
   🔴 Farbe über --accent-text und --danger, NICHT über --success: das ist mit
   #20342D ein sehr dunkles Grün und wäre auf dem dunklen Kachelgrund praktisch
   unsichtbar. --accent-text ist für beide Modi eigens gepflegt.
   Die Richtung hängt nie allein an der Farbe — das Vorzeichen steht im Text. */
.tile-change {
  font-size: var(--text-sm);
  margin-top: var(--space-xs);
}
.tile-change.up {
  color: var(--accent-text);
}
.tile-change.down {
  /* --danger-text, NICHT --danger: die Flaechenfarbe hat auf dem dunklen
     Kachelgrund nur 3,12:1 (gemessen 01.09.2026, noetig sind 4,5:1 bei 13px). */
  color: var(--danger-text);
}
/* Anklickbare Kachel — als <button>, deshalb die Button-Grundwerte zurücksetzen. */
.tile-link {
  width: 100%;
  margin: 0;
  text-align: left;
  font-family: inherit;
  color: var(--text);
  cursor: pointer;
  display: block;
}
.tile-link:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--border-strong);
}
.tile-cta {
  font-size: var(--text-sm);
  color: var(--accent-text);
  font-weight: 600;
  margin-top: var(--space-sm-plus);
}
/* Ohne Inhalt dahinter kein Versprechen: der Hinweis verschwindet bei 0. */
.tile-link.empty .tile-cta {
  display: none;
}
.tile-link.empty {
  cursor: default;
}

/* ── Avatare in der Follower-Liste ────────────────────────────────────── */

.ava {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  flex: 0 0 auto;
  background: var(--surface-2);
  object-fit: cover;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--text-subtle);
  font-size: var(--text-base);
  overflow: hidden;
}

/* ── Zeilen (Events, Team) ────────────────────────────────────────────── */

.row {
  display: flex;
  /* 🔴 Umbruch erlaubt: in schmalen Spalten rutscht die Steuerung unter den
     Text, statt ihn auf Buchstabenbreite zu quetschen (siehe .row-main). */
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-md-plus);
  padding: var(--space-md-plus) 0;
  border-bottom: 1px solid var(--border);
}
.row:last-child {
  border-bottom: 0;
}
.row-main {
  /* 🔴 `14rem` statt `auto`: Darunter bricht die Zeile um, statt den Namen
     buchstabenweise zu stapeln. `min-width: 0` bleibt — ohne das kann ein
     Flex-Kind seinen Inhalt nicht unterschreiten, und eine lange E-Mail
     sprengt die Karte nach rechts. */
  flex: 1 1 14rem;
  min-width: 0;
}
.row-title {
  font-weight: 600;
  font-size: var(--control-font);
  overflow-wrap: anywhere;
}
.row-meta {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-xs);
  overflow-wrap: anywhere;
}

/*
 * Rollen-Auswahl in einer Team-Zeile.
 *
 * Die allgemeine select-Regel setzt volle Breite und einen oberen Abstand —
 * beides ist in einer Zeile falsch, dort steht das Feld neben dem Text.
 * Die Mindesthöhe bleibt bei den 44 px der Safe-Area-Regel, damit das Feld
 * auf einem Telefon sicher zu treffen ist.
 */
.row-select {
  flex: 0 0 auto;
  width: auto;
  min-width: 132px;
  min-height: var(--tap-min);
  margin-top: 0;
}

/*
 * Auswahlfelder in einer Zeilen-Form (Rolle beim Einladen, Protokoll-Filter).
 * Ohne diese Regel wäre das Feld 100 % breit und schöbe den Knopf in die
 * nächste Zeile — auf 375 px sieht das aus wie ein Umbruchfehler.
 */
.inline-form select {
  flex: 0 0 auto;
  width: auto;
  min-width: 148px;
  min-height: var(--tap-min);
  margin-top: 0;
}

/* ── Kontrollkästchen ─────────────────────────────────────────────────── */

.check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  margin-top: var(--space-xl);
}
.check input {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  margin-top: var(--space-2xs);
  accent-color: var(--accent);
}
.check label {
  margin: 0;
  font-size: var(--text-base);
  color: var(--text);
  font-weight: 600;
}
.check .hint {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  font-weight: 400;
  margin-top: var(--space-2xs);
  display: block;
}
.saved {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-md);
  min-height: 18px;
}

/* ── Meldungen ────────────────────────────────────────────────────────── */

.msg {
  border-radius: 10px;
  padding: var(--space-md-plus) var(--space-lg);
  margin-top: var(--space-xl);
  font-size: var(--text-base);
  display: none;
}
.msg.ok {
  background: var(--success-soft);
  border: 1px solid var(--success);
  color: var(--text);
  display: block;
}
.msg.err {
  background: var(--danger-soft);
  border: 1px solid var(--danger);
  color: var(--text);
  display: block;
}

/* ── Balken-Verlauf (ohne Diagramm-Bibliothek) ────────────────────────── */

.chart {
  margin-top: var(--space-2xl);
}
.chart-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-xs) 0;
}
.chart-day {
  width: 52px;
  flex: 0 0 auto;
  font-size: var(--text-xs);
  color: var(--text-subtle);
}
.chart-track {
  flex: 1 1 auto;
  background: var(--surface-2);
  border-radius: 6px;
  height: 14px;
  overflow: hidden;
}
.chart-bar {
  background: var(--chart-bar);
  height: 100%;
  border-radius: 6px;
  min-width: 2px;
}
.chart-value {
  width: 52px;
  flex: 0 0 auto;
  text-align: right;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* ── Hinweis-Einblendung ──────────────────────────────────────────────── */

.toast {
  position: fixed;
  left: var(--space-lg);
  right: var(--space-lg);
  bottom: var(--space-xl);
  max-width: 520px;
  margin: 0 auto;
  border-radius: var(--radius-md);
  padding: var(--space-lg) var(--space-lg-plus);
  font-size: var(--text-base);
  z-index: var(--z-toast);
  box-shadow: var(--shadow-pop);
}
/*
 * 🔴 KEIN `display: none` hier — der Ruhezustand steht als Inline-Stil im
 * Markup. `toast()` blendet über `show()` ein, und das setzt nur den INLINE-Wert
 * zurück; gegen eine Regel aus dieser Datei kommt ein leerer Inline-Wert nicht
 * an. Solange das `display: none` hier stand, blieb JEDE Rückmeldung des Panels
 * unsichtbar — „Gespeichert.", „Einladung verschickt.", auch jede Fehlermeldung
 * aus `fail()`. Der Betreiber speicherte und bekam nichts zu sehen.
 * (Gefunden 06.08. beim Prüfen des Rollenwechsels; gleiche Ursache wie bei der
 * DJ-Trefferliste.)
 */
.toast.ok {
  background: var(--success);
  border: 1px solid var(--success);
  color: var(--text);
}
.toast.err {
  background: var(--danger);
  border: 1px solid var(--danger);
  color: var(--text);
}

.inline-form {
  display: flex;
  gap: var(--space-sm-plus);
  flex-wrap: wrap;
  align-items: flex-end;
  margin-top: var(--space-lg-plus);
}
.inline-form input {
  flex: 1 1 220px;
  width: auto;
}
.inline-form button {
  margin-top: 0;
  width: auto;
  flex: 0 0 auto;
}

/* ── Live-Status am Karten-Pin (pro Veranstaltung) ────────────────────── */

.row-stack {
  flex-wrap: wrap;
}
.status-box {
  flex: 1 1 100%;
  margin-top: var(--space-md);
  padding: var(--space-md-plus);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.status-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm-plus);
  flex-wrap: wrap;
}
.status-head .row-meta {
  margin-top: 0;
}
/* 44px Kantenlänge: das Emoji-Feld muss mit dem Daumen treffbar sein. */
.emoji-chip {
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.emoji-chip.on {
  background: var(--accent);
  border-color: var(--accent);
}
.emoji-row {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-top: var(--space-sm-plus);
}
/* Volle Symbol-Auswahl (Gruppen wie in WhatsApp) */
.emoji-more {
  font-size: var(--text-xl);
  line-height: 1;
  color: var(--text-muted);
}
.emoji-picker {
  margin-top: var(--space-sm-plus);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-sm-plus);
}
.emoji-tabs {
  display: flex;
  gap: var(--space-xs-plus);
  overflow-x: auto;
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--border);
  -webkit-overflow-scrolling: touch;
}
.emoji-tab {
  flex: 0 0 auto;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: var(--radius-full);
  padding: var(--space-xs-plus) var(--space-md);
  font-size: var(--text-sm);
  white-space: nowrap;
}
.emoji-tab.on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}
.emoji-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: var(--space-xs);
  max-height: 240px;
  overflow-y: auto;
  margin-top: var(--space-sm);
}
.emoji-cell {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.emoji-cell:hover {
  background: var(--surface-2);
}
.status-form {
  display: flex;
  gap: var(--space-sm-plus);
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--space-sm-plus);
}
.status-form input {
  flex: 1 1 200px;
  width: auto;
  margin: 0;
}
.status-form button {
  margin-top: 0;
  width: auto;
  flex: 0 0 auto;
}
.status-live {
  font-size: var(--text-sm);
  color: var(--accent-hover);
  margin-top: var(--space-sm);
}
.status-expired {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-sm);
}

/* ── Formular "Veranstaltung anlegen/bearbeiten" ──────────────────────── */
/* Zwei Spalten ab 640px: Beginn/Ende und Einlass/Preis gehören paarweise
   nebeneinander, sonst scrollt man auf dem Handy an zusammengehörigen
   Feldern vorbei. */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--space-lg);
}
.form-grid .full {
  grid-column: 1 / -1;
}
@media (max-width: 640px) {
  .form-grid {
    grid-template-columns: 1fr;
  }
}
.field-hint {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin: var(--space-xs) 0 0;
}

/* Bild und Line-up erscheinen erst, wenn die Veranstaltung existiert —
   vorher gibt es nichts, woran sie hängen könnten. */
.after-save {
  border-top: 1px solid var(--border);
  margin-top: var(--space-2xl);
  padding-top: var(--space-xl);
}
.ev-cover {
  width: 100%;
  max-width: 420px;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  margin: var(--space-md) 0;
  display: block;
}

/* ── Line-up ──────────────────────────────────────────────────────────── */

.dj-chips {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin: var(--space-md) 0 0;
}
.dj-chip {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  padding: var(--space-xs-plus) var(--space-xs-plus) var(--space-xs-plus) var(--space-md-plus);
  font-size: 14px;
  color: var(--text);
}
/* 32px Kantenlänge plus Abstand: kleiner wird das × zur Fehlklick-Falle. */
.dj-chip button {
  width: 32px;
  height: 32px;
  min-height: 32px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--bg);
  color: var(--text-muted);
  font-size: var(--control-font);
  line-height: 1;
  cursor: pointer;
  flex: 0 0 auto;
}
.dj-chip button:hover:not(:disabled) {
  background: var(--danger);
  color: var(--text);
}
/* Der Name im Chip öffnet die Angaben — als Button, damit er per Tastatur
   erreichbar ist, aber ohne Button-Optik (er sitzt mitten im Text). */
.dj-chip .dj-chip-name {
  width: auto;
  height: auto;
  min-height: 0;
  background: none;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  padding: 0;
  border-radius: 0;
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 3px;
}
.dj-chip .dj-chip-name:hover:not(:disabled) {
  background: none;
  color: var(--accent-hover);
}
/* 🔴 KEIN `display: none` hier. Der Ruhezustand steht als Inline-Stil im Markup.
   Grund: `show()` schaltet über `style.display = ''` — gegen eine CSS-Regel
   `display: none` ist das wirkungslos, die Regel gewinnt gegen den leeren
   Inline-Wert. Die DJ-Suche hat dadurch ihre Treffer gefunden, gerendert und
   unsichtbar gelassen: darunter stand "Nicht der Richtige dabei?" (das erscheint
   NUR bei Treffern) über einer leeren Fläche, und "Paul Kalkbrenner" schien nicht
   im Katalog zu sein, obwohl die API ihn liefert. Ruhezustände dieser Art gehören
   ins Markup, wie bei jedem anderen Element hier. */
.dj-results {
  margin-top: var(--space-sm-plus);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  max-height: 260px;
  overflow-y: auto;
}
.dj-hit {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  width: 100%;
  margin: 0;
  padding: var(--space-sm-plus) var(--space-md-plus);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-size: var(--text-base);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  min-height: 56px;
}
.dj-hit:last-child {
  border-bottom: 0;
}
.dj-hit:hover:not(:disabled) {
  background: var(--surface-2);
}
.dj-hit .ava {
  width: 36px;
  height: 36px;
  font-size: var(--text-sm);
}
/* Ein bereits übernommenes Profil pflegt der DJ selbst — der Club sieht das
   am Chip und bekommt gar nicht erst ein Formular angeboten. */
.dj-hit .own {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--text-subtle);
  flex: 0 0 auto;
}

/* ── DJ anlegen / ergänzen ────────────────────────────────────────────── */

.dj-form {
  margin-top: var(--space-lg);
  padding: var(--space-lg-plus);
  background: var(--surface-1);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
}
.dj-form h3 {
  font-size: var(--text-base);
  margin: 0 0 var(--space-xs-plus);
  font-weight: 700;
}
.dj-form label {
  margin-top: var(--space-md-plus);
}
/* Vorschlagszeile bei Namensähnlichkeit — bewusst auffällig, weil das Übergehen
   eine Dublette im 10.000er-Katalog erzeugt. */
.dup-hit {
  display: flex;
  align-items: center;
  gap: var(--space-sm-plus);
  width: 100%;
  margin: var(--space-xs-plus) 0 0;
  padding: var(--space-sm-plus) var(--space-md);
  background: var(--surface-2);
  border: 1px solid var(--accent-dark);
  border-radius: 10px;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  min-height: 48px;
}
.dup-hit:hover:not(:disabled) {
  background: var(--surface-3);
}

/* ── Fußzeile ─────────────────────────────────────────────────────────── */

.foot {
  font-size: var(--text-xs);
  color: var(--text-subtle);
  margin-top: var(--space-4xl);
  border-top: 1px solid var(--border);
  padding-top: var(--space-xl);
}
.foot a {
  color: var(--accent-text);
}

/* ── Nur für Screenreader ─────────────────────────────────────────────── */

/* Standard-Idiom für "nur für Screenreader". Die -1px sind kein Abstand,
   sondern Teil des Rezepts: das Element wird aus dem sichtbaren Fluss gezogen,
   ohne es per display:none aus dem Barrierefreiheits-Baum zu entfernen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px; /* token-check:allow */
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Kleine Bildschirme ───────────────────────────────────────────────── */

@media (max-width: 600px) {
  .venue-head h1 {
    font-size: var(--text-xl);
  }
  .tile-value {
    font-size: var(--text-2xl);
  }
  .row {
    flex-wrap: wrap;
  }
  /* Auf schmalen Geräten klebt sonst zu viel oben fest und vom Inhalt bleibt
     kaum Platz. */
  .tabs {
    top: 0;
    position: static;
  }
  .topbar {
    position: static;
  }
  /* 🔴 Engerer Abstand, sobald Sprache und Darstellung dazukommen: mit dem
     Desktop-Abstand belegte die Kopfzeile auf 375px DREI Zeilen und 197px Höhe
     — ein Viertel des Bildschirms, bevor der erste Inhalt anfängt. Mit 8px
     passen Marke + Sprache in die erste und Darstellung + Abzeichen + Abmelden
     in die zweite Zeile. Am 375px-Fenster nachgemessen, nicht geschätzt. */
  .topbar-inner {
    gap: var(--space-sm);
  }
  /*
   * 🔴 HIER WAREN AM HANDY FUENF REITER UNERREICHBAR (Fabi 22.08.2026,
   *    Screenshot vom Samsung: die Leiste endet mitten in „Followe“).
   *
   * Diese Regel stammt aus einer Zeit mit kurzen Reiternamen und wollte das
   * Scrollen VERMEIDEN: alle Reiter teilen sich den Platz (`flex: 1 1 0`),
   * dazu `overflow-x: visible`. Inzwischen heissen sie „Eventabschluss“,
   * „Einstellungen“, „Automatik“ — acht Stueck ergeben 755 px Inhalt auf
   * 375 px Bildschirm. Zusammen mit `.tabs { overflow: hidden }` am Elternteil
   * bedeutete `visible`: alles ab „Follower“ ist ABGESCHNITTEN und durch
   * nichts erreichbar — kein Wischen, kein Scrollbalken. Die halbe
   * Bedienung des Panels existierte am Telefon nicht.
   *
   * Die Regel bei max-width: 900px hatte den Denkfehler schon korrigiert
   * („Natuerliche Breite behalten statt schrumpfen“) — nur blieb dieser
   * aeltere Block daneben stehen und gewann fuer `overflow-x`.
   *
   * Jetzt dasselbe Verhalten wie auf dem Tablet: wischbar, mit dem
   * Verlauf am rechten Rand als Zeichen, dass es weitergeht.
   */
  .tabs-inner {
    padding: 0 var(--space-sm-plus);
    overflow-x: auto;
  }
  .tab {
    /* NICHT `flex: 1 1 0`: Acht Reiter auf 375 px waeren 47 px pro Stueck —
       darin steht von „Eventabschluss“ nichts Lesbares mehr. */
    flex: 0 0 auto;
    min-width: 0;
    padding: var(--space-lg) var(--space-sm);
    font-size: 14px;
    text-align: center;
  }
}

@media (max-width: 480px) {
  .wrap--narrow {
    padding: var(--space-3xl) var(--space-lg) var(--space-4xl);
  }
  .wrap--narrow h1 {
    font-size: var(--text-2xl);
  }
}

/* ── Ladegerüst (statt Spinner) ───────────────────────────────────────── */

/*
 * 🔴 Die grauen Flächen haben die Maße der echten Inhalte. Ein Gerüst, das
 * anders aussieht als das, was kommt, lässt die Seite beim Umschalten springen
 * — und dann ist es schlechter als ein schlichter Ladehinweis.
 *
 * Die Bewegung liegt in `background-position`, nicht in `transform`: so bleibt
 * die Fläche ruhig stehen und es entsteht kein Layout-Neuaufbau. Wer
 * Bewegung abbestellt hat, bekommt sie nicht (siehe tokens.css).
 */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--surface-1) 0%,
    var(--surface-2) 40%,
    var(--surface-1) 80%
  );
  background-size: 300% 100%;
  border-radius: var(--radius-md);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.skeleton-title {
  height: 32px;
  width: 60%;
  margin-top: var(--space-2xl);
}
.skeleton-line {
  height: 16px;
  width: 40%;
  margin-top: var(--space-md);
  margin-bottom: var(--space-xl);
}
.skeleton-tile {
  height: 96px;
}
.skeleton-card {
  height: 180px;
  margin-top: var(--space-xl);
}
/* Zeilen-Gerüst in einer Liste (Events, Team, Protokoll). */
.skeleton-row {
  height: 56px;
  margin-top: var(--space-md-plus);
}

/* ── Speicher-Status des Profils ──────────────────────────────────────── */

.save-state {
  /* 🔴 Die Breite gehoert HIERHER, nicht als `sp-12` ins Markup: `tabs/profile.js`
     setzt beim Speichern fuenfmal `box.className = 'save-state is-…'` und wischt
     damit jede weitere Klasse weg. Solange das Element durch ein kaputtes </div>
     ausserhalb des Rasters hing, fiel das nicht auf; seit es (01.09.2026) im
     Profil-Raster steht, wurde daraus eine 72px schmale Spalte, in der
     „Aenderungen werden automatisch gespeichert." Wort fuer Wort untereinander
     stand. Als CSS-Regel der Komponente kann kein className-Zuweisung sie
     entfernen. */
  grid-column: span 12;
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-xl);
  min-height: 20px;
}
.save-state.is-busy {
  color: var(--text-subtle);
}
.save-state.is-ok {
  color: var(--accent-text);
}
.save-state.is-error {
  color: var(--danger);
  font-weight: 600;
}

/* ── Schnellzugriff (Strg/Cmd + K) ────────────────────────────────────── */

.palette-overlay {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  z-index: var(--z-overlay);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--space-4xl) var(--space-lg);
}
.palette {
  width: 100%;
  max-width: 520px;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  box-shadow: var(--shadow-pop);
  max-height: 70vh;
  display: flex;
  flex-direction: column;
}
.palette input {
  margin-top: 0;
  min-height: var(--tap-min);
}
.palette-list {
  margin-top: var(--space-md);
  overflow-y: auto;
}
/*
 * Jede Zeile ist ein echter Knopf: so ist sie mit Tabulator erreichbar und wird
 * von Vorlesehilfen als bedienbar angesagt. Ein <div> mit Klick-Behandlung wäre
 * für die Maus identisch und für alles andere unsichtbar.
 */
.palette-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text);
  min-height: var(--tap-min);
  padding: var(--space-md) var(--space-md-plus);
  margin-top: var(--space-2xs);
  border-radius: var(--radius-md);
  font-size: var(--control-font);
}
.palette-item.is-active {
  background: var(--surface-2);
  border-color: var(--border-strong);
}
.palette-hint {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin-top: var(--space-md);
}

@media (max-width: 480px) {
  /*
   * Auf dem Telefon näher an den Rand: 70 vh Höhe brauchen den Platz.
   *
   * 🔴 Oben und unten mit `env(safe-area-inset-*)`, obwohl das Panel im Browser
   * läuft: als zum Startbildschirm hinzugefügte Web-App gibt es keine
   * Browserleiste mehr, und dann liegt das Eingabefeld unter der Statusleiste
   * bzw. die letzte Zeile auf dem Navigationsbalken. `max()` sorgt dafür, dass
   * der gewohnte Abstand gilt, wo es keine Aussparung gibt.
   */
  .palette-overlay {
    padding: max(var(--space-2xl), env(safe-area-inset-top))
             var(--space-md)
             max(var(--space-lg), env(safe-area-inset-bottom));
  }
  /* Die Tastenhilfe nennt Tasten, die es hier nicht gibt. */
  .palette-hint {
    display: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   WEICHES GATING — gesperrte Funktionen bleiben SICHTBAR (#97, Modul 3.8)

   Der Inhalt der Karte wird unscharf, nicht verdeckt: der Betreiber soll
   erkennen, dass hinter der Sperre seine EIGENEN Daten liegen. Ein grauer
   Kasten mit "Pro buchen" verkauft nichts, weil er nichts zeigt.

   🔴 Der Ruhezustand steht hier NICHT als `display:none`. Das Band wird vom
   Skript erzeugt und wieder entfernt (lockCard/unlockCard) — eine
   CSS-Regel dagegen wäre dieselbe Falle, die am 06.08. die DJ-Trefferliste
   und jede Rückmeldung des Panels unsichtbar gemacht hat.
   ═══════════════════════════════════════════════════════════════════════ */

.is-locked {
  position: relative;
  /* Der Schleier darf nicht über die abgerundeten Ecken hinauslaufen. */
  overflow: hidden;
}

/*
 * Alles außer dem Band selbst wird weichgezeichnet.
 *
 * 🔴 `pointer-events:none` ist hier KEINE Absicherung, sondern Kosmetik: die
 * Bedienelemente sind zusätzlich echt `disabled` (siehe lockCard), sonst
 * liefe der Tabulator weiter durch eine Maske, die man nicht lesen kann.
 */
.is-locked > *:not(.pro-veil) {
  filter: blur(var(--locked-blur));
  pointer-events: none;
  user-select: none;
}

/*
 * 🔴 Gesperrte Karten brauchen Platz fuer ihr Band.
 * Das Band liegt `position:absolute` ueber der Karte und zentriert seinen
 * Inhalt — ist der Inhalt hoeher als die Karte, laeuft er oben UND unten
 * heraus und liegt auf der Nachbarkarte. Gemessen am 19.08.2026 im Reiter
 * „Publikum": 137px Ueberlauf bei der Vergleichs-Karte, 58px bei der
 * Push-Karte. Betroffen ist jede kurze Karte mit langem Verkaufstext.
 * 15rem deckt das laengste Band (218px) samt Rahmen ab; groessere Karten
 * bleiben unberuehrt, weil `min-height` nur nach unten begrenzt.
 */
.is-locked {
  min-height: 15rem;
}

.pro-veil {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-xl);
  background: var(--locked-veil);
  z-index: var(--z-sticky);
}

.pro-veil-box {
  max-width: 420px;
  text-align: center;
}

/*
 * "Im Pro-Plan enthalten" — als Fläche, nicht als Text in Akzentfarbe:
 * reines Orange auf Creme erreicht nur 2:1 und wäre im hellen Panel
 * unlesbar (siehe --accent-text in tokens.css).
 */
.pro-veil-badge {
  display: inline-block;
  margin: 0 0 var(--space-sm);
  padding: var(--space-xs) var(--space-md);
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.pro-veil-text {
  margin: 0 0 var(--space-sm);
  color: var(--text);
  font-size: var(--text-base);
  line-height: 1.45;
}

/*
 * Die eigene Zahl. Sie steht SCHARF vor dem unscharfen Hintergrund und ist
 * der eigentliche Beweis, dass die Sperre echte Daten verdeckt.
 */
.pro-veil-fact {
  margin: 0 0 var(--space-md);
  color: var(--accent-text);
  font-size: var(--text-md);
  font-weight: 700;
}

.pro-veil-hint {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.pro-veil-cta {
  min-height: var(--tap-min);
  padding: var(--space-md) var(--space-xl);
  border: none;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--on-accent);
  font-family: inherit;
  font-size: var(--control-font);
  font-weight: 700;
  cursor: pointer;
}
.pro-veil-cta:hover {
  background: var(--accent-hover);
}

/*
 * Auf dem Telefon steht die Karte hochkant und das Band nimmt ihr sonst die
 * ganze Höhe. Oben andocken statt mittig: der erste Blick fällt auf das
 * Angebot, der Rest der Karte bleibt daneben sichtbar.
 */
@media (max-width: 480px) {
  .pro-veil {
    align-items: flex-start;
    padding: var(--space-lg) var(--space-md);
  }
}

/* ── Gäste von außen holen: Aushang, QR, Widget (Modul 3.7) ─────────────── */

/*
 * Zwischenüberschriften innerhalb einer Karte. Es gab bisher keine — die
 * Karte trägt drei getrennte Angebote (Aushang, QR, Website) und wäre als
 * eine Textwand nicht zu überfliegen.
 */
.card h3 {
  margin: var(--space-2xl) 0 var(--space-2xs);
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--text);
}
.card h3:first-of-type {
  margin-top: var(--space-lg);
}

/*
 * Die QR-Vorschau. Weiße Fläche mit Rand, weil der Code auf dem dunklen
 * Kartengrund sonst zwar zu sehen, aber nicht zu scannen wäre — die Ruhezone
 * ringsum gehört zum Code.
 */
.qr-preview {
  display: block;
  width: 160px;
  height: 160px;
  margin-top: var(--space-md);
  padding: var(--space-sm);
  background: var(--qr-quiet);
  border-radius: var(--radius-md);
}

/*
 * Der Einbett-Schnipsel. Feste Schrift, weil dort Quelltext steht: in der
 * Fließtextschrift lassen sich l und 1 nicht unterscheiden, und wer den
 * Schnipsel abtippt statt kopiert, baut sich genau da einen Fehler ein.
 */
#embedSnippet {
  font-family: ui-monospace, monospace;
  font-size: var(--text-sm);
  white-space: pre-wrap;
  word-break: break-all;
}

/* ═══════════════════════════════════════════════════════════════════════
   REDESIGN 17.08.2026 — HIERARCHIE STATT GLEICHFÖRMIGKEIT

   Ausgangslage: 26 identische `.card`-Blöcke, gestapelt in einer Spalte, jede
   mit Überschrift + Erklärabsatz + Feldern. Auf jedem der sechs Reiter derselbe
   Bauplan — deshalb sah für den Betreiber jeder Reiter gleich aus.

   Drei Eingriffe, in dieser Reihenfolge wirksam:
     1. Der Erklärabsatz wandert in eine Sprechblase. Er verschwindet nicht,
        er wird abrufbar — das nimmt jeder Karte die drei grauen Zeilen, die
        sie ihrer Nachbarin gleich machten.
     2. Karten bekommen Typen (Kennzahl / Formular / Liste / Diagramm) und ein
        Raster statt einer Spalte. Unterschiedliche Inhalte dürfen
        unterschiedlich breit sein.
     3. Jeder Reiter bekommt einen eigenen Kopf mit Symbol und eigener
        Anordnung.

   🔴 KEINE zweite Akzentfarbe je Reiter. Sechs Farben für sechs Reiter wären
   die naheliegende Lösung und die falsche: das Panel hat genau einen Akzent
   (Ember-Orange), und der bedeutet "hier handeln". Färbt man Reiter ein,
   konkurriert jede Kopfzeile mit jedem Knopf. Die Unterscheidung trägt hier
   die STRUKTUR, nicht die Farbe.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Sprechblase ──────────────────────────────────────────────────────── */

/*
 * Ein Element für die ganze Seite, am body statt in der Karte — eine Karte
 * mit overflow würde die Blase sonst abschneiden.
 * position:fixed, weil das Panel scrollt und die Kopfzeile klebt.
 */
.tip {
  position: fixed;
  z-index: var(--z-toast);
  max-width: 320px;
  padding: var(--space-sm-plus) var(--space-md);
  background: var(--tip-bg);
  color: var(--tip-text);
  border: 1px solid var(--tip-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-tip);
  font-size: var(--text-sm);
  line-height: 1.5;
  /* Die Blase darf den Zeiger nie abfangen — sonst löst ihr eigenes Erscheinen
     unter dem Cursor ein mouseout am Auslöser aus und sie schließt sich
     sofort wieder (Flackern). */
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.tip.is-offen {
  opacity: 1;
  transform: translateY(0);
}

/* Der Zeiger. --tip-pfeil setzt das Skript auf die Mitte des AUSLÖSERS, nicht
   der Blase: am Fensterrand wird die Blase verschoben, der Zeiger muss trotzdem
   auf sein Element deuten. */
.tip::after {
  content: '';
  position: absolute;
  left: var(--tip-pfeil, 50%);
  /* Halbe Pfeilbreite (border: 6px) — zentriert die Spitze auf dem Zielpunkt.
     Gemessene Geometrie dieses einen Dreiecks, kein Abstands-Token: als Token
     wäre der Wert an die Rahmenbreite direkt darunter nicht mehr gekoppelt. */
  margin-left: -6px; /* token-check:allow */
  border: 6px solid transparent;
  border-top-color: var(--tip-bg);
  top: 100%;
}
.tip--unten::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: var(--tip-bg);
}

/*
 * Der Auslöser. Ein echter button, damit er ohne tabindex in der
 * Tabreihenfolge liegt und die Tastatur ihn erreicht.
 *
 * 🔴 Die sichtbare Fläche ist 18px, die TREFFERfläche 44px (::before). Ein
 * 18px-Ziel ist am Telefon nicht sicher zu treffen (WCAG 2.5.5), ein 44px
 * großes graues Rondell neben jeder Überschrift wäre optisch untragbar.
 * Getrennt zu behandeln löst beides.
 */
.tip-knopf {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  /*
   * 🔴 `min-height`, `min-width` und `margin` müssen ausdrücklich zurückgesetzt
   * werden. Die Grundregel für `button` (weiter oben in dieser Datei) setzt
   * `width: 100%`, `min-height: 52px` und `margin-top: 24px` — gedacht für die
   * großen Handlungsknöpfe. `min-height` schlägt jede `height`-Angabe, der
   * Knopf wurde dadurch zu einer 18 × 52 px hohen orangen Kapsel neben der
   * Überschrift statt zu einem Kreis (am Bildschirm gesehen, 17.08.).
   */
  min-height: 0;
  min-width: 0;
  margin: 0 0 0 var(--space-xs-plus);
  vertical-align: middle;
  background: var(--icon-bg);
  color: var(--icon-fg);
  border: 0;
  border-radius: var(--radius-full);
  cursor: help;
  flex: 0 0 auto;
  transition:
    background var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}
.tip-knopf::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tap-min);
  height: var(--tap-min);
  transform: translate(-50%, -50%);
}
.tip-knopf:hover,
.tip-knopf[aria-expanded='true'] {
  background: var(--accent);
  color: var(--on-accent);
}
.tip-knopf:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
/* Gezeichnetes Hinweiszeichen — siehe Begründung in core/tooltip.js. */
.tip-knopf-zeichen {
  width: 11px;
  height: 11px;
  display: block;
}

/* ── Reiter-Kopf ──────────────────────────────────────────────────────── */

/*
 * Jeder Reiter beginnt mit derselben Zeile — Symbol, Name, ein Satz Zweck —
 * aber mit je eigenem Symbol und eigenem Satz. Das ist die billigste und
 * wirksamste Ortsangabe: der Betreiber sieht beim Wechsel sofort, wo er ist.
 */
.reiter-kopf {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  margin: var(--space-lg) 0 var(--space-2xl);
}
.reiter-symbol {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  background: var(--icon-bg);
  color: var(--icon-fg);
  border-radius: var(--radius-md);
}
.reiter-symbol svg {
  width: 20px;
  height: 20px;
  /* Eine Strichstärke im ganzen Panel. Gemischte Stärken lesen sich als
     Versehen, nicht als Absicht. */
  stroke-width: 1.75;
}
.reiter-titel {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: var(--line-display);
  margin: 0;
  letter-spacing: -0.01em;
}
.reiter-zweck {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  margin: 0;
  max-width: 62ch;
  text-wrap: pretty;
}

/* ── Raster ───────────────────────────────────────────────────────────── */

/*
 * Zwölf Spalten. Karten belegen 12 / 8 / 6 / 4 davon — dadurch entstehen
 * Zeilen mit zwei ungleichen Karten statt immer einer vollbreiten.
 *
 * 🔴 Umbruch bei 860px auf eine Spalte, NICHT über auto-fit. Ein
 * Automatikraster entscheidet nach Platz und stellt dann etwa Formular und
 * Vorschau nebeneinander, die inhaltlich übereinander gehören. Die Breiten
 * sind hier eine Aussage über den Inhalt, keine über den Bildschirm.
 */
/*
 * 🔴 `minmax(0, 1fr)` UND NICHT `1fr`.
 *
 * `1fr` ist die Kurzform von `minmax(auto, 1fr)`. Das `auto`-Minimum
 * bedeutet: die Spalte darf NIE schmaler werden als der breiteste Inhalt
 * darin. Ein einziges Kind, das nicht umbrechen kann — hier das
 * Stunden-Diagramm mit 24 Saeulen — zieht damit die ganze Spalte auf.
 *
 * Gemessen am 22.08.2026 auf einem 390-px-Bildschirm: Container 375 px,
 * BERECHNETE SPALTE 817 px. Das komplette Dashboard liess sich waagerecht
 * schieben, die Reiterleiste war rechts abgeschnitten. Mit `minmax(0, 1fr)`:
 * 343 px. Fabi hatte es auf dem Handy sofort gesehen, hier stand es seit
 * dem ersten Tag.
 */
.raster {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-lg);
  align-items: start;
}
.sp-4 { grid-column: span 4; }
.sp-6 { grid-column: span 6; }
.sp-8 { grid-column: span 8; }
.sp-12 { grid-column: span 12; }

@media (max-width: 860px) {
  .raster { grid-template-columns: minmax(0, 1fr); }
  .sp-4,
  .sp-6,
  .sp-8,
  .sp-12 { grid-column: 1 / -1; }
}

/*
 * Karten im Raster tragen ihren Abstand über gap. Die alte .card bringt
 * margin: 24px 0 mit — im Raster summiert sich das mit dem gap zu einer
 * doppelten Lücke, die wie ein Fehler aussieht.
 */
.raster > .card {
  margin: 0;
}

/*
 * 🔴 KEINE erzwungene Gleichhöhe (`height: 100%`) — das stand hier zuerst und
 * war falsch. Es widerspricht `align-items: start` am Raster, und wo eine kurze
 * Karte neben einer langen steht, streckt es sie zu einer halbleeren Fläche.
 * Karten dürfen unterschiedlich hoch sein; sie stehen oben bündig, und das
 * reicht als Ordnung.
 */

/* ── Karte, überarbeitet ──────────────────────────────────────────────── */

/*
 * 🔴 Der Rahmen verschwindet, der Schatten übernimmt. Rahmen UND Schatten UND
 * Fläche gleichzeitig ist die generische Standardkarte; eine Kante reicht, um
 * eine Fläche vom Blatt zu lösen. Der Schatten ist über --shadow-card in der
 * Hintergrundfarbe getönt, nicht neutral schwarz.
 */
.card {
  box-shadow: var(--shadow-card);
  transition:
    border-color var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}

/*
 * 🔴 KORREKTUR 18.08.2026: Hier stand `border-color: transparent` — der Rahmen
 * sollte durch den Schatten ersetzt werden, wie es für helle Oberflächen
 * richtig ist. Im Dunkelmodus ist das falsch: ein schwarzer Schatten unter
 * einer dunklen Karte auf dunklem Grund ist unsichtbar, und ohne Rahmen
 * verschwimmt alles zu einer einzigen Fläche. Genau das meinte Fabi mit
 * "alles zu dunkel" — es fehlte nicht Helligkeit, es fehlte TRENNUNG.
 * Die Kante bleibt also, und sie ist in tokens.css deutlicher geworden.
 */

/* Beim Überfahren hebt sich die Karte leicht — zeigt, dass sie ein
   zusammenhängender Bereich ist, ohne dass etwas springt. */
.card:hover {
  border-color: var(--border-strong);
}

/* Kopfzeile der Karte: Titel und Info-Knopf in einer Zeile, Werkzeuge rechts. */
.karte-kopf {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.karte-kopf h2 {
  margin: 0;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.karte-werkzeug {
  flex: 0 0 auto;
  display: flex;
  gap: var(--space-sm);
}

/*
 * Karte mit betonter Bedeutung — für die eine Karte pro Reiter, wegen der man
 * den Reiter überhaupt öffnet (Status heute, nächster Termin).
 * Die Betonung liegt in einer Kante, nicht in einer Füllung: eine orange
 * Fläche würde den Handlungsknopf darin unsichtbar machen.
 */
.card--betont {
  /* Kein Kantenbalken mehr (Fabi 21.08.2026) — siehe Kommentar oben.
     Die Betonung kommt aus dem Licht: derselbe Schein wie auf der
     Hauptflaeche, dazu eine etwas hellere Kante. */
  /* 🔴 KEIN eigener Verlauf mehr: `.card` traegt ihn seit dem 22.08.2026
     selbst, und `card card--betont` ergab ihn doppelt — ein
     schmutziger Fleck statt Tiefe. Die Betonung kommt aus Rahmen
     und Schein. */
  background: var(--surface-1);
  border-color: var(--border-strong);
}

/* Ruhige Karte für Nebensächliches (Rechtstexte, Geräteliste): keine Erhebung,
   nur eine leise Kante. Nicht alles auf einer Seite darf gleich laut sein. */
.card--leise {
  background: transparent;
  box-shadow: none;
  border-color: var(--border);
}

/* ── Kennzahlen ───────────────────────────────────────────────────────── */

/*
 * 🔴 font-variant-numeric: tabular-nums. In der Proportionalschrift ist die 1
 * schmaler als die 8 — untereinanderstehende Zahlen tanzen dann, und ein
 * Zahlenwechsel beim Nachladen verschiebt die Kachelbreite sichtbar.
 */
.tile-value {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* Die eine Zahl, um die es auf dem Reiter geht — deutlich größer als ihre
   Nachbarn. Gleich große Kacheln behaupten gleiche Wichtigkeit. */
.tile--haupt .tile-value {
  font-size: 42px;
}
.tile--haupt {
  grid-column: span 2;
}
@media (max-width: 620px) {
  .tile--haupt { grid-column: span 1; }
}

/*
 * Verlaufslinie in der Kachel. Bewusst ohne Achsen und Beschriftung: sie
 * beantwortet "steigt oder fällt das", nicht "auf welchen Wert genau" — die
 * genaue Zahl steht als Ziffer darüber. Eine Achse hier würde eine
 * Ablesbarkeit vortäuschen, die eine 34px hohe Linie nicht hat.
 */
.tile-linie {
  display: block;
  width: 100%;
  height: 34px;
  margin-top: var(--space-sm);
  overflow: visible;
}
.tile-linie path {
  fill: none;
  stroke: var(--chart-bar);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.tile-linie .flaeche {
  fill: var(--chart-bar);
  stroke: none;
  opacity: 0.14;
}

/* ── Zustände ─────────────────────────────────────────────────────────── */

/*
 * Ladegerüst mit Schimmer. Bei prefers-reduced-motion steht die Animation
 * still (Regel am Ende von tokens.css) — die grauen Flächen bleiben trotzdem
 * und halten die Höhe, worum es hier eigentlich geht.
 */
.skeleton {
  background: linear-gradient(90deg, var(--skeleton) 25%, var(--skeleton-hell) 37%, var(--skeleton) 63%);
  background-size: 400% 100%;
  animation: schimmer 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
}
@keyframes schimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/*
 * Leerzustand. Eine leere Liste ohne Erklärung liest sich wie ein Fehler —
 * der Betreiber sucht dann nach dem Defekt statt nach dem nächsten Schritt.
 */
.leer {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--space-3xl) var(--space-xl);
  color: var(--text-muted);
}
.leer-symbol {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: var(--space-md);
  background: var(--icon-bg);
  color: var(--icon-fg);
  border-radius: var(--radius-full);
}
.leer-titel {
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--text);
  margin: 0 0 var(--space-xs);
}
.leer-text {
  font-size: var(--text-sm);
  margin: 0 0 var(--space-lg);
  max-width: 46ch;
  text-wrap: pretty;
}

/* ── Fokus und Bewegung ───────────────────────────────────────────────── */

/*
 * 🔴 Ein sichtbarer Fokusring auf ALLEM, was Fokus bekommen kann. Das Panel
 * wird an einem Bürorechner bedient, oft mit der Tastatur; ohne Ring weiß
 * niemand, wo er steht. :focus-visible statt :focus — sonst bekommt auch
 * der Mausklick einen Ring, was wie ein hängengebliebener Zustand aussieht.
 */
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Gedrückt-Rückmeldung. Ohne sie fühlt sich ein Klick an, als wäre er ins
   Leere gegangen — besonders dort, wo die Antwort vom Server kommt. */
button:not(:disabled):active {
  transform: translateY(1px);
}

/* Anker springen nicht mehr, sie fahren. */
html {
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/*
 * Veranstaltungsliste: feste Zeilenform.
 *
 * 🔴 Seit die Liste im Raster nur noch 8 von 12 Spalten belegt (Redesign
 * 17.08.), reicht die Breite nicht mehr für Titel + Abzeichen + drei Knöpfe in
 * einer Zeile. `row-stack` liess sie umbrechen — aber je nach Titellänge mal
 * nach dem zweiten, mal nach dem dritten Knopf. Über zwanzig Termine ergab das
 * ein Zickzack, in dem das Auge "Bearbeiten" jedes Mal neu suchen muss.
 *
 * Deshalb bricht die Zeile jetzt IMMER an derselben Stelle: Titel und Angaben
 * über die volle Breite, darunter Abzeichen und Knöpfe. Gleichförmig ist hier
 * richtig — anders als bei den Karten ist eine Liste eine Wiederholung
 * desselben Dings, und die soll man scannen können, ohne zu lesen.
 */
#eventList .row {
  align-items: flex-start;
  row-gap: var(--space-sm);
}
#eventList .row-main {
  flex: 1 1 100%;
}

/* ═══════════════════════════════════════════════════════════════════════
   MOBIL (18.08.2026)

   🔴 DER BEFUND, DER DAS AUSGELÖST HAT: Fabi hat das Redesign am Telefon
   geöffnet und "rein gar keine Veränderung" gesehen — zu Recht. Gemessen:
   auf 375px sind ALLE Karten 335px breit, egal ob sp-4, sp-8 oder sp-12.
   Das Raster, der größte Eingriff des Redesigns, ist unterhalb von 860px
   per Konstruktion wirkungslos. Übrig blieben Reiterkopf und Info-Knöpfe —
   zu wenig, um beim Aufmachen aufzufallen.

   Am Telefon entscheidet nicht die Anordnung nebeneinander, sondern was
   ÜBERHAUPT auf den ersten Bildschirm passt. Vorher: 210px Schalterleiste,
   bevor der erste Inhalt kam. Genau da wird hier gespart.
   ═══════════════════════════════════════════════════════════════════════ */

@media (max-width: 760px) {
  /*
   * 🔴 Sprache und Darstellung verlassen die Kopfleiste. Das sind zwei
   * Schaltergruppen mit zusammen fünf Feldern, die auf dem Telefon eine
   * eigene Zeile brauchen — für eine Einstellung, die man einmal trifft und
   * dann nie wieder.
   *
   * KEIN Funktionsverlust: unter Einstellungen → Darstellung stehen dieselben
   * Schalter (`renderDisplaySwitches` in core/chrome.js). Sie lösen die hier
   * versteckten Knöpfe per `.click()` aus — was auch bei `display:none`
   * funktioniert, weil ein Klick per Skript keine Sichtbarkeit braucht.
   * Deshalb dürfen die Knoten NICHT entfernt, sondern nur ausgeblendet werden.
   */
  .topbar .seg {
    display: none;
  }

  .topbar-inner {
    padding: var(--space-sm-plus) var(--space-lg);
    gap: var(--space-sm-plus);
  }

  /* Die Club-Auswahl ist am Telefon das einzige, was oben wirklich gebraucht
     wird — sie bekommt den frei gewordenen Platz. */
  .topbar select {
    flex: 1 1 auto;
    min-width: 0;
  }

  /*
   * 🔴 Der Klebepunkt der Reiterleiste MUSS mitwandern. `.tabs` klebt mit
   * `top: 61px` unter der Kopfleiste — das ist deren gemessene Höhe am
   * Rechner. Wird die Leiste mobil niedriger und der Wert bleibt stehen,
   * entsteht ein Streifen Hintergrund zwischen beiden, durch den der Inhalt
   * beim Scrollen sichtbar durchläuft.
   */
  /*
   * 🔴 Am Telefon klebt die Kopfleiste NICHT mehr. Gemessen: sie ist dort 164px
   * hoch (drei umgebrochene Zeilen) — das ist ein Fünftel des Bildschirms, das
   * dauerhaft für Logo und Abmelden draufginge. Und `.tabs` klebte mit einem
   * festen `top`, das für die einzeilige Leiste am Rechner gemessen war; mobil
   * wäre die Reiterleiste dadurch 107px zu hoch gesprungen und unter der
   * Kopfleiste verschwunden.
   *
   * Jetzt scrollt die Kopfleiste weg und NUR die Reiterleiste bleibt oben —
   * das, was man beim Arbeiten wirklich dauernd braucht. Nebenbei entfällt
   * jede Höhenrechnerei: `top: 0` stimmt immer.
   */
  .topbar {
    position: static;
  }
  .tabs {
    top: 0;
    margin-top: var(--space-md);
  }

  /*
   * 🔴 Der Überlauf der Seite kam aus der Reiterleiste: sechs Reiter ergeben
   * 393px Inhalt auf 375px Bildschirm. `.tabs-inner` durfte zwar seitwärts
   * scrollen, aber ohne Begrenzung am Elternteil zog es die GANZE Seite mit —
   * sichtbar als waagerechter Scrollbalken unter jedem Bildschirm.
   */
  .tabs {
    overflow: hidden;
    /* Nötig für den Verlauf unten — der klebt am rechten Rand DIESER Leiste. */
    position: sticky;
  }
  .tabs-inner {
    max-width: 100%;
    /* Die Leiste soll wischbar wirken: der letzte Reiter darf nicht bündig an
       der Kante enden, sonst sieht sie aus, als wäre sie zu Ende. */
    padding-right: var(--space-3xl);
    scroll-behavior: smooth;
  }

  /*
   * Verlauf am rechten Rand: das einzige, was am Telefon zeigt, dass hinter
   * "Einstellungen" noch etwas liegt. Sechs Reiter brauchen 393px, der
   * Bildschirm hat 375 — ohne dieses Zeichen endet die Leiste für den
   * Betreiber sichtbar bei "Publikum", und die letzten Reiter existieren für
   * ihn nicht.
   *
   * `pointer-events: none`, sonst fängt der Streifen genau die Wischgeste ab,
   * zu der er auffordert.
   */
  .tabs::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 36px;
    height: 100%;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--bg));
  }

  /*
   * Der Schnellzugriff verschwindet am Telefon. Er ist ein Tastaturwerkzeug
   * (Strg/Cmd + K) für Vielnutzer am Rechner; auf einem Telefon gibt es die
   * Tastenkombination nicht, und dieselben Wege stehen in der Reiterleiste.
   * Eine ganze Zeile Kopfleiste dafür ist der falsche Tausch.
   */
  #btnPalette {
    display: none;
  }
  .tabs-inner {
    padding: 0 var(--space-md);
    gap: 0;
  }
  .tab {
    padding: var(--space-md) var(--space-sm-plus);
    font-size: var(--text-sm);
    min-height: var(--tap-min);
  }

  /* Der Kopfbereich mit Clubnamen: am Telefon reicht der halbe Abstand. */
  .venue-head {
    padding: var(--space-xl) var(--space-lg) 0;
  }
  .wrap {
    padding: var(--space-lg) var(--space-lg) var(--space-3xl);
  }

  /*
   * Karten dichter. 24px Polsterung auf 375px Bildschirmbreite kosten 13% der
   * Breite für Luft — am Rechner ist das Ruhe, am Telefon ist es Verlust.
   */
  .card {
    padding: var(--space-lg);
    border-radius: var(--radius-md);
  }
  .raster {
    gap: var(--space-md);
  }

  /* Der Reiterkopf rückt näher an den Inhalt. */
  .reiter-kopf {
    margin: var(--space-md) 0 var(--space-lg);
    gap: var(--space-sm-plus);
  }
  .reiter-symbol {
    width: 32px;
    height: 32px;
  }

  /*
   * Die Hauptkennzahl bekommt die volle Breite statt zwei von zwei Spalten:
   * so steht sie als eigene Zeile über den kleineren Zahlen, statt mit ihnen
   * zu konkurrieren.
   */
  .tile--haupt {
    grid-column: 1 / -1;
  }
  .tile--haupt .tile-value {
    font-size: 34px;
  }
  .tiles {
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-sm-plus);
  }
  /* Ungerade Kachelzahl: die letzte fuellt die Zeile, statt eine leere
     Haelfte neben sich stehen zu lassen. Siehe Kommentar oben. */
  .tiles > .tile:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }
  .tile {
    padding: var(--space-md-plus);
  }

  /*
   * Sprechblasen dürfen am Telefon breiter werden als die 320px vom Rechner —
   * bei 375px Bildschirm blieben sonst 55px ungenutzt, und der Text bräche
   * eine Zeile mehr um.
   */
  .tip {
    max-width: calc(100vw - var(--space-2xl));
  }
}

/*
 * Zwischen Telefon und Rechner (Tablet, Telefon quer): zwei Spalten statt
 * einer. Das Zwölftelraster braucht dafür keine eigenen Regeln — es genügt,
 * die Spannen auf halbe und volle Breite zu falten.
 *
 * 🔴 Der Umbruch bei 860px war bis hierher ein harter Sprung von zwölf
 * Spalten auf eine. Ein 800px breites Fenster zeigte damit dieselbe
 * Einspaltigkeit wie ein Telefon — auf einer Fläche, die bequem zwei Karten
 * nebeneinander trägt.
 */
@media (min-width: 761px) and (max-width: 860px) {
  .raster {
    grid-template-columns: repeat(2, 1fr);
  }
  .sp-4,
  .sp-6 {
    grid-column: span 1;
  }
  .sp-8,
  .sp-12 {
    grid-column: span 2;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   MONATSKALENDER (18.08.2026)

   Das Element, das den Überblick von einem Formularstapel zu einer Ansicht
   macht: sieben Spalten, ein Feld je Tag, belegte Nächte hervorgehoben.
   ═══════════════════════════════════════════════════════════════════════ */

.kal-monat {
  font-size: var(--text-base);
  font-weight: 600;
  min-width: 128px;
  text-align: center;
  /* Feste Mindestbreite, sonst springt die Karte beim Blättern hin und her —
     "Mai 2026" ist deutlich kürzer als "September 2026". */
}

.kal-nav {
  width: var(--tap-min);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0;
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1;
}

.kal-kopf,
.kal-raster {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-xs);
}

.kal-kopf {
  margin-bottom: var(--space-sm);
}
.kal-wt {
  font-size: var(--text-xs);
  color: var(--text-subtle);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/*
 * Ein Tagesfeld. Quadratisch über `aspect-ratio`, damit das Raster bei jeder
 * Kartenbreite seine Form behält — mit fester Höhe würde es auf schmalen
 * Bildschirmen zu länglichen Kästen.
 */
.kal-tag {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  /*
   * 🔴 Quadratisch, ABER gedeckelt. Mit `aspect-ratio: 1` allein wurde ein
   * Tagesfeld auf einer 8-Spalten-Karte am Monitor ~90px hoch — der Kalender
   * füllte den halben Bildschirm und das Dashboard wirkte aufgeblasen statt
   * dicht. Die Höhengrenze hält die Felder bei jeder Kartenbreite in der
   * Größenordnung einer Schaltfläche.
   */
  aspect-ratio: 1;
  max-height: 58px;
  /* Die Grundwerte für `button` zurücksetzen — sonst gelten width:100%,
     min-height:52px und margin-top:24px aus der allgemeinen Regel. */
  width: auto;
  min-height: 0;
  margin: 0;
  padding: 0;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  transition:
    background var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease);
}

/* Leerfelder vor dem Monatsersten: sichtbar leer, nicht unsichtbar — sonst
   franst das Raster in der ersten Zeile aus. */
.kal-tag.is-leer {
  background: transparent;
}

/*
 * 🔴 Belegte Nächte tragen die Akzentfarbe als FLÄCHE. Das ist die einzige
 * Stelle im Panel, an der Orange großflächig steht, und sie ist es wert: der
 * ganze Zweck des Kalenders ist, dass man belegt und frei aus zwei Metern
 * Entfernung unterscheiden kann.
 */
.kal-tag.is-belegt {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
  cursor: pointer;
}
.kal-tag.is-belegt:hover {
  background: var(--accent-hover);
}

/* Heute: ein Ring, keine Füllung — sonst konkurriert der heutige Tag mit der
   Belegung, und beides zusammen wäre nicht mehr unterscheidbar. */
.kal-tag.is-heute {
  border-color: var(--text);
}

.kal-zahl {
  line-height: 1;
}

.kal-punkte {
  display: flex;
  /* Gemessener Abstand zwischen zwei 4px-Punkten — Geometrie dieses einen
     Zeichens, kein Abstands-Token. Als Token stuende ein Wert in der Palette,
     den nichts sonst je benutzt. */
  gap: 3px; /* token-check:allow */
  height: 4px;
}
.kal-punkt {
  width: 4px;
  height: 4px;
  border-radius: var(--radius-full);
  background: var(--on-accent);
  opacity: 0.75;
}

.kal-summe {
  font-variant-numeric: tabular-nums;
}

/*
 * Am Telefon werden die Felder kleiner, aber nicht kleiner als das
 * Antippmaß — deshalb schrumpft der Abstand, nicht die Zelle.
 */
@media (max-width: 760px) {
  .kal-kopf,
  .kal-raster {
    gap: var(--space-xs);
  }
  .kal-tag {
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
  }
  .kal-monat {
    min-width: 96px;
    font-size: var(--text-sm);
  }
}


/* ═══════════════════════════════════════════════════════════════════════
   REITERLEISTE ALS PILLEN (18.08.2026, nach Fabis Referenzen)

   Beide Vorlagen führen die Navigation als Gruppe abgerundeter Felder in
   einer eigenen Leiste — nicht als unterstrichene Reiter. Der Unterschied ist
   nicht nur Geschmack: eine Pillengruppe liest sich als EIN Bedienelement mit
   mehreren Zuständen, unterstrichene Reiter als Reihe einzelner Verweise.
   Für ein Dashboard mit sechs gleichrangigen Bereichen ist Ersteres richtig.
   ═══════════════════════════════════════════════════════════════════════ */

.tabs {
  border-bottom: 0;
}
.tabs-inner {
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-xl);
}
.tab {
  border-bottom: 0;
  border-radius: var(--radius-full);
  padding: var(--space-sm-plus) var(--space-lg);
  min-height: var(--tap-min);
  color: var(--text-muted);
}
.tab:hover:not(:disabled):not(.active) {
  background: var(--surface-2);
  color: var(--text);
}
/*
 * 🔴 Der offene Reiter bekommt eine FLÄCHE, keine Unterstreichung. Auf einer
 * Leiste ohne Trennlinie hinge ein Strich sonst frei im Raum. Helle Fläche mit
 * dunkler Schrift statt Orange: Orange ist im Panel die Farbe für "hier
 * handeln" — die Navigation sagt aber, wo man IST, nicht was zu tun ist.
 */
.tab.active {
  background: var(--text);
  color: var(--bg);
  border-bottom-color: transparent;
}

/* ═══════════════════════════════════════════════════════════════════════════
   VERLÄUFE — nach Design-Vorlage (Fabi 20.08.2026)
   ───────────────────────────────────────────────────────────────────────────
   Die Vorlage füllt ihre Akzentflächen nicht flach, sondern von hell nach
   dunkel, und legt einen weichen Schein unter das aktive Element. Übernommen
   wird genau das — mit dem Marken-Orange, nicht mit dem Grün der Vorlage.

   🔴 Bewusst als eigener Block am Dateiende statt als Änderung an den
   ursprünglichen Regeln: So steht an einer Stelle, was aus der Vorlage kommt,
   und ein Rückbau ist ein Löschen statt einer Rekonstruktion. Bei gleicher
   Spezifität gewinnt die spätere Regel — deshalb reicht die reine Wiederholung
   des Selektors, ohne `!important`.

   🔴 Alle Farbwerte kommen aus tokens.css (`--accent-gradient` etc.).
   Ein Verlauf ist mehrere Farbwerte; stünde er hier, schlüge check-panel-tokens an.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Aktiver Reiter: die tragende Fläche des Panels. */
.chip.active {
  background: var(--accent-gradient);
  box-shadow: var(--accent-glow);
}

/* Segment-Schalter (Sprache, Helligkeit) — kleiner, deshalb ohne Schein:
   zwei leuchtende Flächen nebeneinander nehmen einander die Bedeutung. */
.seg-btn.on {
  background: var(--accent-gradient);
}

/* Tarif-Abzeichen. */
.badge-pro {
  background: var(--accent-gradient);
}

/* Belegte Nächte im Kalender. */
.kal-tag.is-belegt {
  background: var(--accent-gradient);
}

/* Der Kauf-Knopf im Pro-Band — die einzige Fläche, die verkaufen soll,
   und deshalb die einzige mit Verlauf UND Schein. */
.pro-veil-cta {
  background: var(--accent-gradient);
  box-shadow: var(--accent-glow);
}

.pro-veil-cta:hover {
  background: var(--accent-gradient);
  filter: brightness(1.08);
}

/* Die Abo-Karte ist das Gegenstück zur Preiskarte der Vorlage: dunkler Grund,
   aus dem die Marke von unten links heraufglimmt, statt einer weiteren grauen
   Karte. Sie trägt den Preis und den Kauf-Knopf — und ist damit die einzige
   Fläche im Überblick, die etwas verkauft. */
#planCard {
  background: var(--accent-surface-gradient);
  border-color: var(--accent-dark);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SEITENLEISTE — nach Design-Vorlage (Fabi 20.08.2026)
   ───────────────────────────────────────────────────────────────────────────
   Die Vorlage führt ihre Navigation links als stehende Leiste, nicht als
   Reiterzeile. Umgesetzt wird das AUSSCHLIESSLICH über CSS: dieselben Knöpfe,
   dieselbe `setTab`-Logik, dieselben ARIA-Rollen — nur anders angeordnet.

   🔴 Warum kein Umbau des Markups: Die Reiter tragen `role="tablist"`,
   `aria-selected` und die IDs, an denen `router.js`, die Befehlspalette und
   die Sprachumschaltung hängen. Ein neues Gerüst hätte all das nachziehen
   müssen — für ein Ergebnis, das identisch aussieht.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 901px) {
  .tabs {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    margin-top: 0;
    padding: var(--space-2xl) var(--space-md) var(--space-xl);
    background: var(--surface-1);
    border-right: 1px solid var(--border);
    border-bottom: 0;
    overflow-y: auto;
    z-index: var(--z-topbar);
  }

  .tabs-inner {
    max-width: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    /* Platz für die Kopfzeile, die weiterhin oben über die volle Breite läuft. */
    margin-top: var(--space-4xl);
  }

  /* Aus dem unterstrichenen Reiter wird die vollflächige Zeile der Vorlage. */
  .tab {
    width: 100%;
    justify-content: flex-start;
    text-align: left;
    border-bottom: 0;
    border-radius: var(--radius-md);
    padding: var(--space-md) var(--space-md-plus);
  }

  .tab:hover {
    background: var(--surface-2);
    color: var(--text);
  }

  /* Der aktive Punkt ist in der Vorlage eine gefüllte Fläche mit dunkler
     Schrift — nicht ein farbiger Text. Deshalb Verlauf plus --on-accent. */
  .tab.active,
  .tab[aria-selected='true'] {
    background: var(--accent-gradient);
    border-bottom: 0;
    color: var(--on-accent);
    box-shadow: var(--accent-glow);
  }

  /* Kopfzeile und Inhalt rücken um die Leiste ein. */
  .topbar-inner,
  .wrap,
  .venue-head {
    margin-left: var(--sidebar-w);
  }

  /* `margin: 0 auto` der Ursprungsregel würde das Einrücken wieder aufheben —
     deshalb hier ausdrücklich linksbündig mit eigener Höchstbreite. */
  .topbar-inner,
  .wrap {
    margin-right: auto;
    max-width: var(--page-max);
  }

  .venue-head {
    max-width: var(--page-max);
    padding-left: var(--space-xl);
    padding-right: var(--space-xl);
  }
}

/* Unter 900px bleibt alles wie bisher: eine stehende Leiste neben einem
   Telefonbildschirm nimmt die halbe Breite. Die Ursprungsregeln greifen dann
   unverändert, weil dieser ganze Block in der Abfrage steckt. */

/* Gruppenüberschrift in der Seitenleiste — in der Vorlage klein, versal und
   stark gedämpft: sie sortiert, sie konkurriert nicht. */
.nav-gruppe {
  margin: var(--space-lg) 0 var(--space-xs);
  padding: 0 var(--space-md-plus);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav-gruppe:first-child {
  margin-top: 0;
}

/* Unter 900px liegt die Navigation wieder waagerecht — dort wären
   Überschriften zwischen den Knöpfen ein Bruch in der Zeile. */
@media (max-width: 900px) {
  .nav-gruppe {
    display: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIAGRAMME — Flächenkurve und Ring (Design-Vorlage 20.08.2026)
   Gezeichnet wird in core/diagramm.js, gefärbt ausschliesslich hier.
   ═══════════════════════════════════════════════════════════════════════════ */

.kurve {
  width: 100%;
  /* Feste Höhe, weil das SVG über preserveAspectRatio="none" jede Höhe füllt —
     ohne sie fiele die Kurve auf die Höhe ihres Inhalts zusammen, also auf 0. */
  height: 120px;
  margin-top: var(--space-md);
}

.kurve svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Der Verlauf unter der Kurve. `stop-color` ist eine echte CSS-Eigenschaft,
   deshalb greift die Token-Variable hier — anders als in SVG-Attributen. */
.kurve-stop-oben {
  stop-color: var(--accent);
  stop-opacity: 0.45;
}

.kurve-stop-unten {
  stop-color: var(--accent);
  stop-opacity: 0;
}

.kurve-linie {
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* ── Ring ─────────────────────────────────────────────────────────────────── */

.ring {
  position: relative;
  width: 150px;
  height: 150px;
  flex: 0 0 auto;
}

.ring svg {
  width: 100%;
  height: 100%;
  display: block;
}

.ring-grund {
  stroke: var(--surface-3);
  stroke-width: 14;
}

.ring-teil {
  stroke-width: 14;
  /* Runde Enden würden bei kleinen Anteilen über den Nachbarbogen lappen und
     die Verhältnisse verfälschen. */
  stroke-linecap: butt;
}

.ring-teil-1 { stroke: var(--chart-1); }
.ring-teil-2 { stroke: var(--chart-2); }
.ring-teil-3 { stroke: var(--chart-3); }
.ring-teil-4 { stroke: var(--chart-4); }

/* Beschriftung im Kern — sitzt über dem SVG, nicht darin: Text in SVG skaliert
   mit und wird auf schmalen Karten unlesbar klein. */
.ring-kern {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  pointer-events: none;
}

.ring-kern strong {
  color: var(--text);
  font-size: var(--text-xl);
  line-height: 1;
}

.ring-kern span {
  color: var(--text-subtle);
  font-size: var(--text-xs);
  text-align: center;
}

.ring-legende {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm) var(--space-lg);
  align-content: center;
  /* 🔴 Höchstbreite, sonst zieht `flex: 1 1` die zwei Spalten über die ganze
     Karte auseinander: Punkt ganz links, Wert ganz rechts, dazwischen ein
     halber Meter Nichts. Gemessen am 20.08. auf einer 1080px-Karte. */
  flex: 1 1 260px;
  max-width: 420px;
}

.ring-legende-zeile {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-width: 0;
}

.ring-punkt {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  flex: 0 0 auto;
}

.ring-punkt-1 { background: var(--chart-1); }
.ring-punkt-2 { background: var(--chart-2); }
.ring-punkt-3 { background: var(--chart-3); }
.ring-punkt-4 { background: var(--chart-4); }

.ring-legende-label {
  color: var(--text-muted);
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ring-legende-wert {
  color: var(--text);
  font-size: var(--text-sm);
  margin-left: auto;
}

/* Ring und Legende nebeneinander wie in der Vorlage, auf schmalen Karten
   untereinander. */
.ring-zeile {
  display: flex;
  align-items: center;
  gap: var(--space-xl);
  flex-wrap: wrap;
  margin-top: var(--space-md);
}

/* Summe über der Kurve — die Zahl, nach der zuerst gefragt wird. */
.kurve-summe {
  margin: var(--space-md) 0 0;
  color: var(--text);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.1;
}

/* Zeitachse unter der Kurve: nur Anfang und Ende, mehr trägt die Breite nicht. */
.kurve-achse {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-xs);
  color: var(--text-subtle);
  font-size: var(--text-xs);
}

/* Kachelreihe nach Design-Vorlage: gleich breite Karten (20.08.2026).
   Die Vorlage stellt ihre vier Kennzahlen gleichrangig nebeneinander und
   erzeugt die Rangfolge über die Reihenfolge, nicht über die Fläche.
   🔴 Die grössere Zahl der ersten Kachel bleibt — die ursprüngliche
   Begründung ("eine davon ist der Grund, warum jemand die Seite öffnet")
   gilt weiter, sie trägt jetzt nur die Schriftgrösse statt der Breite. */
.tile--haupt {
  grid-column: span 1;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE MENÜFÜHRUNG (Fabi 20.08.2026, nach Handy-Test)
   ───────────────────────────────────────────────────────────────────────────
   🔴 Die Reiter wurden auf 54px zusammengestaucht — alle sechs exakt gleich
   breit, obwohl „Überblick" allein 73px braucht. Grund: `.tabs-inner` ist ein
   Flex-Container, und ohne `flex-shrink: 0` geben Flex-Kinder bei Platzmangel
   nach. Zusammen mit `white-space: nowrap` lief der Text aus seiner Box heraus
   und wurde von der Pille abgeschnitten („Überbl", „Einstellun…").
   Der Container kann bereits scrollen (`overflow-x: auto`) — er durfte nur nie.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  .tab {
    /* Natürliche Breite behalten statt schrumpfen. Das ist der eigentliche Fix. */
    flex: 0 0 auto;
  }

  .tabs-inner {
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-lg);
    /* Beim Wischen an einem Reiter einrasten, damit keine halbe Beschriftung
       am Rand stehen bleibt. */
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }

  .tabs-inner::-webkit-scrollbar {
    display: none;
  }

  .tab {
    scroll-snap-align: start;
    border-radius: var(--radius-full);
    padding: var(--space-sm-plus) var(--space-lg);
    min-height: 44px;
  }

  /* Gleiche Sprache wie die Seitenleiste am Rechner: gefüllte Fläche mit
     dunkler Schrift. Vorher war es eine weisse Pille — zwei verschiedene
     Zustände für dieselbe Sache auf zwei Bildschirmgrössen. */
  .tab.active {
    background: var(--accent-gradient);
    color: var(--on-accent);
    border-bottom-color: transparent;
  }

  /* Der Inhalt beginnt direkt unter der Leiste; ohne diesen Abstand klebt die
     erste Karte an den Reitern. */
  .tabs {
    margin-top: var(--space-md);
  }
}

/* ── Schrittkette und Säulen (Design-Vorlage, Runde 2) ──────────────────── */

/*
 * Die Stufen eines Weges untereinander, dazwischen die Übergangsquote.
 * 🔴 Ersetzt den Trichter: dessen Trapeze verbreiterten sich nach unten,
 * sobald eine Stufe grösser war als die vorige (Gäste kommen über geteilte
 * Links direkt zum Event) — die Form log, die Kette kann das nicht.
 */
.kette {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.kette-stufe {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.kette-kopf {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
}

.kette-wert {
  color: var(--text);
  font-size: var(--text-xl);
  line-height: 1.1;
  /* Feste Mindestbreite, damit die Beschriftungen aller Stufen an derselben
     Kante beginnen — sonst tanzt die Zeile bei zweistelligen Zahlen. */
  min-width: 3ch;
}

.kette-label {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.kette-schacht {
  height: 10px;
  background: var(--surface-2);
  border-radius: var(--radius-full);
  overflow: hidden;
}

.kette-balken {
  height: 100%;
  border-radius: var(--radius-full);
}

.kette-balken-1 { background: var(--chart-1); }
.kette-balken-2 { background: var(--chart-2); }
.kette-balken-3 { background: var(--chart-3); }
.kette-balken-4 { background: var(--chart-4); }

/* Der Übergang zwischen zwei Stufen — eingerückt, damit er als Verbindung
   gelesen wird und nicht als eigene Stufe. */
.kette-uebergang {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding-left: var(--space-sm);
  color: var(--text-subtle);
  font-size: var(--text-xs);
}

.kette-pfeil {
  color: var(--accent-text);
  font-size: var(--text-base);
  line-height: 1;
}

/*
 * 24 Saeulen passen auf kein Handy. Sie duerfen deshalb waagerecht
 * scrollen — aber IN SICH, nicht indem sie die Seite aufziehen.
 *
 * 🔴 `min-width: 0` am Elternteil reicht dafuer NICHT: ein Flex-Kind hat
 * standardmaessig `min-width: auto` und schrumpft nie unter seinen Inhalt.
 * Ohne `overflow-x: auto` HIER wanderte der Ueberlauf nach oben durch, bis
 * er das Raster erreichte — und dann verschob sich das ganze Dashboard.
 */
.saeulen {
  display: flex;
  align-items: flex-end;
  gap: var(--space-xl);
  height: 160px;
  margin-top: var(--space-md);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Sonst schneidet der Scrollrahmen die Zahl ueber der hoechsten Saeule ab. */
  padding-bottom: var(--space-2xs);
}


.saeule-spalte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  flex: 1 1 0;
  height: 100%;
  min-width: 0;
}

.saeule-wert {
  color: var(--text);
  font-size: var(--text-lg);
}

.saeule-schacht {
  flex: 1 1 auto;
  width: 100%;
  max-width: 72px;
  display: flex;
  align-items: flex-end;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.saeule-stab {
  width: 100%;
  background: var(--surface-3);
  border-radius: var(--radius-sm);
}

/* Die eigene Säule trägt den Verlauf — sie ist die Antwort auf die Frage,
   die Vergleichssäule ist nur der Massstab. */
.saeule-stab--eigen {
  background: var(--accent-gradient);
}

.saeule-label {
  color: var(--text-subtle);
  font-size: var(--text-xs);
  text-align: center;
}

@media (max-width: 600px) {
  .trichter {
    flex-direction: column;
    gap: var(--space-md);
  }
  .trichter svg {
    height: 190px;
  }
  .trichter-namen {
    min-width: 0;
  }
}

/* ── Seitenspalte im Überblick (Design-Vorlage, Runde 3) ─────────────────── */

/*
 * Die Vorlage trägt rechts eine schmale Spalte mit Benachrichtigungen,
 * Aktivitäten und Kontakten. Im Panel gibt es alle drei bereits — als
 * „Warten auf Freigabe", „Änderungsprotokoll" und „Team".
 *
 * 🔴 Die Spalte gilt NUR im Überblick, nicht panelweit. Profil, Events und
 * Einstellungen sind Formular-Reiter; dort würde eine feste Spalte die
 * Eingabefelder auf zwei Drittel stauchen, ohne etwas dazuzugewinnen. Die
 * Vorlage ist ein reines Dashboard — das Panel ist ein Arbeitswerkzeug, und
 * dieser Unterschied darf nicht wegkopiert werden.
 *
 * Umgesetzt über das vorhandene 12-Spalten-Raster (`sp-4`), nicht über ein
 * zweites Grid: Der Inhalt bleibt damit an derselben Rasterkante wie alle
 * übrigen Karten, und auf schmalen Bildschirmen greift die bestehende
 * Ein-Spalten-Regel bei 860px ohne Zusatzarbeit.
 */
.seiten-karte {
  /* 🔴 BEIDE Karten in dieselbe Rasterspalte (9 bis Ende), nicht nur auf
     Spaltenbreite: Mit `sp-4` allein setzt das Grid sie automatisch
     nebeneinander in dieselbe Zeile — gemessen: 336px breit, aber bei x=284
     und x=636. Erst die feste Spaltenangabe stapelt sie rechts untereinander
     und macht daraus die Seitenspalte der Vorlage. */
  grid-column: 9 / -1;
  /* Klebt beim Scrollen mit — die Vorlage hält ihre rechte Spalte ebenfalls
     im Blick, während der Hauptbereich weiterläuft. */
  position: sticky;
  top: var(--space-lg);
  /* Eigene Höhe behalten: ohne max-height schöbe ein langes Änderungsprotokoll
     die Karte über den Bildschirmrand, und `sticky` hätte nichts mehr zu halten. */
  max-height: calc(100vh - var(--space-xxl) * 2);
  overflow-y: auto;
}

@media (max-width: 860px) {
  /* Auf dem Telefon wandert die Spalte unter den Inhalt und darf nicht kleben —
     eine klebende Karte im Fluss verdeckt das, was darunter liegt. */
  .seiten-karte {
    position: static;
    max-height: none;
  }
}

@media (max-width: 860px) {
  /* Im Ein-Spalten-Raster darf keine feste Spaltenangabe stehen bleiben —
     `grid-column: 9 / -1` gäbe es dort gar nicht, die Karte fiele aus dem Fluss. */
  .seiten-karte {
    grid-column: auto;
  }
}

/*
 * 🔴 ZURÜCKGENOMMEN am 21.08.2026: Hier stand `grid-row: 2/3` für die beiden
 * Seitenkarten, um sie nach oben zu holen. Das Ergebnis war schlechter als das
 * Problem — die Hauptkarten blieben in ihren automatischen Zeilen, und links
 * oben klaffte ein leeres Feld über die halbe Seite. Eine feste Zeilenangabe
 * in einem Grid mit automatischer Platzierung verschiebt nur EIN Element und
 * lässt alle anderen stehen.
 *
 * Die Karten stehen jetzt wieder dort, wo das Grid sie hinsetzt: rechts,
 * untereinander, in Dokumentreihenfolge. Wer sie weiter oben haben will, muss
 * sie im Markup nach oben ziehen — das ist der ehrliche Weg, nicht eine
 * Zeilennummer, die beim nächsten neuen Kasten wieder kippt.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   LAGE — Hauptfläche des Überblicks (21.08.2026)

   🔴 Ersetzt drei gleich große Kacheln mit je einer nackten Zahl. Fabi über
   den Vorzustand: „nur Bausteine, nur Kacheln, keine Farbverläufe … es sieht
   aus, als hätte Claude Code das gebaut."

   Die Recherche zu Dashboards 2026 (Stripe, Linear, Vercel, Raycast) benennt
   drei Merkmale, die hier umgesetzt sind:
     1. EINE dominante Fläche statt gleichrangiger Kästen. Hierarchie entsteht
        durch Größe UND Inhalt — die Hauptfläche trägt einen Verlauf, die
        Nebenzahlen nicht.
     2. Verlauf statt Stand: die Kurve beantwortet „wird es mehr oder weniger",
        die Zahl allein kann das nicht.
     3. Tiefe aus Licht, nicht aus Rahmen: ein weicher Schein von unten links
        statt einer weiteren grauen Kante.
   ═══════════════════════════════════════════════════════════════════════════ */

.lage {
  display: grid;
  /* 2.2 : 1 — bewusst kein glattes 2:1. Ein exaktes Verhältnis liest sich als
     zweispaltiges Formular; die ungerade Teilung macht sichtbar, dass links
     die Hauptsache steht. */
  grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr);
  gap: var(--space-md);
  align-items: stretch;
}

.lage-haupt {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-xl);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--lage-glanz), var(--surface-1);
  text-align: left;
  cursor: pointer;
  transition: border-color 160ms ease, transform 160ms ease;
}

/* 🔴 Hintergrund ausdruecklich zuruecknehmen: sonst greift die globale
   Regel `button:hover` und flutet die Kachel orange — gemessen 1,6:1
   Kontrast fuer Label und Fusslinks. Siehe auch .lage-mini weiter unten. */
.lage-haupt:hover {
  background: var(--lage-glanz), var(--surface-1);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.lage-haupt:active { transform: translateY(1px); }

.lage-kopf {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}

.lage-zahl-block { display: flex; flex-direction: column; gap: var(--space-2xs); }

.lage-wert {
  font-family: var(--font-display);
  /* Groß, aber nicht plakativ: das hier ist ein Arbeitswerkzeug, keine
     Marketingseite. `clamp` hält die Zahl auf schmalen Fenstern lesbar. */
  font-size: clamp(38px, 4.4vw, 56px);
  line-height: 1;
  /* Luft unter der Zahl statt in der Zeilenhoehe — siehe Kommentar oben. */
  padding-bottom: var(--space-sm);
  letter-spacing: -0.02em;
  color: var(--text);
}

.lage-label {
  font-size: var(--text-sm);
  color: var(--text-subtle);
  letter-spacing: 0.01em;
}

/* Vergleich zum Vormonat. Farbe trägt hier Bedeutung, deshalb steht das
   Vorzeichen IMMER im Text — Farbe allein wäre für Farbenblinde stumm. */
.lage-delta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs-plus);
  padding: var(--space-xs) var(--space-sm-plus);
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border);
  color: var(--text-subtle);
}
.lage-delta.ist-hoch { color: var(--accent); border-color: var(--delta-rand); }
.lage-delta.ist-tief { color: var(--text-subtle); }

.lage-kurve { display: block; margin: 0 calc(var(--space-xs) * -1); }

.lage-fuss {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
.lage-cta { color: var(--accent); font-weight: 600; }

/* ── Nebenzahlen ──────────────────────────────────────────────────────────
   Zwei kleine Flächen, übereinander statt nebeneinander: so bleibt die
   Hauptfläche links unangefochten die größte Form im Bild. */
.lage-seite {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: var(--space-md);
  min-width: 0;
}

.lage-mini {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2xs);
  padding: var(--space-lg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  text-align: left;
  cursor: pointer;
  transition: border-color 160ms ease, transform 160ms ease;
  min-width: 0;
}
.lage-mini:hover {
  /* Gleiche Ursache wie oben — auch diese Kachel ist ein <button>. */
  background: var(--surface-2);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.lage-mini:active { transform: translateY(1px); }

.lage-mini-wert {
  font-family: var(--font-display);
  font-size: 30px;
  line-height: 1.05;
  padding-bottom: var(--space-2xs);
  color: var(--text);
}
.lage-mini-label { font-size: var(--text-sm); color: var(--text-subtle); }
.lage-mini-spark { display: block; margin-top: var(--space-xs); }
.lage-mini-cta {
  margin-top: var(--space-xs);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
}

/* ── Die große Kurve ───────────────────────────────────────────────────── */
.kurve-gross { width: 100%; }
.kurve-gross-svg { display: block; width: 100%; height: 190px; }

.kurve-linie {
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Der Schein macht aus der Linie eine Lichtquelle — dasselbe Mittel, mit dem
     die Vorlagen Tiefe erzeugen, ohne einen Rahmen zu zeichnen. */
  filter: var(--kurve-schein);
}
.kurve-raster { stroke: var(--border); stroke-width: 1; opacity: 0.5; }
.kurve-punkt {
  fill: var(--accent);
  stroke: var(--surface-1);
  stroke-width: 2.5;
}

.kurve-achse {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-2xs);
  font-size: var(--text-xs);
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}
.kurve-leer { margin: var(--space-lg) 0; }

/* Unter 900px steht die Nebenspalte unter der Hauptfläche und teilt sich in
   zwei Spalten — untereinander wären es sonst drei volle Bildschirmhöhen. */
@media (max-width: 900px) {
  .lage { grid-template-columns: 1fr; }
  .lage-seite { grid-template-rows: none; grid-template-columns: 1fr 1fr; }
  .lage-haupt { padding: var(--space-lg); }
  .kurve-gross-svg { height: 150px; }
}
@media (max-width: 560px) {
  .lage-seite { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MONATSKALENDER — vom Datepicker zum Belegungsplan (21.08.2026)

   🔴 Fabi: „der Kalenderschrott". Berechtigt. Der Kalender sah aus wie das
   Datumsfeld eines Formulars: 31 gleich graue Kästchen, belegte Tage
   vollflächig orange übermalt.

   Zwei Fehler steckten darin:
     1. Ein voll gefülltes Feld ÜBERDECKT die Tageszahl fast — ausgerechnet der
        belegte Tag war am schlechtesten zu lesen.
     2. Jeder freie Tag trug denselben grauen Kasten wie jeder andere. 31 Kästen
        gleicher Lautstärke ergeben Rauschen, in dem die zwei belegten Nächte
        untergehen.

   Ein Belegungsplan beantwortet „welche Nächte laufen" — also müssen die
   belegten Nächte die einzigen lauten Elemente sein. Freie Tage werden zur
   ruhigen Zahl ohne Kasten, belegte behalten die Zahl und bekommen einen
   Marker darunter. Heute ist ein Ring, keine Füllung: „heute" ist eine
   Ortsangabe, keine Belegung.
   ═══════════════════════════════════════════════════════════════════════════ */

.kal-tag {
  /* Kompakter: 58px pro Tag ergaben ein Raster, das mehr Platz braucht als der
     Rest der Karte zusammen. */
  max-height: 46px;
  background: transparent;
  color: var(--text-subtle);
  font-weight: 500;
}

/* Freier Tag: nur die Zahl. Beim Überfahren eine leise Fläche, damit man sieht,
   dass er anklickbar ist. */
.kal-tag:hover { background: var(--surface-2); }

/* Belegte Nacht: Zahl bleibt lesbar, der Marker trägt die Aussage. */
.kal-tag.is-belegt {
  background: transparent;
  color: var(--text);
  font-weight: 700;
}
.kal-tag.is-belegt::after {
  content: '';
  position: absolute;
  bottom: var(--space-xs);
  left: 50%;
  transform: translateX(-50%);
  width: 18px;
  height: 3px;
  border-radius: var(--radius-full);
  background: var(--accent);
  box-shadow: 0 0 8px var(--delta-rand);
}
.kal-tag.is-belegt:hover {
  background: var(--surface-2);
}

/* Heute: Ring statt Fläche. */
.kal-tag.is-heute {
  color: var(--text);
  border-color: var(--border-strong);
  background: transparent;
}
.kal-tag.is-heute.is-belegt { border-color: var(--accent); }


/* ═══════════════════════════════════════════════════════════════════════════
   ÜBERBLICK — zwei eigenständige Spalten (21.08.2026)

   🔴 Das 12-Spalten-Raster ordnet in ZEILEN. Steht eine hohe Karte neben einer
   niedrigen, bleibt der Platz unter der niedrigen leer — er gehört bereits zur
   nächsten Zeile. Im Überblick klafften dadurch rund 900 px Leere unter der
   linken Spalte, während rechts Team und Protokoll weiterliefen.

   Was NICHT half, jeweils ausprobiert und wieder entfernt:
     • `grid-auto-flow: dense` — füllt nur Lücken innerhalb einer Zeile
     • `grid-row`-Steuerung — zerriss das Layout am 20.08. schon einmal
     • `grid-template-rows: masonry` — noch nicht breit genug unterstützt

   Zwei Flex-Spalten stapeln unabhängig: Jede Karte rückt an die Unterkante
   ihrer Vorgängerin in DERSELBEN Spalte. Das ist die Anordnung, die Stripe,
   Linear und Vercel im Dashboard nutzen.

   🔴 `align-items: start` ist entscheidend. Ohne das strecken sich beide
   Spalten auf dieselbe Höhe, und die kürzere verteilt ihre Karten über die
   ganze Länge — die Lücken wären zurück, nur gleichmäßiger verteilt.
   ═══════════════════════════════════════════════════════════════════════════ */

.ueberblick-spalten {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-lg);
  align-items: start;
}

.spalte-breit,
.spalte-schmal {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  min-width: 0;
}

/* Unter 860px untereinander — dieselbe Grenze wie beim Raster, damit nicht
   zwei verschiedene Umbruchpunkte auf derselben Seite wirken. */
@media (max-width: 860px) {
  .ueberblick-spalten { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PRO — die Verkaufsseite (21.08.2026)

   🔴 Fabi: „richtig stylisch, nicht so generisch wie du's sonst immer machst,
   sondern wirklich einladend … sodass der Clubbesitzer denkt, ich muss
   unbedingt dieses Pro haben."

   Drei Entscheidungen, die diese Seite vom Rest des Panels abheben — und zwar
   bewusst, denn sie ist die einzige Seite, die etwas verkauft statt zu
   verwalten:

     1. Der Kopf ist zweigeteilt: links das Versprechen, rechts der Preis als
        eigenständige Marke. Der Preis versteckt sich nicht im Fließtext,
        sondern steht als Zahl da, mit durchgestrichenem Listenpreis darüber.
     2. Die Nutzen-Blöcke sind nummeriert und ungleich breit umbrochen. Sechs
        gleich große Kacheln wären wieder das Muster, das wir gerade abgeschafft
        haben.
     3. Die Vergleichstabelle ist eine ECHTE Tabelle (<table>), keine
        Div-Nachbildung: Sie wird zeilenweise vorgelesen, lässt sich kopieren
        und bleibt beim Zoomen zusammen.
   ═══════════════════════════════════════════════════════════════════════════ */

#panel-pro { display: flex; flex-direction: column; gap: var(--space-3xl); }

/* ── Kopf ───────────────────────────────────────────────────────────────── */
.pro-kopf {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(260px, 1fr);
  gap: var(--space-2xl);
  align-items: center;
  padding: var(--space-3xl);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--lage-glanz), var(--surface-1);
}

.pro-auge {
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* 🔴 `--accent-stark`, nicht `--accent`: Orange auf hellem Grund ist 2.31:1
     und damit unter WCAG AA. Siehe tokens.css. */
  color: var(--accent-stark);
  margin-bottom: var(--space-sm);
}

.pro-titel {
  font-family: var(--font-display);
  font-size: clamp(28px, 3.2vw, 42px);
  /* 🔴 1.22 statt 1.08: Boldonse hat kraeftige Ober- und Unterlaengen — bei
     zweizeiligen Ueberschriften beruehrten sie sich sonst. */
  line-height: 1.22;
  letter-spacing: -0.015em;
  margin-bottom: var(--space-md);
  /* Verhindert ein einzelnes Wort in der letzten Zeile. */
  text-wrap: balance;
}

.pro-lead {
  font-size: var(--text-md);
  line-height: 1.6;
  color: var(--text-muted);
  /* Rund 65 Zeichen — darüber verliert das Auge beim Zeilensprung die Spur. */
  max-width: 54ch;
}

.pro-kopf-aktion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-md);
  margin-top: var(--space-xl);
}

.btn-gross {
  padding: var(--space-md) var(--space-2xl);
  font-size: var(--text-md);
  font-weight: 700;
  border-radius: var(--radius-md);
  background: var(--accent-gradient);
  color: var(--on-accent);
  border: 0;
  cursor: pointer;
  transition: filter var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn-gross:hover { filter: brightness(1.07); }
.btn-gross:active { transform: translateY(1px); }

.pro-kopf-fuss { font-size: var(--text-sm); color: var(--text-subtle); }

/* ── Preis als eigenständige Marke ──────────────────────────────────────── */
.pro-preis {
  padding: var(--space-xl);
  border: 1px solid var(--delta-rand);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  text-align: center;
}
.pro-preis-alt { color: var(--text-subtle); font-size: var(--text-md); }
.pro-preis-zahl {
  font-family: var(--font-display);
  font-size: clamp(36px, 4vw, 52px);
  line-height: 1;
  padding-bottom: var(--space-xs);
  color: var(--accent-stark);
}
.pro-preis-takt { font-size: var(--text-md); color: var(--text); }
.pro-preis-rechnung {
  margin-top: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-subtle);
  line-height: 1.5;
}

/* ── Nutzen ─────────────────────────────────────────────────────────────── */
.pro-abschnitt {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  margin-bottom: var(--space-xl);
}

.pro-nutzen-raster {
  display: grid;
  /* Sechs Spalten als Grundraster. Damit lassen sich ungleiche Breiten bauen,
     ohne dass jede Karte eine eigene Medienabfrage braucht. */
  grid-template-columns: repeat(6, 1fr);
  gap: var(--space-lg);
}

.pro-nutzen-karte {
  /* Standard: ein Drittel der Breite (2 von 6 Spalten). */
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-xl);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.pro-nutzen-karte:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
}

/*
 * Der erste Block traegt das Hauptargument (automatische Uebernahme) und
 * bekommt die doppelte Flaeche: vier von sechs Spalten, zwei Zeilen hoch.
 * Die Bloecke 2 und 3 stapeln sich rechts daneben, 4 bis 6 laufen darunter
 * in einer Dreierreihe.
 *
 * 🔴 Hierarchie ueber GROESSE, nicht ueber Farbe. Ein farbig hervorgehobener
 * Block unter fuenf grauen liest sich als Werbebanner; ein groesserer liest
 * sich als „das ist der Punkt".
 */
.pro-nutzen-karte.ist-gross {
  grid-column: span 4;
  grid-row: span 2;
  padding: var(--space-3xl);
  background: var(--lage-glanz), var(--surface-1);
  /* 🔴 NICHT zentrieren. Die Karte ist über zwei Zeilen gestreckt (694 px
     gemessen), ihr Inhalt misst 299 px. `center` verteilte die übrigen
     395 px je zur Hälfte nach oben und unten — die Karte sah im Screenshot
     schlicht leer aus. Stattdessen: Text oben verankern, den Ablauf an die
     Unterkante (siehe `margin-top: auto` unten). Dann trägt die Fläche
     Struktur statt Luft. */
  justify-content: flex-start;
}

/* Der Ablauf (Website → Basscamp → App) sitzt an der Unterkante und füllt
   damit die gestreckte Höhe. Unter 1100 px ist die Karte nur so hoch wie ihr
   Inhalt — dann gibt es keinen freien Raum und die Regel bleibt wirkungslos. */
.pro-nutzen-karte.ist-gross .pro-ablauf {
  margin-top: auto;
}

.pro-nutzen-karte.ist-gross .pro-nutzen-titel {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.2vw, 30px);
  line-height: 1.25;
}

.pro-nutzen-karte.ist-gross .pro-nutzen-text {
  /* Die Hauptkarte trägt das wichtigste Argument und die doppelte Fläche.
     Mit --text-md blieben bei 694 px Höhe rund 240 px leer, gemessen — die
     Karte wirkte dünn besetzt statt ausgezeichnet. Größerer Satz mit mehr
     Durchschuss füllt die Fläche und setzt zugleich die Hierarchie, die
     die Größe verspricht. 46ch bleibt: das hält die Zeile lesbar kurz. */
  font-size: var(--text-lg);
  line-height: 1.75;
  max-width: 46ch;
}

.pro-nutzen-karte.ist-gross .pro-nutzen-symbol { width: 32px; height: 32px; }

/* Kopfzeile: Symbol links, Nummer rechts aussen. Die Nummer ordnet, sie
   dominiert nicht mehr — vorher stand sie gross und orange ueber allem. */
.pro-nutzen-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-xs);
}

.pro-nutzen-zeichen {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  color: var(--accent-stark);
}

.pro-nutzen-symbol { width: 22px; height: 22px; }

.pro-nutzen-nr {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

.pro-nutzen-titel {
  font-size: var(--text-lg);
  font-weight: 700;
  /* Verhindert einzelne Woerter in der letzten Zeile — die Titel brachen
     vorher mitten im Wort um („Automatische Event- / Synchronisierung"). */
  text-wrap: balance;
}

.pro-nutzen-text {
  color: var(--text-muted);
  line-height: 1.6;
}

/* Ab hier wird es zu eng fuer die Komposition: alle Bloecke gleich breit,
   der grosse behaelt nur seine groessere Schrift. */
@media (max-width: 1100px) {
  .pro-nutzen-raster { grid-template-columns: repeat(4, 1fr); }
  .pro-nutzen-karte { grid-column: span 2; }
  .pro-nutzen-karte.ist-gross {
    grid-column: span 4;
    grid-row: auto;
    padding: var(--space-2xl);
  }
}

@media (max-width: 700px) {
  .pro-nutzen-raster { grid-template-columns: 1fr; }
  .pro-nutzen-karte,
  .pro-nutzen-karte.ist-gross { grid-column: 1 / -1; }
  .pro-nutzen-karte.ist-gross { padding: var(--space-xl); }
}

/* ── Vergleichstabelle ──────────────────────────────────────────────────── */
.pro-tabelle-huelle {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Auf schmalen Fenstern scrollt die Tabelle in sich, statt die Seite
     seitwärts zu schieben. */
  overflow-x: auto;
}

.pro-tabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
  /* Feste Breiten statt Automatik: Sonst richtet der Browser die Spalten nach
     der Textlaenge aus, und Free bekaeme genauso viel Raum wie Pro. */
  table-layout: fixed;
}

/* Merkmal 44 %, Free 22 %, Pro 34 % — die Pro-Spalte ist damit die Haelfte
   breiter als Free (Fabi 21.08.2026). */
.pro-tabelle th:first-child,
.pro-tabelle td:first-child { width: 44%; }
.pro-tabelle th:nth-child(2),
.pro-tabelle td:nth-child(2) { width: 22%; }
.pro-tabelle th:last-child,
.pro-tabelle td:last-child { width: 34%; }

/* Die Pro-Ueberschrift traegt zusaetzlich Gewicht. */
.pro-tabelle thead th.ist-pro { font-size: var(--text-base); font-weight: 700; }

.pro-tabelle th,
.pro-tabelle td {
  padding: var(--space-md-plus) var(--space-lg);
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.pro-tabelle thead th {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-subtle);
  background: var(--surface-2);
  position: sticky;
  top: 0;
}

/* Die Pro-Spalte ist die, um die es geht — sie bekommt Farbe und Gewicht. */
.pro-tabelle thead th.ist-pro { color: var(--accent); }
.pro-tabelle td:last-child { color: var(--text); font-weight: 600; }
.pro-tabelle td:nth-child(2) { color: var(--text-subtle); }

.pro-tabelle tbody th {
  font-weight: 500;
  color: var(--text);
}
.pro-tabelle tbody tr:last-child th,
.pro-tabelle tbody tr:last-child td { border-bottom: 0; }

/* Zeilen, die in beiden Tarifen enthalten sind: leiser, damit der Blick an
   den Unterschieden hängen bleibt. */
.pro-tabelle tr.ist-beide th,
.pro-tabelle tr.ist-beide td { color: var(--text-subtle); font-weight: 500; }

/* 🔴 Das Haekchen traegt seine Aussage durch die FORM, nicht durch Farbe.
   Farbig war es einer von 16 orangen Punkten auf einer Seite — und der
   Akzent verliert seine Wirkung, wenn er ueberall ist. Die Pro-Spalte
   hebt sich ohnehin durch ihre Flaeche ab (--pro-spalte). */
.pro-haken { width: 18px; height: 18px; color: var(--text); }
.pro-strich { width: 18px; height: 18px; color: var(--text-subtle); opacity: 0.6; }

/* Nur für Vorleseprogramme — sichtbar wäre es Doppelung zum Häkchen. */
.nur-vorlesen {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px; /* token-check:allow — Teil des Standard-Rezepts fuer visuell verborgenen Text, kein Abstand im Layout */
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.pro-fussnote { margin-top: var(--space-md); }

/* ── Abschluss und Fragen ───────────────────────────────────────────────── */
.pro-abschluss {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: var(--space-lg);
  align-items: start;
}

.pro-frage { font-weight: 700; margin-top: var(--space-lg); }
.pro-frage:first-child { margin-top: 0; }
.pro-antwort {
  margin: var(--space-xs) 0 0;
  color: var(--text-muted);
  line-height: 1.6;
}

@media (max-width: 900px) {
  .pro-kopf { grid-template-columns: 1fr; padding: var(--space-xl); }
  .pro-abschluss { grid-template-columns: 1fr; }
  #panel-pro { gap: var(--space-2xl); }
}

/* ── Pro-Seite: Nachbesserungen aus der Verkaufsanalyse (21.08.2026) ────────
   Übernommen wurden nur belegbare Punkte. Ausdrücklich NICHT übernommen:
   erfundene Vertrauenssignale (Geld-zurück-Garantie, „über 50 Clubs nutzen
   Pro" — es sind zwei), Verknappung und ein erfundenes Testimonial. */

/* Vertrauenszeile sitzt direkt am Knopf, wo der Zweifel entsteht. */
.pro-trust {
  margin-top: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-subtle);
}

/* Die Pro-Spalte ist die, um die es geht — sie bekommt eine eigene Fläche.
   Vorher waren Free und Pro optisch gleichrangig, und der Blick blieb an
   der Spalte hängen, die nichts verkauft. */
.pro-tabelle th:last-child,
.pro-tabelle td:last-child {
  background: var(--pro-spalte);
}
.pro-tabelle thead th:last-child {
  border-top-right-radius: var(--radius-lg);
}

/* Der durchgestrichene Preis war fast so groß wie der Angebotspreis — das
   liest sich als Schnäppchen, nicht als fairer Kurs. Kleiner und leiser. */
.pro-preis-alt { font-size: var(--text-sm); opacity: 0.75; }

/* Ersparnis als eigene Zeile über dem Preis: „die Hälfte" ist die Aussage,
   die hängen bleibt — nicht die Differenz in Euro. */
.pro-preis-spar {
  display: inline-block;
  margin-bottom: var(--space-sm);
  padding: var(--space-2xs) var(--space-sm-plus);
  border-radius: var(--radius-full);
  background: var(--accent-gradient);
  color: var(--on-accent);
  font-size: var(--text-sm);
  font-weight: 700;
}

/* ── Am Telefon bleibt der Kaufknopf erreichbar ────────────────────────────
   🔴 Ohne das scrollt ein Betreiber durch Nutzen, Tabelle und Fragen — und
   muss dann wieder ganz nach oben, um zu kaufen. Der Knopf steht deshalb
   unten fest, sobald der Kopfbereich aus dem Bild ist.

   Nur unter 900px: Am Rechner ist die Seite breit genug, dass der Knopf im
   Kopf sichtbar bleibt, und eine feste Leiste wäre dort nur im Weg. */
@media (max-width: 900px) {
  .pro-sticky {
    position: sticky;
    bottom: 0;
    z-index: var(--z-topbar);
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    margin: var(--space-lg) calc(var(--space-lg) * -1) 0;
    padding: var(--space-md) var(--space-lg);
    /* Der Rand nach unten schützt vor der Gestenleiste des Telefons. */
    padding-bottom: max(var(--space-md), env(safe-area-inset-bottom));
    background: var(--surface-1);
    border-top: 1px solid var(--border);
    text-align: center;
  }
  .pro-sticky .btn-gross { width: 100%; }
}
/* Am Rechner ist die Leiste gegenstandslos. */
@media (min-width: 901px) {
  .pro-sticky { display: none; }
}

/* Herkunft des Streichpreises — leise, aber direkt daneben. */
.pro-preis-herkunft { display: block; font-size: var(--text-xs); color: var(--text-subtle); }

/* ── Ablauf in der Hauptkarte (21.08.2026) ─────────────────────────────────
   Drei beschriftete Schritte statt Leerraum. Die Karte ist doppelt so hoch
   wie die anderen; ohne Inhalt sah das nach einem Rasterfehler aus. */
.pro-ablauf {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border);
}

.pro-ablauf-schritt {
  padding: var(--space-sm) var(--space-md-plus);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface-2);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
}

/* Der mittlere Schritt ist der, den wir übernehmen — er trägt die Marke. */
.pro-ablauf-schritt:nth-of-type(2) {
  border-color: var(--delta-rand);
  color: var(--accent-stark);
}

.pro-ablauf-pfeil {
  color: var(--text-subtle);
  font-size: var(--text-lg);
  line-height: 1;
}

@media (max-width: 700px) {
  .pro-ablauf { gap: var(--space-xs); }
  .pro-ablauf-schritt { padding: var(--space-xs) var(--space-sm); }
}

/* Netto-Hinweis am Preis — leise, aber vor dem Klick sichtbar. */
.pro-preis-netto {
  margin-top: var(--space-xs);
  font-size: var(--text-xs);
  color: var(--text-subtle);
}

/* ── Social-Kanaele ────────────────────────────────────────────────────── */

/* Markenlogo in der Beschriftung. Es erbt die Textfarbe (siehe
   core/netzwerke.js) und sitzt optisch auf der Grundlinie des Wortes —
   mathematisch zentriert wirkt es einen Hauch zu hoch. */
.netz-logo {
  display: inline-flex;
  align-items: center;
  margin-right: var(--space-2xs);
  vertical-align: -2px;
  opacity: 0.85;
}

.netz-zeile { display: flex; flex-direction: column; gap: var(--space-2xs); }

/* Eingabe und Entfernen-Knopf teilen sich die Zeile. Der Knopf bleibt
   quadratisch, damit er die Zeilenhoehe nicht sprengt. */
.netz-eingabe { display: flex; gap: var(--space-xs); align-items: stretch; }
.netz-eingabe input { flex: 1 1 auto; min-width: 0; }

.netz-weg {
  flex: 0 0 auto;
  width: 44px;
  min-height: 44px;
  margin-top: 0;
  padding: 0;
  font-size: var(--text-lg);
  line-height: 1;
}

/* Auswahl und Knopf stehen nebeneinander; auf schmalen Schirmen
   untereinander, damit beide voll antippbar bleiben. */
.netz-hinzu {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
  flex-wrap: wrap;
  margin-top: var(--space-lg);
}
.netz-hinzu select { flex: 0 1 220px; }
.netz-hinzu button { margin-top: 0; }

/* ── Nachtabschluss: Auswertung ──────────────────────────────────────── */

/* Die Kennzahlen stehen nebeneinander und brechen um, statt zu schrumpfen —
   eine Zahl, die man zusammenkneifen muss, liest niemand. */
.nacht-kennzahlen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xl);
  margin-bottom: var(--space-xl);
}

.nacht-kachel { min-width: 130px; }

/* 🔴 GROESSE IST KEINE LAUTSTAERKE (Fabi 11.09.2026: „das ist zu gross").
   Die Zahlen standen auf clamp(26px, 3vw, 38px) — auf einem breiten Schirm
   also 38px, vier Kacheln nebeneinander, und die Karte schrie mehr als sie
   sagte. Der Wert bleibt der groesste Text der Kachel, aber er ueberfaehrt
   die Zeile darunter nicht mehr. */
.nacht-wert {
  font-family: var(--font-display);
  font-size: clamp(22px, 1.9vw, 27px);
  line-height: 1.15;
  color: var(--text);
}

.nacht-label {
  margin-top: var(--space-2xs);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Die Vergleichszeile traegt die eigentliche Aussage („12 % weniger als
   davor") und darf deshalb nicht schwaecher gesetzt sein als die
   Beschriftung darueber. */
.nacht-zusatz {
  margin-top: var(--space-2xs);
  font-size: var(--text-base);
  color: var(--text);
}

/* 🔴 Der Name des Abends steht UEBER dem Datum und traegt das Gewicht
   (Fabi 11.09.2026: „event name anzeigen"). „Hardstyle Invasion" sagt dem
   Betreiber sofort, welcher Abend gemeint ist — „2026-08-21" nie. */
.nacht-event {
  margin-top: var(--space-2xs);
  /* 🔴 Ohne Begrenzung zieht ein langer Veranstaltungstitel die ganze
     Kachel in die Breite: „LOONYLAND pres. LUCA DANTE SPADAFORA & 2 ENGEL &
     CHARLIE" machte aus 235 px gemessene 459 px und warf die Kachel allein
     in die zweite Zeile. Umbrechen statt strecken. */
  max-width: 28ch;
  overflow-wrap: anywhere;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text);
}

/* 🔴 Das Datum war mit 13px die kleinste Zeile der Kachel, obwohl es die
   Zahl ueberhaupt erst einordnet (Fabi 11.09.2026: „datm groesser"). Jetzt
   16px — groesser als jede Beschriftung, aber unter dem Kennzahlwert. */
.nacht-datum {
  margin-top: var(--space-2xs);
  font-size: var(--text-md);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* ── Abo-Zeile im Ueberblick ─────────────────────────────────────────── */

/* Ganz oben, aber flach: Der Abo-Zustand ist eine Randnotiz, solange alles
   laeuft. Erst wenn etwas ansteht (Zahlung offen, Kuendigung), fuellt sich
   die Zeile mit Text und waechst von selbst. */
.abo-zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-xl);
}
.abo-zeile .btn-row { margin: 0; }
.abo-zeile button { margin-top: 0; }

.abo-satz {
  margin: 0;
  font-weight: 600;
  color: var(--text);
}

/* Ueberschrift nur fuer Vorleseprogramme: Der Bereich braucht eine
   Benennung im Dokumentaufbau, aber auf dem Schirm wuerde ein „Abo" ueber
   einem Einzeiler den Platz verdoppeln, den die Sache wert ist. */
.nur-vorlesen {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Zahlenlisten im Ueberblick ──────────────────────────────────────── */

.zahlen-liste { display: flex; flex-direction: column; }

/* Titel links, Zahlen rechtsbuendig — so stehen die Ziffern untereinander
   und lassen sich vergleichen, ohne dass das Auge springt. */
.zahlen-zeile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--border);
}
.zahlen-zeile:last-child { border-bottom: 0; }

.zahlen-titel {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
}

.zahlen-werte { display: flex; gap: var(--space-lg); flex: 0 0 auto; }

/* Tabellenziffern: sonst tanzen die Zahlen von Zeile zu Zeile. */
.zahlen-wert {
  font-variant-numeric: tabular-nums;
  min-width: 3.5ch;
  text-align: right;
  color: var(--text);
}

/* Ticket-Klicks sind die Teilmenge und stehen deshalb zurueckhaltender. */
.zahlen-ticket { color: var(--text-muted); }

/* Spaltenkoepfe: kleiner und ruhiger als die Werte darunter — sie sollen
   die Liste erklaeren, nicht mit ihr konkurrieren. */
.zahlen-kopf .zahlen-titel,
.zahlen-kopf .zahlen-wert {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Das gecrawlte Titelbild in der Eventliste. Fest in der Hoehe, damit die
   Zeilen gleich hoch bleiben — hochkant und quer gemischt wuerde die Liste
   sonst treppenfoermig. */
.row-bild {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: var(--radius-md);
  background: var(--surface-2);
}

/* Anklickbare Kennzahl-Kachel. Sie ist ein <button>, erbt also den
   Vollflaechen-Hover — derselbe Fall wie bei den Lage-Kacheln, deshalb
   hier ebenfalls ausdruecklich zurueckgenommen. */
.tile--klickbar {
  width: 100%;
  margin-top: 0;
  text-align: left;
  font-family: inherit;
  font-weight: inherit;
  min-height: 0;
  cursor: pointer;
}
.tile--klickbar:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--border-strong);
}

.verlauf-titel {
  margin: 0 0 var(--space-md);
  font-size: var(--text-md);
  color: var(--text);
}

/* ── Ladeanzeige am Knopf ────────────────────────────────────────────── */

/* Ein mitlaufender Ring am Knopf. Er dreht sich, solange der Crawler
   arbeitet, und verschwindet erst, wenn der Lauf wirklich durch ist —
   nicht nach einer geschaetzten Zeit. */
.laedt {
  position: relative;
  padding-left: calc(var(--space-xl) + var(--space-md));
  opacity: 1;
  cursor: progress;
}

.laedt::before {
  content: "";
  position: absolute;
  left: var(--space-md);
  /* 🔴 Vertikal zentriert ueber `inset` + `margin-block: auto`, NICHT ueber
     `top: 50%; margin-top: -8px`. Zwei Gruende: Das negative Literal waere
     die halbe Ringhoehe und muesste bei jeder Groessenaenderung mitgepflegt
     werden — und `transform: translateY(-50%)` als Alternative wuerde von
     der Drehung ueberschrieben. */
  top: 0;
  bottom: 0;
  margin-block: auto;
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  /* Eine offene Seite macht die Drehung erst sichtbar. */
  border-right-color: transparent;
  border-radius: var(--radius-full);
  animation: dreht 900ms linear infinite;
}

@keyframes dreht {
  to { transform: rotate(360deg); }
}

/* Wer Bewegung im System abgestellt hat, bekommt einen ruhigen Ring
   statt gar keiner Rueckmeldung. */
@media (prefers-reduced-motion: reduce) {
  .laedt::before { animation: none; opacity: 0.6; }
}

/* ── Countdown zum Start der Marktzahlen ─────────────────────────────── */

/* Abgesetzt, aber nicht schreiend: Der Block wirbt, steht aber in einer
   Arbeitsoberflaeche. Ein oranger Kasten mit Verlauf waere ein Banner,
   und Banner werden uebersehen. */
.countdown {
  padding: var(--space-lg);
  margin-bottom: var(--space-xl);
  border: 1px solid var(--accent-dark);
  border-radius: var(--radius-lg);
  /* 🔴 KEIN Verlauf (Fabi 22.08.2026: „der hintergund bleibt aber textbox
     ohne verlauf"). Die Box sitzt IN einer Karte, die selbst schon den
     Verlauf traegt — zwei uebereinander ergeben einen schmutzigen Fleck
     statt einer Tiefe. Die Karte behaelt ihren, diese Box bleibt flach. */
  background: var(--surface-2);
}

.countdown-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}

.countdown-titel {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--text);
}

/* Die Tageszahl traegt die Dringlichkeit und darf deshalb als einzige
   Stelle im Block die Akzentfarbe fuehren. */
.countdown-tage {
  font-weight: 700;
  color: var(--accent-text);
  white-space: nowrap;
}

.countdown-text {
  margin: var(--space-md) 0 var(--space-lg);
  max-width: 68ch;
  line-height: 1.7;
  color: var(--text-muted);
}

.countdown button { margin-top: 0; }

/* ── Genre-Auswahl im Event-Formular ─────────────────────────────────── */

/* 🔴 `position: relative` am Rahmen, damit die aufgeklappte Auswahl DARUEBER
   liegt statt das Formular auseinanderzuschieben. Genau das war der Fehler:
   siebzehn Schaltflaechen in voller Breite untereinander (Fabi 22.08.2026:
   „dropdown mit mehrfachauswahl. keine liste"). */
.genre-feld { position: relative; }

/* Das zugeklappte Feld sieht aus wie ein Auswahlfeld — weil es eines ist. */
.genre-anzeige {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  margin-top: var(--space-2xs);
  min-height: 44px;
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  color: var(--text);
  font-weight: 400;
  text-align: left;
  cursor: pointer;
}

.genre-anzeige:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--border-strong);
}

.genre-pfeil { flex: 0 0 auto; color: var(--text-muted); }

/* Aufgeklappt: schwebt ueber dem Formular, scrollt bei Bedarf in sich. */
.genre-wahl {
  position: absolute;
  z-index: var(--z-aufklapp);
  top: 100%;
  left: 0;
  right: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  max-height: 260px;
  overflow-y: auto;
  margin-top: var(--space-2xs);
  padding: var(--space-md);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  box-shadow: var(--shadow-card);
}

/* Antippbar statt Mehrfach-Auswahlfeld — auf dem Handy der einzige Weg,
   der wirklich funktioniert. Mindesthoehe fuer den Daumen. */
.genre-chip {
  /* 🔴 `width: auto` gegen die globale Button-Regel: Ohne das nimmt jeder
     Chip die volle Zeile und aus der Auswahl wird wieder eine Liste. */
  width: auto;
  flex: 0 0 auto;
  margin-top: 0;
  min-height: 40px;
  padding: var(--space-xs) var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
}

.genre-chip:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--border-strong);
  color: var(--text);
}

/* Gewaehlt: gefuellt, damit die Auswahl auf einen Blick erkennbar ist
   und nicht erst beim Lesen der Randfarbe. */
.genre-chip.an {
  background: var(--accent-gradient);
  border-color: transparent;
  color: var(--on-accent);
}

/* Leerzustand der QR-Karte: der eigene Code und der Weg zum Aushang. */
.qr-leerhilfe {
  display: flex;
  align-items: center;
  gap: var(--space-xl);
  flex-wrap: wrap;
  margin-top: var(--space-lg);
}

/* Weisser Grund und Innenabstand: Ein QR auf dunklem Untergrund wird von
   vielen Kameras nicht erkannt, und ohne Rand ebenfalls nicht. */
.qr-vorschau {
  width: 168px;
  height: 168px;
  padding: var(--space-sm);
  border-radius: var(--radius-md);
  background: var(--qr-quiet);
}

/* Abschnittsueberschrift im Ueberblick. Trennt Statistik, Umsatz und
   Follower voneinander — vorher lagen die Karten in einer Reihe und der
   Betreiber musste jede lesen, um zu wissen, wovon sie handelt. */
.abschnitt {
  margin: var(--space-2xl) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  letter-spacing: 0.4px;
  color: var(--text-muted);
  text-transform: uppercase;
}

/* Die erste Ueberschrift braucht oben keinen zusaetzlichen Abstand. */
.abschnitt:first-of-type { margin-top: var(--space-xl); }

/* ── Globale Club-Messung ────────────────────────────────────────────── */

/* 🔴 Diese Karte ist der wichtigste Grund, warum ein Club seine Umsaetze
   pflegt (Fabi 22.08.2026). Deshalb traegt sie als einzige ein Bild und
   eine Ueberschrift in Plakatgroesse — alles andere im Panel ist
   Arbeitsflaeche, das hier ist ein Versprechen. */
.szene-karte {
  position: relative;
  overflow: hidden;
  padding: var(--space-3xl);
  border-color: var(--accent-dark);
  /* Reihenfolge: Schleier ueber dem Bild, Bild ueber der Flaeche. */
  background: var(--szene-schleier), var(--szene-bild), var(--surface-1);
  background-size: cover, cover, auto;
  background-position: center, center right, center;
}

/* 🔴 Mit `.szene-karte` davor, sonst gewinnt `.card h2` (Klasse + Element
   schlaegt Klasse allein) und die Ueberschrift bleibt bei 17px — gemessen. */
.szene-karte .szene-titel {
  margin: 0 0 var(--space-md);
  max-width: 22ch;
  font-family: var(--font-display);
  /* 🔴 Kleiner und luftiger als der erste Wurf (Fabi 22.08.2026: „ist zu
     gross und zeilen abstand mus mehr sein"). Bei 56 px stiessen die beiden
     Zeilen fast aneinander — die Boldonse ist eine blockige Versalschrift,
     bei der 1,05 als Durchschuss die Unterlaengen der ersten Zeile auf die
     Versalien der zweiten setzt. 1,25 gibt ihr Luft, ohne dass die
     Ueberschrift ihre Wucht verliert. */
  font-size: clamp(26px, 2.8vw, 38px);
  line-height: 1.25;
  color: var(--text);
}

/* Auf schmalen Schirmen wuerde das Bild den Text ueberlagern — dort
   traegt die Karte nur noch den Schleier. */
@media (max-width: 700px) {
  .szene-karte {
    padding: var(--space-xl);
    background: var(--szene-schleier), var(--surface-1);
  }
}

/* ── Zeitraum-Leiste (Fabi 22.08.2026) ──────────────────────────────────
   „bei den ganzen statistiken sind keine Zeitraum filter drin"

   🔴 Eigene Klasse statt `.chips`: Die Leiste sitzt zwischen Überschrift
   und Zahlen und braucht dort mehr Luft nach unten als eine gewöhnliche
   Chip-Reihe im Formular — sonst kleben die Knöpfe auf den Kacheln. */
.zeitraum-leiste {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin: var(--space-md) 0 var(--space-lg);
}
.zeitraum-leiste:empty { display: none; }

/* Gesperrte Stufe: sichtbar, aber erkennbar tot. Ein Schloss davor sagt
   ohne Text, warum — der Titel liefert den Satz beim Verweilen nach. */
.chip-gesperrt::before {
  content: '\1F512';
  margin-right: var(--space-2xs);
  font-size: 11px;
}

/* Kachel ohne Zahl: Der Strich steht für „siehst du nicht", nicht für 0.
   Deshalb gedämpft — eine kräftige Ziffernfarbe würde ihn wie einen Wert
   aussehen lassen. */
.nacht-kachel-gesperrt .nacht-wert { color: var(--text-muted); }
.nacht-kachel-gesperrt { opacity: 0.72; }

/* ── Kalender mit Mehrfachauswahl (Fabi 22.08.2026) ──────────────────────
   „großer kalender mit mehrfach auswahl und danach einfach auf übenhemen
   klicken."

   🔴 Der Kalender steht links, die Angaben rechts. Untereinander wäre der
   Übernehmen-Knopf unter einer Bildschirmhöhe Kalender verschwunden — und
   ein Knopf, den man erst suchen muss, ist bei „viel einfacher" das
   Gegenteil des Auftrags. */
.kalender-spalten {
  display: grid;
  grid-template-columns: minmax(280px, 380px) 1fr;
  gap: var(--space-xl);
  align-items: start;
}
@media (max-width: 860px) {
  .kalender-spalten { grid-template-columns: 1fr; }
}

.kalender { user-select: none; }

.kalender-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.kalender-monat {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--text);
  text-transform: capitalize;
}
.kalender-pfeil {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  width: auto;
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
}
.kalender-pfeil:hover { border-color: var(--accent); color: var(--accent); }

.kalender-gitter {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-2xs);
}

.kalender-wochentage { margin-bottom: var(--space-2xs); }
.kalender-wochentag {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  font-family: inherit;
  padding: var(--space-2xs) 0;
  margin: 0;
  width: auto;
  min-height: 0;
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.kalender-wochentag:hover { color: var(--accent); background: var(--surface-2); }

.kalender-luecke { min-height: var(--tap-min); }

/* 🔴 Jeder Tag ist mindestens ein volles Tap-Ziel. Ein Kalender mit 30px-
   Feldern ist am Telefon nicht bedienbar, und genau dort steht der Betreiber
   (im Club, nicht am Schreibtisch). */
.kalender-tag {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-height: var(--tap-min);
  width: 100%;
  margin: 0;
  padding: 0;
  font-size: var(--text-sm);
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}
.kalender-tag:hover:not(:disabled) { border-color: var(--accent); }
.kalender-tag.gewaehlt {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}
.kalender-tag.kalender-heute:not(.gewaehlt) { border-color: var(--accent); }
.kalender-tag.kalender-vorbei {
  opacity: 0.3;
  cursor: default;
}

.kalender-angaben { min-width: 0; }

/* ── Klassen ohne Regel, nachgetragen (22.08.2026) ──────────────────────
   Gefunden vom neuen check-panel-klassen.js: acht Klassen wurden im Panel
   vergeben, hatten aber nirgends eine Regel. Drei davon tragen sichtbaren
   Text und standen damit unformatiert auf der Seite. */

/* Der Hinweis unter einem gesperrten Feld („Mit Pro erscheint der
   Ticket-Button…"). Er trägt zusätzlich `.field-hint`, brauchte aber einen
   eigenen Abstand nach oben — sonst klebt er am gesperrten Eingabefeld. */
.feld-gate-hinweis {
  margin-top: var(--space-xs);
}

/* Die Prozentzahl zwischen zwei Stufen des Trichters. */
.kette-quote {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
}

/* Zweite Zeile in einer Listenzeile (z. B. „seit 14.08.2026" beim Gerät). */
.row-sub {
  margin-top: var(--space-2xs);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Kopfbereich des Pro-Reiters: der Text neben dem Preis. */
.pro-kopf-text {
  min-width: 0;
}

/* Die Gegenüberstellung Free/Pro und die drei Karten darunter. */
.pro-vergleich {
  margin-top: var(--space-xl);
}
.pro-status,
.pro-rechnungen,
.pro-faq {
  margin-top: var(--space-lg);
}

/* ══════════════════════════════════════════════════════════════════════════
   MOBIL: DER KOPF FRISST DEN BILDSCHIRM (Fabi 22.08.2026)

   Fabi zeigte einen Screenshot vom Samsung: „haben wir keinen mobile Version
   vom Club Dashboard?"

   🔴 GEMESSEN, nicht geschätzt (390 × 844 px):
     Kopfleiste     164 px
     Clubkopf       125 px
     Reiterleiste    60 px
     ────────────────────
     389 px, bis der erste Inhalt anfängt — 46 % des Bildschirms.

   Ein Betreiber öffnet das Panel abends an der Tür, um EINE Zahl zu sehen.
   Wenn er dafür erst an einem halben Bildschirm Kopfzeile vorbeiscrollen
   muss, benutzt er es nicht.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /*
   * Die Kopfleiste umbrach in DREI Zeilen (gemessen 156 px):
   *   1. Logo
   *   2. Club-Auswahl — ueber die volle Breite
   *   3. Abzeichen „Free“ + Abmelden
   *
   * Zwei Kleinigkeiten erzwangen das: ein Platzhalter mit `flex: 1 1 auto`,
   * der die restliche Zeile auffrass, und eine Club-Auswahl, die sich die
   * volle Breite nahm. Beides behoben passen Auswahl, Abzeichen und
   * Abmelden in EINE Zeile.
   */
  .topbar-spacer {
    display: none;
  }
  #switchWrap {
    /*
     * 🔴 `flex-basis: 120px` UND NICHT `auto`.
     *
     * Mit `auto` ist der Ausgangspunkt die INHALTSBREITE der Auswahlliste —
     * hier 343 px, weil der laengste Clubname sie aufzieht. Damit passt sie
     * neben dem Logo nicht mehr in die Zeile, bekommt eine eigene, und
     * `flex-grow` blaeht sie dort auf die volle Breite. Abzeichen und
     * Abmelden landen in einer dritten Zeile. `min-width: 0` allein aendert
     * daran nichts: es erlaubt das Schrumpfen, verhindert aber nicht den
     * Umbruch, der vorher passiert.
     *
     * Mit 120 px als Basis passen Auswahl, Abzeichen und Abmelden in EINE
     * Zeile, und `grow` gibt der Auswahl den Rest.
     */
    flex: 1 1 120px;
    min-width: 0;
  }
  #switchWrap select {
    width: 100%;
    min-width: 0;
  }
  /* Ohne diese Zeile schrumpfen Abzeichen und Knopf statt der Auswahl. */
  #planBadge,
  #btnLogout {
    flex: 0 0 auto;
  }

  .topbar-inner {
    padding: var(--space-sm) var(--space-lg);
    gap: var(--space-sm);
  }

  /*
   * Der Clubkopf trägt Logo, Name, Stadt und Begrüßung — vier Elemente für
   * eine Information, die oben in der Auswahlliste ohnehin schon steht.
   *
   * 🔴 Die Begrüßung („Angemeldet als …") verschwindet am Telefon. Sie
   *    beantwortet eine Frage, die sich abends an der Tür niemand stellt,
   *    und kostet eine ganze Zeile. Am Rechner bleibt sie.
   */
  .venue-head {
    padding: var(--space-md) var(--space-lg) 0;
  }
  .venue-head #greeting {
    display: none;
  }
  .venue-head h1 {
    font-size: var(--text-lg);
  }
  .venue-logo {
    max-height: 34px;
  }

  /*
   * 🔴 Die beiden Nebenkacheln NEBENEINANDER statt untereinander.
   *    Gemessen: je 343 × 114 px — zwei volle Zeilen für zwei Zahlen. Neben-
   *    einander sind sie halb so hoch und genauso lesbar; und die Frage
   *    „Follower gegen QR-Scans" ist ein Vergleich, der nebeneinander gehört.
   */
  .lage-seite {
    grid-template-rows: none;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-sm);
  }
  .lage-mini {
    padding: var(--space-md);
  }
  .lage-mini-wert {
    font-size: var(--text-2xl);
  }
  /* Der Verlaufsstrich unter der Followerzahl braucht in der halben Breite
     zu viel Platz für zu wenig Aussage. */
  .lage-mini-spark {
    display: none;
  }
}


/* 🔴 STEHT BEWUSST AM DATEIENDE. Eine Media-Query ist nicht spezifischer
   als eine normale Regel — bei gleicher Spezifitaet gewinnt die spaetere.
   Dieser Block stand zuerst fuenf Zeilen VOR `.saeule-spalte` und wurde
   davon still ueberschrieben (gemessen: 5 px Spalten statt 26). */
/*
 * Am Handy bekommen die Saeulen eine MINDESTBREITE und scrollen dafuer.
 *
 * 🔴 Der erste Versuch war das Gegenteil — enger stellen, damit alle 24
 *    ins Bild passen. Ergebnis am 390-px-Bildschirm: 13 px pro Saeule, und
 *    die Beschriftungen liefen ineinander („0001020304…“ als durchgehende
 *    Ziffernkette). Ein Diagramm, dessen Achse man nicht lesen kann, ist
 *    keins. Im Screenshot gesehen, nicht gerechnet.
 *
 *    Lieber scrollen als quetschen: 26 px reichen fuer „00“ und die Zahl
 *    darueber, die 24 Stunden ergeben rund 620 px — das wischt sich in der
 *    Karte, ohne die Seite mitzunehmen (siehe .saeulen overflow-x).
 */
@media (max-width: 640px) {
  .saeulen { gap: var(--space-sm); }
  .saeule-spalte {
    flex: 0 0 auto;
    min-width: 26px;
  }
  .saeule-wert { font-size: var(--text-sm); }
}

/* ── Pushes (Push-Engine) ── */
.quota-bar { height: 8px; border-radius: var(--radius-full); background: var(--surface-2); overflow: hidden; margin: var(--space-xs) 0; }
.quota-bar-fill { height: 100%; background: var(--accent-gradient); transition: width var(--dur-base) var(--ease); }
.push-preview { border-radius: var(--radius-lg); padding: var(--space-sm) var(--space-md); background: var(--surface-2); border: 1px solid var(--border); }
.push-preview-app { font-size: var(--text-xs); color: var(--text-muted); margin-bottom: var(--space-2xs); }
.push-preview-title { font-weight: 700; color: var(--text); }
.push-preview-body { color: var(--text); }
.push-preview img { max-width: 100%; border-radius: var(--radius-md); margin: var(--space-xs) 0; }
.geo-days { display: grid; gap: var(--space-xs); }
.geo-day { display: grid; grid-template-columns: 36px auto 16px auto minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-xs); align-items: center; }
.geo-day-name { font-weight: 600; }
.sub-card { position: relative; padding: var(--space-xs) 0; }
@media (max-width: 720px) { .geo-day { grid-template-columns: 36px minmax(0, 1fr) 16px minmax(0, 1fr); } .geo-day input[type="text"] { grid-column: span 4; } }
.push-felder { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-sm); }
.push-tabelle { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.push-tabelle th, .push-tabelle td { text-align: left; padding: var(--space-xs) var(--space-sm); border-bottom: 1px solid var(--border); vertical-align: top; }
.push-tabelle th { color: var(--text-muted); font-weight: 600; }
@media (max-width: 720px) { .push-felder { grid-template-columns: minmax(0, 1fr); } }
