Commit Graph

264 Commits

Author SHA1 Message Date
Peter Meier ca4dfad8be feat(termine+matrix): Nutzer-Termin-Einreichung (Draft) + Matrix-Notifications
Deploy / verify (push) Successful in 1m32s
Deploy / deploy (push) Successful in 1m54s
- /termin-melden: öffentliches Formular → /api/termin legt calendar_item als
  Draft an (scoped Write-Key), Admin bestätigt per draft→published
- /api/cms-webhook: empfängt RustyCMS-Webhooks (X-Webhook-Secret) → Matrix
- src/lib/server/matrix.ts: notifyMatrix() Helper
- Form-Proxies (stellungnahme/contact/newsletter/mitmachen) pingen Matrix
- deploy.yml: Matrix/Webhook/Termin-Key Env-Vars

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:32:36 +02:00
Peter Meier 5b5fe8789e feat(stellungnahme): Send-Panel — tägliche Bearbeitung + E-Mail-Versand-Hinweis
Deploy / verify (push) Successful in 1m19s
Deploy / deploy (push) Successful in 1m34s
Hinweis dass Einsendungen einmal täglich bearbeitet und die fertige
Stellungnahme per E-Mail zurückgesendet werden; E-Mail als Pflichtfeld
markiert (required + Kennzeichnung), sent-Bestätigung entsprechend angepasst.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 20:43:03 +02:00
Peter Meier cb66442aac fix(stellungnahme): Sende-Status bei Neu-Erzeugen zurücksetzen
Deploy / verify (push) Successful in 1m33s
Deploy / deploy (push) Successful in 1m43s
generateOutput() setzt sendState/sendError auf idle, damit nach erfolgreichem
Senden ein neu erzeugter Brieftext nicht am stale "übermittelt"-Status hängt.
resetAll (Neustart) resettet die Sende-Felder weiterhin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 12:21:31 +02:00
Peter Meier 7788e0370e feat(link-list): CMS-Feld columns (auto|single) für Spaltenlayout
Deploy / verify (push) Successful in 1m13s
Deploy / deploy (push) Successful in 1m28s
single = immer untereinander, auto = breitenbasiert mehrspaltig ab >4.
Regionalplan-Generatorenliste (w1-w40) auf single.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 22:40:30 +02:00
Peter Meier 552446b670 feat(stellungnahme): "An das Team senden" — Prompt landet in RustyCMS
Deploy / verify (push) Successful in 1m16s
Deploy / deploy (push) Successful in 1m37s
- StellingnahmeGeneratorBlock: Senden-Panel im KI-Block (Name, Email,
  Vorranggebiet, generierter Prompt) → /api/stellungnahme, Consent + Honeypot
- neuer Endpoint /api/stellungnahme spiegelt /api/contact (Origin, Honeypot,
  client-age, Validierung) → forwarded an CMS forms-Plugin
- Privacy-Notice: Senden = ausdrückliche Übermittlung

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 22:31:39 +02:00
Peter Meier d64754c238 feat(search): Multi-Wort + Ranking + Keyboard-Nav; fix LinkList-Spalten
Deploy / verify (push) Successful in 1m18s
Deploy / deploy (push) Successful in 1m33s
- Search: AND-Match über Tokens, Feld-gewichtetes Ranking, ↑↓⏎-Nav,
  Match-Highlight, Trefferzahl + aria-live
