Stadionzeitung gegen ASV Marktschorgast vorbereiten

This commit is contained in:
2026-08-28 13:11:43 +02:00
parent 736a588a88
commit f88b5f1dd1
40 changed files with 873 additions and 8 deletions

View File

@@ -517,6 +517,7 @@ kein Download-Link — nur die Web-Ansicht. Der Ablauf pro Heimspiel ist damit:
Inhalt ist eine Liste von **Blöcken**, die Anzeigen füllen die Lücken dazwischen (⌷ = Lücke):
```
Cover → [Vorwort → Interview (nur wenn die Ausgabe eins trägt)] ⌷ Ergebnis-Rückblick ⌷
Gegnerstatistik der tragenden Mannschaft (automatisch aus deren Tabelle) ⌷
[je Mannschaft eine Tabelle, Reihenfolge = matchcenter.json — EIN Block, dazwischen nie eine
Anzeige; Erste + Zweite bilden im gefalteten Heft eine Doppelseite] ⌷ Vorschau ⌷ Termine ⌷
News ⌷ Ansprechpartner ⌷ Mitglied-werden-Poster ⌷ Historie-Teaser (Website-Verweis +
@@ -547,7 +548,7 @@ Lücken bekommen 7 Lücken zwei. Zwei hintereinander ist das Optimum, nicht eins
Zweier-Paar auf einer Doppelseite landen kann, schlägt man das Heft gelegentlich auf zwei Anzeigen auf.
Ein `images[]`-Eintrag hat
`"type": "image"` (wie gehabt, `base`/`widths`/`alt`) oder `"type": "live"` (`page`: `cover` |
`vorwort` | `interview` | `aufruf` | `tabelle` | `termine` | `news` | `ergebnisse` | `vorschau` | `kontakt` | `mitglied` | `historie` | `sportheim` | `partner` | `momente` | `impressum`, kein Bild;
`vorwort` | `interview` | `aufruf` | `tabelle` | `termine` | `news` | `ergebnisse` | `gegner` | `vorschau` | `kontakt` | `mitglied` | `historie` | `sportheim` | `partner` | `momente` | `impressum`, kein Bild;
`tabelle` zusätzlich mit `team`: Team-Key aus `matchcenter.json`, ohne `team` greift der Team-Key
der Ausgabe). Fehlt `type` (alte Phase-1-Ausgaben) → Fallback `image`, bricht nicht. **Gerendert
wird jede Seite (Bild wie Live) über `app/components/stadionzeitung-seite.php`** — die eine

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
/**
* Gegnerstatistik der Stadionzeitung. Alle Werte stammen aus dem bereits
* aufgebauten Stadionzeitungs-Snapshot; die Komponente rendert nur. Dadurch
* sind Entwurf und veröffentlichte Druckausgabe konsistent und archivfest.
*
* Props: $info stadionzeitung_live_data($issue)['gegner']
*/
$info = is_array($info ?? null) ? $info : [];
$fixture = is_array($info['fixture'] ?? null) ? $info['fixture'] : [];
$own = is_array($info['own'] ?? null) ? $info['own'] : null;
$opponent = is_array($info['opponent_stats'] ?? null) ? $info['opponent_stats'] : null;
$opponentName = (string) ($info['opponent'] ?? 'Unser Gegner');
$kickoff = (string) ($fixture['kickoff'] ?? '');
$kickoffDate = $kickoff !== '' ? substr($kickoff, 0, 10) : '';
$kickoffTime = $kickoff !== '' ? substr($kickoff, 11, 5) : '';
$rows = [
['label' => 'Tabellenplatz', 'key' => 'rank'],
['label' => 'Spiele', 'key' => 'played'],
['label' => 'Siege', 'key' => 'won'],
['label' => 'Unentschieden', 'key' => 'drawn'],
['label' => 'Niederlagen', 'key' => 'lost'],
['label' => 'Tordifferenz', 'key' => 'goal_diff', 'signed' => true],
['label' => 'Punkte', 'key' => 'points'],
];
$format = static function (?array $row, string $key, bool $signed = false): string {
if ($row === null || !array_key_exists($key, $row)) {
return '';
}
$value = (int) $row[$key];
return $signed && $value > 0 ? '+' . $value : (string) $value;
};
?>
<div class="stadionzeitung-gegner">
<header class="stadionzeitung-page__head">
<p class="stadionzeitung-page__kicker">Unser Gegner</p>
<h2 class="stadionzeitung-page__heading"><?= e($opponentName) ?></h2>
<?php if (!empty($info['league']) || !empty($info['season'])): ?>
<p class="stadionzeitung-page__sub"><?= e(trim(implode(' · ', array_filter([(string) ($info['league'] ?? ''), (string) ($info['season'] ?? '')])))) ?></p>
<?php endif; ?>
</header>
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
<div class="stadionzeitung-gegner__duell">
<div class="stadionzeitung-gegner__club stadionzeitung-gegner__club--own">
<?php component('crest', ['src' => $fixture['home_crest'] ?? $own['crest'] ?? null, 'name' => $fixture['home'] ?? 'TSV 08 Kulmbach']); ?>
<strong><?= e((string) ($fixture['home'] ?? 'TSV 08 Kulmbach')) ?></strong>
</div>
<div class="stadionzeitung-gegner__match">
<span>gegen</span>
<?php if ($kickoffDate !== ''): ?>
<strong><?= e(german_date($kickoffDate)) ?></strong>
<?php endif; ?>
<?php if ($kickoffTime !== ''): ?>
<span><?= e($kickoffTime) ?> Uhr</span>
<?php endif; ?>
</div>
<div class="stadionzeitung-gegner__club">
<?php component('crest', ['src' => $fixture['away_crest'] ?? $opponent['crest'] ?? null, 'name' => $fixture['away'] ?? $opponentName]); ?>
<strong><?= e((string) ($fixture['away'] ?? $opponentName)) ?></strong>
</div>
</div>
<?php if ($own !== null && $opponent !== null): ?>
<div class="stadionzeitung-gegner__vergleich" role="table" aria-label="Tabellenvergleich">
<div class="stadionzeitung-gegner__vergleich-head" role="row">
<span role="columnheader">TSV 08</span>
<span role="columnheader">Vergleich</span>
<span role="columnheader">ASV</span>
</div>
<?php foreach ($rows as $row): ?>
<div class="stadionzeitung-gegner__vergleich-row" role="row">
<strong role="cell"><?= e($format($own, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
<span role="rowheader"><?= e((string) $row['label']) ?></span>
<strong role="cell"><?= e($format($opponent, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<p class="stadionzeitung-gegner__empty">Die aktuellen Vergleichsdaten waren beim letzten Abruf nicht verfügbar.</p>
<?php endif; ?>
</div>

View File

@@ -10,7 +10,7 @@ declare(strict_types=1);
* $entry Eintrag aus issue.images[]:
* type 'image' (base/widths/alt),
* type 'live' (page: cover|vorwort|interview|aufruf|tabelle|termine|
* news|ergebnisse|vorschau|kontakt; tabelle optional
* news|ergebnisse|gegner|vorschau|kontakt; tabelle optional
* mit team: Team-Key aus matchcenter.json),
* type 'leer' (weiße Füllseite, nur Druckfassung — hält die
* Seitenzahl auf einem Vielfachen von 4)
@@ -55,6 +55,9 @@ $type = $entry['type'] ?? 'image';
<?php case 'ergebnisse': ?>
<?php component('stadionzeitung-ergebnisse', ['groups' => $data['ergebnisse'] ?? []]); ?>
<?php break; ?>
<?php case 'gegner': ?>
<?php component('stadionzeitung-gegner', ['info' => $data['gegner'] ?? null]); ?>
<?php break; ?>
<?php case 'vorschau': ?>
<?php component('stadionzeitung-vorschau', ['items' => $data['vorschau'] ?? []]); ?>
<?php break; ?>

View File

@@ -8,7 +8,7 @@ declare(strict_types=1);
* (Kicker + Überschrift über einblendendem Vereinsfoto), aber mit einer
* Icon-Liste statt Fließtext.
*
* Die drei Termine sind KEIN Live-Abruf: bin/stadionzeitung-add.php friert
* Die Termine sind KEIN Live-Abruf: bin/stadionzeitung-add.php friert
* sie beim Anlegen der Ausgabe einmalig ein (`termine_snapshot`, siehe dort
* und termine_build_lists()) — eine gedruckte Ausgabe zeigt dauerhaft, was
* am Spieltag anstand, nicht was von "heute" aus gesehen ansteht.
@@ -60,6 +60,8 @@ $termineLink = club_domain('termine');
} elseif (!$isMatch && !empty($item['location'])) {
$parts[] = (string) $item['location'];
}
$title = (string) ($item['title'] ?? '');
$meta = implode(' · ', $parts);
?>
<li class="stadionzeitung-termine__item">
<?php /* Icon nach Termin-Art (Wunsch Felix 29.07.2026): Spiele bekommen die
@@ -67,8 +69,8 @@ $termineLink = club_domain('termine');
Blick unterscheidbar. */ ?>
<span class="stadionzeitung-termine__icon" aria-hidden="true"><?= icon($isMatch ? 'trophy' : 'calendar-event') ?></span>
<div class="stadionzeitung-termine__body">
<p class="stadionzeitung-termine__title"><?= e((string) ($item['title'] ?? '')) ?></p>
<p class="stadionzeitung-termine__meta"><?= e(implode(' · ', $parts)) ?></p>
<p class="stadionzeitung-termine__title" title="<?= e($title) ?>"><?= e($title) ?></p>
<p class="stadionzeitung-termine__meta" title="<?= e($meta) ?>"><?= e($meta) ?></p>
</div>
</li>
<?php endforeach; ?>

View File

@@ -988,10 +988,12 @@ function stadionzeitung_build_snapshot(array $issue): array
{
$date = (string) ($issue['date'] ?? '');
$issueTeam = (string) ($issue['team_key'] ?? '');
$issueOpponent = trim((string) ($issue['opponent'] ?? ''));
$tabellen = [];
$ergebnisse = [];
$vorschau = [];
$gegner = null;
foreach (json_load('matchcenter')['teams'] ?? [] as $team) {
$key = (string) ($team['key'] ?? '');
if ($key === '') {
@@ -1004,6 +1006,44 @@ function stadionzeitung_build_snapshot(array $issue): array
'table' => $team['table'] ?? [],
];
// Gegnerseite der tragenden Mannschaft: ausschließlich aus demselben
// Matchcenter-Datensatz wie die Tabelle ableiten. So gibt es keinen
// zweiten BFV-Abruf und der Stand wird beim Veröffentlichen zusammen
// mit den übrigen Live-Daten eingefroren.
if ($key === $issueTeam && $issueOpponent !== '') {
$table = is_array($team['table'] ?? null) ? $team['table'] : [];
$ownRow = null;
$opponentRow = null;
foreach ($table as $row) {
if (!empty($row['is_own_club'])) {
$ownRow = $row;
}
if (strcasecmp(trim((string) ($row['club'] ?? '')), $issueOpponent) === 0) {
$opponentRow = $row;
}
}
$fixture = null;
foreach ($team['next_matches'] ?? [] as $match) {
$matchDate = substr((string) ($match['kickoff'] ?? ''), 0, 10);
$clubs = [(string) ($match['home'] ?? ''), (string) ($match['away'] ?? '')];
if ($matchDate === $date && in_array($issueOpponent, $clubs, true)) {
$fixture = $match;
break;
}
}
$gegner = [
'team_name' => (string) ($team['name'] ?? ''),
'opponent' => $issueOpponent,
'league' => (string) ($team['league'] ?? ''),
'season' => (string) ($team['season'] ?? ''),
'fixture' => $fixture,
'own' => $ownRow,
'opponent_stats' => $opponentRow,
];
}
// Nur Spiele mit erfasstem Ergebnis — ein Testspiel ohne Tore ist
// kein Rückblick (dieselbe Regel wie im News-Feed).
$withScore = array_values(array_filter(
@@ -1058,6 +1098,7 @@ function stadionzeitung_build_snapshot(array $issue): array
return [
'tabellen' => $tabellen,
'gegner' => $gegner,
'ergebnisse' => $ergebnisse,
'vorschau' => $vorschau,
// Fünf statt sechs: mit den größeren Überschriften + CTA-Fuß braucht

View File

@@ -309,6 +309,7 @@ try {
}
$bloecke[] = ['name' => 'ergebnisse', 'seiten' => [$live('ergebnisse')], 'anzeigen_danach' => true];
$bloecke[] = ['name' => 'gegner', 'seiten' => [$live('gegner')], 'anzeigen_danach' => true];
// Eine Tabellen-Seite je Mannschaft, Reihenfolge wie in matchcenter.json
// (= config 'matchcenter.teams'). Kommt eine Mannschaft dazu (z. B. die

View File

@@ -124,7 +124,7 @@
{
"slug": "emons-stuebinger",
"sponsor": "Emons Spedition und AST Stübinger Hoch-, Tief- und Straßenbau, Kulmbach",
"aktiv": true,
"aktiv": false,
"base": "img/anzeigen/emons-stuebinger",
"widths": [
480,
@@ -247,6 +247,53 @@
960,
1440
]
},
{
"slug": "emons-partnerdank",
"sponsor": "Emons Spedition und Dank an unsere Partner",
"aktiv": true,
"alt": "Anzeige: Emons Spedition, darunter unser Dank an alle Partner",
"base": "img/anzeigen/emons-partnerdank",
"widths": [
480,
960,
1440
]
},
{
"slug": "gagel-pickelmann",
"sponsor": "Gagel Bäder und Mineralölhandel Pickelmann",
"aktiv": true,
"base": "img/anzeigen/gagel-pickelmann",
"widths": [
480,
960,
1440
]
},
{
"slug": "schramm",
"sponsor": "Landgasthof und Metzgerei Schramm, Forstlahm",
"aktiv": true,
"base": "img/anzeigen/schramm",
"widths": [
480,
960,
1440
]
},
{
"slug": "tagesskifahrt-2027",
"sponsor": "Unsere Tagesskifahrt ins Hochzillertal 2027",
"aktiv": true,
"bis": "2027-02-20",
"alt": "Eigenanzeige: Unsere Tagesskifahrt ins Hochzillertal am 20. Februar 2027",
"base": "img/anzeigen/tagesskifahrt-2027",
"widths": [
480,
960,
1440
]
}
]
}

View File

@@ -1,5 +1,582 @@
{
"issues": [
{
"slug": "2026-08-29-asv-marktschorgast",
"opponent": "ASV Marktschorgast",
"date": "2026-08-29",
"team_key": "erste-mannschaft",
"status": "entwurf",
"pages": 44,
"player_image": {
"base": "img/stadionzeitung/2026-08-29-asv-marktschorgast/spieler",
"widths": [
320,
640,
1000
],
"ext": "png",
"alt": ""
},
"qr_image": "img/stadionzeitung/2026-08-29-asv-marktschorgast/qr.png",
"vorwort": {
"heading": "Jetzt soll der erste Heimsieg her!",
"paragraphs": [
"Liebe Fußballfreunde,",
"herzlich willkommen im Katzbachtal. Ein besonderer Gruß gilt dem Schiedsrichtergespann und unseren Gästen vom ASV Marktschorgast.",
"Der starke 7:1-Auswärtssieg in Rugendorf gibt uns Rückenwind. Trotzdem zählt heute nur die neue Aufgabe: Gegen den direkten Tabellennachbarn aus Marktschorgast wollen wir endlich unseren ersten Heimsieg feiern.",
"Leidenschaft, Wille, Heimsieg. Los geht's!"
],
"closing": "Rot-schwarze Grüße",
"signee_name": "Benedikt Höfner",
"signee_role": "Sportlicher Leiter"
},
"interview": {
"teaser": "Unser Trainer Ali Kilic über den starken Auftritt in Rugendorf, den ASV Marktschorgast und den ersehnten ersten Heimsieg",
"heading": "Drei Fragen an Ali Kilic",
"person_name": "Ali Kilic",
"person_role": "Trainer 1. Mannschaft",
"intro": null,
"fragen": [
{
"frage": "Ali, wie blickst du auf das letzte Auswärtsspiel in Rugendorf zurück?",
"antwort": "Das war ein sehr guter Auftritt von uns. Trotz der teilweise hitzigen Stimmung haben wir uns nicht beirren lassen, sind bei unserem Spiel geblieben und haben über 90 Minuten eine konzentrierte Auswärtsleistung gezeigt. Das 7:1 wollen wir trotzdem nicht zu hoch hängen. Entscheidend ist, dass wir diesen Schwung mitnehmen und gegen Marktschorgast endlich unseren ersten Heimsieg holen."
},
{
"frage": "Marktschorgast steht aktuell einen Punkt vor uns. Was für einen Gegner erwartest du?",
"antwort": "Die Tabelle zeigt, wie eng es aktuell zugeht. Marktschorgast wird uns alles abverlangen. Für uns geht es darum, unabhängig vom Gegner unsere eigenen Prinzipien auf den Platz zu bringen, aufmerksam zu verteidigen und mutig nach vorne zu spielen."
},
{
"frage": "In den ersten beiden Heimspielen hat es noch nicht mit einem Sieg geklappt. Was müssen wir diesmal besser machen?",
"antwort": "Wir müssen von der ersten Minute an wach und konsequent sein. Gerade zuhause wollen wir das Spiel aktiv gestalten, unsere Fehler kleinhalten und unsere Chancen besser nutzen. Wenn wir als Mannschaft dieselbe Geschlossenheit wie in Rugendorf zeigen, haben wir sehr gute Möglichkeiten, den ersten Heimsieg zu holen."
}
],
"photo": "img/persons/ali-kilic.jpg"
},
"aufruf": {
"kicker": "Sportfest 2026",
"heading": "Helfende Hände gesucht",
"intro": [
"Sportfest vom 4. bis 6. September.",
"Drei Tage Fußball, Essen und Feiern.",
"Dafür brauchen wir dich."
],
"tasks_title": "Wobei wir Hilfe brauchen",
"tasks": [
"Grillen",
"Kaffee, Kuchen und Getränke verkaufen",
"Pizza backen und verkaufen",
"Kuchen backen und mitbringen"
],
"contacts_intro": "Du willst mit anpacken? Melde dich bei einem von uns:",
"contacts": [
"Sam Kern",
"Kerstin Tauber",
"Fabian Früh"
],
"link": "veranstaltungen/sportfest-2026",
"cta_label": "Alle Infos",
"cta_title": "Alles zum Sportfest",
"poster": {
"base": "img/veranstaltungen/sportfest-2026/plakat-01",
"widths": [
640,
1000,
1587
],
"alt": "Plakat zum Sportfest 2026 mit Luftbild unserer Sportanlage und den Terminen vom 4. bis 6. September"
}
},
"verfasser_photo": {
"base": "img/stadionzeitung/2026-08-29-asv-marktschorgast/verfasser",
"widths": [
120,
222
],
"alt": ""
},
"termine_snapshot": [
{
"date": "2026-09-02",
"date_end": null,
"title": "(SG1) TSV Melkendorf III/ TSV 08 Kulmbach II TSV 1902 Thurnau II",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Reserve BK 5 BT-KU",
"href": "/matchcenter",
"kickoff": "2026-09-02T18:00",
"team_name": "2. Mannschaft",
"league": "Reserve BK 5 BT-KU",
"raw": {
"kickoff": "2026-09-02T18:00",
"date_display": "Mi, 02.09.",
"time_display": "18:00 Uhr",
"competition": "Liga",
"home": "(SG1) TSV Melkendorf III/ TSV 08 Kulmbach II",
"away": "TSV 1902 Thurnau II",
"home_crest": "img/crests/00ES8GNK4O000002VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK4O00000SVV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "zweite-mannschaft",
"team_name": "2. Mannschaft"
}
},
{
"date": "2026-09-04",
"date_end": null,
"title": "TSV 08 Kulmbach ATS Wartenfels",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Kreisklasse",
"href": "/matchcenter",
"kickoff": "2026-09-04T18:00",
"team_name": "1. Mannschaft",
"league": "Kreisklasse",
"raw": {
"kickoff": "2026-09-04T18:00",
"date_display": "Fr, 04.09.",
"time_display": "18:00 Uhr",
"competition": "Liga",
"home": "TSV 08 Kulmbach",
"away": "ATS Wartenfels",
"home_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK4O000012VV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "erste-mannschaft",
"team_name": "1. Mannschaft"
}
},
{
"date": "2026-09-04",
"date_end": "2026-09-06",
"title": "Sportfest 2026",
"department": "verein",
"type": "event",
"meta": "16:30 Uhr · Hans-Rausch-Sportanlage",
"href": "/veranstaltungen/sportfest-2026",
"time": "16:30",
"location": "Hans-Rausch-Sportanlage",
"raw": {
"slug": "sportfest-2026",
"title": "Sportfest 2026",
"date_start": "2026-09-04",
"date_end": "2026-09-06",
"time": "16:30",
"location": "Hans-Rausch-Sportanlage",
"department": "verein",
"status": "veroeffentlicht",
"text": "Drei Tage Fußball, Essen, Trinken, Kaffee und Kuchen: bei uns ist für groß und klein alles dabei, für die Kinder steht eine Hüpfburg.",
"ankuendigung": null,
"rueckblick": null,
"karte": "club",
"anfahrt": [],
"plakate": [
{
"base": "img/veranstaltungen/sportfest-2026/plakat-01",
"widths": [
640,
1000,
1587
],
"alt": "Plakat zum Sportfest 2026 mit Luftbild unserer Sportanlage und den Terminen vom 4. bis 6. September",
"source": "1-ankuendigung.png"
},
{
"base": "img/veranstaltungen/sportfest-2026/plakat-02",
"widths": [
640,
1000,
1587
],
"alt": "Programmplakat zum Sportfest 2026 mit allen Spielen, Turnieren und der Kinderolympiade am Samstag",
"source": "2-programm.png"
}
],
"galerie": []
}
},
{
"date": "2026-09-05",
"date_end": null,
"title": "(SG1) TSV Melkendorf III/ TSV 08 Kulmbach II (SG 2) SV Weidenberg III/SSV Warmensteinach II (flex)",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Reserve BK 5 BT-KU",
"href": "/matchcenter",
"kickoff": "2026-09-05T18:00",
"team_name": "2. Mannschaft",
"league": "Reserve BK 5 BT-KU",
"raw": {
"kickoff": "2026-09-05T18:00",
"date_display": "Sa, 05.09.",
"time_display": "18:00 Uhr",
"competition": "Liga",
"home": "(SG1) TSV Melkendorf III/ TSV 08 Kulmbach II",
"away": "(SG 2) SV Weidenberg III/SSV Warmensteinach II (flex)",
"home_crest": "img/crests/00ES8GNK4O000002VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK4O000013VV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "zweite-mannschaft",
"team_name": "2. Mannschaft"
}
},
{
"date": "2026-09-06",
"date_end": null,
"title": "TSV 08 Kulmbach 1. FC 1928 Schwarzenbach/Saale",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Frauen KL Ost",
"href": "/matchcenter",
"kickoff": "2026-09-06T11:00",
"team_name": "Frauenmannschaft",
"league": "Frauen KL Ost",
"raw": {
"kickoff": "2026-09-06T11:00",
"date_display": "So, 06.09.",
"time_display": "11:00 Uhr",
"competition": "Liga",
"home": "TSV 08 Kulmbach",
"away": "1. FC 1928 Schwarzenbach/Saale",
"home_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK9O00000QVV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "damen",
"team_name": "Frauenmannschaft"
}
}
],
"images": [
{
"type": "live",
"page": "cover"
},
{
"type": "live",
"page": "vorwort"
},
{
"type": "live",
"page": "interview"
},
{
"type": "live",
"page": "aufruf"
},
{
"type": "image",
"base": "img/anzeigen/eldorado",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: eldorado Radsporttechnik Kulmbach"
},
{
"type": "live",
"page": "ergebnisse"
},
{
"type": "image",
"base": "img/anzeigen/egu",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Erfrischungsgetränke-Union Kulmbacher Gruppe GmbH"
},
{
"type": "image",
"base": "img/anzeigen/hofmann-graef",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Buchhandlung Hofmann, Kulmbach, und Automobilwerkstatt Gräf, Thurnau"
},
{
"type": "live",
"page": "gegner"
},
{
"type": "image",
"base": "img/anzeigen/muench-richterstegner",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Planungsbüro Münch und Richter & Stegner Steuerungstechnik"
},
{
"type": "image",
"base": "img/anzeigen/malteser-herrmann",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Malteser-Hilfsdienst und Schlosserei Herrmann, Kulmbach"
},
{
"type": "live",
"page": "tabelle",
"team": "erste-mannschaft"
},
{
"type": "live",
"page": "tabelle",
"team": "zweite-mannschaft"
},
{
"type": "live",
"page": "tabelle",
"team": "damen"
},
{
"type": "image",
"base": "img/anzeigen/apotheken-wenkel",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Apotheke im Fritz, Stadtpark Apotheke und Schlüsseldienst Wenkel, Kulmbach"
},
{
"type": "image",
"base": "img/anzeigen/karl-geyer",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Geyer Farbe + Raum, Kulmbach, Starthilfe Boden"
},
{
"type": "live",
"page": "vorschau"
},
{
"type": "image",
"base": "img/anzeigen/gsb",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: GSB Security und GSB Gebäude Service, Bindlach"
},
{
"type": "image",
"base": "img/anzeigen/physiofit-wohlfart",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Physio Fit Neudrossenfeld und Textilpflege Wohlfart, Kulmbach"
},
{
"type": "live",
"page": "termine"
},
{
"type": "image",
"base": "img/anzeigen/sport2000-pizza",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Sport 2000 Downstairs und Kulmbacher Pizza-Service"
},
{
"type": "image",
"base": "img/anzeigen/schulz-csu",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Schreinerei Schulz, Mainleus, und CSU Stadtverband Kulmbach"
},
{
"type": "live",
"page": "news"
},
{
"type": "image",
"base": "img/anzeigen/mattis-ka2",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Karl Mattis Flaschnerei und KA2 Fitness, Kulmbach"
},
{
"type": "live",
"page": "kontakt"
},
{
"type": "image",
"base": "img/anzeigen/motor-nuetzel",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Motor-Nützel Vertriebs-GmbH, Bayreuth"
},
{
"type": "image",
"base": "img/anzeigen/vereinskarte-edeka",
"widths": [
480,
960,
1410
],
"alt": "Eigenanzeige: So funktioniert die Vereinskarte beim E center Seidl Kulmbach"
},
{
"type": "live",
"page": "mitglied"
},
{
"type": "image",
"base": "img/anzeigen/trapper-verkehrsakademie",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Trapper GmbH Entsorgungsfachbetrieb und Verkehrsakademie, Kulmbach"
},
{
"type": "image",
"base": "img/anzeigen/ohnemueller-dippold",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Gaststätte und Metzgerei Ohne-Müller, Kulmbach-Weiher, und Bäckerei Dippold, Melkendorf"
},
{
"type": "live",
"page": "historie"
},
{
"type": "image",
"base": "img/anzeigen/hanft",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Hanft Bürotechnik GmbH, Kulmbach"
},
{
"type": "image",
"base": "img/anzeigen/elma-kleinheinz",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: elma GmbH Bayreuth und Metzgerei Kleinheinz, Kulmbach"
},
{
"type": "live",
"page": "sportheim"
},
{
"type": "image",
"base": "img/anzeigen/stadionzeitung-digital",
"widths": [
480,
960,
1440
],
"alt": "Eigenanzeige: Unsere Stadionzeitung gibt es jetzt auch online, mit QR-Code zum Scannen"
},
{
"type": "image",
"base": "img/anzeigen/sportfest-2026-programm",
"widths": [
480,
960,
1440
],
"alt": "Eigenanzeige: Programm des Sportfests 2026 mit allen Spielen, Turnieren und der Kinderolympiade"
},
{
"type": "live",
"page": "partner"
},
{
"type": "image",
"base": "img/anzeigen/emons-partnerdank",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Emons Spedition, darunter unser Dank an alle Partner"
},
{
"type": "image",
"base": "img/anzeigen/gagel-pickelmann",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Gagel Bäder und Mineralölhandel Pickelmann"
},
{
"type": "live",
"page": "momente"
},
{
"type": "image",
"base": "img/anzeigen/schramm",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Landgasthof und Metzgerei Schramm, Forstlahm"
},
{
"type": "image",
"base": "img/anzeigen/tagesskifahrt-2027",
"widths": [
480,
960,
1440
],
"alt": "Eigenanzeige: Unsere Tagesskifahrt ins Hochzillertal am 20. Februar 2027"
},
{
"type": "live",
"page": "impressum"
},
{
"type": "image",
"base": "img/stadionzeitung/2026-08-29-asv-marktschorgast/rueckseite",
"widths": [
480,
960,
1410
],
"alt": "Rückseite der Stadionzeitung gegen ASV Marktschorgast"
}
]
},
{
"slug": "2026-08-15-tsv-koednitz",
"opponent": "TSV Ködnitz",

View File

@@ -6605,11 +6605,17 @@ body.is-sz-full .back-to-top {
font-weight: var(--fw-bold);
font-size: 4.4cqi;
line-height: 1.25;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.stadionzeitung-termine__meta {
font-size: 3.1cqi;
color: var(--clr-text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* === termine-list (Termine/Events-Seite) === */
@@ -7033,6 +7039,106 @@ a.news-feature__link:hover .news-feature__more {
line-height: 1;
}
/* === stadionzeitung-gegner (Live-Seite) === */
.stadionzeitung-gegner {
min-height: 100%;
}
.stadionzeitung-gegner__duell {
display: grid;
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
align-items: center;
gap: 2.5cqi;
margin-bottom: 5cqi;
padding: 3.3cqi;
border: 1px solid var(--clr-glass-border);
border-radius: var(--radius-btn);
background: color-mix(in srgb, var(--clr-accent) 5%, #fff);
}
.stadionzeitung-gegner__club {
--crest-size: 12cqi;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.7cqi;
min-width: 0;
text-align: center;
}
.stadionzeitung-gegner__club strong {
font-size: 3.2cqi;
line-height: 1.15;
}
.stadionzeitung-gegner__club--own strong {
color: var(--clr-accent);
}
.stadionzeitung-gegner__match {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5cqi;
font-size: 2.5cqi;
color: var(--clr-text-muted);
white-space: nowrap;
}
.stadionzeitung-gegner__match strong {
font-size: 2.9cqi;
color: var(--clr-text);
}
.stadionzeitung-gegner__vergleich {
border-block: 1px solid var(--clr-glass-border);
}
.stadionzeitung-gegner__vergleich-head,
.stadionzeitung-gegner__vergleich-row {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
align-items: center;
text-align: center;
}
.stadionzeitung-gegner__vergleich-head {
padding-block: 1.7cqi;
font-size: 2.5cqi;
font-weight: var(--fw-bold);
text-transform: uppercase;
letter-spacing: var(--ls-caps);
color: var(--clr-text-muted);
}
.stadionzeitung-gegner__vergleich-row {
min-height: 6.5cqi;
border-top: 1px solid var(--clr-glass-border);
}
.stadionzeitung-gegner__vergleich-row span {
font-size: 2.8cqi;
color: var(--clr-text-muted);
}
.stadionzeitung-gegner__vergleich-row strong {
font-family: var(--ff-heading);
font-size: 4.8cqi;
line-height: 1;
}
.stadionzeitung-gegner__vergleich-row strong:first-child {
color: var(--clr-accent);
}
.stadionzeitung-gegner__empty {
padding: 4.2cqi;
border: 1px solid var(--clr-glass-border);
font-size: 3.3cqi;
color: var(--clr-text-muted);
text-align: center;
}
/* === 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),
@@ -8585,4 +8691,3 @@ body.lightbox-open {
overflow: hidden;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB