Stadionzeitung Untersteinach vorbereiten und Instagram aktualisieren

This commit is contained in:
2026-10-16 22:50:26 +02:00
parent 5a107a955a
commit 33b73087cf
33 changed files with 773 additions and 3 deletions

View File

@@ -54,7 +54,7 @@ selbst gehosteter Stack ohne Abhängigkeiten von Drittanbietern.
| Partner/Sponsoren | `data/partners.json` | — | | Partner/Sponsoren | `data/partners.json` | — |
| Instagram-Beiträge | `data/instagram.json` + `public/assets/img/instagram/` | Aufgenommen ausschließlich mit **`php bin/instagram-add.php <post-url>`** (holt Bild, Text und Datum) — Einträge nie von Hand tippen, Bilder nie von Hand skalieren. **Kein Cron**, chat-gepflegt wie `events.json`. Eintrag und Bild müssen immer zusammen existieren, `bin/preflight.php` prüft beide Richtungen | | Instagram-Beiträge | `data/instagram.json` + `public/assets/img/instagram/` | Aufgenommen ausschließlich mit **`php bin/instagram-add.php <post-url>`** (holt Bild, Text und Datum) — Einträge nie von Hand tippen, Bilder nie von Hand skalieren. **Kein Cron**, chat-gepflegt wie `events.json`. Eintrag und Bild müssen immer zusammen existieren, `bin/preflight.php` prüft beide Richtungen |
| Matchcenter (Spiele/Ergebnisse/Tabellen) | `data/matchcenter.json` + `public/assets/img/crests/` | **maschinenverwaltet von `bin/matchcenter-sync.php` — nie von Hand editieren**. Team-/Wettbewerbs-IDs in `config.php` (`matchcenter.teams`) | | Matchcenter (Spiele/Ergebnisse/Tabellen) | `data/matchcenter.json` + `public/assets/img/crests/` | **maschinenverwaltet von `bin/matchcenter-sync.php` — nie von Hand editieren**. Team-/Wettbewerbs-IDs in `config.php` (`matchcenter.teams`) |
| Stadionzeitung (Ausgaben-Archiv) | `data/stadionzeitung.json` + `public/assets/img/stadionzeitung/` | **maschinenverwaltet von `bin/stadionzeitung-add.php` + `bin/stadionzeitung-publish.php` (Status/Snapshot) — nie von Hand editieren; einzige Chat-Pflege-Ausnahmen sind `vorwort`, `interview`, `aufruf`, `veranstaltung` (Slug-Verweis auf `veranstaltungen.json`), `cover` (`teaser` einer Sonderausgabe), `opponent_short` (gedruckter Anzeigename des Gegners) und `gegner_teams` (weitere Mannschaften mit Gegnerseite).** Der Ausgaben-Ordner wird bei jedem Lauf komplett geleert und neu gefüllt | | Stadionzeitung (Ausgaben-Archiv) | `data/stadionzeitung.json` + `public/assets/img/stadionzeitung/` | **maschinenverwaltet von `bin/stadionzeitung-add.php` + `bin/stadionzeitung-publish.php` (Status/Snapshot) — nie von Hand editieren; einzige Chat-Pflege-Ausnahmen sind `vorwort`, `interview`, `aufruf`, `rueckblick` (Text/Bildnachweis; `image` bleibt script-verwaltet), `veranstaltung` (Slug-Verweis auf `veranstaltungen.json`), `cover` (`teaser` einer Sonderausgabe), `opponent_short` (gedruckter Anzeigename des Gegners) und `gegner_teams` (weitere Mannschaften mit Gegnerseite).** Der Ausgaben-Ordner wird bei jedem Lauf komplett geleert und neu gefüllt |
| Sponsoren-Anzeigen (Stadionzeitung) | `data/anzeigen.json` + `public/assets/img/anzeigen/` | Dauerhafter Bestand, **nicht** pro Ausgabe: Motive ändern sich selten, das Heft erscheint oft. `sponsor`, `alt` (optional), `aktiv`, `bis` (optional, Enddatum gegen das Ausgabedatum), `platzierung` (optional, fester Platz auf einer Live-Seite statt im Streu-Pool) und die **Reihenfolge** (= Reihenfolge im Heft) im Chat gepflegt; `base`/`widths` schreibt ausschließlich `bin/anzeige-add.php`. Anzeigen nie in den Ausgaben-Ordner legen | | Sponsoren-Anzeigen (Stadionzeitung) | `data/anzeigen.json` + `public/assets/img/anzeigen/` | Dauerhafter Bestand, **nicht** pro Ausgabe: Motive ändern sich selten, das Heft erscheint oft. `sponsor`, `alt` (optional), `aktiv`, `bis` (optional, Enddatum gegen das Ausgabedatum), `platzierung` (optional, fester Platz auf einer Live-Seite statt im Streu-Pool) und die **Reihenfolge** (= Reihenfolge im Heft) im Chat gepflegt; `base`/`widths` schreibt ausschließlich `bin/anzeige-add.php`. Anzeigen nie in den Ausgaben-Ordner legen |
| Termine/Events (`/termine`) | `data/events.json` (Vereins-Termine **ohne** eigene Detailseite) — Spieltermine kommen weiterhin nur aus `data/matchcenter.json`, Feste mit eigener Seite nur aus `data/veranstaltungen.json`; die Termine-Seite mergt alle drei | Von Claude im Chat gepflegt wie `teams.json`/`partners.json` — **keine** Automatisierung, kein Bin-Skript. Spieltermine nie hier duplizieren. Ein Fest, das eine Detailseite hat, steht **nur** in `veranstaltungen.json` (`bin/preflight.php` prüft das) | | Termine/Events (`/termine`) | `data/events.json` (Vereins-Termine **ohne** eigene Detailseite) — Spieltermine kommen weiterhin nur aus `data/matchcenter.json`, Feste mit eigener Seite nur aus `data/veranstaltungen.json`; die Termine-Seite mergt alle drei | Von Claude im Chat gepflegt wie `teams.json`/`partners.json` — **keine** Automatisierung, kein Bin-Skript. Spieltermine nie hier duplizieren. Ein Fest, das eine Detailseite hat, steht **nur** in `veranstaltungen.json` (`bin/preflight.php` prüft das) |
| Veranstaltungen (`/veranstaltungen` + Detailseiten) | `data/veranstaltungen.json` + `public/assets/img/veranstaltungen/` | Termin, Texte, Programm, Turnierpläne (`turniere[]`, nur fürs Heft), Abschnitte von Claude im Chat gepflegt — **außer `plakate` und `galerie`: die schreibt ausschließlich `bin/veranstaltung-bilder.php`**. Adresse nie in die Texte schreiben (steht in `club.json`) | | Veranstaltungen (`/veranstaltungen` + Detailseiten) | `data/veranstaltungen.json` + `public/assets/img/veranstaltungen/` | Termin, Texte, Programm, Turnierpläne (`turniere[]`, nur fürs Heft), Abschnitte von Claude im Chat gepflegt — **außer `plakate` und `galerie`: die schreibt ausschließlich `bin/veranstaltung-bilder.php`**. Adresse nie in die Texte schreiben (steht in `club.json`) |
@@ -834,6 +834,19 @@ Raster: 6×4-Gitter, das erste Foto 4×2, die Anordnung je Anzahl (1 bis 7) als
`__bento--nN` mit `grid-template-areas`. Entstanden als Füllseite, die eine 43-seitige Ausgabe `__bento--nN` mit `grid-template-areas`. Entstanden als Füllseite, die eine 43-seitige Ausgabe
auf 44 brachte. auf 44 brachte.
**Redaktioneller Spielrückblick (16.10.2026).** Optionales Feld `rueckblick` einer Ausgabe:
`kicker`, `heading`, `meta`, `result`, `paragraphs[]`, `credit`, `source_url`
sind Chat-Pflege; `image` (inklusive chat-gepflegtem Alt-Text) verwaltet das Add-Skript aus
`<ordner>/rueckblick.*`. Die Live-Seite steht nach den Ergebnissen, vor der Galerie. Das Foto
liegt dauerhaft im Ausgaben-Ordner. Bei erneutem Erzeugen muss die Quelle wieder mitgeliefert
werden; fehlt sie, bricht das Skript vor dem Leeren des Zielordners ab. Preflight prüft Foto
und Bildnachweis. Der gemeinsame Bild-/Textnachweis steht einmal direkt unter dem Foto
(im Web zur Quelle verlinkt, auch im Druck lesbar). Kein Bild hochskalieren oder fremd einbinden.
Für die Untersteinach-Ausgabe: öffentliches Derby-Vorschaubild
`https://www.anpfiff.info/upload/images/Teaser8/843447.jpg` (560 × 270), Bildquelle anpfiff.info.
Felix hat die Nutzungsgenehmigung im Chat am 16.10.2026 bestätigt. Ein individueller Fotograf
ist am frei sichtbaren Bild nicht ausgewiesen; deshalb keinen Namen vermuten.
**Gegner- und Ergebnisseite neu gestaltet (19.09.2026).** Beide Seiten waren inhaltlich richtig und **Gegner- und Ergebnisseite neu gestaltet (19.09.2026).** Beide Seiten waren inhaltlich richtig und
gestalterisch leer, der Umbau lief über mehrere verworfene Entwürfe. Was davon bleibt: gestalterisch leer, der Umbau lief über mehrere verworfene Entwürfe. Was davon bleibt:
- **Ergebnisse als Anzeigetafel** (Vorbild kicker/Sofascore): Wappen und Name je Seite, das Ergebnis - **Ergebnisse als Anzeigetafel** (Vorbild kicker/Sofascore): Wappen und Name je Seite, das Ergebnis

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/** Redaktioneller Spielrückblick. Text/Quelle: Chat-Pflege; image: add-Skript. */
$rueckblick = $issue['rueckblick'] ?? [];
$sourceUrl = (string) ($rueckblick['source_url'] ?? '');
$sourceLink = filter_var($sourceUrl, FILTER_VALIDATE_URL)
&& in_array(parse_url($sourceUrl, PHP_URL_SCHEME), ['https', 'http'], true);
?>
<div class="stadionzeitung-rueckblick">
<header class="stadionzeitung-page__head">
<p class="stadionzeitung-page__kicker"><?= e((string) ($rueckblick['kicker'] ?? 'Rückblick')) ?></p>
<h2 class="stadionzeitung-page__heading"><?= e((string) ($rueckblick['heading'] ?? '')) ?></h2>
</header>
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
<div class="stadionzeitung-rueckblick__scoreline">
<p class="stadionzeitung-ergebnisse__result"><?= e((string) ($rueckblick['result'] ?? '')) ?></p>
<p class="stadionzeitung-page__sub"><?= e((string) ($rueckblick['meta'] ?? '')) ?></p>
</div>
<figure class="stadionzeitung-rueckblick__figure">
<?php component('img', [
'image' => $rueckblick['image'],
'sizes' => '(min-width: 520px) 430px, 90vw',
'class' => 'stadionzeitung-rueckblick__foto',
'eager' => $eager ?? false,
]); ?>
<figcaption class="stadionzeitung-rueckblick__credit">
<?php if ($sourceLink): ?>
<a href="<?= e($sourceUrl) ?>" target="_blank" rel="noopener noreferrer"><?= e((string) ($rueckblick['credit'] ?? '')) ?></a>
<?php else: ?>
<?= e((string) ($rueckblick['credit'] ?? '')) ?>
<?php endif; ?>
</figcaption>
</figure>
<div class="stadionzeitung-rueckblick__text">
<?php foreach ($rueckblick['paragraphs'] ?? [] as $paragraph): ?>
<p class="stadionzeitung-vorwort__text"><?= e((string) $paragraph) ?></p>
<?php endforeach; ?>
</div>
</div>

