14 Commits

Author SHA1 Message Date
fs
25f36e5a53 Karten-Innenabstände fluid: mehr Platz auf schmalen Handys
Auf schmalen Bildschirmen stapeln sich Container- und Kartenabstand so, dass für
den Inhalt kaum Breite bleibt. Gemessen bei 309px: Container 11,5 + Karte 32 je
Seite, das Eingabefeld hatte 220px, also 71% der Bildschirmbreite.

Kein harter Breakpoint ("ab 310px vollflächig"), sondern fluide Abstände — ein
Umbruch bei 310px sähe bei 311px wieder falsch aus. Das Muster gab es im Projekt
schon: fee-table, membership-card, legal__card und matchcenter-empty nutzen
clamp()-Abstände. Fest waren genau die drei, über die es stolperte: .form (32px),
.group-card (32px) und .group-tabs__panel (40px).

Zwei neue Token in tokens.css als einzige Quelle, --pad-card (20…32px) und
--pad-card-lg (24…40px). Die OBERGRENZEN sind die bisherigen festen Werte, am
Desktop ändert sich also nichts — nachgemessen: 32px bei 1269px Viewport, wie
vorher. Es wird nur nach unten schmaler.

Ergebnis: Feldbreite bei 309px von 71% auf 76%, bei 379px von 74% auf 80%.
Kein Überlauf auf /turnen, den Disziplinseiten und /kontakt bei 320px und 1280px.

Die vier bereits fluiden Karten behalten ihre eigenen clamp()-Werte, damit ihr
Desktop-Bild unangetastet bleibt; sie in die Token einzusammeln ist eine
Aufräumung für später.

VORBESTEHEND und nicht von dieser Änderung verursacht (per git stash gegengeprüft,
mit und ohne Änderung identisch): /mitglied-werden läuft bei 320px um 12px über,
/turnen bei 300px um 13px. Die 320px sind eine echte Gerätebreite (iPhone SE),
das gehört als Nächstes angeschaut.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 21:34:29 +02:00
fs
9244149bac Sperrung der Kartentitel: neuer Token --ls-heading statt --ls-caps
--ls-caps (0.08em) war zu viel: bei 34px sind das 2,7px und die Überschriften
wirkten auseinandergezogen. Gewollt war ein Hauch Luft, etwa 0,4px (Felix).

Dafür gibt es keinen Token, und rohe Werte verbietet die Token-Disziplin — also
--ls-heading: 0.012em, was bei 34px genau 0,408px ergibt (nachgemessen). Der Fall
trifft jede Coolvetica-Überschrift in h3-Größe, nicht nur diese Karten: der
Schnitt ist condensed, bei 60px trägt er ohne Sperrung, bei 34px kleben die
Versalien. --ls-caps bleibt für kleine Labels, wofür es gedacht ist.

Klarstellung zum vorigen Commit: die Titel waren und bleiben Coolvetica. Der
Verweis auf Abel in meiner Begründung war ein Zitat der CLAUDE.md-Regel für
kleine Auszeichnungen, keine Änderung an der Schriftart.

CLAUDE.md entsprechend berichtigt, inklusive der Warnung, hier nicht --ls-caps
zu nehmen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 20:46:25 +02:00
fs
a3cfd4941d Banner-Hintergründe CSP-fest: <img> statt Inline-Variable
Beim ersten Deploy blieben die Slides des Banner-Sliders schwarz. Ursache war
kein fehlendes Bild, sondern die CSP: public/.htaccess setzt
default-src 'self' ohne style-src, der Browser verwirft damit jedes
style-Attribut — und die Komponente lieferte Bild und Akzentfarbe genau so
(style="--banner-bg: url(…); --banner-accent: #6cbbbc"). Lokal war das
unsichtbar, weil php -S keine .htaccess liest.

Der Hintergrund ist jetzt ein <img class="ad-banner__bg"> über die bestehende
img-Komponente (CSP erlaubt img-src) und bringt srcset mit: das Handy lädt die
640er statt der 1600er, die erste Slide lädt eager mit fetchpriority. Der
dunkle Leseverlauf liegt auf ::before statt im background-image.