- LinkListBlock: breitenbasierte Spalten (auto-fill minmax) statt fixer
  4-Zeilen-Grid — verhinderte Zerbröseln bei vielen langen Labels

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 21:44:34 +02:00
Peter Meier 52929122f5 fix(ui): roter NEU-Badge, separate Nav-Pills, Footer-Headlines + Spalten
Deploy / verify (push) Successful in 1m26s
Deploy / deploy (push) Successful in 1m44s
- AnnouncementBanner: führendes **bold** rendert als roter Pill-Badge
- Header: Kalender/Adressbuch/Suche je eigene Pill statt geteiltem Container
- LinkListBlock: uppercase raus, >4 Links → 4er-Spalten ab sm

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:20:24 +02:00
Peter Meier 81c067fa0c fix(newsletter): stack inline footer form on mobile
Deploy / verify (push) Successful in 1m14s
Deploy / deploy (push) Successful in 1m30s
Email field + submit button stacked on mobile (button full width below the
input) and side by side from sm up. The long "Newsletter abonnieren" button
was squeezing the email field on narrow screens.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:38:57 +02:00
Peter Meier d8a6508cde feat(footer): use the grid layout system instead of fixed flex columns
Deploy / verify (push) Successful in 1m18s
Deploy / deploy (push) Successful in 1m28s
Drop the footer's flex override so it renders through the standard 12-col
grid + per-block layout (mobile/tablet/desktop) like pages do. Add optional
column-start (desktopStart/tabletStart) to the layout system so blocks can be
offset in the grid — used to place the inline newsletter form directly under
the "Kontakt & Community" column.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:19:59 +02:00
Peter Meier 686af53be0 feat(newsletter): slim inline newsletter form for footer
Deploy / verify (push) Successful in 1m12s
Deploy / deploy (push) Successful in 1m54s
Add form-newsletter-inline internal component: compact email + button row
with a consent checkbox, dark-themed for the footer. Turnstile loads lazily
on first email focus (footer is on every page). Reuses /api/newsletter and
the newsletter validation. Wired into footer-main next to Kontakt & Community.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:08:27 +02:00
Peter Meier af90483dc4 feat(newsletter): newsletter signup as internal component
Deploy / verify (push) Successful in 1m18s
Deploy / deploy (push) Successful in 1m34s
Wire a newsletter signup form into the CMS internal-component pattern
(form-newsletter). Posts to /api/newsletter which subscribes to listmonk
(double opt-in) and mirrors a best-effort backup record to the RustyCMS
forms plugin. Reuses the contact-form anti-spam stack: Cloudflare
Turnstile, honeypots, client-age check, origin validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 11:02:48 +02:00
Peter Meier 0ab2c58eb4 feat(header): icon nav redesign + migrate icons mdi→lucide
Deploy / verify (push) Successful in 1m26s
Deploy / deploy (push) Successful in 2m26s
- Header desktop nav: social icons grouped in a wald-tinted pill with
  labels, active-state (aria-current + bold), opacity hover (no per-item bg)
- Mobile overlay: social links as icon+label rows with active-state
- Search button: lucide:search, icon-only
- Migrate all icons mdi→lucide app-wide (234 refs); brand/language logos
  (google, whatsapp, mastodon, telegram, language-*) stay on mdi
