/* ============================================================
   TCLE – Startseite (home.css · Mobile-First 2026)
   ============================================================ */

/* ════════════════════════════════════════════════════════════
   HERO
   Foto liegt als volle Hintergrundebene hinter dem gesamten Hero
   (Mobile & Desktop), ein dunkles Overlay sorgt für Lesbarkeit
   des hellen Texts darüber.
   ════════════════════════════════════════════════════════════ */

.hero {
  width: 100%;
  background: var(--color-navy);
  position: relative;
  overflow: clip;
  /* Waagerechtes Wischen blättert das Karussell (js/hero.js) und soll die
     Seite dabei nicht mitziehen. Senkrechtes Scrollen und Zoomen bleiben. */
  touch-action: pan-y pinch-zoom;
}

.hero-photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Eigener Stapelkontext: der z-index der Bilder unten bleibt innerhalb
     des Fotos und kommt .hero-inner und den Punkten nicht in die Quere. */
  isolation: isolate;
}
/* Karussell: alle Bilder liegen deckungsgleich übereinander (cover/center),
   sichtbar wird nur, welches Bild gerade .is-active trägt (js/hero.js) */
.hero-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  opacity: 0;
  /* Ein Bild, das abgelöst wird, bleibt voll sichtbar stehen, bis das neue
     darüber eingeblendet ist, und verschwindet erst dann. Blendeten beide
     gleichzeitig über, schien in der Mitte das Blau des Heros durch beide
     halbdurchsichtigen Bilder. */
  transition: opacity .01s linear .9s, transform .6s var(--ease-out);
  /* Zurückhaltende Gradation nur für die Karussellbilder: etwas weniger
     Sättigung, dafür mehr Tiefe in den Schatten. Statisch – der Crossfade
     zwischen den Bildern läuft unverändert über opacity. */
  filter: saturate(.9) contrast(1.05);
}
.hero-photo img.is-active {
  opacity: 1;
  z-index: 1;
  transition: opacity .9s ease, transform .6s var(--ease-out);
}
/* Dunkles Overlay fürs Foto: sorgt dafür, dass der helle Text überall
   lesbar bleibt, unabhängig davon wie hell/dunkel der Bildausschnitt ist.
   Darüber liegt eine Vignette, die die Ränder weich abfallen lässt und den
   Blick in die Bildmitte führt. */
.hero-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  background:
    radial-gradient(120% 95% at 50% 42%, transparent 40%, rgba(10,16,28,.22) 100%),
    /* Von unten statt von der Seite. Die drei Stuetzstellen bleiben
       unveraendert, nur die Richtung dreht sich: Der Hero-Text steht
       mittig, lag bisher also bei 50 % der Breite und liegt jetzt bei
       50 % der Hoehe. Etwas heller als zuvor (dort .86/.62/.18), damit
       die Fotos nicht so dunkel wirken; am Text rund .45 Deckung. */
    linear-gradient(to top,
      rgba(10,22,46,.72) 0%,
      rgba(10,22,46,.48) 45%,
      rgba(10,22,46,.10) 100%);
}

/* ── Karussell: Punkt-Navigation ──────────────────────────────
   Manueller Bildwechsel, siehe js/hero.js. Liegt bewusst außerhalb
   von .hero-photo (aria-hidden), damit die Buttons für Tastatur/
   Screenreader erreichbar bleiben.
──────────────────────────────────────────────────────────── */
.hero-dots {
  position: absolute;
  left: 50%;
  bottom: var(--space-4);
  transform: translateX(-50%);
  /* Über .hero-inner (z-index:1) – dessen unsichtbare Box (.hero-text füllt
     die Zelle) fängt sonst trotz fehlender sichtbarer Pixel die Klicks ab. */
  z-index: 2;
  display: flex;
}
/* Sichtbarer Punkt bleibt klein (9px), die Klickfläche darum ist
   WCAG-2.5.5-konform min. 44px – Punkt liegt als ::before mittig darin.
   Der aktive Punkt zieht sich zur 24px breiten Pille auf, wie bei den
   Punktleisten der Wischreihen; die 44px-Fläche hat dafür Platz. */
.hero-dot {
  width: var(--touch);
  height: var(--touch);
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: manipulation;
}
.hero-dot::before {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: rgba(255,255,255,.45);
  transition: background-color var(--dur-base) var(--ease-out),
              width var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}
@media (hover: hover) {
  .hero-dot:hover::before { background: rgba(255,255,255,.7); }
}
.hero-dot.is-active::before {
  background: #fff;
  width: 24px;
}
/* Rückmeldung beim Drücken; steht nach .is-active, damit sie auch auf dem
   aktiven Punkt greift. */
.hero-dot:active::before {
  background: rgba(255,255,255,.85);
  transform: scale(.85);
  transition-duration: .1s;
}
.hero-dot:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
  border-radius: 50%;
}
@media (min-width: 1024px) {
  .hero-dots { bottom: var(--space-6); }
}

/* ── Layout-Container ──────────────────────────────────────── */
.hero-inner {
  max-width: var(--max);
  margin: 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  /* Nav-Höhe (60px) als oberer Offset. Unten: Platz für die Punkt-Navigation
     (.hero-dots, absolut positioniert) reservieren, damit sie nicht mit dem
     letzten Hero-Button überlappt. */
  padding: calc(60px + var(--space-8) + var(--space-4)) var(--space-inline) calc(var(--touch) + var(--space-4) + var(--space-3));
  gap: var(--space-8);
  position: relative;
  z-index: 1;
}

/* Tablet (640px+): mehr Luft, Nav 72px */
@media (min-width: 640px) {
  .hero-inner {
    padding-top: calc(72px + var(--space-10) + var(--space-4));
    gap: var(--space-10);
  }
}

/* Desktop (1024px+): volle Höhe · Nav 82px · 100svh */
@media (min-width: 1024px) {
  .hero {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
  }
  .hero-inner {
    align-items: stretch;
    flex: 1;
    /* Container full-width – Padding trägt .hero-text */
    max-width: none;
    margin: 0;
    padding: 0;
    gap: 0;
  }
}

/* ── Text-Spalte ───────────────────────────────────────────────
   Fünf Zeilen: leere Ausgleichszeile, Vereinsname, Headline, CTAs und
   noch eine leere Ausgleichszeile. Die beiden 1fr-Zeilen teilen sich
   den übrigen Platz zu gleichen Teilen – der Block aus Vereinsname,
   Headline und CTAs sitzt dadurch als Einheit mittig, auch waagerecht.
──────────────────────────────────────────────────────────── */
.hero-text {
  display: grid;
  grid-template-rows: 1fr auto auto auto 1fr;
  justify-items: center;
  text-align: center;
}
/* Ausgleichszeilen über und unter dem Block */
.hero-text::before,
.hero-text::after { content: ''; }

@media (min-width: 1024px) {
  .hero-text {
    /* Oben: Nav-Höhe (82px) + Luft; unten Platz für die Punkt-Navigation */
    padding: calc(82px + var(--space-8)) var(--space-inline) var(--space-12);
  }
}

/* Text liegt hell auf dem dunkel überlagerten Foto */
/* Dachzeile: der Vereinsname steht als eigenes Etikett über der Headline.
   Halbfett, ohne Sperrung und leicht transparent, ohne Deko-Strich. Die
   Transparenz steckt in der Farbe, nicht in opacity, weil die Einblendung
   (heroRevealIn) opacity auf 1 animiert.

   Größe und Abstand sind bewusst gesetzt und hängen zusammen: Der Block aus
   Dachzeile, Headline und Buttons sitzt als Einheit mittig (.hero-text,
   grid-template-rows). Ein größerer Abstand nach unten lässt den Block
   wachsen und schiebt die Dachzeile deshalb nach oben – allerdings nur um
   die halbe Differenz, weil die beiden 1fr-Zeilen den Rest aufteilen.
   Gemessen bei 1440×900: 40 % der Hero-Höhe vorher, 38 % jetzt.

   Ohne den größeren Abstand würde die Zeile bei dieser Schriftgröße fast an
   der Headline kleben und nicht mehr als Etikett lesbar sein. Beide Werte
   also nur zusammen ändern. */
.hero-eyebrow {
  font-size: clamp(1.15rem, 1.15vw + .62rem, 1.75rem);
  font-weight: var(--weight-semibold);
  letter-spacing: .02em;
  color: rgba(255,255,255,.85);
  margin-bottom: clamp(1.6rem, 3.2vw, 2.9rem);
}
/* Mobile: Vereinsname bleibt einzeilig. Der Name ist zu lang für eine feste
   Größe, deshalb folgt sie hier der Viewportbreite. min() sorgt dafür, dass
   die Größe nie über den Wert der Basisregel oben hinauswächst – auf
   breiteren Handys bleibt sie unberührt. */
@media (max-width: 639px) {
  .hero-eyebrow {
    /* Obergrenze gemessen, nicht geschätzt: Die Zeile darf wegen nowrap nicht
       umbrechen und würde sonst abgeschnitten. Bei 4.55vw bleibt auf 320px
       noch 18px Reserve, auf 390px 36px. Mehr verträgt der Name nicht. */
    font-size: min(1.5vw + .72rem, 4.55vw);
    white-space: nowrap;
  }
}