Die Akzentfarbe kann als beliebiger Hex-Wert nicht ohne Inline-Style in die
Seite. Sie steht deshalb als Token in tokens.css (wo Farben laut CLAUDE.md
hingehören), components.css bildet den Namen darauf ab, und banners.json nennt
nur noch "accent": "breadcrumb".

bin/preflight.php bricht ab, wenn unter app/ wieder ein style-Attribut
auftaucht — der Fehler wäre sonst erneut erst in Produktion sichtbar. Beim
Bauen dieser Wache zweimal selbst hineingetappt: ein Muster mit [^>]* bricht an
jedem schließenden PHP-Tag ab, und die Zeichenfolge dieses Tags beendet den
PHP-Modus auch in einem //-Kommentar (preflight gab ab dort seinen eigenen
Quelltext aus, php -l meldete nichts).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 16:50:43 +02:00
fs
a101b0c3ec 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
2026-07-31 14:55:27 +02:00
fs
3fa521eaf1 Design-System: Typo-Skala schließen, h4–h6 auf Abel, Icon-Größen tokenisieren
Zweiter Teil der Konsolidierung. Vorher standen 31 font-size-Werte außerhalb
der Skala — beim Durchgehen stellte sich heraus, dass 20 davon gar keine
Textgrößen sind: der icon()-Helper rendert 1em, also steuerte font-size dort
die Icon-Größe. Dafür gibt es jetzt eine eigene, kleine Skala (--icon-s/m/l/xl
in rem, --icon-inline-sm/--icon-inline/--icon-inline-lg in em für Icons, die im
Textfluss mitwachsen sollen). Elf Ad-hoc-Werte fallen damit auf sieben Stufen.

h4–h6 laufen nicht mehr über Coolvetica. Sie lagen mit 26px und 21px unter der
--fs-650-Grenze aus CLAUDE.md, ab der der Condensed-Schnitt in Uppercase
unleserlich wird — die Regel war also nur dokumentiert, nicht durchsetzbar.
Jetzt tragen h1–h3 Coolvetica (alle über der Grenze) und h4–h6 Abel mit
Sperrung. Bezeichnend: das einzige <h4> im Markup hatte sich genau dieses
Muster bereits von Hand gebaut. Die Basisregel liefert es jetzt, die Komponente
gibt ihre drei Duplikat-Deklarationen ab — sichtbar ändert sich dadurch nichts.

Neue Stufen schließen die Lücken: --fs-550 (fluider Lead), --fs-690 (Karten-
Überschrift) und --fs-1000 (Display-Hero). Vier fast deckungsgleiche clamp()-
Rampen für Karten-Überschriften (bento__heading, bento__stat-value,
group-card__name, team-card__name) laufen jetzt über --fs-690; team-card__name
wächst dabei am Desktop um ~5px, die anderen drei bleiben im 1px-Bereich.

Die Wappen-Initialen im Matchcenter hingen an zwei Mini-Schriftgrößen (10,4 und
11,2px) unterhalb der Skala. Sie sind in Wahrheit ~0,4 × Kreisdurchmesser,
folgen jetzt also --crest-size statt einer eigenen font-size. Nebenbei fallen
drei redundante Doppel-Selektoren weg: .crest--initials trägt immer auch .crest.

Ebenfalls tokenisiert: 27 letter-spacing-Werte mit elf verschiedenen Zahlen auf
vier Stufen (--ls-tight/caps/wide/wider), maximale Abweichung 0,02em.

Danach steht kein font-size- und kein letter-spacing-Wert mehr außerhalb von
tokens.css.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:17:13 +02:00
fs
8304095dc3 Design-System: Token-Ebene für Spacing, Fokus und Tap-Targets
Vorbereitung für die Konsolidierung. tokens.css war für Farben und Typo schon
die Single Source of Truth, für Abstände aber nur mit --space-section und
--container-pad besetzt — dem standen ~450 Spacing-Deklarationen mit 39
verschiedenen rem-Werten gegenüber.