- generate-icons: emit mdi + lucide subsets; add @iconify-json/lucide
- iconify-offline: register lucide collection
- scripts/icon-map|validate|apply: reusable migration tooling

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:44:56 +02:00
Peter Meier e434ee3620 feat(termin): Termin-Detail unter /kalender/termin/<slug>, 302 von alt
Deploy / verify (push) Successful in 1m21s
Deploy / deploy (push) Successful in 1m39s
Route /termin/[slug] -> /kalender/termin/[slug] verschoben, alte URL
302-redirect (QR-Codes/geteilte Links bleiben gueltig). Breadcrumb 3-stufig
(Start > Kalender > Titel). QR-/Detail-/OG-Links auf neuen Pfad.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:35:15 +02:00
Peter Meier a628e0e8d1 fix(calendar): <li>-Disc-Marker (Punkt) auf iOS/WebKit entfernen
Deploy / verify (push) Successful in 1m12s
Deploy / deploy (push) Successful in 1m34s
Punkt links der Datums-Kachel war der event-item <li>-Marker, nicht der
summary-Disclosure-Marker. list-none am <ul> wird von globaler Typo-Regel
überschrieben → list-style:none + ::marker{content:""} direkt auf .event-item.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:18:56 +02:00
Peter Meier a0e2015eeb fix(calendar): EventDateBox simpler flex-center Layout (Safari-fest)
Deploy / verify (push) Successful in 1m17s
Deploy / deploy (push) Successful in 1m30s
Grid/calc/leading-Experimente raus. Schlichtes flex justify/items-center
mit innerem text-center-Block (Wochentag/Tag/Monat) — rendert auf iOS
Safari zuverlässig. wald-Farbschema + rounded-br-4xl + shadow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:11:10 +02:00
Peter Meier d484a7d90b fix(calendar): leading-none auf Tag-Zahl — Tailwind text-* default line-height blähte Zeilenbox, JUN an Unterkante
Deploy / verify (push) Successful in 1m11s
Deploy / deploy (push) Successful in 1m30s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 22:18:26 +02:00
Peter Meier 8a0d3280f9 fix(calendar): EventDateBox neu — feste rem-Größen, kein Range-Overflow
Deploy / verify (push) Successful in 1m11s
Deploy / deploy (push) Successful in 1m55s
EventDateBox von Grund auf neu: <time> mit a11y-Label, feste rem-Schriften
statt fluid/calc-Skalierung, size-16/sm:size-20. Range-Box: gleiche Höhe,
nur breiter; symmetrisches gap → Monat rutscht nicht mehr aus der Box.
Zusätzlich iOS-Safari Disclosure-Marker (dunkler Punkt) in CalendarBlock
ausgeblendet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 22:14:39 +02:00
Peter Meier 93fcf79f86 fix(calendar): EventDateBox skaliert proportional zur Quadratgröße
Deploy / verify (push) Successful in 1m13s
Deploy / deploy (push) Successful in 1m34s
Feste px-Schriftgrößen + h-20 verursachten auf Mobile Overflow ("Jun"
rutschte raus). Jetzt eine CSS-Var --s (Kantenlänge, responsive clamp);
alle Innenmaße per calc() abgeleitet. Range-Box nur breiter, gleiche
Höhe → identische Schrift wie Einzel-Box.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:55:03 +02:00
Peter Meier ccf500fc62 style: Lead-Absatz schwarz + Kommentar-Empty-State dezenter
Deploy / verify (push) Successful in 1m20s
Deploy / deploy (push) Successful in 1m36s
- app.css: erster Markdown-Absatz im Artikel auf --text-primary (schwarz)
  statt --text-secondary (grau).
- Comments-Empty-State: kleineres helleres Icon (size-5/stein-300), Text
  semibold + stein-300 (gleich hell wie Icon), engerer Icon-Text-Abstand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:07:46 +02:00
Peter Meier 0b3ddd86e3 feat(termin): Detailseite-Redesign + gedeckeltes Bild
Deploy / verify (push) Successful in 1m20s
Deploy / deploy (push) Successful in 1m37s
- 2-Spalten-Layout (Inhalt auf Lesebreite, sticky Aktions-Card rechts)
- Bild gedeckelt (max-h-440, contained, Hover-Zoom) statt full-width
- Countdown-Badge (Heute/Morgen/in X Tagen/vergangen)
- Aktionen gruppiert: "Zum Kalender" (ICS/Google) + "Teilen" (Link/QR/Bild)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:17:27 +02:00
Peter Meier 905c2e4d36 refactor(calendar): EventDateBox-Komponente für Datums-Kachel
Deploy / verify (push) Successful in 1m7s
Deploy / deploy (push) Successful in 1m59s
Einzel- und Mehrtages-Datum in eine dedizierte Komponente ausgelagert.
Beide Varianten gleiche Höhe (h-20); Mehrtag zeigt Wochentag- und Tag-Range
(z. B. "Sa–So" / "27–28") und wächst nur in der Breite. Zentriert gestapelt
(kein Overflow), himmel-Box konsistent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 14:00:54 +02:00
Peter Meier 6925ffee45 feat(termin): vollwertige Detailseite + QR/Detail-Link im Kalender
Deploy / verify (push) Successful in 1m15s
Deploy / deploy (push) Successful in 1m25s
/termin/<slug> ist jetzt echte Seite statt Redirect:
- alle Infos ungekürzt (Datum/Zeit in Europe/Berlin, Ort+Maps, Tags,
  Bild+Lightbox, volle Beschreibung, Anhang, externer Link)