/* Headline */
.hero-h1 {
  font-size: clamp(2.4rem, 5.5vw + .5rem, 5.5rem);
  font-weight: var(--weight-semibold);
  color: #fff;
  line-height: var(--leading-none);
  /* Größte Überschrift der Website (38px mobil → 87px auf 1440px) und
     damit eigene Größenstufe; Aufbau und Begründung siehe base.css.
     Bei -.055em stießen auf Desktop in "Schlag groß" S und c fast
     zusammen. Der Bereich beginnt bei 552px Viewport – darunter hält
     die 2.4rem-Untergrenze der font-size die Größe konstant.
     -.048em war immer noch zu eng: bei 87px überlappten "gr" um 13,6px²
     und "hl" um 5,6px² – die Serifen von h und l bildeten unten einen
     durchgehenden Balken. Auch -.02em reichte noch nicht: auf 1920px
     (dort 96px, siehe Media Query unten) blieben g und r in "groß" mit
     5,8px² verbunden. Erst bei -.008em ist das Paar frei. Das ist die
     größte Rücknahme der Website, weil dies die größte Schrift ist –
     und sie kostet nichts, weil die Zeilen hier mit <br> hart umbrechen
     und deshalb kein Umbruch entstehen kann. */
  letter-spacing: clamp(-.008em, .0115rem - .061vw, -.004em);
  /* Ersetzt den Abstand, den vorher der Beschreibungstext zu den Buttons
     beigesteuert hat – die CTAs bleiben als eigene Gruppe abgesetzt. */
  margin-bottom: clamp(1.5rem, 3.5vw, 3rem);
}
.hero-h1 em { font-style: normal; color: var(--color-brand-lt); }
/* Desktop: Headline in einer Zeile, darunter bleibt sie zweizeilig */
@media (min-width: 1024px) {
  .hero-h1 br { display: none; }
}

/* CTAs */
.hero-btns {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
}
/* Zweiter Weg neben dem Hauptbutton: schlichter Textlink mit Pfeil,
   gleiche Schriftgröße und Höhe wie .btn, damit beide auf einer Linie
   stehen. */
.hero-link {
  display: inline-flex;
  align-items: center;
  gap: .3em;
  min-height: var(--touch);
  padding: 0 var(--space-3);
  font-size: var(--fs-sm);
  font-weight: var(--weight-bold);
  color: #fff;
  text-decoration: none;
}
.hero-link::after {
  content: '›';
  font-size: 1.35em;
  line-height: 1;
  transform: translateY(-.05em);
  transition: transform .2s var(--ease-out);
}
@media (hover: hover) {
  .hero-link:hover { text-decoration: underline; text-underline-offset: .25em; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .hero-link:hover::after { transform: translate(3px, -.05em); }
}
/* Der globale Fokusring ist navy und wäre auf dem dunklen Foto unsichtbar.
   Gilt auch für den Glasknopf daneben, der denselben dunklen Grund hat. */
.hero-link:focus-visible,
.hero-btns .btn-glass:focus-visible { outline-color: #fff; }

/* ── Hero-Höhe: Handy & Tablet ─────────────────────────────────
   Anordnung des Hero-Texts ist auf allen Breiten dieselbe: zentriert,
   Buttons direkt unter der Headline (Regeln oben). Auch bis 1023px
   füllt der Hero den Bildschirm, die Stats-Leiste liegt beim Aufruf
   unter der Falz – wie ab 1024px.
──────────────────────────────────────────────────────────── */
@media (max-width: 1023px) {
  /* Volle Bildschirmhöhe, der Textblock sitzt darin mittig. svh statt dvh,
     damit der Hero beim Ein- und Ausfahren der Browserleiste nicht springt. */
  .hero {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
  }
  .hero-inner {
    flex: 1;
  }
}
/* ════════════════════════════════════════════════════════════
   NEWS – Wischreihe auf dem Handy, 2 Spalten ab 700px, 3 ab 960px
   ════════════════════════════════════════════════════════════ */
.news-section {
  background: var(--color-bg);
  padding: var(--space-section) var(--space-inline);
}
/* Kartenraster statt Meldungsliste. Vorher lief die Liste einspaltig
   neben einem 20rem breiten Deko-Banner: die Liste war 1818px hoch, das
   Banner 418px, darunter blieben rund 1400px der rechten Spalte leer –
   77 % der Spaltenhöhe. Der Abschnitt war mit 2241px der längste der
   Seite. Drei Meldungen, drei Spalten: die Reihe ist auf dem Desktop
   voll, ohne dass eine Meldung wegfällt. */
.news-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-gap);
}
@media (min-width: 700px) {
  .news-list { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 960px) {
  .news-list { grid-template-columns: repeat(3, 1fr); }
}

/* Handy (eine Spalte): Die Meldungen stehen nebeneinander in einer
   Wischreihe statt untereinander. Jede Karte ist 85 % breit, damit die
   nächste rechts ins Bild ragt und zeigt, dass es weitergeht. Die Reihe
   läuft bis an den Bildschirmrand (negatives Margin hebt das seitliche
   Padding der Sektion auf, Padding und scroll-padding setzen die erste
   Karte wieder bündig an den Text darüber). Ohne JS voll bedienbar.
   Ab 700px greift weiterhin das Raster oben. */
@media (max-width: 699.98px) {
  .news-list {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scroll-padding-inline: var(--space-inline);
    margin-inline: calc(-1 * var(--space-inline));
    padding-inline: var(--space-inline);
    scrollbar-width: none;
    /* Schatten und Fokusring der Karten ragen nach unten heraus und
       würden sonst abgeschnitten – wie bei der Trainings-Spur. */
    padding-bottom: .75rem;
    margin-bottom: -.75rem;
  }
  .news-list::-webkit-scrollbar { display: none; }
  /* Richtungssperre beim senkrechten Scrollen, siehe js/home.js */
  .news-list.is-achse-y { overflow-x: hidden; }
  .news-list > .news-item {
    flex: 0 0 85%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }
}

/* Die Karte selbst ist .n-card aus css/base.css, dieselbe wie auf
   pages/news.html. .news-item bleibt als Klasse daneben stehen, weil
   js/home.js danach sortiert und die Ausblendregel unten danach zählt.
   Auf der Startseite stehen nur die drei neuesten Meldungen; alles
   Weitere über den Button "Alle News" im Sektionskopf. Gezählt wird die
   DOM-Reihenfolge NACH dem Sortieren in js/home.js, ohne JS die
   Reihenfolge im HTML – beide beginnen mit der neuesten Meldung.
   Die zwei Klassen im Selektor schlagen das display:flex von .n-card. */
.news-item:nth-of-type(n+4) {
  display: none;
}

/* Der Textlink "Mehr erfahren" sitzt am Kartenfuß wie der Knopf bzw.
   "Weiterlesen" auf der News-Seite, damit er bei unterschiedlich langen
   Anreißern auf einer Linie steht. Schriftgröße wie "Weiterlesen"
   (.n-more-sum auf pages/news.html). */
.n-body > .news-link {
  margin-top: auto;
  font-size: var(--fs-sm);
  padding-top: var(--space-4);
  align-self: flex-start;
}

/* ════════════════════════════════════════════════════════════
   TEAMS 2026
   ════════════════════════════════════════════════════════════ */
/* Der Abschnitt läuft als blaues Vollband statt auf dem grauen Grund.
   Grund: Training (weiß), Mannschaften (grau) und News (weiß) standen als
   dritte Wiederholung derselben Form hintereinander – Überschrift und Text
   links, ein Objekt rechts. Das Band bricht die Folge, ohne am Inhalt etwas
   zu ändern. Der Wechsel grau/weiß der übrigen Abschnitte bleibt bestehen;
   das Band zählt wie die Gastronomie als eigene Fläche dazwischen.
   Blau ist Vereinsfarbe, Weiß darauf erreicht 7,97:1. */
.teams-section {
  background: var(--color-navy);
  padding: var(--space-section) var(--space-inline);
  scroll-margin-top: 5rem;
}
.teams-section .h2 { color: #FFFFFF; }
/* Das Akzentwort kann hier nicht Blau bleiben, es stünde auf Blau. Gelb auf
   Blau ist laut CLAUDE.md die erlaubte Richtung. Bewusst das volle
   --color-brand statt des abgeschwächten --color-brand-lt: Die Liga-Zeilen
   der Badges im selben Abschnitt (.team-badge span) tragen denselben Ton,
   mit dem helleren Gelb stand die Überschrift schwächer da als die
   Kleinschrift darunter. --color-brand auf #214F98 erreicht 6,18:1,
   --color-brand-lt käme auf 6,64:1; beides liegt deutlich über 4,5:1.
   Die Hero-Überschrift (.hero-h1 em) behält das hellere Gelb. */
.teams-section .h2 em { color: var(--color-brand); }
.teams-section .teams-intro { color: #FFFFFF; }
/* .teams-info setzt weiter unten im Datei-Abschnitt "Kleinteile" noch einmal
   color: var(--color-text-soft) und gewinnt bei gleicher Spezifitaet. Deshalb
   hier mit dem Abschnitt davor. */
.teams-section .teams-info { color: rgba(255,255,255,.88); }   /* 6,20:1 */

/* ── Eine Spalte statt Text links, Karte rechts ──
   Die Kontaktkarte war das Objekt rechts, das die Form zur Wiederholung
   machte. Sie steht jetzt als Zeile unter den Mannschaften, der Text
   läuft über die volle Breite. */
.teams-inner {
  display: grid;
  gap: var(--space-gap);
}
.teams-section .teams-intro { max-width: 46ch; }
.teams-section .teams-info { max-width: 56ch; }

/* Eine Spalte bis 600px. Mannschaft und Liga stehen nebeneinander; in zwei
   Spalten braucht die Zeile mehr Breite, als eine halbe Spalte auf dem Handy
   hergibt. Gemessen bei 320px Viewport: das zweispaltige Raster wurde 422px
   breit und lief aus dem Bild – ohne Scrollbalken, weil body overflow-x: clip
   trägt, der Inhalt wäre also unbemerkt abgeschnitten worden.
   Vier Spalten erst ab 1100px: Darunter wird die Zelle schmaler als die
   längste Zeile ("Damen 2" + "BEZIRKSOBERLIGA"). */
.teams-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: .75rem;
  margin-top: 1.5rem;
}
@media (min-width: 600px) {
  .teams-grid { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1100px) {
  .teams-grid { grid-template-columns: repeat(4, 1fr); }
}
/* Mannschaft und Liga stehen in einer Zeile: Name links, Liga rechts als
   Label. Auf dem Band trägt die Zelle keine weiße Fläche und keine Kante
   mehr, sondern einen Tonwertschritt im Blau – eine Linie auf Blau wäre
   entweder unsichtbar oder lauter als der Inhalt. */
.team-badge {
  background: rgba(255,255,255,.10);
  border-radius: var(--radius-md);
  padding: 1.1rem 1.3rem;
  font-size: 1rem;
  font-weight: 700;
  color: #FFFFFF;
  line-height: 1.3;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
/* Das <br> im Markup trennt Mannschaft und Liga für den Fall ohne CSS;
   im Flex-Layout ist der Umbruch überflüssig. */
.team-badge br { display: none; }
/* Die Ligabezeichnung war der grüne Zweitakzent für hellen Grund. Auf Blau
   erreicht --color-green-dk nur 1,31:1 und ist damit unlesbar; Gelb ist die
   Akzentfarbe, die CLAUDE.md für Blau vorsieht (6,18:1). */
.team-badge span {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-brand);
  white-space: nowrap;
}

/* ── Kontaktzeile ──
   Aus der weißen Karte wird eine Zeile am Fuß des Bandes: links Ansprache,
   rechts die beiden Wege. Die Trennlinie ist dieselbe Lösung wie bei den
   Gastronomie-Fakten auf dunklem Grund. */
.teams-contact {
  background: transparent;
  border: 0;
  border-top: 1px solid rgba(255,255,255,.22);
  border-radius: 0;
  padding: 2rem 0 0;
  box-shadow: none;
  display: grid;
  gap: 1.25rem;
}
/* Dachzeile, Ueberschrift, Satz und Buttons stehen ohne Wrapper nebeneinander
   im Markup. Ohne ausdrueckliche Platzierung fuellen sie vier Zellen und die
   Zeile zerfaellt. Text deshalb untereinander in Spalte 1, Buttons ueber alle
   Zeilen in Spalte 2. */
@media (min-width: 760px) {
  .teams-contact {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto;
    align-items: start;
    column-gap: 2.5rem;
    row-gap: .35rem;
  }
  .teams-contact > .eyebrow      { grid-area: 1 / 1; }
  .teams-contact-h3              { grid-area: 2 / 1; }
  .teams-contact-body            { grid-area: 3 / 1; }
  .teams-contact-btns            { grid-area: 1 / 2 / -1 / 3; align-self: center; }
}
.teams-section .eyebrow { color: rgba(255,255,255,.85); }
.teams-section .eyebrow::before { background: #FFFFFF; }
.teams-section .teams-contact-h3 { color: #FFFFFF; }
.teams-section .teams-contact-body { color: rgba(255,255,255,.88); margin-bottom: 0; }
/* Nebeneinander statt untereinander: Die Zeile hat die Breite dafür, die
   Karte hatte sie nicht. */
.teams-section .teams-contact-btns { flex-direction: row; flex-wrap: wrap; }
/* btn-outline-dk ist ein blauer Ton auf hellem Grund und auf dem Band nicht
   zu sehen. Gleiche Rolle, heller Ton. */
.teams-section .btn-outline-dk {
  background: rgba(255,255,255,.14);
  color: #FFFFFF;
}
@media (hover: hover) {
  .teams-section .btn-outline-dk:hover { background: rgba(255,255,255,.24); }
}

/* ════════════════════════════════════════════════════════════
   ÜBER UNS
   ════════════════════════════════════════════════════════════ */
.about-section {
  background: var(--color-bg);
  padding: var(--space-section) var(--space-inline);
  position: relative;
  overflow: hidden;
}
.about-inner { max-width: var(--max); margin: 0 auto; position: relative; z-index: 1; }

/* Abschnittsüberschriften gleiten herein (js/home.js, initAboutScroll):
   SplitText legt je Zeile eine Kante (.hdr-line-mask) um die Zeile und
   setzt dort overflow: clip. Das würde bei line-height 1 Ober- und
   Unterlängen mit abschneiden; deshalb hier überschrieben durch einen
   clip-path, der nur unten schneidet, knapp unter der Zeile (Platz für
   Unterlängen), nach oben und zur Seite offen. Ausgleichsabstände wären
   keine Lösung: Deren negative Ränder fallen zwischen den Zeilen zusammen,
   gemessen war die Überschrift damit 21px höher. clip-path ändert am
   Layout nichts.
   Der Strich vor der Dachzeile skaliert über --hdr-dash, ohne Skript
   steht er voll da. home.css bleibt nach einem Seitenwechsel geladen, die
   Regel greift auf Unterseiten aber nie, weil dort niemand --hdr-dash
   setzt. */
.hdr-line-mask {
  overflow: visible !important;
  clip-path: inset(-.5em -.5em -.16em -.5em);
}
.eyebrow::before {
  transform: scaleX(var(--hdr-dash, 1));
  transform-origin: left center;
}

/* Mobile: 1 Spalte, ab Tablet: 2 Spalten */
.about-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
  gap: clamp(2rem, 5vw, 7rem);
  align-items: center;
}

/* ════════════════════════════════════════════════════════════
   TRAINING – Fotokachel plus drei Ziele
   Handy: alles untereinander. Ab 700px zwei Spalten, Foto und
   Kosten-Kachel über die volle Breite. Ab 1024px steht das Foto links
   über zwei Reihen, rechts oben zwei Kacheln, darunter die Kosten quer.
   Vorher drei gleiche Karten (Slider bzw. Wischreihe) plus gelber Knopf
   darunter – sie sahen aus wie die Terminkarten zwei Abschnitte weiter.
   ════════════════════════════════════════════════════════════ */
.training-section {
  background: var(--color-bg-alt);
  padding: var(--space-section) var(--space-inline);
}
.tr-bento {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-gap);
  margin-top: 1rem;
}
@media (min-width: 700px) {
  .tr-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tr-feature,
  .tr-card--wide { grid-column: 1 / -1; }
}
@media (min-width: 1024px) {
  .tr-bento { grid-template-columns: minmax(0, 1.15fr) repeat(2, minmax(0, 1fr)); }
  .tr-feature { grid-column: 1; grid-row: 1 / span 2; }
  .tr-card--wide { grid-column: 2 / span 2; }
}

/* ── Fotokachel: die laufende Saison ──
   Text in Weiß auf einem Verlauf aus Vereinsblau, der das Foto unten
   abdunkelt. Gelb nur als Fläche (Etikett, Knopf), nie als Schrift. */
.tr-feature {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 26rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-navy);
  color: #fff;
}
.tr-feature-img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}
.tr-feature::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
    rgba(27,64,122,0)   25%,
    rgba(27,64,122,.78) 58%,
    rgba(27,64,122,.96) 100%);
}
.tr-feature-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
.tr-feature-badge {
  background: var(--color-brand);
  color: var(--color-navy-dk);
  font-size: var(--fs-2xs);
  font-weight: 800;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  padding: .35rem .75rem;
  border-radius: var(--radius-full);
  margin-bottom: .9rem;
}
.tr-feature-title {
  /* 700 statt 800 – Begründung siehe h1/h2 in css/base.css */
  font-size: clamp(1.7rem, 1.3rem + 1.5vw, 2.2rem);
  font-weight: 700;
  color: #fff;
  letter-spacing: var(--tracking-normal);
  line-height: 1.1;
  margin-bottom: .5rem;
}
.tr-feature-text {
  font-size: var(--fs-sm);   /* war .9rem = 14,4px */
  line-height: 1.6;
  color: rgba(255,255,255,.9);
  max-width: 34ch;
  margin-bottom: 1.25rem;
}

