Files
tsv08kulmbach-website/public/assets/css/components.css

8123 lines
218 KiB
CSS
Raw Normal View History

/* ============================================================
COMPONENTS eine Sektion pro Komponente, Banner-Kommentare
============================================================ */
/* === hero === */
.hero {
position: relative;
display: grid;
align-items: end;
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* svh statt vh: stabil gegenüber ein-/ausfahrender Browser-UI auf Phones. */
min-height: min(92vh, 900px);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
min-height: min(92svh, 900px);
padding-block: calc(var(--header-h) + 80px) var(--space-section);
overflow: hidden;
}
/* Kompakte Variante: schlanker Unterseiten-Header statt vollflächig. */
.hero--compact {
min-height: min(60vh, 560px);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
min-height: min(60svh, 560px);
padding-block: calc(var(--header-h) + 64px) var(--space-5xl);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Mobile: Höhe am Inhalt statt am Viewport orientieren weniger Leer-Scroll.
Startseiten-Hero lässt bewusst einen Streifen Folge-Inhalt anblitzen (Scroll-Affordance),
Unterseiten-Heros kollabieren auf Überschrift + Teaser. */
@media (max-width: 768px) {
.hero {
min-height: min(82vh, 700px);
min-height: min(82svh, 700px);
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
padding-block: calc(var(--header-h) + var(--space-5xl)) var(--space-4xl);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
}
.hero--compact {
min-height: 0;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
padding-block: calc(var(--header-h) + var(--space-5xl)) var(--space-3xl);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
}
}
.hero__media {
position: absolute;
inset: 0;
z-index: -1;
2026-06-20 22:18:34 +02:00
/* Unten ausblenden statt mit grauem BG zudecken: der echte, dunkle
texturierte Seiten-Hintergrund scheint durch transparent & matcht
den Grund exakt (kein graues, opakes Band mehr). */
-webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 92%);
mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 92%);
}
.hero__img {
width: 100%;
height: 100%;
object-fit: cover;
}
.hero__video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
@media (prefers-reduced-motion: reduce) {
.hero__video {
display: none;
}
}
2026-06-20 22:18:34 +02:00
/* Reine Schwarz-Abdunklung (kein grauer Fill) der Auslauf zum Grund kommt
aus der Mask auf .hero__media, hier wird nur schwärzer getönt. */
.hero__media::after {
content: '';
position: absolute;
inset: 0;
2026-06-20 22:18:34 +02:00
background: linear-gradient(180deg, rgb(0 0 0 / 0.45) 0%, rgb(0 0 0 / 0.15) 45%, rgb(0 0 0 / 0.5) 100%);
}
.hero__content {
width: 100%;
}
.hero__title {
text-shadow: 0 2px 24px rgb(0 0 0 / 0.5);
}
/* Keyword-Subline innerhalb der h1 (SEO) — visuell kleinere zweite Zeile */
.hero__tagline {
display: block;
margin-top: var(--space-xs);
font-size: var(--fs-600);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
}
.hero__text {
margin-top: var(--space-s);
max-width: 60ch;
text-shadow: 0 1px 12px rgb(0 0 0 / 0.6);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
text-wrap: pretty;
}
/* Display-Hero: schmaleres Maß fürs Zentrieren ausgewogene Zeilen statt
vier Zeilen mit unruhigem Flatterrand. */
.hero--display .hero__text {
max-width: 52ch;
}
.hero__actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-xs);
margin-top: var(--space-xl);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Zweispaltige Variante (siehe hero.php hero--duo"): links Titel/Text/CTAs
linksbündig, rechts die Termin-Karte als Live-Aufhänger. Ersetzt für
diese Variante das zentrierte Layout komplett kein hero--center. */
.hero__content--duo {
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
align-items: center;
gap: clamp(var(--space-l), var(--space-m) + 2vw, var(--space-4xl));
text-align: left;
}
@media (max-width: 992px) {
.hero__content--duo {
grid-template-columns: 1fr;
}
}
.hero--duo .hero__title {
/* --fs-1000 sprengt die schmalere Spalte — eine Stufe kleiner. */
font-size: var(--fs-900);
}
/* Glas-Karte für die nächsten Termine dieselbe Optik wie andere Leaf-Karten
(--clr-glass-bg + Blur, siehe @supports weiter unten), nur mit dem
stärkeren Rand, weil sie auf bewegtem Video statt festem Seitengrund sitzt.
Enthält bis zu drei Folien (Spiele + Vereins-Events, s. hero-upcoming.php),
die assets/js/carousel.js überblendet. */
.hero__upcoming {
--hero-upcoming-interval: 5s;
padding: clamp(var(--space-m), var(--space-s) + 1vw, var(--space-l));
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border-strong);
border-radius: var(--radius-card);
}
.hero__upcoming-track {
margin: 0;
padding: 0;
list-style: none;
}
/* Ohne JS liegt nur die erste Folie da (die weiteren tragen hidden). Mit JS
werden alle Folien gestapelt und übergeblendet dadurch nimmt die Karte die
Höhe der höchsten Folie an und der Hero springt beim Wechsel nicht.
Gleiches Muster wie beim Banner-Slider (.ad-banner.is-enhanced). */
.hero__upcoming.is-enhanced .hero__upcoming-track {
display: grid;
}
.hero__upcoming.is-enhanced .hero__upcoming-slide {
grid-area: 1 / 1;
/* Grid-Items haben min-width:auto ohne explizites Minimum weitet eine
lange nowrap-Vereinszeile (SG-Namen) die Folie über die Kartenkante,
statt in der Ellipsis-Kette (.match-feature__side/__club) zu enden. */
min-width: 0;
opacity: 0;
transform: translateY(8px);
pointer-events: none;
transition: opacity 0.5s ease, transform 0.5s ease, visibility 0s linear 0.5s;
visibility: hidden;
}
.hero__upcoming.is-enhanced .hero__upcoming-slide.is-active {
opacity: 1;
transform: none;
pointer-events: auto;
visibility: visible;
transition: opacity 0.5s ease, transform 0.5s ease, visibility 0s;
}
.hero__upcoming-link {
display: block;
color: inherit;
text-decoration: none;
transition: transform var(--transition);
}
.hero__upcoming-link:hover {
transform: translateY(-2px);
}
.hero__upcoming-label {
margin-bottom: var(--space-xs);
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-wide);
color: rgb(255 255 255 / 0.65);
}
/* Eingedampft gegenüber dem next-matches-Band auf /matchcenter die Karte ist
hier ein Live-Aufhänger neben dem Titel, kein eigener Abschnitt. Die
Meta-Zeile (Mannschaft · Liga · Heim/Auswärts) fällt komplett weg, der
hero__upcoming-label übernimmt ihre Rolle (was ist das hier"). */
.hero__upcoming .match-feature__meta {
display: none;
}
.hero__upcoming .match-feature {
gap: var(--space-xs);
}
.hero__upcoming .match-feature .crest {
--crest-size: clamp(1.75rem, 1.5rem + 0.6vw, 2.1rem);
}
/* Die größere Team-Schrift (--fs-690) braucht mehr Luft zwischen Heim- und
Gast-Zeile als das Default-Fixture-Gap (--space-2xs) sonst wirken beide
Zeilen zusammengequetscht. */
.hero__upcoming .match-feature__fixture {
gap: var(--space-s);
}
.hero__upcoming .match-feature__club {
font-size: var(--fs-690);
}
.hero__upcoming .match-feature__when {
font-size: var(--fs-400);
}
/* Event-Folien werden genauso eingedampft wie die Spiel-Folien, damit beide
Varianten in der Karte gleich groß wirken (und dieselbe Höhe brauchen). */
.hero__upcoming .event-feature {
gap: var(--space-xs);
}
.hero__upcoming .event-feature__title {
font-size: var(--fs-690);
}
.hero__upcoming .event-feature__when {
font-size: var(--fs-400);
}
/* Steuerleiste an der unteren Kartenkante: Indikatoren links, Pause rechts.
Bewusst ohne Pfeile im Hero zählt jeder Quadratzentimeter, und die
Indikatoren springen ohnehin direkt zu jedem Termin. */
.hero__upcoming-controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-s);
margin-top: var(--space-s);
padding-top: var(--space-2xs);
border-top: 1px solid var(--clr-glass-border);
}
.hero__upcoming-controls[hidden] {
display: none;
}
.hero__upcoming-indicators {
display: flex;
flex-wrap: wrap;
gap: var(--space-2xs);
}
/* Wie die Banner-Indikatoren: 44px Trefferfläche (WCAG 2.5.5), sichtbar ist
nur die 6px-Leiste in der Mitte. */
.hero__upcoming-dot {
position: relative;
width: 40px;
height: var(--tap-min);
padding: 0;
background: none;
border: 0;
cursor: pointer;
}
.hero__upcoming-dot::before,
.hero__upcoming-progress {
position: absolute;
inset: calc(50% - 3px) 0 auto;
height: 6px;
border-radius: 999px;
}
.hero__upcoming-dot::before {
content: "";
background: var(--clr-glass-border-strong);
transition: background var(--transition);
}
.hero__upcoming-dot:hover::before {
background: rgb(255 255 255 / 0.45);
}
.hero__upcoming-progress {
background: var(--clr-accent);
transform: scaleX(0);
transform-origin: left;
}
/* Der durchlaufende Fortschritt treibt den Folienwechsel (animationend in
carousel.js) dieselbe Keyframe wie beim Banner-Slider, nur schnellerer Takt. */
.hero__upcoming-dot.is-active .hero__upcoming-progress {
animation: ad-progress var(--hero-upcoming-interval) linear forwards;
}
.hero__upcoming.is-paused .hero__upcoming-dot.is-active .hero__upcoming-progress {
animation-play-state: paused;
}
@media (prefers-reduced-motion: reduce) {
.hero__upcoming-dot.is-active .hero__upcoming-progress {
animation: none;
transform: scaleX(1);
}
}
/* Glas-Optik als Delta zu .btn--icon (Größe/Rundung/Trefferfläche kommen von
dort). .btn muss im Selektor mitstehen: utilities.css lädt nach
components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. */
.btn.hero__upcoming-toggle {
flex: 0 0 auto;
font-size: var(--icon-s);
color: var(--clr-text);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
transition: background var(--transition);
}
.btn.hero__upcoming-toggle:hover {
background: rgb(255 255 255 / 0.2);
}
.hero__upcoming-toggle[hidden] {
display: none;
}
/* Pause-Icon im Abspiel-Zustand, Play-Icon wenn pausiert. */
.hero__upcoming-toggle .hero__upcoming-toggle-icon--play {
display: none;
}
.hero__upcoming-toggle[aria-pressed="true"] .hero__upcoming-toggle-icon--pause {
display: none;
}
.hero__upcoming-toggle[aria-pressed="true"] .hero__upcoming-toggle-icon--play {
display: inline-block;
}
/* Variante: Text mittig zentriert (z. B. Startseite) */
.hero--center {
align-items: center;
text-align: center;
}
.hero--center .hero__text {
margin-inline: auto;
}
/* letter-spacing schiebt zentrierten Text optisch nach rechts (Spacing nach letztem Char).
text-indent gleich dem letter-spacing-Wert kompensiert das. */
.hero--center .hero__tagline {
text-indent: 0.14em;
}
.hero--center .hero__actions {
justify-content: center;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Schmale Viewports: lange Teaser lesen sich zentriert schlecht (beidseitiger
Flatterrand, 67 Zeilen). Unterseiten-Heros laufen mobil deshalb linksbündig
mit ruhiger Kante und eine Schriftstufe kleiner; das Bild dimmt stärker, weil
der Text dort einen größeren Teil der Fläche überdeckt. Der Display-Hero der
Startseite (kurzer Titel + Tagline, kein Langtext) bleibt zentriert und
behält seine eigenen, fein abgestimmten Verläufe (höhere Spezifität). */
@media (max-width: 600px) {
.hero--center:not(.hero--display) {
text-align: left;
}
.hero--center:not(.hero--display) .hero__text {
margin-inline: 0;
font-size: var(--fs-500);
}
.hero--center:not(.hero--display) .hero__tagline {
text-indent: 0;
}
.hero--center:not(.hero--display) .hero__actions {
justify-content: flex-start;
}
.hero__media::after {
background: linear-gradient(180deg, rgb(0 0 0 / 0.55) 0%, rgb(0 0 0 / 0.3) 45%, rgb(0 0 0 / 0.6) 100%);
}
}
/* Variante: Editorial-Display (Startseite) — linksbündig unten, große Typo */
.hero--display .hero__media::after {
/* zusätzlicher Verlauf von links für Textlesbarkeit über dem Video */
background:
linear-gradient(90deg, rgb(10 10 10 / 0.62) 0%, rgb(10 10 10 / 0.25) 45%, transparent 70%),
2026-06-20 22:18:34 +02:00
linear-gradient(180deg, rgb(0 0 0 / 0.42) 0%, rgb(0 0 0 / 0.15) 45%, rgb(0 0 0 / 0.5) 100%);
}
/* Center+Display: kein Seitenverlauf, nur zentrales Abdunkeln für Lesbarkeit */
.hero--center.hero--display .hero__media::after {
background:
radial-gradient(ellipse 80% 60% at 50% 40%, rgb(10 10 10 / 0.5) 0%, transparent 100%),
2026-06-20 22:18:34 +02:00
linear-gradient(180deg, rgb(0 0 0 / 0.4) 0%, rgb(0 0 0 / 0.14) 45%, rgb(0 0 0 / 0.5) 100%);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Kicker: einziges gesperrtes Versalien-Element im Hero bewusst ohne
Schmuck-Linien, damit die Typo-Hierarchie ruhig bleibt (Eyebrow Titel
Subline Text). */
.hero__kicker {
margin-bottom: var(--space-m);
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wider);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Sperrung optisch kompensieren (Spacing nach letztem Zeichen). */
text-indent: 0.18em;
color: rgb(255 255 255 / 0.85);
}
.hero--display .hero__title {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-1000);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Einzugs-Tempo statt Video-Energie: Kicker Titel Text CTAs blenden
gestaffelt ein. prefers-reduced-motion kappt das global (reset.css). */
.hero--display:not(.hero--duo) .hero__content > * {
animation: hero-content-in 0.6s both ease-out;
}
.hero--display:not(.hero--duo) .hero__content > *:nth-child(1) { animation-delay: 0s; }
.hero--display:not(.hero--duo) .hero__content > *:nth-child(2) { animation-delay: 0.1s; }
.hero--display:not(.hero--duo) .hero__content > *:nth-child(3) { animation-delay: 0.2s; }
.hero--display:not(.hero--duo) .hero__content > *:nth-child(4) { animation-delay: 0.3s; }
/* hero--duo: links (Kicker/Titel/CTAs) staffelt sich selbst, die Termin-Karte
kommt als eigener Block danach. */
.hero--duo .hero__primary > * {
animation: hero-content-in 0.6s both ease-out;
}
.hero--duo .hero__primary > *:nth-child(1) { animation-delay: 0s; }
.hero--duo .hero__primary > *:nth-child(2) { animation-delay: 0.1s; }
.hero--duo .hero__primary > *:nth-child(3) { animation-delay: 0.2s; }
.hero--duo .hero__upcoming {
animation: hero-content-in 0.6s both ease-out;
animation-delay: 0.3s;
}
@keyframes hero-content-in {
from {
opacity: 0;
transform: translateY(14px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Subline ruhig in Abel, Groß-/Kleinschreibung konkurriert nicht mehr mit
Kicker (gesperrte Versalien) und Coolvetica-Titel. */
.hero--display .hero__tagline {
margin-top: var(--space-xs);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
font-family: var(--ff-body);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-550);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
font-weight: 400;
letter-spacing: 0;
text-indent: 0;
text-transform: none;
line-height: 1.35;
color: rgb(255 255 255 / 0.92);
}
.hero__scroll-cue {
position: absolute;
left: 50%;
bottom: 1.25rem;
translate: -50% 0;
display: grid;
place-items: center;
width: 44px;
height: 44px;
color: var(--clr-text-muted);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-l);
transition: color var(--transition);
animation: scroll-cue-bounce 2.4s ease-in-out infinite;
}
.hero__scroll-cue:hover {
color: var(--clr-text);
}
@keyframes scroll-cue-bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(8px); }
}
/* === instagram === */
/* Sektions-Kopf zentriert (einheitlich mit partners/persons/…) */
.instagram > .container > h2,
.instagram > .container > .text-muted {
text-align: center;
}
.instagram > .container > .text-muted {
max-width: 60ch;
margin-inline: auto;
}
.instagram__grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--space-s);
margin-top: var(--space-2xl);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Mobil: Ein-Reihen-Swiper statt 2er-Grid volle Bildgröße, natürliche
Instagram-Geste. Fluchtet mit dem Text-Container; die angeschnittene
Folgekarte ist die Wisch-Affordance, Scrollbar bleibt darum versteckt. */
@media (max-width: 600px) {
.instagram__grid {
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
grid-template-columns: none;
grid-auto-flow: column;
grid-auto-columns: min(72vw, 320px);
gap: var(--space-xs);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
}
.instagram__grid::-webkit-scrollbar {
display: none;
}
.instagram__link {
scroll-snap-align: start;
}
}
.instagram__link {
position: relative;
display: block;
border-radius: var(--radius-card);
overflow: hidden;
box-shadow: var(--shadow-card);
}
.instagram__link img {
width: 100%;
height: auto;
/* Instagram-Portrait 1080x1350 */
aspect-ratio: 4 / 5;
object-fit: cover;
transition: transform var(--transition);
}
.instagram__link:hover img,
.instagram__link:focus-visible img {
transform: scale(1.05);
}
.instagram__badge {
position: absolute;
top: 0.75rem;
right: 0.75rem;
display: grid;
place-items: center;
width: 2rem;
height: 2rem;
background: rgb(0 0 0 / 0.6);
border-radius: 50%;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-300);
color: var(--clr-text);
}
.instagram__fallback {
margin-top: var(--space-l);
padding: var(--space-3xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
text-align: center;
}
.instagram__fallback p {
margin-inline: auto;
}
.instagram__fallback .btn {
margin-top: var(--space-s);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.instagram__more {
margin-top: var(--space-l);
text-align: center;
}
/* === split (Bild/Text-Sektion) === */
.split__inner {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
align-items: center;
gap: var(--space-4xl);
}
/* Sanft aufgehelltes, durchgehendes Band über die volle Breite generisch für
jede Sektion (Split via tinted: true im JSON, person-grid u.a. per Klasse).
Direkt aufeinanderfolgende tinted-Sektionen verschmelzen nahtlos. */
.section--tinted {
background: linear-gradient(180deg, rgb(255 255 255 / 0.06), rgb(255 255 255 / 0.035));
border-block: 1px solid rgb(255 255 255 / 0.1);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Abgesetztes, dunkleres Band über die volle Breite das Gegenstück zu
--tinted, wenn eine Sektion sich nach unten statt nach oben abheben soll. */
.section--sunken {
background: var(--clr-bg-deep);
border-block: 1px solid rgb(255 255 255 / 0.08);
}
.section--tinted + .section--tinted {
border-top: 0;
}
.section--tinted:has(+ .section--tinted) {
border-bottom: 0;
}
/* Bild/Text-Sektionen im Band: mehr Luft nach oben und unten */
.split.section--tinted {
padding-block: clamp(var(--space-6xl), var(--space-5xl) + 3vw, var(--space-7xl));
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Textabschnitt ohne Bild (section.php ohne image/gallery): einspaltig, Text auf
Lesebreite statt über die halbe Seite gezogen. */
.split--plain .split__inner {
grid-template-columns: minmax(0, 1fr);
}
.split--plain .split__text {
max-width: 60ch;
}
/* Die extra Luft von .split.section--tinted rechnet mit einem Bild daneben.
Ohne Bild wirkt sie leer, deshalb zurück auf das normale Sektions-Maß. */
.split--plain.section--tinted {
padding-block: var(--space-section);
}
.split--flip .split__text {
order: 2;
}
.split--flip .split__media {
order: 1;
}
.split__text p {
margin-top: var(--space-s);
}
.split__cta {
margin-top: var(--space-l);
}
.split__img {
width: 100%;
border-radius: var(--radius-card);
box-shadow: var(--shadow-card);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Polaroid-Variante (polaroid: true im Section-JSON): <figure class="polaroid">
um das Bild dicker heller Fotorahmen, unten klassisch breiter, leicht gekippt
(flip-Sektionen gegenläufig, damit zwei Polaroids nicht parallel hängen),
Klebestreifen über den oberen Ecken (::before/::after deshalb der Wrapper,
auf einem <img> greifen Pseudo-Elemente nicht). Hover richtet das Foto sanft
auf; der globale reduced-motion-Kill-Switch in reset.css fängt die Transition. */
.polaroid {
--polaroid-tilt: -2deg;
position: relative;
margin: 0;
padding: var(--space-s) var(--space-s) var(--space-3xl);
background: var(--clr-photo-frame);
border-radius: var(--radius-photo);
box-shadow: var(--shadow-card);
transform: rotate(var(--polaroid-tilt));
transition: transform var(--transition);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.split--flip .polaroid {
--polaroid-tilt: 2deg;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid:hover {
transform: rotate(0deg) scale(1.02);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid::before,
.polaroid::after {
content: "";
position: absolute;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
top: calc(-1 * var(--space-2xs));
width: var(--space-6xl);
height: var(--space-xl);
background: var(--clr-tape);
box-shadow: var(--shadow);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid::before {
left: calc(-1 * var(--space-xs));
transform: rotate(-45deg);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid::after {
right: calc(-1 * var(--space-xs));
transform: rotate(45deg);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Rundung/Schatten trägt im Polaroid der Rahmen, nicht das Foto */
.polaroid .split__img {
display: block;
border-radius: 0;
box-shadow: none;
}
/* Bildunterschrift auf dem weißen Unterrand (optionales caption-Feld am
Bild) bewusst nüchtern in Abel, wie die Timeline-Captions auf /historie
(Handschrift-Variante war Felix zu verspielt, 30.07.2026). Die Unterschrift
füllt das Kinn" des Polaroids, deshalb schrumpft der Rahmen-Unterrand,
wenn sie da ist. */
.polaroid__caption {
margin-top: var(--space-xs);
font-size: var(--fs-400);
text-align: center;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-sepia-text);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid:has(.polaroid__caption) {
padding-bottom: var(--space-s);
}
/* Schmale Viewports: Klebestreifen proportional zum kleineren Rahmen verkleinern,
sonst dominieren sie das Foto (am Desktop ~14 % der Rahmenbreite, mobil sonst ~24 %) */
@media (max-width: 600px) {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.polaroid::before,
.polaroid::after {
width: var(--space-5xl);
height: var(--space-l);
}
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Galerie-Variante der Bild/Text-Sektion (gallery: [] im JSON): erstes Bild
volle Breite, weitere halbbreit darunter kleine Collage. Polaroids kippen
darin abwechselnd und dezenter als das Einzel-Polaroid, Rahmen und
Klebestreifen schrumpfen mit den kleineren Fotos mit. */
.split__gallery {
display: grid;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
grid-template-columns: 1fr 1fr;
gap: var(--space-l);
align-items: start;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.split__gallery > :first-child {
grid-column: 1 / -1;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.split__gallery .polaroid {
--polaroid-tilt: -1.5deg;
padding: var(--space-xs) var(--space-xs) var(--space-l);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.split__gallery .polaroid:nth-child(even) {
--polaroid-tilt: 1.5deg;
}
.split__gallery .polaroid::before,
.split__gallery .polaroid::after {
width: var(--space-5xl);
height: var(--space-l);
}
@media (max-width: 992px) {
.split__inner {
grid-template-columns: 1fr;
gap: var(--space-2xl);
}
.split--flip .split__text {
order: 0;
}
.split--flip .split__media {
order: 0;
}
}
/* === timeline (Vereinshistorie, Museums-Look) === */
.timeline-intro {
max-width: 60ch;
margin-inline: auto;
padding-block: var(--space-3xl) 0;
text-align: center;
color: var(--clr-text-muted);
}
/* Sprung-Navigation: Jahres-Pills, klebt beim Scrollen oben */
.timeline-nav {
position: sticky;
top: 1rem;
z-index: 5;
display: flex;
justify-content: center;
margin-bottom: var(--space-4xl);
}
.timeline-nav__list {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-2xs);
padding: var(--space-2xs);
background: rgb(10 10 10 / 0.82);
border: 1px solid var(--clr-glass-border);
border-radius: 999px;
backdrop-filter: blur(6px);
}
.timeline-nav a {
display: inline-block;
padding: 0.25em 0.85em;
font-family: var(--ff-heading);
/* Coolvetica unter ~28px wird unleserlich (Projekt-Faustregel) */
font-size: var(--fs-650);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
text-transform: uppercase;
text-decoration: none;
color: var(--clr-text-muted);
border-radius: 999px;
transition: color var(--transition), background var(--transition);
}
.timeline-nav a:hover {
color: var(--clr-text);
}
.timeline-nav a.is-active {
color: var(--clr-text);
background: var(--clr-accent);
}
/* Mittellinie + Stationen */
.timeline {
position: relative;
display: grid;
gap: var(--space-6xl);
padding-block: var(--space-s) var(--space-2xl);
}
.timeline::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 2px;
transform: translateX(-50%);
background: linear-gradient(180deg,
transparent,
rgb(var(--clr-accent-rgb) / 0.55) 6%,
rgb(var(--clr-accent-rgb) / 0.55) 94%,
transparent);
}
.timeline__event {
position: relative;
width: calc(50% - 3.5rem);
}
.timeline__event:nth-child(even) {
margin-left: auto;
}
.timeline__marker {
position: absolute;
top: 0.6rem;
left: calc(100% + 3.5rem);
width: 16px;
height: 16px;
transform: translateX(-50%);
background: var(--clr-accent);
border-radius: 50%;
box-shadow: 0 0 0 4px rgb(var(--clr-accent-rgb) / 0.25), 0 0 18px rgb(var(--clr-accent-rgb) / 0.5);
}
.timeline__event:nth-child(even) .timeline__marker {
left: -3.5rem;
}
.timeline__year {
font-size: var(--fs-900);
color: var(--clr-text);
text-shadow: 0 2px 18px rgb(0 0 0 / 0.5);
margin-bottom: var(--space-s);
}
.timeline__event:nth-child(odd) .timeline__year {
text-align: right;
}
/* Museums-Rahmen: Foto wie ein aufgezogener Print, leicht gedreht */
.timeline__figure {
margin: 0;
padding: var(--space-s) var(--space-s) var(--space-s);
background: var(--clr-sepia-bg);
border-radius: 3px;
box-shadow: 0 12px 35px rgb(0 0 0 / 0.5);
transform: rotate(-1.2deg);
transition: transform var(--transition);
}
.timeline__event:nth-child(even) .timeline__figure {
transform: rotate(1.2deg);
}
.timeline__event:hover .timeline__figure {
transform: rotate(0deg) scale(1.02);
}
.timeline__figure img {
width: 100%;
height: auto;
display: block;
}
.timeline__text {
padding-top: var(--space-s);
font-size: var(--fs-500);
line-height: 1.45;
color: var(--clr-sepia-text);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Station ohne Foto: dieselbe Sepia-Fläche, nur ohne den Abstand zum Bild darüber */
.timeline__figure--note .timeline__text {
padding-top: 0;
}
/* Scroll-Reveal nur mit JS (js-reveal), sonst alles sichtbar */
.js-reveal .timeline__event {
opacity: 0;
translate: 0 28px;
transition: opacity 600ms ease, translate 600ms ease;
}
.js-reveal .timeline__event.is-visible {
opacity: 1;
translate: 0 0;
}
@media (max-width: 768px) {
.timeline::before {
left: 8px;
}
.timeline__event,
.timeline__event:nth-child(even) {
width: auto;
margin-left: 0;
padding-left: var(--space-3xl);
}
.timeline__marker,
.timeline__event:nth-child(even) .timeline__marker {
left: 8px;
}
.timeline__event:nth-child(odd) .timeline__year {
text-align: left;
}
}
/* === partners === */
.partners > .container {
text-align: center;
}
.partners > .container > p {
max-width: 60ch;
margin-inline: auto;
}
/* Intro-Abstand zur Überschrift einheitlich mit den anderen Sektionen */
.partners__intro {
margin-top: var(--space-s);
}
.partners__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 220px));
justify-content: center;
align-items: center;
gap: var(--space-2xl);
margin-block: var(--space-3xl);
}
.partners__item {
display: grid;
place-items: center;
padding: var(--space-l);
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Weiße Karte die Logos sind die farbigen Originale der Partner,
ein neutraler weißer Grund trägt jede Markenfarbe */
background: var(--clr-logo-card);
border-radius: var(--radius-card);
min-height: 120px;
}
.partners__item img {
max-height: 80px;
width: auto;
max-width: 100%;
object-fit: contain;
}
/* === sponsor-arguments === */
.sponsor-arguments__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-3xl) var(--space-4xl);
list-style: none;
padding: 0;
}
.sponsor-arguments__item {
display: flex;
gap: var(--space-m);
align-items: flex-start;
}
.sponsor-arguments__icon {
flex-shrink: 0;
width: 2.5rem;
height: 2.5rem;
background: var(--clr-accent);
border-radius: 8px;
display: grid;
place-items: center;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: #fff;
margin-top: var(--space-3xs);
}
.sponsor-arguments__title {
font-family: var(--ff-heading);
font-size: var(--fs-675);
text-transform: uppercase;
line-height: var(--lh-heading);
margin: 0 0 var(--space-2xs);
}
.sponsor-arguments__text {
color: var(--clr-text-muted);
font-size: var(--fs-500);
line-height: var(--lh-body);
margin: 0;
}
@media (max-width: 768px) {
.sponsor-arguments__grid {
grid-template-columns: 1fr;
gap: var(--space-2xl);
}
}
/* === sponsor-channels === */
.sponsor-channels > .container {
text-align: center;
}
.sponsor-channels__intro {
max-width: 65ch;
margin-inline: auto;
margin-top: var(--space-s);
color: var(--clr-text-muted);
}
.sponsor-channels__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-l);
margin-top: var(--space-3xl);
list-style: none;
padding: 0;
align-items: stretch;
}
.sponsor-channels__card {
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-top: 3px solid var(--clr-accent);
border-radius: var(--radius-card);
padding: var(--space-2xl);
display: flex;
flex-direction: column;
gap: 0;
text-align: left;
transition: background var(--transition), box-shadow var(--transition);
}
.sponsor-channels__card:hover {
background: rgb(255 255 255 / 0.07);
box-shadow: 0 8px 32px rgb(0 0 0 / 0.35);
}
.sponsor-channels__head {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0;
}
.sponsor-channels__kicker {
font-family: var(--ff-body);
font-size: var(--fs-300);
font-weight: var(--fw-bold);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
text-transform: uppercase;
color: var(--clr-text-muted);
margin: 0 0 var(--space-s);
}
.sponsor-channels__icon {
width: 2.75rem;
height: 2.75rem;
background: var(--clr-accent);
border-radius: 8px;
display: grid;
place-items: center;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-m);
color: #fff;
margin-bottom: var(--space-m);
}
.sponsor-channels__title {
font-family: var(--ff-heading);
font-size: var(--fs-700);
text-transform: uppercase;
line-height: var(--lh-heading);
margin: 0 0 var(--space-xs);
}
.sponsor-channels__desc {
color: var(--clr-text-muted);
font-size: var(--fs-500);
line-height: var(--lh-body);
margin: 0;
}
.sponsor-channels__divider {
border: none;
border-top: 1px solid var(--clr-glass-border);
margin: var(--space-l) 0;
}
.sponsor-channels__features {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: var(--space-xs);
flex: 1;
}
.sponsor-channels__features li {
display: flex;
align-items: center;
gap: var(--space-xs);
font-size: var(--fs-500);
color: var(--clr-text);
}
.sponsor-channels__check {
flex-shrink: 0;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: var(--clr-accent);
}
@media (max-width: 768px) {
.sponsor-channels__grid {
grid-template-columns: 1fr;
}
.sponsor-channels__title {
font-size: var(--fs-700);
}
}
@media (min-width: 769px) and (max-width: 992px) {
.sponsor-channels__grid {
grid-template-columns: repeat(2, 1fr);
}
.sponsor-channels__card:last-child:nth-child(odd) {
grid-column: 1 / -1;
max-width: 50%;
margin-inline: auto;
}
}
/* === persons (Ansprechpartner-Visitenkarten) === */
.persons > .container {
text-align: center;
}
.persons__intro {
margin-inline: auto;
margin-top: var(--space-s);
max-width: 60ch;
color: var(--clr-text-muted);
}
/* Kurze Hairline unter der Bereichs-Überschrift */
.persons h2::after {
content: "";
display: block;
width: 2.5rem;
height: 2px;
margin: var(--space-2xs) auto 0;
background: var(--clr-accent);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Flexbox statt Grid bewusst: Grid zentriert mit auto-fit + justify-content
nur den GESAMTEN Spaltensatz als Block. Bei mehreren vollen Reihen plus einem
Rest (z. B. 5 Karten = 4 + 1) landet der letzte Einzeleintrag trotzdem unter
Spalte 1 des (zwar zentrierten) Rasters optisch wieder linksbündig. Flexbox
mit flex-wrap zentriert dagegen JEDE Zeile für sich, auch die letzte
unvollständige. flex-grow:0 verhindert, dass eine fast leere letzte Zeile die
Karte(n) darin künstlich breitzieht. */
.persons__grid {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-m);
margin-top: var(--space-3xl);
text-align: left;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Höchstens drei Karten je Reihe (vorher fünf à 200px): bei fünf Ansprech-
partnern stehen jetzt 3 + 2 statt einer gequetschten Fünferreihe. Erst ab
dieser Breite passen Text und Kontakt-Knöpfe nebeneinander in die Karte
(siehe .person-card__body) in 200px-Karten rutschten die Knöpfe wieder
unter den Text und die gesparte Zeile war zurück.
flex-basis über calc() statt fester px-Breite: reagiert auf die Container-
breite statt auf eine angenommene Kartengröße. */
.persons__grid > li {
flex: 0 1 calc((100% - 2 * var(--space-m)) / 3);
min-width: 0;
}
@media (max-width: 768px) {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.persons__grid > li {
flex-basis: calc((100% - var(--space-m)) / 2);
}
}
@media (max-width: 500px) {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.persons__grid > li {
flex-basis: 100%;
}
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Untergruppierte Ansicht (group_by_department): Zwischenüberschrift je
Abteilung, Karten darunter linksbündig eine einzelne Karte wirkt so
verortet statt verwaist zentriert. */
.persons__group-title {
margin-top: var(--space-2xl);
font-family: var(--ff-body);
font-size: var(--fs-500);
text-align: left;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.persons__grid--grouped {
justify-content: flex-start;
margin-top: var(--space-s);
}
.person-card {
display: grid;
height: 100%;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
transition: transform var(--transition), box-shadow var(--transition);
}
.person-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-card);
}
.person-card__media img {
width: 100%;
height: auto;
aspect-ratio: 4 / 5;
object-fit: cover;
/* Ausschnitt nach oben → Gesicht bleibt im Bild, nicht der Bauch */
object-position: center top;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Ohne Foto: Kreis-Avatar mit Initialen statt grauer Silhouette liest sich
sofort als Profilbild folgt". Gleiche Seitenverhältnisse wie das Foto,
damit die Kartenreihe bündig bleibt. */
.person-card__media--initials {
display: grid;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
place-items: center;
aspect-ratio: 4 / 5;
background: var(--clr-bg-deep);
}
.person-card__initials {
display: grid;
place-items: center;
width: var(--space-6xl);
height: var(--space-6xl);
border-radius: 50%;
border: 1px solid var(--clr-glass-border-strong);
background: var(--clr-glass-bg);
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: 1;
color: var(--clr-text-muted);
}
/* Links der Text, rechts die Kontakt-Knöpfe auf einer Höhe damit (statt
darunter) spart pro Karte eine ganze Button-Zeile Scrollstrecke.
Flex mit wrap statt zwei Grid-Spalten: bleibt für die Textspalte weniger als
ihre flex-basis übrig (schmale 200px-Karten im Ansprechpartner-Grid), rutschen
die Knöpfe von selbst wieder unter den Text, statt Name und Nummer auf je
zwei Zeilen zu quetschen. Kein Breakpoint nötig, die Kartenbreite entscheidet. */
.person-card__body {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-2xs) var(--space-s);
padding: var(--space-s) var(--space-m) var(--space-m);
/* Verlauf knüpft an die dunklen Studiofotos an */
background: linear-gradient(180deg, rgb(20 20 20 / 0) 0%, rgb(20 20 20 / 0.35) 100%);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.person-card__text {
display: grid;
gap: var(--space-3xs);
/* 9rem = Umbruchschwelle: darunter passen Text und Knöpfe nicht mehr
nebeneinander. min-width: 0, damit lange Mailadressen umbrechen statt
die Knöpfe aus der Karte zu drücken. */
flex: 1 1 9rem;
min-width: 0;
}
/* Kompaktere Kacheln im Ansprechpartner-Grid (faq-contact bleibt unberührt):
flacherer Foto-Beschnitt = deutlich weniger Scrollstrecke, object-position
top hält die Gesichter im Bild. */
.persons .person-card__media img,
.persons .person-card__media--initials {
aspect-ratio: 4 / 3;
}
.persons .person-card__body {
padding: var(--space-xs) var(--space-s) var(--space-s);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Hierarchie: der NAME ist die Karten-Überschrift, die Abteilung nur eine
Kicker-Zeile darüber (kleine Versalien mit rotem Akzent-Balken Rot als
Textfarbe wäre auf dunklem Grund zu kontrastarm, siehe Design-Regeln). */
/* Dezente einzeilige Kicker-Zeile fs-300 ist die kleinste Token-Stufe,
kleiner" kommt aus engerer Sperrung. Lange Abteilungsnamen (Step Aerobic,
Fitness & Pilates") werden mit gekürzt statt umzubrechen. */
.person-card__department {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-faint);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Klassenbasiert statt über das Element: der Name rendert je Kontext als
h3 oder h4, soll aber immer gleich aussehen (h4h6 laufen in base.css
sonst über Abel). --fs-650 = Coolvetica-Minimum, nie kleiner. */
.person-card__name {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: var(--lh-heading);
text-transform: uppercase;
letter-spacing: var(--ls-tight);
color: var(--clr-text);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.person-card__detail {
font-size: var(--fs-400);
color: var(--clr-text-muted);
overflow-wrap: anywhere;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Kontaktwege als echte Buttons statt Textlinks. Größe, Rundung und die 44px
kommen komplett aus der globalen .btn--icon-Regel (utilities.css) hier
bewusst KEIN Größen-Delta mehr: die frühere lokale Verkleinerung
(min-width: 0 + em-Padding + btn--sm) ließ die Knöpfe als flache Pillen
erscheinen und wich als einzige Stelle im Projekt vom Icon-Button-Standard ab. */
.person-card__actions {
display: flex;
flex: 0 0 auto;
gap: var(--space-2xs);
}
.person-card__contact span {
overflow-wrap: anywhere;
}
.person-card__contact:hover {
text-decoration: underline;
text-underline-offset: 0.25em;
}
/* === mitmachen / positions (Ehrenamt-Stellen) === */
/* Filter-Stripe (Alle/Fußball/Turnen) — Unterstrich-Tabbar wie group-tabs */
.filter-bar {
display: flex;
flex-wrap: wrap;
margin-bottom: var(--space-2xl);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Bereichs-Tabs auf /ansprechpartner: zentriert in der Sektion, direkt über
den Karten (die Leiste startet hidden, persons-tabs.js blendet sie ein).
Schmales Tab-Padding: die Unterstreichung (inset-Shadow über die volle
Tab-Breite) soll am Text kleben, nicht 20px davor beginnen bei der
zentrierten Zweier-Leiste wirkt das Standard-Padding wie ein Versatz. */
.persons-tabs__bar {
justify-content: center;
gap: var(--space-l);
}
.persons-tabs__bar .tab {
padding-inline: var(--space-2xs);
}
/* Ohne JS stehen beide Panels untereinander — Luft zwischen ihnen. */
.persons--embedded + .persons--embedded {
margin-top: var(--space-4xl);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* Gemeinsame Tab-Basis für Filter-Leiste und Gruppen-Tabs. Beide waren bis auf
flex-shrink und 4px Innenabstand zeichengleich implementiert. Aktiv-Zustand
kommt je nach Muster über aria-pressed (Filter) oder aria-selected (Tabs).
Fokus liegt inset, damit der Ring nicht in den Nachbar-Tab ragt. */
.tab {
display: inline-flex;
align-items: center;
min-height: var(--tap-min);
padding: var(--space-xs) var(--space-m);
background: none;
border: none;
box-shadow: inset 0 -2px 0 var(--clr-glass-border);
font-family: var(--ff-body);
font-size: var(--fs-500);
color: var(--clr-text-muted);
cursor: pointer;
white-space: nowrap;
transition: color var(--transition), box-shadow var(--transition);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
.tab:hover {
color: var(--clr-text);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
.tab[aria-pressed="true"],
.tab[aria-selected="true"] {
color: var(--clr-text);
box-shadow: inset 0 -2px 0 var(--clr-accent);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
.tab:focus-visible {
outline: var(--focus-ring);
outline-offset: -2px;
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* Erster Filter bündig zur Textkante links. */
.filter-bar__tab:first-child {
padding-inline-start: 0;
}
.positions__list {
display: grid;
gap: var(--space-l);
}
.positions__empty {
margin: 0;
padding: var(--space-3xl) 0;
max-width: 60ch;
color: var(--clr-text-muted);
font-size: var(--fs-500);
line-height: var(--lh-body);
}
.positions__empty[hidden] {
display: none;
}
.positions__empty a {
color: var(--clr-text);
text-decoration: underline;
text-underline-offset: 0.2em;
}
/* "Warum mithelfen?": geteiltes sponsor-arguments-Raster, hier mit Überschrift
(nur auf dieser Seite Partner-/Sportheim-Variante bleibt ohne Heading unberührt) */
#warum-mithelfen > .container {
text-align: center;
}
#warum-mithelfen .sponsor-arguments__intro {
max-width: 60ch;
margin: var(--space-s) auto 0;
color: var(--clr-text-muted);
}
#warum-mithelfen .sponsor-arguments__grid {
margin-top: var(--space-3xl);
text-align: left;
}
/* Aufklappbare Stelle (details/summary, FAQ-Mechanik): eingeklappt nur Bereich + Titel */
.position-card {
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
transition: border-color var(--transition);
}
.position-card[open] {
border-color: var(--clr-glass-border-strong, var(--clr-glass-border));
}
/* display:grid o. Ä. würde sonst [hidden]{display:none} überschreiben — explizit halten */
.position-card[hidden] {
display: none;
}
/* Klickzeile: Icon + Bereich/Titel + Chevron */
.position-card__head {
display: flex;
align-items: center;
gap: var(--space-s);
padding: var(--space-m) var(--space-l);
cursor: pointer;
list-style: none;
transition: background var(--transition);
}
.position-card__head::-webkit-details-marker {
display: none;
}
.position-card__head:hover {
background: rgb(255 255 255 / 0.04);
}
.position-card__head:focus-visible {
Design-System: Fokus vereinheitlichen, Formularfeld-Ring WCAG-fest machen Letzter Teil. base.css hatte längst eine globale :focus-visible-Regel, trotzdem existierten 15 Fokus-Regeln — die meisten davon Ballast. Fünf Overrides wiederholten die Basisregel praktisch wortgleich (.back-to-top, .ad-banner__dot, .faq__q, .table-scroll, .btn) und sind ersatzlos entfallen; sie unterschieden sich höchstens um 1px Offset. Die Basisregel selbst läuft jetzt über --focus-ring/--focus-offset, .position-card__head wechselt von Akzentrot auf Weiß. Übrig bleiben zehn Regeln, davon deklarieren nur noch vier überhaupt eine outline — jede mit Grund (inset-Offset bei .tab und .position-card__head, geschichteter Ring beim Formularfeld). Die anderen sechs sind reine Zusatz- effekte (transform, Farbe, Fläche) und lassen den Basis-Ring durch. Der eigentliche Fund steckte im Formularfeld: es setzte outline: none und ersetzte den Ring durch einen roten Rahmen mit 30%-Glow. Akzentrot erreicht auf der Feldfläche aber nur 2,8:1 und verfehlt damit WCAG 1.4.11 (>=3:1) für Fokus-Indikatoren — Tastaturnutzer hatten dort also den schwächsten Fokus der ganzen Seite. Roter Rahmen und Glow bleiben als Marken-Signal, der weiße Standard-Ring kommt zurück; outline-offset entspricht der Glow-Breite, beide Ringe liegen bündig nebeneinander statt übereinander. CLAUDE.md dokumentiert die neuen Regeln: Token-Disziplin mit Tabelle (Spacing, Typo, Icons, Sperrung, Fokus, Trefferfläche) samt der bewussten em-Ausnahme, das Button- und Tab-System inklusive der (0,2,0)-Falle durch die CSS-Ladereihenfolge, und die Fokus-Regel. Dazu ein Punkt in der Checkliste. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:33:53 +02:00
outline: var(--focus-ring);
outline-offset: -2px;
}
.position-card__icon {
flex-shrink: 0;
width: 2.5rem;
height: 2.5rem;
background: var(--clr-accent);
border-radius: 8px;
display: grid;
place-items: center;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-m);
color: #fff;
}
.position-card__heading {
flex: 1;
min-width: 0;
}
.position-card__area {
display: block;
font-family: var(--ff-body);
font-size: var(--fs-300);
font-weight: var(--fw-bold);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
text-transform: uppercase;
color: var(--clr-text-muted);
margin: 0 0 var(--space-3xs);
}
.position-card__title {
font-family: var(--ff-heading);
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* --fs-675 (34px) ist laut tokens.css für die Header-Wortmarke gedacht, nicht für
Karten-Titel --fs-690 ("Karten-/Kachel-Überschrift") ist der richtige Token,
dasselbe Muster wie .team-card__name/.group-card__name/.bento__heading. */
font-size: var(--fs-690);
text-transform: uppercase;
line-height: var(--lh-heading);
margin: 0;
}
.position-card__chevron {
flex: none;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: var(--clr-text-muted);
transition: transform var(--transition), color var(--transition);
}
.position-card[open] .position-card__chevron {
transform: rotate(180deg);
color: var(--clr-text);
}
/* Aufgeklappter Inhalt: Detailspalte + Ansprechpartner */
.position-card__body {
display: grid;
grid-template-columns: 1fr minmax(0, 16rem);
gap: var(--space-3xl);
align-items: start;
padding: 0 var(--space-l) var(--space-l) var(--space-6xl);
animation: faq-reveal 260ms ease;
}
.position-card__main > :first-child {
margin-top: 0;
}
.position-card__summary {
color: var(--clr-text-muted);
font-size: var(--fs-500);
line-height: var(--lh-body);
margin: 0;
}
.position-card__tasks {
list-style: none;
padding: 0;
margin: var(--space-m) 0 0;
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.position-card__tasks li {
display: flex;
align-items: flex-start;
gap: var(--space-xs);
font-size: var(--fs-500);
line-height: var(--lh-body);
}
.position-card__check {
flex-shrink: 0;
margin-top: 0.2em;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: var(--clr-accent);
}
.position-card__meta {
margin: var(--space-m) 0 0;
display: grid;
gap: var(--space-xs);
}
.position-card__meta-row {
display: grid;
gap: var(--space-3xs);
}
.position-card__meta dt {
display: inline-flex;
align-items: center;
gap: var(--space-2xs);
font-size: var(--fs-300);
font-weight: var(--fw-bold);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
text-transform: uppercase;
color: var(--clr-text-muted);
}
.position-card__meta-icon {
color: var(--clr-accent);
}
.position-card__meta dd {
margin: 0;
font-size: var(--fs-500);
line-height: var(--lh-body);
}
/* Kompakte Kontakt-Karte: flacheres Foto als im Ansprechpartner-Grid */
.position-card__contact .person-card__media img {
aspect-ratio: 4 / 3.4;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* .person-card__department läuft hier als <h4> (level-Prop, siehe person-card.php) statt
als <h3> wie im Ansprechpartner-Grid base.css gibt h4 damit Abel statt Coolvetica,
bei gleicher Schriftgröße (--fs-650) liest sich das als fette Blocktype statt kompakter
Headline. In der schmalen 16rem-Sidebar wirkt das riesig UND (mangels color-Override)
heller als der gedämpfte Name darunter. Gleiche kleine Kicker-Optik wie .position-card__area
direkt nebenan der Name bleibt die eigentliche Aussage. */
.position-card__contact .person-card__department {
font-size: var(--fs-300);
font-weight: var(--fw-bold);
letter-spacing: var(--ls-wide);
color: var(--clr-text-muted);
}
@media (max-width: 768px) {
.position-card__body {
grid-template-columns: 1fr;
gap: var(--space-l);
padding: 0 var(--space-l) var(--space-l);
}
.position-card__contact {
max-width: 18rem;
}
}
/* === contact form === */
.contact__inner {
display: grid;
gap: var(--space-3xl);
justify-items: center;
}
.contact__intro {
max-width: 60ch;
text-align: center;
}
.contact__intro p {
margin-top: var(--space-s);
}
.form {
display: grid;
gap: var(--space-m);
width: 100%;
max-width: 720px;
padding: var(--space-2xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
.form__row {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: var(--space-m);
}
@media (max-width: 600px) {
.form__row {
grid-template-columns: 1fr;
}
}
2026-06-20 22:18:34 +02:00
/* Floating Label: Label liegt im leeren Feld wie ein Platzhalter und wandert bei
Fokus oder Inhalt nach oben. Rein visuell das echte <label for> bleibt im DOM
(kein Placeholder-als-Label), darum auch für Screenreader voll nutzbar. */
.form__field {
2026-06-20 22:18:34 +02:00
position: relative;
}
.form__field input,
.form__field select,
.form__field textarea {
width: 100%;
padding: var(--space-l) var(--space-xs) var(--space-2xs);
2026-06-20 22:18:34 +02:00
background: var(--clr-field-bg);
border: 1px solid var(--clr-field-border);
border-radius: var(--radius-btn);
color: var(--clr-text);
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}
2026-06-20 22:18:34 +02:00
/* Label im Ruhezustand — sitzt auf der Eingabezeile (deckt das " "-Placeholder) */
.form__field:not(.form__field--checkbox) > label {
position: absolute;
left: 0.9rem;
top: 1.4rem;
font-size: var(--fs-500);
line-height: 1;
color: var(--clr-text-muted);
pointer-events: none;
transform-origin: left top;
transition: transform var(--transition), color var(--transition);
}
/* Geschwebt: bei Fokus, bei vorhandenem Inhalt (placeholder=" "-Trick) sowie
dauerhaft für Select und Datumsfelder (haben keinen :placeholder-shown-Zustand). */
.form__field:not(.form__field--checkbox):has(input:focus) > label,
.form__field:not(.form__field--checkbox):has(textarea:focus) > label,
.form__field:not(.form__field--checkbox):has(select:focus) > label,
.form__field:not(.form__field--checkbox):has(input:not(:placeholder-shown)) > label,
.form__field:not(.form__field--checkbox):has(textarea:not(:placeholder-shown)) > label,
.form__field:not(.form__field--checkbox):has(select) > label,
.form__field:not(.form__field--checkbox):has(input[type="date"]) > label {
transform: translateY(-0.95rem) scale(0.78);
color: var(--clr-text);
}
.form__field input:hover,
.form__field select:hover,
.form__field textarea:hover {
2026-06-20 22:18:34 +02:00
border-color: var(--clr-field-border-hover);
}
Design-System: Fokus vereinheitlichen, Formularfeld-Ring WCAG-fest machen Letzter Teil. base.css hatte längst eine globale :focus-visible-Regel, trotzdem existierten 15 Fokus-Regeln — die meisten davon Ballast. Fünf Overrides wiederholten die Basisregel praktisch wortgleich (.back-to-top, .ad-banner__dot, .faq__q, .table-scroll, .btn) und sind ersatzlos entfallen; sie unterschieden sich höchstens um 1px Offset. Die Basisregel selbst läuft jetzt über --focus-ring/--focus-offset, .position-card__head wechselt von Akzentrot auf Weiß. Übrig bleiben zehn Regeln, davon deklarieren nur noch vier überhaupt eine outline — jede mit Grund (inset-Offset bei .tab und .position-card__head, geschichteter Ring beim Formularfeld). Die anderen sechs sind reine Zusatz- effekte (transform, Farbe, Fläche) und lassen den Basis-Ring durch. Der eigentliche Fund steckte im Formularfeld: es setzte outline: none und ersetzte den Ring durch einen roten Rahmen mit 30%-Glow. Akzentrot erreicht auf der Feldfläche aber nur 2,8:1 und verfehlt damit WCAG 1.4.11 (>=3:1) für Fokus-Indikatoren — Tastaturnutzer hatten dort also den schwächsten Fokus der ganzen Seite. Roter Rahmen und Glow bleiben als Marken-Signal, der weiße Standard-Ring kommt zurück; outline-offset entspricht der Glow-Breite, beide Ringe liegen bündig nebeneinander statt übereinander. CLAUDE.md dokumentiert die neuen Regeln: Token-Disziplin mit Tabelle (Spacing, Typo, Icons, Sperrung, Fokus, Trefferfläche) samt der bewussten em-Ausnahme, das Button- und Tab-System inklusive der (0,2,0)-Falle durch die CSS-Ladereihenfolge, und die Fokus-Regel. Dazu ein Punkt in der Checkliste. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:33:53 +02:00
/* Roter Rahmen + Glow als Marken-Signal, dazu der weiße Standard-Ring.
Der rote Rahmen allein reichte nicht: Akzentrot kommt auf der Feldfläche nur
auf 2,8:1 und verfehlt damit WCAG 1.4.11 (>=3:1) für Fokus-Indikatoren.
outline-offset entspricht der Glow-Breite, beide Ringe liegen also bündig
nebeneinander statt übereinander. */
.form__field input:focus-visible,
.form__field select:focus-visible,
.form__field textarea:focus-visible {
Design-System: Fokus vereinheitlichen, Formularfeld-Ring WCAG-fest machen Letzter Teil. base.css hatte längst eine globale :focus-visible-Regel, trotzdem existierten 15 Fokus-Regeln — die meisten davon Ballast. Fünf Overrides wiederholten die Basisregel praktisch wortgleich (.back-to-top, .ad-banner__dot, .faq__q, .table-scroll, .btn) und sind ersatzlos entfallen; sie unterschieden sich höchstens um 1px Offset. Die Basisregel selbst läuft jetzt über --focus-ring/--focus-offset, .position-card__head wechselt von Akzentrot auf Weiß. Übrig bleiben zehn Regeln, davon deklarieren nur noch vier überhaupt eine outline — jede mit Grund (inset-Offset bei .tab und .position-card__head, geschichteter Ring beim Formularfeld). Die anderen sechs sind reine Zusatz- effekte (transform, Farbe, Fläche) und lassen den Basis-Ring durch. Der eigentliche Fund steckte im Formularfeld: es setzte outline: none und ersetzte den Ring durch einen roten Rahmen mit 30%-Glow. Akzentrot erreicht auf der Feldfläche aber nur 2,8:1 und verfehlt damit WCAG 1.4.11 (>=3:1) für Fokus-Indikatoren — Tastaturnutzer hatten dort also den schwächsten Fokus der ganzen Seite. Roter Rahmen und Glow bleiben als Marken-Signal, der weiße Standard-Ring kommt zurück; outline-offset entspricht der Glow-Breite, beide Ringe liegen bündig nebeneinander statt übereinander. CLAUDE.md dokumentiert die neuen Regeln: Token-Disziplin mit Tabelle (Spacing, Typo, Icons, Sperrung, Fokus, Trefferfläche) samt der bewussten em-Ausnahme, das Button- und Tab-System inklusive der (0,2,0)-Falle durch die CSS-Ladereihenfolge, und die Fokus-Regel. Dazu ein Punkt in der Checkliste. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:33:53 +02:00
outline: var(--focus-ring);
outline-offset: var(--focus-offset);
2026-06-20 22:18:34 +02:00
border-color: var(--clr-accent);
box-shadow: 0 0 0 3px rgb(var(--clr-accent-rgb) / 0.3);
}
2026-06-20 22:18:34 +02:00
/* Der " "-Platzhalter aus dem Floating-Trick bleibt unsichtbar */
.form__field ::placeholder {
2026-06-20 22:18:34 +02:00
color: transparent;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Autofill (Chrome/Safari/Edge füllen Telefon/E-Mail gern automatisch): der
Browser rendert das Feld sonst mit einer eigenen hellen Füllfläche + schwarzer
Schrift, die sich weder per background noch per color übersteuern lässt.
Einzig wirksamer Hebel ist ein deckender box-shadow inset (deshalb die OPAKE
--clr-field-bg-solid statt der sonst überall genutzten transparenten
--clr-field-bg) + -webkit-text-fill-color für die Schriftfarbe. Die absurd
lange transition verhindert, dass Chrome die native Füllung beim periodischen
Neuanwenden kurz aufblitzen lässt. :autofill (ohne Präfix) deckt Firefox ab. */
.form__field input:-webkit-autofill,
.form__field input:-webkit-autofill:hover,
.form__field input:-webkit-autofill:focus,
.form__field select:-webkit-autofill,
.form__field textarea:-webkit-autofill,
.form__field input:autofill,
.form__field select:autofill,
.form__field textarea:autofill {
-webkit-text-fill-color: var(--clr-text);
caret-color: var(--clr-text);
-webkit-box-shadow: 0 0 0 1000px var(--clr-field-bg-solid) inset;
box-shadow: 0 0 0 1000px var(--clr-field-bg-solid) inset;
transition: background-color 600000s ease-in-out 0s, box-shadow 600000s ease-in-out 0s;
}
/* Fehlerzustand: per JS (aria-invalid) und nativ nach Nutzereingabe (:user-invalid) */
.form__field input[aria-invalid="true"],
.form__field select[aria-invalid="true"],
.form__field textarea[aria-invalid="true"],
.form__field input:user-invalid,
.form__field select:user-invalid,
.form__field textarea:user-invalid {
border-color: var(--clr-error);
}
.form__field select {
appearance: none;
padding-right: var(--space-3xl);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%23ffffff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.9rem center;
}
.form__field select option {
background: var(--clr-bg);
color: var(--clr-text);
}
.form__required {
color: var(--clr-accent);
}
.form__hint {
margin-top: var(--space-2xs);
font-size: var(--fs-400);
color: var(--clr-text-muted);
}
.form__error-msg {
margin-top: var(--space-2xs);
font-size: var(--fs-400);
color: var(--clr-error);
}
.form button[disabled] {
opacity: 0.65;
cursor: progress;
}
.form__field textarea {
resize: vertical;
min-height: 8rem;
}
.form__field--checkbox {
2026-06-20 22:18:34 +02:00
display: grid;
grid-template-columns: auto 1fr;
align-items: start;
gap: var(--space-2xs);
}
.form__field--checkbox input {
/* 24px — Mindest-Zielgröße (WCAG 2.5.8) */
width: 1.5rem;
height: 1.5rem;
margin-top: var(--space-4xs);
accent-color: var(--clr-accent);
}
.form__field--checkbox label {
font-size: var(--fs-500);
}
/* Leer: unsichtbar, aber im Accessibility-Tree display:none würde die
aria-live-Region abmelden und Screenreader verpassen die erste Meldung. */
.form__status:empty {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
}
.form__success {
padding: var(--space-xs) var(--space-s);
border: 1px solid var(--clr-success);
border-radius: var(--radius-btn);
color: var(--clr-success);
}
.form__error {
padding: var(--space-xs) var(--space-s);
border: 1px solid var(--clr-error);
border-radius: var(--radius-btn);
color: var(--clr-error);
}
.form__submit {
margin: 0;
}
/* Gruppierte Abschnitte (fieldset/legend) jeder Block ein dezent umrandetes
Feld mit Titel auf der Rahmenlinie. Gliedert lange Formulare optisch klar. */
.form__group {
margin: 0;
padding: var(--space-m) var(--space-l) var(--space-l);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
min-inline-size: 0;
}
.form__legend {
padding: 0 var(--space-2xs);
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-text);
}
.form__group-body {
display: grid;
gap: var(--space-m);
}
/* === Werbe-/Sponsoren-Banner (Slider) === */
.ad-banner {
--banner-interval: 6s;
}
.ad-banner__track {
list-style: none;
margin: 0;
padding: 0;
}
/* Meta-Zeile unter dem Slider: Label links, Controls rechts */
.ad-banner__meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-s);
margin-top: var(--space-s);
min-height: 2rem;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Unter 600px verlieren Label und die vier Controls (Pfeile, Dots, Pause) den
Platz nebeneinander das Label bricht auf 4-5 schmale Zeilen, während die
Controls mittig danebenschweben. Gestapelt statt gequetscht: Label über volle
Breite, Controls darunter als eigene, zentrierte Zeile. */
@media (max-width: 600px) {
.ad-banner__meta {
flex-direction: column;
align-items: flex-start;
min-height: 0;
}
.ad-banner__controls {
align-self: stretch;
justify-content: center;
}
}
.ad-banner__meta-label {
font-size: var(--fs-400);
color: var(--clr-text-muted);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-tight);
}
.ad-banner__slide[hidden] {
display: none;
}
.ad-banner__slide {
display: flex;
flex-direction: column;
align-items: flex-start;
min-height: 320px;
padding: clamp(var(--space-xl), var(--space-s) + 2vw, var(--space-4xl));
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
box-shadow: var(--shadow-card);
}
/* Inhaltsbreite begrenzen, damit Titel/Text die linke Hälfte belegen und das
Foto rechts frei bleibt. */
.ad-banner__content {
max-width: 60ch;
}
/* Fußzeile: CTAs links, Anzeige-/Status-Label rechts — an den unteren Rand. */
.ad-banner__footer {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs) var(--space-s);
width: 100%;
margin-top: auto;
padding-top: var(--space-l);
}
/* Crossfade-Übergang (nur mit JS): Slides im selben Grid-Feld stapeln, sodass
die Höhe konstant bleibt (kein Sprung) und ein- wie ausgehende Folie sauber
überblenden. Die ausgehende driftet leicht nach unten, die eingehende steigt
auf. Ohne JS greift weiter .ad-banner__slide[hidden] (nur erste Folie).
Reduced-Motion: globaler Kill-Switch in reset.css macht den Wechsel instant. */
.ad-banner.is-enhanced .ad-banner__track {
display: grid;
}
.ad-banner.is-enhanced .ad-banner__slide {
grid-area: 1 / 1;
opacity: 0;
transform: translateY(8px);
pointer-events: none;
transition: opacity 0.55s ease, transform 0.55s ease, visibility 0s linear 0.55s;
visibility: hidden;
}
.ad-banner.is-enhanced .ad-banner__slide.is-active {
opacity: 1;
transform: none;
pointer-events: auto;
visibility: visible;
transition: opacity 0.55s ease, transform 0.55s ease, visibility 0s;
}
/* Optionaler Hintergrund pro Banner (data: "background").
Dunkler Verlauf über dem Bild hält Text & CTA links lesbar. */
.ad-banner__slide--bg {
background-image:
linear-gradient(to right, rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.45) 60%, rgb(0 0 0 / 0.3)),
var(--banner-bg);
background-size: cover;
background-position: center;
/* Bild an der Innenkante kappen, nicht unter den 1px-Rahmen malen
(sonst schimmert es an der transparenten Rahmenkante durch). */
background-clip: padding-box;
border-color: transparent;
}
/* Pro-Slide-Akzentfarbe (data: "accent") z. B. Sponsor-CI statt Vereins-Rot.
--banner-accent kommt als Inline-Variable von der Komponente. */
.ad-banner__slide--accent {
--clr-accent: var(--banner-accent);
--clr-accent-dark: color-mix(in srgb, var(--banner-accent) 82%, #000);
}
/* Solider Button: dunkler, aus der Akzentfarbe abgeleiteter Text helle
Akzentfarben (z. B. Teal) hätten mit Weiß zu wenig Kontrast (WCAG 1.4.3). */
.ad-banner__slide--accent .ad-banner__cta.btn:not(.btn--outline) {
color: color-mix(in srgb, var(--banner-accent) 22%, #000);
}
.ad-banner__slide--accent .ad-banner__cta.btn--outline {
color: var(--banner-accent);
border-color: var(--banner-accent);
}
.ad-banner__slide--accent .ad-banner__cta.btn--outline:hover {
background: color-mix(in srgb, var(--banner-accent) 16%, transparent);
border-color: var(--banner-accent);
color: var(--banner-accent);
}
.ad-banner__slide--bg .ad-banner__text {
color: var(--clr-text);
}
@media (max-width: 768px) {
/* Auf Mobil läuft der Verlauf nach unten, damit der gestapelte Text lesbar bleibt. */
.ad-banner__slide--bg {
background-image:
linear-gradient(to bottom, rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.5)),
var(--banner-bg);
}
}
/* Eigenwerbung (Hier könnte Ihre Werbung stehen") rote Glasfläche mit
gestricheltem Frame, das eine freie Werbefläche andeutet. */
.ad-banner__slide--house {
position: relative;
overflow: hidden;
background:
radial-gradient(135% 145% at 100% 0%, rgb(var(--clr-accent-rgb) / 0.24), transparent 55%),
var(--clr-glass-bg);
border-color: rgb(var(--clr-accent-rgb) / 0.5);
}
.ad-banner__slide--house .ad-banner__content,
.ad-banner__slide--house .ad-banner__logo {
position: relative;
z-index: 1;
}
.ad-banner__slide--house .ad-banner__tag {
color: #fff;
background: var(--clr-accent);
border-color: transparent;
}
.ad-banner__slide--house .ad-banner__text {
color: var(--clr-text);
}
/* Eigenwerbung MIT Foto-Hintergrund: rot-dunkler Verlauf von links hält den
Text lesbar, das Foto bleibt rechts sichtbar. */
.ad-banner__slide--house.ad-banner__slide--bg {
background-image:
linear-gradient(to right, rgb(12 10 11 / 0.9), rgb(20 16 17 / 0.55) 55%, rgb(20 16 17 / 0.12) 90%),
var(--banner-bg);
background-size: cover;
background-position: center;
/* wie bei --bg: nicht unter den Rahmen malen (--house-Shorthand setzt es zurück) */
background-clip: padding-box;
border-color: transparent;
}
@media (max-width: 768px) {
/* Auf Mobil läuft der Verlauf nach unten (Text steht gestapelt darüber). */
.ad-banner__slide--house.ad-banner__slide--bg {
background-image:
linear-gradient(to bottom, rgb(12 10 11 / 0.88), rgb(20 16 17 / 0.7)),
var(--banner-bg);
}
}
/* Anzeige-/Status-Label: sitzt rechts in der Fußzeile (margin-left:auto).
Dunkle Pille, damit es auch über dem Foto lesbar bleibt. */
.ad-banner__tag {
margin-left: auto;
align-self: center;
padding: 0.2em 0.7em;
font-size: var(--fs-300);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
background: rgb(0 0 0 / 0.45);
border: 1px solid rgb(255 255 255 / 0.18);
border-radius: 999px;
}
.ad-banner__title {
font-family: var(--ff-heading);
font-size: var(--fs-700);
line-height: var(--lh-heading);
margin-bottom: var(--space-2xs);
}
.ad-banner__text {
max-width: 52ch;
color: var(--clr-text-muted);
}
/* CTA-Reihe: Primär- + optionaler Outline-Sekundär-Button nebeneinander. */
.ad-banner__actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-xs);
}
/* Logo führt die Slide an: kompaktes Badge oben links. */
.ad-banner__logo {
margin-bottom: var(--space-l);
}
/* Helle Platte für dunkle Firmenlogos (Wortmarken). */
.ad-banner__logo--light {
padding: var(--space-2xs) var(--space-xs);
background: #fff;
border-radius: var(--radius-btn);
}
.ad-banner__logo img {
display: block;
width: auto;
height: auto;
max-width: 230px;
max-height: 56px;
object-fit: contain;
}
/* Vereinswappen (Eigenwerbung) darf etwas größer stehen. */
.ad-banner__slide--house .ad-banner__logo img {
max-height: 76px;
}
@media (max-width: 768px) {
.ad-banner__content {
max-width: 100%;
}
}
/* Steuerung: Pause/Play-Taste + Indikatorleiste — sitzt rechts in .ad-banner__meta. */
.ad-banner__controls {
display: flex;
align-items: center;
gap: var(--space-xs);
flex-shrink: 0;
}
.ad-banner__controls[hidden] {
display: none;
}
.ad-banner__toggle[hidden] {
display: none;
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* Glas-Optik als Delta zu .btn--icon Größe, Rundung, Zentrierung und die
44px-Trefferfläche kommen von dort. Beide Controls waren vorher zeichengleich
dupliziert. .btn muss im Selektor mitstehen: utilities.css lädt nach
components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. */
.btn.ad-banner__toggle,
.btn.ad-banner__nav-btn {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: var(--clr-text);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
transition: background var(--transition);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
.btn.ad-banner__toggle:hover,
.btn.ad-banner__nav-btn:hover {
background: rgb(255 255 255 / 0.2);
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
border-color: var(--clr-glass-border);
}
.ad-banner__toggle-icon {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
}
/* Pause-Icon im Abspiel-Zustand, Play-Icon wenn pausiert. */
.ad-banner__toggle .ad-banner__toggle-icon--play {
display: none;
}
.ad-banner__toggle[aria-pressed="true"] .ad-banner__toggle-icon--pause {
display: none;
}
.ad-banner__toggle[aria-pressed="true"] .ad-banner__toggle-icon--play {
display: inline-block;
}
/* Indikatorleiste — die aktive Leiste füllt sich über --banner-interval. */
.ad-banner__indicators {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-2xs);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* Trefferfläche 48x44px, sichtbar bleibt der 6px-Balken. Der Balken liegt im
::before statt auf dem Button selbst so kann overflow:hidden entfallen, das
sonst jede Vergrößerung der Trefferfläche wieder abschneiden würde. */
.ad-banner__dot {
position: relative;
width: 48px;
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
height: var(--tap-min);
padding: 0;
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
background: none;
border: 0;
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
cursor: pointer;
}
.ad-banner__dot::before,
.ad-banner__progress {
position: absolute;
inset: calc(50% - 3px) 0 auto;
height: 6px;
border-radius: 999px;
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
}
.ad-banner__dot::before {
content: "";
background: var(--clr-glass-border);
transition: background var(--transition);
}
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
.ad-banner__dot:hover::before {
background: rgb(255 255 255 / 0.35);
}
.ad-banner__progress {
background: var(--clr-accent);
transform: scaleX(0);
transform-origin: left;
}
.ad-banner__dot.is-active .ad-banner__progress {
animation: ad-progress var(--banner-interval) linear forwards;
}
.ad-banner.is-paused .ad-banner__dot.is-active .ad-banner__progress {
animation-play-state: paused;
}
@keyframes ad-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
@media (prefers-reduced-motion: reduce) {
.ad-banner__dot.is-active .ad-banner__progress {
animation: none;
transform: scaleX(1);
}
}
/* === key-facts (Faktenleiste) === */
.key-facts__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: var(--space-s);
margin: 0;
padding: 0;
list-style: none;
}
.key-facts__item {
display: flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-s) var(--space-m);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
.key-facts__icon {
display: inline-flex;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-l);
color: var(--clr-accent);
}
.key-facts__text {
display: grid;
gap: var(--space-4xs);
}
.key-facts__label {
font-size: var(--fs-400);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.key-facts__value {
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: var(--lh-heading);
}
/* === team-about === */
.team-about p {
max-width: 68ch;
}
/* === training-location (Bento-Grid) === */
.bento {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(0, auto);
gap: var(--space-m);
}
/* Tile-Größen: Trainingszeiten = großer Anker, Spielort = breit, dazu zwei kleine. */
.bento__tile--times { grid-column: span 2; grid-row: span 2; }
.bento__tile--venue { grid-column: span 2; }
.bento__tile--accent { grid-column: span 1; }
.bento__tile--route { grid-column: span 1; }
.bento__tile {
position: relative;
display: flex;
flex-direction: column;
padding: var(--space-xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
}
/* Akzent-Tile: gefüllt, weiße Schrift (gut lesbar), zentrierte Kennzahl. */
.bento__tile--accent {
justify-content: center;
gap: var(--space-3xs);
background: var(--clr-accent);
border-color: var(--clr-accent);
text-align: center;
}
.bento__tile--route {
justify-content: center;
align-items: center;
gap: var(--space-s);
text-align: center;
}
/* Inhalt über dem Deko-Icon halten. */
.bento__heading,
.bento__sessions,
.bento__address,
.bento__note {
position: relative;
z-index: 1;
}
.bento__heading {
display: flex;
align-items: center;
gap: var(--space-xs);
margin-bottom: var(--space-l);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-690);
line-height: var(--lh-heading);
}
.bento__hicon {
flex: none;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-l);
color: var(--clr-accent);
}
.bento__sessions {
margin: 0;
padding: 0;
list-style: none;
}
.bento__sessions li {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-s);
padding: var(--space-s) 0;
border-bottom: 1px solid var(--clr-glass-border);
}
.bento__sessions li:first-child { padding-top: 0; }
.bento__sessions li:last-child { padding-bottom: 0; border-bottom: 0; }
.bento__day {
font-size: var(--fs-600);
}
.bento__time {
font-family: var(--ff-heading);
font-size: var(--fs-650);
color: var(--clr-text);
}
.bento__note {
margin-top: var(--space-s);
}
.bento__address {
margin: 0;
font-size: var(--fs-600);
line-height: 1.5;
}
/* Akzent-Tile-Typo. */
.bento__stat-label {
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: rgb(255 255 255 / 0.85);
}
.bento__stat-value {
font-family: var(--ff-heading);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-690);
line-height: var(--lh-heading);
color: #fff;
}
.bento__route-label {
font-family: var(--ff-heading);
font-size: var(--fs-650);
}
/* Großes, angeschnittenes Deko-Icon unten rechts. */
.bento__deco {
position: absolute;
right: -1rem;
bottom: -1.75rem;
z-index: 0;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-deco);
line-height: 1;
color: var(--clr-text);
opacity: 0.06;
pointer-events: none;
}
@media (max-width: 900px) {
.bento {
grid-template-columns: repeat(2, 1fr);
}
.bento__tile--times { grid-column: span 2; grid-row: auto; }
.bento__tile--venue { grid-column: span 2; }
}
@media (max-width: 560px) {
.bento {
grid-template-columns: 1fr;
}
.bento__tile--times,
.bento__tile--venue,
.bento__tile--accent,
.bento__tile--route {
grid-column: span 1;
}
}
/* === turnen-dash (Turn-Disziplin-Dashboard im Bento-Look wie Mannschaftsseiten) === */
.turnen-dash {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-m);
}
/* Eine Gruppe: Trainingszeiten (2/3) + Verantwortlich (1/3), Ort volle Breite darunter. */
.turnen-dash--single {
grid-template-areas:
"train train lead"
"venue venue venue";
}
.turnen-dash--single .turnen-dash__training { grid-area: train; }
.turnen-dash--single .turnen-dash__contact { grid-area: lead; }
.turnen-dash--single .turnen-dash__venue { grid-area: venue; }
/* Mehrere Gruppen: Ort (2/3) + Kontakt rechts (1/3) Zeiten stehen je Gruppe.
Kontakt steht dadurch konsistent rechts wie bei den Einzel-Disziplinen. */
.turnen-dash:not(.turnen-dash--single) {
grid-template-areas: "venue venue lead";
}
.turnen-dash:not(.turnen-dash--single) .turnen-dash__contact { grid-area: lead; }
.turnen-dash:not(.turnen-dash--single) .turnen-dash__venue { grid-area: venue; }
/* Mit Hinweis-Kachel: rote Banner-Zeile ganz oben (volle Breite). */
.turnen-dash--notice.turnen-dash--single {
grid-template-areas:
"notice notice notice"
"train train lead"
"venue venue venue";
}
.turnen-dash--notice:not(.turnen-dash--single) {
grid-template-areas:
"notice notice notice"
"venue venue lead";
}
.turnen-dash__notice { grid-area: notice; }
/* Hinweis-Kachel: klar rot, weiße Schrift, Icon links (z. B. Wartelisten-Status). */
.turnen-dash__notice {
flex-direction: row;
align-items: flex-start;
gap: var(--space-xs);
background: var(--clr-accent);
border-color: var(--clr-accent);
color: #fff;
}
.turnen-dash__notice p {
margin: 0;
max-width: none;
font-size: var(--fs-600);
line-height: 1.5;
}
.turnen-dash__notice-icon {
flex: none;
margin-top: 0.1em;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-l);
}
/* Trainingsort: Adresse links, Route-Button rechts (wie team-bento__venue). */
.turnen-dash__venue {
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-m);
}
.turnen-dash__venue-main {
position: relative;
z-index: 1;
}
.turnen-dash__venue .bento__heading {
margin-bottom: var(--space-2xs);
}
.turnen-dash__route {
position: relative;
z-index: 1;
flex: none;
}
/* Kontakt-Kachel: schlichter weißer Mail-Link (zentriert) auf der Akzentfläche. */
.turnen-dash__mail {
display: inline-flex;
align-self: center;
align-items: center;
gap: var(--space-2xs);
margin-top: var(--space-xs);
color: #fff;
font-size: var(--fs-500);
text-decoration: underline;
text-underline-offset: 0.2em;
}
.turnen-dash__mail:hover,
.turnen-dash__mail:focus-visible {
color: rgb(255 255 255 / 0.82);
}
.turnen-dash__mail-icon {
flex: none;
}
@media (max-width: 900px) {
.turnen-dash,
.turnen-dash--single {
grid-template-columns: 1fr;
grid-template-areas:
"train"
"lead"
"venue";
}
.turnen-dash:not(.turnen-dash--single) {
grid-template-areas:
"lead"
"venue";
}
.turnen-dash--notice,
.turnen-dash--notice.turnen-dash--single {
grid-template-areas:
"notice"
"train"
"lead"
"venue";
}
.turnen-dash--notice:not(.turnen-dash--single) {
grid-template-areas:
"notice"
"lead"
"venue";
}
}
/* === group-list (Turn-Gruppen einer Disziplin) === */
.group-list__title {
margin-bottom: var(--space-l);
text-align: center;
}
/* === group-tabs (Tab-Navigation für rich Gruppen) === */
.group-tabs__bar {
display: flex;
justify-content: center;
overflow-x: auto;
scrollbar-width: none;
margin-bottom: var(--space-2xl);
gap: 0;
}
.group-tabs__bar::-webkit-scrollbar { display: none; }
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* Tabs im Panel dürfen nicht schrumpfen — sie scrollen stattdessen horizontal. */
.group-tabs__tab {
flex-shrink: 0;
}
/* Panel-Karte übernimmt das bestehende group-card--stacked-Layout */
.group-tabs__panel {
display: grid;
grid-template-columns: 1.6fr 1fr;
gap: var(--space-4xl);
align-items: start;
padding: var(--space-3xl) var(--space-3xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
/* display:grid überschreibt den UA-Stil [hidden]{display:none} — explizit korrigieren */
.group-tabs__panel[hidden] {
display: none;
}
@media (max-width: 768px) {
.group-tabs__panel {
grid-template-columns: 1fr;
gap: var(--space-xl);
padding: var(--space-l) var(--space-xl);
}
}
/* Schlichte Gruppen (z. B. Kurse) als Raster, beschreibende Gruppen gestapelt. */
.group-list--grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: var(--space-m);
}
.group-list--stacked {
display: flex;
flex-direction: column;
gap: var(--space-4xl);
}
.group-card {
padding: var(--space-xl) var(--space-2xl) var(--space-2xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
/* Gestapelt: Beschreibung links, Trainingszeiten-Panel rechts. */
.group-list--stacked .group-card {
display: grid;
grid-template-columns: 1.6fr 1fr;
gap: var(--space-4xl);
align-items: start;
padding: var(--space-3xl) var(--space-3xl);
}
@media (max-width: 768px) {
.group-list--stacked .group-card {
grid-template-columns: 1fr;
gap: var(--space-xl);
padding: var(--space-l) var(--space-xl) var(--space-xl);
}
}
/* Beschreibungsspalte: angenehme Zeilenlänge + Lesefluss. */
.group-card__body {
max-width: 64ch;
}
/* Name links, Level-Chip rechts vertikal zentriert */
.group-card__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-s);
flex-wrap: wrap;
}
.group-card__name {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-690);
line-height: var(--lh-heading);
}
.group-card__level {
flex-shrink: 0;
padding: var(--space-4xs) var(--space-2xs);
font-size: var(--fs-400);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
border: 1px solid var(--clr-glass-border-strong);
border-radius: 999px;
white-space: nowrap;
}
/* Intro = Lead-Paragraph, deutlich abgesetzt vom Level-Chip */
.group-card__intro {
margin: var(--space-m) 0 0;
font-size: var(--fs-600);
line-height: 1.65;
color: var(--clr-text);
}
/* Detail-Abschnitte: Akzent-Randstrich links als visueller Anker */
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
/* Font-Familie, Uppercase und Sperrung kommen jetzt aus der h4-Basisregel
hier bleibt nur, was diese Überschrift von der Basis unterscheidet. */
.group-card__detail-heading {
margin: var(--space-3xl) 0 0;
padding-left: var(--space-xs);
border-left: 2px solid var(--clr-accent);
font-size: var(--fs-500);
color: var(--clr-text);
}
.group-card__detail-text {
margin: var(--space-2xs) 0 0;
padding-left: var(--space-xs);
font-size: var(--fs-600);
line-height: 1.72;
color: var(--clr-text);
}
.group-card__recommendation {
margin: var(--space-2xl) 0 0;
padding: var(--space-s) var(--space-s) 0;
border-top: 1px solid var(--clr-glass-border);
font-size: var(--fs-500);
font-style: italic;
line-height: 1.6;
color: var(--clr-text-muted);
}
/* Trainingszeiten-Panel in der Karte. */
.group-card__schedule {
margin-top: var(--space-m);
}
.group-list--stacked .group-card__schedule,
.group-tabs .group-card__schedule {
margin-top: 0;
padding: var(--space-xl);
background: var(--clr-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
border-top: 2px solid var(--clr-accent);
}
.group-card__schedule-title {
display: flex;
align-items: center;
gap: var(--space-2xs);
margin: 0 0 var(--space-s);
font-size: var(--fs-650);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-tight);
}
.group-card__schedule-icon {
flex: none;
color: var(--clr-accent);
}
.group-card__trainers {
margin: var(--space-s) 0 0;
padding-top: var(--space-xs);
border-top: 1px solid var(--clr-glass-border);
font-size: var(--fs-500);
line-height: 1.5;
}
.group-card__note {
margin: var(--space-2xs) 0 0;
font-size: var(--fs-500);
}
/* Trainingszeiten-Liste (Tag/Zeit + optional Label, Notiz, Übungsleitung). */
.schedule-list {
margin: 0;
padding: 0;
list-style: none;
}
.schedule-row {
padding: var(--space-xs) 0;
border-bottom: 1px solid var(--clr-glass-border);
}
.schedule-row:first-child { padding-top: 0; }
.schedule-row:last-child { padding-bottom: 0; border-bottom: 0; }
.schedule-row__label {
display: block;
margin-bottom: var(--space-3xs);
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-accent);
font-family: var(--ff-body);
}
.schedule-row__when {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-s);
}
.schedule-row__day {
font-size: var(--fs-600);
color: var(--clr-text);
}
.schedule-row__time {
font-size: var(--fs-600);
color: var(--clr-text);
}
.schedule-row__note {
display: block;
margin-top: var(--space-3xs);
font-size: var(--fs-500);
color: var(--clr-text-muted);
}
.schedule-row__trainers {
display: block;
margin-top: var(--space-3xs);
font-size: var(--fs-500);
line-height: 1.5;
color: var(--clr-text-muted);
}
.schedule-row__trainers-label {
color: var(--clr-text-muted);
}
.group-list__footnote {
margin: var(--space-l) 0 0;
font-size: var(--fs-500);
}
@media (max-width: 600px) {
.schedule-row__when {
flex-direction: column;
gap: var(--space-4xs);
}
.schedule-row__time {
text-align: left;
}
}
/* === cta-band === */
.cta-band__inner {
max-width: 60ch;
margin-inline: auto;
text-align: center;
}
.cta-band__text {
margin-top: var(--space-xs);
margin-inline: auto;
}
.cta-band__actions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-xs);
margin-top: var(--space-xl);
}
/* === faq (Accordion) === */
.faq__inner {
max-width: 760px;
margin-inline: auto;
}
.faq__inner > h2 {
text-align: center;
}
/* Schlichte Trennlinien-Liste statt Kästchen. */
.faq__list {
margin-top: var(--space-3xl);
border-top: 1px solid var(--clr-glass-border);
}
.faq__item {
border-bottom: 1px solid var(--clr-glass-border);
}
.faq__q {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-s);
padding: var(--space-m) var(--space-3xs);
font-size: var(--fs-600);
line-height: 1.3;
cursor: pointer;
list-style: none;
transition: color var(--transition);
}
.faq__q::-webkit-details-marker {
display: none;
}
.faq__q:hover {
color: var(--clr-text-muted);
}
.faq__chevron {
flex: none;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-s);
color: var(--clr-text-muted);
transition: transform var(--transition), color var(--transition);
}
.faq__item[open] .faq__q {
color: var(--clr-text);
}
.faq__item[open] .faq__chevron {
transform: rotate(180deg);
color: var(--clr-text);
}
.faq__a {
padding: 0 var(--space-3xs) var(--space-l);
color: var(--clr-text-muted);
}
.faq__a p {
max-width: 64ch;
margin: 0;
}
/* Antwort beim Öffnen sanft einblenden (reduced-motion via reset.css deaktiviert). */
.faq__item[open] .faq__a {
animation: faq-reveal 260ms ease;
}
@keyframes faq-reveal {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
/* === age-groups (Jugend-Altersklassen) === */
.age-groups > .container {
text-align: center;
}
.age-groups__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-xl);
margin: var(--space-3xl) 0 0;
padding: 0;
list-style: none;
text-align: left;
}
@media (max-width: 600px) {
.age-groups__grid {
grid-template-columns: 1fr;
}
}
.age-group {
display: grid;
grid-template-rows: auto 1fr;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
transition: transform var(--transition), box-shadow var(--transition);
}
.age-group:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-card);
}
.age-group__media {
position: relative;
overflow: hidden;
}
.age-group__img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 3 / 2;
object-fit: cover;
transition: transform var(--transition);
}
.age-group:hover .age-group__img {
transform: scale(1.05);
}
.age-group__body {
display: grid;
gap: var(--space-2xs);
align-content: start;
padding: var(--space-l) var(--space-l) var(--space-l);
}
.age-group__name {
font-size: var(--fs-700);
line-height: var(--lh-heading);
}
.age-group__training {
display: inline-flex;
align-items: flex-start;
gap: var(--space-2xs);
margin: 0;
font-size: var(--fs-600);
line-height: 1.45;
color: var(--clr-text-muted);
}
.age-group__icon {
flex: none;
margin-top: 0.2em;
color: var(--clr-accent);
}
/* Platzhalter-Karten (B-/A-Jugend „In Entstehung"): Bild gedämpft, Label oben links. */
.age-group--upcoming .age-group__img {
opacity: 0.5;
filter: grayscale(0.5);
}
.age-group--upcoming:hover .age-group__img {
transform: none;
}
.age-group__soon {
position: absolute;
top: 0.9rem;
left: 0.9rem;
padding: var(--space-3xs) var(--space-xs);
font-family: var(--ff-body);
font-size: var(--fs-400);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
text-transform: uppercase;
color: #fff;
background: var(--clr-accent);
border-radius: var(--radius-btn);
}
/* === team-cards (Mannschafts-Karten) === */
.team-cards > .container {
text-align: center;
}
.team-cards__intro {
max-width: 60ch;
margin: var(--space-s) auto 0;
}
/* Intro als „Klärtext" unter den Kacheln → mehr Luft nach oben zur Kartenreihe */
.team-cards__intro--below {
margin-top: var(--space-3xl);
}
.team-cards__grid {
display: grid;
/* Zwei Karten pro Reihe (50/50) — bei vier Mannschaften ergibt das ein 2×2-Raster */
grid-template-columns: repeat(2, 1fr);
gap: var(--space-l);
margin: var(--space-3xl) 0 0;
padding: 0;
list-style: none;
text-align: left;
}
@media (max-width: 600px) {
.team-cards__grid {
grid-template-columns: 1fr;
}
}
.team-card {
display: grid;
grid-template-rows: auto 1fr;
height: 100%;
color: var(--clr-text);
text-decoration: none;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
transition: transform var(--transition), box-shadow var(--transition);
}
.team-card:hover,
.team-card:focus-visible {
transform: translateY(-4px);
box-shadow: var(--shadow-card);
}
.team-card__img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 10;
object-fit: cover;
transition: transform var(--transition);
}
.team-card:hover .team-card__img,
.team-card:focus-visible .team-card__img {
transform: scale(1.04);
}
.team-card__body {
display: flex;
flex-direction: column;
gap: var(--space-3xs);
padding: var(--space-l) var(--space-l) var(--space-l);
}
.team-card__name {
/* Coolvetica/Heading (siehe CLAUDE.md) — bewusst groß und prägnant. */
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--fs-690);
line-height: var(--lh-heading);
}
.team-card__meta {
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.team-card__cta {
display: inline-flex;
align-items: center;
gap: var(--space-2xs);
/* an den unteren Rand schieben → CTA aller Karten fluchtet, egal wie lang der Name */
margin-top: auto;
padding-top: var(--space-s);
/* Body-Schrift (Abel) — Coolvetica bleibt den Überschriften vorbehalten */
font-size: var(--fs-500);
color: var(--clr-accent);
}
.team-card__arrow {
transition: transform var(--transition);
}
.team-card:hover .team-card__arrow {
transform: translateX(3px);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* === stadionzeitung-cards (Ausgaben-Archiv) === */
/* Regal statt Grid: 7-10 Ausgaben pro Saison sind zu wenig für ein Raster, das
nicht bei 1-3 Karten wie eine leere Fläche mit einer verlorenen Karte
wirkt. Dasselbe Muster wie .instagram__grid (dort nur mobil, hier immer,
weil die Kartenzahl selbst auf Desktop-Breite selten eine Zeile füllt)
angeschnittene Folgekarte als Wisch-Affordance, kein eigener JS-Code nötig
(natives Scrollen reicht, Buttons gäbe es sonst nirgends im Projekt für
dieses Muster). */
.stadionzeitung-cards__grid {
display: grid;
grid-auto-flow: column;
grid-auto-columns: min(66vw, 280px);
gap: var(--space-l);
margin: var(--space-l) 0 0;
padding: 0 0 var(--space-2xs);
list-style: none;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
}
.stadionzeitung-cards__grid::-webkit-scrollbar {
display: none;
}
.stadionzeitung-card {
display: grid;
grid-template-rows: auto 1fr;
height: 100%;
color: var(--clr-text);
text-decoration: none;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
scroll-snap-align: start;
transition: transform var(--transition), box-shadow var(--transition);
}
.stadionzeitung-card:hover,
.stadionzeitung-card:focus-visible {
transform: translateY(-4px);
box-shadow: var(--shadow-card);
}
.stadionzeitung-card__img {
display: block;
width: 100%;
height: auto;
/* Magazinseite: Hochformat statt der 16/10-Fotokachel bei .team-card. */
aspect-ratio: 3 / 4;
object-fit: cover;
object-position: top;
transition: transform var(--transition);
}
.stadionzeitung-card:hover .stadionzeitung-card__img,
.stadionzeitung-card:focus-visible .stadionzeitung-card__img {
transform: scale(1.04);
}
/* Live-gerendertes Cover als Karten-Vorschau (siehe stadionzeitung-cards.php)
statt eines Bilds dieselbe Zoom-Affordance beim Hover, aber ohne den
480px-Bildschirm-Deckel der Einzelansicht (soll die Kartenbreite ausfüllen). */
.stadionzeitung-card__media .stadionzeitung-cover {
max-width: none;
transition: transform var(--transition);
}
.stadionzeitung-card:hover .stadionzeitung-card__media .stadionzeitung-cover,
.stadionzeitung-card:focus-visible .stadionzeitung-card__media .stadionzeitung-cover {
transform: scale(1.04);
}
.stadionzeitung-card__body {
display: flex;
flex-direction: column;
gap: var(--space-3xs);
padding: var(--space-l);
}
.stadionzeitung-card__name {
/* fs-690 (wie .team-card__name) ist für kurze Teamnamen gedacht Gegner-
Bezeichnungen können lang/zusammengesetzt sein ("Gegen X & SG Y/Z"),
darum eine Stufe kleiner. --fs-650 ist die harte Untergrenze für
Coolvetica in Versalien (CLAUDE.md). */
font-size: var(--fs-650);
line-height: var(--lh-heading);
}
.stadionzeitung-card__meta {
font-size: var(--fs-500);
color: var(--clr-text-muted);
}
.stadionzeitung-card__cta {
display: inline-flex;
align-items: center;
gap: var(--space-2xs);
margin-top: auto;
padding-top: var(--space-s);
font-size: var(--fs-500);
color: var(--clr-accent);
}
.stadionzeitung-card__arrow {
transition: transform var(--transition);
}
.stadionzeitung-card:hover .stadionzeitung-card__arrow {
transform: translateX(3px);
}
/* === team-roster (Kader + Trainerstab) === */
.team-roster > .container {
text-align: center;
}
.team-roster__intro {
max-width: 60ch;
margin: var(--space-s) auto 0;
}
/* Positions-Zwischenüberschrift (Trainer & Betreuer, Torwart, Abwehr, …) */
.team-roster__group {
margin-top: var(--space-4xl);
padding-bottom: var(--space-2xs);
border-bottom: 1px solid var(--clr-glass-border);
text-align: left;
font-size: var(--fs-700);
line-height: var(--lh-heading);
}
.team-roster__grid {
display: grid;
/* Feste 5 pro Reihe → größere Cards/Bilder; runter gestuft auf schmaleren Screens */
grid-template-columns: repeat(5, 1fr);
gap: var(--space-m);
margin: var(--space-l) 0 0;
padding: 0;
list-style: none;
text-align: left;
}
@media (max-width: 992px) {
.team-roster__grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (max-width: 768px) {
.team-roster__grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 500px) {
.team-roster__grid {
grid-template-columns: repeat(2, 1fr);
}
}
.roster-card {
display: grid;
grid-template-rows: auto 1fr;
height: 100%;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
transition: transform var(--transition), box-shadow var(--transition);
}
.roster-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-card);
}
/* Trainerstab dezent mit Akzentkante abgesetzt */
.roster-card--staff {
border-color: var(--clr-accent);
}
.roster-card__media img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 4 / 5;
object-fit: cover;
object-position: center top;
}
.roster-card__body {
display: flex;
flex-direction: column;
gap: var(--space-4xs);
padding: var(--space-xs) var(--space-s) var(--space-s);
background: linear-gradient(180deg, rgb(20 20 20 / 0) 0%, rgb(20 20 20 / 0.35) 100%);
}
.roster-card__role {
font-size: var(--fs-400);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
color: var(--clr-accent);
}
/* Name in Abel (Body) — Coolvetica wäre unter 28px unzulässig (siehe CLAUDE.md) */
.roster-card__name {
font-size: var(--fs-500);
}
/* --- Variante: Name als Overlay im Foto, unten links, dunkler Verlauf von unten --- */
.roster-card--overlay {
position: relative;
display: block;
}
.roster-card--overlay .roster-card__img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 4 / 5;
object-fit: cover;
object-position: center top;
}
.roster-card__caption {
position: absolute;
inset: auto 0 0 0;
display: flex;
flex-direction: column;
gap: var(--space-4xs);
padding: var(--space-3xl) var(--space-s) var(--space-xs);
/* dunkler Fade von unten → Name bleibt auf jedem Foto lesbar */
background: linear-gradient(180deg, rgb(15 15 15 / 0) 0%, rgb(15 15 15 / 0.55) 45%, rgb(15 15 15 / 0.9) 100%);
}
/* Name hier in Coolvetica (≥28px = fs-650, Mindestgröße eingehalten) */
.roster-card--overlay .roster-card__name {
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: var(--lh-heading);
text-transform: uppercase;
color: #fff;
}
.roster-card--overlay .roster-card__role {
/* Auf dem dunklen Foto-Verlauf: klein und weiß statt rot → besser lesbar */
font-size: var(--fs-300);
color: #fff;
}
/* === faq-contact (FAQ 2/3 + Ansprechpartner 1/3) === */
.faq-contact__inner {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
gap: var(--space-4xl);
align-items: start;
}
/* Ohne Kontakt: FAQ allein, lesbar zentriert. */
.faq-contact--solo .faq-contact__inner {
grid-template-columns: minmax(0, 760px);
justify-content: center;
}
/* Sektions-Kopf zentriert über dem 2-Spalten-Inhalt (FAQ + Kontakt) */
.faq-contact__title {
text-align: center;
margin: 0;
}
/* Gedämpfte Subline unter der Überschrift (einheitlich mit den anderen Sektionen) */
.faq-contact__intro {
max-width: 60ch;
margin-inline: auto;
margin-bottom: var(--space-3xl);
text-align: center;
}
/* Abstände je nachdem, ob eine Subline folgt */
.faq-contact__title + .faq-contact__intro {
margin-top: var(--space-s);
}
.faq-contact__title + .faq-contact__inner {
margin-top: var(--space-3xl);
}
.faq-contact__aside > h2 {
margin-bottom: var(--space-l);
}
/* --- Ansprechpartner-Mini-Slider (mehrere Kontakte) ---
Ohne JS: alle Karten gestapelt sichtbar. Mit JS (--ready): nur eine sichtbar,
wechselt automatisch; Punkte zur manuellen Auswahl. */
.contact-slider {
/* Auf Kartenbreite begrenzt und zentriert → Karte und Punkte teilen dieselbe Mittelachse */
max-width: 320px;
margin-inline: auto;
}
.contact-slider__track {
display: flex;
flex-direction: column;
gap: var(--space-l);
margin: 0;
padding: 0;
list-style: none;
}
.contact-slider__dots {
/* Ohne JS funktionslos → ausgeblendet; erst mit aktivem Slider sichtbar. */
display: none;
}
.contact-slider--ready .contact-slider__dots {
display: flex;
justify-content: center;
gap: var(--space-2xs);
margin-top: var(--space-s);
}
.contact-slider__dot {
/* 24px-Ziel (WCAG 2.5.8), sichtbarer Punkt 10px */
display: grid;
place-items: center;
width: 24px;
height: 24px;
padding: 0;
background: none;
border: 0;
cursor: pointer;
}
.contact-slider__dot::before {
content: '';
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid var(--clr-glass-border-strong);
transition: background var(--transition), border-color var(--transition);
}
.contact-slider__dot[aria-current="true"]::before {
background: var(--clr-accent);
border-color: var(--clr-accent);
}
@keyframes contact-slide-fade {
from { opacity: 0; }
to { opacity: 1; }
}
.contact-slider--ready .contact-slider__slide.is-active {
animation: contact-slide-fade 0.4s ease;
}
.faq-contact__main .faq__list {
margin-top: 0;
}
.faq-contact__aside .person-card {
max-width: 320px;
margin-inline: auto;
}
/* Flacheres Foto im Kontakt-Block (Gesicht bleibt oben erhalten). */
.faq-contact__aside .person-card__media img {
aspect-ratio: 4 / 3;
}
@media (max-width: 900px) {
.faq-contact__inner {
grid-template-columns: 1fr;
gap: var(--space-3xl);
}
}
/* === team-photo (Mannschaftsfoto in voller Breite) === */
.team-photo__figure {
margin: 0;
}
.team-photo__img {
display: block;
width: 100%;
height: auto;
border-radius: var(--radius-card);
border: 1px solid var(--clr-glass-border);
}
.team-photo__caption {
margin-top: var(--space-xs);
text-align: center;
color: var(--clr-text-muted);
font-size: var(--fs-400);
}
/* === team-bento (Bild + Einleitung + Training + Spielort als Dashboard) === */
.team-bento {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-m);
grid-template-areas:
"about about about"
"train train klasse"
"venue venue venue";
}
.team-bento__about { grid-area: about; }
.team-bento__training { grid-area: train; }
.team-bento__klasse { grid-area: klasse; }
.team-bento__venue { grid-area: venue; }
.team-bento__about {
justify-content: center;
}
.team-bento__about > h2 {
margin-bottom: var(--space-xs);
}
.team-bento__about p {
color: var(--clr-text-muted);
max-width: 60ch;
}
/* Spielort: breite untere Kachel — Adresse links, Button rechts. */
.team-bento__venue {
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-m);
}
.team-bento__venue-main {
position: relative;
z-index: 1;
}
.team-bento__venue .bento__heading {
margin-bottom: var(--space-2xs);
}
.team-bento__route {
position: relative;
z-index: 1;
flex: none;
}
@media (max-width: 900px) {
.team-bento {
grid-template-columns: 1fr;
grid-template-areas:
"about"
"train"
"klasse"
"venue";
}
}
/* === intro-bento (Jugend-Einleitung: Bild + Text + Spielort + Stat) === */
.intro-bento {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-m);
grid-template-areas:
"image about about"
"image venue stat";
}
.intro-bento__image {
grid-area: image;
position: relative;
min-height: 260px;
padding: 0;
overflow: hidden;
}
.intro-bento__img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center top;
}
.intro-bento__about {
grid-area: about;
justify-content: center;
}
.intro-bento__about > h2 {
margin-bottom: var(--space-xs);
}
.intro-bento__about p {
max-width: 60ch;
color: var(--clr-text-muted);
}
.intro-bento__venue {
grid-area: venue;
}
.intro-bento__venue .bento__address {
margin-bottom: var(--space-m);
}
.intro-bento__route {
position: relative;
z-index: 1;
align-self: start;
margin-top: auto;
}
.intro-bento__stat {
grid-area: stat;
}
@media (max-width: 900px) {
.intro-bento {
grid-template-columns: 1fr;
grid-template-areas:
"image"
"about"
"venue"
"stat";
}
.intro-bento__image {
aspect-ratio: 16 / 10;
min-height: 0;
}
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* === prose (Lesespalte für langen Fließtext) ===
Eine Zeilenlänge und eine Typografie für alle Lesetexte der Seite:
Rechtstexte (.legal__body) und News-Artikel (.news-article__body) setzen die
Klasse zusätzlich, statt die gleichen Regeln zweimal zu führen.
72ch ist ein Maß, kein Spacing-Wert, und im Projekt etabliert (vgl. die 60ch
der einspaltigen split-Sektion). */
.prose {
max-width: 72ch;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose h2 {
font-size: var(--fs-700);
margin-bottom: var(--space-s);
}
/* Coolvetica nie unter --fs-650 (28px) Unterüberschriften daher in Abel,
per Laufweite/Uppercase ausgezeichnet statt in der Display-Schrift. */
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose h3 {
font-family: var(--ff-body);
font-size: var(--fs-600);
font-weight: var(--fw-bold);
text-transform: none;
line-height: var(--lh-body);
margin-top: var(--space-xl);
margin-bottom: var(--space-2xs);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose p,
.prose ul {
margin-bottom: var(--space-s);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Interne Deeplinks im Fließtext (inline_links_html()) gleiche Optik wie in
den FAQ-Antworten: unterstrichen, keine Akzentfarbe (Rot erreicht auf dem
dunklen Grund keinen ausreichenden Textkontrast). */
.prose a {
color: var(--clr-text);
text-decoration: underline;
text-underline-offset: 0.2em;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose a:hover {
color: var(--clr-text-muted);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose ul {
padding-left: var(--space-m);
max-width: 70ch;
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose li {
margin-bottom: var(--space-3xs);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.prose li::marker {
color: var(--clr-accent);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* === legal (Impressum, Datenschutz) ===
Schmale, gut lesbare Fließtext-Seite. Top-Padding klärt den absolut
positionierten Header (analog zur Hero-Logik). */
.legal {
padding-block: calc(var(--header-h) + 80px) var(--space-section);
}
.legal__head {
max-width: 60ch;
margin-bottom: clamp(var(--space-3xl), var(--space-l) + 3vw, var(--space-5xl));
}
.legal__kicker {
display: flex;
align-items: center;
gap: var(--space-xs);
margin-bottom: var(--space-m);
font-size: var(--fs-500);
text-transform: uppercase;
letter-spacing: var(--ls-wider);
}
.legal__kicker::before {
content: '';
width: 3rem;
height: 4px;
background: var(--clr-accent);
border-radius: 2px;
}
.legal__lead {
margin-top: var(--space-m);
color: var(--clr-text-muted);
}
/* Die Lesespalte selbst steht in .prose (siehe eigenen Block) .legal__body
trägt die Klasse zusätzlich. Hier bleibt nur, was den Rechtstexten eigen ist:
der große Abstand zwischen ihren Paragraphen-Sektionen. */
.legal__body > section + section {
margin-top: clamp(var(--space-3xl), var(--space-xl) + 2vw, var(--space-5xl));
}
/* Adress-/Kontaktblöcke (Verantwortlicher, Bankverbindung) als abgesetzte Karte */
.legal__card {
margin-bottom: var(--space-s);
padding: clamp(var(--space-m), var(--space-s) + 1.5vw, var(--space-xl));
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
.legal__card :last-child {
margin-bottom: 0;
}
.legal__card address {
font-style: normal;
line-height: var(--lh-body);
}
.legal__cards {
display: grid;
gap: var(--space-s);
margin-bottom: var(--space-s);
}
@media (min-width: 600px) {
.legal__cards--2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
/* === department-choice (Abteilungs-Auswahl Fußball | Turnen) === */
.department-choice > .container {
text-align: center;
}
.department-choice__intro {
max-width: 60ch;
margin: var(--space-s) auto 0;
}
.department-choice__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-l);
margin: 0;
padding: 0;
list-style: none;
text-align: left;
}
@media (max-width: 600px) {
.department-choice__grid {
grid-template-columns: 1fr;
}
}
.department-choice__card {
display: flex;
flex-direction: column;
height: 100%;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
overflow: hidden;
}
/* Bildband ist optional (Prop $item['image']) — ohne Bild bleibt die Karte reiner Text. */
.department-choice__media {
overflow: hidden;
}
.department-choice__img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
transition: transform var(--transition);
}
.department-choice__card:hover .department-choice__img,
.department-choice__card:focus-within .department-choice__img {
transform: scale(1.04);
}
.department-choice__body {
display: flex;
flex-direction: column;
flex: 1;
gap: var(--space-3xs);
padding: clamp(var(--space-xl), var(--space-m) + 2vw, var(--space-4xl));
}
.department-choice__heading {
font-size: var(--fs-700);
line-height: var(--lh-heading);
color: var(--clr-text);
}
.department-choice__subtitle {
font-size: var(--fs-500);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
color: var(--clr-accent);
}
.department-choice__text {
margin-top: var(--space-xs);
color: var(--clr-text-muted);
}
.department-choice__btn {
Design-System: Button-Varianten konsolidieren, 44px-Trefferflächen Dritter Teil. .btn hatte nur primary + outline + sm/lg, daneben lebten mehrere Controls als Eigenbau — teils zeichengleich dupliziert. Tabs: .group-tabs__tab und .filter-bar__tab waren bis auf flex-shrink und 4px Innenabstand identisch. Beide laufen jetzt über eine gemeinsame .tab-Basis, die aria-pressed (Filter) und aria-selected (Tabs) gleich behandelt; von den BEM-Klassen bleibt nur das jeweilige Delta. Innenabstand vereinheitlicht auf --space-m, die Gruppen-Tabs verlieren dadurch 4px pro Seite. Icon-Buttons: .ad-banner__nav-btn und .ad-banner__toggle waren vollständige Duplikate voneinander. Sie tragen jetzt .btn .btn--icon und behalten nur die Glas-Optik als Delta. Der Selektor schreibt .btn mit — utilities.css lädt nach components.css, bei gleicher Spezifität gewänne sonst die rote .btn-Fläche. Trefferflächen auf 44px (WCAG 2.5.5): .btn bekommt min-height und wird inline-flex, damit Icon und Label ohne Zusatz-Markup zentriert liegen. Bezeichnend auch hier — .department-choice__btn hatte inline-flex, align-items und exakt denselben gap bereits selbst deklariert und gibt sie jetzt ab. Controls, die optisch klein bleiben sollen, strecken die Fläche stattdessen unsichtbar per Pseudo-Element (.tap-target, automatisch auch für .btn--sm) — gewertet wird die Trefferfläche, nicht die gezeichnete. Der Banner-Indikator brauchte einen anderen Weg: er trug overflow: hidden, um den Fortschrittsbalken zu beschneiden, was jede Erweiterung wieder abgeschnitten hätte. Der sichtbare 6px-Balken liegt jetzt im ::before, der Fortschritt ist selbst rund — overflow entfällt, der Button ist 48x44px. Haupt-Nav-Links, Dropdown-Trigger und Footer-Social-Links bekommen min-height statt einer Pseudo-Erweiterung: sie stehen in Reihen, wo überlappende Trefferflächen den Nachbarn verdecken würden. In der 60px hohen Kopfleiste ist die Höhe ohnehin nicht sichtbar. Bewusst unverändert: die Formular-Checkbox bleibt bei 24px (WCAG 2.5.8). <input> ist ein Replaced Element, dort greift ::after nicht zuverlässig — und das zugehörige <label> ist klickbar und liefert die große Fläche. .btn--ghost ist angelegt, hat aber aktuell keinen Abnehmer: die vermuteten nackten Links sind bei näherem Hinsehen Bildkarten (.instagram__link), Wrapper (.split__cta) oder eigenständige Karten-Affordanzen (.team-card__cta), keine tertiären Buttons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:28:02 +02:00
/* display/align-items/gap kommen jetzt aus .btn */
align-self: start;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Fester Abstand statt margin-top:auto bei den Bildkarten würde "auto" den
Button an den unteren Kartenrand drücken und eine große Lücke zum Text
aufreißen (die Kartenhöhe kommt jetzt vom Bild, nicht mehr vom Textinhalt). */
margin-top: var(--space-m);
}
.department-choice__arrow {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-inline);
}
/* === fee-table (Beitragstabellen) === */
.fee-table {
padding: clamp(var(--space-m), var(--space-s) + 1.5vw, var(--space-xl));
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
.fee-table__title {
font-size: var(--fs-650);
line-height: var(--lh-heading);
margin-bottom: var(--space-s);
}
.fee-table__list {
margin: 0;
}
.fee-table__row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-s);
padding: var(--space-xs) 0;
border-bottom: 1px solid var(--clr-glass-border);
}
.fee-table__row:last-child {
border-bottom: 0;
}
.fee-table__label {
margin: 0;
}
.fee-table__price {
margin: 0;
flex: none;
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: 1;
color: var(--clr-accent);
}
.fee-table__note {
margin-top: var(--space-s);
font-size: var(--fs-400);
color: var(--clr-text-muted);
}
/* Mehrere Beitragstabellen + Austritts-Hinweis gestapelt (Turn-Übersicht). */
.fee-stack {
display: flex;
flex-direction: column;
gap: var(--space-l);
margin-top: var(--space-l);
}
/* === membership (Mitglied werden) === */
.membership-signup__inner {
max-width: 720px;
margin-inline: auto;
}
/* Zentrierter, ruhiger Sektions-Kopf (einheitlich mit instagram/partners) */
.membership-signup__head {
max-width: 60ch;
margin: 0 auto var(--space-3xl);
text-align: center;
}
.membership-signup__intro {
margin-top: var(--space-s);
color: var(--clr-text-muted);
}
/* Eine einzige Karte: Beitragsinfo + Formular zusammen, durch Hairline getrennt. */
.membership-card {
padding: clamp(var(--space-l), var(--space-s) + 2.5vw, var(--space-3xl));
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Verschachtelte Bausteine verlieren ihre eigene Karten-Optik (eine Karte, ein Rahmen).
box-shadow/backdrop-filter gehören mit rein: .form bekommt weiter unten global
--glass-shadow (Drop-Shadow + Top-Sheen-Highlight) + Blur ohne Reset bleibt das
auf dem jetzt randlosen <form> hängen und wirft einen sichtbaren Schatten/Glow
genau an der Naht zur Beitragstabelle, obwohl gar kein eigener Rahmen mehr da ist. */
.membership-card .fee-table,
.membership-card .form {
max-width: none;
margin: 0;
padding: 0;
background: none;
border: 0;
border-radius: 0;
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
box-shadow: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.membership-card .fee-table {
padding-bottom: var(--space-xl);
margin-bottom: var(--space-xl);
border-bottom: 1px solid var(--clr-glass-border);
}
/* Turnen-Hinweise: ruhige Liste, Icon links, dezente Hairline als Trenner. */
.membership-notes {
margin: 0 0 var(--space-3xl);
padding: 0;
list-style: none;
}
.membership-notes__item {
display: flex;
gap: var(--space-s);
padding: var(--space-m) 0;
border-bottom: 1px solid var(--clr-glass-border);
}
.membership-notes__item:first-child {
padding-top: 0;
}
.membership-notes__item:last-child {
padding-bottom: 0;
border-bottom: 0;
}
.membership-notes__icon {
flex: none;
margin-top: var(--space-4xs);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-l);
line-height: 1;
color: var(--clr-accent);
}
.membership-notes__title {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* --fs-650 (28px, die Coolvetica-Untergrenze aus CLAUDE.md) wirkte hier neben
dem --icon-l-Icon zu klein. --fs-675 (34px) wie sponsor-arguments__title
dasselbe Icon+Titel+Text-Listenmuster, dort bewährt. */
font-size: var(--fs-675);
line-height: var(--lh-heading);
margin-bottom: var(--space-3xs);
}
.membership-notes__body p {
color: var(--clr-text-muted);
}
/* Download-Block: alles sauber mittig, Texte in lesbarer Breite. */
.membership-download {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-xs);
text-align: center;
}
.membership-download__btn {
display: inline-flex;
align-items: center;
gap: var(--space-2xs);
}
.membership-download__icon {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-inline);
}
.membership-download__hint,
.membership-download__contact {
margin: 0;
max-width: 48ch;
font-size: var(--fs-400);
color: var(--clr-text-muted);
}
.legal__muted {
color: var(--clr-text-muted);
}
/* === facility (Gelände / Drohnen-Luftbild auf der Vereinsseite) === */
.facility > .container {
text-align: center;
}
.facility__lead {
max-width: 70ch;
margin-top: var(--space-s);
margin-inline: auto;
color: var(--clr-text-muted);
}
.facility__figure {
margin: var(--space-3xl) 0 0;
}
.facility__img {
display: block;
width: 100%;
height: auto;
border-radius: var(--radius-card);
box-shadow: var(--shadow-card);
}
.facility__caption {
margin-top: var(--space-xs);
color: var(--clr-text-faint);
font-size: var(--fs-500);
}
.facility__actions {
margin-top: var(--space-xl);
}
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
/* === matchcenter === */
/* Vereinswappen gemeinsam für Karten und Tabelle; fehlt das Bild, rendert die
Komponente einen Initialen-Kreis (.crest--initials) statt eines kaputten <img>. */
/* Weißes Chip hält auch helle/weiße Logos auf dunklem Grund sichtbar. */
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
/* Größe läuft über --crest-size: Kontexte setzen nur diese eine Variable, Breite,
Höhe und die Initialen-Schriftgröße folgen daraus. .crest--initials trägt immer
auch .crest, deshalb genügt überall der Basis-Selektor. */
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
.crest {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
--crest-size: 2.25rem;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
box-sizing: border-box;
flex: none;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
width: var(--crest-size);
height: var(--crest-size);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
padding: 3px;
object-fit: contain;
background: #fff;
border-radius: 50%;
}
.crest--initials {
display: inline-grid;
place-items: center;
padding: 0;
font-family: var(--ff-body);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
/* Initialen als Anteil des Durchmessers statt als eigene Stufe der Typo-Skala:
so bleibt der Kreis in jeder Größe gleich proportioniert, und es entstehen
keine Mini-Schriftgrößen unterhalb von --fs-300. */
font-size: calc(var(--crest-size) * 0.4);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
font-weight: var(--fw-bold);
line-height: 1;
color: var(--clr-text-muted);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: 50%;
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Aufmacher des Nächste Spiele"-Bands: strukturgleich mit .match-row (Heim über
Gast, linksbündig), nur groß ein Bauprinzip für das ganze Band. Bewusst ohne
eigene Fläche, ohne Badges und ohne Icons: die Wirkung kommt aus der Größe.
Drei Schriftrollen Meta (Abel gesperrt) · Namen (Coolvetica) · Anstoß (Abel). */
.match-feature {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: flex;
flex-direction: column;
gap: clamp(var(--space-s), var(--space-xs) + 0.6vw, var(--space-l));
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__meta {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: flex;
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
flex-wrap: wrap;
align-items: baseline;
gap: 0.5em;
font-size: var(--fs-400);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-text-muted);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__sep {
color: var(--clr-text-faint);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__fixture {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: flex;
flex-direction: column;
gap: var(--space-2xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__side {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: flex;
align-items: center;
gap: clamp(var(--space-2xs), var(--space-2xs) + 0.6vw, var(--space-s));
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
min-width: 0; /* lange Vereinsnamen dürfen umbrechen statt zu überlaufen */
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
.match-feature .crest {
--crest-size: clamp(2.25rem, 1.6rem + 2vw, 3rem);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Die Vereinsnamen sind das einzige Coolvetica-Element (wer"), alles Beschreibende
bleibt Abel (wann/was"). Coolvetica hat nur einen Schnitt die eigene Mannschaft
wird deshalb über Helligkeit markiert, nicht über fett (kein Fake-Bold). */
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* Vereinszeilen sind IMMER einzeilig (Felix, 30.07.2026): lange (SG-)Namen
werden mit Auslassungspunkten gekürzt statt hässlich umzubrechen der
volle Name steht im Matchcenter bzw. auf der verlinkten Seite. */
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__club {
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
min-width: 0;
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
font-family: var(--ff-heading);
font-size: var(--fs-700);
line-height: var(--lh-heading);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
text-transform: uppercase;
color: var(--clr-text-muted);
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__side.is-own .match-feature__club {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-text);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-feature__when {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: flex;
flex-wrap: wrap;
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
align-items: baseline;
gap: 0.5em;
font-size: var(--fs-600);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* === event-feature (Termin-Aufmacher) === */
/* Gegenstück zu .match-feature für alles, was kein Spiel ist (Vereins-Events).
Gleiches Bauprinzip und dieselben drei Schriftrollen statt des Fixtures mit
Wappen steht links das Datums-Chip (wie in der .termine-list, damit ein Termin
überall gleich aussieht). */
.event-feature {
display: flex;
flex-direction: column;
gap: clamp(var(--space-s), var(--space-xs) + 0.6vw, var(--space-l));
}
.event-feature__head {
display: flex;
align-items: center;
gap: clamp(var(--space-2xs), var(--space-2xs) + 0.6vw, var(--space-s));
min-width: 0;
}
.event-feature__chip {
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 56px;
padding: var(--space-3xs) var(--space-2xs);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-btn);
line-height: 1.15;
}
.event-feature__chip-day {
font-family: var(--ff-heading);
font-size: var(--fs-650);
}
.event-feature__chip-month {
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.event-feature__body {
display: flex;
flex-direction: column;
gap: var(--space-4xs);
min-width: 0;
}
/* Der Titel ist das einzige Coolvetica-Element (was"), alles Beschreibende
bleibt Abel (wann/wo") dieselbe Rollenverteilung wie bei .match-feature. */
.event-feature__title {
font-family: var(--ff-heading);
font-size: var(--fs-700);
line-height: var(--lh-heading);
text-transform: uppercase;
overflow-wrap: anywhere; text-wrap: balance;
}
.event-feature__where {
font-size: var(--fs-400);
color: var(--clr-text-muted);
}
.event-feature__when {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.5em;
font-size: var(--fs-600);
}
.event-feature__sep {
color: var(--clr-text-faint);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Band Nächste Spiele" abgesetzte Fläche (.section--sunken) mit roter Oberkante,
damit der Bereich nicht als Hero-Überhang gelesen wird. */
.next-matches {
border-top: 2px solid var(--clr-accent);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.next-matches__grid {
display: grid;
/* Der Aufmacher trägt mehr Gewicht als die Terminliste. */
grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
align-items: start;
gap: clamp(var(--space-m), var(--space-s) + 1.5vw, var(--space-3xl));
margin-top: clamp(var(--space-l), var(--space-m) + 1vw, var(--space-3xl));
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.next-matches__list-title {
margin-bottom: var(--space-xs);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Coolvetica wäre in dieser Größe unleserlich — Abel mit Sperrung (CLAUDE.md). */
font-family: var(--ff-body);
font-size: var(--fs-400);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
color: var(--clr-text-muted);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
@media (max-width: 992px) {
.next-matches__grid {
grid-template-columns: 1fr;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
}
/* Pro-Mannschaft-Sektion: Kopf mit Name/Liga + Link zur Mannschaftsseite. */
.matchcenter-team__head {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-s);
margin-bottom: var(--space-l);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
.matchcenter-team__league {
display: inline-flex;
align-items: center;
gap: 0.4em;
margin-top: var(--space-3xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-text-muted);
}
/* Saison-Umschalter: wiederverwendete Stripe-Tabbar (group-tabs__bar/__tab), aber
linksbündig und etwas kompakter als bei den Gruppen-Tabs. Ohne JS sind beide
Panels gestapelt sichtbar (group-tabs.js versteckt erst on init das zweite). */
.matchcenter-team__seasons-bar {
justify-content: flex-start;
margin-bottom: var(--space-m);
}
/* display-neutrales Panel (kein group-tabs__panel-Grid) das innere
matchcenter-team__grid bringt sein eigenes Layout mit. */
.matchcenter-team__season-panel[hidden] {
display: none;
}
.matchcenter-team__empty {
margin: 0;
color: var(--clr-text-muted);
}
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
/* kicker-Layout: Tabelle 2/3 links, Spiele 1/3 rechts; gestapelt auf Mobil.
align-items:start + 0-Margins der Karten beide Spalten starten oben bündig. */
.matchcenter-team__grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: clamp(var(--space-l), var(--space-s) + 2vw, var(--space-4xl));
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
align-items: start;
}
@media (max-width: 992px) {
.matchcenter-team__grid {
grid-template-columns: 1fr;
}
}
/* min-width:0 erlaubt der Tabellenspalte, schmaler als die min-width:520 der
Tabelle zu werden sonst schiebt die Tabelle die ganze Seite in den
horizontalen Scroll, statt selbst in ihrer Karte zu scrollen. */
.matchcenter-team__grid > * {
min-width: 0;
}
/* Mehrere Listen (Nächste Spiele / Letzte Ergebnisse) gleichmäßig gestapelt.
max-width hält die kompakten Zeilen gestapelt (992px) lesbar schmal, statt sie
über die volle Breite zu ziehen; im 2-spaltigen Desktop greift es nicht (die
1fr-Spalte ist ohnehin schmaler). */
.matchcenter-team__aside {
display: flex;
flex-direction: column;
gap: var(--space-s);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
max-width: 30rem;
}
/* Kompakte Spielliste (Seitenspalte) — gleiche Karten-Optik wie die Tabelle. */
.match-list {
margin: 0;
padding: 0;
list-style: none;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Im Nächste Spiele"-Band trägt die Terminliste keine Kartenfläche sonst stünde
ein gerahmter Block neben dem flächenlosen Aufmacher. Die Trennlinien der Zeilen
reichen; in den Mannschafts-Sektionen bleibt .match-list die Karte.
Zwei Klassen nötig: die Glas-Registry am Dateiende setzt .match-list den
box-shadow und würde einen Ein-Klassen-Selektor sonst überschreiben. */
.match-list.match-list--plain {
background: none;
border: 0;
border-radius: 0;
box-shadow: none;
}
.match-list--plain .match-row__link {
padding-inline: 0;
}
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
.match-row {
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
border-bottom: 1px solid var(--clr-glass-border);
}
.match-row:last-child {
border-bottom: 0;
}
/* Raster und Innenabstand liegen im Wrapper: ist die Zeile ein Link, ist damit
die komplette Zeilenfläche klickbar ohne Link sieht nichts anders aus. */
.match-row__link {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
column-gap: var(--space-xs);
padding: var(--space-xs) var(--space-s);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
color: inherit;
text-decoration: none;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
a.match-row__link:hover {
background: rgb(255 255 255 / 0.06);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-row__head {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
grid-column: 1 / -1;
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: var(--space-2xs);
margin-bottom: var(--space-2xs);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
}
.match-row__date {
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
font-size: var(--fs-300);
color: var(--clr-text-muted);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.match-row__meta {
font-size: var(--fs-300);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-caps);
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
color: var(--clr-text-faint);
}
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
.match-row__teams {
display: flex;
flex-direction: column;
gap: var(--space-3xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
min-width: 0; /* erlaubt Ellipsis in den Namen */
}
.match-row__team {
display: flex;
align-items: center;
gap: var(--space-2xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
min-width: 0;
}
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
.match-row__team .crest {
--crest-size: 1.6rem;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
.match-row__name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--fs-400);
}
.match-row__team.is-own .match-row__name {
font-weight: var(--fw-bold);
color: var(--clr-text);
}
.match-row__outcome {
align-self: center;
}
.match-row__score {
font-family: var(--ff-heading);
font-size: var(--fs-650);
line-height: 1;
white-space: nowrap;
}
.match-row__time {
font-size: var(--fs-400);
color: var(--clr-text-muted);
white-space: nowrap;
}
/* Liga-Tabelle: horizontal scrollbar (fokussierbare Region) auf schmalen Screens. */
.table-scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
/* Ruhender Rahmen um den Scroller: trägt den Wisch-Hinweis (Fade am rechten
Rand), der nicht mitscrollen darf. Nur auf Breiten sichtbar, wo die Tabelle
(min-width 520px) tatsächlich überläuft. */
.table-scroll-frame {
position: relative;
}
@media (max-width: 620px) {
.table-scroll-frame::after {
content: '';
position: absolute;
inset: 1px 1px 1px auto;
width: 32px;
border-radius: 0 var(--radius-card) var(--radius-card) 0;
background: linear-gradient(90deg, transparent, rgb(0 0 0 / 0.55));
pointer-events: none;
}
}
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
.league-table {
width: 100%;
min-width: 520px;
border-collapse: collapse;
background: var(--clr-glass-bg);
font-size: var(--fs-400);
}
.league-table th,
.league-table td {
padding: var(--space-2xs) var(--space-2xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
text-align: center;
border-bottom: 1px solid var(--clr-glass-border);
}
.league-table tbody tr:last-child th,
.league-table tbody tr:last-child td {
border-bottom: 0;
}
/* Spaltenköpfe in Abel (Coolvetica wäre hier zu klein, < 28px). */
.league-table thead th {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: var(--fs-300);
text-transform: uppercase;
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-tight);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-text-muted);
white-space: nowrap;
}
.league-table thead th abbr {
text-decoration: none;
}
.league-table__rank {
width: 2.75rem;
border-left: 3px solid transparent;
color: var(--clr-text-muted);
}
/* Vereinsspalte (Kopf + Zellen) linksbündig — höhere Spezifität als .league-table th. */
.league-table .league-table__club {
text-align: left;
}
.league-table tbody th.league-table__club {
display: flex;
align-items: center;
gap: var(--space-2xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
min-width: 0; /* erlaubt Ellipsis im Namen */
font-weight: var(--fw-regular);
}
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
.league-table tbody .crest {
--crest-size: 1.75rem;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
/* Lange Vereinsnamen sauber kürzen (voller Name im title-Attribut). */
.league-table__name {
min-width: 0;
overflow: hidden;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.league-table__pts {
font-weight: var(--fw-bold);
color: var(--clr-text);
}
/* Eigene Vereinszeile hervorheben (rote Tönung hinter weißem Text). */
.league-table tbody tr.is-own {
background: rgb(var(--clr-accent-rgb) / 0.16);
}
.league-table tbody tr.is-own th,
.league-table tbody tr.is-own td {
font-weight: var(--fw-bold);
color: var(--clr-text);
}
/* Auf-/Abstiegszonen: farbiger linker Rand am Rang. */
.league-table tbody tr.zone-promotion .league-table__rank {
border-left-color: var(--clr-success);
}
.league-table tbody tr.zone-promotion-playoff .league-table__rank {
border-left-color: color-mix(in srgb, var(--clr-success) 60%, var(--clr-text-faint));
}
.league-table tbody tr.zone-relegation-playoff .league-table__rank {
border-left-color: color-mix(in srgb, var(--clr-error) 60%, var(--clr-text-faint));
}
.league-table tbody tr.zone-relegation .league-table__rank {
border-left-color: var(--clr-error);
}
.league-table__legend {
display: flex;
flex-wrap: wrap;
gap: var(--space-2xs) var(--space-m);
margin: var(--space-xs) 0 0;
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
padding: 0;
list-style: none;
font-size: var(--fs-300);
color: var(--clr-text-muted);
}
.league-table__legend-item {
display: inline-flex;
align-items: center;
gap: 0.45em;
}
.league-table__legend-item::before {
content: "";
width: 0.85rem;
height: 0.85rem;
border-radius: 3px;
background: var(--clr-text-faint);
}
.league-table__legend-item.zone-promotion::before {
background: var(--clr-success);
}
.league-table__legend-item.zone-promotion-playoff::before {
background: color-mix(in srgb, var(--clr-success) 60%, var(--clr-text-faint));
}
.league-table__legend-item.zone-relegation-playoff::before {
background: color-mix(in srgb, var(--clr-error) 60%, var(--clr-text-faint));
}
.league-table__legend-item.zone-relegation::before {
background: var(--clr-error);
}
/* Fallback ohne Cache. */
.matchcenter-empty {
max-width: 540px;
margin-inline: auto;
padding: clamp(var(--space-l), var(--space-s) + 2vw, var(--space-3xl));
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
text-align: center;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
}
.matchcenter-empty__icon {
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
font-size: var(--icon-xl);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-accent);
}
.matchcenter-empty p {
margin-top: var(--space-xs);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
color: var(--clr-text-muted);
}
.matchcenter-empty__actions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-xs);
margin-top: var(--space-l);
Matchcenter: Spielplan, Ergebnisse & Tabellen (eigene Seite statt BFV-Widget) Neue Unterseite /matchcenter ersetzt die alten BFV-Widget-Embeds (verstoßen gegen CSP) durch eine self-hostete Lösung: Cron-Scraper holt die Daten aus der öffentlichen BFV-Widget-JSON-API, schreibt data/matchcenter.json und lädt die Vereinswappen lokal — Besucher kontaktieren nur unsere Domain. - bin/matchcenter-sync.php: CLI/Cron-Scraper (Muster wie instagram-sync), JSON-API team/{id}/matches + competition/{compoundId}/table, Wappen via getLogo lokal, atomarer Write, Fail-safe. Auto-Saison: Tabellen-compoundId wird aus der Matches-API abgeleitet (team_id ist saison-stabil). Per-Team-Cache-Fallback bei Fetch-Fehlern, damit Sektionen nie leeren. - Seite app/pages/matchcenter.php + Route + Nav-Eintrag (unter Fußball). - Komponenten: match-slider (nächste Spiele), match-card, match-row, league-table (mit Auf-/Abstiegszonen), matchcenter-section (kicker-Layout: Tabelle 2/3 + Spiele 1/3), matchcenter-empty, crest (weißes Chip + Initialen-Fallback). - carousel.js: banner.js zum generischen [data-carousel]-Antrieb verallgemeinert (Banner- und Match-Slider teilen ihn); crest.js: Logo-Fallback im Browser. - helpers.php: sportsevent_nodes() für SportsEvent-JSON-LD. - Icons calendar-event; config.example + .gitignore + CLAUDE.md ergänzt. - Responsive geprüft (kein Seiten-Overflow 360–1280, Tabelle scrollt in der Karte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0192vTfGmGpoWeyUse4TuQFj
2026-06-19 10:57:14 +02:00
}
/* === sportheim === */
/* Bento: großes Foto links (2 Spalten × 2 Zeilen),
kleines Foto + roter CTA oben rechts, Karte + Adresse unten rechts */
.sportheim-bento {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 220px;
gap: var(--space-m);
grid-template-areas:
"p1 p1 p2 cta"
"p1 p1 map adr";
}
/* --- Foto-Kacheln --- */
.sportheim-bento__photo {
position: relative;
overflow: hidden;
border-radius: var(--radius-card);
}
.sportheim-bento__photo img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 600ms ease;
}
.sportheim-bento__photo:hover img {
transform: scale(1.04);
}
.sportheim-bento__photo--main { grid-area: p1; }
.sportheim-bento__photo--sec { grid-area: p2; }
/* --- Karten-Kachel --- */
.sportheim-bento__map {
grid-area: map;
position: relative;
overflow: hidden;
border-radius: var(--radius-card);
}
.sportheim-bento__map img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* --- Adress-Kachel --- */
.sportheim-bento__addr {
grid-area: adr;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
padding: var(--space-l);
display: flex;
flex-direction: column;
justify-content: center;
font-style: normal;
}
.sportheim-bento__addr-label {
font-size: var(--fs-300);
font-weight: var(--fw-bold);
Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen. h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der --fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar. Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts. Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten- Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()- Rampen für Karten-Überschriften (bento__heading, bento__stat-value, group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich. Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und 11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser, folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest. Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em. Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von tokens.css. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
letter-spacing: var(--ls-wide);
text-transform: uppercase;
color: var(--clr-text-muted);
margin: 0 0 var(--space-xs);
}
.sportheim-bento__addr-text {
font-size: var(--fs-500);
line-height: 1.6;
margin: 0;
}
/* --- CTA-Kachel (rot, volle Höhe) --- */
.sportheim-bento__cta {
grid-area: cta;
background: var(--clr-accent);
border-radius: var(--radius-card);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: var(--space-l);
text-align: center;
padding: var(--space-2xl) var(--space-m);
}
.sportheim-bento__cta-title {
font-family: var(--ff-heading);
font-size: var(--fs-650);
text-transform: uppercase;
line-height: var(--lh-heading);
color: #fff;
margin: 0;
}
/* Tablet: 2-spaltig, Foto groß oben, darunter Kleinzeug */
@media (max-width: 900px) {
.sportheim-bento {
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: 200px;
grid-template-areas:
"p1 p1"
"p1 p1"
"p2 cta"
"map adr";
}
}
/* Mobile: alles gestapelt */
@media (max-width: 500px) {
.sportheim-bento {
grid-template-columns: 1fr;
grid-auto-rows: 220px;
grid-template-areas:
"p1"
"p2"
"map"
"cta"
"adr";
}
.sportheim-bento__addr,
.sportheim-bento__cta {
grid-row: auto;
height: auto;
min-height: 140px;
}
}
2026-06-20 22:18:34 +02:00
/* ============================================================
FROSTED GLASS globaler Look für alle Glas-Oberflächen.
EINZIGE Stelle für Blur + Ruhe-Glow (DRY statt 28× wiederholt).
Neue Glas-Karte? Hier zur passenden Liste ergänzen:
Leaf = eigenständige Karte bekommt Blur + Glow
Container = umschließt selbst Glas-Karten nur Glow
(kein Blur, sonst Doppel-Frost bei verschachtelten Karten)
Bewusst ausgenommen: Form-Inputs, Wappen-Initialen, Banner-/Slider-Controls.
Glas-Bg/-Border kommen weiterhin aus den Komponenten (var(--clr-glass-*)).
============================================================ */
/* Ruhe-Glow + Top-Sheen für ALLE Glas-Flächen (Leaf + Container).
Hover-Lift bleibt pro Komponente erhalten (:hover hat höhere Spezifität). */
.instagram__fallback,
.sponsor-channels__card,
.person-card,
.position-card,
.partners__item,
.key-facts__item,
.bento__tile,
.group-card,
.group-tabs__panel,
.age-group,
.match-list,
.matchcenter-empty,
.roster-card,
.team-card,
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.stadionzeitung-card,
2026-06-20 22:18:34 +02:00
.department-choice__card,
.legal__card,
.fee-table,
.league-table,
.membership-card,
.sportheim-bento__addr,
.form {
box-shadow: var(--glass-shadow);
}
/* Echtes Frosted-Glass-Blur nur auf Leaf-Karten Container (.match-list,
.group-tabs__panel, .age-group, Tabellen) bleiben blur-frei, damit darin
liegende Glas-Karten nicht doppelt verschwimmen. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.instagram__fallback,
.sponsor-channels__card,
.person-card,
.position-card,
.partners__item,
.key-facts__item,
.bento__tile,
.group-card,
Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte; dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah. Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante: links der Aufmacher (match-feature), rechts die folgenden Termine als verlinkte match-row-Zeilen ohne Kartenfläche. Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast, linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch. match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist. Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin, weil PHP global auf UTC läuft) und match_competition_label(). match-slider.php und match-card.php entfallen — Letztere wurde ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
.matchcenter-empty,
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.hero__upcoming,
2026-06-20 22:18:34 +02:00
.roster-card,
.team-card,
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
.stadionzeitung-card,
2026-06-20 22:18:34 +02:00
.department-choice__card,
.legal__card,
.membership-card,
.sportheim-bento__addr,
.form {
-webkit-backdrop-filter: var(--glass-blur);
backdrop-filter: var(--glass-blur);
}
}
Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
/* === stadionzeitung-issue-head (schmaler Kopf statt hero, Ausgaben-Seite) === */
/* --header-space, nicht --header-h: die Leiste nimmt 92px weg, nicht 60px
(siehe tokens.css). Werte so gewählt, dass sich am Desktop nichts verschiebt. */
.stadionzeitung-issue-head {
/* Deutlich schlanker als ein voller Hero (dessen +80px/+64px), da der
Viewer darunter den Platz braucht. */
padding-block: calc(var(--header-space) + var(--space-s)) var(--space-l);
}
/* Die Druckfassung darf großzügiger sein: sie scrollt als Blatt-Vorschau und
braucht die Bildschirmhöhe nicht wie der Swipe-Viewer. */
.stadionzeitung-issue-head--druck {
padding-block: calc(var(--header-space) + var(--space-2xl)) var(--space-xl);
}
/* Drei feste Zonen und zwei Reihen: Rückweg links, Titel mittig über den Seiten
(wie der Viewer darunter), Datum bzw. Drucken-Knopf rechts darunter über die
volle Breite die Statuszeile. */
.stadionzeitung-issue-head__inner {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: baseline;
gap: var(--space-2xs) var(--space-l);
}
.stadionzeitung-issue-head__back {
display: inline-flex;
align-items: center;
gap: var(--space-3xs);
justify-self: start;
color: var(--clr-text-muted);
font-size: var(--fs-500);
text-decoration: none;
}
.stadionzeitung-issue-head__back:hover {
color: var(--clr-text);
}
/* Größer als --fs-650, weil Coolvetica condensed ist: 28px Versalien wirken hier
neben der Navigation kleiner als sie sind und der Titel verlor gegen die
Badges, die früher daneben standen. */
.stadionzeitung-issue-head__title {
grid-column: 2;
grid-row: 1;
justify-self: center;
text-align: center;
font-size: var(--fs-675);
font-family: var(--ff-heading);
text-transform: uppercase;
}
/* Badges neben dem Titel: Druckfassung" (neutral) kennzeichnet die
?druck=1-Ansicht, Entwurf" (rot umrandet) unveröffentlichte Ausgaben
ein Entwurf darf nie mit einer fertigen Ausgabe verwechselt werden. Abel
statt Coolvetica: unter --fs-650 (siehe CLAUDE.md). */
.stadionzeitung-issue-head__badge {
display: inline-block;
padding: var(--space-4xs) var(--space-xs);
font-family: var(--ff-body);
font-size: var(--fs-300);
letter-spacing: var(--ls-caps);
vertical-align: middle;
color: var(--clr-text-muted);
border: 1px solid var(--clr-glass-border-strong);
border-radius: var(--radius-btn);
}
.stadionzeitung-issue-head__badge--entwurf {
color: var(--clr-text);
border-color: rgb(var(--clr-accent-rgb) / 0.6);
}
/* Rechte Zone der Druckfassung: nur die eine Aktion. Bewusst KEIN Aufklapp-Menü
es gibt genau einen Knopf, ein Menü würde die Hauptaktion hinter einen Klick
legen und bräuchte Zustand, den die Seite sonst nirgends hat. */
.stadionzeitung-issue-head__actions {
grid-column: 3;
grid-row: 1;
justify-self: end;
font-family: var(--ff-body);
text-transform: none;
}
/* Statuszeile unter dem Titel, über die volle Breite zentriert: Zustand und
Bilanz sind Information, keine Überschrift deshalb hier und nicht mehr als
Badges neben dem Titel. */
.stadionzeitung-issue-head__state {
grid-column: 1 / -1;
grid-row: 2;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: var(--space-2xs);
font-family: var(--ff-body);
font-size: var(--fs-400);
letter-spacing: var(--ls-caps);
text-transform: uppercase;
color: var(--clr-text-muted);
}
.stadionzeitung-issue-head__date {
grid-column: 3;
justify-self: end;
font-family: var(--ff-body);
font-size: var(--fs-500);
text-transform: none;
color: var(--clr-text-muted);
}
/* Drei Zonen nebeneinander brauchen Platz darunter gestapelt: Archiv oben
links, Titel + Datum darunter mittig. */
@media (max-width: 768px) {
.stadionzeitung-issue-head__inner {
grid-template-columns: 1fr;
justify-items: center;
text-align: center;
}
.stadionzeitung-issue-head__back {
justify-self: start;
}
.stadionzeitung-issue-head__title,
.stadionzeitung-issue-head__date,
.stadionzeitung-issue-head__actions,
.stadionzeitung-issue-head__state {
grid-column: 1;
grid-row: auto;
justify-self: center;
}
}
/* === stadionzeitung-viewer (Swipe-Ansicht einer Ausgabe) === */
/* Ohne JS: ganz normale gestapelte Liste, jede Seite ihr eigenes Bild. */
.stadionzeitung-viewer {
padding-block: var(--space-m) var(--space-4xl);
}
.stadionzeitung-viewer__track {
display: flex;
flex-direction: column;
gap: var(--space-m);
margin: 0;
padding: 0 var(--container-pad);
list-style: none;
}
.stadionzeitung-page__img {
display: block;
width: 100%;
height: auto;
/* Ein bedrucktes Blatt hat keine runden Ecken. */
box-shadow: 0 6px 24px rgb(0 0 0 / 0.35);
}
.stadionzeitung-viewer__controls {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-m);
margin-top: var(--space-l);
}
.stadionzeitung-viewer__controls[hidden] {
display: none;
}
.stadionzeitung-viewer__counter {
min-width: 9ch;
font-size: var(--fs-500);
color: var(--clr-text-muted);
text-align: center;
}
/* Glas-Optik wie .ad-banner__nav-btn dieselbe Steuerungs-Sprache überall.
Der Vollbild-Knopf gehört dazu: als roter Primär-Knopf in einer Reihe aus
zwei Glas-Knöpfen zöge er die Aufmerksamkeit von der Seite weg. */
.btn.stadionzeitung-viewer__nav-btn,
.btn.stadionzeitung-viewer__full-btn {
font-size: var(--icon-s);
color: var(--clr-text);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
transition: background var(--transition);
}
.btn.stadionzeitung-viewer__nav-btn:hover,
.btn.stadionzeitung-viewer__full-btn:hover {
background: rgb(255 255 255 / 0.2);
}
/* Im Vollbild ist der Knopf gedrückt — das darf man auch sehen. */
.btn.stadionzeitung-viewer__full-btn[aria-pressed="true"] {
background: var(--clr-accent);
border-color: var(--clr-accent);
}
/* Mit JS: Track wird zum horizontalen Scroll-Snap-Swiper. Kein eigener
Touch-Code native Scroll-Snap-Mechanik übernimmt das Swipen. */
.stadionzeitung-viewer.is-enhanced .stadionzeitung-viewer__track {
flex-direction: row;
gap: 0;
overflow-x: auto;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.stadionzeitung-viewer.is-enhanced .stadionzeitung-viewer__track::-webkit-scrollbar {
display: none;
}
.stadionzeitung-viewer.is-enhanced .stadionzeitung-viewer__page {
display: flex;
flex: 0 0 100%;
/* Ohne das schrumpft ein Flex-Item nie unter die Content-Breite seiner
Kinder (Default: min-width:auto) eine breite Tabelle in der
Live-Seite hätte sonst den ganzen horizontalen Swipe-Track aufgerissen,
obwohl .table-scroll selbst schon eigenständig scrollbar ist. */
min-width: 0;
justify-content: center;
scroll-snap-align: start;
scroll-snap-stop: always;
padding-inline: var(--container-pad);
}
/* Ganze Seite im Viewport sichtbar halten (kein Vertikal-Scroll INNERHALB
des horizontalen Swipers das würde sich mit der Swipe-Geste beißen). */
.stadionzeitung-viewer.is-enhanced .stadionzeitung-page__img {
width: auto;
max-width: 100%;
max-height: 72vh;
object-fit: contain;
}
/* Live-Seite (Tabelle/Termine/News/Ergebnisse/Vorschau/Kontakt) jede
Stadionzeitungs-Seite ist ein bedrucktes A5-Blatt: HELL, unabhängig vom
dunklen Website-Theme (der Rest der Seite bleibt dunkel das ist die
Ausnahme, nicht die Regel). Die Farb-Tokens werden hier lokal
überschrieben, damit league-table/termine-list/news-feed automatisch hell
werden statt jede Komponente einzeln zu überschreiben (Token-Disziplin,
siehe CLAUDE.md). Kontextneutral (läuft im Swipe-Viewer UND in der
Druckfassung, gerendert von stadionzeitung-seite.php) alles
Viewer-Spezifische (max-width, Schatten, Swipe-Verhalten) liegt in den
.stadionzeitung-viewer-Selektoren darunter. Eigener Vertikal-Scroll
innerhalb der Seite ist unproblematisch (anders als beim Bild): die Seite
selbst nimmt nicht an der horizontalen Swipe-Geste teil, nur der Track. */
.stadionzeitung-page {
--clr-text: #171717;
--clr-text-muted: #4d4d4d;
--clr-text-faint: #6e6e6e;
--clr-glass-bg: #ffffff;
--clr-glass-border: #dddddd;
--clr-glass-border-strong: #999999;
/* Container fürs Selbst-Containment der Live-Seiten (dasselbe Prinzip wie
.stadionzeitung-cover, siehe CLAUDE.md): Innenmaße in cqi relativ zur
Seitenbreite, damit die Seite im Viewer (480px), in der Druck-
Blattvorschau (schmaler) und auf dem bedruckten Blatt (135mm)
proportional exakt gleich aussieht. Umgestellt sind bisher Vorwort +
Kopf-Muster; die übrigen Live-Seiten folgen im Feinschliff. Nebeneffekt
der inline-size-Containment: der Inhalt (z. B. eine breite Tabelle)
kann die Seitenbreite nicht mehr aufdrücken. */
container-type: inline-size;
width: 100%;
padding: var(--space-l);
background: #ffffff;
color: var(--clr-text);
}
.stadionzeitung-viewer .stadionzeitung-page {
max-width: 480px;
box-shadow: 0 6px 24px rgb(0 0 0 / 0.35);
}
/* Weiße Füllseite (nur Druckfassung): hält die Seitenzahl des Falt-Hefts auf
einem Vielfachen von 4 bewusst komplett leer, wie eine unbedruckte
Umschlag-Innenseite einer Zeitschrift. */
.stadionzeitung-page--leer {
height: 100%;
}
/* Gemeinsames Kopf-Muster der Live-Seiten (Kicker + Überschrift + Trennlinie)
dieselbe Anmutung wie die Canva-Vorlage (V O R W O R T" über der
Headline). Vorwort/Termine haben historisch eigene Kopf-Klassen mit
Foto-Hintergrund; neue Live-Seiten nutzen diese generischen. */
.stadionzeitung-page__head {
display: flex;
flex-direction: column;
gap: 0.8cqi;
margin-bottom: 4.2cqi;
text-align: left;
}
.stadionzeitung-page__kicker {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-wider);
color: var(--clr-text-muted);
}
/* Bewusst nicht in Versalien wie Vorwort/Termine: ruhiger redaktioneller
Ton statt einer schreienden Poster-Zeile. Größe einheitlich mit der
Vorwort-Überschrift (Felix, 29.07.2026: Coolvetica-Überschriften im Heft
durchgängig kräftiger). */
.stadionzeitung-page__heading {
font-size: 9.5cqi;
line-height: 1.05;
text-transform: none;
}
.stadionzeitung-page__sub {
font-size: 3.1cqi;
font-weight: var(--fw-bold);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.stadionzeitung-page__rule {
display: block;
margin-bottom: 4.2cqi;
border-top: 1px solid var(--clr-glass-border);
}
/* Gemeinsamer CTA-Fuß der Live-Seiten (Kontakt: /mitmachen, News: /news,
Termine: /termine, Vorschau: /matchcenter) im TICKET-Stil (Interview
29.07.2026): links der Textteil mit rotem Mehr online-Chip und
Coolvetica-Titel, rechts der QR als Abriss hinter einer perforierten
Linie mit Kerben oben/unten wie eine Eintrittskarte. Die Kerben sind
weiße Kreise mit roter Kontur, die der overflow des Tickets halbiert. */
.stadionzeitung-page__cta {
position: relative;
display: flex;
align-items: stretch;
margin-top: 4.2cqi;
border: 1px solid var(--clr-accent);
border-radius: var(--radius-btn);
overflow: hidden;
}
.stadionzeitung-page__cta-text {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
flex: 1;
min-width: 0;
padding: 2.2cqi 3cqi;
}
/* Rotes Label als Chip mit weißer Schrift Rot als Fläche, nie als kleine
Textfarbe auf Weiß (4,5:1 würde sonst reißen, Kontrastregel CLAUDE.md). */
.stadionzeitung-page__cta-label {
display: inline-block;
margin-bottom: 1cqi;
padding: 0.5cqi 1.6cqi;
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.3cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: #fff;
background: var(--clr-accent);
border-radius: var(--radius-btn);
}
/* Titel in der Heading-Schrift der CTA spricht dieselbe Sprache wie die
Seitenüberschriften. Proportional zur Seite (cqi), wie das ganze Blatt. */
.stadionzeitung-page__cta-title {
font-family: var(--ff-heading);
font-size: 5.8cqi;
line-height: 0.95;
text-transform: uppercase;
}
.stadionzeitung-page__cta-link {
margin-top: 0.7cqi;
font-size: 2.9cqi;
color: var(--clr-text-muted);
}
/* Der Abriss: perforierte Trennlinie + QR + „Scan mich“. */
.stadionzeitung-page__cta-abriss {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1cqi;
flex: none;
padding: 2cqi 2.8cqi;
border-left: 1px dashed var(--clr-accent);
}
/* Perforations-Kerben: halbe Kreise an Ober- und Unterkante der Trennlinie
(overflow: hidden des Tickets schneidet die äußere Hälfte ab). */
.stadionzeitung-page__cta-abriss::before,
.stadionzeitung-page__cta-abriss::after {
content: '';
position: absolute;
left: -1.6cqi;
width: 3cqi;
height: 3cqi;
background: #fff;
border: 1px solid var(--clr-accent);
border-radius: 50%;
}
.stadionzeitung-page__cta-abriss::before {
top: -1.9cqi;
}
.stadionzeitung-page__cta-abriss::after {
bottom: -1.9cqi;
}
.stadionzeitung-page__cta-qr {
width: 13cqi;
height: 13cqi;
}
.stadionzeitung-page__cta-scan {
font-size: 2.1cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
white-space: nowrap;
}
/* Der CTA-Fuß ist auf JEDER Seite an der Blattunterkante verankert: Seiten
mit wenig Inhalt (z. B. die Vorschau in einer engen Spielwoche) ließen
das Ticket sonst mitten auf der Seite schweben mit dem Anker haben alle
Verweis-Seiten denselben Rhythmus. Der Mindestabstand nach oben kommt aus
den margin-bottom der Inhalte darüber. */
.stadionzeitung-ergebnisse,
.stadionzeitung-news,
.stadionzeitung-kontakt,
.stadionzeitung-partner,
.stadionzeitung-momente,
.stadionzeitung-historie {
display: flex;
flex-direction: column;
min-height: 100%;
}
.stadionzeitung-ergebnisse .stadionzeitung-page__cta,
.stadionzeitung-news .stadionzeitung-page__cta,
.stadionzeitung-kontakt .stadionzeitung-page__cta,
.stadionzeitung-partner .stadionzeitung-page__cta,
.stadionzeitung-momente .stadionzeitung-page__cta,
.stadionzeitung-historie .stadionzeitung-page__cta {
margin-top: auto;
}
/* A5-Seitenverhältnis (148:210) wie ein echtes Blatt im Swipe-Modus, damit
Bild- und Live-Seiten dieselbe Größe/denselben Rhythmus beim Durchblättern
haben. Reicht der Inhalt nicht in die Fläche, scrollt die Seite intern.
DEFINITE Breite aus der Zielhöhe statt width:auto + max-height: das
inline-size-Containment (s. o.) lässt eine auto-Breite sonst auf das
bloße Padding kollabieren (der Inhalt zählt beim Containment per
Definition nicht mit reproduzierbar 48px schmale Seiten). min() hält
die Seite auf schmalen Viewports in der Track-Breite. */
.stadionzeitung-viewer.is-enhanced .stadionzeitung-page {
width: min(calc(72vh * 148 / 210), 100%);
max-width: none;
aspect-ratio: 148 / 210;
overflow-y: auto;
}
/* --- Vollbild-Lesemodus ---------------------------------------------------
Am Handy ist die Seite durch ihre eigene Breite begrenzt, nicht durch die
Höhe: bei 390px Bildschirm ist eine A5-Seite 553px hoch, und Kopfleiste,
Navigation, Steuerung und Fußzeile beanspruchen zusammen mehr Platz als die
Seite selbst. Der Vollbildmodus räumt genau das weg und lässt die Seite
randlos die volle Breite nehmen. Das ist keine Zauberei: die Seite wächst um
etwa ein Zehntel der eigentliche Gewinn ist die ruhige Fläche. Für dichte
Seiten (Tabellen) bleibt das Aufziehen mit zwei Fingern das Mittel der Wahl,
das der viewport-Meta-Tag bewusst erlaubt. */
body.is-sz-full {
overflow: hidden;
}
body.is-sz-full .site-header,
body.is-sz-full .site-footer,
body.is-sz-full .stadionzeitung-issue-head,
body.is-sz-full .back-to-top {
display: none;
}
/* z-index über dem Mobil-Menü (25/30) und der Lightbox (40), unter dem
Skip-Link (100) die Kopfleiste ist hier ohnehin ausgeblendet. */
.stadionzeitung-viewer.is-full {
position: fixed;
inset: 0;
z-index: 45;
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--space-2xs);
padding-block: var(--space-2xs);
background: var(--clr-bg-deep);
}
.stadionzeitung-viewer.is-full .stadionzeitung-viewer__page {
padding-inline: 0;
}
/* dvh statt vh: am Handy klappt die Adressleiste beim Scrollen ein mit vh
würde die Seitenhöhe dabei springen. */
.stadionzeitung-viewer.is-full .stadionzeitung-page,
.stadionzeitung-viewer.is-full .stadionzeitung-cover {
width: min(calc(92dvh * 148 / 210), 100%);
max-height: 92dvh;
box-shadow: none;
}
.stadionzeitung-viewer.is-full .stadionzeitung-viewer__controls {
margin-top: 0;
}
/* Beide Icons liegen im Markup, sichtbar ist immer nur eines. */
.stadionzeitung-viewer__icon--close,
.stadionzeitung-viewer.is-full .stadionzeitung-viewer__icon--open {
display: none;
}
.stadionzeitung-viewer.is-full .stadionzeitung-viewer__icon--close {
display: inline-flex;
}
@media (max-width: 768px) {
/* Die Druckfassung ist ein gefaltetes Heft aus beidseitigem A4-Druck mit
einem Handy nicht herstellbar. Der Knopf wäre eine Sackgasse, deshalb
gehört er hier weg. (0,2,0) nötig, weil utilities.css nach dieser Datei
lädt und `.btn { display: inline-flex }` sonst gewinnt. */
.btn.stadionzeitung-viewer__print {
display: none;
}
/* Der Innenabstand kostet am Handy prozentual am meisten Seitenbreite. */
.stadionzeitung-viewer.is-enhanced .stadionzeitung-viewer__page {
padding-inline: var(--space-2xs);
}
/* Der Abstand nach OBEN bleibt wie am Desktop: die Leiste braucht ihre 92px,
und darunter noch Luft, sonst klebt der Zurück-Link am Logo (genau das war
hier der Fall). Gekürzt wird nur nach unten die Höhe für die Seite kommt
aus der ausgeblendeten Datumszeile darunter. */
.stadionzeitung-issue-head {
padding-bottom: var(--space-2xs);
}
/* Das Datum steht schon auf dem Cover direkt darunter (Saison 2026/27 ·
1. August 2026") am Handy ist die Zeile im Kopf reine Doppelung und
kostet Höhe, die die Seite besser braucht. */
.stadionzeitung-issue-head__date {
display: none;
}
}
/* Cover hat die aspect-ratio schon fest (siehe .stadionzeitung-cover) im
Swipe-Modus nur dieselbe Höhen-Deckelung wie die anderen Live-Seiten. */
.stadionzeitung-viewer.is-enhanced .stadionzeitung-cover {
max-height: 72vh;
width: auto;
max-width: none;
}
.stadionzeitung-viewer__print {
display: flex;
width: fit-content;
margin: var(--space-l) auto 0;
}
/* Tabellen-Seite: gedruckte Buchseite statt Website-Karte scharfe Ecken
wie .stadionzeitung-page__img, kein .radius-card der geteilten
.table-scroll (die auf /fussball weiterhin abgerundet bleibt). */
/* Tabelle auf der A5-Seite: kein Rahmen (die Blattkante rahmt schon, und der
Kasten kostete unten Platz, bis die Legende abgeschnitten war Felix,
29.07.2026), kein Wisch-Fade (das Blatt scrollt nicht), und die
Website-Tabelle erzwingt min-width 520px hier stattdessen alles in cqi
(Selbst-Containment wie das Cover), damit Tabelle UND Legende in jeder
Darstellungsgröße vollständig in die Seite passen. */
.stadionzeitung-page .table-scroll {
border: 0;
border-radius: 0;
}
.stadionzeitung-page .table-scroll-frame::after {
content: none;
}
.stadionzeitung-page .league-table {
min-width: 0;
font-size: 2.7cqi;
}
.stadionzeitung-page .league-table thead th {
font-size: 2.3cqi;
}
.stadionzeitung-page .league-table th,
.stadionzeitung-page .league-table td {
padding: 1cqi 0.9cqi;
}
.stadionzeitung-page .league-table tbody .crest {
--crest-size: 4.5cqi;
}
.stadionzeitung-page .league-table__rank {
width: 6cqi;
}
.stadionzeitung-page .league-table__legend {
margin-top: 2.5cqi;
gap: 1.7cqi 4.2cqi;
font-size: 2.5cqi;
}
/* Swatch skaliert mit der Legenden-Schrift statt fest in rem. */
.stadionzeitung-page .league-table__legend-item::before {
width: 0.9em;
height: 0.9em;
}
/* Wappen auf dem weißen Blatt ohne Kreis-Chip: nicht jedes Vereinslogo ist
rund, der Kreis beschneidet eckige Wappen (Felix, 29.07.2026). Der weiße
Chip stammt vom dunklen Website-Grund und ist auf Papier unsichtbar bzw.
nur als Beschnitt sichtbar. Der Initialen-Fallback bleibt bewusst ein
Kreis, bekommt auf Weiß aber eine feine Kontur. */
.stadionzeitung-page img.crest {
padding: 0;
background: transparent;
border-radius: 0;
}
.stadionzeitung-page .crest--initials {
border: 1px solid var(--clr-glass-border);
}
/* === stadionzeitung-cover (automatisch generiertes Titelblatt, Phase 3) === */
/* Einzige fotografische Stadionzeitungs-Seite bewusst NICHT die helle
.stadionzeitung-page-Basis (die gilt für Tabelle/Termine/News,
siehe oben). Selbst-Containment: `container-type: inline-size` + alle
internen Maße in `cqi` (relativ zur eigenen Breite) statt der
Website-Schriftgrößen-Tokens das Cover sieht dadurch in jedem Kontext
(Karten-Vorschau ~280px, Swipe-Viewer bis 480px, Druck ~90mm) proportional
exakt gleich aus, unabhängig von Root-Schriftgröße/Viewport. Feste
aspect-ratio unconditional (nicht erst im is_enhanced-Zustand wie bei den
Live-Seiten): das Layout braucht immer eine definierte Fläche, auch ohne JS.
Ausnahme von der cqi-Regel: `letter-spacing` bleibt über die `--ls-*`-Token
(dimensionslose `em`-Vielfache, skalieren ohnehin mit der eigenen
Schriftgröße kein Konflikt mit dem Selbst-Containment). */
.stadionzeitung-cover {
position: relative;
overflow: hidden;
width: 100%;
max-width: 480px;
aspect-ratio: 148 / 210;
container-type: inline-size;
color: #fff;
/* Fallback-Fläche, falls kein Hero-Bild geladen werden kann sonst deckt
.stadionzeitung-cover__bg das komplett ab. */
background: var(--clr-bg-deep);
box-shadow: 0 6px 24px rgb(0 0 0 / 0.35);
}
/* Passepartout-Rahmen dünne Linie mit Luft zur Kante, kein volles
Randlos-Foto, gibt der Seite den "gedruckte Titelseite"-Charakter. Auf z2
wie .inner, damit sie nicht vom Spielerfoto verdeckt wird. */
.stadionzeitung-cover::before {
content: '';
position: absolute;
z-index: 2;
inset: 2.5cqi;
border: 1px solid rgb(255 255 255 / 0.4);
pointer-events: none;
}
/* Vereins-Hero-Bild als Hintergrund (dieselbe Quelle wie die Startseite). */
.stadionzeitung-cover__bg {
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
/* Rechter Bildausschnitt des Vereinsfotos (Sportheim/Flutlicht) statt
Mitte dort sitzt das interessantere Motiv (Felix, 29.07.2026). */
object-position: right;
}
/* Abdunklung für Lesbarkeit unter dem Spielerfoto (das bleibt unverdunkelt,
knackig scharf), aber über dem Hintergrundbild. */
.stadionzeitung-cover::after {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(180deg, rgb(0 0 0 / 0.68) 0%, rgb(0 0 0 / 0.15) 38%, rgb(0 0 0 / 0.75) 100%);
}
/* Freigestelltes Spielerfoto ist der Star: sehr großformatig, rechts
randabfallend (bleed"), reicht fast über die volle Höhe bis auf Ebene des
Masthead-Titels. Ohne Foto bleibt Hintergrundbild + Verlauf die Seite. Die
Schlagzeile (.stadionzeitung-cover__corner) sitzt dafür bewusst unten links
statt zentriert über die volle Breite beide Elemente teilen sich die
Fläche wie ein echtes zweispaltiges Cover-Layout, statt sich zu überlappen. */
.stadionzeitung-cover__player {
position: absolute;
z-index: 1;
right: -8cqi;
bottom: 0;
height: 98cqi;
width: auto;
}
.stadionzeitung-cover__inner {
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
height: 100%;
padding: 5cqi 6cqi;
}
.stadionzeitung-cover__masthead {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.2cqi;
text-align: center;
}
/* Kicker-Zeile wie bei echten Magazinen: Saison + Ausgabedatum, klein,
gesperrt gibt dem Cover die "Front-Matter"-Anmutung einer Zeitschrift.
Schlicht weiß statt rot+Schatten (Schatten auf Rot wirkte unruhig/schmutzig)
der verstärkte obere Verlauf (siehe ::after) trägt den Kontrast allein. */
.stadionzeitung-cover__kicker {
font-family: var(--ff-body);
font-size: 2.7cqi;
font-weight: var(--fw-bold);
text-transform: uppercase;
letter-spacing: var(--ls-wider);
color: rgb(255 255 255 / 0.92);
}
/* Logo neben dem Titel, auf gleicher Höhe wie ein Zeitschriften-Wortmarken-
Lockup, nicht gestapelt. */
.stadionzeitung-cover__masthead-row {
display: flex;
align-items: center;
gap: 2.5cqi;
}
.stadionzeitung-cover__logo {
height: 15cqi;
width: auto;
}
/* Riesiger Zeitschriften-Masthead statt kleinem Website-Label trägt die
Seite, nie kleiner als eine echte Magazin-Wortmarke. */
.stadionzeitung-cover__wordmark {
font-family: var(--ff-heading);
font-size: 21.5cqi;
line-height: 0.82;
text-transform: uppercase;
text-shadow: 0 2px 10px rgb(0 0 0 / 0.5);
}
/* Dezente Tagline unterm Masthead bewusst kursiv/gemischte Groß-Kleinschreibung
als Kontrast zur Versal-Wortmarke, wie ein Zeitschriften-Untertitel. */
.stadionzeitung-cover__tagline {
font-family: var(--ff-body);
font-style: italic;
font-size: 3.2cqi;
letter-spacing: var(--ls-tight);
color: rgb(255 255 255 / 0.8);
}
/* Unten links gestapelt: Begegnung (Headline) über Slogan/QR (Footer) sitzt
im dunkel abgedunkelten unteren Bildbereich, freie Typografie direkt auf
dem Hintergrund, kein Kasten/keine Karte. Kontrast kommt aus dem
Abdunklungs-Verlauf (::after), nicht aus text-shadow: Chrome rendert
text-shadow auf mehrzeiligem, umbrechendem Text (lange Gegner-Namen) beim
Druck-Export nachweislich als soliden Kasten statt eines weichen Schattens
(in einer echten Druckvorschau geprüft, reproduzierbar). margin-top: auto
schiebt die ganze Gruppe an den unteren Rand, unabhängig von der Höhe des
Masthead darüber. */
.stadionzeitung-cover__corner {
margin-top: auto;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 3cqi;
/* Deutlich schmaler als der optisch verfügbare Platz, mit Sicherheitsabstand
zum randabfallenden Spielerfoto rechts der darf nie angeschnitten
werden, egal wie lang der Gegner-Name ist. */
max-width: 56cqi;
}
.stadionzeitung-cover__headline {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2.5cqi;
text-align: left;
}
/* Beide Wappen nebeneinander: Layout auf den Container, nicht aufs Wappen
siehe Kommentar beim Ergebnis-Rückblick, hier lag derselbe Fehler. Er fiel
nur nicht auf, weil `display: flex` auf einem <img> wirkungslos ist; sobald
ein Verein kein Wappen hat und die Initialen-Variante (ein <span>) greift,
hätte es deren Zentrierung zerlegt. */
.stadionzeitung-cover__crests {
--crest-size: 11cqi;
display: flex;
align-items: center;
gap: 2.5cqi;
}
/* Bewusst NICHT Coolvetica (die Riesen-Versalien vom Masthead) bei langen,
zusammengesetzten Gegner-Namen wird der enge Condensed-Schnitt in Großbuchstaben
schnell unleserlich. Abel in gemischter Groß-/Kleinschreibung liest sich als
ruhige, editoriale "Cover-Zeile" und setzt bewusst einen Kontrast zum
schreienden Masthead darüber genau dieses Zusammenspiel macht ein
Magazin-Cover aus (eine Display-Schrift, eine Lese-Schrift). */
.stadionzeitung-cover__matchup {
font-family: var(--ff-body);
font-size: 5.8cqi;
font-weight: var(--fw-bold);
line-height: 1.08;
letter-spacing: var(--ls-tight);
}
.stadionzeitung-cover__meta {
font-size: 3.1cqi;
color: rgb(255 255 255 / 0.85);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
/* Rote Trennlinie zwischen Begegnung und Fußzeile klassisches
Magazin-Gestaltungsmittel, markiert den Wechsel von Schlagzeile zu
Fußzeilen-Information deutlicher als ein bloßer Abstand. */
.stadionzeitung-cover__footer {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 1.5cqi;
text-align: left;
}
/* Zweite Coverzeile (Teaser auf die Interview-Seite im Heft): Lese-Serif
kursiv wie ein Magazin-Anreißer, davor ein roter Balken Rot als Fläche,
nie als Textfarbe auf dem dunklen Foto (Kontrastregel, CLAUDE.md). Die
Breite bleibt in der linken Spalte, damit die Zeile dem randabfallenden
Spielerfoto nicht in die Quere kommt. */
.stadionzeitung-cover__teaser {
max-width: 54cqi;
padding-left: 1.8cqi;
border-left: 0.9cqi solid var(--clr-accent);
font-family: var(--ff-serif);
font-style: italic;
font-size: 3.4cqi;
line-height: 1.35;
color: rgb(255 255 255 / 0.92);
}
.stadionzeitung-cover__teaser-label {
display: block;
font-family: var(--ff-body);
font-style: normal;
font-weight: var(--fw-bold);
font-size: 2.5cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: #fff;
}
/* QR bewusst minimal: kleiner Code + eine Zeile, keine Plakette (Felix,
29.07.2026). Der weiße Grund unterm Code bleibt ohne ihn ist ein QR
auf Foto nicht zuverlässig scanbar. */
.stadionzeitung-cover__digital {
display: flex;
align-items: center;
gap: 1.6cqi;
}
.stadionzeitung-cover__qr {
width: 11cqi;
height: 11cqi;
flex: none;
border-radius: 2px;
background: #fff;
padding: 0.9cqi;
}
.stadionzeitung-cover__link {
font-size: 2.7cqi;
color: rgb(255 255 255 / 0.8);
}
/* QR-Plakette statt frei stehendem Code wirkt wie ein gedrucktes
Info-Kärtchen (Rahmen + rote Akzent-Kante), nicht wie ein Website-Widget. */
/* === stadionzeitung-vorwort (Live-Seite, Phase 3) === */
/* Schlichte weiße Content-Seite wie Tabelle/Termine/News (läuft in
.stadionzeitung-page, deren lokale Token-Overrides siehe
dort automatisch greifen), normale Website-Token-Skala statt cqi (anders
als das Cover: das Vorwort taucht nie in einer Karten-Vorschau auf).
Etwas mehr Luft als die Geschwister-Seiten: negativer Margin hebt das
geerbte Padding von .stadionzeitung-page auf, das eigene
Padding ist großzügiger passend zu einem redaktionellen Brief statt
einer dichten Datenliste wie Tabelle/Termine. */
/* Eigene aspect-ratio statt sich auf die Höhe von .live-page zu verlassen
dasselbe Prinzip wie .stadionzeitung-cover: liefert in jedem Modus
(Swipe/Enhanced, No-JS-Stapel, Druck) zuverlässig eine definierte Fläche,
damit das unten einblendende Hintergrundbild (siehe .stadionzeitung-vorwort__bg)
immer eine Fläche zum Einblenden hat. `.live-page` selbst setzt ihre
aspect-ratio nämlich nur über `max-height` + `aspect-ratio` im Enhanced-Modus
kein echtes `height`, worauf sich ein Prozent- oder inset:0-Kind nicht
verlassen kann. Etwas mehr Luft als die Geschwister-Seiten: negativer
Margin hebt das geerbte Padding von .stadionzeitung-page auf,
das eigene Padding ist großzügiger. */
.stadionzeitung-vorwort {
position: relative;
/* z-index: 0 erzwingt einen eigenen Stacking-Context sonst bricht der
z-index: -1 des Hintergrundbilds (siehe unten) aus dieser Box aus und
landet hinter der weißen Fläche von .stadionzeitung-page,
statt nur hinter dem eigenen Fließtext (reproduzierbar leer geblieben,
bis dieser eine Wert fehlte position: relative allein reicht dafür
nicht, das erzeugt noch keinen Stacking-Context). */
z-index: 0;
aspect-ratio: 148 / 210;
overflow-y: auto;
margin: calc(var(--space-l) * -1);
/* cqi statt Space-Token: Selbst-Containment wie das Cover die Seite
sieht in jedem Kontext (Viewer, Blattvorschau, Druck) proportional
gleich aus. Design-Referenz 480px Seitenbreite, 1cqi = 4,8px. */
padding: 6.7cqi 6.7cqi 5cqi;
text-align: left;
}
/* Vereins-Hero-Bild (dieselbe Quelle wie Startseite/Cover) blendet unten ein
dasselbe Ausklingen wie bei .hero__media, hier aber am unteren Seitenrand:
der Fließtext braucht oben die volle Fläche, im leeren Rest darunter darf
ein Foto durchscheinen, wie im ursprünglichen Canva-Vorwort. z-index: -1
hält es hinter dem normal fließenden Text (unpositionierte Inhalte malen
sich sonst grundsätzlich VOR positionierten Geschwistern mit z-index 0). */
.stadionzeitung-vorwort__bg {
position: absolute;
z-index: -1;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
/* Weißer Verlauf ÜBER dem Foto statt mask-image auf dem Foto selbst Chrome
respektiert mask-image beim PDF-Export nachweislich nicht (das Foto
erschien dort voll deckend statt ausgeblendet, reproduzierbar geprüft).
Ein simpler Gradient-Layer ist dieselbe Technik wie die Abdunklung beim
Cover (::after) und druckt zuverlässig dadurch kann das Foto jetzt auch
im PDF mit ausgeblendet erscheinen, nicht nur auf dem Bildschirm. */
.stadionzeitung-vorwort__bg-fade {
position: absolute;
z-index: -1;
inset: 0;
background: linear-gradient(180deg, #fff 0%, #fff 72%, rgb(255 255 255 / 0) 100%);
}
.stadionzeitung-vorwort__head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 5cqi;
}
.stadionzeitung-vorwort__kicker {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-wider);
color: var(--clr-text-muted);
}
.stadionzeitung-vorwort__logo {
height: 12.5cqi;
width: auto;
}
/* Bewusst NICHT in Versalien (anders als der globale h1h6-Standard aus
base.css) ein Begrüßungssatz in Großbuchstaben liest sich geschrien,
eine echte Zeitschriften-Headline schreit nicht. */
.stadionzeitung-vorwort__heading {
font-size: 9.5cqi;
line-height: 1.05;
text-transform: none;
margin-bottom: 4.2cqi;
}
/* Einzige Stelle im Projekt mit einer dritten Schriftart (--ff-serif,
PT Serif) ein Vorwort ist ein redaktioneller Brief, keine UI-Fläche;
eine Lese-Serif passt hier besser als die Website-Grotesk --ff-body. */
.stadionzeitung-vorwort__text {
font-family: var(--ff-serif);
font-size: 3.75cqi;
line-height: var(--lh-body);
margin-bottom: 3.3cqi;
}
.stadionzeitung-vorwort__signature {
display: flex;
align-items: center;
gap: 3.3cqi;
margin-top: 4.2cqi;
padding-top: 3.3cqi;
border-top: 1px solid var(--clr-glass-border);
}
.stadionzeitung-vorwort__portrait {
flex: none;
width: 11.7cqi;
height: 11.7cqi;
object-fit: cover;
/* Wie bei den Kontakt-Porträts: Fokus oben, Köpfe nie anschneiden. */
object-position: 50% 15%;
border-radius: 50%;
}
.stadionzeitung-vorwort__signature-text {
display: flex;
flex-direction: column;
}
.stadionzeitung-vorwort__closing {
font-family: var(--ff-serif);
font-style: italic;
font-size: 3.1cqi;
color: var(--clr-text-muted);
}
/* Unterzeichner als handschriftliche Unterschrift (--ff-signature, Great
Vibes) wie in der Canva-Vorlage. Script-Schriften bauen klein, deshalb
deutlich größer als der übrige Text; KEINE Versalien und kein
letter-spacing, das zerreißt die verbundenen Buchstaben. */
.stadionzeitung-vorwort__signee {
font-family: var(--ff-signature);
font-size: 7cqi;
line-height: 1.1;
text-transform: none;
}
.stadionzeitung-vorwort__role {
font-size: 3.1cqi;
color: var(--clr-text-muted);
}
/* === stadionzeitung-termine (Live-Seite, Phase 3) === */
/* Gleiches Bauprinzip wie .stadionzeitung-vorwort (Kicker + Überschrift über
einblendendem Vereinsfoto, eigene aspect-ratio statt sich auf .live-page zu
verlassen, negativer Margin für mehr Rand) hier blendet das Foto aber
OBEN ein (der Kicker/die Überschrift sitzt direkt drauf, die Liste braucht
darunter die volle weiße Fläche), nicht unten wie beim Vorwort. */
.stadionzeitung-termine {
position: relative;
z-index: 0;
aspect-ratio: 148 / 210;
overflow-y: auto;
margin: calc(var(--space-l) * -1);
/* cqi wie Vorwort/Cover (Selbst-Containment), Referenz 480px Breite. */
padding: 6.7cqi 6.7cqi 5cqi;
text-align: left;
}
.stadionzeitung-termine__bg {
position: absolute;
z-index: -1;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
/* Verlauf UMGEKEHRT zum Vorwort: oben nur ein leichter weißer Schleier (genug
Kontrast für Kicker/Überschrift), unterhalb der Überschrift komplett weiß,
bevor die Liste beginnt. Gradient-Layer statt mask-image druckt
zuverlässig (siehe ausführliche Begründung bei .stadionzeitung-vorwort__bg-fade). */
.stadionzeitung-termine__bg-fade {
position: absolute;
z-index: -1;
inset: 0;
background: linear-gradient(180deg, rgb(255 255 255 / 0.55) 0%, #fff 42%, #fff 100%);
}
.stadionzeitung-termine__head {
display: flex;
flex-direction: column;
gap: 0.8cqi;
margin-bottom: 4.2cqi;
}
.stadionzeitung-termine__kicker {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-wider);
color: var(--clr-text-muted);
}
/* Bewusst nicht in Versalien, wie die Vorwort-Überschrift passt zum
ruhigen redaktionellen Ton statt einer schreienden Poster-Zeile. */
.stadionzeitung-termine__heading {
font-size: 9.5cqi;
line-height: 1.05;
text-transform: none;
}
.stadionzeitung-termine__rule {
display: block;
margin-bottom: 4.2cqi;
border-top: 1px solid var(--clr-glass-border);
}
.stadionzeitung-termine__list {
margin: 0;
padding: 0;
list-style: none;
}
.stadionzeitung-termine__item {
display: flex;
align-items: center;
gap: 3.3cqi;
padding-block: 3.3cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-termine__item:last-child {
border-bottom: 0;
}
/* Rundes Icon-Badge statt Datums-Chip (anders als .termine-list auf /termine)
Akzentfarbe als Tönung, wie die QR-Plakette am Cover ein wiederkehrendes
rotes Gestaltungsmittel. */
.stadionzeitung-termine__icon {
display: flex;
align-items: center;
justify-content: center;
flex: none;
width: 9.2cqi;
height: 9.2cqi;
border-radius: 50%;
background: rgb(var(--clr-accent-rgb) / 0.12);
color: var(--clr-accent);
font-size: 4.2cqi;
}
.stadionzeitung-termine__body {
display: flex;
flex-direction: column;
min-width: 0;
}
/* Titel prominenter wie News-Titel/Kontakt-Namen (Abel-Fake-Bold allein
ist zu leise, deshalb zusätzlich größer). */
.stadionzeitung-termine__title {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 4.4cqi;
line-height: 1.25;
}
.stadionzeitung-termine__meta {
font-size: 3.1cqi;
color: var(--clr-text-muted);
}
/* === termine-list (Termine/Events-Seite) === */
/* Zeilen-Liste wie .match-row statt Karten hier geht's um schnelles
Überfliegen vieler Termine, keine Bild-Vorschau nötig. */
.termine-list {
margin: var(--space-l) 0 0;
padding: 0;
list-style: none;
border-top: 1px solid var(--clr-glass-border);
}
.termine-list__item {
border-bottom: 1px solid var(--clr-glass-border);
}
.termine-list__link {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: var(--space-s);
padding: var(--space-s) var(--space-xs);
color: inherit;
text-decoration: none;
transition: background var(--transition);
}
a.termine-list__link:hover {
background: rgb(255 255 255 / 0.06);
}
/* Datums-Chip statt reinem Fließtext links Tag groß/Monat klein, wie ein
Ticket-Abschnitt. Das vollständige Datum (inkl. Zeitraum) steht zusätzlich
ausgeschrieben in der Meta-Zeile, der Chip ist rein dekorativ (aria-hidden). */
.termine-list__date-chip {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 56px;
padding: var(--space-3xs) var(--space-2xs);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-btn);
line-height: 1.15;
}
.termine-list__date-day {
font-family: var(--ff-heading);
font-size: var(--fs-650);
}
.termine-list__date-month {
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.termine-list__body {
display: flex;
flex-direction: column;
gap: var(--space-4xs);
min-width: 0;
}
.termine-list__title {
font-weight: 700;
}
.termine-list__meta {
font-size: var(--fs-400);
color: var(--clr-text-muted);
}
.termine-list__badge {
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
padding: var(--space-4xs) var(--space-xs);
border-radius: var(--radius-btn);
border: 1px solid var(--clr-glass-border);
color: var(--clr-text-muted);
white-space: nowrap;
}
.termine-list__badge--fussball {
border-color: rgb(var(--clr-accent-rgb) / 0.5);
color: var(--clr-text);
}
/* === news-list/news-row (News-Seite) === */
/* Zeilen-Liste wie .termine-list bewusst KEIN Karten-Grid: Einträge sind zu
unterschiedlich hoch (hohe Bild-Posts neben kurzen Text-Ergebnissen), ein
Grid reißt dabei Löcher, weil kurze Karten den Platz neben einer hohen
Karte nicht auffüllen können. Eine Spalte hat dieses Problem nicht. */
.news-list {
margin: var(--space-l) 0 0;
padding: 0;
list-style: none;
border-top: 1px solid var(--clr-glass-border);
}
.news-row {
border-bottom: 1px solid var(--clr-glass-border);
}
.news-row__link {
display: flex;
align-items: flex-start;
gap: var(--space-m);
padding: var(--space-s) var(--space-xs);
color: inherit;
text-decoration: none;
transition: background var(--transition);
}
a.news-row__link:hover {
background: rgb(255 255 255 / 0.06);
}
/* Ein Medien-Slot für ALLE Zeilen: 4:5-Hochformat-Kachel mit Glasfläche.
Instagram lädt ohnehin 4:5-Hochformat hoch Fotos füllen die Kachel also
unbeschnitten; Ergebnis-Zeilen zentrieren ihr Wappen auf derselben Fläche.
So haben Bild- und Wappen-Zeilen denselben visuellen Baustein statt
hartes Quadrat neben schwebendem Kreis". */
.news-row__media {
flex-shrink: 0;
width: 96px;
aspect-ratio: 4 / 5;
display: grid;
place-items: center;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-btn);
overflow: hidden;
}
.news-row__img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
/* Variable muss auf .crest selbst gesetzt werden (die Komponente definiert
--crest-size lokal, ein Wert auf dem Eltern-Container käme nie an)
gleiches Muster wie .hero__upcoming .match-feature .crest. */
.news-row__media--crest .crest {
--crest-size: 72px;
}
.news-row__body {
display: flex;
flex-direction: column;
gap: var(--space-4xs);
min-width: 0;
}
.news-row__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs);
font-size: var(--fs-300);
color: var(--clr-text-muted);
}
.news-row__badge {
text-transform: uppercase;
letter-spacing: var(--ls-caps);
padding: var(--space-4xs) var(--space-xs);
border-radius: var(--radius-btn);
border: 1px solid var(--clr-glass-border);
}
.news-row__badge--ergebnis {
border-color: rgb(var(--clr-accent-rgb) / 0.5);
color: var(--clr-text);
}
/* Aufmacher (featured: true): der neueste Eintrag als große Glas-Karte über
der Liste Meta/Badge teilen sich die news-row__-Klassen (identische
Bausteine, nur der Rahmen ist größer). Bild ab 769px links neben dem Text,
Hochformat-Posts (Instagram 4:5) werden auf 4:3 beschnitten, damit die
Karte kompakt bleibt. */
.news-feature {
margin-top: var(--space-l);
}
.news-feature__link {
display: grid;
gap: var(--space-l);
padding: var(--space-l);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
color: inherit;
text-decoration: none;
transition: background var(--transition);
}
a.news-feature__link:hover {
background: rgb(255 255 255 / 0.06);
}
@media (min-width: 769px) {
.news-feature__link--media {
grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
align-items: center;
}
}
.news-feature__img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 4 / 3;
object-fit: cover;
border-radius: var(--radius-btn);
}
.news-feature__media--crest {
display: grid;
place-items: center;
}
/* Auf .crest selbst, nicht auf dem Container (siehe news-row__media--crest) */
.news-feature__media--crest .crest {
--crest-size: 96px;
}
.news-feature__body {
display: flex;
flex-direction: column;
gap: var(--space-2xs);
min-width: 0;
}
.news-feature__title {
font-size: var(--fs-550);
font-weight: 700;
line-height: 1.25;
}
.news-feature__text {
font-size: var(--fs-500);
color: var(--clr-text-muted);
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.news-row__title {
font-weight: 700;
}
.news-row__text {
font-size: var(--fs-500);
color: var(--clr-text-muted);
/* Lange Captions/Meldungen nicht endlos wachsen lassen. */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Artikel lesen" sichtbarer Hinweis, dass die Zeile weiterführt. Ohne ihn
unterscheidet sich eine Meldung mit Detailseite für Sehende nur durch den
Hover-Hintergrund von einer ohne. Coolvetica ist hier verboten (nie unter
--fs-650), also Abel mit Versalien und Laufweite. Liegt INNERHALB des
Zeilenlinks: kein zusätzlicher Tab-Stop, kein verschachteltes <a>. */
.news-row__more,
.news-feature__more {
display: inline-flex;
align-items: center;
gap: var(--space-3xs);
margin-top: var(--space-3xs);
color: var(--clr-text-muted);
font-family: var(--ff-body);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
a.news-row__link:hover .news-row__more,
a.news-feature__link:hover .news-feature__more {
color: var(--clr-text);
}
/* === news-article (Detailseite einer Meldung) === */
/* Blog-Optik: Aufmacher über der Lesespalte, Fließtext in .prose (gemeinsame
Zeilenlänge mit den Rechtstexten). Der Kopf der Seite kommt von
.detail-head, deshalb hier kein Titel-Styling. */
.news-article__lead {
max-width: 72ch;
margin-bottom: var(--space-xl);
border-radius: var(--radius-card);
overflow: hidden;
}
.news-article__lead-img,
.news-article__img {
display: block;
width: 100%;
height: auto;
}
/* h2 im Artikel: mehr Luft nach oben als im Rechtstext, weil hier Absätze und
nicht Sektionen davor stehen. */
.news-article__heading {
margin-top: var(--space-xl);
}
.news-article__figure {
margin-block: var(--space-l);
}
.news-article__figure-link {
display: block;
border-radius: var(--radius-card);
overflow: hidden;
/* Die Bildfläche trägt hier keinen Textlink-Look aus .prose a. */
text-decoration: none;
}
.news-article__caption {
margin-top: var(--space-2xs);
color: var(--clr-text-muted);
font-size: var(--fs-400);
}
/* Zitat: Akzentbalken links wie im Stadionzeitungs-Interview, Rot nur als
Fläche, nie als Textfarbe. */
.news-article__quote {
margin-block: var(--space-l);
padding-left: var(--space-m);
border-left: 4px solid var(--clr-accent);
}
.news-article__quote blockquote p {
margin-bottom: 0;
font-size: var(--fs-600);
line-height: var(--lh-body);
}
.news-article__quote-source {
margin-top: var(--space-2xs);
color: var(--clr-text-muted);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
/* === stadionzeitung-ergebnisse (Live-Seite) === */
/* Ergebnis-Rückblick: zwei Zeilen pro Spiel (Heim über Gast, wie das
Nächste Spiele"-Band) lange Vereinsnamen passen auf der schmalen
A5-Seite nie in eine Zeile. Eigene Mannschaft über Gewicht der Body-Schrift
markiert (Abel hat echte Schnitte anders als Coolvetica erlaubt, siehe
CLAUDE.md nie über font-weight" bei Coolvetica). */
.stadionzeitung-ergebnisse__team {
margin-bottom: 4.2cqi;
}
.stadionzeitung-ergebnisse__team-name {
margin-bottom: 1.7cqi;
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.stadionzeitung-ergebnisse__match {
padding-bottom: 1.7cqi;
margin-bottom: 1.7cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-ergebnisse__match:last-child {
margin-bottom: 0;
border-bottom: 0;
}
.stadionzeitung-ergebnisse__meta {
font-size: 2.5cqi;
color: var(--clr-text-faint);
}
/* Das Zeilen-Layout gehört auf die ZEILE, nicht auf das Wappen darin (stand
hier mal als `.stadionzeitung-ergebnisse__row .crest` dann wurde das Wappen
selbst zum Grid, lag als Block-Element auf eigener Zeile, und Vereinsname und
Tore rutschten als Inline-Spans darunter zusammen). `--crest-size` bleibt
trotzdem hier: Custom Properties erben, das Wappen bleibt eine dumme
Komponente und der Kontext gibt ihm seine Größe so machen es alle anderen
Wappen-Kontexte im Projekt auch. */
.stadionzeitung-ergebnisse__row {
--crest-size: 5.8cqi;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 1.7cqi;
padding-block: 0.6cqi;
}
.stadionzeitung-ergebnisse__club {
min-width: 0;
font-size: 3.75cqi;
line-height: 1.2;
}
.stadionzeitung-ergebnisse__row--own .stadionzeitung-ergebnisse__club {
font-weight: var(--fw-bold);
}
.stadionzeitung-ergebnisse__goals {
font-family: var(--ff-heading);
font-size: 5.8cqi;
line-height: 1;
}
/* === stadionzeitung-vorschau (Live-Seite) === */
/* Nächstes Spiel je Mannschaft nach dem Spieltag Meta-Zeile + Begegnung in
zwei Wappen-Zeilen (dasselbe Zeilen-Muster wie der Ergebnis-Rückblick),
darunter Datum/Anstoß/Ort. */
.stadionzeitung-vorschau__match {
margin-bottom: 4.2cqi;
padding-bottom: 3.3cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-vorschau__match:last-child {
margin-bottom: 0;
border-bottom: 0;
}
.stadionzeitung-vorschau__meta {
margin-bottom: 1.7cqi;
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
/* Layout auf die Zeile, nicht aufs Wappen siehe Kommentar beim
Ergebnis-Rückblick, hier lag derselbe Fehler. */
.stadionzeitung-vorschau__row {
--crest-size: 5.8cqi;
display: flex;
align-items: center;
gap: 1.7cqi;
padding-block: 0.6cqi;
}
/* Vereinsnamen prominenter — dieselbe Hierarchie-Stufe wie Termine-Titel. */
.stadionzeitung-vorschau__club {
min-width: 0;
font-size: 4.4cqi;
line-height: 1.2;
}
.stadionzeitung-vorschau__row--own .stadionzeitung-vorschau__club {
font-weight: var(--fw-bold);
}
.stadionzeitung-vorschau__when {
margin-top: 0.8cqi;
font-size: 3.1cqi;
color: var(--clr-text-muted);
}
/* === stadionzeitung-kontakt (Live-Seite) === */
/* Ansprechpartner wie die KONTAKT"-Seite der Canva-Vorlage: Abteilung +
Name + Nummer links, rundes Porträt rechts. Ohne Foto ein getöntes
Icon-Badge in Akzentfarbe dieselbe Sprache wie die Termine-Seite. */
.stadionzeitung-kontakt__list {
margin: 0;
padding: 0;
list-style: none;
}
.stadionzeitung-kontakt__item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 3.3cqi;
padding-block: 3.3cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-kontakt__item:last-child {
border-bottom: 0;
}
.stadionzeitung-kontakt__department {
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
/* Name deutlich als wichtigste Zeile: Abel hat nur einen echten Schnitt, das
Fake-Bold allein bleibt zu leise deshalb zusätzlich eine Stufe größer
als der übrige Zeilentext. */
.stadionzeitung-kontakt__name {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 4.4cqi;
line-height: 1.25;
}
.stadionzeitung-kontakt__contact {
font-size: 3.1cqi;
color: var(--clr-text-muted);
}
.stadionzeitung-kontakt__portrait {
flex: none;
width: 11.7cqi;
height: 11.7cqi;
border-radius: 50%;
object-fit: cover;
/* Personenfotos sind Ganzkörper-Hochformate der Fokus liegt oben beim
Kopf, sonst schneidet der Kreis-Beschnitt die Köpfe an. */
object-position: 50% 15%;
}
.stadionzeitung-kontakt__portrait--icon {
display: flex;
align-items: center;
justify-content: center;
background: rgb(var(--clr-accent-rgb) / 0.12);
color: var(--clr-accent);
font-size: 4.2cqi;
}
/* === stadionzeitung-interview (Live-Seite) === */
/* Das Gespräch zur Cover-Teaser-Zeile Kopf-Muster wie die Geschwister-
Seiten, Fragen in Abel fett, Antworten in der Lese-Serif (PT Serif, wie
das Vorwort: redaktioneller Text, keine UI-Fläche). Inhalt ist wie das
Vorwort chat-gepflegt (interview-Feld der Ausgabe). */
.stadionzeitung-interview__head-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 3.3cqi;
}
.stadionzeitung-interview__portrait {
flex: none;
width: 14cqi;
height: 14cqi;
border-radius: 50%;
object-fit: cover;
/* Wie bei den Kontakt-Porträts: Fokus oben, Köpfe nie anschneiden. */
object-position: 50% 15%;
}
.stadionzeitung-interview__intro {
margin-bottom: 3.3cqi;
font-family: var(--ff-serif);
font-style: italic;
font-size: 3.4cqi;
line-height: var(--lh-body);
color: var(--clr-text-muted);
}
.stadionzeitung-interview__qa {
margin-bottom: 3.3cqi;
}
.stadionzeitung-interview__qa:last-child {
margin-bottom: 0;
}
.stadionzeitung-interview__frage {
margin-bottom: 0.8cqi;
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 3.4cqi;
line-height: 1.3;
}
.stadionzeitung-interview__antwort {
font-family: var(--ff-serif);
font-size: 3.4cqi;
line-height: var(--lh-body);
}
/* === stadionzeitung-news (Live-Seite) === */
/* Eigene Liste statt des geteilten news-feed von /news: feste Medienspalte
(Wappen/Foto/Icon-Badge in EINER Größe), damit alle Titel bündig stehen
auf /news variieren die Spaltenbreiten, auf der schmalen A5-Seite sprangen
die Titel dadurch sichtbar. Maße in cqi (Selbst-Containment, siehe
.stadionzeitung-page). */
.stadionzeitung-news__list {
margin: 0;
padding: 0;
list-style: none;
}
.stadionzeitung-news__item {
display: grid;
grid-template-columns: 8.5cqi 1fr;
gap: 2.5cqi;
align-items: center;
padding-block: 2.1cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-news__item:last-child {
border-bottom: 0;
}
.stadionzeitung-news__media {
display: flex;
align-items: center;
justify-content: center;
width: 8.5cqi;
height: 8.5cqi;
}
.stadionzeitung-news__media--crest .crest {
--crest-size: 8.5cqi;
}
.stadionzeitung-news__media--img {
object-fit: cover;
}
.stadionzeitung-news__media--icon {
border-radius: 50%;
background: rgb(var(--clr-accent-rgb) / 0.12);
color: var(--clr-accent);
font-size: 4.2cqi;
}
.stadionzeitung-news__meta {
font-size: 2.5cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
/* Titel deutlich als wichtigste Zeile wie die Namen der Kontakt-Seite:
Abel-Fake-Bold allein ist zu leise, deshalb zusätzlich größer. */
.stadionzeitung-news__title {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 4cqi;
line-height: 1.3;
}
.stadionzeitung-news__text {
font-size: 2.9cqi;
color: var(--clr-text-muted);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* === stadionzeitung-mitglied (Live-Seite, Poster) === */
/* Mitglieder-Werbung als Poster: riesige zentrierte Coolvetica-Typo, letztes
Wort in Vereinsrot (auf Weiß erreicht das Rot für große Schrift die
nötigen 3:1), Claim + Abteilungszeile darunter, geteilter CTA-Fuß unten.
Der Poster-Block zentriert sich in der verfügbaren Höhe der A5-Seite. */
.stadionzeitung-mitglied {
display: flex;
flex-direction: column;
height: 100%;
text-align: center;
/* Dünne Rahmenlinie wie das Passepartout des Covers macht aus der
weißen Fläche eine gestaltete Plakatseite. Abgerundet über das
Karten-Token (moderner, Wunsch Felix 29.07.2026). */
border: 1px solid var(--clr-text);
border-radius: var(--radius-card);
}
.stadionzeitung-mitglied__poster {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
gap: 4.2cqi;
padding: 6cqi 4cqi;
}
.stadionzeitung-mitglied__logo {
width: 13cqi;
height: auto;
}
.stadionzeitung-mitglied__headline {
display: flex;
flex-direction: column;
text-transform: uppercase;
line-height: 0.92;
}
.stadionzeitung-mitglied__line {
font-size: 15cqi;
}
/* Das kurze „des" kleiner — klassischer Poster-Rhythmus groß/klein/groß. */
.stadionzeitung-mitglied__line:nth-child(2) {
font-size: 9cqi;
}
.stadionzeitung-mitglied__line--accent {
color: var(--clr-accent);
}
.stadionzeitung-mitglied__claim {
max-width: 68cqi;
font-size: 3.6cqi;
line-height: var(--lh-body);
color: var(--clr-text-muted);
}
.stadionzeitung-mitglied__departments {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 3.1cqi;
text-transform: uppercase;
letter-spacing: var(--ls-wider);
}
/* Großer zentrierter QR statt des generischen CTA-Fußes der Listen-Seiten. */
.stadionzeitung-mitglied__qr-block {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.7cqi;
margin-top: 2cqi;
}
.stadionzeitung-mitglied__qr {
width: 20cqi;
height: 20cqi;
}
.stadionzeitung-mitglied__link {
font-size: 2.9cqi;
color: var(--clr-text-muted);
}
/* === stadionzeitung-historie (Live-Seite) === */
/* Teaser auf die Website-Historie + Material-Aufruf für die Chronik 2028:
Kopf-Muster wie die Geschwister-Seiten, zwei historische Fotos
nebeneinander mit Bildunterschriften, Aufruf-Absatz mit der
Historie-Mailadresse, geteilter CTA-Fuß mit QR auf /historie. */
.stadionzeitung-historie__text {
margin-bottom: 4.2cqi;
font-size: 3.4cqi;
line-height: var(--lh-body);
}
/* Polaroid-Look: weißer Fotorahmen mit dicker Unterkante (dort sitzt die
Bildunterschrift), Schlagschatten und leichte Gegen-Rotation der beiden
Fotos wie aus dem Schuhkarton auf die Seite gelegt. */
.stadionzeitung-historie__bilder {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3.5cqi;
margin-block: 2cqi 5cqi;
padding-inline: 1cqi;
}
.stadionzeitung-historie__polaroid {
margin: 0;
padding: 1.6cqi 1.6cqi 0;
background: #fff;
border: 1px solid var(--clr-glass-border);
box-shadow: 0 3px 14px rgb(0 0 0 / 0.16);
}
.stadionzeitung-historie__polaroid--links {
transform: rotate(-1.6deg);
}
.stadionzeitung-historie__polaroid--rechts {
transform: rotate(1.4deg);
}
.stadionzeitung-historie__img {
display: block;
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
/* Leicht entsättigt Richtung Archivfoto die beiden Bilder haben
unterschiedliche Alterungen, so wirken sie als Paar. */
filter: grayscale(0.25);
}
.stadionzeitung-historie__caption {
padding-block: 1.4cqi;
font-size: 2.3cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
text-align: center;
color: var(--clr-text-muted);
}
/* Aufruf als Notizzettel: gestrichelter Rahmen wie ein eingelegter Zettel
im Album hebt die Handlungsaufforderung von Teaser-Text und Ticket ab. */
.stadionzeitung-historie__aufruf {
margin-bottom: 4.2cqi;
padding: 2.5cqi 3cqi;
font-size: 3.2cqi;
line-height: var(--lh-body);
border: 1px dashed var(--clr-glass-border-strong);
border-radius: var(--radius-btn);
}
.stadionzeitung-historie__mail {
font-weight: var(--fw-bold);
white-space: nowrap;
}
/* === stadionzeitung-sportheim (Live-Seite) === */
/* Nachbau der Canva-Seite Feiern im Katzbachtal": Kicker + Headline,
Serif-Text, unten blutet das Gastraum-Foto randabfallend aus der Seite
(weißer Verlauf darüber, dieselbe drucksichere Technik wie beim Vorwort),
darauf die weiße QR-Karte. Rote Pinselstrich-Ecken als CSS-Näherung. */
.stadionzeitung-sportheim {
position: relative;
z-index: 0;
display: flex;
flex-direction: column;
aspect-ratio: 148 / 210;
overflow: hidden;
margin: calc(var(--space-l) * -1);
padding: 6.7cqi 6.7cqi 0;
}
.stadionzeitung-sportheim__text {
margin-bottom: 4.2cqi;
font-family: var(--ff-serif);
font-size: 3.75cqi;
line-height: var(--lh-body);
}
.stadionzeitung-sportheim__foto-bereich {
position: relative;
flex: 1;
min-height: 0;
margin-inline: -6.7cqi;
}
.stadionzeitung-sportheim__foto {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.stadionzeitung-sportheim__foto-fade {
position: absolute;
inset: 0;
background: linear-gradient(180deg, #fff 0%, rgb(255 255 255 / 0) 45%);
}
.stadionzeitung-sportheim__qr-karte {
position: absolute;
right: 8cqi;
bottom: 8cqi;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.2cqi;
padding: 2cqi;
background: #fff;
border-radius: var(--radius-btn);
box-shadow: 0 2px 12px rgb(0 0 0 / 0.18);
}
.stadionzeitung-sportheim__qr {
width: 20cqi;
height: 20cqi;
}
.stadionzeitung-sportheim__link {
font-size: 2.5cqi;
color: var(--clr-text-muted);
}
/* === stadionzeitung-impressum (Live-Seite) === */
/* Zentriertes Impressum mit Logo und dünner Rahmenlinie (wie das
Mitglied-Poster) ersetzt das frühere Canva-Bild, Daten aus club.json. */
.stadionzeitung-impressum {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3.3cqi;
height: 100%;
padding: 6cqi 5cqi;
text-align: center;
border: 1px solid var(--clr-text);
border-radius: var(--radius-card);
}
.stadionzeitung-impressum__logo {
width: 12cqi;
height: auto;
}
.stadionzeitung-impressum__name {
font-size: 8cqi;
line-height: 1.05;
text-transform: none;
margin-bottom: 1.7cqi;
}
.stadionzeitung-impressum__block p {
font-size: 3cqi;
line-height: 1.5;
}
.stadionzeitung-impressum__label {
margin-bottom: 0.8cqi;
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 2.7cqi;
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.stadionzeitung-impressum__note {
font-size: 2.5cqi;
color: var(--clr-text-faint);
}
/* === stadionzeitung-partner (Live-Seite) === */
/* Anzeigen-Akquise im eigenen Heft (Selbstbeweis-Seite, Sie-Form wie
/partner-werden): Intro, drei Paket-Zeilen mit Icon-Badges (dieselbe
Sprache wie die Termine-Icons), Ansprechpartner-Zeile, Ticket-CTA. */
.stadionzeitung-partner__intro {
margin-bottom: 4.2cqi;
font-size: 3.4cqi;
line-height: var(--lh-body);
}
.stadionzeitung-partner__pakete {
margin: 0 0 4.2cqi;
padding: 0;
list-style: none;
}
.stadionzeitung-partner__paket {
display: flex;
align-items: flex-start;
gap: 3.3cqi;
padding-block: 2.7cqi;
border-bottom: 1px solid var(--clr-glass-border);
}
.stadionzeitung-partner__paket:last-child {
border-bottom: 0;
}
.stadionzeitung-partner__icon {
display: flex;
align-items: center;
justify-content: center;
flex: none;
width: 9.2cqi;
height: 9.2cqi;
border-radius: 50%;
background: rgb(var(--clr-accent-rgb) / 0.12);
color: var(--clr-accent);
font-size: 4.2cqi;
}
.stadionzeitung-partner__paket-titel {
font-family: var(--ff-body);
font-weight: var(--fw-bold);
font-size: 4cqi;
line-height: 1.25;
}
.stadionzeitung-partner__paket-text {
margin-top: 0.6cqi;
font-size: 3cqi;
line-height: 1.45;
color: var(--clr-text-muted);
}
.stadionzeitung-partner__kontakt {
font-size: 3.2cqi;
color: var(--clr-text-muted);
}
.stadionzeitung-partner__kontakt strong {
color: var(--clr-text);
}
/* === stadionzeitung-momente (Live-Seite, Heft-Abschluss) === */
/* 2×2-Galerie der neuesten Instagram-Fotos + Folge-uns-Ticket quadratische
Kacheln wie im Instagram-Raster, bewusst ohne Bildunterschriften: die
Fotos sind der Abschluss des Hefts, kein Nachrichtenteil. */
/* Natives Instagram-Hochformat (4:5) statt quadratischem Beschnitt die
Posts sind oft Grafiken mit Text bis an die Kanten, ein Quadrat-Crop
schneidet Inhalt ab. Damit vier Hochformate + Ticket auf die A5-Seite
passen, läuft die Galerie als schmalerer zentrierter Block. */
.stadionzeitung-momente__galerie {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2cqi;
max-width: 73cqi;
margin: 0 auto 2.5cqi;
}
/* Verdichteter Kopf + Ticket ohne Standard-Abstand die Fläche gehört auf
dieser Seite den Fotos. */
.stadionzeitung-momente .stadionzeitung-page__head {
margin-bottom: 2.5cqi;
}
.stadionzeitung-momente .stadionzeitung-page__cta {
margin-top: 1.5cqi;
}
.stadionzeitung-momente__foto {
display: block;
width: 100%;
aspect-ratio: 4 / 5;
object-fit: cover;
}
/* === stadionzeitung-druck (Druckfassung, Broschüren-Montage) === */
/* Bildschirm-Ansicht der Route ?druck=1: jedes Blatt als A4-quer-Vorschau
(297:210) mit zwei A5-Seiten, in Broschüren-Reihenfolge (die Montage
selbst rechnet stadionzeitung-druck.php CSS kann Seiten nicht über
Blattgrenzen umsortieren). Die beiden Seiten stoßen in der Blattmitte
aneinander (dort wird gefaltet), Restbreite bleibt außen. */
.stadionzeitung-druck {
padding-block: var(--space-m) var(--space-4xl);
}
.stadionzeitung-druck__hilfe {
display: grid;
gap: var(--space-s);
justify-items: center;
max-width: 65ch;
margin: var(--space-xl) auto 0;
padding-inline: var(--container-pad);
text-align: center;
}
.stadionzeitung-druck__hilfe-title {
font-size: var(--fs-650);
}
.stadionzeitung-druck__blaetter {
display: grid;
gap: var(--space-l);
max-width: 900px;
margin: 0 auto;
padding: 0 var(--container-pad);
list-style: none;
}
.stadionzeitung-druck__blatt-label {
margin-bottom: var(--space-2xs);
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.stadionzeitung-druck__flaeche {
display: grid;
grid-template-columns: 1fr 1fr;
aspect-ratio: 297 / 210;
background: #fff;
box-shadow: 0 6px 24px rgb(0 0 0 / 0.35);
}
.stadionzeitung-druck__slot {
display: flex;
min-width: 0;
overflow: hidden;
}
.stadionzeitung-druck__slot:first-child {
justify-content: flex-end;
}
.stadionzeitung-druck__slot:last-child {
justify-content: flex-start;
}
/* Falz-Steg auf den Innenbögen (ab Blatt 2): randabfallend gestaltete
Anzeigen stießen sonst mit 0mm an die Blattmitte beim Falten
verschwindet das im Knick und wirkt, als liefe die Anzeige in die
Nachbarseite. 1% der Bogenbreite 3mm im Druck; der Umschlagbogen
(erste zwei Seiten) bleibt bewusst bündig, dort ist der Anschnitt
in die Falz Absicht. */
.stadionzeitung-druck__blatt:nth-child(n+3) .stadionzeitung-druck__slot:first-child {
padding-right: 2%;
}
.stadionzeitung-druck__blatt:nth-child(n+3) .stadionzeitung-druck__slot:last-child {
padding-left: 2%;
}
/* Jede Seite füllt die Blatthöhe in A5-Proportion Bilder bringen ihr
Seitenverhältnis selbst mit (Canva exportiert A5), Live-Seiten bekommen
es hier; Überstand wird beschnitten statt das Blatt zu sprengen. */
.stadionzeitung-druck .stadionzeitung-page {
height: 100%;
width: auto;
aspect-ratio: 148 / 210;
overflow: hidden;
}
.stadionzeitung-druck .stadionzeitung-page__img {
height: 100%;
width: auto;
box-shadow: none;
}
.stadionzeitung-druck .stadionzeitung-cover {
height: 100%;
width: auto;
max-width: none;
}
/* === detail-head (schmaler Kopf der Detailseiten: Veranstaltung, News-Artikel) === */
/* Kein Hero: die Fest-Seite hat kein eigenes Titelbild, und das Plakat im
Hochformat würde als cover-beschnittener Hintergrund zerstört; beim
News-Artikel trägt der Aufmacher im Artikelkörper das Bild (Blog-Optik).
Gleiche Grundhaltung wie bei der Stadionzeitungs-Ausgabe, die ihren Kopf aber
bewusst selbst mitbringt (Viewer-Chrome, siehe detail-head.php). */
.detail-head {
/* --header-h muss drin sein, sonst liegt der Zurück-Link hinter der festen
Kopfleiste (gleiche Rechnung wie .stadionzeitung-issue-head). */
/* --header-space, nicht --header-h: mit --header-h begann der Zurück-Link
exakt an der Unterkante des Logos, ohne einen Pixel Luft. */
padding-block: calc(var(--header-space) + var(--space-s)) var(--space-l);
border-bottom: 1px solid var(--clr-glass-border);
}
.detail-head__back {
display: inline-flex;
align-items: center;
gap: var(--space-3xs);
min-height: var(--tap-min);
color: var(--clr-text-muted);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
text-decoration: none;
}
.detail-head__back:hover {
color: var(--clr-text);
}
.detail-head__title {
margin-top: var(--space-2xs);
}
.detail-head__badge {
display: inline-block;
vertical-align: middle;
margin-left: var(--space-2xs);
padding: 0.2em 0.6em;
border-radius: var(--radius-btn);
background: var(--clr-accent);
color: var(--clr-text);
font-family: var(--ff-body);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
.detail-head__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-2xs);
margin-top: var(--space-2xs);
color: var(--clr-text-muted);
font-size: var(--fs-500);
}
.detail-head__ort {
display: inline-flex;
align-items: center;
gap: var(--space-3xs);
}
/* === veranstaltungen-cards (Übersicht: was ansteht + Rückblick) === */
/* EINE Kartenform für beide Abschnitte: Plakat links, Text rechts, volle Breite,
untereinander gestapelt. Das Hochformat des Plakats bekommt so die Höhe, die
es braucht, ohne die Karte endlos lang zu machen. */
.veranstaltungen-cards__list {
display: grid;
gap: var(--space-l);
margin-top: var(--space-l);
}
.veranstaltung-card {
display: flex;
align-items: stretch;
height: 100%;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
color: inherit;
text-decoration: none;
transition: transform var(--transition), border-color var(--transition);
}
.veranstaltung-card:hover {
transform: translateY(-4px);
border-color: var(--clr-glass-border-strong);
box-shadow: var(--shadow-card);
}
.veranstaltung-card__media {
flex: 0 0 clamp(180px, 26%, 340px);
background: var(--clr-bg-deep);
}
.veranstaltung-card__img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.veranstaltung-card__body {
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--space-2xs);
padding: var(--space-2xl);
}
.veranstaltung-card__meta {
color: var(--clr-text-muted);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
.veranstaltung-card__text {
color: var(--clr-text-muted);
}
.veranstaltung-card__cta {
display: inline-flex;
align-items: center;
gap: var(--space-3xs);
margin-top: var(--space-2xs);
color: var(--clr-accent);
font-family: var(--ff-body);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
.veranstaltung-card:hover .veranstaltung-card__arrow {
transform: translateX(3px);
}
.veranstaltung-card__arrow {
transition: transform var(--transition);
}
@media (max-width: 768px) {
/* Am Handy steht das Plakat über dem Text, sonst bliebe für keines von
beiden genug Breite. */
.veranstaltung-card {
flex-direction: column;
}
.veranstaltung-card__media {
flex: none;
}
.veranstaltung-card__body {
padding: var(--space-l);
}
}
/* === veranstaltung-programm (Tagesprogramm) === */
.veranstaltung-programm__tage {
display: grid;
gap: var(--space-3xl);
margin-top: var(--space-l);
}
.veranstaltung-programm__tag-titel {
padding-bottom: var(--space-2xs);
border-bottom: 1px solid var(--clr-glass-border);
}
.veranstaltung-programm__liste {
display: grid;
gap: var(--space-s);
margin-top: var(--space-s);
}
.veranstaltung-programm__punkt {
display: grid;
grid-template-columns: 5rem minmax(0, 1fr);
gap: var(--space-s);
align-items: baseline;
}
/* Uhrzeit bewusst WEISS, nicht in Akzentrot: Rot erreicht auf dem dunklen Grund
nur ~3,4:1 und ist damit für Text zu schwach (siehe CLAUDE.md, Design). Die
Spalte trennt die Zeit schon deutlich genug vom Titel; das Rot sitzt
stattdessen als dünne Linie an der Zeile. */
.veranstaltung-programm__zeit {
color: var(--clr-text);
padding-left: var(--space-2xs);
border-left: 2px solid var(--clr-accent);
font-family: var(--ff-body);
font-size: var(--fs-500);
font-variant-numeric: tabular-nums;
letter-spacing: var(--ls-caps);
}
.veranstaltung-programm__body {
display: block;
}
.veranstaltung-programm__titel {
display: block;
font-size: var(--fs-500);
}
.veranstaltung-programm__text {
display: block;
margin-top: var(--space-3xs);
color: var(--clr-text-muted);
font-size: var(--fs-400);
}
/* Rückblick: das Programm dokumentiert nur noch, es informiert nicht mehr. */
.veranstaltung-programm--compact .veranstaltung-programm__tage {
gap: var(--space-l);
}
.veranstaltung-programm--compact .veranstaltung-programm__titel,
.veranstaltung-programm--compact .veranstaltung-programm__zeit {
font-size: var(--fs-400);
}
@media (max-width: 600px) {
.veranstaltung-programm__punkt {
grid-template-columns: 4rem minmax(0, 1fr);
gap: var(--space-2xs);
}
}
/* === veranstaltung-info (Angaben + Karte) === */
/* Links ein Drittel Fakten, rechts zwei Drittel Karte. Das Kartenbild ist nur
512px breit (selbst gehostetes OSM-Rendering), deshalb bekommt die Karte eine
Obergrenze statt der halben Seitenbreite sonst wird sie hochskaliert weich. */
/* Zwei gleiche Spalten, weil die Karte dann ungefähr ihre eigenen 512px breit
ist: eine breitere Spalte würde das Bild hochskalieren und die Straßennamen
weich zeichnen. */
.veranstaltung-info__panel {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: var(--space-2xl);
/* start, nicht center: zentriert schwebte der kürzere Textblock neben der
hohen Karte im Leeren. Oben auf gleicher Höhe beginnen beide Spalten. */
align-items: start;
padding: var(--space-2xl);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
box-shadow: var(--shadow-card);
}
/* Ein Textblock mit EINER linken Kante statt einer Label/Wert-Tabelle: die
winzigen Versal-Labels mit Haarlinien-Icons und die zweite Einrückung daneben
wirkten unruhig und billig (Felix, 30.07.2026). Die Hierarchie macht jetzt
allein die Schriftgröße. */
.veranstaltung-info__wann {
margin-top: var(--space-l);
font-size: var(--fs-550);
line-height: 1.2;
}
.veranstaltung-info__beginn {
margin-top: var(--space-3xs);
color: var(--clr-text-muted);
font-size: var(--fs-500);
}
.veranstaltung-info__adresse {
margin-top: var(--space-l);
/* <address> läuft per Default kursiv — hier ist es eine Anschrift, kein Zitat. */
font-style: normal;
font-size: var(--fs-500);
line-height: 1.5;
}
.veranstaltung-info__hinweis {
max-width: 44ch;
margin-top: var(--space-l);
color: var(--clr-text-muted);
font-size: var(--fs-400);
}
.veranstaltung-info__map {
margin: 0;
}
/* 4:3 statt des quadratischen Originals: quadratisch war die Karte höher als der
Textblock daneben und links blieb ein großes Loch. Der zentrierte Beschnitt
lässt unser Gelände (etwa auf halber Höhe) stehen. */
.veranstaltung-info__map-link {
position: relative;
display: block;
aspect-ratio: 4 / 3;
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
overflow: hidden;
}
.veranstaltung-info__map-img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.veranstaltung-info__map-cta {
position: absolute;
inset-inline: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-3xs);
min-height: var(--tap-min);
padding: var(--space-2xs) var(--space-s);
background: var(--clr-accent);
color: var(--clr-text);
font-family: var(--ff-body);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
}
.veranstaltung-info__map-link:hover .veranstaltung-info__map-cta {
background: var(--clr-accent-dark);
}
.veranstaltung-info__map-credit {
margin-top: var(--space-2xs);
color: var(--clr-text-faint);
font-size: var(--fs-300);
}
@media (max-width: 992px) {
.veranstaltung-info__panel {
grid-template-columns: minmax(0, 1fr);
gap: var(--space-2xl);
padding: var(--space-l);
}
}
/* === veranstaltung-plakate === */
/* Plakate im Hochformat: nie beschneiden (sie tragen Text), sondern in der
Höhe begrenzen und nebeneinander stellen. */
.veranstaltung-plakate__grid {
display: flex;
flex-wrap: wrap;
gap: var(--space-l);
margin-top: var(--space-l);
}
.veranstaltung-plakate__item {
flex: 1 1 260px;
max-width: 420px;
}
.veranstaltung-plakate__link {
display: block;
border-radius: var(--radius-card);
overflow: hidden;
box-shadow: var(--shadow-card);
transition: transform var(--transition);
}
.veranstaltung-plakate__link:hover {
transform: translateY(-4px);
}
.veranstaltung-plakate__img {
display: block;
width: 100%;
height: auto;
}
.veranstaltung-plakate--compact .veranstaltung-plakate__item {
flex: 0 1 200px;
max-width: 200px;
}
/* === veranstaltung-galerie + lightbox === */
.veranstaltung-galerie__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
gap: var(--space-2xs);
margin-top: var(--space-l);
}
.veranstaltung-galerie__link {
display: block;
border-radius: var(--radius-photo);
overflow: hidden;
}
.veranstaltung-galerie__img {
display: block;
width: 100%;
height: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
transition: transform var(--transition);
}
.veranstaltung-galerie__link:hover .veranstaltung-galerie__img {
transform: scale(1.05);
}
/* Großansicht. Ohne JS bleibt sie `hidden` und die Vorschaubilder sind normale
Links auf die Bilddatei deshalb steht hier nichts, was ohne JS sichtbar
wäre. z-index über dem Mobil-Menü (25/30), unter dem Skip-Link (100). */
.lightbox {
position: fixed;
inset: 0;
z-index: 40;
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-4xl) var(--space-l);
background: var(--clr-lightbox-bg);
}
/* MUSS (0,2,0) sein: `[hidden]` aus reset.css hat dieselbe Spezifität wie
`.lightbox` und verliert, weil components.css später lädt ohne diese Regel
liegt das Overlay beim Laden offen über der ganzen Seite. */
.lightbox[hidden] {
display: none;
}
body.lightbox-open {
overflow: hidden;
}
.lightbox__img {
max-width: 100%;
/* Höhe der Fläche minus dem Platz, den Zähler und Knöpfe brauchen. */
max-height: calc(100vh - 2 * var(--space-4xl));
width: auto;
height: auto;
object-fit: contain;
}
.lightbox__counter {
position: absolute;
bottom: var(--space-l);
left: 50%;
transform: translateX(-50%);
margin: 0;
color: var(--clr-text-muted);
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: var(--ls-wide);
}
/* (0,2,0) nötig: utilities.css lädt NACH components.css, bei gleicher
Spezifität gewinnt sonst die .btn-Basis (siehe CLAUDE.md). */
.btn.lightbox__btn {
position: absolute;
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border-strong);
}
.btn.lightbox__btn:hover:not(:disabled) {
background: var(--clr-accent);
border-color: var(--clr-accent);
}
.btn.lightbox__btn:disabled {
opacity: 0.35;
}
.btn.lightbox__close {
top: var(--space-l);
right: var(--space-l);
}
.btn.lightbox__prev {
top: 50%;
left: var(--space-s);
transform: translateY(-50%);
}
.btn.lightbox__next {
top: 50%;
right: var(--space-s);
transform: translateY(-50%);
}
@media (max-width: 600px) {
.lightbox {
padding: var(--space-4xl) var(--space-2xs);
}
/* Am Handy sitzen Vor/Zurück unten neben dem Zähler, wo der Daumen ist. */
.btn.lightbox__prev,
.btn.lightbox__next {
top: auto;
bottom: var(--space-s);
transform: none;
}
.btn.lightbox__prev {
left: var(--space-2xl);
}
.btn.lightbox__next {
right: var(--space-2xl);
}
}
/* === Druck (Stadionzeitung) === */
/* Nur wirksam, wenn eine Stadionzeitungs-Ansicht gedruckt wird :has()-Scope
statt global, damit der Druck jeder anderen Seite unangetastet bleibt.
Farben sind bereits digital hell (.stadionzeitung-page) hier geht es nur
um Layout: Chrome ausblenden, A4 quer, ein Broschüren-Blatt pro Bogen.
Der offizielle Druckweg ist die Druckfassung (?druck=1, Broschüren-
Reihenfolge fürs Falt-Heft); der normale Viewer druckt als einfacher
Seiten-Stapel (eine Seite pro Blatt, Lesereihenfolge) als Fallback
brauchbar, fürs Heft die Druckfassung nehmen. Nach jeder Änderung mit
einer echten Druckvorschau prüfen. */
@media print {
body:has(.stadionzeitung-viewer),
body:has(.stadionzeitung-druck) {
background: #fff !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
body:has(.stadionzeitung-viewer) .site-header,
body:has(.stadionzeitung-viewer) .site-footer,
body:has(.stadionzeitung-viewer) .skip-link,
body:has(.stadionzeitung-viewer) .back-to-top,
body:has(.stadionzeitung-viewer) .stadionzeitung-issue-head,
body:has(.stadionzeitung-viewer) .stadionzeitung-viewer__controls,
body:has(.stadionzeitung-viewer) .stadionzeitung-viewer__print,
body:has(.stadionzeitung-druck) .site-header,
body:has(.stadionzeitung-druck) .site-footer,
body:has(.stadionzeitung-druck) .skip-link,
body:has(.stadionzeitung-druck) .back-to-top,
body:has(.stadionzeitung-druck) .stadionzeitung-issue-head,
body:has(.stadionzeitung-druck) .stadionzeitung-druck__hilfe,
body:has(.stadionzeitung-druck) .stadionzeitung-druck__blatt-label {
display: none !important;
}
/* Chrome rendert WEICHE Schatten im PDF-Export als harte graue Kästen
(dokumentierte Falle, siehe Cover-Kommentar zu text-shadow) im
Druck fliegen deshalb pauschal alle Schatten der Stadionzeitungs-
Seiten raus. Konturen kommen aus Rahmenlinien (Polaroids, Tickets),
nicht aus Schatten; am Bildschirm bleiben die Schatten erhalten. */
body:has(.stadionzeitung-druck) .stadionzeitung-druck *,
body:has(.stadionzeitung-viewer) .stadionzeitung-viewer * {
box-shadow: none !important;
text-shadow: none !important;
}
@page {
size: A4 landscape;
margin: 5mm;
}
/* Der UMSCHLAGBOGEN (Druckseite 1 = Rückseite + Cover, Druckseite 2 =
Vorwort + Impressum) läuft randabfallend: named page mit margin 0,
die beiden Seiten füllen je eine A4-Hälfte (148,5×210mm praktisch
exakt A5-Proportion, keine Verzerrung). Auf Druckern mit
Randlos-Modus/im Copyshop wird das echt randlos, Bürodrucker
beschneiden auf ihr Hardware-Minimum (~4mm weiß statt unserer 5mm). */
@page umschlag {
size: A4 landscape;
margin: 0;
}
.stadionzeitung-druck__blatt:nth-child(-n+2) {
page: umschlag;
}
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-druck__flaeche {
height: 210mm;
}
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-druck__slot {
flex: 1;
}
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-page__img,
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-cover,
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-page {
width: 100%;
height: 100%;
aspect-ratio: auto;
object-fit: cover;
}
/* Vorwort/Termine bringen eine eigene aspect-ratio mit auf dem
randlosen Bogen sollen sie die volle Slot-Höhe füllen (das
Wiesen-Foto blutet dann bis an die Blattkante). */
.stadionzeitung-druck__blatt:nth-child(-n+2) .stadionzeitung-vorwort {
aspect-ratio: auto;
height: calc(100% + 2 * var(--space-l));
}
/* --- Druckfassung: ein Broschüren-Blatt pro Bogen --- */
.stadionzeitung-druck {
padding: 0;
}
.stadionzeitung-druck__blaetter {
display: block;
max-width: none;
margin: 0;
padding: 0;
}
.stadionzeitung-druck__blatt {
break-after: page;
break-inside: avoid;
}
.stadionzeitung-druck__blatt:last-child {
break-after: auto;
}
/* Feste Höhe in mm statt aspect-ratio: der bedruckbare Bereich ist
210mm 2×5mm Rand 199mm statt exakt 200mm als Rundungspuffer, die
Fläche darf den Bogen nie überragen, sonst schiebt der Überstand eine
Leerseite in den Ausdruck. Der kleine seitliche Rest (die A5-Seiten
behalten ihre exakte Proportion) bleibt als schmaler weißer Streifen
außen innen an der Falz stoßen die Seiten bündig aneinander. */
.stadionzeitung-druck__flaeche {
aspect-ratio: auto;
height: 199mm;
box-shadow: none;
}
/* --- Fallback: normaler Viewer gedruckt (Seiten-Stapel) --- */
.stadionzeitung-viewer {
padding: 0 !important;
}
.stadionzeitung-viewer__track {
display: block !important;
overflow: visible !important;
padding: 0 !important;
}
.stadionzeitung-viewer__page {
display: block !important;
flex: none !important;
break-inside: avoid;
padding: 0 !important;
}
.stadionzeitung-viewer .stadionzeitung-page,
.stadionzeitung-viewer .stadionzeitung-cover {
max-width: none;
max-height: none !important;
overflow: visible !important;
width: 100%;
margin-inline: auto;
box-shadow: none;
}
.stadionzeitung-viewer .stadionzeitung-page__img {
max-height: none !important;
width: 100% !important;
height: auto !important;
box-shadow: none;
}
/* Vorwort/Termine behalten ihre aspect-ratio (dieselbe A5-Fläche, auf der
das Hintergrundbild einblendet) nur der Scroll-Affordance fällt weg
(overflow-y: auto rendert im PDF-Export sichtbares Scrollbar-Chrome).
In der Druckfassung beschneidet der Seiten-Container Überstand
(overflow: hidden auf .stadionzeitung-page, s. o.). */
/* width/height müssen das Seiten-Padding MIT abdecken: die negativen
Ränder der beiden Komponenten heben es auf, ein reines 100% misst
aber nur den Innenbereich das Foto endete sonst ein Padding
(~10mm) vor der rechten/unteren Blattkante. */
.stadionzeitung-vorwort,
.stadionzeitung-termine {
max-width: none;
width: calc(100% + 2 * var(--space-l));
overflow-y: visible;
}
/* Sportheim: gleiche Breiten-Korrektur, aber overflow bleibt hidden
die rotierten Pinselstrich-Balken ragen konstruktionsbedingt über die
Seite hinaus und würden sonst auf die Nachbarseite drucken. */
.stadionzeitung-sportheim {
max-width: none;
width: calc(100% + 2 * var(--space-l));
overflow: hidden;
}
}