Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung

Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News,
Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover,
Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen
kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei
hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das
Skript selbst, statt sie von Hand zu prüfen.

Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus
über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit
Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie
doppelt gepflegt wird.

News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head.

Behobene Fehler:
- Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das
  Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen
  (Ergebnis-Rückblick, Vorschau, Cover).
- --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px
  Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links
  unter dem Logo.
- base_url in der Produktions-Config ohne www, während .htaccess auf www
  umleitet; preflight prüft das jetzt.
- .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen.

Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php
(Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit
Warnung, wenn base_url nicht auf die echte Domain zeigt).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
This commit is contained in:
2026-07-31 14:55:27 +02:00
parent 3fb480dd78
commit a101b0c3ec
861 changed files with 75244 additions and 487 deletions

View File

@@ -0,0 +1,112 @@
/* ============================================================
DATEIEN — Marken-Skin für die Dateiablage (Files Gallery, /dateien)
KEIN Teil des Seiten-Layouts und deshalb bewusst die 7. CSS-Datei: geladen wird
sie ausschließlich von storage/dateien/system/include/head.html, also in einem
fremden Dokument, das wir nicht rendern. Sie steht NACH der files.css der App und
gewinnt damit über die Variablen.
Zusammen mit tokens.css geladen (Farbwerte kommen von dort, nie als Hex von hier).
Die App ist durchgängig variablengesteuert — wir setzen deshalb ihre Variablen und
fassen ihre Selektoren fast nicht an. Das übersteht Updates.
============================================================ */
/* Die Schrift bleibt bewusst die der App (system-ui): ein Datei-Manager ist ein
Werkzeug, nicht eine Seite der Website — nah am Standard heißt hier vertraute
Bedienung, und die Systemschrift ist in kleinen Größen und langen Dateinamen
ohnehin robuster als unsere Abel. Die Marke tragen Wappen und Rot. */
:root {
/* Farbton der App auf das Markenrot ziehen. Die App leitet daraus Flächen,
Ränder und Ordnerfarben ab (hsl(var(--hue), 20%, …)) — alles bekommt einen
warmen Rotstich statt Blau, ohne dass wir einzelne Regeln überschreiben. */
--hue: var(--clr-accent-h);
/* Der Akzent selbst (Buttons, Links, Auswahl) exakt auf --clr-accent.
Die App wählt je Theme eine der drei Varianten. */
--hsl-primary-dark: var(--clr-accent-hsl);
--hsl-primary-light: var(--clr-accent-hsl);
--hsl-primary-contrast: var(--clr-accent-hsl);
/* --- Kontrast (gemessen, nicht geschätzt) ---
Die App leitet Flächen UND Ordnerfarben aus --hue ab. Mit dem Markenrot als
Farbton stand ein dunkelroter Ordner auf dunkelroter Fläche: 1,07:1, praktisch
unsichtbar. Deshalb hier drei Korrekturen. */
/* Flächen etwas tiefer als das Seiten-Grau (#222 ≈ 13 %): der Ordner ist ein
gefülltes Rot, und Rot ist von Natur aus dunkel — es braucht den Abstand nach
unten. Bei 13 % kommt das Rot nur auf 3,03:1, bei 10 % auf 3,30:1. */
--surface-base-lightness-dark: 10%;
/* Text heller als die Vorgabe der App (80 %): hebt Dateinamen auf 11,97:1 und
zieht die abgeleiteten Meta-Töne (Brotkrumen, Anzahl-Badge) mit nach oben. */
--text-base-lightness-dark: 88%;
/* Ordner im Markenrot. Vorderseite ist die große Fläche und trägt die Erkennbarkeit
(gemessen 3,91:1 — über den 3:1, die WCAG 1.4.11 für Grafik verlangt), Rückseite dunkler
als Kante. Erste Zeile ist der Fallback für Browser ohne color-mix(). */
--svg-folder-fg-dark: var(--clr-accent);
--svg-folder-fg-dark: color-mix(in srgb, var(--clr-accent) 80%, white);
--svg-folder-fg-large-dark: var(--clr-accent);
--svg-folder-fg-large-dark: color-mix(in srgb, var(--clr-accent) 80%, white);
--svg-folder-bg-dark: var(--clr-accent-dark);
--svg-folder-bg-large-dark: var(--clr-accent-dark);
}
/* --- Login-Seite ---
Die Login-Seite der App rendert nur „Einloggen" und ihr Formular; sie bindet
include/footer.html nicht ein (index.php:561 rendert eine eigene, knappe Seite) und
kennt keinen Platz für eigenes Markup. Damit man sieht, wessen Ablage das ist, kommt
das Vereinswappen als dekorative Fläche darüber — Bild statt CSS-Textinhalt, damit
nichts Sinntragendes im Stylesheet landet. */
.page-login-body .login-container::before {
content: '';
display: block;
width: 96px;
height: 124px;
margin: 0 auto 1.5rem;
background: url('../img/logo.svg') center / contain no-repeat;
}
/* --- Fußzeile (storage/dateien/system/include/footer.html) ---
.custom-footer-fixed ist der Hook der App (fest am unteren Rand, volle Breite).
Wir geben ihm nur Typografie und Abstand. */
.tsv-footer {
display: flex;
align-items: center;
justify-content: center;
padding: 0.375rem 1rem;
border-top: 2px solid hsl(var(--clr-accent-hsl));
line-height: 1.4;
}
.tsv-footer a {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--text1);
text-decoration: none;
white-space: nowrap;
}
/* Wappen in der Fußzeile: echtes <img> mit Maßen (kein Layout-Sprung), dekorativ —
der Linktext trägt die Bedeutung. Die offizielle `logo`-Option der App fällt hier
aus: sie wird über _c.config in js/custom.js gesetzt, und dieser Hook braucht wie
css/custom.css eine öffentliche URL, die unser storage_path nicht hat. */
.tsv-footer a img {
height: 2.6em; /* darunter wird das Wappen zum Fleck */
width: auto;
}
.tsv-footer a:hover,
.tsv-footer a:focus-visible {
color: hsl(var(--clr-accent-hsl));
text-decoration: underline;
}
/* Die App reserviert keinen Platz für die feste Fußzeile — sonst verschwindet die
letzte Dateizeile bzw. der letzte Menüpunkt darunter. */
#files-container,
#sidebar-inner {
padding-bottom: 4rem;
}