/* ── Drei Ziele ──
   Flache Kacheln ohne Rahmen und Schatten in Ruhe; die Fläche kommt aus
   --color-bg-card (im weißen Abschnitt der Grundton). Beim Überfahren
   heben sie sich wie alle anderen Karten um 3px mit shadow-md. */
.tr-card {
  background: var(--color-bg-card);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  position: relative;
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
@media (hover: hover) {
  .tr-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
  }
}
.tr-icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: #fff;
  color: var(--color-navy);
  flex-shrink: 0;
  margin-bottom: 1rem;
}
.tr-icon svg { width: 1.3rem; height: 1.3rem; }
.tr-title {
  font-size: 1.2rem;
  /* 700 statt 800 – Begründung siehe h1/h2 in css/base.css */
  font-weight: 700;
  color: var(--color-text);
  /* Feste Größe – auf dieser Größe ist -.02em
     zu eng für die Serif (siehe Tracking-Abschnitt in base.css). */
  letter-spacing: -.011em;
  margin-bottom: .5rem;
}
.tr-body {
  /* War .83rem = 13,3px. --fs-sm ist die Groesse fuer Text in einer
     Kachel und steht so schon bei .n-text in css/base.css. */
  font-size: var(--fs-sm);
  color: var(--color-text-soft);
  line-height: 1.7;
  flex: 1;
}
.tr-link {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin-top: 1.1rem;
  font-size: .75rem;
  font-weight: 700;
  color: var(--color-navy);
  min-height: 44px;
  position: relative;
  z-index: 1;
}
.tr-link::after {
  content: '→';
  transition: transform var(--dur-fast) var(--ease-out);
}
/* Klickfläche des Links. Bezug ist .tr-link selbst (position:relative, siehe oben),
   nicht die Karte: Die Kachel ist also nicht flächig klickbar, nur der Linktext. */
