/* ============================================================
   Handball Ferienschule – Design System v2
   Designsprache der Originalseite: Rot / Weiß / Dunkelgrau,
   Condensed-Typografie in Großbuchstaben, rechteckige Buttons.
   ============================================================ */
/* DSGVO-konform: Fonts von EU-Servern (fonts.bunny.net, Drop-in-Ersatz für Google Fonts, kein Tracking) */
@import url('https://fonts.bunny.net/css?family=oswald:400,500,600,700|source-sans-pro:400,600,700&display=swap');

:root {
  --red: #e2001a;           /* HFS-Rot: Topbar, Buttons, Akzente */
  --red-dark: #b80015;
  --dark: #3a3f44;          /* Überschriften, Nav, Footer */
  --darker: #26292c;
  --navy: #3a3f44;          /* Alias (Admin nutzt --navy) */
  --navy-dark: #26292c;
  --sand: #f5b942;          /* Warn-Akzent (Auslastung, „knapp“) */
  --bg: #f7f7f7;
  --card: #ffffff;
  --text: #3a3f44;
  --muted: #5f6569;          /* dunkler als früher – WCAG-AA-Kontrast auf Weiß (war 4.40:1, jetzt 5.9:1) */
  --line: #e4e6e8;
  --ok: #0c6e38;             /* dunkler – WCAG-AA-Kontrast auf hellgrünem Badge-Hintergrund (war 3.1:1) */
  --radius: 3px;
  --shadow: 0 2px 10px rgba(0, 0, 0, .09);
  --font: "Source Sans Pro", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-head: "Oswald", "Arial Narrow", system-ui, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* Ausnahme vom Reset darueber: ein modaler <dialog> steht nur deshalb mittig im Fenster,
   weil der Browser ihm `margin: auto` gibt. Das `margin: 0` der Zeile davor hat das
   ueberschrieben — jedes Pop-up klebte oben links in der Ecke. Hier zurueckgeholt, an
   einer Stelle statt an jedem Dialog einzeln (Bildschau, Verwaltung, Gutscheine). */
dialog { margin: auto; }
html { scroll-behavior: smooth; }
body { font-family: var(--font); color: var(--text); background: #fff; line-height: 1.6; }
img { max-width: 100%; display: block; }
a { color: var(--red); }

h1, h2, h3, h4 { font-family: var(--font-head); text-transform: uppercase; letter-spacing: .02em; }

.container { max-width: 1180px; margin: 0 auto; padding: 0 20px; }

/* ---------- Aktionsbanner (Einstellungen -> Aktion, optional) ----------
   Vorher komplett inline in lib/nav.php (Fund aus dem Codebase-Review, 2026-08-18) – nur die
   Hintergrundfarbe bleibt inline (`--banner-bg`), weil sie eine von Hans getroffene Wahl je
   Aktion ist, keine feste Design-Entscheidung. Ruhiger als vorher: kleinere, gleichmaessigere
   Schrift statt durchgehend fett, weniger Innenabstand (keine unnoetige Hoehe), der Knopf
   bleibt der hellste Punkt in der Zeile und damit gut sichtbar. */
.hfs-banner { background: var(--banner-bg, var(--red)); color: #fff; font-size: .86rem; }
.hfs-banner .container { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 4px 16px; padding: 8px 16px; text-align: center; }
.hfs-banner .text { font-weight: 500; }
.hfs-banner .cta { display: inline-block; flex: none; padding: 5px 16px; background: #fff;
  color: var(--banner-bg, var(--red)); border-radius: 999px; font-weight: 700; font-size: .82rem;
  text-decoration: none; white-space: nowrap; transition: opacity var(--t-fast, .15s) ease; }
.hfs-banner .cta:hover { opacity: .85; }
@media (max-width: 560px) { .hfs-banner .container { padding: 7px 14px; } }

/* ---------- Topbar (ROT wie Original) ---------- */
.topbar { background: var(--red); color: #fff; font-size: .88rem; font-weight: 600; }
.topbar .container { display: flex; justify-content: space-between; align-items: center; min-height: 42px; flex-wrap: wrap; gap: 4px 16px; }
.topbar a { color: #fff; text-decoration: none; margin-right: 20px; }
.topbar a:hover { opacity: .85; }

/* ---------- Header / Nav (weiß, Nav in Versalien) ---------- */
/* Eigentlicher Grund, warum die Nav bisher NICHT dauerhaft sichtbar blieb (2026-08-28,
   Fund beim Nachbauen des WhatsApp-Feedbacks): #site-header (der JS-Ankerpunkt aus
   lib/seite.php/site.js) ist nur so hoch wie Banner+Topbar+Header zusammen – ein sticky
   Kind kann aber nie ueber den Rand seines eigenen Elternelements hinaus kleben bleiben.
   Sobald man weiter scrollte, als dieser Wrapper hoch war, verschwand die Nav MIT ihm.
   `display: contents` nimmt den Wrapper aus dem Layout heraus (bleibt per getElementById
   weiter auffindbar, wrapMain() in site.js braucht nur DOM-Nachbarschaft, keine Box) –
   damit ist body der wirksame Elternrahmen, und der ist so hoch wie die ganze Seite. */
#site-header { display: contents; }
header.site { background: #fff; position: sticky; top: 0; z-index: 50; box-shadow: 0 1px 0 var(--line); }
header.site .container { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 120px;
  transition: min-height var(--t-med) var(--ease); }
.logo { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.logo img.brand { height: 92px; width: auto; display: block; transition: height var(--t-med) var(--ease); }
@media (max-width: 900px) { header.site .container { min-height: 92px; } .logo img.brand { height: 66px; } }
/* Schrumpft beim Scrollen (2026-08-28, WhatsApp-Feedback). Sichtbar auch am Seitenende war
   die Nav schon vorher (position: sticky oben) – hier kommt nur die Verkleinerung dazu,
   die Klasse setzt js/site.js. */
header.site.scrolled .container { min-height: 72px; }
header.site.scrolled .logo img.brand { height: 52px; }
@media (max-width: 900px) {
  header.site.scrolled .container { min-height: 64px; }
  header.site.scrolled .logo img.brand { height: 44px; }
}
.logo .ball { width: 52px; height: 52px; flex: none; }
.logo .lt { font-family: var(--font-head); font-weight: 700; text-transform: uppercase; color: var(--red); font-size: 1.5rem; line-height: 1.02; letter-spacing: .01em; }
.logo small { display: block; font-family: var(--font-head); font-weight: 500; font-size: .62rem; color: var(--dark); letter-spacing: .14em; margin-top: 4px; }
nav.main { display: flex; align-items: center; gap: 2px; }
nav.main a { font-family: var(--font-head); text-transform: uppercase; text-decoration: none; color: var(--dark); font-weight: 500; font-size: 1rem; letter-spacing: .04em; padding: 10px 13px; }
nav.main a:hover, nav.main a.active { color: var(--red); }
.btn { display: inline-block; background: var(--red); color: #fff !important; font-family: var(--font-head); font-weight: 600; text-transform: uppercase; letter-spacing: .06em; text-decoration: none; padding: 12px 26px; border-radius: var(--radius); border: none; cursor: pointer; font-size: .95rem; transition: background .15s; }
.btn:hover { background: var(--red-dark); }
.btn.ghost { background: transparent; color: var(--dark) !important; border: 2px solid var(--dark); }
.btn.ghost:hover { background: var(--dark); color: #fff !important; }
.btn.big { padding: 15px 36px; font-size: 1.05rem; }
.mobile-cta { display: none; }   /* feste CTA-Leiste – nur auf Mobil sichtbar (s. Media-Query) */
#navToggle { display: none; background: none; border: none; font-size: 1.7rem; color: var(--dark); cursor: pointer; }

/* ---------- Foto-Slideshow (Startseite) ---------- */
/* Das Fotoband der Campseiten (.camp-photo) traegt dasselbe Mass. Deshalb dieselbe Regel und
   nicht dieselbe Zahl an zwei Stellen — sonst wandert die Startseite irgendwann allein weiter. */
.slider, .camp-photo { position: relative; width: 100%; height: min(78vh, 660px); min-height: 430px; overflow: hidden; background: var(--darker); }
/* Der Titel steht IM Foto, unten links – das Fotoband ist der Seitenkopf. Stand bis
   2026-08-12 nur inline in camp.php; die Standortseiten hatten deshalb stattdessen einen
   grauen Balken. Jetzt hier, damit beide Campseiten denselben Kopf tragen. */
.camp-photo > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.camp-titel { position: absolute; z-index: 2; left: clamp(20px, 5vw, 60px); bottom: clamp(40px, 6vh, 60px);
  max-width: min(720px, 72%); }
.camp-titel .badge { margin-bottom: 14px; }
.camp-titel h1 { font-family: var(--font-head); font-weight: 700; text-transform: uppercase; color: #fff;
  font-size: clamp(1.8rem, 4.8vw, 3.2rem); line-height: 1.02; text-wrap: balance;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55), 0 4px 30px rgba(0, 0, 0, .6); }
.camp-titel .lead { margin: 10px 0 0; font-size: 1.05rem; color: #f1f3f4;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6), 0 2px 18px rgba(0, 0, 0, .55); }

.slider .slide { position: absolute; inset: 0; opacity: 0; transition: opacity .8s ease; }
.slider .slide.on { opacity: 1; }
.slider .slide img { width: 100%; height: 100%; object-fit: cover; }

/* Verlauf nach unten: traegt die Aussage lesbar ueber jedem Foto (Kontrast ≥ 4.5:1),
   ohne das Bild flaechig abzudunkeln. */
.slider::after, .camp-photo::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(20,22,24,.88) 0%, rgba(20,22,24,.55) 26%, rgba(20,22,24,.10) 52%, rgba(20,22,24,0) 72%); }

/* Die Aussage steht jetzt in der Anzeigenschrift der Seite, nicht auf einem Aufkleber. */
.slider .caption { position: absolute; z-index: 2; left: clamp(20px, 5vw, 60px); bottom: clamp(104px, 15vh, 150px);
  max-width: min(18ch, 62%); color: #fff; font-family: var(--font-head); font-weight: 700; text-transform: uppercase;
  font-size: clamp(2rem, 5.6vw, 4rem); line-height: .96; letter-spacing: -.005em; text-wrap: balance;
  text-shadow: 0 2px 18px rgba(0,0,0,.45); }
.slider .caption::before { content: ""; display: block; width: 64px; height: 5px; background: var(--red); margin-bottom: clamp(14px, 2vw, 22px); }

.slider .hero-cta { position: absolute; z-index: 3; left: clamp(20px, 5vw, 60px); bottom: clamp(38px, 6vh, 58px); }

/* Pfeile und Punkte bilden rechts unten eine Bedienzeile. Mittig am linken Rand
   standen die Pfeile der Aussage im Weg (4 px Abstand zum Titel). */
.slider .arrow { position: absolute; top: auto; bottom: clamp(76px, 10.5vh, 104px); transform: none; background: none; border: none; color: #fff; font-size: 2.4rem; line-height: 1; cursor: pointer; padding: 6px 14px; text-shadow: 0 1px 6px rgba(0,0,0,.5); z-index: 3; }
.slider .arrow:hover { color: var(--red); }
.slider .arrow.prev { left: auto; right: calc(clamp(20px, 5vw, 60px) + 54px); }
.slider .arrow.next { right: clamp(20px, 5vw, 60px); }
.slider .dots { position: absolute; right: clamp(20px, 5vw, 60px); bottom: clamp(44px, 6.6vh, 64px); display: flex; justify-content: flex-end; gap: 10px; z-index: 3; }
.slider .dots button { width: 13px; height: 13px; border-radius: 50%; border: none; background: rgba(255,255,255,.55); cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.4); }
.slider .dots button.on { background: #fff; }

/* ---------- Seitenkopf (Unterseiten) ---------- */
.hero { position: relative; color: #fff; background: linear-gradient(rgba(38,41,44,.82), rgba(38,41,44,.82)), var(--dark); }
.hero .container { position: relative; z-index: 1; padding: 58px 20px 64px; max-width: 900px; text-align: center; }
/* Typografisch statt weisser Kasten (Fund aus dem Codebase-Review, 2026-08-18): dieselbe
   feine rote Linie wie bei `.slider .caption::before`, damit Startseite und Unterseiten
   dieselbe Bildsprache teilen statt zweier verschiedener Auszeichnungen fuer denselben Zweck. */
.badge { display: inline-block; background: none; color: #fff; font-family: var(--font-head); font-weight: 600; font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; padding: 0; margin-bottom: 20px; text-shadow: 0 1px 3px rgba(0,0,0,.35); }
.badge::before { content: ""; display: block; width: 40px; height: 3px; background: var(--red); margin: 0 auto 10px; }
/* In .camp-titel steht der Text linksbuendig (siehe dort) – die Linie folgt, statt mittig
   ueber kuerzerem Text zu haengen. */
.camp-titel .badge::before { margin-left: 0; margin-right: 0; }
.hero h1 { font-size: clamp(1.7rem, 4.5vw, 2.7rem); line-height: 1.15; font-weight: 600; margin-bottom: 16px; }
.hero p.lead { font-size: 1.12rem; color: #d9dcdf; margin-bottom: 26px; max-width: 720px; margin-left: auto; margin-right: auto; }
.hero .actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
.hero .actions .btn.ghost { color: #fff !important; border-color: #fff; }
.hero .actions .btn.ghost:hover { background: #fff; color: var(--dark) !important; }
.hero.small .container { padding: 42px 20px 48px; }
/* Redesign 2026-08-19: Text unten links statt zentriert – das Kopfbild soll den groessten
   Teil der Flaeche behalten, siehe docs/superpowers/specs/2026-08-19-hero-typografie-...
   `body[data-page="..."] .hero` (weiter unten) verankert den Container per Flex am unteren
   Rand; hier nur Breite/Ausrichtung/Abstand des Textblocks selbst. */
.hero.small .container { text-align: left; max-width: 560px; padding: 0 30px 34px; margin: 0; }
/* Kraeftigerer Schatten als die Grundfassung (.35): die Zeile ist klein und steht ueber
   Fotos, die in der Verwaltung ausgetauscht werden – ueber hellem Sand oder einem sonnigen
   Gesicht traegt der Verlauf allein sie nicht. Die H1 hat aus demselben Grund laengst einen
   doppelten Schatten; hier fehlte er. */
.hero.small .badge { position: static; padding-left: 0; display: inline-flex; align-items: center; gap: 10px;
  text-shadow: 0 1px 2px rgba(0,0,0,.7), 0 2px 14px rgba(0,0,0,.55); }
.hero.small .badge::before { position: static; width: 22px; height: 2px; border-radius: 0;
  box-shadow: none; transform: none; margin: 0; }
.hero.small h1 { font-size: clamp(1.9rem, 4.6vw, 2.7rem); line-height: 1.04; letter-spacing: -.01em; }
/* Der Vorspann steht seit 2026-08-19 nicht mehr im Hero, sondern als `p.sub` im ersten
   Abschnitt darunter – nicht ausgeblendet, sondern verschoben (er traegt echten Inhalt,
   auf /camps sogar aus der Verwaltung). An seiner Stelle steht jetzt der Handlungsknopf:
   die Unterseiten hatten bisher gar keinen im Seitenkopf. */
.hero.small .hero-tat { margin: 18px 0 0; }

/* Intro-Band unter der Slideshow (Startseite) */
.introband { background: #fff; padding: 56px 0 8px; }
.introband h1 { color: var(--dark); font-size: clamp(1.5rem, 3.6vw, 2.3rem); font-weight: 600; line-height: 1.2; margin-bottom: 14px; }
.introband .lead { font-family: var(--font-head); text-transform: uppercase; color: var(--dark); font-size: 1.05rem; font-weight: 500; letter-spacing: .03em; max-width: 800px; }
/* Eigene Regel statt Wiederverwendung von `.hero .actions`: dort ist zentriert (weisser Text
   auf Foto), hier links (folgt Ueberschrift/Fliesstext daneben) — echter `gap` statt der
   frueheren `margin-left` am zweiten Knopf, damit auf Mobil (unten) sauber untereinander
   getrennt statt aneinandergeklebt. */
.introband .actions { display: flex; gap: 14px; flex-wrap: wrap; }
.hero-stats { display: flex; gap: 44px; margin-top: 34px; flex-wrap: wrap; }
.hero-stats div { text-align: center; }
.hero-stats b { display: block; font-family: var(--font-head); font-size: 2rem; color: var(--red); }
.hero-stats span { font-size: .82rem; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

/* ---------- Sections ---------- */
section.block { padding: 52px 0; }
section.block.alt { background: var(--bg); }
h2.section { font-size: clamp(1.35rem, 3vw, 1.9rem); color: var(--dark); font-weight: 600; margin-bottom: 8px; }
h2.section::after { content: ""; display: block; width: 64px; height: 4px; background: var(--red); margin-top: 10px; }
p.sub { color: var(--muted); margin: 16px 0 32px; max-width: 680px; }

/* ---------- Cards ---------- */
.grid { display: grid; gap: 20px; }
.grid.c3 { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
/* auto-fit statt auto-fill: die zwei Karten fuellen die Reihe aus und stapeln unter 320 px+Luft
   von selbst — kein eigener Media-Query fuer Mobil noetig. */
.grid.c2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

/* ---------- Die Aufstellung (Teamseite) ----------------------------------------------------
   Kein Kartenraster mit Rahmen und Schatten, sondern eine Mannschaftsaufstellung: das Portraet
   traegt den Namen, darunter steht in einer schmalen Spalte, was die Person kann. Der Ort ueber
   dem Namen ist keine Zierde — bei einem Trainerteam, das aus Hamburg, Leipzig, vom Niederrhein
   und aus Schweden anreist, ist die Herkunft eine echte Angabe.
   Der Gruender bekommt die ganze Reihe: gleich grosse Kacheln wuerden behaupten, hier sei jeder
   dasselbe.
   ------------------------------------------------------------------------------------------- */
/* Reihen statt Raster: die Bildseite wechselt, das Zweitbild ueberlappt die aeussere Ecke,
   dahinter steht ein roter Block. Gleich grosse Kacheln lesen sich wie ein Katalog — eine
   Mannschaftsaufstellung ist keine Produktliste, und die alte Seite hatte darin recht.
   Der rote Block ist derselbe Anspielstrich, der vor jedem Ortsnamen steht, nur als Flaeche. */
.aufstellung { display: grid; gap: clamp(46px, 6vw, 92px); margin-top: 32px; }
.person { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(26px, 5vw, 64px); align-items: center; }
.person:nth-child(even) .bilder { order: 2; }
/* Jede zweite Reihe faellt etwas tiefer — der Versatz, der die Seite in Bewegung haelt. */
.person:nth-child(odd) .bilder { margin-top: clamp(0px, 2vw, 26px); }

.person .bilder { position: relative; }
.person .bilder::before { content: ""; position: absolute; z-index: 0; background: var(--red);
  left: -16px; bottom: -16px; width: 44%; height: 44%; }
.person:nth-child(even) .bilder::before { left: auto; bottom: auto; right: -16px; top: -16px; }
.person .haupt { position: relative; z-index: 1; overflow: hidden; background: var(--darker); border-radius: var(--radius); }
.person .haupt img, .person .ohne-foto { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; display: block;
  transition: transform .6s var(--ease); }
/* Zweit- und Drittbild: kleiner, mit weissem Rand wie ein Abzug, ueber die Ecke gelegt. */
.person .neben { position: absolute; z-index: 2; margin: 0; width: 42%; overflow: hidden;
  border: 5px solid #fff; box-shadow: var(--shadow); border-radius: var(--radius); }
.person .neben img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.person .neben.n1 { right: -7%; bottom: -9%; }
.person .neben.n2 { left: -7%; top: -8%; width: 33%; }
.person:nth-child(even) .neben.n1 { right: auto; left: -7%; }
.person:nth-child(even) .neben.n2 { left: auto; right: -7%; }
/* Fehlt das Foto, steht dort nicht einfach ein schwarzer Kasten: die Initialen liegen ueber den
   Torraumboegen, die auf jedem Seitenkopf dieser Seite liegen. Eine Luecke, die zur Seite gehoert,
   liest sich als „Foto folgt" — ein schwarzes Rechteck liest sich als Fehler. */
.person .ohne-foto { position: relative; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, #2f3337, #23262a 60%, #2f3337); color: rgba(255,255,255,.5);
  font-family: var(--font-head); font-size: 3rem; letter-spacing: .1em; }
.person .ohne-foto::before, .person .ohne-foto::after {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%); aspect-ratio: 1;
  border-radius: 50%; pointer-events: none; }
.person .ohne-foto::before { width: 150%; bottom: -62%; border: 2px solid rgba(255,255,255,.10); }
.person .ohne-foto::after  { width: 196%; bottom: -88%; border: 2px dashed rgba(226,0,26,.20); }
/* Nur das Bild bewegt sich, im festen Rahmen — die Reihe selbst bleibt stehen. */
.person:hover .haupt img { transform: scale(1.045); }

/* Der Text: Herkunft als Anspielstrich, Name gross, Lizenz in Rot, dann der Satz. */
.person .text { min-width: 0; }
.person .ort { display: block; font-family: var(--font-head); font-size: .72rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 10px; padding-left: 26px; position: relative; }
.person .ort::before { content: ""; position: absolute; left: 0; top: .52em; width: 18px; height: 2px; background: var(--red); }
.person h3 { margin: 0; color: var(--dark); font-size: clamp(1.5rem, 3vw, 2.2rem); line-height: 1.02;
  text-transform: uppercase; letter-spacing: .01em; }
.person .rolle { margin: 10px 0 0; font-family: var(--font-head); text-transform: uppercase;
  letter-spacing: .05em; font-size: .95rem; color: var(--red); }
.person .satz { margin: 14px 0 0; color: var(--muted); font-size: 1rem; line-height: 1.7; max-width: 48ch; }
.person .satz.offen { font-style: italic; opacity: .75; }

/* Der Gruender bekommt mehr Flaeche: gleich grosse Reihen wuerden behaupten, hier sei jeder dasselbe. */
.person.gross { grid-template-columns: minmax(0, 1.2fr) minmax(0, .9fr); }
.person.gross h3 { font-size: clamp(1.9rem, 4.2vw, 3rem); }
.person.gross .satz { font-size: 1.06rem; line-height: 1.75; }

/* Auf dem Telefon steht nichts mehr uebereinander: Portraet oben, die weiteren Bilder als
   Reihe darunter. Ueberlappungen brauchen Platz, den ein Telefon nicht hat. */
@media (max-width: 760px) {
  .aufstellung { gap: 46px; }
  .person, .person.gross { grid-template-columns: 1fr; gap: 18px; }
  .person:nth-child(even) .bilder, .person:nth-child(odd) .bilder { order: 0; margin-top: 0; }
  .person .bilder { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .person .haupt { grid-column: 1 / -1; }
  .person .haupt img, .person .ohne-foto { aspect-ratio: 4 / 3; }
  .person .neben, .person:nth-child(even) .neben { position: static; width: auto; border-width: 4px; }
  .person .bilder::before, .person:nth-child(even) .bilder::before {
    left: -14px; right: auto; top: auto; bottom: -14px; width: 38%; height: 30%; }
  .person .ohne-foto { font-size: 2.4rem; }
}
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 24px; }
/* h2 mit derselben Groesse: einige Karten tragen seit dem 2026-08-29 ein h2 statt h3, weil
   ihre Seite sonst von h1 direkt auf h3 sprang. Die Rangfolge aendert sich, die Optik nicht. */
.card h3, .card h2:not(.section) { color: var(--dark); font-size: 1.15rem; font-weight: 600; margin-bottom: 8px; }
.card p { font-size: .95rem; color: var(--muted); }
.card .icon { width: 48px; height: 48px; border-radius: var(--radius); background: var(--red); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 1.35rem; margin-bottom: 14px; }

/* ---------- SVG-Icons (ersetzen die früheren Emojis) ---------- */
.ic { width: 1.15em; height: 1.15em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -.18em; flex: none; }
.card .icon .ic { width: 26px; height: 26px; }              /* weiß auf rotem Tile (erbt color:#fff) */
.ico { color: var(--red); display: inline-flex; align-items: center; vertical-align: middle; }  /* Inline-Icon */
h2.section .ico { margin-right: 8px; }
h2.section .ico .ic { width: 1.05em; height: 1.05em; }
a .ic { margin-right: 7px; vertical-align: -.2em; }
.chk { color: var(--ok); } .chk-x { color: var(--red); }   /* Inline ✓/✗-Ersatz */

/* Camp-Karte */
.camp { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.camp .head { background: var(--dark); color: #fff; padding: 16px 20px; border-top: 4px solid var(--red); }
.camp .head .dates { font-family: var(--font-head); font-size: .82rem; color: #f2b8bf; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.camp .head h3 { color: #fff; margin: 4px 0 0; font-size: 1.2rem; font-weight: 600; }
.camp .body { padding: 18px 20px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.camp .region { color: var(--muted); font-size: .88rem; }
.camp .meta { display: flex; justify-content: space-between; align-items: center; margin-top: auto; gap: 10px; flex-wrap: wrap; }
.camp .price { font-family: var(--font-head); font-weight: 700; font-size: 1.3rem; color: var(--dark); flex: 1 1 auto; min-width: 150px; }
.camp .price small { font-family: var(--font); font-weight: 600; color: var(--muted); font-size: .72rem; }
.tag { display: inline-block; font-size: .75rem; font-weight: 700; padding: 3px 10px; border-radius: 2px; text-transform: uppercase; letter-spacing: .04em; }
.tag.frei { background: #e5f7ec; color: var(--ok); }
.tag.knapp { background: #fdf3e0; color: #7a4f07; } /* WCAG-AA-Kontrast (war 3.57:1) */
.tag.voll { background: #fde8ea; color: #c1001a; } /* WCAG-AA-Kontrast (war 4.21:1) */
/* Grau, nicht rot: ein vergangener Termin ist keine schlechte Nachricht, sondern gar keine.
   „zu" (Anmeldung geschlossen) liegt dazwischen – der Termin findet statt, nur nicht mehr
   ueber das Formular. */
.tag.vorbei { background: #eceef1; color: #4a5568; }
.tag.zu { background: #eef2fb; color: #2b4a8a; }

/* ---------- Info A–Z Accordion ---------- */
.accordion details { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 10px; overflow: hidden; }
.accordion summary { cursor: pointer; font-family: var(--font-head); font-weight: 500; text-transform: uppercase; letter-spacing: .03em; color: var(--dark); padding: 14px 18px; list-style: none; display: flex; gap: 12px; align-items: baseline; }
.accordion summary::-webkit-details-marker { display: none; }
.accordion summary .letter { color: var(--red); font-size: 1.1rem; font-weight: 700; min-width: 1.2em; }
.accordion details[open] summary { border-bottom: 1px solid var(--line); background: #fafafa; }
.accordion .content { padding: 14px 18px; font-size: .95rem; color: var(--text); }
.accordion .content ul { margin: 8px 0 8px 20px; }

/* ---------- Timeline (Tagesablauf) ---------- */
.timeline { border-left: 3px solid var(--red); padding-left: 22px; max-width: 560px; }
.timeline li { list-style: none; position: relative; padding-bottom: 16px; }
.timeline li::before { content: ""; position: absolute; left: -29px; top: 7px; width: 11px; height: 11px; border-radius: 50%; background: var(--dark); border: 2px solid #fff; box-shadow: 0 0 0 2px var(--red); }
.timeline b { color: var(--dark); margin-right: 8px; }

/* ---------- Formulare ---------- */
form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
form .row.single { grid-template-columns: 1fr; }
label { font-weight: 700; font-size: .86rem; color: var(--dark); display: block; margin-bottom: 4px; }
label .req { color: var(--red); }
input, select, textarea { width: 100%; padding: 10px 12px; border: 1px solid #c9cdd1; border-radius: var(--radius); font-family: var(--font); font-size: .95rem; background: #fff; color: var(--text); }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--red); outline-offset: 0; border-color: var(--red); }
/* Kein Flex mehr, sondern das Kaestchen absolut neben den Text gestellt.
   Als Flex-Behaelter wurde jedes Kind zu einem eigenen Element — auch das
   `<span class="req">*</span>` am Ende. Der Textlauf dazwischen schrumpfte nicht unter
   seine min-content-Breite, und das Sternchen landete dahinter ausserhalb: auf /gutschein
   („Ich habe die Gutschein-Bedingungen sowie die Datenschutzerklaerung gelesen…") 87 px
   ueber dem Rand, die ganze Seite scrollte auf dem Telefon seitwaerts. Auf /anmeldung
   faellt es nicht auf, weil die Saetze dort kuerzer sind; die Ursache ist dieselbe.
   Absolut gesetzt bleiben Text und Sternchen ein normaler Fliesstext und brechen um. */
.check { position: relative; display: block; padding-left: 30px; font-size: .9rem; margin: 14px 0; }
.check input { position: absolute; left: 0; top: 3px; width: auto; margin: 0; }
.alert { padding: 12px 16px; border-radius: var(--radius); margin: 14px 0; font-size: .92rem; display: none; }
.alert.err { background: #fde8ea; color: var(--red-dark); display: block; }
.alert.ok { background: #e5f7ec; color: var(--ok); display: block; }
/* Dritte Stufe zwischen den beiden (2026-08-25, fuer die Planung): der Vorgang hat geklappt,
   aber nicht vollstaendig – eingeteilt, doch ohne Adresse ging keine Anfrage raus. Als „ok"
   waere das eine Falschmeldung, als „err" ein Fehlalarm fuer etwas, das gespeichert wurde.
   Farbwerte wie die beiden darueber: getoenter Hintergrund, dunkler Text fuer den Kontrast. */
.alert.warn { background: #fdf1dd; color: #8a5400; display: block; }

/* Buchungs-Steps */
.steps { display: flex; gap: 8px; margin-bottom: 28px; flex-wrap: wrap; }
.steps span { font-family: var(--font-head); text-transform: uppercase; font-size: .8rem; font-weight: 600; letter-spacing: .04em; padding: 7px 16px; border-radius: 2px; background: var(--card); border: 1px solid var(--line); color: var(--muted); }
.steps span.active { background: var(--red); color: #fff; border-color: var(--red); }
.steps span.done { background: #e5f7ec; color: var(--ok); border-color: #bfe8cf; }

/* ---------- Footer ---------- */
footer.site { background: var(--darker); color: #b6bcc2; margin-top: 64px; }
footer.site .cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 32px; padding: 48px 0 32px; }
/* h2, nicht h4 (2026-08-29): der Seiteninhalt endet bei h2, die Fusszeile sprang direkt auf
   h4 — ein Sprung ueber h3 hinweg auf rund 35 Seiten, weil die Fusszeile ueberall dieselbe
   ist. Als h2 sind es gleichrangige Geschwister des Seiteninhalts, und Screenreader
   behalten die Spaltentitel in ihrer Ueberschriftennavigation. Groesse bleibt wie gehabt. */
footer.site h2 { color: #fff; font-size: 1rem; font-weight: 600; margin-bottom: 12px; }
footer.site a { color: #b6bcc2; text-decoration: none; display: block; padding: 3px 0; font-size: .92rem; }
footer.site a:hover { color: #fff; }
/* Unterscheidet den Marken-Absatz optisch von den Links daneben (2026-08-28,
   WhatsApp-Feedback: beide teilten sich bisher dieselbe Farbe #b6bcc2). */
footer.site .marke { font-style: italic; opacity: .82; }
footer.site .legal { border-top: 1px solid rgba(255,255,255,.12); padding: 16px 0; font-size: .82rem; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
/* padding statt nur margin (Lighthouse-Fund 2026-08-30): die Links waren nur ~23,5px hoch,
   knapp unter der 24px-Mindestgroesse fuer Touch-Targets, besonders eng beim Umbruch auf
   mehrere Zeilen auf schmalen Bildschirmen. */
footer.site .legal a { display: inline; margin-left: 16px; padding: 5px 0; }

/* ---------- Tabellen ---------- */
table.list { width: 100%; border-collapse: collapse; background: var(--card); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); font-size: .9rem; }
table.list th { background: var(--dark); color: #fff; text-align: left; padding: 10px 12px; font-family: var(--font-head); font-weight: 500; font-size: .82rem; text-transform: uppercase; letter-spacing: .05em; }
table.list td { padding: 10px 12px; border-top: 1px solid var(--line); }
table.list tr:hover td { background: #fafafa; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  #navToggle { display: block; }
  nav.main { display: none; position: absolute; top: 100%; left: 0; right: 0; background: #fff; flex-direction: column; align-items: stretch; padding: 12px 20px 20px; box-shadow: var(--shadow); }
  nav.main.open { display: flex; }
  nav.main a { padding: 12px; border-bottom: 1px solid var(--line); }
  form .row { grid-template-columns: 1fr; }
  .topbar .phone-extra { display: none; }
  .slider .caption { max-width: 100%; bottom: 92px; }
  /* Auf Mobil traegt die feste Leiste am Fuss bereits die Hauptaktion — ein zweiter,
     identischer Vollbreit-Knopf im Hero waere dieselbe Aufforderung doppelt. */
  .slider .hero-cta { display: none; }
  /* Mobil steht die Aussage ganz unten — dort ist unten kein Platz fuer Pfeile UND Punkte.
     Die Pfeile gehen zurueck an die Flanken, wo sie nichts verdecken. */
  .slider .arrow { top: 46%; bottom: auto; transform: translateY(-50%); font-size: 2rem; opacity: .8; }
  .slider .arrow.prev { left: 4px; right: auto; }
  .slider .arrow.next { right: 4px; }
  .slider .dots { bottom: 40px; }
}
/* ============================================================
   Animationen & Micro-Interactions (UI-Politur)
   – nur transform/opacity, 150–300ms, ease-out rein
   – Scroll-Reveal-Klassen setzt js/site.js (ohne JS bleibt alles sichtbar)
   – respektiert prefers-reduced-motion
   ============================================================ */
:root {
  --ease: cubic-bezier(.22, .61, .36, 1);
  --t-fast: .18s;
  --t-med: .3s;
}

/* --- Scroll-Reveal ---
   Kuerzer und knapper als bis 2026-08-14 (550 ms / 18 px): die Bewegung soll zeigen, dass
   Karten als Gruppe kommen, und dann fertig sein. Ueber 400 ms wartet man auf sie.
   Die Regel fuer `h2.section.reveal::after` stand hier bis heute — sie ist entfallen, weil
   Ueberschriften nicht mehr animiert werden; eine Regel fuer einen Fall, den es nicht gibt,
   liest beim naechsten Mal jemand als Absicht. */
.reveal { opacity: 0; transform: translateY(12px); transition: opacity .38s var(--ease), transform .38s var(--ease); transition-delay: var(--rd, 0ms); }
.reveal.in { opacity: 1; transform: none; }

/* --- Buttons: Anheben + Druck-Feedback --- */
.btn { transition: background var(--t-fast) ease, transform var(--t-fast) var(--ease), box-shadow var(--t-fast) ease; touch-action: manipulation; }
.btn:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(226, 0, 26, .25); }
.btn.ghost:hover { box-shadow: 0 6px 16px rgba(58, 63, 68, .18); }
.btn:active { transform: translateY(0) scale(.97); box-shadow: none; transition-duration: .08s; }

/* --- Nav: animierte Unterstreichung --- */
nav.main a:not(.btn) { position: relative; transition: color var(--t-fast) ease; }
nav.main a:not(.btn)::after { content: ""; position: absolute; left: 13px; right: 13px; bottom: 6px; height: 2px; background: var(--red); transform: scaleX(0); transform-origin: left; transition: transform .25s var(--ease); }
nav.main a:not(.btn):hover::after, nav.main a:not(.btn).active::after { transform: scaleX(1); }

/* --- Mobile-Nav: weiches Aufklappen beim Öffnen (Schließen bleibt bewusst sofort: Exit < Enter) --- */
@media (max-width: 900px) {
  nav.main.open { animation: navIn .22s var(--ease); }
}
@keyframes navIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* --- Cards: sanftes Anheben, Icon-Reaktion --- */
.card { transition: transform var(--t-med) var(--ease), box-shadow var(--t-med) ease; }
/* Kein translateY mehr (2026-08-28, WhatsApp-Feedback): Cards sind reine Info-Kacheln, kein
   Link/Button – das Hochspringen wie bei .btn:hover suggerierte Klickbarkeit, die es nicht
   gibt. Der Schatten bleibt als leiseres Feedback, ohne die Bewegung eines Buttons. */
.grid .card:hover { box-shadow: 0 4px 14px rgba(0, 0, 0, .08); }
.card .icon { transition: transform var(--t-med) var(--ease); }
/* Nur noch Groesse, keine Drehung (2026-08-14): die Karte hebt sich beim Ueberfahren
   ohnehin — zwei Effekte uebereinander sind einer zu viel. */
.card:hover .icon { transform: scale(1.06); }

/* --- Slideshow: Ken-Burns-Zoom + Caption-Einblendung --- */
.slider .slide img { transform: scale(1.08); transition: transform 7s linear; }
.slider .slide.on img { transform: scale(1); }
/* Die Aussage baut sich auf, statt einzublenden: aus der Unschaerfe nach oben in die Ruhelage. */
.slider .caption { opacity: 0; transform: translateY(20px); filter: blur(6px);
  transition: opacity .7s var(--ease) .2s, transform .7s var(--ease) .2s, filter .7s var(--ease) .2s; }
.slider .slide.on .caption { opacity: 1; transform: translateY(0); filter: blur(0); }
.slider .caption::before { transform-origin: left; transform: scaleX(0); transition: transform .55s var(--ease) .45s; }
.slider .slide.on .caption::before { transform: scaleX(1); }
/* Die Pfeile bleiben beim Zeigen an Ort und Stelle — nur die Farbe wechselt (Regel oben). */
.slider .arrow { transition: color var(--t-fast) ease; }
.slider .dots button { transition: transform var(--t-fast) var(--ease), background var(--t-fast) ease; }
.slider .dots button:hover { transform: scale(1.3); }
.slider .dots button.on { transform: scale(1.15); }

/* --- Akkordeon: Inhalt gleitet auf --- */
.accordion summary { transition: background var(--t-fast) ease, color var(--t-fast) ease; }
.accordion summary:hover { background: #fafafa; color: var(--red); }
.accordion details[open] .content { animation: accIn .28s var(--ease); }
@keyframes accIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* --- Formulare, Tabellen, Links: weiche Zustandswechsel --- */
input, select, textarea { transition: border-color var(--t-fast) ease, box-shadow var(--t-fast) ease; }
table.list td { transition: background var(--t-fast) ease; }
footer.site a { transition: color var(--t-fast) ease; }
.topbar a { transition: opacity var(--t-fast) ease; }

/* ============================================================
   Signature: Handball-Torraum + „Anpfiff"-Hero-Entrance
   – Die konzentrischen Torraumbögen (6 m durchgezogen, 9 m gestrichelt)
     sind die unverwechselbare Markierung des Handballfelds und liegen als
     ruhiges Erkennungszeichen in jedem Seitenkopf. Der kleine rote Punkt
     im Badge ist der 7-Meter-Punkt.
   – „Anpfiff": der Hero-Inhalt nimmt beim Laden Aufstellung.
   – Reines transform/opacity; der Reduce-Block unten neutralisiert alles.
   ============================================================ */
.hero { overflow: hidden; }
.hero::before, .hero::after {
  content: ""; position: absolute; z-index: 0; left: 50%; bottom: -60%;
  width: min(700px, 128%); aspect-ratio: 1 / 1; transform: translateX(-50%);
  border-radius: 50%; pointer-events: none; animation: heroArc 1s var(--ease) both;
}
.hero::before { border: 2px solid rgba(255, 255, 255, .11); }                                   /* 6-Meter-Linie */
.hero::after  { width: min(940px, 168%); bottom: -84%; border: 3px dashed rgba(226, 0, 26, .45); animation-delay: .08s; }  /* 9-Meter-Linie (gestrichelt) – 2026-08-19 praesenter, siehe Spec */

/* Kräftigere Seitenkopf-Typo mit Tiefe über den Bögen */
.hero h1 { font-size: clamp(2rem, 5.4vw, 3.2rem); line-height: 1.08; letter-spacing: .01em; text-shadow: 0 2px 24px rgba(0, 0, 0, .28); }
.hero .badge { position: relative; padding-left: 30px; }
.hero .badge::before { content: ""; position: absolute; left: 14px; top: 50%; width: 7px; height: 7px; border-radius: 50%; background: var(--red); transform: translateY(-50%); box-shadow: 0 0 0 3px rgba(226, 0, 26, .25); }

/* „Anpfiff"-Aufstellung: Badge fällt ein, Rest steigt gestaffelt */
.hero .badge, .hero h1, .hero p.lead, .hero .actions, .hero .hero-tat { animation: heroRise .6s var(--ease) both; }
.hero .hero-tat { animation-delay: .20s; }   /* nimmt den Platz, an dem vorher der Vorspann stand */
.hero .badge   { animation-name: heroDrop; animation-duration: .55s; }
.hero h1       { animation-delay: .10s; }
.hero p.lead   { animation-delay: .20s; }
.hero .actions { animation-delay: .30s; }

@keyframes heroArc  { from { opacity: 0; transform: translateX(-50%) scale(.9); } to { opacity: 1; transform: translateX(-50%) scale(1); } }
/* Materializing-Enter (opacity + translateY + blur): Elemente kommen „in den Fokus" statt nur einzublenden */
@keyframes heroRise { from { opacity: 0; transform: translateY(18px); filter: blur(6px); } to { opacity: 1; transform: none; filter: blur(0); } }
@keyframes heroDrop { from { opacity: 0; transform: translateY(-12px); filter: blur(4px); } to { opacity: 1; transform: none; filter: blur(0); } }

/* Das Kopfbild kommt seit 2026-08-14 aus `lib/seite.php` (`--kopfbild`), nicht mehr aus
   acht festen Regeln mit je vier Dateiendungen. Der Browser laedt alle Ebenen einer
   `background-image`-Liste — auf jeder Seite mit Kopfbild waren das **drei vergebliche
   404-Anfragen** (.jpeg, .png, .webp), auf acht Seiten 24 Stueck. Sie machten die Seite
   langsamer und verstopften die Fehlerkonsole, in der dann echte Fehler untergehen.
   Nebenbei laedt jetzt jedes Format, das wirklich im Ordner liegt, statt nur .jpg.
   Verlauf 2026-08-19 vom Mittelband (26–72%, .46) auf einen reinen Bodenverlauf umgestellt:
   der Text sitzt jetzt unten links, in der Bildmitte – wo meist das Motiv steht – braucht es
   keine Abdunklung mehr. */
/* Die Stuetzstellen sind am gerenderten Seitenkopf gemessen, nicht geschaetzt: der Textblock
   liegt zwischen 57 % (Oberkante Kicker) und 92 % (Unterkante Knopf) der Bildhoehe. Ein
   Verlauf, der erst bei 88 % Wirkung zeigt, laesst genau die kleine Zeile ungedeckt, die
   sie am noetigsten hat. Ueber 40 % bleibt das Bild vollstaendig unberuehrt – dort steht
   auf diesen Fotos das Motiv. */
body[style*="--kopfbild"] .hero { background-image: linear-gradient(to bottom, rgba(16,18,20,0) 0%, rgba(16,18,20,0) 40%, rgba(16,18,20,.28) 62%, rgba(16,18,20,.46) 100%), var(--kopfbild); }

/* ============================================================
   Barrierefreiheit
   ============================================================ */
/* Skip-Link: unsichtbar bis per Tab fokussiert, springt zum Hauptinhalt */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 1000;
  background: var(--dark); color: #fff; padding: 12px 20px;
  font-weight: 600; text-decoration: none; border-radius: 0 0 6px 0;
}
.skip-link:focus { left: 0; }

/* Sichtbarer Fokus-Ring für Tastaturnutzung (Mauskicks bleiben ruhig) */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
.card:focus-visible, summary:focus-visible {
  outline: 2px solid var(--red); outline-offset: 2px; border-radius: 2px;
}

/* --- Cookie-Banner --- */
.cookie-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
  background: var(--dark); color: #fff; padding: 18px 20px;
  display: flex; flex-wrap: wrap; gap: 14px 24px; align-items: center; justify-content: space-between;
  box-shadow: 0 -4px 20px rgba(0,0,0,.2);
}
.cookie-banner p { margin: 0; font-size: .9rem; max-width: 640px; line-height: 1.5; }
.cookie-banner p a { color: var(--sand); }
.cookie-banner .cookie-actions { display: flex; gap: 10px; flex-shrink: 0; }
.cookie-banner .btn.ghost { border-color: #fff; color: #fff !important; }
@media (max-width: 640px) { .cookie-banner { flex-direction: column; align-items: stretch; } }

/* --- Reduzierte Bewegung: alles deaktivieren --- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  html { scroll-behavior: auto; }
}

/* ============================================================
   Handy-Feinschliff  –  echter Phone-Breakpoint (nur ≤600px)
   Der bisherige Breakpoint war 900px (Tablet); auf schmalen
   Handys wirkte dadurch vieles zusammengequetscht. Diese Regeln
   greifen NUR auf dem Handy – Tablet & Desktop bleiben unverändert.
   ============================================================ */
@media (max-width: 600px) {
  /* Mehr nutzbare Breite + ruhigere vertikale Rhythmik */
  .container { padding: 0 16px; }
  section.block { padding: 34px 0; }
  .hero .container { padding: 40px 16px 44px; }
  .hero.small .container { padding: 30px 16px 34px; }
  /* Bottom-Wert bewusst deutlich groesser als der Rest der mobilen Rhythmik (34px): die feste
     „Jetzt zum Camp anmelden"-Leiste (.mobile-cta, site.js) sitzt fest am Bildschirmrand –
     mit 4px lagen die beiden roten Knoepfe ("Jetzt Camp buchen" im Intro, die Leiste darunter)
     ohne echte Luft dazwischen, sahen aus wie ein Duplikat statt zwei getrennte CTAs. */
  .introband { padding: 38px 0 32px; }
  /* Beide Knoepfe untereinander, gleich breit — vorher inline nebeneinander mit nur 10px
     Abstand, wodurch „Standorte & Termine" nicht mit „Jetzt Camp buchen" fluchtete, sobald
     der zweite Knopf auf eine neue Zeile umbrach (Noah, 24.08.: „nach rechts gerueckt"). */
  .introband .actions { flex-direction: column; align-items: stretch; }
  .introband .actions .btn { width: 100%; text-align: center; }
  footer.site { margin-top: 44px; }
  footer.site .cols { gap: 24px; padding: 36px 0 24px; }

  /* Überschriften auf schmalem Screen nicht zu wuchtig */
  h2.section { font-size: 1.28rem; }
  .introband h1 { font-size: 1.5rem; }

  /* Topbar mobil: Kontaktdaten raus (Telefon/E-Mail stehen im Inhalt der Kontakt-Seite),
     nur Instagram + Facebook – als kompakte Buttons */
  .topbar .tb-contact { display: none; }
  .topbar .container { justify-content: center; text-align: center; min-height: 38px; }
  .topbar .tb-social { display: flex; gap: 8px; }
  /* .10 statt .16 (Lighthouse-Fund 2026-08-30): weisser Text auf dem aufgehellten Rot kam
     auf 4,38:1 Kontrast, gefordert sind 4,5:1. Etwas weniger Weiss im Hintergrund senkt die
     Aufhellung genug (rechnerisch ~4,65:1), ohne dass der Pillen-Look merklich anders wirkt. */
  .topbar .tb-social a { margin: 0; padding: 4px 16px; border-radius: 999px; font-weight: 600;
    background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.45); }

  /* Hero-Stats: gleichmäßig, mittig, enger */
  .hero-stats { gap: 18px 26px; justify-content: center; margin-top: 24px; }
  .hero-stats b { font-size: 1.7rem; }

  /* Karten etwas kompakter innen */
  .card { padding: 20px; }
  .grid { gap: 16px; }

  /* Camp-Karte: Preis und Verfügbarkeits-Tag sauber untereinander
     statt in einer engen Zeile zusammengequetscht */
  .camp .meta { flex-direction: column; align-items: flex-start; gap: 8px; }
  .camp .price { min-width: 0; }

  /* Breite Tabellen horizontal scrollen lassen statt quetschen */
  .table-wrap, table.list { display: block; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* `table.list.karten`: aus jeder Zeile wird auf dem Telefon eine Karte.
     Seitliches Schieben ist keine Loesung, sondern eine Aufgabe an den Leser — die Terminliste
     war 743 px breit in einer 358-px-Spalte, also lag die Haelfte immer ausserhalb des Bildes.
     Die Spaltenueberschrift wandert dabei in die Zeile (`data-label`), sonst steht da nur ein
     Datum ohne Bedeutung. Bewusst per Klasse: Tabellen ohne `data-label` blieben sonst ohne
     Beschriftung zurueck. */
  table.list.karten, table.list.karten tbody, table.list.karten tr, table.list.karten td { display: block; width: auto; }
  table.list.karten { overflow: visible; background: none; box-shadow: none; }
  table.list.karten thead { display: none; }
  table.list.karten tr { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow); margin-bottom: 12px; overflow: hidden; }
  table.list.karten td { display: flex; gap: 14px; justify-content: space-between; align-items: baseline;
    border-top: 0; padding: 9px 14px; }
  table.list.karten td + td { border-top: 1px solid var(--line); }
  table.list.karten td::before { content: attr(data-label); color: var(--muted); font-size: .74rem;
    text-transform: uppercase; letter-spacing: .06em; font-weight: 600; flex: 0 0 auto; }
  table.list.karten td:empty { display: none; }        /* ausgebuchte Termine haben keinen Knopf */
  table.list.karten td .btn { width: 100%; text-align: center; }

  /* Buchungs-Schritte umbrechen sauber, volle Breite der aktiven Stufe */
  .steps { gap: 6px; }
  .steps span { flex: 1 1 auto; text-align: center; }

  /* Hero-CTAs mobil: volle Breite, klar tippbar */
  .hero .actions { flex-direction: column; }
  .hero .actions .btn { width: 100%; }

  /* Feste Aktions-Leiste unten: „Jetzt anmelden" immer erreichbar (stärkster CTA auf Mobil) */
  .mobile-cta { display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
    padding: 10px 14px; padding-bottom: calc(10px + env(safe-area-inset-bottom));
    background: rgba(255,255,255,.94); backdrop-filter: blur(8px);
    border-top: 1px solid var(--line); box-shadow: 0 -4px 16px rgba(0,0,0,.10); }
  .mobile-cta .btn { width: 100%; text-align: center; padding: 14px; }
  /* War fest 68px (26.08.2026, Noah: "immer noch nicht richtig" – auf iPhones mit
     Home-Indikator wuchs die Leiste selbst um env(safe-area-inset-bottom) (Zeile oben),
     dieser Platzhalter aber nicht mit. Der Rest der letzten Zeile blieb dauerhaft hinter der
     Leiste verdeckt, nicht nur kurz beim Scrollen – kein Scrollweg mehr, ihn freizulegen.
     Jetzt derselbe Zuschlag wie bei der Leiste selbst, damit beide immer zusammenpassen. */
  body { padding-bottom: calc(68px + env(safe-area-inset-bottom)); }
}

/* ---------- Browser-Oberflaechen ----------
   Textmarkierung, Cursor und Bildlaufleiste liefert der Browser sonst in Systemgrau —
   Farben, die zu keinem Entwurf gehoeren. Sie kommen jetzt aus der Marke. */
::selection { background: var(--red); color: #fff; }
::-moz-selection { background: var(--red); color: #fff; }
input, textarea, select { caret-color: var(--red); }

@supports (scrollbar-color: red white) {
  html { scrollbar-color: #c3c7ca var(--bg); }
}
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: #c3c7ca; border: 3px solid var(--bg); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--dark); }
/* ============================================================
   Seitenkopf-Fotos (Unterseiten)
   – Foto per Ordnerstruktur einsetzen: einfach eine Datei mit dem
     passenden Namen (siehe unten) unter img/hero/ ablegen — kein Code
     nötig. Solange keine Datei da ist, bleibt automatisch der bisherige
     dunkle Hintergrund + Torraumbögen (Fallback über background-color,
     nicht Bildbezogen). Erlaubte Formate: .jpg/.jpeg/.png/.webp — die
     zuerst gefundene Datei gewinnt.
   – Anleitung: siehe img/hero/ANLEITUNG-FOTOS.txt
   ============================================================ */
body[data-page="camps"] .hero, body[data-page="info"] .hero, body[data-page="team"] .hero,
body[data-page="kontakt"] .hero, body[data-page="anmeldung"] .hero, body[data-page="gutschein"] .hero {
  background-size: cover; background-position: center;
}
/* Die `--kopfbild`-Verlaufsregel stand hier ein zweites Mal, wortgleich zur Fassung im
   „Signature"-Abschnitt weiter oben. Beim Verlaufs-Umbau am 2026-08-19 zusammengefuehrt –
   zwei identische Regeln bedeuten, dass eine Aenderung an der falschen Stelle wirkungslos
   bleibt. Die gueltige Fassung steht oben bei den Torraumbögen. */

/* ===================================================================
   Standortseiten: Fotos vom Ort
   Der Ort ist das eigentliche Argument – die Bilder bekommen deshalb
   die volle Breite und keinen Kartenrahmen. Erstes Bild gross, Rest
   als Raster; auf dem Telefon ein wischbarer Streifen.
   =================================================================== */
.ortbilder { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px; background: var(--darker); }
.ortbild { position: relative; display: block; padding: 0; border: 0; margin: 0; cursor: zoom-in;
  overflow: hidden; background: var(--darker); min-height: 150px; border-radius: var(--radius); }
.ortbild img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.16, 1, .3, 1); }
.ortbild span { position: absolute; left: 0; right: 0; bottom: 0; padding: 26px 16px 12px;
  font-family: var(--font-head); text-transform: uppercase; letter-spacing: .05em;
  font-size: .78rem; color: #fff; text-align: left;
  background: linear-gradient(to top, rgba(20, 22, 24, .82), rgba(20, 22, 24, 0));
  transform: translateY(4px); opacity: .92; transition: transform .35s var(--ease), opacity .35s var(--ease); }
.ortbild:hover img, .ortbild:focus-visible img { transform: scale(1.045); }
.ortbild:hover span, .ortbild:focus-visible span { transform: translateY(0); opacity: 1; }
.ortbild:focus-visible { outline: 3px solid var(--red); outline-offset: -3px; }

@media (min-width: 900px) {
  .ortbilder { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 172px; }
  /* Ab drei Bildern führt das erste als Doppelkachel. Darunter gäbe es nichts zu führen. */
  .ortbild:first-child:nth-last-child(n+3) { grid-column: span 2; grid-row: span 2; }
  .ortbild:first-child:last-child { grid-column: 1 / -1; grid-row: span 2; }
  .ortbild:first-child:nth-last-child(2), .ortbild:first-child:nth-last-child(2) ~ .ortbild { grid-column: span 2; grid-row: span 2; }
}
@media (max-width: 899px) {
  .ortbilder { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .ortbilder::-webkit-scrollbar { display: none; }
  .ortbild { flex: 0 0 84%; height: 238px; scroll-snap-align: center; }
  .ortbild:first-child { flex-basis: 92%; }
}

/* ===================================================================
   Ein einzelnes Foto neben dem Standorttext (Modell B, 2026-08-14)
   Unter drei Fotos gibt es keine Galerie mehr – siehe standort.php.
   Das uebrige Foto steht hier neben dem Text und illustriert ihn,
   statt als vollflaechiger Balken unter dem Titelbild zu stehen.
   Ohne Textfoto bleibt der Block einspaltig wie zuvor.
   =================================================================== */
/* Absatzabstand im Fliesstext (2026-08-25). Der Reset ganz oben setzt `* { margin: 0 }` —
   damit klebten in `.beschreibung` alle Absaetze aneinander. Auf der Standortseite werden die
   uebernommenen Texte der alten Website je Leerzeile in ein eigenes <p> zerlegt (absatz_liste),
   und genau dieser Abstand fehlte: aus vier Absaetzen wurde optisch eine Wand. Aufgefallen ist
   es erst, als unter „Lage & Anreise" ein zweiter Absatz dazukam — der Fehler war aber schon
   vorher in jedem mehrabsaetzigen Ortstext.
   `p + p` und nicht `margin-bottom`: der letzte Absatz soll keinen Abstand nach unten
   bekommen, sonst waechst der Block nach dem Text weiter, als sei da noch etwas. */
.beschreibung p + p { margin-top: 1.05em; }

.textbild-satz { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 34px;
  align-items: start; }
.textbild { margin: 0; }
/* Leichtes Hochformat statt 4/5 (2026-08-29). Die Vorlagen sind quer (1920x1277, also 3:2);
   bei 4/5 fielen 47 % der Bildbreite weg, und neben den drei Absaetzen der Startseite stand
   das Foto 187 px zu tief. Mit 5/4 auf 400 px Spalte sind es 17 % Beschnitt und 107 px –
   auf den Standortseiten (laengerer Text) sitzt das Bild dann 72 px ueber dem Textende,
   was deutlich weniger auffaellt als ein herausragendes Bild. */
/* `height: auto` gehoert dazu, auch wenn hier keine Hoehe gesetzt ist: ein `height`-Attribut
   am <img> ist ein Praesentationshinweis und setzt eine echte CSS-Hoehe, die `aspect-ratio`
   schlaegt – das Foto stand dann 320 px breit und 1000 px hoch in der Spalte. Die Attribute
   sind hier raus, die Zeile haelt den Fall trotzdem fest. Kein Sprung beim Laden: Breite und
   Verhaeltnis bestimmen die Box schon vor dem Bild. */
.textbild img { width: 100%; height: auto; aspect-ratio: 5 / 4; object-fit: cover; border-radius: var(--radius); }
.textbild figcaption { margin-top: 9px; font-family: var(--font-head); text-transform: uppercase;
  letter-spacing: .05em; font-size: .78rem; color: var(--muted); }
@media (max-width: 800px) {
  /* Untereinander: bei 400 px Bildspalte blieben dem Text sonst rund 20 Zeichen je Zeile. */
  .textbild-satz { grid-template-columns: 1fr; gap: 22px; }
  .textbild img { aspect-ratio: 16 / 10; }
}

/* Grossansicht: nativer Dialog, damit Tastatur und Fokusfang vom Browser kommen */
/* `fit-content` statt `auto`: ein modaler Dialog hat links UND rechts inset 0 und wird mit
   `width:auto` so breit wie erlaubt – das Bild stand dann am linken Rand einer unsichtbaren
   1180-px-Flaeche, und die Pfeile klebten am Fensterrand statt am Foto. */
#bildschau { border: 0; padding: 0; max-width: min(1180px, 94vw); max-height: 92vh; width: fit-content;
  background: transparent; overflow: visible; color: #fff; }
#bildschau::backdrop { background: rgba(18, 20, 22, .88); }
#bildschau figure { margin: 0; }
#bildschau img { max-width: 100%; max-height: 82vh; display: block; border-radius: var(--radius);
  box-shadow: 0 18px 48px rgba(0, 0, 0, .5); }
#bildschau figcaption { font-family: var(--font-head); text-transform: uppercase; letter-spacing: .06em;
  font-size: .82rem; padding: 14px 2px 0; color: #e8eaec; }
#bildschau button { position: absolute; background: rgba(255, 255, 255, .12); color: #fff; border: 0;
  cursor: pointer; border-radius: var(--radius); line-height: 1; transition: background .2s var(--ease); }
#bildschau button:hover { background: var(--red); }
#bildschau .zu { top: -46px; right: 0; font-size: 1.6rem; padding: 6px 14px; }
#bildschau .blaettern { top: 40%; font-size: 2.4rem; padding: 6px 18px; }
#bildschau .blaettern.vor { left: -62px; }
#bildschau .blaettern.zur { right: -62px; }
@media (max-width: 780px) {
  #bildschau .blaettern.vor { left: 4px; }
  #bildschau .blaettern.zur { right: 4px; }
}

/* Was im Preis steckt – eine Aufzählung statt dreier gleicher Karten, die auf jeder
   Standortseite dasselbe gesagt haben.
   War ein mehrspaltiges Raster (Noah, 26.08.2026: "nicht so huebsch, von der Aufteilung" –
   bei einer Zahl Zeilen, die nicht durch die Spaltenzahl teilbar war, blieb eine Kachel
   allein in der letzten Reihe stehen; bei Zeilen OHNE Titel – der bisherige Regelfall, siehe
   leistung_teile() – gab es ohnehin keine Fettung und die Karten wirkten wie plumper
   Fliesstext mit Strich davor). Jetzt eine Reihe je Leistung, Titel in einer festen linken
   Spalte: kein Rasterrest mehr, egal wie viele Zeilen es sind, und selbst titellose Zeilen
   (`.ohnetitel`) reihen sich sauber ein statt eine leere Spalte freizulassen. */
.leistungen { list-style: none; margin: 26px 0 0; padding: 0; max-width: 760px; }
.leistungen li { padding: 14px 0 14px 20px; border-top: 1px solid var(--line); font-size: .93rem;
  color: var(--muted); position: relative; display: grid; grid-template-columns: 200px 1fr;
  gap: 2px 24px; align-items: baseline; }
.leistungen li:last-child { border-bottom: 1px solid var(--line); }
.leistungen li.ohnetitel { grid-template-columns: 1fr; }
.leistungen li::before { content: ""; position: absolute; left: 0; top: 22px; width: 9px; height: 2px; background: var(--red); }
.leistungen b { font-family: var(--font-head); text-transform: uppercase;
  letter-spacing: .04em; color: var(--dark); font-size: .92rem; }
@media (max-width: 620px) {
  .leistungen li { grid-template-columns: 1fr; gap: 2px 0; }
}

/* ===================================================================
   Lage & Anreise: Karte mit Einwilligung (2026-08-19)
   Der Platzhalter ist bewusst als Flaeche erkennbar (Schraffur) und nicht
   als Graufeld: er soll aussehen wie etwas, das noch kommt, nicht wie ein
   Bild, das nicht geladen hat. Die Hoehe steht fest, damit beim Laden der
   Karte nichts springt – der Rahmen fuellt exakt dieselbe Box.
   =================================================================== */
.kartenbox { max-width: 900px; }
.karte { position: relative; height: clamp(280px, 34vw, 420px); overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg); }
.karte iframe { width: 100%; height: 100%; border: 0; display: block; }
.karte-frage { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; text-align: center; padding: 24px;
  background: repeating-linear-gradient(45deg, #eef0f2, #eef0f2 14px, #e6e9ec 14px, #e6e9ec 28px); }
.karte-frage b { font-family: var(--font-head); text-transform: uppercase;
  letter-spacing: .04em; color: var(--dark); }
.karte-frage p { font-size: .84rem; color: var(--muted); max-width: 42ch; line-height: 1.55; }
.karte-fuss { margin-top: 10px; font-size: .9rem; }

@media (prefers-reduced-motion: reduce) {
  .ortbild img, .ortbild span { transition: none; }
  .ortbild:hover img, .ortbild:focus-visible img { transform: none; }
}

/* ===================================================================
   Bildhöhen wachsen mit der Breite

   Der Seitenkopf hatte keine eigene Höhe – sie kam allein vom Text,
   also rund 260 px, egal wie breit das Fenster ist. `cover` skaliert
   das Foto aber auf die Breite: bei 1200 px ist ein 3:2-Bild 800 px
   hoch, sichtbar sind 260 – ein Drittel. Bei 1800 px ist es 1200 hoch,
   sichtbar immer noch 260 – ein Fünftel. Breiter heißt damit **weniger**
   Foto, und weil mittig beschnitten wird, verschwinden zuerst Beine und
   Boden.

   Deshalb wächst die Höhe jetzt mit der Breite (vw statt fester Wert):
   der sichtbare Anteil bleibt konstant, bis die Obergrenze greift.
   34vw × 1,5 ≈ die Hälfte des Bildes, auf jeder Fenstergröße gleich.
   =================================================================== */
body[data-page="camps"] .hero, body[data-page="info"] .hero, body[data-page="team"] .hero,
body[data-page="kontakt"] .hero, body[data-page="anmeldung"] .hero, body[data-page="gutschein"] .hero {
  /* Die Hoehe folgt der Breite (46vw), gedeckelt nicht durch einen festen Pixelwert,
     sondern durch die Fensterhoehe: ein Seitenkopf darf gross sein, aber nie mehr als
     drei Viertel des Bildschirms fuellen. Vorher stand hier 520px – ab rund 1530 px
     Breite wuchs damit nur noch das Bild, nicht der Rahmen, und genau das hat wieder
     Bildinhalt abgeschnitten. */
  min-height: max(320px, min(46vw, 72vh));
  /* Redesign 2026-08-19: Text unten links statt zentriert (siehe .hero.small weiter oben) –
     justify-content dafuer von center auf flex-end. */
  display: flex; flex-direction: column; justify-content: flex-end;
  /* Leicht oberhalb der Mitte verankert: fällt etwas weg, dann der Boden
     und nicht die Gesichter. */
  background-position: center 44%;
}
body[data-page="camps"] .hero > .container, body[data-page="info"] .hero > .container,
body[data-page="team"] .hero > .container, body[data-page="kontakt"] .hero > .container,
body[data-page="anmeldung"] .hero > .container, body[data-page="gutschein"] .hero > .container { width: 100%; }

/* Startseiten-Slideshow: dieselbe Rechnung, nur großzügiger – sie ist das erste Bild der Seite. */
.slider { height: max(340px, min(52vw, 78vh)); }

/* Standortseiten: das Bildraster darf auf breiten Schirmen mitwachsen. */
@media (min-width: 900px) {
  .ortbilder { grid-auto-rows: clamp(160px, 15vw, 320px); }
}

/* Auf dem Telefon zählt die Höhe des Geräts mehr als die Breite: 34vw wären
   dort 130 px und damit ein Streifen.
   2026-08-19 von 62vw heraufgesetzt: der Wert war fuer den frueher mittig stehenden Text
   bemessen. Seit der Text unten sitzt, ist er hier gemessen 209 px hoch — bei 62vw (233 px
   auf einem 375er Schirm) blieben **23 px Foto**, also genau der Fehler, den dieser Umbau
   beheben soll. 112vw laesst dem Bild rund die Haelfte. */
@media (max-width: 640px) {
  body[data-page="camps"] .hero, body[data-page="info"] .hero, body[data-page="team"] .hero,
  body[data-page="kontakt"] .hero, body[data-page="anmeldung"] .hero, body[data-page="gutschein"] .hero {
    min-height: max(420px, 112vw);
  }
  .hero.small .container { padding: 0 20px 26px; }
  .slider, .camp-photo { height: 76vw; }
}

/* Lesbarkeit ohne Fleck im Bild
   ------------------------------
   Erster Versuch war eine radiale Ellipse hinter der Schrift – die hat sichtbare Kanten
   und schwebt als Fleck im Himmel, weil sie an nichts anschliesst. Eine Abdunklung darf
   entweder das ganze Bild betreffen oder von Rand zu Rand laufen; alles dazwischen liest
   sich als Objekt.

   Deshalb jetzt ein waagerechtes Band über die volle Breite: oben und unten läuft es auf
   null aus, das Foto bleibt an beiden Kanten unberührt, und in der Mitte trägt es die
   Schrift. Weil es links und rechts keine Kante hat, sieht man es nicht als Form. */
/* Zusätzlich die Schrift selbst tragfähig machen – zwei Schatten: einer eng für die Kante,
   einer weit für den Grund. */
body[data-page="camps"] .hero h1, body[data-page="info"] .hero h1, body[data-page="team"] .hero h1,
body[data-page="kontakt"] .hero h1, body[data-page="anmeldung"] .hero h1, body[data-page="gutschein"] .hero h1 {
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55), 0 4px 30px rgba(0, 0, 0, .6);
}
body[data-page="camps"] .hero p.lead, body[data-page="info"] .hero p.lead, body[data-page="team"] .hero p.lead,
body[data-page="kontakt"] .hero p.lead, body[data-page="anmeldung"] .hero p.lead, body[data-page="gutschein"] .hero p.lead {
  color: #f1f3f4; text-shadow: 0 1px 2px rgba(0, 0, 0, .6), 0 2px 18px rgba(0, 0, 0, .55);
}

/* ---------------------------------------------------------------------------
   Ortkachel (2026-08-14)
   Eine Bauform fuer alle drei Stellen, an denen Orte stehen: Startseite
   („Naechste Termine"), /camps und /handballcamps. Vorher hatte jede Seite ihre
   eigene: unter /handballcamps ein Bild mit fester Hoehe und darunter vier
   Absaetze — jede Karte so hoch wie ihr Text, also ein Stapel statt eines
   Rasters. Deshalb hier: gleiche Bildhoehe ueber `aspect-ratio`, gleicher
   Textblock ueber `flex`, und der Fuss immer unten ueber `margin-top:auto`.
   Damit sind die Kacheln einer Reihe gleich hoch, egal wie lang der Ortsname
   ist. Das Bild traegt den Termin — ohne Foto braucht es keine Kachel. */
.ortkacheln { align-items: stretch; }
.ortkachel { display: flex; flex-direction: column; overflow: hidden; height: 100%;
  background: var(--card, #fff); border-radius: var(--radius); text-decoration: none; color: inherit;
  box-shadow: 0 1px 2px rgba(20, 22, 24, .06), 0 8px 24px rgba(20, 22, 24, .06);
  transition: transform .35s var(--ease, ease), box-shadow .35s var(--ease, ease); }
.ortkachel:hover, .ortkachel:focus-visible { transform: translateY(-4px);
  box-shadow: 0 2px 4px rgba(20, 22, 24, .08), 0 18px 40px rgba(20, 22, 24, .16); }
.ortkachel:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }

/* Das Bild fuehrt. `aspect-ratio` statt fester Hoehe: auf dem Telefon wird die Kachel
   breiter und das Foto waechst mit, statt zum Streifen zu werden. */
.ortkachel .bild { position: relative; aspect-ratio: 3 / 2; background: var(--darker); overflow: hidden; border-radius: var(--radius); }
/* Der Bildzoom ist entfallen (2026-08-14): die Kachel hebt sich schon, und ein Zoom auf
   jedem Foto war der vierte Ort auf dieser Seite mit demselben Hover-Scale. Ein Effekt
   je Geste reicht — die Karte bewegt sich, das Bild bleibt ruhig. */
.ortkachel .bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Der Termin steht IM Bild, nicht darunter: er ist die Antwort auf „wann?", und
   unten im Text konkurriert er mit dem Preis. Der Verlauf haelt ihn lesbar, auch
   ueber einem hellen Himmel. */
.ortkachel .bild::after { content: ""; position: absolute; inset: auto 0 0 0; height: 55%;
  background: linear-gradient(to top, rgba(20, 22, 24, .82), rgba(20, 22, 24, 0)); }
.ortkachel .wann { position: absolute; z-index: 1; left: 14px; bottom: 12px; color: #fff;
  font-family: var(--font-head); font-size: .82rem; letter-spacing: .04em; text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .5); }

.ortkachel .text { display: flex; flex-direction: column; flex: 1; padding: 16px 18px 18px; }
.ortkachel h3, .ortkachel h2 { margin: 0; font-size: 1.15rem; line-height: 1.15; text-wrap: balance; }
.ortkachel .region { color: var(--muted); font-size: .88rem; margin-top: 3px; }
/* `auto` klebt den Fuss an die Unterkante — dadurch stehen Preis und Terminzahl in
   einer Reihe auf gleicher Hoehe, auch wenn ein Ortsname zweizeilig wird. */
.ortkachel .fuss { margin-top: auto; padding-top: 14px; display: flex; align-items: baseline;
  justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.ortkachel .preis { font-family: var(--font-head); font-size: 1.05rem; color: var(--navy); }
.ortkachel .preis.leer { font-size: .92rem; color: var(--muted); }
.ortkachel .mehr { font-size: .86rem; font-weight: 600; color: var(--red); white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .ortkachel { transition: none; }
  .ortkachel:hover { transform: none; }
}

/* Lesbarkeit des Seitenkopfs auf dem Telefon (2026-08-14).
   Der Verlauf der Kopfbilder läuft oben und unten auf 0 aus. Auf dem Telefon wird der
   Vorspann drei- bis vierzeilig und rutscht genau in den auslaufenden Bereich — über
   hellem Sand oder Himmel stand der Text dann auf dem Foto statt darüber. Diese Schicht
   liegt zusätzlich darunter, statt acht Seitenregeln einzeln nachzuziehen; der Text hat
   `z-index: 1` und bleibt darüber. */
/* 2026-08-19: seit der Text unten links sitzt, braucht der obere Bildteil auch auf dem
   Telefon keine Abdunklung mehr – aus dem ganzflaechigen Schleier (.28 → .58) wird ein
   Bodenverlauf. Etwas kraeftiger als am Schreibtisch, weil der Text hier zweizeilig wird
   und die Flaeche unter ihm knapper ist. */
@media (max-width: 700px) {
  .hero::before { content: ""; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(to bottom, rgba(16, 18, 20, 0) 40%, rgba(16, 18, 20, .58) 100%); }
}