- alle Aktionen: ICS, Google, Link kopieren, Teilen, QR, Social-Bild
- Link zum Kalender drunter (kein Auto-Redirect mehr)
- Breite via Layout-.container-custom (gleich wie andere Seiten)
- SEO: OG/Twitter/canonical zentral aus Layout (kein Doppel-Tag),
  Event-JSON-LD + Breadcrumb für Rich Results / Share-Preview

CalendarBlock: QR-Button + "Details →"-Link je Termin (→ /termin/<slug>/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:50:09 +02:00
Peter Meier fdc18ab5b8 fix(social-image): Uhrzeit/Datum in Europe/Berlin rendern
Deploy / verify (push) Successful in 1m14s
Deploy / deploy (push) Successful in 2m8s
Social-Image-Generierung lief SSR auf Server-TZ (UTC) → terminZeit
"10:00+02:00" wurde als "08:00" aufs Bild gerendert (−2h im Sommer).
toLocaleDate/TimeString in Kalender- und Post-Route auf timeZone
"Europe/Berlin" gepinnt. Cache-Version v26→v27 invalidiert alte PNGs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:20:01 +02:00
Peter Meier 781869b2b4 fix(footer): Lizenz-/Copyright-Markdown sauber rendern
Deploy / verify (push) Successful in 1m12s
Deploy / deploy (push) Successful in 2m6s
- globalen Grid-Row-Trenner (::before aus app.css) im Flex-Footer abschalten
  → kein Phantom-Flex-Item mehr, Inhalt bündig links
- Trailing-Margins (letzter Block + letztes <p>) auf 0 → kein Leerraum unten
- Markdown-Links unterstreichen (konsistent mit den Link-Listen)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:49:21 +02:00
Peter Meier eee25e8275 fix(types): GeoJSON via explizite geojson-Imports
Deploy / verify (push) Successful in 1m12s
Deploy / deploy (push) Successful in 2m9s
Kit-Bump auf 2.65 entfernte transitives @types/geojson aus dem Lockfile —
CI-tsc fand den globalen GeoJSON-Namespace nicht mehr. @types/geojson als
devDependency + explizite Type-Imports statt UMD-Namespace.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 23:06:25 +02:00
Peter Meier 77ff44f6ef fix(csrf): non-www-Canonical + trustedOrigins für www-Fallback
Deploy / verify (push) Failing after 1m12s
Deploy / deploy (push) Has been skipped
SvelteKits CSRF-Check blockte multipart-POSTs (/api/mitmachen) mit 403:
ORIGIN env stand auf www, Caddy redirected aber www -> non-www — jeder
Besucher war auf non-www, Origin-Header passte nie. Env-Flip auf non-www
(secrets), hier: www als trustedOrigin-Fallback + Kit-Bump auf ^2.65
(trustedOrigins gibt es ab 2.23).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 22:58:28 +02:00
Peter Meier ae9536db3a fix(forms): unsichtbare Unicode-Zeichen in Eingaben strippen + FormCard-Rahmen
Deploy / verify (push) Successful in 1m2s
Deploy / deploy (push) Successful in 1m19s
- cleanText(): Zero-Width-/Bidi-Marks/BOM (Copy-Paste aus iOS/WhatsApp)
  vor Validierung und im Payload entfernen — Telefonnummern mit
  U+202D/U+202C fielen sonst durch die Validierung
- FormCard.svelte: gerahmter Container, umschließt Kontakt- und
  Mitmachen-Formular

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 12:36:47 +02:00
Peter Meier b29dd587b8 feat: Mitmachen-Formular nativ (löst OpnForm ab)
Deploy / verify (push) Successful in 1m8s
Deploy / deploy (push) Successful in 1m17s
- MitmachenFormComponent: Name der BI*, Anliegen*, Ansprechpartner,
  Telefon, E-Mail, Datei-Upload (max 5×5MB, JPG/PNG/WebP/GIF/PDF),
  Consent — Honeypots + Client-Age + Turnstile wie Kontaktformular
- /api/mitmachen: Multipart-Validierung (shared Modul), Forwarding an
  CMS /api/forms/mitmachen/submit-multipart
- internal_component: form-mitmachen registriert
- ~35 neue mitmachen_*-Translation-Keys

Prod braucht BODY_SIZE_LIMIT=30M (adapter-node default 512K) — via
secrets .env.prod deployt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:59:31 +02:00
Peter Meier d9519a867e perf: LCP-Fix, Banner-Crops, SSR-Cache, Bulk-Windkarte
Deploy / verify (push) Successful in 1m3s
Deploy / deploy (push) Successful in 1m47s
- TopBanner: JS-Fade-Gate entfernt (opacity-0 bis Hydration schob LCP
  von ~3s auf ~8.6s) — Bild malt jetzt progressiv über den LQIP
- buildBannerResponsive: Breakpoint-Varianten (1/1, 16/9, 24/9) mit
  media-Attributen, quality 60; CMS braucht explizites h neben ar,
  sonst kein Crop (Mobile bekam 1.92:1 unscharf hochskaliert)
- Layout-Preload: ein Link pro Breakpoint-Variante (WebP)
- Layout-Bootstrap-Batch + Logo-SVG-Fetch TTL-gecacht (liefen pro
  SSR-Request); invalidateCollection versteht CSV-Key-Heads
- WindkarteBlock: 40 Einzel-Fetches -> 1 List-Request mit Filter
- app.html: preconnect cms.pm86.de, api.iconify.design, analytics
- u-url Microformat: echte canonicalUrl statt href="#" (SEO-Audit)
- Icon-Subset: 'cloud' ergänzt (kein Runtime-Fetch an iconify mehr)
- StrommixBlock: nutzloses transition-colors entfernt (CLS-Audit)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 09:50:01 +02:00
Peter Meier 41597f87b5 feat(windkarte): InfoAccordion, anlagen-Hinweis, Tooltip ohne Icons
Deploy / verify (push) Successful in 1m6s
Deploy / deploy (push) Successful in 1m18s
- Disclaimer aus CMS-Feld (hinweis_text) via InfoAccordion statt Hardcode
- info_text-Feld für Block-Fließtext ergänzt
- anlagen_geplant_hinweis-Feld in WindArea + Panel-Anzeige
- Tooltip-Icons entfernt (square-outline/wind-turbine/map-marker inline SVGs)
- Panel: square-outline → ruler-square für Fläche
- Iconify-Subset neu generiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 12:35:29 +02:00
Peter Meier 1c63f68c0b feat(social): add post image thumbnail to OG social card
Deploy / verify (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m57s
Ports the same loadPostImage + thumbBlock pattern from the calendar
social route. Reads postImage.src (fallback: image.src), loads via
CMS transform API as base64 JPEG, renders next to QR code.
Posts without an image are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 09:24:41 +02:00
Peter Meier 08181129c4 feat: Event-Bild im Social-Bild + UX-Verbesserungen
Deploy / verify (push) Successful in 1m3s
Deploy / deploy (push) Successful in 1m23s
Social-Bild Calendar:
- Termin-Bild als Thumbnail neben QR-Code (Reihenfolge: QR | Bild)
- Wrapper transparent, Bild im natürlichen Aspect via object-fit:contain
  und fit=inside auf transform-API — kein Crop, kein Letterbox
- Wachstum auf qrSize+28 begrenzt
- Title-Fontsize bei vorhandenem Thumb zusätzlich verkleinert
- Eckige Kanten (kein border-radius) für QR-Box und Thumb

Calendar-Block:
- Vorschaubild im Termin-Item gleich gerendert: object-contain,
  max-w-24/max-h-24, kein Crop
- "Teilen"-Gruppe in Aktions-Toolbar bricht auf Mobile auf eigene
  Zeile um, Trennstrich nur auf sm+ sichtbar

Direkt-Link:
- Calendar: /kalender/?social=<slug> öffnet Modal automatisch
- Post: /post/<slug>?social=1 öffnet Modal automatisch
- Modal-Header: "Direktlink"-Button kopiert URL ins Clipboard

Skeleton-Loader:
- Animierter grauer Skeleton während Bild-Render via satori
- Per Theme-Wechsel resetten, fade-in via opacity-Transition
- Story-Container Fix: explizite 280x158 Maße statt aspect-ratio

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 13:35:38 +02:00
Peter Meier c225fb8be5 feat: Daten-Disclaimer Accordion oberhalb der Windkarte
Deploy / verify (push) Successful in 1m2s
Deploy / deploy (push) Successful in 1m18s
Erklärt warum Anlagenzahl/Höhe-Schätzwerte entfernt wurden. Default
geschlossen, Chevron-Pfeil als Indikator zum Aufklappen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 08:51:00 +02:00
Peter Meier 4f0ec5ce21 refactor: Anlagen-Zahl + Max.-Höhe komplett aus UI entfernt
Deploy / verify (push) Successful in 1m5s
Deploy / deploy (push) Successful in 1m17s
Beide Felder waren nicht belastbar (Schätzungen bzw. nicht final
festgelegt). Entfernt aus:
- Windkarte-Hover-Tooltip
- WindAreaPanel (Kenndaten + Export-Info)
- StellingnahmeGenerator-Steckbrief + Disclaimer-Footnote

Übrig: Fläche, Investor, Status. Genaue Anlagenzahl wird erst im
Genehmigungsverfahren bestimmt — keine vorausgreifende Vermittlung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 08:39:35 +02:00
Peter Meier f90116a923 fix: Windkarten-Tooltip + Anlagenzahl-Disclaimer überarbeitet
Deploy / verify (push) Successful in 1m4s
Deploy / deploy (push) Successful in 1m25s
Windkarte-Tooltip:
- Auf Touch-Geräten (@media hover:none) ausgeblendet, Detail-Panel
  öffnet eh bei Tap
- max-width 360px, min-width 220px, white-space:normal,
  größeres padding/Schrift für bessere Lesbarkeit
- Anlagen-Zahl aus Tooltip entfernt (nicht belastbar)
- Gemeinden ungekürzt anzeigen, Truncate auf 3 entfernt

WindAreaPanel:
- "Anlagen geplant" nach unten verschoben (nach Investor), Zeile mit
  opacity-60 + italic + mute-Farbe — zeigt visuell dass es nur eine
  Schätzung ist
- Disclaimer-Text überarbeitet: Obergrenzen-Schätzung 2-3 Anlagen je
  100 ha (270-Meter-Klasse) statt Faustregel 4-6

StellingnahmeGenerator: gleicher Disclaimer-Text-Wortlaut.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 08:15:06 +02:00
Peter Meier 21b555b61d fix: Calendar-Toolbar bricht Mobile-Wrap-Layout pro Gruppe sauber um
Deploy / verify (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m28s
Label und Buttons jeder Gruppe (Kalender / Teilen / Anzeigen) in
eigene inline-flex-Container gekapselt. Umbruch passiert nur zwischen
Gruppen, Labels werden nicht mehr von ihren Buttons getrennt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 13:23:41 +02:00
Peter Meier 155d9fb4b0 feat: Social-Bild-Generator auch für Posts (Endpoint, Modal, PostActions-Button)
Deploy / verify (push) Successful in 1m4s
Deploy / deploy (push) Successful in 1m23s
Neuer Endpoint /api/social/post/[slug] mit gleichem Pattern wie für
Termine: Logo, Tag-Pill aus Title/Tags-Keywords (Presse, Demo,
Rückblick, Interview, Studie, Rechtlich, Meinung etc.), Datum,
Headline mit dynamischer Fontsize, Subheadline/Excerpt-Snippet, QR
zum Beitrag, Footer. 3 Formate × 3 Themes wie Kalender.

SocialImageModal in eigene wiederverwendbare Komponente extrahiert
und sowohl im PostActions als auch im CalendarBlock eingebunden.
PostActions akzeptiert socialSlug-Prop und blendet bei vorhandenem
Slug einen Modal-Trigger-Button neben den anderen Aktions-Icons ein.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 13:14:14 +02:00
Peter Meier 287a44ff6b feat: Social-Bild erweitert (Logo, Status-Pill, Description, Story, Themes) + OG-Route + Calendar-Buttons aufgeräumt
Deploy / verify (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m19s
Social-Bild-Endpoint:
- Logo aus page_config (gefärbt in Theme-Akzent) statt Wordmark
- Status-Pill (ONLINE/Demo/Info/Anhörung/Stammtisch/Sitzung) aus
  Titel-Keywords und Tags, mit eigener Farbe
- Description-Snippet unter Titel (Square + Story)
- Story-Format 1080x1920 ergänzt
- Theme-Varianten: wald (default), transparent-onlight,
  transparent-ondark
- Uhrzeit unter Datum (2. Zeile) mit Clock-Icon im Akzent-Grün
- QR linksbündig bei Square + Story, kleiner (180px)
- Location-Pin top-aligned, Title-Fontsize dynamisch bei langen Titeln

Neue Route /termin/[slug]: OG-Meta-Tags für Link-Previews
(FB/WhatsApp/Twitter), JS-Redirect zu /kalender/#event-<slug>.
QR-Code im Social-Bild zeigt jetzt auf /termin/[slug].

Calendar-Block Aktionen reorganisiert:
- Primary-Reihe: Mehr Info, Auf Karte, Anhang
- Kompakte Toolbar (gerahmt): Kalender (ICS, Google) | Teilen (Link,
  Share, Bild) | Im Grid
- Theme-Selector im Social-Modal mit Vorschau-Hintergrund-Indikator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 13:02:47 +02:00
Peter Meier 6d1a084973 refactor: Stellingnahme-Generator UX-Überarbeitung Step 5
Deploy / verify (push) Successful in 1m4s
Deploy / deploy (push) Successful in 1m15s
- Sticky farb-hinterlegter Stepper (Sprung zwischen Schritten klarer)
- Step 5 reorganisiert: Setup oben, "═══ Ergebnis ═══" Trenner,
  Schreibvorlage- und KI-Cards primär sichtbar, Feintuning
  (Vorschau, Argument-Reihenfolge, Einleitung, Abschluss) in
  ein collapsed "Brief im Detail anpassen"-Accordion zusammengelegt
- "Mit Platzhaltern füllen"-Button für Absender-Felder
- KI-Block: nummerierte 1-2-3-4-Anleitung, "In Zwischenablage
  kopieren"-Button + .txt-Download, editierbare Inhalts-Regeln
- KI-Prompt nachgeschärft: konkrete Rechtsgrundlagen, klare Anti-
  KI-Floskel-Liste, expliziter Hinweis "Entwurf-Banner entfernen",
  Verbot von em/en-dashes als Satz-Trenner
- buildText post-processed em/en-dashes zu Kommas
- UI-Texte: em/en-dashes durch Kommas ersetzt
- "Anlagen geplant"-Disclaimer (Schätzung ~4-6 WEA/100ha) in
  Stellingnahme-Card und WindAreaPanel ergänzt
- Reset setzt Step + Scroll zurück, History bleibt erhalten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 11:02:48 +02:00
Peter Meier ace3562111 feat: Social-Bild-Modal mit QR-Code für Kalender-Termine
Deploy / verify (push) Successful in 1m7s
Deploy / deploy (push) Successful in 1m39s
Single Button öffnet Vorschau-Modal mit beiden Formaten side-by-side.
Pro Format Download-Button. ESC + Click-outside schließen.

Endpoint generiert zusätzlich QR-Code (qrcode → PNG-Buffer), der
direkt auf den Termin im Kalender-Grid verweist
(/kalender/#event-<slug>). Pin-Icon, QR und Layout für OG (1200x630)
und Square (1080x1080).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:25:07 +02:00
Peter Meier f0d9fecfb8 feat: Social-Media-Bild-Generator für Kalender-Termine
Neuer Endpoint /api/social/calendar/[slug] rendert Termin via satori +
resvg zu PNG. Formate: og (1200x630) und square (1080x1080).
Gebrandetes Layout mit Datum, Titel, Ort. Inter-Font lazy von gstatic,
10min In-Memory-Cache pro Slug+Format.

CalendarBlock: zwei Download-Buttons pro Termin (Bild quer / quadr.).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 09:28:00 +02:00
Peter Meier d921b2758b refactor: AI-Prompt für Stellungnahme nachgeschärft
Klare Rolle, zwingende Regeln (Argumente erhalten, keine Erfindungen,
Briefkopf-Struktur, ≥70 % neu formuliert), explizites Ausgabeformat.
Kontext zum Windvorranggebiet und persönliche Betroffenheit prominent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 09:22:06 +02:00
Peter Meier 415e772e57 fix: Windkarte verbirgt Labels ausgeblendeter Status
Per-Status LayerGroups statt einer globalen labelLayer. syncLabels
respektiert hiddenStatuses und entfernt Labels für versteckte
Status-Kategorien beim Zoomen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 09:22:00 +02:00
Peter Meier 894263e5c4 fix: OrganisationsMap erst bei Klick interaktiv, kein Page-Scroll-Hijack
Deploy / verify (push) Successful in 1m1s
Deploy / deploy (push) Successful in 1m25s
Initial Drag/Zoom deaktiviert. Overlay 'Karte aktivieren' freigibt
Interaktion. Marker-Klick aktiviert automatisch mit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:17:15 +02:00
Peter Meier aebe5f4854 fix: kleinere Map-Höhe auf Mobile (320px statt 400px+)
Deploy / verify (push) Successful in 58s
Deploy / deploy (push) Successful in 1m8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:06:53 +02:00
Peter Meier fc81d973a5 feat: Ansprechpartner im OrganisationsMap Detail-Panel
Deploy / verify (push) Successful in 1m2s
Deploy / deploy (push) Successful in 1m11s
Marker-Klick zeigt jetzt zusätzlich Name, Rolle, Email und Telefon
der Kontaktpersonen pro Organisation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:02:47 +02:00
Peter Meier c9ba88ab80 feat: OrganisationsMapBlock — Karte der Bürgerinitiativen
Deploy / verify (push) Successful in 1m5s
Deploy / deploy (push) Successful in 1m13s
Neuer Block-Typ `organisations_map`: Leaflet-Karte mit CircleMarkern für alle
Organisationen die ein location.lat/lng haben. Klick auf Marker öffnet
Detail-Panel (Desktop: rechte Sidebar / Mobile: Bottom Sheet) mit Name,
Standort, Beschreibung und Website-Link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:03:26 +02:00
Peter Meier 88b2df0c05 feat: location-Feld an Organisation, Header-Tooltips
Deploy / verify (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m13s
- block-types: OrganisationEntry.location { text, lat, lng }
- Header: title-Attribut auf Social-Icons + Suche-Button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:54:13 +02:00
Peter Meier 6c774c4913 refactor: SearchableTextBlock Redesign, Ort-Badge Truncate
Deploy / verify (push) Successful in 59s
Deploy / deploy (push) Successful in 1m12s
- SearchableTextBlock: Farbverlauf-Header entfernt, Tag/Tags durch .chip ersetzt,
  Suche auf Adressbuch-Style ausgerichtet, Kopier-Buttons auf Icon-only reduziert,
  border-l-4 Akzent entfernt
- EventBadges: whitespace-nowrap entfernt, truncate max-w-[16rem] + title für lange Ortstexte
- PostCard: min-w-0 auf Badges-Container für korrekte Truncate-Propagation
- iconify-mdi-subset: qrcode + download Icons ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:25:34 +02:00
Peter Meier 982a7a3b73 feat: QR-Code, vCard-Export, Org-Gruppenansicht im Adressbuch
Deploy / verify (push) Successful in 1m10s
Deploy / deploy (push) Successful in 1m45s
- vcard.ts: shared vCard-Generator (downloadVCard, downloadVCardAll, buildVCardString)
- QrModal.svelte + QrButton.svelte: wiederverwendbare QR-Komponenten mit PNG-Download
- AdressbuchBlock: Org-Gruppenansicht (Toggle), QR + vCard pro Kontakt,
  Buchstaben-Trennzeilen, Such-Highlight, "Alle exportieren", Print-Styles
- ContactCard: vCard-Download-Button
- PostActions: QR-Button für Seiten-URL
- qrcode npm-Paket hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:15:57 +02:00