.tr-link::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
}
@media (hover: hover) {
  .tr-link:hover::after { transform: translateX(.25rem); }
  .tr-card:hover .tr-link::after { transform: translateX(.25rem); }
}

/* Handy: Symbol links, Text rechts daneben – drei kompakte Zeilen statt
   drei hoher Karten. */
@media (max-width: 699.98px) {
  /* Auf dem schmalen Hochformat läge der Text mitten auf den Gesichtern.
     Deshalb hier Foto oben, Text darunter auf Blau. */
  .tr-feature {
    min-height: 0;
    justify-content: flex-start;
  }
  .tr-feature-img {
    position: static;
    height: auto;
    aspect-ratio: 16 / 10;
  }
  .tr-feature::before { display: none; }
  .tr-card {
    display: grid;
    grid-template-columns: 2.75rem minmax(0, 1fr);
    column-gap: 1rem;
  }
  .tr-icon { grid-row: 1 / span 3; margin-bottom: 0; }
  .tr-title,
  .tr-body,
  .tr-link { grid-column: 2; }
  .tr-title { font-size: 1.05rem; margin-bottom: .3rem; }
  .tr-link { margin-top: .4rem; }
}
/* Quer liegende Kosten-Kachel: Symbol, Text, Link in einer Zeile.
   Die Link-Spalte hat eine feste Breite statt 'auto'. Mit 'auto' richtet sie
   sich nach dem gerenderten Linkinhalt, also auch nach dem Pfeil aus
   .tr-link::after. Fällt der Pfeil beim Überfahren für einen Frame weg (Safari
   zeichnet das Pseudoelement beim Start seiner transform-Transition kurz nicht),
   werden gut 10px frei, die Textspalte wird breiter und der Fließtext kippt von
   zwei Zeilen auf eine: Die Kachel wird 20px flacher und sofort wieder höher, es
   flackert. Dem Text fehlten dafür nur 8,8px. Mit fester Spalte hängt die
   Breite nicht mehr am Pfeil, und der Text hat rund 28px Abstand zur
   Umbruchkante. Der Link steht per justify-self rechts in der Spalte, damit er
   optisch an derselben Stelle sitzt wie vorher. */
@media (min-width: 700px) {
  .tr-card--wide {
    display: grid;
    grid-template-columns: 2.75rem minmax(0, 1fr) 7rem;
    grid-template-areas: "icon title link" "icon body link";
    column-gap: 1.25rem;
    align-items: center;
  }
  .tr-card--wide .tr-icon  { grid-area: icon; margin-bottom: 0; }
  .tr-card--wide .tr-title { grid-area: title; align-self: end; }
  .tr-card--wide .tr-body  { grid-area: body; align-self: start; }
  .tr-card--wide .tr-link  { grid-area: link; margin-top: 0; justify-self: end; }
}

/* ── Punktleiste der Wischreihen (nur Mobil) ──────────────
   Unter 700px stehen die News als horizontal wischbare Reihe (siehe
   .news-list weiter oben); js/home.js (wischPunkte()) erzeugt darunter
   die Punkte. Ohne JS bleibt die Reihe voll bedienbar, es fehlt nur die
   Punktleiste. Training und Termine hatten bis zur Umstellung auf
   Fotokachel und Agenda dieselbe Reihe, sie stehen jetzt untereinander.
──────────────────────────────────────────────────────────── */
.card-slider-dots { display: none; }

@media (max-width: 699.98px) {
  /* ── Punktleiste ──
     Der sichtbare Punkt ist 8px klein, die Schaltfläche darum herum
     bleibt mit 44px Höhe griffig – deshalb sitzt die Farbe auf ::after
     und nicht auf dem Button selbst. */
  .training-section .card-slider-dots,
  .news-section .card-slider-dots,
  .events-section .card-slider-dots {
    display: flex;
    justify-content: center;
    gap: 0;
    margin-top: .5rem;
  }
  .training-section .card-slider-dot,
  .news-section .card-slider-dot,
  .events-section .card-slider-dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 2.75rem;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    /* Der aktive Punkt wird zur Pille, sein Knopf dafür breiter */
    transition: width var(--dur-base) var(--ease-out);
  }
  .training-section .card-slider-dot::after,
  .news-section .card-slider-dot::after,
  .events-section .card-slider-dot::after {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    background: rgba(33,79,152,.25);
    transition: background-color var(--dur-base) var(--ease-out),
                width            var(--dur-base) var(--ease-out);
  }
  .training-section .card-slider-dot[aria-current="true"]::after,
  .news-section .card-slider-dot[aria-current="true"]::after,
  .events-section .card-slider-dot[aria-current="true"]::after {
    background: var(--color-navy);
    width: 24px;
  }
  .training-section .card-slider-dot[aria-current="true"],
  .news-section .card-slider-dot[aria-current="true"],
  .events-section .card-slider-dot[aria-current="true"] {
    width: 2.5rem;
  }
}

/* Ohne Bewegung wechselt die Pille ohne Übergang von Punkt zu Punkt. */
@media (prefers-reduced-motion: reduce) {
  .training-section .card-slider-dot,
  .news-section .card-slider-dot,
  .events-section .card-slider-dot,
  .training-section .card-slider-dot::after,
  .news-section .card-slider-dot::after,
  .events-section .card-slider-dot::after {
    transition: none;
    transform: none;
  }
  .training-section .card-slider-dot[aria-current="true"]::after,
  .news-section .card-slider-dot[aria-current="true"]::after,
  .events-section .card-slider-dot[aria-current="true"]::after {
    transform: none;
  }
}

/* ════════════════════════════════════════════════════════════
   EVENTS – Agenda: der nächste Termin groß, daneben die Zeilen
   Beim Termin ist das Datum die Hauptinfo (CLAUDE.md), deshalb steht der
   nächste anstehende Termin mit großem Tagesdatum auf Blau. Daneben
   (ab 960px) bzw. darunter eine einzige Fläche mit bis zu drei Zeilen:
   erst was danach noch kommt, dann unter "Zuletzt" was schon war.
   Aufgebaut wird das in js/home.js (initAgenda()): Dort wird die Karte
   des nächsten Termins aus der Liste gelöst und zu .ev-card--next.
   Ohne JS steht nur die Liste da, mit den ersten drei Terminen aus dem
   Quelltext. Vorher drei gleiche Karten als Slider bzw. Wischreihe.
   ════════════════════════════════════════════════════════════ */
.events-section {
  background: var(--color-bg);
  padding: var(--space-section) var(--space-inline);
}
.ev-agenda {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-gap);
  margin-top: 1rem;
}
@media (min-width: 960px) {
  .ev-agenda.has-next.has-list {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    align-items: stretch;
  }
}

/* ── Die Liste ──
   Eine Fläche statt einzelner Karten, die Termine darin als Zeilen.
   Die Zählregel greift ohne JS auf die Reihenfolge im Quelltext; mit JS
   ist der nächste Termin schon herausgelöst und die übrigen sind
   sortiert, es bleiben also dieselben drei Plätze. */
.ev-list {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: .4rem clamp(1.25rem, 2.5vw, 1.75rem);
}
.ev-list > .ev-card:nth-of-type(n+4) {
  display: none;
}
.ev-list-label {
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-mute);
  margin: 1rem 0 .1rem;
}
.ev-card {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
}
.ev-list > .ev-card {
  padding: 1rem 0;
  border-top: 1px solid var(--color-border);
}
/* Feste Breite, damit die Texte aller Zeilen auf einer Linie beginnen,
   egal wie breit die Ziffern sind. */
.ev-list .ev-date {
  width: 3.5rem;
  min-width: 0;
  padding-inline: 0;
}
.ev-list > .ev-card:first-child,
.ev-list-label + .ev-card {
  border-top: 0;
}
.ev-date {
  background: rgba(33,79,152,.08);
  border: 1px solid rgba(33,79,152,.15);
  border-radius: 12px;
  padding: .6rem .85rem;
  text-align: center;
  flex-shrink: 0;
  min-width: 54px;
}
.ev-day {
  font-size: 1.6rem;
  font-weight: 800;
  color: var(--color-navy);
  letter-spacing: var(--tracking-snug);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.ev-month {
  /* War .58rem und rendert damit auf 9,3px. Jetzt --fs-xs wie .eyebrow
     und .gastro-subtitle: dieselbe Rolle, dieselbe Groesse. */
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--color-text-mute);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
}
/* Vorbei: Datum grau statt blau, damit Rückblick und Ausblick auch
   ohne die Zwischenzeile auseinanderzuhalten sind. */
.ev-card--vorbei .ev-date {
  background: transparent;
  border-color: var(--color-border-card);
}
.ev-card--vorbei .ev-day { color: var(--color-text-mute); }
.ev-cat {
  font-size: var(--fs-xs);   /* war .6rem = 9,6px */
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-navy);
  margin-bottom: .4rem;
}
.ev-title {
  font-size: .95rem;
  font-weight: 700;
  color: var(--color-text);
  /* Feste 15,2px – kleinste Überschrift der Startseite, entsprechend
     wenig Verengung (siehe Tracking-Abschnitt in base.css). */
  letter-spacing: -.008em;
  margin-bottom: .4rem;
  line-height: 1.25;
}
.ev-desc {
  font-size: .8rem;
  color: var(--color-text-mute);
  line-height: 1.6;
}

/* Weiterführender Link – nur bei Terminen, zu denen es tatsächlich eine
   Zielseite gibt. Gleiche Machart wie .news-link (css/base.css), nur auf
   die kleinere Kartentypografie heruntergezogen. */
