HeadlineBlock rendert als SectionHeader sobald kicker oder action gesetzt ist,
sonst schlichte Text-Headline wie bisher (rückwärtskompatibel, opt-in).
SectionHeader-Titel unterstützt jetzt \n → <br>. headline-Schema extends
section_header.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Die AI-Rewrite-Regeln (DEFAULT_AI_RULES) waren im Block hardcodiert und
hätten pro Generator (40 Instanzen) dupliziert werden müssen, um im CMS
editierbar zu sein. Stattdessen ein Singleton stellungnahme_config
(Slug "default") mit Feld aiRules: der Resolver lädt es einmal und hängt
block.aiRules an alle Generator-Blöcke. Komponente seedet daraus, mit
DEFAULT_AI_RULES als Code-Fallback; Reset-Button setzt auf den CMS-Wert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The carousel iframe row was wrapped in {#key currentIndex} with
transition:fade, so switching slides (or navigating to the page) faded
the old and new row in overlap — briefly showing two rows / a blink.
Drop the fade from both iframe containers, matching the modal variant
which uses {#key} without a transition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a global modal/popup system driven entirely from the CMS. A new
`modal` config collection self-targets routes via a glob/regex urlPattern
(optional time window), and its `content` array of block references renders
through the existing BlockRenderer — so markdown, HTML and YouTube blocks
work exactly like a page row. A `modals` list collection holds the active
set behind an enable flag (analogous to `campaigns`).
- modal-match.ts: glob (`*`/`**`) + `~regex` pathname matcher, time window
and modal selection helpers (+ unit tests)
- ContentModal.svelte: immediate/delay/scroll/exit_intent triggers, session
vs. permanent dismiss (sessionStorage + localStorage, keyed by slug+version)
- +layout.server.ts: load `modals-global` in the bootstrap batch, resolve
block images server-side
- +layout.svelte: mount on non-embed routes, match against the current path
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- LinkListBlock: id+scroll-mt-24 -> Anker-Sprung moeglich
- Frist-CTA verlinkt auf #generatoren (springt direkt zur Liste)
- WindkarteBlock: Hinweis "Klicke dein Vorranggebiet" (Karte ist Picker)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PostActions: 🔊 Vorlesen liest Artikeltext (Titel+Body, versteckte Elemente
gefiltert), Toggle Pause/Weiter + Stop, deutsche Stimme, satzweise, stoppt
bei Seitenwechsel. Button erscheint nur wenn speechSynthesis verfügbar.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Body-Lock sperrt Seiten-Scroll; mobile-nav hatte overflow-hidden ohne
Höhe → auf Android nicht scrollbar. Jetzt max-h(100dvh-Header) +
overflow-y-auto + overscroll-contain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gelb-Palette ins @theme (fixt auch bisher wirkungslose gelb-* Klassen im
Deadline-Banner), .btn-warning als wiederverwendbare Variante; Termin-melden-
Button nutzt sie statt inline-style/arbitrary utilities.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regel 6: Quellen/Normen/Aktenzeichen direkt im Fließtext benennen.
Regel 7: keine Verweise auf Anlagen/Anhänge — jeder Beleg muss vollständig
im Dokument selbst stehen (nichts wird beigefügt).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
- 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>