Neu: 14-stufige Spacing-Skala auf 4px-Raster, aus dem Ist-Bestand geclustert
statt frei erfunden. Die neun häufigsten Werte der Codebase (1, 1.5, 1.25, 2.5,
0.75, 0.5, 1.75, 2, 3rem — zusammen ~60% aller Deklarationen) liegen bereits
exakt auf Stufen, die Migration ist dort verlustfrei. Nach oben wird das Raster
gröber (3 → 4 → 5 → 7rem), weil große Abstände das vertragen. --space-4xs (2px)
ist ausdrücklich nur für optische Korrekturen an Icon-/Baseline-Nudges.

Dazu --tap-min (44px, WCAG 2.5.5) und --focus-ring/--focus-offset. Der Fokus
wird auf Weiß festgeschrieben: 15,9:1 auf --clr-bg gegenüber 3,2:1 für Rot,
das WCAG 1.4.11 nur knapp schafft und als einziger Indikator zu schwach ist.

--container-pad und --space-section verweisen jetzt auf die Skala statt eigene
Werte zu führen. Entfernt: --clr-bg-light und --clr-surface-raised, beide
projektweit 0× verwendet.

Consumer folgen in den nächsten Commits — dieser Schritt ändert die Darstellung
noch nicht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
2026-07-27 10:07:31 +02:00
fs
66c402d9f7 Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider
Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte
eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte;
dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein
einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah.

Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür
vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante:
links der Aufmacher (match-feature), rechts die folgenden Termine als
verlinkte match-row-Zeilen ohne Kartenfläche.

Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast,
linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei
typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile
mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder
Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über
font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch.

match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen
jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist.
Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin,
weil PHP global auf UTC läuft) und match_competition_label().

match-slider.php und match-card.php entfallen — Letztere wurde
ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den
Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:39:57 +02:00
fs
8437f00e06 Feinschliff: Formulare neu, Glas global dunkler, Hero-Fade sauber
Formulare (form-field.php, 3 Form-Wrapper, components.css, form.js):
- Floating Labels (Label im Feld, wandert bei Fokus/Inhalt hoch; select/date
  dauerhaft oben) via :has() + placeholder=" "-Trick. Echtes <label> bleibt
  im DOM (kein Placeholder-als-Label).
- Globale "Pflichtfelder mit *"-Hinweiszeile entfernt; Stern bleibt am Feld,
  pro Feld als visually-hidden "(Pflichtfeld)" für Screenreader erklärt.
- Markenroter Fokus-Ring statt Weiß.
- Felder als sanfter Füll-Look: weichere Ränder (eigene --clr-field-*-Tokens),
  Erkennbarkeit über Fläche + Rand (WCAG 1.4.11 erfüllt).
- form.js: Submit-Button-Text wird je Formular korrekt wiederhergestellt.

Glas-Look global (tokens.css, components.css):
- Frosted Glass zentral: --glass-blur + --glass-shadow (Glow + Top-Sheen),
  eine Regel statt 28× wiederholt; Leaf-Karten mit Blur, Container nur Glow
  (kein Doppel-Frost). @supports-Fallback.
- Dunkleres Glas (--clr-glass-bg auf Schwarz-Tint), dezenter Card-Rand.

Hero-Fade (components.css):
- Unterer Auslauf nicht mehr mit grauem --clr-bg zugedeckt, sondern .hero__media
  per mask-image ausgeblendet → echter dunkler, texturierter Hintergrund scheint
  durch (schwärzer, durchsichtig, kein graues Band). Abdunklung auf reines
  Schwarz. Gilt für alle drei Hero-Varianten.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGzc6GhWhmLJt1jC2q1SRZ