.ev-link {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-top: .5rem;
  font-size: .8rem;
  font-weight: var(--weight-bold);
  color: var(--color-navy);
  text-decoration: underline;
  text-underline-offset: .45em;
  text-decoration-thickness: 1px;
  min-height: var(--touch);
}
.ev-link::after {
  content: '→';
  transition: transform var(--dur-fast) var(--ease-out);
}
@media (hover: hover) {
  .ev-link:hover::after { transform: translateX(.25rem); }
}

/* ── Der nächste Termin ──
   Vereinsblau, Schrift weiß. Gelb nur als Fläche im Etikett "Als
   Nächstes", nie als Schrift. Tag, Monat, Wochentag und "in x Tagen"
   schreibt js/home.js aus dem datetime in .ev-when. */
.ev-card--next {
  position: relative;
  overflow: hidden;
  flex-direction: column;
  gap: 0;
  background: var(--color-navy);
  color: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
/* ── Leer-Zustand: Foto hinter dem Vereinsblau ─────────────
   Steht kein Termin an, baut js/home.js dieselbe blaue Kachel mit
   der Zusatzklasse .ev-card--leer. Hier liegt ein Foto darunter,
   darüber eine Blaufläche als zweite Hintergrundebene. Bewusst
   über background-image statt ::before: .ev-card--next vergibt an
   seine Kinder z-index (.ev-link), eine zusätzliche Ebene müsste
   sich da einsortieren. Als Hintergrundebene entfällt das.
   rgba(33,79,152,.88) ist --color-navy; als Hintergrund braucht es
   den Zahlenwert, eine Deckkraft lässt sich an einer Variablen
   ohne color-mix() nicht nachträglich setzen.

   background-blend-mode mischt die Fotoebene im Modus luminosity
   mit der Hintergrundfarbe darunter: Das Foto gibt nur noch die
   Helligkeit, den Farbton gibt das Vereinsblau. Ohne das käme das
   Gelbgrün der Bälle durch und das Blau kippte ins Petrol. Die
   Blaufläche darüber bleibt normal. Fehlt die Unterstützung,
   rendert es als Foto unter Blau, also lesbar, nur bunter.
   Hellster Punkt hinter der Schrift gemessen: 5,19:1 gegen Weiß. */
.ev-card--leer {
  background-color: var(--color-navy);
  background-image:
    linear-gradient(rgba(33,79,152,.80), rgba(33,79,152,.80)),
    url(../images/startseite/startseite-termine-tennisbaelle.jpg);
  background-size: cover;
  background-position: center;
  background-blend-mode: normal, luminosity;
}

.ev-chip {
  background: var(--color-brand);
  color: var(--color-navy-dk);
  font-size: var(--fs-2xs);
  font-weight: 800;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  padding: .35rem .75rem;
  border-radius: var(--radius-full);
  margin-bottom: 1.4rem;
}
.ev-card--next .ev-date {
  display: flex;
  align-items: flex-end;
  gap: .9rem;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  text-align: left;
  margin-bottom: 1.25rem;
}
.ev-card--next .ev-day {
  font-size: clamp(4rem, 3rem + 4vw, 6.5rem);
  letter-spacing: -.05em;
  line-height: .8;
  color: #fff;
}
.ev-card--next .ev-month { display: none; }
.ev-when {
  font-size: .82rem;
  line-height: 1.35;
  color: rgba(255,255,255,.82);
  padding-bottom: .15rem;
}
.ev-when b {
  display: block;
  font-size: 1rem;
  color: #fff;
}
.ev-countdown {
  display: inline-block;
  margin-top: .3rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  background: rgba(255,255,255,.14);
  padding: .15rem .55rem;
  border-radius: 6px;
  color: #fff;
}
.ev-card--next .ev-cat { color: rgba(255,255,255,.72); }
.ev-card--next .ev-title {
  font-size: clamp(1.3rem, 1.1rem + .8vw, 1.75rem);
  color: #fff;
  letter-spacing: -.015em;
  line-height: 1.2;
  margin-bottom: .5rem;
}
.ev-card--next .ev-desc {
  font-size: .88rem;
  color: rgba(255,255,255,.85);
}
.ev-card--next .ev-link {
  position: relative;
  z-index: 1;
  margin-top: 1rem;
  color: #fff;
}

/* ════════════════════════════════════════════════════════════
   GALERIE – Mobile: 2×2, Desktop: originales Layout
   ════════════════════════════════════════════════════════════ */
/* Farbwechsel der Startseite: Über uns (grau), Training (weiß), Teams
   (Vereinsblau, siehe .teams-section), News (weiß), Termine (grau),
   Gastronomie (Foto), Impressionen (grau), Partner (weiß), FAQ (grau).
   Teams und Gastronomie sind die beiden eigenen Flächen im Wechsel. css/base.css zählt Termine,
   Impressionen und FAQ zu den weißen Abschnitten; hier werden die drei
   samt Kartenfarbe auf Grau zurückgestellt und die News auf Weiß gesetzt,
   damit der Wechsel aufgeht. */
.events-section,
.gallery-section,
.faq-section {
  --color-bg:      var(--color-bg-base);
  --color-bg-card: #FFFFFF;
  --bg-card:       #FFFFFF;
}
.news-section {
  --color-bg:      var(--color-bg-alt);
  --color-bg-card: var(--color-bg-base);
  --bg-card:       var(--color-bg-base);
}
.gallery-section {
  background: var(--color-bg);
  padding: var(--space-section) var(--space-inline);
}

/* Mobile (320px+): 2 Spalten, 2 Reihen – Höhe skalaliert mit Viewport */
.gallery-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* clamp: 130px bei 320px, ~20vw bei mittleren Screens, max 220px */
  grid-template-rows: clamp(130px, 22vw, 220px) clamp(130px, 22vw, 220px);
  gap: clamp(.5rem, 1.5vw, 1rem);
  margin-top: 1rem;
}
.gallery-item:first-child { grid-row: span 1; grid-column: span 1; }

/* js/gallery.js liefert fünf Bilder – so viele Zellen hat aber erst das
   Desktop-Raster ab 992px (dort belegt das erste Bild beide Reihen der
   ersten Spalte, es bleiben vier Zellen für die übrigen vier Bilder).
   Hier oben gibt es nur zwei mal zwei Zellen; das fünfte Bild würde eine
   dritte Reihe aufmachen. Deshalb unterhalb von 992px ausblenden. */
.gallery-item:nth-child(5) { display: none; }

/* Tablet (768px): etwas höhere Reihen */
@media (min-width: 768px) {
  .gallery-grid {
    grid-template-rows: clamp(180px, 20vw, 260px) clamp(180px, 20vw, 260px);
  }
}

/* Desktop (992px+): 3-Spalten-Layout mit großem Hauptbild links */
@media (min-width: 992px) {
  .gallery-grid {
    grid-template-columns: 2fr 1fr 1fr;
    grid-template-rows: clamp(190px, 15vw, 240px) clamp(190px, 15vw, 240px);
  }
  .gallery-item:first-child { grid-row: span 2; grid-column: span 1; }
  .gallery-item:nth-child(5) { display: block; }
}

.gallery-item {
  border-radius: var(--radius-md);
  overflow: hidden;
  position: relative;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  cursor: pointer;
  touch-action: manipulation;
}
.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-base) var(--ease-out),
              filter    var(--dur-base) var(--ease-out);
  filter: brightness(.97) saturate(1.05);
}
@media (hover: hover) {
  .gallery-item:hover img {
    transform: scale(1.04);
    filter: brightness(1.02) saturate(1.12);
  }
  .gallery-item:hover .gallery-overlay { opacity: 1; }
}
/* Rückmeldung beim Antippen: Auf Touch-Geräten gibt es kein Hover, ohne
   das hier passierte bis zum Öffnen der Lightbox gar nichts. Abdunkeln statt
   Verkleinern – transform gehört dem Hover-Zoom und der Einblendung. */
.gallery-item:active img {
  filter: brightness(.85) saturate(1.05);
  transition-duration: .1s;
}
.gallery-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,.3) 0%, transparent 50%);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
}
/* ════════════════════════════════════════════════════════════
   GASTRONOMIE
   ════════════════════════════════════════════════════════════ */
.gastro-section {
  position: relative;
  min-height: clamp(560px, 86svh, 780px);
  display: flex;
  align-items: flex-end;
  background: #0a162e;
  overflow: hidden;
}
/* Das Foto füllt die ganze Fläche, der Verlauf darüber hält den weißen
   Text lesbar: auf dem Handy von unten, ab 900px zusätzlich von links,
   wo der Text steht (gleiche Farbe wie das Overlay im Hero). */
