Stadionzeitung: Ergebnis- und Gegnerseite neu gestaltet
Ergebnisse laufen als Anzeigetafel (Wappen und Name je Seite, Ergebnis gross in der Mitte) statt als Listenzeilen. Verworfen und im CSS begruendet: Tore am rechten Blattrand, getoente Karten je Spiel, roter Strich unter der Mannschaftszeile, graue Verlierer-Ziffern. Vereinsnamen einzeilig, sonst ausgepunktet. Die Gegnerseite bekommt ein symmetrisches Duell, eine aus den Tabellenwerten abgeleitete Aufmacher-Zeile, den Vergleich als Balkenpaar aus der Mitte und einen Tabellenausschnitt ueber die geteilte league-table-Komponente. Die Balkenlaengen kommen aus Klassen in 5-Prozent-Stufen, nie aus einem style-Attribut (die CSP verwirft inline styles stillschweigend). Das Mitglied-werden-Poster sagt jetzt "Werde Teil unseres Vereins". Alle geaenderten Seiten auf A5-Hoehe nachgemessen, kein Ueberstand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv9SGDu3m3diiPrW9Fmj3v
This commit is contained in:
45
CLAUDE.md
45
CLAUDE.md
@@ -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`) und `cover` (`teaser` einer Sonderausgabe).** 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`, `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`) |
|
||||||
@@ -795,6 +795,49 @@ keinen farbigen Rahmen über das Spielerfoto** — der Kicker bleibt „Saison
|
|||||||
die Ausgabe nicht, in die die Felder gehören. `bin/preflight.php` prüft, dass der Slug und jeder
|
die Ausgabe nicht, in die die Felder gehören. `bin/preflight.php` prüft, dass der Slug und jeder
|
||||||
Turnier-Key wirklich existieren — ein Tippfehler ergäbe sonst eine **leere** A5-Seite ohne Fehler.
|
Turnier-Key wirklich existieren — ein Tippfehler ergäbe sonst eine **leere** A5-Seite ohne Fehler.
|
||||||
|
|
||||||
|
**Gegnerseiten ohne Fest, und der Anzeigename des Gegners (17.09.2026).** Zwei Felder, beide
|
||||||
|
chat-gepflegt und von `bin/stadionzeitung-add.php` über erneute Läufe durchgetragen wie `vorwort`:
|
||||||
|
|
||||||
|
- **`gegner_teams`** (Liste von Team-Keys) gibt weiteren Mannschaften eine Gegnerseite, ohne dass es
|
||||||
|
eine Veranstaltung braucht. Der Sportfest-Weg blieb unverändert daneben stehen (Heimspiele im
|
||||||
|
Festzeitraum); dieser hier nimmt das nächste Spiel im Fenster **zwei Tage vor bis drei Tage nach**
|
||||||
|
dem Ausgabedatum, **auch auswärts** — am normalen Spielwochenende fährt eine der drei Mannschaften
|
||||||
|
fast immer weg, und ihr Gegner ist trotzdem eine Seite wert. `stadionzeitung_gegner_fixtures()`
|
||||||
|
bleibt die eine entscheidende Stelle. Findet eine benannte Mannschaft kein Spiel im Fenster,
|
||||||
|
entsteht keine Seite und das Skript **warnt** — ein Tippfehler im Team-Key sähe sonst aus wie ein
|
||||||
|
spielfreies Wochenende. Auf der Gegnerseite steht seitdem **immer unsere Mannschaft links**
|
||||||
|
(Klasse `--own`), bei einem Auswärtsspiel läuft die Zeile „… bei …" statt „… gegen …"; vorher war
|
||||||
|
die linke Spalte fest die Heimmannschaft und die Hervorhebung lag beim Gegner.
|
||||||
|
- **`opponent_short`** ist der gedruckte Anzeigename des Gegners, gelesen über
|
||||||
|
**`stadionzeitung_opponent_display()`** (Cover, Archivzeile, Ausgaben-Kopf, Titel, Meta, Alt-Text
|
||||||
|
der Rückseite). **`opponent` selbst muss die BFV-Schreibweise behalten** — die Gegnerseite sucht
|
||||||
|
damit ihre Tabellenzeile und ihre Begegnung in `matchcenter.json` über einen exakten
|
||||||
|
Namensvergleich. Bei Spielgemeinschaften ist das eine Zeile wie „(SG1) TSV Wirsberg I/ FC
|
||||||
|
Kupferberg I", die auf einem Cover nichts zu suchen hat; `opponent_short` trägt dann
|
||||||
|
„Wirsberg/Kupferberg". Fehlt das Feld, bleibt es beim vollen Namen.
|
||||||
|
|
||||||
|
Nebenbei löst das oft die Seitenzahl: drei Gegnerseiten statt einer sind **zwei Seiten mehr**, und
|
||||||
|
ein Heft, das bei 42 stand, steht damit auf 44.
|
||||||
|
|
||||||
|
**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:
|
||||||
|
- **Ergebnisse als Anzeigetafel** (Vorbild kicker/Sofascore): Wappen und Name je Seite, das Ergebnis
|
||||||
|
groß in der Mitte. Vorher waren es Listenzeilen, und eine Zeile stellt Heim und Gast untereinander
|
||||||
|
statt gegenüber. Verworfen und nicht wieder einzubauen: Tore am rechten Blattrand (halbe
|
||||||
|
Seitenbreite Leere zwischen Name und Ziffer), eine getönte Karte je Spiel („altbacken"), ein roter
|
||||||
|
Strich unter der Mannschaftszeile (lauter als die Ergebnisse) und graue Verlierer-Ziffern (auf
|
||||||
|
Papier schlechter lesbar). Vereinsnamen laufen **einzeilig** und werden sonst ausgepunktet.
|
||||||
|
- **Gegnerseite**: Duell symmetrisch und leise (beide Wappen gleich groß, der Name des Gegners steht
|
||||||
|
nur in der Überschrift laut da), darunter eine abgeleitete Aufmacher-Zeile („Sieben Siege aus acht
|
||||||
|
Spielen", aus den Tabellenwerten gebaut), der Vergleich als **Balkenpaar aus der Mitte** und zum
|
||||||
|
Schluss ein **Tabellenausschnitt** über die geteilte `league-table`-Komponente. Der Tabellenplatz
|
||||||
|
steht bewusst dort und nicht als Balken (klein ist besser, der Balken läge falsch herum) und auch
|
||||||
|
nicht als lose Ziffer im Kopf (war gebaut, wirkte unruhig).
|
||||||
|
- **Balkenlängen kommen aus Klassen in 5-Prozent-Stufen**, nie aus einem `style`-Attribut — die CSP
|
||||||
|
verwirft inline styles stillschweigend, die Balken wären erst nach dem Deploy unsichtbar.
|
||||||
|
- Die Gegnerseite druckt **`opponent_display`** (Kurzname der Ausgabe, wenn die Seite den Gegner der
|
||||||
|
Ausgabe zeigt); `opponent` bleibt die BFV-Schreibweise für den Namensvergleich.
|
||||||
|
|
||||||
**Cover (automatisch generiert, Phase 3):** einzige fotografische Stadionzeitungs-Seite —
|
**Cover (automatisch generiert, Phase 3):** einzige fotografische Stadionzeitungs-Seite —
|
||||||
`app/components/stadionzeitung-cover.php`. Echtes Magazin-Cover statt Website-Baustein: **kein**
|
`app/components/stadionzeitung-cover.php`. Echtes Magazin-Cover statt Website-Baustein: **kein**
|
||||||
Stadionfoto mehr als Hintergrund, stattdessen ein ruhiger Verlauf in Vereinsfarben, auf dem das
|
Stadionfoto mehr als Hintergrund, stattdessen ein ruhiger Verlauf in Vereinsfarben, auf dem das
|
||||||
|
|||||||
@@ -40,19 +40,28 @@ $matchcenterLink = club_domain('matchcenter');
|
|||||||
<section class="stadionzeitung-ergebnisse__team">
|
<section class="stadionzeitung-ergebnisse__team">
|
||||||
<h3 class="stadionzeitung-ergebnisse__team-name"><?= e(trim(implode(' · ', array_filter([(string) ($group['team_name'] ?? ''), (string) ($group['league'] ?? '')])))) ?></h3>
|
<h3 class="stadionzeitung-ergebnisse__team-name"><?= e(trim(implode(' · ', array_filter([(string) ($group['team_name'] ?? ''), (string) ($group['league'] ?? '')])))) ?></h3>
|
||||||
<?php foreach ($group['matches'] ?? [] as $match): ?>
|
<?php foreach ($group['matches'] ?? [] as $match): ?>
|
||||||
<div class="stadionzeitung-ergebnisse__match">
|
<?php
|
||||||
<p class="stadionzeitung-ergebnisse__meta">
|
$sides = [
|
||||||
<?= e(trim((string) ($match['date_display'] ?? ''))) ?><?php if (($match['competition'] ?? 'Liga') !== 'Liga'): ?> · <?= e((string) $match['competition']) ?><?php endif; ?>
|
['club' => $match['home'] ?? '', 'crest' => $match['home_crest'] ?? null, 'goals' => $match['goals_home'] ?? null],
|
||||||
</p>
|
['club' => $match['away'] ?? '', 'crest' => $match['away_crest'] ?? null, 'goals' => $match['goals_away'] ?? null],
|
||||||
<?php foreach ([['club' => $match['home'] ?? '', 'crest' => $match['home_crest'] ?? null, 'goals' => $match['goals_home'] ?? null],
|
];
|
||||||
['club' => $match['away'] ?? '', 'crest' => $match['away_crest'] ?? null, 'goals' => $match['goals_away'] ?? null]] as $side): ?>
|
?>
|
||||||
<div class="stadionzeitung-ergebnisse__row<?= str_contains((string) $side['club'], 'TSV 08 Kulmbach') ? ' stadionzeitung-ergebnisse__row--own' : '' ?>">
|
<article class="stadionzeitung-ergebnisse__match">
|
||||||
|
<?php foreach ($sides as $i => $side): ?>
|
||||||
|
<?php if ($i === 1): ?>
|
||||||
|
<div class="stadionzeitung-ergebnisse__score">
|
||||||
|
<p class="stadionzeitung-ergebnisse__result">
|
||||||
|
<span class="stadionzeitung-ergebnisse__goals"><?= e((string) $sides[0]['goals']) ?></span><span class="stadionzeitung-ergebnisse__colon">:</span><span class="stadionzeitung-ergebnisse__goals"><?= e((string) $sides[1]['goals']) ?></span>
|
||||||
|
</p>
|
||||||
|
<p class="stadionzeitung-ergebnisse__meta"><?= e(trim((string) ($match['date_display'] ?? ''))) ?><?php if (($match['competition'] ?? 'Liga') !== 'Liga'): ?> · <?= e((string) $match['competition']) ?><?php endif; ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="stadionzeitung-ergebnisse__side<?= str_contains((string) $side['club'], 'TSV 08 Kulmbach') ? ' stadionzeitung-ergebnisse__side--own' : '' ?>">
|
||||||
<?php component('crest', ['src' => $side['crest'], 'name' => (string) $side['club']]); ?>
|
<?php component('crest', ['src' => $side['crest'], 'name' => (string) $side['club']]); ?>
|
||||||
<span class="stadionzeitung-ergebnisse__club"><?= e((string) $side['club']) ?></span>
|
<span class="stadionzeitung-ergebnisse__club"><?= e((string) $side['club']) ?></span>
|
||||||
<span class="stadionzeitung-ergebnisse__goals"><?= e((string) $side['goals']) ?></span>
|
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</article>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</section>
|
</section>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|||||||
@@ -18,15 +18,29 @@ $teamName = trim((string) ($info['team_name'] ?? ''));
|
|||||||
$fixture = is_array($info['fixture'] ?? null) ? $info['fixture'] : [];
|
$fixture = is_array($info['fixture'] ?? null) ? $info['fixture'] : [];
|
||||||
$own = is_array($info['own'] ?? null) ? $info['own'] : null;
|
$own = is_array($info['own'] ?? null) ? $info['own'] : null;
|
||||||
$opponent = is_array($info['opponent_stats'] ?? null) ? $info['opponent_stats'] : null;
|
$opponent = is_array($info['opponent_stats'] ?? null) ? $info['opponent_stats'] : null;
|
||||||
$opponentName = (string) ($info['opponent'] ?? 'Unser Gegner');
|
// Gedruckt wird der Anzeigename (Kurzname der Ausgabe, wenn gepflegt) — die
|
||||||
|
// BFV-Schreibweise „(SG1) TSV Wirsberg I/ FC Kupferberg I" ist ein Suchschlüssel,
|
||||||
|
// keine Überschrift.
|
||||||
|
$ausschnitt = is_array($info['table_excerpt'] ?? null) ? $info['table_excerpt'] : [];
|
||||||
|
$opponentName = (string) ($info['opponent_display'] ?? $info['opponent'] ?? 'Unser Gegner');
|
||||||
|
|
||||||
|
// Links steht IMMER unsere Mannschaft (Klasse --own hebt sie hervor), rechts der
|
||||||
|
// Gegner. Bei einem Heimspiel ist das ohnehin die Reihenfolge Heim/Gast; fährt die
|
||||||
|
// Mannschaft aber auswärts, trüge die Hervorhebung sonst der gegnerische Verein.
|
||||||
|
$istHeim = !empty($fixture['is_home']);
|
||||||
|
$ownName = (string) (($istHeim ? ($fixture['home'] ?? null) : ($fixture['away'] ?? null)) ?? 'TSV 08 Kulmbach');
|
||||||
|
$ownCrest = ($istHeim ? ($fixture['home_crest'] ?? null) : ($fixture['away_crest'] ?? null)) ?? $own['crest'] ?? null;
|
||||||
|
$gegnerLabel = $opponentName;
|
||||||
|
$gegnerCrest = ($istHeim ? ($fixture['away_crest'] ?? null) : ($fixture['home_crest'] ?? null)) ?? $opponent['crest'] ?? null;
|
||||||
|
|
||||||
$kickoff = (string) ($fixture['kickoff'] ?? '');
|
$kickoff = (string) ($fixture['kickoff'] ?? '');
|
||||||
$kickoffDate = $kickoff !== '' ? substr($kickoff, 0, 10) : '';
|
$kickoffDate = $kickoff !== '' ? substr($kickoff, 0, 10) : '';
|
||||||
$kickoffTime = $kickoff !== '' ? substr($kickoff, 11, 5) : '';
|
$kickoffTime = $kickoff !== '' ? substr($kickoff, 11, 5) : '';
|
||||||
|
|
||||||
|
// Der Tabellenplatz steht NICHT in der Balkenliste: klein ist dort besser,
|
||||||
|
// ein Balken läge genau falsch herum. Er gehört nach oben neben die Wappen.
|
||||||
|
// „Spiele“ fällt ebenfalls raus (für beide gleich, steht in der Kopfzeile).
|
||||||
$rows = [
|
$rows = [
|
||||||
['label' => 'Tabellenplatz', 'key' => 'rank'],
|
|
||||||
['label' => 'Spiele', 'key' => 'played'],
|
|
||||||
['label' => 'Siege', 'key' => 'won'],
|
['label' => 'Siege', 'key' => 'won'],
|
||||||
['label' => 'Unentschieden', 'key' => 'drawn'],
|
['label' => 'Unentschieden', 'key' => 'drawn'],
|
||||||
['label' => 'Niederlagen', 'key' => 'lost'],
|
['label' => 'Niederlagen', 'key' => 'lost'],
|
||||||
@@ -41,6 +55,57 @@ $format = static function (?array $row, string $key, bool $signed = false): stri
|
|||||||
$value = (int) $row[$key];
|
$value = (int) $row[$key];
|
||||||
return $signed && $value > 0 ? '+' . $value : (string) $value;
|
return $signed && $value > 0 ? '+' . $value : (string) $value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Balkenlänge als KLASSE, nie als style-Attribut: die CSP verwirft inline
|
||||||
|
// styles stillschweigend (siehe CLAUDE.md), der Balken wäre in Produktion
|
||||||
|
// unsichtbar. Deshalb 5-Prozent-Stufen, die components.css ausdefiniert.
|
||||||
|
$barStep = static function (?array $row, ?array $other, string $key): int {
|
||||||
|
if ($row === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$value = abs((int) ($row[$key] ?? 0));
|
||||||
|
$scale = max($value, $other === null ? 0 : abs((int) ($other[$key] ?? 0)));
|
||||||
|
if ($scale <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int) round($value / $scale * 20);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ein Satz statt einer Zahlenkolonne: derselbe Bestand, nur in Sprache. Die
|
||||||
|
// erste zutreffende Regel gewinnt, damit immer genau eine Aussage dasteht.
|
||||||
|
$zahlwort = static function (int $n): string {
|
||||||
|
$woerter = [0 => 'Kein', 1 => 'Ein', 2 => 'Zwei', 3 => 'Drei', 4 => 'Vier', 5 => 'Fünf',
|
||||||
|
6 => 'Sechs', 7 => 'Sieben', 8 => 'Acht', 9 => 'Neun', 10 => 'Zehn', 11 => 'Elf',
|
||||||
|
12 => 'Zwölf', 13 => 'Dreizehn', 14 => 'Vierzehn', 15 => 'Fünfzehn'];
|
||||||
|
return $woerter[$n] ?? (string) $n;
|
||||||
|
};
|
||||||
|
$aufmacher = '';
|
||||||
|
if ($opponent !== null) {
|
||||||
|
$played = (int) ($opponent['played'] ?? 0);
|
||||||
|
$won = (int) ($opponent['won'] ?? 0);
|
||||||
|
$lost = (int) ($opponent['lost'] ?? 0);
|
||||||
|
$rank = (int) ($opponent['rank'] ?? 0);
|
||||||
|
$points = (int) ($opponent['points'] ?? 0);
|
||||||
|
$diff = (int) ($opponent['goal_diff'] ?? 0);
|
||||||
|
if ($played > 0 && $lost === 0) {
|
||||||
|
$aufmacher = 'Noch ohne Niederlage';
|
||||||
|
} elseif ($played > 0 && $won === 0) {
|
||||||
|
$aufmacher = 'Noch ohne Sieg';
|
||||||
|
} elseif ($played > 0 && $won / $played >= 0.7) {
|
||||||
|
$aufmacher = $zahlwort($won) . ' Siege aus ' . mb_strtolower($zahlwort($played)) . ' Spielen';
|
||||||
|
} elseif ($rank === 1) {
|
||||||
|
$aufmacher = 'Tabellenführer mit ' . $points . ' Punkten';
|
||||||
|
} elseif ($played > 0 && $diff <= -8) {
|
||||||
|
$aufmacher = $zahlwort(abs($diff)) . ' Tore mehr kassiert als geschossen';
|
||||||
|
} elseif ($played > 0 && $diff >= 8) {
|
||||||
|
$aufmacher = $zahlwort($diff) . ' Tore mehr geschossen als kassiert';
|
||||||
|
} elseif ($played > 0) {
|
||||||
|
$aufmacher = $points . ' Punkte aus ' . $played . ' Spielen';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$spieltagInfo = $opponent !== null && (int) ($opponent['played'] ?? 0) > 0
|
||||||
|
? 'Stand nach ' . (int) $opponent['played'] . ' Spieltagen'
|
||||||
|
: '';
|
||||||
?>
|
?>
|
||||||
<div class="stadionzeitung-gegner">
|
<div class="stadionzeitung-gegner">
|
||||||
<header class="stadionzeitung-page__head">
|
<header class="stadionzeitung-page__head">
|
||||||
@@ -53,25 +118,26 @@ $format = static function (?array $row, string $key, bool $signed = false): stri
|
|||||||
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
|
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
|
||||||
|
|
||||||
<div class="stadionzeitung-gegner__duell">
|
<div class="stadionzeitung-gegner__duell">
|
||||||
<div class="stadionzeitung-gegner__club stadionzeitung-gegner__club--own">
|
<div class="stadionzeitung-gegner__club">
|
||||||
<?php component('crest', ['src' => $fixture['home_crest'] ?? $own['crest'] ?? null, 'name' => $fixture['home'] ?? 'TSV 08 Kulmbach']); ?>
|
<?php component('crest', ['src' => $ownCrest, 'name' => $ownName]); ?>
|
||||||
<strong><?= e((string) ($fixture['home'] ?? 'TSV 08 Kulmbach')) ?></strong>
|
<span class="stadionzeitung-gegner__club-name"><?= e($ownName) ?></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stadionzeitung-gegner__match">
|
<div class="stadionzeitung-gegner__vs">
|
||||||
<span>gegen</span>
|
<p class="stadionzeitung-gegner__vs-wort"><?= $istHeim ? 'gegen' : 'bei' ?></p>
|
||||||
<?php if ($kickoffDate !== ''): ?>
|
<?php if ($kickoffDate !== ''): ?>
|
||||||
<strong><?= e(german_date($kickoffDate)) ?></strong>
|
<p class="stadionzeitung-gegner__anstoss"><?= e(german_date($kickoffDate)) ?><?php if ($kickoffTime !== ''): ?><br><?= e($kickoffTime) ?> Uhr<?php endif; ?></p>
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($kickoffTime !== ''): ?>
|
|
||||||
<span><?= e($kickoffTime) ?> Uhr</span>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="stadionzeitung-gegner__club">
|
<div class="stadionzeitung-gegner__club">
|
||||||
<?php component('crest', ['src' => $fixture['away_crest'] ?? $opponent['crest'] ?? null, 'name' => $fixture['away'] ?? $opponentName]); ?>
|
<?php component('crest', ['src' => $gegnerCrest, 'name' => $gegnerLabel]); ?>
|
||||||
<strong><?= e((string) ($fixture['away'] ?? $opponentName)) ?></strong>
|
<span class="stadionzeitung-gegner__club-name"><?= e($gegnerLabel) ?></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if ($aufmacher !== ''): ?>
|
||||||
|
<p class="stadionzeitung-gegner__aufmacher"><?= e($aufmacher) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($own !== null && $opponent !== null): ?>
|
<?php if ($own !== null && $opponent !== null): ?>
|
||||||
<div class="stadionzeitung-gegner__vergleich" role="table" aria-label="Tabellenvergleich">
|
<div class="stadionzeitung-gegner__vergleich" role="table" aria-label="Tabellenvergleich">
|
||||||
<div class="stadionzeitung-gegner__vergleich-head" role="row">
|
<div class="stadionzeitung-gegner__vergleich-head" role="row">
|
||||||
@@ -79,18 +145,33 @@ $format = static function (?array $row, string $key, bool $signed = false): stri
|
|||||||
Markup — das Kürzel des Marktschorgast-Gegners wäre in jeder Ausgabe
|
Markup — das Kürzel des Marktschorgast-Gegners wäre in jeder Ausgabe
|
||||||
mitgedruckt worden. Die Überschrift nennt den Gegner ohnehin. */ ?>
|
mitgedruckt worden. Die Überschrift nennt den Gegner ohnehin. */ ?>
|
||||||
<span role="columnheader">Wir</span>
|
<span role="columnheader">Wir</span>
|
||||||
<span role="columnheader">Vergleich</span>
|
<span role="columnheader"><?= e($spieltagInfo !== '' ? $spieltagInfo : 'Vergleich') ?></span>
|
||||||
<span role="columnheader">Gegner</span>
|
<span role="columnheader">Gegner</span>
|
||||||
</div>
|
</div>
|
||||||
<?php foreach ($rows as $row): ?>
|
<?php foreach ($rows as $row): ?>
|
||||||
<div class="stadionzeitung-gegner__vergleich-row" role="row">
|
<div class="stadionzeitung-gegner__vergleich-row" role="row">
|
||||||
<strong role="cell"><?= e($format($own, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
|
<strong class="stadionzeitung-gegner__wert" role="cell"><?= e($format($own, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
|
||||||
<span role="rowheader"><?= e((string) $row['label']) ?></span>
|
<span class="stadionzeitung-gegner__balken stadionzeitung-gegner__balken--own" aria-hidden="true"><span class="stadionzeitung-gegner__balken-fuellung stadionzeitung-gegner__balken-fuellung--s<?= $barStep($own, $opponent, (string) $row['key']) ?>"></span></span>
|
||||||
<strong role="cell"><?= e($format($opponent, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
|
<span class="stadionzeitung-gegner__label" role="rowheader"><?= e((string) $row['label']) ?></span>
|
||||||
|
<span class="stadionzeitung-gegner__balken" aria-hidden="true"><span class="stadionzeitung-gegner__balken-fuellung stadionzeitung-gegner__balken-fuellung--s<?= $barStep($opponent, $own, (string) $row['key']) ?>"></span></span>
|
||||||
|
<strong class="stadionzeitung-gegner__wert" role="cell"><?= e($format($opponent, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p class="stadionzeitung-gegner__empty">Die aktuellen Vergleichsdaten waren beim letzten Abruf nicht verfügbar.</p>
|
<p class="stadionzeitung-gegner__empty">Die aktuellen Vergleichsdaten waren beim letzten Abruf nicht verfügbar.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php /* Der Tabellenplatz stand kurz als zwei lose Ziffern oben im Duell und
|
||||||
|
wirkte dort unruhig (Felix, 19.09.2026). Hier zeigt ihn der Ausschnitt
|
||||||
|
im Zusammenhang: wer steht zwischen uns und ihnen. Gerendert mit der
|
||||||
|
geteilten league-table-Komponente, nie mit einer zweiten Tabelle. */ ?>
|
||||||
|
<?php if ($ausschnitt !== []): ?>
|
||||||
|
<div class="stadionzeitung-gegner__ausschnitt">
|
||||||
|
<p class="stadionzeitung-gegner__ausschnitt-titel">Die Tabelle dazwischen</p>
|
||||||
|
<?php foreach ($ausschnitt as $block): ?>
|
||||||
|
<?php component('league-table', ['table' => $block, 'caption' => 'Tabellenausschnitt ' . (string) ($info['league'] ?? '')]); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mitglied-werden-Seite der Stadionzeitung (Live-Seite) — Poster statt Liste:
|
* Mitglied-werden-Seite der Stadionzeitung (Live-Seite) — Poster statt Liste:
|
||||||
* riesige zentrierte Coolvetica-Headline („Werde Teil des Nullachters", das
|
* riesige zentrierte Coolvetica-Headline („Werde Teil unseres Vereins", das
|
||||||
* letzte Wort in Vereinsrot), darunter Claim-Satz und Abteilungszeile,
|
* letzte Wort in Vereinsrot), darunter Claim-Satz und Abteilungszeile,
|
||||||
* unten der geteilte CTA-Fuß mit QR auf /mitglied-werden. Fester Baustein
|
* unten der geteilte CTA-Fuß mit QR auf /mitglied-werden. Fester Baustein
|
||||||
* jeder Ausgabe (bin/stadionzeitung-add.php plant sie nach den
|
* jeder Ausgabe (bin/stadionzeitung-add.php plant sie nach den
|
||||||
@@ -25,8 +25,8 @@ $mitgliedLink = club_domain('mitglied-werden');
|
|||||||
<img class="stadionzeitung-mitglied__logo" src="<?= e(asset('img/logo.svg')) ?>" alt="" width="75" height="97">
|
<img class="stadionzeitung-mitglied__logo" src="<?= e(asset('img/logo.svg')) ?>" alt="" width="75" height="97">
|
||||||
<h2 class="stadionzeitung-mitglied__headline">
|
<h2 class="stadionzeitung-mitglied__headline">
|
||||||
<span class="stadionzeitung-mitglied__line">Werde Teil</span>
|
<span class="stadionzeitung-mitglied__line">Werde Teil</span>
|
||||||
<span class="stadionzeitung-mitglied__line">des</span>
|
<span class="stadionzeitung-mitglied__line">unseres</span>
|
||||||
<span class="stadionzeitung-mitglied__line stadionzeitung-mitglied__line--accent">Nullachters</span>
|
<span class="stadionzeitung-mitglied__line stadionzeitung-mitglied__line--accent">Vereins</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p class="stadionzeitung-mitglied__claim">Seit 1908 in Kulmbach zuhause. Egal ob auf dem Platz, in der Halle oder am Spielfeldrand: bei uns ist Platz für dich.</p>
|
<p class="stadionzeitung-mitglied__claim">Seit 1908 in Kulmbach zuhause. Egal ob auf dem Platz, in der Halle oder am Spielfeldrand: bei uns ist Platz für dich.</p>
|
||||||
<p class="stadionzeitung-mitglied__departments">Fußball · Jugend · Turnen</p>
|
<p class="stadionzeitung-mitglied__departments">Fußball · Jugend · Turnen</p>
|
||||||
|
|||||||
@@ -7261,74 +7261,136 @@ a.news-feature__link:hover .news-feature__more {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* === stadionzeitung-ergebnisse (Live-Seite) === */
|
/* === stadionzeitung-ergebnisse (Live-Seite) === */
|
||||||
/* Ergebnis-Rückblick: zwei Zeilen pro Spiel (Heim über Gast, wie das
|
/* Ergebnis-Rückblick als Anzeigetafel: Wappen und Vereinsname je Seite, das
|
||||||
„Nächste Spiele"-Band) — lange Vereinsnamen passen auf der schmalen
|
Ergebnis groß in der Mitte (Vorbild kicker/Sofascore). Vierter Entwurf,
|
||||||
A5-Seite nie in eine Zeile. Eigene Mannschaft über Gewicht der Body-Schrift
|
19.09.2026 — die drei Vorgänger scheiterten alle an derselben Ursache:
|
||||||
markiert (Abel hat echte Schnitte — anders als Coolvetica erlaubt, siehe
|
sie waren Listenzeilen, und eine Zeile stellt Heim und Gast untereinander
|
||||||
CLAUDE.md „nie über font-weight" bei Coolvetica). */
|
statt gegenüber, obwohl eine Begegnung etwas Symmetrisches ist. Mit den
|
||||||
|
Toren rechts am Blattrand lag halbe Seitenbreite Leere zwischen Name und
|
||||||
|
Ziffer, eine getönte Karte dagegen sah „altbacken" aus, und mit den Toren
|
||||||
|
links fehlte der Seite die Hierarchie.
|
||||||
|
|
||||||
|
Die Mittelachse löst zusätzlich das Namensproblem: lange Namen wie
|
||||||
|
„(SG1) TSV Melkendorf III/ TSV 08 Kulmbach II" umbrechen in ihrer Spalte
|
||||||
|
über mehrere Zeilen, ohne dass irgendetwas verrutscht — deshalb steht der
|
||||||
|
Name UNTER dem Wappen und mittig, nicht daneben.
|
||||||
|
|
||||||
|
Flächen gibt es keine, nur Linien: Haarlinie zwischen den Begegnungen,
|
||||||
|
roter Strich unter der Mannschaftszeile, sonst weißes Blatt. */
|
||||||
|
/* Trennung der Mannschaften: Haarlinie plus reichlich Abstand auf beiden
|
||||||
|
Seiten. Die Linie liegt am Abschnitt, nicht an der letzten Begegnung darin —
|
||||||
|
sonst wanderte sie bei mehreren Spielen pro Mannschaft mitten in den Block. */
|
||||||
.stadionzeitung-ergebnisse__team {
|
.stadionzeitung-ergebnisse__team {
|
||||||
margin-bottom: 4.2cqi;
|
padding-bottom: 4.6cqi;
|
||||||
}
|
margin-bottom: 4.6cqi;
|
||||||
|
|
||||||
.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);
|
border-bottom: 1px solid var(--clr-glass-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-ergebnisse__match:last-child {
|
.stadionzeitung-ergebnisse__team:last-of-type {
|
||||||
|
padding-bottom: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-ergebnisse__meta {
|
/* Mannschaftszeile bewusst leise: die Gliederung macht der Abstand zwischen
|
||||||
font-size: 2.5cqi;
|
den Mannschaften, keine Linie (ein roter Strich darunter war gebaut und am
|
||||||
|
19.09.2026 wieder entfernt — er zog mehr Aufmerksamkeit als die Ergebnisse
|
||||||
|
darunter). */
|
||||||
|
.stadionzeitung-ergebnisse__team-name {
|
||||||
|
margin-bottom: 1.6cqi;
|
||||||
|
font-family: var(--ff-body);
|
||||||
|
font-size: 2.4cqi;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--ls-caps);
|
||||||
color: var(--clr-text-faint);
|
color: var(--clr-text-faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Das Zeilen-Layout gehört auf die ZEILE, nicht auf das Wappen darin (stand
|
.stadionzeitung-ergebnisse__match {
|
||||||
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;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1.7cqi;
|
gap: 2.1cqi;
|
||||||
padding-block: 0.6cqi;
|
padding-block: 1.4cqi;
|
||||||
|
border-bottom: 1px solid var(--clr-glass-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-ergebnisse__match:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Beide Seiten sind gleich gebaut und gleich breit (1fr), damit die Mittelachse
|
||||||
|
wirklich in der Mitte liegt — auch wenn eine Spielgemeinschaft drei Zeilen
|
||||||
|
Namen mitbringt und der Gegner eine. `--crest-size` setzt der Kontext, die
|
||||||
|
crest-Komponente bleibt dumm (gleiches Muster wie in allen anderen
|
||||||
|
Wappen-Kontexten). */
|
||||||
|
.stadionzeitung-ergebnisse__side {
|
||||||
|
--crest-size: 8.5cqi;
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
gap: 1.2cqi;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Einzeilig, notfalls ausgepunktet: ein umbrechender Name schiebt die
|
||||||
|
Anzeigetafel auseinander und die Zeilenpaare stehen dann ungleich hoch
|
||||||
|
nebeneinander. Die volle Schreibweise steht ohnehin im Matchcenter. */
|
||||||
.stadionzeitung-ergebnisse__club {
|
.stadionzeitung-ergebnisse__club {
|
||||||
min-width: 0;
|
max-width: 100%;
|
||||||
font-size: 3.75cqi;
|
overflow: hidden;
|
||||||
line-height: 1.2;
|
font-size: 3.2cqi;
|
||||||
|
line-height: 1.15;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-ergebnisse__row--own .stadionzeitung-ergebnisse__club {
|
.stadionzeitung-ergebnisse__side--own .stadionzeitung-ergebnisse__club {
|
||||||
font-weight: var(--fw-bold);
|
font-weight: var(--fw-bold);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-ergebnisse__goals {
|
.stadionzeitung-ergebnisse__score {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
gap: 0.8cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-ergebnisse__result {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.8cqi;
|
||||||
font-family: var(--ff-heading);
|
font-family: var(--ff-heading);
|
||||||
font-size: 5.8cqi;
|
font-size: 7.4cqi;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Das Ergebnis läuft durchgehend in voller Textfarbe: eine zurückgenommene
|
||||||
|
Verlierer-Ziffer war gebaut und am 19.09.2026 verworfen (Felix) — auf dem
|
||||||
|
gedruckten Blatt ist eine graue Ziffer schlechter lesbar, und wer gewonnen
|
||||||
|
hat, sagt die Zahl selbst. */
|
||||||
|
.stadionzeitung-ergebnisse__meta {
|
||||||
|
font-size: 2.5cqi;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--ls-caps);
|
||||||
|
color: var(--clr-text-faint);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* === stadionzeitung-gegner (Live-Seite) === */
|
/* === stadionzeitung-gegner (Live-Seite) === */
|
||||||
|
/* Gegnerseite als Duell-Aufmacher plus Balkenvergleich (19.09.2026). Vorher
|
||||||
|
war das eine rosa getönte Karte mit der Begegnung und darunter eine
|
||||||
|
Zahlenkolonne aus sieben Zeilen: inhaltlich richtig, gestalterisch ohne
|
||||||
|
Blickfang, und die untere Blatthälfte blieb leer.
|
||||||
|
|
||||||
|
Drei Entscheidungen tragen den Aufbau:
|
||||||
|
- Das GEGNERWAPPEN ist der Bildanker (deutlich größer als unseres). Die
|
||||||
|
Seite handelt von ihm, nicht von der Begegnung.
|
||||||
|
- Der Tabellenplatz steht oben bei den Wappen, NICHT als Balken: dort ist
|
||||||
|
klein besser, ein Balken läge genau falsch herum.
|
||||||
|
- Der Vergleich läuft als Balkenpaar aus der Mitte (Vorbild Sofascore).
|
||||||
|
Die Länge kommt aus einer KLASSE in 5-Prozent-Stufen, nie aus einem
|
||||||
|
style-Attribut: die CSP verwirft inline styles stillschweigend, der
|
||||||
|
Balken wäre in Produktion unsichtbar (siehe CLAUDE.md). */
|
||||||
.stadionzeitung-gegner {
|
.stadionzeitung-gegner {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
@@ -7336,90 +7398,204 @@ a.news-feature__link:hover .news-feature__more {
|
|||||||
.stadionzeitung-gegner__duell {
|
.stadionzeitung-gegner__duell {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: start;
|
||||||
gap: 2.5cqi;
|
gap: 2.5cqi;
|
||||||
margin-bottom: 5cqi;
|
margin-top: 2.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Beide Seiten sind gleich gebaut und gleich groß. Der Gegner war hier kurz
|
||||||
|
mit doppelt so großem Wappen und seinem Namen in Coolvetica gesetzt — damit
|
||||||
|
stand er zweimal laut auf derselben Seite (Überschrift und Duell) und das
|
||||||
|
Blatt wirkte unruhig (Felix, 19.09.2026). Die Überschrift nennt ihn, das
|
||||||
|
Duell zeigt nur noch, wer gegen wen und auf welchem Platz. */
|
||||||
.stadionzeitung-gegner__club {
|
.stadionzeitung-gegner__club {
|
||||||
--crest-size: 12cqi;
|
--crest-size: 11cqi;
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-rows: auto minmax(7.4cqi, auto);
|
||||||
align-items: center;
|
justify-items: center;
|
||||||
gap: 1.7cqi;
|
gap: 1.2cqi;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__club strong {
|
.stadionzeitung-gegner__club-name {
|
||||||
font-size: 3.2cqi;
|
font-size: 3.2cqi;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__club--own strong {
|
/* Mittelspalte: „gegen" und der Anstoß stehen zusammen, damit im Duell nur
|
||||||
color: var(--clr-accent);
|
noch drei Dinge auf einer Höhe liegen (wir, wann, sie). Zwei lose
|
||||||
}
|
Platz-Ziffern und eine freistehende Datumszeile standen hier kurz und
|
||||||
|
machten den Kopf unruhig (Felix, 19.09.2026) — der Tabellenplatz steht
|
||||||
.stadionzeitung-gegner__match {
|
jetzt im Ausschnitt unter den Balken. */
|
||||||
display: flex;
|
.stadionzeitung-gegner__vs {
|
||||||
flex-direction: column;
|
display: grid;
|
||||||
align-items: center;
|
justify-items: center;
|
||||||
gap: 0.5cqi;
|
gap: 1.2cqi;
|
||||||
font-size: 2.5cqi;
|
padding-top: 3.3cqi;
|
||||||
color: var(--clr-text-muted);
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__match strong {
|
.stadionzeitung-gegner__vs-wort {
|
||||||
font-size: 2.9cqi;
|
font-size: 2.7cqi;
|
||||||
color: var(--clr-text);
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--ls-caps);
|
||||||
|
color: var(--clr-text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__anstoss {
|
||||||
|
font-size: 2.7cqi;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--clr-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Im Ausschnitt entfällt die Zonen-Legende: sie erklärt Auf- und Abstieg,
|
||||||
|
und das ist die Aufgabe der vollständigen Tabellenseite weiter hinten im
|
||||||
|
Heft. Hier geht es nur um die Nachbarschaft der beiden Mannschaften. */
|
||||||
|
.stadionzeitung-gegner__ausschnitt {
|
||||||
|
margin-top: 3.3cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__ausschnitt .league-table__legend {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Der Ausschnitt läuft eine Spur enger als die vollständige Tabellenseite:
|
||||||
|
er teilt sich das Blatt mit Duell, Aufmacher und Balken. Gemessen: mit den
|
||||||
|
Maßen der Tabellenseite stand die Seite 16px über der A5-Kante. */
|
||||||
|
.stadionzeitung-gegner__ausschnitt .league-table th,
|
||||||
|
.stadionzeitung-gegner__ausschnitt .league-table td {
|
||||||
|
padding: 0.7cqi 0.9cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__ausschnitt .league-table tbody .crest {
|
||||||
|
--crest-size: 4cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__ausschnitt-titel {
|
||||||
|
margin-bottom: 1.4cqi;
|
||||||
|
font-size: 2.4cqi;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--ls-caps);
|
||||||
|
color: var(--clr-text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zwei Blöcke (wenn die Mannschaften weit auseinanderliegen) bekommen Luft
|
||||||
|
dazwischen, sonst sähe es aus wie eine durchgehende Tabelle mit Sprung. */
|
||||||
|
.stadionzeitung-gegner__ausschnitt .table-scroll-frame + .table-scroll-frame {
|
||||||
|
margin-top: 2.1cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die Tabelle in einem Satz: derselbe Bestand, nur in Sprache. Coolvetica
|
||||||
|
trägt hier, weil die Zeile kurz ist und nie umbricht. */
|
||||||
|
.stadionzeitung-gegner__aufmacher {
|
||||||
|
margin-top: 3.3cqi;
|
||||||
|
padding-top: 2.5cqi;
|
||||||
|
border-top: 0.5cqi solid var(--clr-accent);
|
||||||
|
font-family: var(--ff-heading);
|
||||||
|
font-size: 5.8cqi;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: var(--ls-heading);
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich {
|
.stadionzeitung-gegner__vergleich {
|
||||||
border-block: 1px solid var(--clr-glass-border);
|
margin-top: 2.5cqi;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-head,
|
.stadionzeitung-gegner__vergleich-head,
|
||||||
.stadionzeitung-gegner__vergleich-row {
|
.stadionzeitung-gegner__vergleich-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 2fr 1fr;
|
grid-template-columns: 6cqi minmax(0, 1fr) 24cqi minmax(0, 1fr) 6cqi;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 1.7cqi;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-head {
|
.stadionzeitung-gegner__vergleich-head {
|
||||||
padding-block: 1.7cqi;
|
padding-bottom: 1.4cqi;
|
||||||
font-size: 2.5cqi;
|
margin-bottom: 1.4cqi;
|
||||||
font-weight: var(--fw-bold);
|
border-bottom: 1px solid var(--clr-glass-border);
|
||||||
|
font-size: 2.4cqi;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: var(--ls-caps);
|
letter-spacing: var(--ls-caps);
|
||||||
color: var(--clr-text-muted);
|
color: var(--clr-text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die beiden äußeren Spaltenköpfe sitzen über den Zahlen, der mittlere über
|
||||||
|
dem Label — deshalb spannt er über die drei inneren Spalten. */
|
||||||
|
.stadionzeitung-gegner__vergleich-head span:nth-child(2) {
|
||||||
|
grid-column: 2 / 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-row {
|
.stadionzeitung-gegner__vergleich-row {
|
||||||
min-height: 6.5cqi;
|
min-height: 5.8cqi;
|
||||||
border-top: 1px solid var(--clr-glass-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-row span {
|
.stadionzeitung-gegner__wert {
|
||||||
|
font-family: var(--ff-heading);
|
||||||
|
font-size: 4.4cqi;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__label {
|
||||||
font-size: 2.8cqi;
|
font-size: 2.8cqi;
|
||||||
color: var(--clr-text-muted);
|
color: var(--clr-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-row strong {
|
/* Balkenpaar: der linke wächst aus der Mitte nach links, der rechte nach
|
||||||
font-family: var(--ff-heading);
|
rechts. Die Spur bleibt sichtbar (helle Fläche), damit auch ein Wert von
|
||||||
font-size: 4.8cqi;
|
null als Zeile lesbar ist. */
|
||||||
line-height: 1;
|
.stadionzeitung-gegner__balken {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
block-size: 2.2cqi;
|
||||||
|
border-radius: 1.1cqi;
|
||||||
|
background: var(--clr-glass-border);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stadionzeitung-gegner__vergleich-row strong:first-child {
|
.stadionzeitung-gegner__balken--own {
|
||||||
color: var(--clr-accent);
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stadionzeitung-gegner__balken-fuellung {
|
||||||
|
display: block;
|
||||||
|
block-size: 100%;
|
||||||
|
border-radius: 1.1cqi;
|
||||||
|
background: var(--clr-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unsere Seite rot, die des Gegners schwarz: die einzige Farbe der Seite
|
||||||
|
steht damit bei uns, ohne dass Rot Fließtext tragen müsste. */
|
||||||
|
.stadionzeitung-gegner__balken--own .stadionzeitung-gegner__balken-fuellung {
|
||||||
|
background: var(--clr-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5-Prozent-Stufen, siehe Kommentar oben (kein style-Attribut). */
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s0 { inline-size: 0%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s1 { inline-size: 5%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s2 { inline-size: 10%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s3 { inline-size: 15%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s4 { inline-size: 20%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s5 { inline-size: 25%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s6 { inline-size: 30%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s7 { inline-size: 35%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s8 { inline-size: 40%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s9 { inline-size: 45%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s10 { inline-size: 50%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s11 { inline-size: 55%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s12 { inline-size: 60%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s13 { inline-size: 65%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s14 { inline-size: 70%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s15 { inline-size: 75%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s16 { inline-size: 80%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s17 { inline-size: 85%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s18 { inline-size: 90%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s19 { inline-size: 95%; }
|
||||||
|
.stadionzeitung-gegner__balken-fuellung--s20 { inline-size: 100%; }
|
||||||
|
|
||||||
.stadionzeitung-gegner__empty {
|
.stadionzeitung-gegner__empty {
|
||||||
padding: 4.2cqi;
|
padding: 4.2cqi;
|
||||||
border: 1px solid var(--clr-glass-border);
|
border: 1px solid var(--clr-glass-border);
|
||||||
|
|||||||
Reference in New Issue
Block a user