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>
This commit is contained in:
2026-07-27 00:39:57 +02:00
parent bee19a2ddc
commit 66c402d9f7
10 changed files with 461 additions and 401 deletions

View File

@@ -7,7 +7,9 @@
position: relative;
display: grid;
align-items: end;
/* svh statt vh: stabil gegenüber ein-/ausfahrender Browser-UI auf Phones. */
min-height: min(92vh, 900px);
min-height: min(92svh, 900px);
padding-block: calc(var(--header-h) + 80px) var(--space-section);
overflow: hidden;
}
@@ -15,9 +17,26 @@
/* Kompakte Variante: schlanker Unterseiten-Header statt vollflächig. */
.hero--compact {
min-height: min(60vh, 560px);
min-height: min(60svh, 560px);
padding-block: calc(var(--header-h) + 64px) 3.5rem;
}
/* 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);
padding-block: calc(var(--header-h) + 48px) 3rem;
}
.hero--compact {
min-height: 0;
padding-block: calc(var(--header-h) + 44px) 2.5rem;
}
}
.hero__media {
position: absolute;
inset: 0;
@@ -78,6 +97,13 @@
margin-top: 1rem;
max-width: 60ch;
text-shadow: 0 1px 12px rgb(0 0 0 / 0.6);
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 {
@@ -103,10 +129,6 @@
text-indent: 0.14em;
}
.hero--center.hero--display .hero__tagline {
text-indent: 0.1em;
}
.hero--center .hero__actions {
justify-content: center;
}
@@ -126,47 +148,35 @@
linear-gradient(180deg, rgb(0 0 0 / 0.4) 0%, rgb(0 0 0 / 0.14) 45%, rgb(0 0 0 / 0.5) 100%);
}
/* Kicker: einziges gesperrtes Versalien-Element im Hero — bewusst ohne
Schmuck-Linien, damit die Typo-Hierarchie ruhig bleibt (Eyebrow → Titel →
Subline → Text). */
.hero__kicker {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.25rem;
font-size: var(--fs-500);
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--clr-text);
}
.hero__kicker::before {
content: '';
width: 3rem;
height: 4px;
background: var(--clr-accent);
border-radius: 2px;
}
/* Kicker zentriert: Text mittig, Akzentlinie beidseitig (— Text —) */
.hero--center .hero__kicker {
justify-content: center;
}
.hero--center .hero__kicker::after {
content: '';
width: 3rem;
height: 4px;
background: var(--clr-accent);
border-radius: 2px;
/* Sperrung optisch kompensieren (Spacing nach letztem Zeichen). */
text-indent: 0.18em;
color: rgb(255 255 255 / 0.85);
}
.hero--display .hero__title {
font-size: clamp(3.5rem, 2rem + 7.5vw, 7.5rem);
}
/* Subline ruhig in Abel, Groß-/Kleinschreibung — konkurriert nicht mehr mit
Kicker (gesperrte Versalien) und Coolvetica-Titel. */
.hero--display .hero__tagline {
margin-top: 0.5rem;
font-size: clamp(1.75rem, 1rem + 2.5vw, 2.75rem);
letter-spacing: 0.1em;
color: rgb(255 255 255 / 0.88);
margin-top: 0.75rem;
font-family: var(--ff-body);
font-size: clamp(1.25rem, 0.95rem + 1.3vw, 1.75rem);
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 {
@@ -212,10 +222,26 @@
margin-top: 2rem;
}
/* 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 {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: none;
grid-auto-flow: column;
grid-auto-columns: min(72vw, 320px);
gap: 0.75rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
}
.instagram__grid::-webkit-scrollbar {
display: none;
}
.instagram__link {
scroll-snap-align: start;
}
}
@@ -288,6 +314,13 @@
border-block: 1px solid rgb(255 255 255 / 0.1);
}
/* 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;
}
@@ -3623,267 +3656,104 @@
border-radius: 50%;
}
/* Einzelne Begegnung. */
.match-card {
/* 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 {
display: flex;
flex-direction: column;
gap: 0.85rem;
padding: clamp(1rem, 0.8rem + 0.8vw, 1.4rem);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-card);
gap: clamp(1rem, 0.8rem + 0.6vw, 1.5rem);
}
/* Datum oben mittig (kicker-Stil). */
.match-card__date {
.match-feature__meta {
display: flex;
align-items: center;
justify-content: center;
gap: 0.4em;
font-size: var(--fs-300);
flex-wrap: wrap;
align-items: baseline;
gap: 0.5em;
font-size: var(--fs-400);
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--clr-text-muted);
}
.match-card__date-icon {
font-size: 0.95em;
}
.match-card__fixture {
display: grid;
/* minmax(0, …) statt 1fr: erlaubt den Spalten, schmaler als ihr Inhalt zu
werden (sonst überläuft die Karte auf sehr schmalen Screens). */
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
align-items: center;
gap: 0.75rem;
}
.match-card__side {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
min-width: 0; /* verhindert Grid-Blowout der 1fr-Spalten bei langen Namen */
text-align: center;
}
.match-card__club {
font-size: var(--fs-400);
line-height: 1.2;
overflow-wrap: anywhere; /* lange Namen brechen um statt zu überlaufen */
}
.match-card__side.is-own .match-card__club {
font-weight: var(--fw-bold);
color: var(--clr-text);
}
.match-card__center {
display: flex;
flex-direction: column;
align-items: center;
min-width: 3.25rem;
}
.match-card__score {
font-family: var(--ff-heading);
font-size: var(--fs-700);
line-height: 1;
}
.match-card__colon {
margin: 0 0.12em;
}
.match-card__vs {
font-family: var(--ff-heading);
font-size: var(--fs-650);
.match-feature__sep {
color: var(--clr-text-faint);
}
/* Zeit mittig unter dem Ergebnis/Anstoß (kicker-Stil). */
.match-card__time {
margin-top: 0.4rem;
font-size: var(--fs-400);
color: var(--clr-text-muted);
white-space: nowrap;
}
/* Hero-Variante (im Slider): größer und ruhiger. */
.match-card--hero {
padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}
.match-card--hero .match-card__score {
font-size: var(--fs-800);
}
.match-card--hero .crest,
.match-card--hero .crest--initials {
width: 3rem;
height: 3rem;
}
.match-card--hero .match-card__club {
font-size: var(--fs-500);
}
/* „Nächste Spiele"-Slider — Mechanik wie .ad-banner (gemeinsamer Antrieb
carousel.js, gemeinsame Keyframe ad-progress). */
.match-slider {
--slider-interval: 6s;
}
.match-slider > .container > h2 {
text-align: center;
}
.match-slider__track {
list-style: none;
margin: 2rem auto 0;
padding: 0;
max-width: 620px;
}
.match-slider__slide[hidden] {
display: none;
}
.match-slider__team {
margin-bottom: 0.85rem;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: var(--fs-300);
color: var(--clr-text-muted);
}
/* Crossfade nur mit JS: Slides im selben Grid-Feld stapeln (konstante Höhe). */
.match-slider.is-enhanced .match-slider__track {
display: grid;
grid-template-columns: minmax(0, 1fr); /* gestapelte Slides nie breiter als der Track */
}
.match-slider.is-enhanced .match-slider__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;
}
.match-slider.is-enhanced .match-slider__slide.is-active {
opacity: 1;
transform: none;
pointer-events: auto;
visibility: visible;
transition: opacity 0.55s ease, transform 0.55s ease, visibility 0s;
}
.match-slider__controls {
.match-feature__fixture {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-top: 1.75rem;
}
.match-slider__controls[hidden] {
display: none;
}
.match-slider__toggle {
display: inline-grid;
place-items: center;
width: 2.25rem;
height: 2.25rem;
padding: 0;
color: var(--clr-text);
background: var(--clr-glass-bg);
border: 1px solid var(--clr-glass-border);
border-radius: 999px;
cursor: pointer;
transition: background var(--transition);
}
.match-slider__toggle[hidden] {
display: none;
}
.match-slider__toggle:hover {
background: rgb(255 255 255 / 0.2);
}
.match-slider__toggle:focus-visible {
outline: 2px solid var(--clr-text);
outline-offset: 3px;
}
.match-slider__toggle-icon {
font-size: 1.15rem;
}
.match-slider__toggle .match-slider__toggle-icon--play {
display: none;
}
.match-slider__toggle[aria-pressed="true"] .match-slider__toggle-icon--pause {
display: none;
}
.match-slider__toggle[aria-pressed="true"] .match-slider__toggle-icon--play {
display: inline-block;
}
.match-slider__dots {
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
gap: 0.5rem;
}
.match-slider__dot {
position: relative;
width: 48px;
height: 6px;
padding: 0;
border: 0;
border-radius: 999px;
background: var(--clr-glass-border);
cursor: pointer;
overflow: hidden;
transition: background var(--transition);
.match-feature__side {
display: flex;
align-items: center;
gap: clamp(0.6rem, 0.4rem + 0.6vw, 1rem);
min-width: 0; /* lange Vereinsnamen dürfen umbrechen statt zu überlaufen */
}
.match-slider__dot:hover {
background: rgb(255 255 255 / 0.35);
.match-feature .crest,
.match-feature .crest--initials {
width: clamp(2.25rem, 1.6rem + 2vw, 3rem);
height: clamp(2.25rem, 1.6rem + 2vw, 3rem);
font-size: var(--fs-400);
}
.match-slider__dot:focus-visible {
outline: 2px solid var(--clr-text);
outline-offset: 3px;
/* 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). */
.match-feature__club {
font-family: var(--ff-heading);
font-size: var(--fs-700);
line-height: var(--lh-heading);
text-transform: uppercase;
color: var(--clr-text-muted);
overflow-wrap: anywhere;
}
.match-slider__progress {
position: absolute;
inset: 0;
background: var(--clr-accent);
transform: scaleX(0);
transform-origin: left;
.match-feature__side.is-own .match-feature__club {
color: var(--clr-text);
}
.match-slider__dot.is-active .match-slider__progress {
animation: ad-progress var(--slider-interval) linear forwards;
.match-feature__when {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.5em;
font-size: var(--fs-600);
}
.match-slider.is-paused .match-slider__dot.is-active .match-slider__progress {
animation-play-state: paused;
/* 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);
}
@media (prefers-reduced-motion: reduce) {
.match-slider__dot.is-active .match-slider__progress {
animation: none;
transform: scaleX(1);
.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(1.25rem, 1rem + 1.5vw, 2.5rem);
margin-top: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
}
.next-matches__list-title {
margin-bottom: 0.75rem;
/* 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;
letter-spacing: 0.08em;
color: var(--clr-text-muted);
}
@media (max-width: 992px) {
.next-matches__grid {
grid-template-columns: 1fr;
}
}
@@ -3967,12 +3837,23 @@
border-radius: var(--radius-card);
}
/* 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;
}
.match-row {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
column-gap: 0.75rem;
padding: 0.7rem 0.9rem;
border-bottom: 1px solid var(--clr-glass-border);
}
@@ -3980,13 +3861,43 @@
border-bottom: 0;
}
.match-row__date {
/* 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 {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
column-gap: 0.75rem;
padding: 0.7rem 0.9rem;
color: inherit;
text-decoration: none;
}
a.match-row__link:hover {
background: rgb(255 255 255 / 0.06);
}
.match-row__head {
grid-column: 1 / -1;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.5rem;
margin-bottom: 0.45rem;
}
.match-row__date {
font-size: var(--fs-300);
color: var(--clr-text-muted);
}
.match-row__meta {
font-size: var(--fs-300);
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--clr-text-faint);
}
.match-row__teams {
display: flex;
flex-direction: column;
@@ -4045,6 +3956,25 @@
border-radius: var(--radius-card);
}
/* 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;
}
}
.table-scroll:focus-visible {
outline: 2px solid var(--clr-text);
outline-offset: 2px;
@@ -4386,7 +4316,6 @@
.group-card,
.group-tabs__panel,
.age-group,
.match-card,
.match-list,
.matchcenter-empty,
.roster-card,
@@ -4413,8 +4342,7 @@
.key-facts__item,
.bento__tile,
.group-card,
.match-card,
.matchcenter-empty,
.matchcenter-empty,
.roster-card,
.team-card,
.department-choice__card,

View File

@@ -19,6 +19,7 @@
--clr-sepia-bg: #f3efe4; /* Timeline-Museumsrahmen (Foto-Mount) */
--clr-sepia-text: #3a372f; /* Timeline-Text auf hellem Sepia-Grund */
--clr-glass-bg: rgb(0 0 0 / 0.22); /* dunkles Glas (dunkler als der Grund) */
--clr-surface-raised: rgb(255 255 255 / 0.055); /* Karte, die auf einem abgesetzten (dunkleren) Band liegt */
--clr-glass-border: rgb(255 255 255 / 0.14); /* sehr dezenter Card-Rand — Glow/Sheen tragen die Kontur */
--clr-glass-border-strong: rgb(255 255 255 / 0.45); /* Back-to-Top, position-/group-card etc.: ≥3:1 (WCAG 1.4.11) */
--clr-field-bg: rgb(255 255 255 / 0.07); /* Formularfelder: sanfte Füllfläche (etwas heller als das Glas) */
@@ -37,8 +38,10 @@
--fs-650: 1.75rem; /* 28px Zwischengröße (z.B. Footer-Headings) */
--fs-675: 2.125rem; /* 34px Header-Wortmarke */
--fs-700: clamp(2rem, 1.2rem + 3.5vw, 3.125rem); /* 50px h3 */
--fs-800: clamp(2.25rem, 1.3rem + 4.5vw, 3.75rem); /* 60px h2 */
--fs-900: clamp(3rem, 1.75rem + 5.5vw, 6rem); /* 96px h1 */
/* Mobil-Minima bewusst hoch: Coolvetica Condensed wirkt bei gleicher
nomineller Größe deutlich kleiner als normale Schnitte. */
--fs-800: clamp(2.625rem, 1.3rem + 4.5vw, 3.75rem); /* 4260px h2 */
--fs-900: clamp(3.5rem, 1.75rem + 5.5vw, 6rem); /* 5696px h1 */
--lh-heading: 0.9;
--lh-body: 1.5;
--fw-regular: 400;