.gastro-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 60%;
}
/* Parallaxe: Das Foto läuft beim Scrollen langsamer mit als der Text und
   wirkt dadurch weiter hinten. Anders als eine Einblendung sieht es in
   jeder Lage fertig aus, deshalb darf es am Scroll hängen (Ausnahme in
   docs/ANIMATIONEN.md). Dafür ist es oben und unten um den Weg
   (--gastro-drift) größer als die Fläche, das overflow: hidden des
   Abschnitts schneidet den Rest ab.
   Native Scroll-driven Animation statt GSAP, kein Skript: Die Zeitleiste
   misst in jedem Frame neu. Sie hängt am Abschnitt, nicht am Foto, weil
   das Foto sonst seine eigene Verschiebung mitmessen würde. Linear, weil
   sich eine Parallaxe mit Easing vom Scroll löst. Über die eigene
   translate-Eigenschaft, damit transform frei bleibt.
   Ohne Unterstützung oder mit reduzierter Bewegung steht das Foto still
   wie bisher. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .gastro-section { view-timeline: --gastro-view block; }
    .gastro-photo {
      --gastro-drift: 60px;
      inset: calc(var(--gastro-drift) * -1) 0;
      height: calc(100% + 2 * var(--gastro-drift));
      animation: gastro-drift linear both;
      animation-timeline: --gastro-view;
      animation-range: cover;
    }
    @media (max-width: 767.98px) {
      .gastro-photo { --gastro-drift: 24px; }
    }
  }
}
@keyframes gastro-drift {
  from { translate: 0 calc(var(--gastro-drift) * -1); }
  to   { translate: 0 var(--gastro-drift); }
}
.gastro-section::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(0deg, rgba(10,22,46,.94) 0%, rgba(10,22,46,.72) 55%, rgba(10,22,46,.15) 88%);
}
@media (min-width: 900px) {
  .gastro-section::after {
    background:
      linear-gradient(90deg, rgba(10,22,46,.88) 0%, rgba(10,22,46,.6) 40%, rgba(10,22,46,.05) 70%),
      linear-gradient(0deg, rgba(10,22,46,.5) 0%, transparent 50%);
  }
}
/* max-width mit dem seitlichen Padding darin: Sonst wäre die Spalte
   innerhalb des Paddings um 2x --space-inline schmaler als die .inner
   der übrigen Abschnitte und der Text stünde ab rund 1370px Breite
   32px weiter rechts als jede andere Abschnittskante. */
.gastro-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: calc(var(--max) + 2 * var(--space-inline));
  margin: 0 auto;
  padding: var(--space-section) var(--space-inline);
}
.gastro-text { max-width: 44rem; }
.gastro-section .eyebrow { color: rgba(255,255,255,.85); }
.gastro-section .eyebrow::before { background: #fff; }

/* Der Restaurantname ist die Abschnittsüberschrift der Gastronomie und
   läuft deshalb in der Überschriftenschrift wie .h2 in allen anderen
   Abschnitten. Der Block ist ein <div> und erbt die Serif nicht von selbst.
   700 statt 800, weil Libre Baskerville nur mit 400 und 700 geladen ist
   (Begründung siehe @font-face in css/base.css). Größe und Tracking
   entsprechen --fs-display / --tracking-display der übrigen
   Abschnittsüberschriften. Gelb nur, weil der Grund hier dunkelblau ist,
   wie bei der Hero-Überschrift. */
.gastro-name  {
  font-family: var(--font-heading);
  font-size: var(--fs-display);
  font-weight: var(--weight-bold);
  color: #fff;
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-none);
  margin-bottom: .6rem;
}
.gastro-name em     { font-style: normal; color: var(--color-brand-lt); }
.gastro-subtitle    { font-size: .78rem; font-weight: 700; letter-spacing: var(--tracking-wider); text-transform: uppercase; color: rgba(255,255,255,.75); margin-bottom: 1.25rem; }
.gastro-desc        { font-size: var(--fs-md); color: rgba(255,255,255,.9); line-height: 1.85; margin-bottom: 1.25rem; max-width: 440px; }

/* Die drei Eckdaten: fette Zeile plus kurze Erklärung, getrennt durch
   feine Linien wie in der Zahlenleiste unter dem Hero. Bewusst ohne
   Fläche und Rahmen, damit nichts nach einem Knopf aussieht. Auf dem
   Handy untereinander, ab 700px drei Spalten. */
.gastro-facts {
  margin: 0 0 2.25rem;
  display: grid;
  border-top: 1px solid rgba(255,255,255,.28);
}
.gastro-facts > div {
  padding: 1rem 0;
  border-bottom: 1px solid rgba(255,255,255,.18);
}
.gastro-facts dt { color: #fff; font-weight: 700; font-size: .95rem; margin-bottom: .2rem; }
.gastro-facts dd { margin: 0; color: rgba(255,255,255,.78); font-size: .85rem; line-height: 1.5; }
@media (min-width: 700px) {
  .gastro-facts {
    grid-template-columns: repeat(3, 1fr);
    border-bottom: 1px solid rgba(255,255,255,.28);
  }
  .gastro-facts > div { border-bottom: 0; padding: 1.1rem 1.25rem; }
  .gastro-facts > div:first-child { padding-left: 0; }
  .gastro-facts > div + div { border-left: 1px solid rgba(255,255,255,.18); }
}
.btn-glass {
  color: #fff;
  background: rgba(255,255,255,.14);
  /* Kein Rahmen, wie die getönten Buttons in css/base.css.
     Bewusst ohne backdrop-filter: Der Knopf soll durchsichtig bleiben.
     Im Hero kam die Unschärfe außerdem erst nach der Einblendung dazu
     (solange .hero-btns opacity < 1 hat, greift sie nicht), der Knopf
     sprang dann von durchsichtig auf milchig. */
}
@media (hover: hover) {
  .btn-glass:hover { background: rgba(255,255,255,.24); }
}
@media (prefers-reduced-transparency: reduce) {
  .btn-glass { background: rgba(10,22,46,.85); }
}

/* ════════════════════════════════════════════════════════════
   SPONSOREN
   ════════════════════════════════════════════════════════════ */
.sponsors-section {
  background: var(--color-bg-alt);
  padding: var(--space-section-sm) var(--space-inline);
}
.sponsors-inner { max-width: var(--max); margin: 0 auto; }
.sponsors-lbl {
  text-align: center;
  font-size: var(--fs-xs);   /* war .63rem = 10,1px */
  font-weight: 700;
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-text-soft);
  margin-bottom: 2.5rem;
}
.sponsors-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: .85rem;
}

/* Logoband. Die drei gleichen Gruppen (siehe index.html) liegen in einer
   Spur. Ab 1024px ist nur die erste zu sehen und die Reihe steht wie
   bisher zentriert. Seit dem siebten Partner bricht sie dort auf zwei
   Zeilen um (gemessen von 1024px bis 1920px, bei 1440px fünf oben und
   zwei unten). Ein Umlauf würde nur dieselben Logos mehrfach zeigen,
   deshalb bleibt die Reihe trotzdem stehen. Unter 1024px läuft die
   Spur endlos von links nach rechts, weil die Reihe sonst auf vier Zeilen
   umbricht (gemessen bei 390px: 251px hoch statt 60px). */