View File

@@ -100,6 +100,9 @@ $type = $entry['type'] ?? 'image';
<?php case 'galerie': ?> <?php case 'galerie': ?>
<?php component('stadionzeitung-galerie', ['issue' => $issue]); ?> <?php component('stadionzeitung-galerie', ['issue' => $issue]); ?>
<?php break; ?> <?php break; ?>
<?php case 'rueckblick': ?>
<?php component('stadionzeitung-rueckblick', ['issue' => $issue, 'eager' => $eager]); ?>
<?php break; ?>
<?php case 'momente': ?> <?php case 'momente': ?>
<?php component('stadionzeitung-momente', ['items' => $data['momente'] ?? []]); ?> <?php component('stadionzeitung-momente', ['items' => $data['momente'] ?? []]); ?>
<?php break; ?> <?php break; ?>

View File

@@ -393,6 +393,21 @@ if (is_file($szFile)) {
if (is_file($szFile)) { if (is_file($szFile)) {
$szData = $szData ?? (json_decode((string) file_get_contents($szFile), true) ?: []); $szData = $szData ?? (json_decode((string) file_get_contents($szFile), true) ?: []);
foreach ($szData['issues'] ?? [] as $ausgabe) { foreach ($szData['issues'] ?? [] as $ausgabe) {
if (is_array($ausgabe['rueckblick'] ?? null)) {
$rueckblick = $ausgabe['rueckblick'];
$foto = $rueckblick['image'] ?? [];
if (empty($foto['base']) || empty($foto['widths'])) {
$errors[] = "Stadionzeitung '{$ausgabe['slug']}': Foto zum Spielrückblick fehlt.";
}
foreach ($foto['widths'] ?? [] as $w) {
if (!is_file(PUBLIC_PATH . '/assets/' . ($foto['base'] ?? '') . "-{$w}.jpg")) {
$errors[] = "Stadionzeitung '{$ausgabe['slug']}': Rückblick-Foto fehlt ({$w}px).";
}
}
if (trim((string) ($rueckblick['credit'] ?? '')) === '') {
$errors[] = "Stadionzeitung '{$ausgabe['slug']}': Bildnachweis zum Spielrückblick fehlt.";
}
}
foreach ($ausgabe['galerie']['bilder'] ?? [] as $bild) { foreach ($ausgabe['galerie']['bilder'] ?? [] as $bild) {
foreach ($bild['widths'] ?? [] as $w) { foreach ($bild['widths'] ?? [] as $w) {
$datei = PUBLIC_PATH . '/assets/' . ($bild['base'] ?? '') . "-{$w}.jpg"; $datei = PUBLIC_PATH . '/assets/' . ($bild['base'] ?? '') . "-{$w}.jpg";

View File

@@ -160,6 +160,7 @@ $vorwort = $findOne('vorwort');
$rueckseite = $findOne('rueckseite'); $rueckseite = $findOne('rueckseite');
$spieler = $findOne('spieler'); $spieler = $findOne('spieler');
$verfasser = $findOne('verfasser'); $verfasser = $findOne('verfasser');
$rueckblickFoto = $findOne('rueckblick');
$galerieQuellen = $findAll('galerie'); $galerieQuellen = $findAll('galerie');
// Anzeigen kommen NICHT mehr aus dem Ablieferordner, sondern aus dem dauerhaften // Anzeigen kommen NICHT mehr aus dem Ablieferordner, sondern aus dem dauerhaften
// Bestand (data/anzeigen.json, gepflegt über bin/anzeige-add.php). Ein noch // Bestand (data/anzeigen.json, gepflegt über bin/anzeige-add.php). Ein noch
@@ -213,6 +214,10 @@ $oldOpponentShort = $oldIssue['opponent_short'] ?? null;
// Galerie-Seite: Kopf (kicker/heading/text) und Alt-Texte sind Chat-Pflege, // Galerie-Seite: Kopf (kicker/heading/text) und Alt-Texte sind Chat-Pflege,
// die Bilder schreibt dieser Lauf aus <ordner>/galerie/ (siehe unten). // die Bilder schreibt dieser Lauf aus <ordner>/galerie/ (siehe unten).
$oldGalerie = is_array($oldIssue['galerie'] ?? null) ? $oldIssue['galerie'] : null; $oldGalerie = is_array($oldIssue['galerie'] ?? null) ? $oldIssue['galerie'] : null;
$rueckblick = is_array($oldIssue['rueckblick'] ?? null) ? $oldIssue['rueckblick'] : null;
if ($rueckblick !== null && $rueckblickFoto === null) {
$fail('Spielrückblick vorhanden, aber rueckblick.* fehlt im Ablieferordner.');
}
$oldGegnerTeams = is_array($oldIssue['gegner_teams'] ?? null) ? array_values($oldIssue['gegner_teams']) : null; $oldGegnerTeams = is_array($oldIssue['gegner_teams'] ?? null) ? array_values($oldIssue['gegner_teams']) : null;
$veranstaltung = null; $veranstaltung = null;
if (is_string($oldVeranstaltung) && $oldVeranstaltung !== '') { if (is_string($oldVeranstaltung) && $oldVeranstaltung !== '') {
@@ -437,6 +442,13 @@ try {
$bloecke[] = ['name' => 'ergebnisse', 'seiten' => [$live('ergebnisse')], 'anzeigen_danach' => true]; $bloecke[] = ['name' => 'ergebnisse', 'seiten' => [$live('ergebnisse')], 'anzeigen_danach' => true];
// Redaktioneller Spielrückblick: Text und Bildnachweis sind Chat-Pflege,
// das Foto kommt aus dem Ablieferordner und bleibt in dieser Ausgabe.
if ($rueckblick !== null) {
$rueckblick['image'] = $bild($rueckblickFoto, 'rueckblick', (string) ($rueckblick['image']['alt'] ?? $rueckblick['heading'] ?? 'Spielrückblick'));
$bloecke[] = ['name' => 'rueckblick', 'seiten' => [$live('rueckblick')], 'anzeigen_danach' => true];
}
// Galerie direkt hinter dem Ergebnis-Rückblick: erst das Ergebnis, dann die // Galerie direkt hinter dem Ergebnis-Rückblick: erst das Ergebnis, dann die
// Bilder dazu. Eigener Block, eine Anzeige dazwischen ist unbedenklich. // Bilder dazu. Eigener Block, eine Anzeige dazwischen ist unbedenklich.
if (!empty($galerie['bilder'])) { if (!empty($galerie['bilder'])) {
@@ -830,6 +842,7 @@ $issues[] = [
'veranstaltung' => $oldVeranstaltung, 'veranstaltung' => $oldVeranstaltung,
'cover' => $oldCover, 'cover' => $oldCover,
'galerie' => $galerie, 'galerie' => $galerie,
'rueckblick' => $rueckblick,
'verfasser_photo' => $verfasserPhoto, 'verfasser_photo' => $verfasserPhoto,
'termine_snapshot' => $termineSnapshot, 'termine_snapshot' => $termineSnapshot,
'images' => $images, 'images' => $images,

View File

@@ -1,7 +1,43 @@
{ {
"fetched_at": 1791023677, "fetched_at": 1792183583,
"username": "tsv08kulmbach", "username": "tsv08kulmbach",
"posts": [ "posts": [
{
"shortcode": "DehQgDrDB0Z",
"caption": "🔴⚫️ Vorschau",
"alt": "🔴⚫️ Vorschau",
"taken_at": 1792077339,
"is_video": false,
"image": "img/instagram/DehQgDrDB0Z.jpg",
"url": "https://www.instagram.com/p/DehQgDrDB0Z/"
},
{
"shortcode": "DeeldfjMZEm",
"caption": "Neue Trikots für unsere E-Jugend! ⚽️😍\n„Euer Ort, euer Verein, euer Trikot“ – unter diesem Motto sorgt die bundesweite TUI-Aktion auch beim TSV 08 Kulmbach für strahlende Gesichter! 👕😊\nDas ReiseCenter Schaffranek sicherte sich unter mehr als 500 Bewerbern einen von 200 Trikotsätzen. Wer sich darüber freuen durfte, entschieden anschließend die Verantwortlichen im ReiseCenter per Los: Sie befüllten die Lostrommel mit den Namen aller Vereine im Kulmbacher Stadtgebiet, die Jugendarbeit bis zur E-Jugend anbieten, und führten die Ziehung durch. Das gezogene Los: TSV 08 Kulmbach! 🍀🙌\nMelanie Schaffranek überreichte die neuen Trikots bei unserem E-Jugendfestival und konnte unsere Nachwuchskicker direkt darin in Aktion erleben. ⚽\nEin herzliches Dankeschön an TUI sowie an Melanie Schaffranek und das gesamte Team des ReiseCenter Schaffranek für diese tolle Unterstützung unserer Jugendarbeit! ❤️🖤\nUnsere E-Jugend trägt das TUI-Lächeln ab sofort auf dem Trikot – und die Freude darüber im Gesicht! 😃\n\n#tsv08kulmbach #jugendfussball #reisetui \nDanke @reisebuero_schaffranek",
"alt": "Neue Trikots für unsere E-Jugend! ⚽️😍",
"taken_at": 1791987664,
"is_video": false,
"image": "img/instagram/DeeldfjMZEm.jpg",
"url": "https://www.instagram.com/p/DeeldfjMZEm/"
},
{
"shortcode": "DePJUbkjKPc",
"caption": "🔴⚫️ Vorschau",
"alt": "🔴⚫️ Vorschau",
"taken_at": 1791469594,
"is_video": false,
"image": "img/instagram/DePJUbkjKPc.jpg",
"url": "https://www.instagram.com/p/DePJUbkjKPc/"
},
{
"shortcode": "DeG8wTzjAVR",
"caption": "Ergebnisse vom Wochenende 🔴⚫️\n\nDerbysieg für unsere Erste 🤹🏻‍♂️ und unsere Frauen bleiben weiterhin ungeschlagen! 💪🏻",
"alt": "Ergebnisse vom Wochenende 🔴⚫️",
"taken_at": 1791194571,
"is_video": false,
"image": "img/instagram/DeG8wTzjAVR.jpg",
"url": "https://www.instagram.com/p/DeG8wTzjAVR/"
},
{ {
"shortcode": "Dd9tmXplrZx", "shortcode": "Dd9tmXplrZx",
"caption": "🔴⚫️ Vorschau inkl. Stadtderby 🔥", "caption": "🔴⚫️ Vorschau inkl. Stadtderby 🔥",

View File

@@ -1,5 +1,616 @@
{ {
"issues": [ "issues": [
{
"slug": "2026-10-17-sv-fortuna-untersteinach",
"opponent": "SV Fortuna Untersteinach",
"opponent_short": null,
"gegner_teams": [
"zweite-mannschaft",
"damen"
],
"date": "2026-10-17",
"team_key": "erste-mannschaft",
"status": "entwurf",
"pages": 44,
"player_image": {
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/spieler",
"widths": [
320,
640,
1000
],
"ext": "png",
"alt": ""
},
"qr_image": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/qr.png",
"vorwort": {
"heading": "Willkommen zum Heimspiel",
"paragraphs": [
"Liebe Fußballfreunde,",
"herzlich willkommen im Katzbachtal! Wir begrüßen unsere Gäste aus Untersteinach, ihre mitgereisten Fans und den Schiedsrichter.",
"Nach dem tragischen Todesfall in der Mannschaft aus Bischofsgrün war die Absage unseres letzten Spiels selbstverständlich. Unsere Gedanken sind bei den Angehörigen und der Mannschaft.",
"Heute empfangen wir mit Untersteinach einen Gegner, der bislang eine starke Saison spielt. Unsere Jungs haben im Training konzentriert gearbeitet und wollen nun vor heimischem Publikum daran anknüpfen. Unterstützt sie lautstark und bleibt fair. Auf geht’s!"
],
"closing": "Rot-schwarze Grüße",
"signee_name": "Benedikt Höfner",
"signee_role": "Sportlicher Leiter"
},
"interview": {
"teaser": "Unser Trainer Ali Kilic über die Trainingswoche und das Heimspiel gegen Untersteinach",
"heading": "Zwei Fragen an Ali Kilic",
"person_name": "Ali Kilic",
"person_role": "Trainer 1. Mannschaft",
"intro": null,
"fragen": [
{
"frage": "Wie hat die Mannschaft diese Trainingswoche gearbeitet?",
"antwort": "Wir hatten eine gute Trainingswoche und haben konzentriert gearbeitet. Die Jungs haben gut mitgezogen. Jetzt kommt es darauf an, das auch im Spiel umzusetzen. Wir wollen von Anfang an wach sein, uns gegenseitig unterstützen und gemeinsam in die Partie finden. Es wird sicher auch Phasen geben, in denen nicht alles klappt. Dann müssen wir dranbleiben und als Mannschaft zusammenhalten. Wir wollen unseren Zuschauern ein gutes Heimspiel zeigen und die Arbeit aus dem Training auf den Platz bringen."
},
{
"frage": "Was erwartest du von Untersteinach?",
"antwort": "Untersteinach spielt bisher eine sehr gute Saison. Wir haben Respekt vor ihnen und wissen, dass wir als Mannschaft eine gute Leistung brauchen. Wir müssen aufmerksam sein, die Zweikämpfe annehmen und dürfen ihnen keine einfachen Möglichkeiten geben. Gleichzeitig wollen wir unser eigenes Spiel aufziehen und unsere Chancen nutzen. Dafür brauchen wir auch mit dem Ball Ruhe und den Mut, nach vorne zu spielen. Wir spielen zu Hause und wollen hier etwas holen. Entscheidend wird sein, dass wir über die gesamte Partie zusammenarbeiten und jeder für den anderen da ist."
}
],
"photo": "img/persons/ali-kilic.jpg"
},
"aufruf": null,
"veranstaltung": null,
"cover": null,
"galerie": {
"kicker": "Rückblick",
"heading": "Unterwegs in Kirchleus",
"bilder": [
{
"source": "01-IMG_0586_01.jpg",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/galerie-01",
"widths": [
640,
1200
],
"alt": "Einer unserer Spieler holt in Kirchleus zum Schuss aus, ein Gegenspieler kommt einen Schritt zu spät."
},
{
"source": "02-IMG_0692_01.jpg",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/galerie-02",
"widths": [
640,
1200
],
"alt": "Zweikampf um den Ball: Einer unserer Spieler setzt sich gegen einen Kirchleuser durch."
},
{
"source": "03-IMG_0565_01.jpg",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/galerie-03",
"widths": [
640,
1200
],
"alt": "Einer unserer Spieler treibt den Ball nach vorne, ein Kirchleuser läuft heran."
},
{
"source": "04-IMG_0612_01.jpg",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/galerie-04",
"widths": [
640,
1200
],
"alt": "An der Eckfahne nimmt einer unserer Spieler den Ball an."
},
{
"source": "05-IMG_0571_01.jpg",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/galerie-05",
"widths": [
640,
1200
],
"alt": "Einer unserer Spieler läuft in der Herbstsonne über den Platz."
}
],
"text": "Ein Rückblick auf unser Auswärtsspiel am 27. September beim 1. FC Kirchleus, das wir knapp mit 2:3 verloren haben."
},
"rueckblick": {
"kicker": "Derby-Rückblick",
"heading": "Derbysieg im Katzbachtal",
"meta": "TSV 08 Kulmbach – VfB Kulmbach · 3. Oktober 2026",
"result": "2:0",
"paragraphs": [
"Das Stadtderby blieb lange offen. Der VfB hatte vor allem in der ersten Halbzeit mehr vom Spiel. Auch nach der Pause mussten unsere Jungs zunächst dagegenhalten.",
"Mit zunehmender Spielzeit fand unsere Mannschaft besser in die Partie und entschied das Derby mit zwei späten Treffern für sich. Am Ende standen ein Heimsieg, drei Punkte und eine weiße Weste."
],
"credit": "Quelle: anpfiff.info",
"source_url": "https://www.anpfiff.info/sites/fb/spielbericht.aspx?SK=6&Lg=118&Sp=1153653&Ver=784&TmHm=1265&TmGt=1225&Top=2&Ticker=1&Men=0",
"image": {
"type": "image",
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/rueckblick",
"widths": [
480,
560
],
"alt": "Zweikampf zwischen einem Spieler des TSV 08 Kulmbach in Rot und einem Spieler des VfB Kulmbach in Blau beim Stadtderby am 3. Oktober 2026."
}
},
"verfasser_photo": {
"base": "img/stadionzeitung/2026-10-17-sv-fortuna-untersteinach/verfasser",
"widths": [
120,
222
],
"alt": ""
},
"termine_snapshot": [
{
"date": "2026-10-24",
"date_end": null,
"title": "TSV 08 Kulmbach – TDC Lindau 2",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Kreisklasse",
"href": "/matchcenter",
"kickoff": "2026-10-24T14:00",
"team_name": "1. Mannschaft",
"league": "Kreisklasse",
"raw": {
"kickoff": "2026-10-24T14:00",
"date_display": "Sa, 24.10.",
"time_display": "14:00 Uhr",
"competition": "Liga",
"home": "TSV 08 Kulmbach",
"away": "TDC Lindau 2",
"home_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK3G000019VV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "erste-mannschaft",
"team_name": "1. Mannschaft"
}
},
{
"date": "2026-10-24",
"date_end": null,
"title": "1. FC Trogen (flex) – TSV 08 Kulmbach",
"department": "fussball",
"type": "spiel",
"meta": "Auswärtsspiel · Frauen KL Ost",
"href": "/matchcenter",
"kickoff": "2026-10-24T17:00",
"team_name": "Frauenmannschaft",
"league": "Frauen KL Ost",
"raw": {
"kickoff": "2026-10-24T17:00",
"date_display": "Sa, 24.10.",
"time_display": "17:00 Uhr",
"competition": "Liga",
"home": "1. FC Trogen (flex)",
"away": "TSV 08 Kulmbach",
"home_crest": "img/crests/00ES8GNK9O00001CVV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"is_home": false,
"team_key": "damen",
"team_name": "Frauenmannschaft"
}
},
{
"date": "2026-11-01",
"date_end": null,
"title": "TSV 08 Kulmbach – SSV Schwarzenbach a.Wald",
"department": "fussball",
"type": "spiel",
"meta": "Heimspiel · Frauen KL Ost",
"href": "/matchcenter",
"kickoff": "2026-11-01T10:30",
"team_name": "Frauenmannschaft",
"league": "Frauen KL Ost",
"raw": {
"kickoff": "2026-11-01T10:30",
"date_display": "So, 01.11.",
"time_display": "10:30 Uhr",
"competition": "Liga",
"home": "TSV 08 Kulmbach",
"away": "SSV Schwarzenbach a.Wald",
"home_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK9O00000PVV0AG08LVUPGND5I.png",
"is_home": true,
"team_key": "damen",
"team_name": "Frauenmannschaft"
}
},
{
"date": "2026-11-01",
"date_end": null,
"title": "SV Hutschdorf – TSV 08 Kulmbach",
"department": "fussball",
"type": "spiel",
"meta": "Auswärtsspiel · Kreisklasse",
"href": "/matchcenter",
"kickoff": "2026-11-01T14:00",
"team_name": "1. Mannschaft",
"league": "Kreisklasse",
"raw": {
"kickoff": "2026-11-01T14:00",
"date_display": "So, 01.11.",
"time_display": "14:00 Uhr",
"competition": "Liga",
"home": "SV Hutschdorf",
"away": "TSV 08 Kulmbach",
"home_crest": "img/crests/00ES8GNK3G00000LVV0AG08LVUPGND5I.png",
"away_crest": "img/crests/00ES8GNK3G000012VV0AG08LVUPGND5I.png",
"is_home": false,
"team_key": "erste-mannschaft",
"team_name": "1. Mannschaft"
}
},
{
"date": "2027-02-20",
"date_end": null,
"title": "Tagesskifahrt 2027",
"department": "verein",
"type": "event",
"meta": "Skigebiet Hochzillertal",
"href": "/veranstaltungen/tagesskifahrt-2027",
"time": "",
"location": "Skigebiet Hochzillertal",
"raw": {
"slug": "tagesskifahrt-2027",
"title": "Tagesskifahrt 2027",
"date_start": "2027-02-20",
"date_end": null,
"time": "",
"location": "Skigebiet Hochzillertal",
"department": "verein",
"status": "veroeffentlicht",
"text": "Wir fahren für einen Tag zum Skifahren ins Skigebiet Hochzillertal. Die Plätze sind auf 40 Personen begrenzt, angemeldet wird bei Fabian Früh.",
"ankuendigung": [
"Einmal im Winter machen wir uns gemeinsam auf und fahren für einen Tag ins Skigebiet Hochzillertal bei Kaltenbach. Ob Erwachsene, Jugendliche oder Kinder: Auf den Pisten ist für alle etwas dabei. Die Fahrt ist auf 40 Personen begrenzt, wer dabei sein möchte, meldet sich am besten früh.",
"Erwachsene zahlen 115 Euro, Jugendliche 95 Euro und Kinder 70 Euro. Anmelden könnt ihr euch bei Fabian Früh unter 0160 97516797."
],
"rueckblick": null,
"karte": "",
"anfahrt": [],
"plakate": [
{
"base": "img/veranstaltungen/tagesskifahrt-2027/plakat-01",
"widths": [
640,
1000,
1024
],
"alt": "Plakat zu unserer Tagesskifahrt am Samstag, 20. Februar 2027 ins Skigebiet Hochzillertal, mit den Preisen für Erwachsene, Jugendliche und Kinder und der Anmeldung bei Fabian Früh.",
"source": "1-ankuendigung.jpeg"
}
],
"galerie": []
}
}
],
"images": [
{
"type": "live",
"page": "cover"
},
{
"type": "live",
"page": "vorwort"
},
{
"type": "live",
"page": "interview"
},
{
"type": "image",
"base": "img/anzeigen/eldorado",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: eldorado Radsporttechnik Kulmbach"
},
{
"type": "image",
"base": "img/anzeigen/egu",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Erfrischungsgetränke-Union Kulmbacher Gruppe GmbH"
},
{
"type": "live",
"page": "ergebnisse"
},
{
"type": "image",
"base": "img/anzeigen/hofmann-graef",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Buchhandlung Hofmann, Kulmbach, und Automobilwerkstatt Gräf, Thurnau"
},
{
"type": "live",
"page": "rueckblick"
},
{
"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": "galerie"
},
{
"type": "image",
"base": "img/anzeigen/apotheken-wenkel",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Apotheke im Fritz, Stadtpark Apotheke und Schlüsseldienst Wenkel, Kulmbach"
},
{
"type": "live",
"page": "gegner",
"team": "erste-mannschaft"
},
{
"type": "image",
"base": "img/anzeigen/karl-geyer",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Geyer Farbe + Raum, Kulmbach, Starthilfe Boden"
},
{
"type": "image",
"base": "img/anzeigen/gsb",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: GSB Security und GSB Gebäude Service, Bindlach"
},
{
"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/physiofit-wohlfart",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Physio Fit Neudrossenfeld und Textilpflege Wohlfart, Kulmbach"
},
{
"type": "live",
"page": "vorschau"
},
{
"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": "termine"
},
{
"type": "image",
"base": "img/anzeigen/mattis-ka2",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Karl Mattis Flaschnerei und KA2 Fitness, Kulmbach"
},
{
"type": "live",
"page": "news"
},
{
"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": "kontakt"
},
{
"type": "image",
"base": "img/anzeigen/trapper-verkehrsakademie",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Trapper GmbH Entsorgungsfachbetrieb und Verkehrsakademie, Kulmbach"
},
{
"type": "live",
"page": "mitglied"
},
{
"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": "image",
"base": "img/anzeigen/hanft",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Hanft Bürotechnik GmbH, Kulmbach"
},
{
"type": "live",
"page": "historie"
},
{
"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/gagel-pickelmann",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Gagel Bäder und Mineralölhandel Pickelmann"
},
{
"type": "live",
"page": "partner"
},
{
"type": "live",
"page": "danke",
"anzeige": {
"base": "img/anzeigen/emons",
"widths": [
480,
960,
1141
],
"alt": "Anzeige: Emons Spedition Himmelkron, Ihr Partner für nationale und internationale Transporte"
}
},
{
"type": "image",
"base": "img/anzeigen/schramm",
"widths": [
480,
960,
1440
],
"alt": "Anzeige: Landgasthof und Metzgerei Schramm, Forstlahm"
},
{
"type": "live",
"page": "momente"
},
{
"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-10-17-sv-fortuna-untersteinach/rueckseite",
"widths": [
480,
960,
1410
],
"alt": "Rückseite der Stadionzeitung gegen SV Fortuna Untersteinach"
}
]
},
{ {
"slug": "2026-10-03-vfb-kulmbach", "slug": "2026-10-03-vfb-kulmbach",
"opponent": "VfB Kulmbach", "opponent": "VfB Kulmbach",
@@ -8085,4 +8696,4 @@
} }
} }
] ]
} }

View File

@@ -8628,6 +8628,44 @@ p.stadionzeitung-turnier__label:first-of-type {
object-fit: cover; object-fit: cover;
} }
/* === stadionzeitung-rueckblick (redaktionelle Seite mit Bildnachweis) === */
.stadionzeitung-rueckblick {
display: flex;
flex-direction: column;
min-height: 100%;
}
/* Kopf/Trennlinie, Ergebnis und Fließtext verwenden die vorhandenen
Heft-Klassen. Hier nur die Anordnung von Bild und Ergebnis definieren. */
.stadionzeitung-rueckblick__scoreline {
display: flex;
align-items: center;
gap: 4cqi;
margin-bottom: 4cqi;
}
.stadionzeitung-rueckblick__scoreline .stadionzeitung-ergebnisse__result {
flex: 0 0 auto;
margin: 0;
}
.stadionzeitung-rueckblick__figure {
margin: 0 0 3cqi;
}
.stadionzeitung-rueckblick__foto {
display: block;
width: 100%;
height: auto;
}
.stadionzeitung-rueckblick__credit {
font-size: 2.5cqi;
line-height: 1.4;
color: var(--clr-text-muted);
margin-top: 1cqi;
}
/* === stadionzeitung-galerie (Live-Seite, optional: Fotos vom letzten Spiel) === */ /* === stadionzeitung-galerie (Live-Seite, optional: Fotos vom letzten Spiel) === */
/* Bento-Raster auf einem 6×4-Gitter: das erste Foto ist der Aufmacher (4×2), /* Bento-Raster auf einem 6×4-Gitter: das erste Foto ist der Aufmacher (4×2),
die übrigen legen sich je nach Anzahl darum. Die Fläche unter dem Kopf gehört die übrigen legen sich je nach Anzahl darum. Die Fläche unter dem Kopf gehört

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

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