2026-06-20 22:18:34 +02:00
fs
adf142b18e Feinschliff: Navigation, Hero-Center, Personen-Karten & Tokens
Querschnitt-Verbesserungen ohne eigenes Feature:
- Navigation: Untermenü-Trenner (separator) + Mitmachen-Link, rote Akzent-Leiste
- Startseiten-Hero zentriert (align center, ohne Hero-CTAs); .hero--center-Styles
- person-card/person-grid: Kontakt-Layout, 3-Spalten-Raster (Startseite)
- jsonld: geo aus club.json; cta unterstützt #hash-Anker
- verein: hartcodierten Maps-Link/Inline-CTA entfernt, .facility zentriert
- tokens: Sepia-Farben für Timeline; base: globale p-max-width entfernt
- historie: Timeline um 2024/2025 ergänzt
- Icons link-45deg (Footer) und robot (meta) nachgereicht

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGzc6GhWhmLJt1jC2q1SRZ
2026-06-20 20:49:46 +02:00
fs
4b78285698 Neue Seiten: Mitglied/Partner werden, Sportheimbuchung & Ansprechpartner
Mitglied werden: Hub-Seite mit Online-Anmeldung (membership-form +
membership-submit-Action, Honeypot + Time-Trap), Abteilungswahl
(department-choice), Beitragstabelle (fee-table) und Turn-Aufnahmeantrag
als PDF-Download. Daten in data/mitglied-werden.json.

Partner werden & Sportheimbuchung: neue Seiten samt Routing und Navigation.

Ansprechpartner: echter Hero (Vereinsgelände), Bereiche aus dem group-Feld
der Single Source (Fußball / Turnen) zu zwei Sektionen gebündelt, Disziplin
als Karten-Überschrift. Fehlende Turn-Disziplin-Leads (Frisque, Lorz,
Kornatz, Trotzke) aus den Turnen-Unterseiten extrahiert und in
data/ansprechpartner.json ergänzt (allgemeine Turnabteilungs-Mail als
Kontakt). WhatsApp für alle Personen mit Telefonnummer. person-grid:
kompaktere Karten, Hairline unter der Bereichsüberschrift, 5 Spalten am
Desktop. Startseite auf die Haupt-Ansprechpartner je Bereich begrenzt.

Dazu: neue Icons (check-circle, download, file-earmark-text, whatsapp),
Anpassungen an Header/Footer/CTA/age-groups sowie tokens/layout/utilities.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZsKTL5kRSG4KkK8w2LKkE
2026-06-19 11:16:10 +02:00
546f1ca059 Footer-Headings auf 28px (neuer Token --fs-650) + Letter-Spacing für Coolvetica-Lesbarkeit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 22:07:56 +02:00
b95a0bce2d Formular-Regeln in CLAUDE.md; A11y-Fixes: Feldränder 3:1-Kontrast (neuer Token), Checkbox 24px + größeres Label, aria-live-Region nie display:none
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:59:34 +02:00
181f52fc73 h1 auf 96px-Clamp vergrößert; Hintergrund-Textur als WebP q70 (statt JPEG q20, behebt Verpixelung)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:27:28 +02:00
0f19729a88 Neubau Fundament + Startseite: Designsystem, PHP-Komponenten, Brevo-Formular, Instagram-Sync
- Ordnerstruktur mit public/-Docroot, Deny-.htaccess für app/bin/config/data/storage
- CLAUDE.md mit Leitplanken (self-hosted only, Single Source of Truth, Component-first)
- Design-Tokens aus alter Seite extrahiert (Akzent #e20612, Coolvetica/Abel als woff2)
- Front Controller mit Routen-Register, Sitemap, Canonical, JSON-LD (SportsClub)
- Startseite: Hero, Instagram-Feed (lokaler Cache), Historie/Sportheim, Stats, Partner, Kontakt
- Kontaktformular via PHPMailer/Brevo mit Honeypot + HMAC-Time-Trap (kein reCAPTCHA)
- bin/instagram-sync.php: Scraper mit Strategie-Kette, flock, atomarem Cache, lokalen Bildern

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:16:44 +02:00