.sponsors-track {
  display: flex;
  align-items: center;
  justify-content: center;
}
.sponsors-group {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  /* Zeilen 28px, Logos 44px auseinander. Wirkt nur ab 1024px: Das Band
     darunter und die Fassung ohne Bewegung setzen eigene Werte. Die
     Schriftlogos (Ungericht, Systecs, FrauenFinanzBeratung) haben keinen
     Innenabstand und klebten mit .85rem fast aneinander. */
  gap: 1.75rem 2.75rem;
}
.sponsors-group[aria-hidden="true"] { display: none; }
.sponsor-item {
  padding: .75rem 1.75rem;
  min-height: 44px;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 50px;
  font-size: .78rem;
  font-weight: 600;
  color: var(--color-text-mute);
  letter-spacing: .03em;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
@media (hover: hover) {
  .sponsor-item:hover {
    border-color: rgba(33,79,152,.25);
    color: var(--color-text-soft);
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
  }
}
/* Partnerlogo ohne Chip – Höhe an den Chips ausgerichtet, Breite nach
   Seitenverhältnis der Datei. */
.sponsor-logo {
  display: block;
  height: 60px;
  width: auto;
  max-width: 100%;
}
.sponsors-cta {
  display: flex;
  justify-content: center;
  margin-top: 2rem;
}

/* ── Logoband unter 1024px: endloser Umlauf nach rechts ── */
@media (max-width: 1023.98px) {
  .sponsors-row {
    /* Bis an den Bildschirmrand: hebt das seitliche Padding des
       Abschnitts auf. Unter 1320px ist .sponsors-inner genau so breit wie
       der Bildschirm minus diesem Padding, ein 100vw-Trick mit seinem
       Scrollbalken-Problem ist deshalb nicht nötig. */
    margin-inline: calc(var(--space-inline) * -1);
    justify-content: flex-start;
    flex-wrap: nowrap;
    /* Seitlich an der Kante schneiden, sonst wächst das Dokument nach
       rechts und die Seite ließe sich quer schieben. Oben und unten 12px
       Luft, damit Schatten und das Anheben beim Überfahren nicht
       abgeschnitten werden. */
    clip-path: inset(-12px 0);
    /* Weiches Auslaufen an beiden Rändern, gleiche Technik wie die
       Wischreihe in css/page.css. */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
    /* Waagerecht schiebt der Finger das Band (initLogobandZiehen() in
       js/home.js), senkrecht scrollt weiter die Seite. */
    touch-action: pan-y;
  }
  .sponsors-track {
    flex: 0 0 auto;
    animation: sponsoren-lauf 20s linear infinite;
  }
  .sponsors-group {
    flex: 0 0 auto;
    flex-wrap: nowrap;
    gap: 1.75rem;
    /* Der Abstand zur nächsten Gruppe gehört in die Gruppe, nicht als gap
       in die Spur: nur so ist eine Gruppe genau ein Drittel der Spur und
       der Sprung am Ende des Umlaufs fällt exakt auf das nächste Logo.
       Mit gap wäre er um ein Drittel des Abstands daneben. */
    padding-right: 1.75rem;
  }
  .sponsors-group[aria-hidden="true"] { display: flex; }
  /* Jedes Logo als eigene Ebene. Beim Neustart springt die Spur um eine
     Gruppenbreite an eine Stelle, die 20s nicht zu sehen war. Safari hat
     die Kacheln der großen Spur dort schon verworfen und zeigt die Logos
     für einen Moment weiß. Kleine eigene Ebenen behält es, Bilder setzt
     es dabei direkt ein, ohne neu zu zeichnen. Auf dem iPhone über
     vorschau.tcle.info geprüft. Gehört mit decoding="sync" an den Logos
     in index.html zusammen. */
  .sponsors-group > * { will-change: transform; }
  /* Anhalten beim Überfahren, sobald der Abschnitt aus dem Bild ist
     (initLogobandPause() in js/home.js) und solange der Finger das Band
     schiebt (initLogobandZiehen()). */
  .sponsors-row.sponsors-row--pausiert .sponsors-track,
  .sponsors-row.sponsors-row--gezogen .sponsors-track {
    animation-play-state: paused;
  }
}
@media (max-width: 1023.98px) and (hover: hover) {
  .sponsors-row:hover .sponsors-track { animation-play-state: paused; }
}

/* Von links nach rechts: die Spur startet eine Gruppenbreite weiter links
   und läuft auf 0 zu. Bei drei gleich breiten Gruppen ist das genau ein
   Drittel, am Ende steht wieder dasselbe Bild wie am Anfang. */
@keyframes sponsoren-lauf {
  from { transform: translate3d(calc(-100% / 3), 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* Ohne Bewegung kein Band: die Reihe steht wie am Desktop und bricht auf
   dem Handy wieder um. Nichts bleibt dabei unsichtbar oder halb
   angeschnitten. */
@media (max-width: 1023.98px) and (prefers-reduced-motion: reduce) {
  .sponsors-row {
    margin-inline: 0;
    justify-content: center;
    flex-wrap: wrap;
    clip-path: none;
    -webkit-mask-image: none;
            mask-image: none;
    touch-action: auto;
  }
  /* flex: 0 1 auto hebt das 0 0 auto des Bandes auf. Ohne das bleiben
     Spur und Gruppe auf ihrer max-content-Breite von 779px stehen, laufen
     auf dem Handy aus dem Bild und sind durch das overflow-x: clip des
     Body nicht einmal mehr erreichbar. */
  .sponsors-track {
    flex: 0 1 auto;
    animation: none;
  }
  .sponsors-group {
    flex: 0 1 auto;
    flex-wrap: wrap;
    gap: .85rem;
    padding-right: 0;
  }
  .sponsors-group[aria-hidden="true"] { display: none; }
  .sponsors-group > * { will-change: auto; }
}

/* ════════════════════════════════════════════════════════════
   FAQ
   ════════════════════════════════════════════════════════════ */
.faq-section {
  background: var(--color-bg);
  padding: var(--space-section) var(--space-inline);
}
.faq-inner {
  max-width: 720px;
  margin: 0 auto;
}
.faq-item {
  border-bottom: 1px solid var(--color-border);
}
.faq-q {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--ff);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem 0;
  min-height: 44px;
  font-size: clamp(.88rem, 1.5vw, .97rem);
  font-weight: 700;
  color: var(--color-text);
  letter-spacing: var(--tracking-normal);
  transition: color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) {
  .faq-q:hover { color: var(--color-navy); }
}
/* Rückmeldung beim Drücken, auch ohne Maus. Das Symbol wird nur getönt,
   nicht skaliert – transform trägt dort die Drehung des geöffneten Zustands. */
.faq-q:active { color: var(--color-navy); }
.faq-q:active .faq-icon { background: rgba(33,79,152,.08); }
.faq-icon {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  color: var(--color-navy);
  flex-shrink: 0;
  transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.faq-item.open .faq-icon {
  transform: rotate(45deg);
  background: rgba(33,79,152,.08);
  border-color: rgba(33,79,152,.25);
}
/* Nur der Zustand, keine Bewegung: Die Antwort klappt sofort auf und
   zu. Warum hier nichts animiert wird, steht mit der kompletten
   Messreihe am FAQ-Block in js/home.js. */
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
}
.faq-a-inner {
  min-height: 0;
  overflow: hidden;
}
/* Kein Deckkraft-Uebergang auf dem Antworttext: Solange eine Flaeche mit
   opacity < 1 gezeichnet wird, schaltet der Browser das Subpixel-
   Antialiasing der Schrift ab und am Ende wieder an. Zusammen mit dem
   Layout, das grid-template-rows in jedem Frame ausloest, wird der Text
   dabei jeden Frame leicht anders gerastert - sichtbar als Zittern, am
   staerksten bei den beiden Antworten mit blauen Links. Das Aufklappen
   enthuellt den Text ohnehin, ein Fade bringt daneben nichts. */
.faq-a-content {
  font-size: .875rem;
  color: var(--color-text-mute);
  line-height: 1.8;
  padding-bottom: 1.5rem;
}
.faq-item.open .faq-a {
  grid-template-rows: 1fr;
}

/* CTA-Banner: steht in css/base.css, gemeinsam mit den Unterseiten. */


/* ════════════════════════════════════════════════════════════
   HERO BUTTONS – Mobile: vertikal gestapelt
   ════════════════════════════════════════════════════════════ */
@media (max-width: 480px) {
  .hero-btns { flex-direction: column; align-items: center; }
  .hero-btns .btn { width: 100%; max-width: 320px; justify-content: center; }
}

/* ════════════════════════════════════════════════════════════
   GROSSE MONITORE (1920px+)
   Mehr Luft in den Sektionen, größeres max-width für Inner
   ════════════════════════════════════════════════════════════ */
@media (min-width: 1920px) {
  /* Alle Home-Sektionen: etwas mehr vertikales Padding */
  .news-section,
  .teams-section,
  .about-section,
  .training-section,
  .events-section,
  .gallery-section,
  .faq-section {
    padding-top: clamp(7rem, 8vw, 10rem);
    padding-bottom: clamp(7rem, 8vw, 10rem);
  }

  /* Hero-Headline noch prominenter auf großen Screens */
  .hero-h1 { font-size: 6rem; }

  /* Galerie-Reihen etwas höher */
  .gallery-grid {
    grid-template-rows: 280px 280px;
  }
}

/* ════════════════════════════════════════════════════════════
   SEKTIONSKOPF DER STARTSEITE
   .sec-hdr steht in css/base.css und wird von sieben Unterseiten
   mitbenutzt; css/home.css laden ausserdem 4winners, impressionen,
   spielplan und termine. Deshalb hier über body[data-root=""] auf die
   Startseite eingegrenzt – die Unterseiten behalten ihren Kopf.

   Zwei Dinge: .sec-hdr richtet auf flex-end aus, die Überschrift bringt
   aber margin-bottom mit, weshalb die Schaltfläche unter der Grundlinie
   hing statt neben ihr. Und die Slider-Pfeile stehen in einer eigenen
   Zeile zwischen Überschrift und Karten. Ausrichtung auf flex-start,
   Überschriftenabstand auf 0, und der Abstand unter dem Kopf wird dort
   kleiner, wo eine Pfeilzeile folgt – die trägt ihren eigenen.
   ════════════════════════════════════════════════════════════ */
body[data-root=""] .sec-hdr {
  align-items: flex-start;
}
/* Nur wenn nichts mehr folgt. Steht ein Einleitungssatz unter der
   Überschrift (Training), behält sie ihren normalen Abstand – sonst
   klebt der Satz an der Zeile darüber. Zentrierte Köpfe sind
   ausgenommen, sie haben ihren eigenen Wert weiter unten; ohne das
   :not() gewinnt diese Regel dort per Spezifität. */
body[data-root=""] .sec-hdr:not(.sec-hdr--center) .h2:last-child {
  margin-bottom: 0;
}
/* Der Kopf zentrierter Abschnitte (FAQ, Instagram) behält seine
   Ausrichtung – dort steht keine Schaltfläche rechts daneben. */
body[data-root=""] .sec-hdr--center {
  align-items: center;
}
body[data-root=""] .sec-hdr--center .h2 {
  margin-bottom: var(--space-2);
}

/* ════════════════════════════════════════════════════════════
   KLEINE SMARTPHONES (320–360px): Extra-Optimierungen
   ════════════════════════════════════════════════════════════ */
@media (max-width: 360px) {
  /* Karten-Padding reduzieren */
  .tr-card,
  .ev-card { padding: 1rem; }

  /* FAQ-Fragen etwas kleiner */
  .faq-q { font-size: .82rem; }

}

/* ════════════════════════════════════════════════════════════
   EXTRAHIERTE INLINE-STYLES
   ════════════════════════════════════════════════════════════ */

/* sec-hdr zentriert (FAQ) */
.sec-hdr--center {
  justify-content: center;
  text-align: center;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

/* Aktionsbuttons von News, Terminen und Impressionen unter den Karten
   bzw. Fotos, mittig statt oben rechts im Sektionskopf. */
.sec-hdr-actions {
  display: flex;
  justify-content: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: var(--space-8);
}

/* Teams */
.teams-intro { margin-bottom: 1.5rem; }
.teams-contact-h3 { margin-bottom: 1rem; }
.teams-contact-body { font-size: var(--fs-md); color: var(--color-text-soft); margin-bottom: 1.5rem; }
.teams-contact-btns { display: flex; flex-direction: column; gap: .75rem; }
.teams-contact-note { margin-top: 1.25rem; font-size: .85rem; color: var(--color-text-mute); }

/* About */
.about-btns { margin-top: 2.75rem; display: flex; gap: .85rem; flex-wrap: wrap; }
.about-img-wrap { margin-top: 2rem; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 32px rgba(0,0,0,.10); }
/* Responsiv: 240px auf Mobile, ~40vw auf Tablet, max 420px auf Desktop */
.about-section-img { width: 100%; height: clamp(220px, 40vw, 420px); display: block; object-fit: cover; }

/* Gastronomie */
.gastro-btns { display: flex; gap: .85rem; flex-wrap: wrap; }


/* FAQ Links */
.faq-link { color: var(--color-navy); }

/* Teams */
/* .teams-info und .teams-contact-body hatten keine eigene Groesse und erbten
   damit body (--fs-base, 17,4px). Sie standen so groesser da als der
   Einleitungssatz .teams-intro darueber, der .intro mit --fs-md traegt. */
.teams-info { font-size: var(--fs-md); margin-top: 1.75rem; color: var(--color-text-soft); line-height: 1.8; }

/* ════════════════════════════════════════════════════════════
   HERO REVEAL ANIMATIONEN
   ════════════════════════════════════════════════════════════ */

/* Ausgangszustand: unsichtbar + leicht nach unten versetzt.

   Die 0s-Animation mit 0.4s Verzögerung ist das Sicherheitsnetz für den
   Fall, dass js/hero.js nicht läuft (JS deaktiviert, Script-Ladefehler):
   Sichtbar wird der Hero-Text sonst nur durch .hr-visible, das allein
   dieses Script setzt – ohne Script bliebe die komplette Hero-Überschrift
   dauerhaft unsichtbar. Nach 400ms fällt er stattdessen von selbst auf
   opacity 1 zurück. Gleiches Muster wie das body:not(.layout-ready)-Gate
   in css/base.css, inklusive derselben 400ms. Läuft das Script, kommt
   .hr-visible lange vorher und überschreibt die Animation komplett
   (höhere Spezifität), das Sicherheitsnetz wird dann nie sichtbar. */
[data-hero-reveal] {
  opacity: 0;
  transform: translateY(28px);
  animation: _hero-unhide 0s .4s forwards;
}
@keyframes _hero-unhide {
  to { opacity: 1; transform: none; }
}
/* js/hero.js setzt .hero-js auf <html>, sobald es die Sichtbarkeit selbst
   uebernimmt, und schaltet das Sicherheitsnetz damit ab. Das :not() haelt die
   Regel bewusst von der Einblendung fern: Sie greift nur im noch nicht
   eingeblendeten Zustand und kann .hr-visible darunter nie ueberschreiben,
   unabhaengig von der Reihenfolge der Regeln. */
.hero-js [data-hero-reveal]:not(.hr-visible) {
  animation: none;
}

/* Sichtbar-Zustand: Animation startet */
[data-hero-reveal].hr-visible {
  animation: heroRevealIn .75s var(--ease-out) both;
}

/* Stagger-Delays per data-delay Attribut */
[data-hero-reveal][data-delay="1"].hr-visible { animation-delay: .10s; }
[data-hero-reveal][data-delay="2"].hr-visible { animation-delay: .20s; }
[data-hero-reveal][data-delay="3"].hr-visible { animation-delay: .30s; }
[data-hero-reveal][data-delay="4"].hr-visible { animation-delay: .40s; }
[data-hero-reveal][data-delay="5"].hr-visible { animation-delay: .50s; }

@keyframes heroRevealIn {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ════════════════════════════════════════════════════════════
   BUTTON ENHANCEMENTS – Hover/Press-Effekte
   ════════════════════════════════════════════════════════════ */

/* Hover: keine eigenen Regeln mehr, es gilt css/base.css (nur Farbe,
   kein Anheben) */

/* "Press"-Effekt beim Klick – alle Hero-Buttons */
.hero-btns .btn:active {
  transform: translateY(1px) scale(.97);
  transition-duration: .08s;
}

/* ════════════════════════════════════════════════════════════
   VEREINSZAHLEN (in „Mehr als nur Tennis“, unter dem Einleitungstext)
   Früher eine blaue Leiste direkt unter dem Hero. Jetzt ohne eigene
   Fläche auf dem Grau des Abschnitts, deshalb Zahlen in Blau statt Gelb
   (Gelb ist auf hellem Grund unlesbar). Die Unterseiten haben mit
   .page-stats in css/page.css weiter ein eigenes blaues Zahlenband.
   ════════════════════════════════════════════════════════════ */
.about-stats {
  display: grid;
  /* Gleich breite Spalten statt auto: Beim Hochzählen (js/hero.js)
     wächst "0+" auf "500+", mit auto würden die Nachbarn mitwandern. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 1rem;
  /* So breit wie .intro darüber (css/base.css) */
  max-width: 520px;
  margin-top: 2.25rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--color-border-h);
}

/* Vier nebeneinander nur, wenn der Block breit genug ist. Das hängt an
   der Spalte, nicht am Fenster: Zwischen etwa 860 und 1250px steht der
   Abschnitt zweispaltig und die Textspalte ist schmaler als auf dem
   Tablet, "Mannschaften" brach dort bei vier Spalten in zwei Zeilen um.
   Ab 31rem passt die längste Beschriftung.
   Bewusst ohne Container Query: Mit container-type an .about-text sprang
   die Startseite in Safari auf dem iPhone beim Scrollen durch diesen
   Abschnitt, während die Zahlen hochzählen (Oktober 2026, auf dem Gerät
   bestätigt). Stattdessen schaltet die Mindestbreite der Spalten selbst:
   Ist der Block mindestens 31rem breit, wird (31rem - 100%) * 999
   negativ und clamp() nimmt ein Viertel, sonst die Hälfte. 0,8rem bzw.
   0,6rem statt genau der halben Lücke, damit Rundung keine dritte Spalte
   erzeugt. */
.about-stats {
  grid-template-columns: repeat(auto-fill, minmax(clamp(calc(25% - .8rem), (31rem - 100%) * 999, calc(50% - .6rem)), 1fr));
}

.about-stats + .about-btns { margin-top: 2.25rem; }

.hs-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .35rem;
}

.hs-number {
  font-size: clamp(1.9rem, 3.2vw, 2.5rem);
  /* Bewusste Ausnahme: Serif auch außerhalb von h1–h3. 700 statt 800, weil
     Libre Baskerville nur mit 400 und 700 geladen ist. */
  font-family: var(--font-heading);
  font-weight: 700;
  color: var(--color-navy);
  /* 0 statt -.04em: der negative Wert war auf Urbanist abgestimmt, in der
     Serif stoßen die Ziffern damit zusammen (mobil 1/9 in "1964"). */
  letter-spacing: 0;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.hs-label {
  font-size: clamp(.65rem, 1.2vw, .75rem);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-mute);
}

/* content-visibility: auto ist hier bewusst ENTFERNT (vorher auf Training,
   News, Termine, Mannschaft, Impressionen, Gastronomie, Partner und FAQ,
   in css/page.css zusaetzlich auf .page-sec).

   WARUM RAUS: In Safari flackerte die verkleinerte Darstellung beim Scrollen
   60-mal je Sekunde. Die Platzhalter aus contain-intrinsic-size lagen daneben
   (.training-section stand auf 2300px bei 887px echter Hoehe am Desktop,
   1346px auf dem Handy), beim Rendern sprang die Seitenhoehe zurueck, der
   Abschnitt fiel damit wieder aus der Reichweite und wurde erneut
   uebersprungen - eine Schaukel, die sich selbst fuettert. Belegt an einer
   Bildschirmaufnahme: strikte Alternation Frame fuer Frame.

   ALLES GEMESSENE AN EINEM ORT, damit niemand blind einen neuen Anlauf
   nimmt. Chromium, Median aus 5 Laeufen:

     Desktop 1512x860, CPU 4x     mit cv    ohne cv
       LCP                         780ms     1048ms
       Layout beim Laden           252ms      458ms
       Layout beim Scrollen        364ms      180ms
       Layout-Durchlaeufe Scroll     126        103

     Handy 390x844, DPR 3, CPU 4x  mit cv    ohne cv
       LCP                         208ms      208ms   (kein Unterschied)
       Layout, 6 Wischgesten       220ms      468ms
       ausgelassene Frames             0          0

   Die beiden Zeilen widersprechen sich nicht, sie messen Verschiedenes: Auf
   dem Handy bringt die Regel keine Ladezeit, halbiert aber die Layout-Arbeit
   beim Scrollen. Wer hier wieder ran will, misst Layout-Zeit beim Scrollen,
   nicht LCP.

   WENN SIE ZURUECKKOMMT, dann nicht mit festen Platzhaltern fuer alle: Die
   echten Hoehen schwanken je nach Breite um 100 bis 400px. Eine Fassung nur
   fuer Touch-Geraete, mit an zehn Breiten gemessenen Werten und drei
   Media-Queries ueber (pointer: coarse), steht fertig in der Historie:
   git show 72b07e5 (Aufbau) und git show 0f95f84 (Scroll-Messung).
   (pointer: coarse) statt reinem max-width ist dort kein Zufall: Safari-Zoom
   schiebt die CSS-Breite in beide Richtungen, Vergroessern auf 200 % macht
   aus einem 1512px-Fenster 756px und faellt sonst in den Mobil-Bereich. */

/* Während eines Anker-Sprungs (siehe home.js) kurz deaktiviert: die
   contain-intrinsic-size-Schätzung oben weicht je nach Gerät/Schriftrendering
   von der echten Höhe ab, wodurch der Sprung sonst leicht daneben landen
   kann. Mit "visible" nutzt der Browser die echte Höhe für die Berechnung. */
body.cv-unlock .news-section,
body.cv-unlock .teams-section,
body.cv-unlock .about-section,
body.cv-unlock .training-section,
body.cv-unlock .events-section,
body.cv-unlock .gallery-section,
body.cv-unlock .gastro-section,
body.cv-unlock .sponsors-section,
body.cv-unlock .faq-section {
  content-visibility: visible;
}

/* ── Reduced Motion: alle Animationen deaktivieren ── */
@media (prefers-reduced-motion: reduce) {
  [data-hero-reveal],
  [data-hero-reveal].hr-visible {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .hero-btns .btn:active {
    transform: none;
  }
}

