Mail templates (6 templates touched):
- New shared `_styles.ts` exports a robust font stack starting with
Arial/Helvetica so mail readers that lack -apple-system and
BlinkMacSystemFont don't fall back to Monospace (observed in at least
one webmail client).
- `fontFamily` is now set on every text-bearing element, not only on
`<Body>`, because some clients (Outlook, several webmail readers) do
not inherit body CSS into nested sections.
- ASCII substitutions are gone: "Ueber" → "Über", "fuer" → "für",
"bestaetigen" → "bestätigen", "uebernehmen" → "übernehmen",
"verlaesslich" → "verlässlich".
- InviteEmail + NewsEmail buttons switch from the off-brand yellow
(#f0b84b) to the brand dark green so the CTA matches the header.
/invite form:
- InviteState gains an `attempt` counter plus echoed checkbox `values`,
mirroring the /register and /onboarding fix from earlier branches. A
failed submit no longer wipes the Datenschutz / Adressbuch-Opt-In
ticks. Passwords stay empty for security.
- Field error <p> elements gain role="alert" + aria-live="polite" so
screen readers announce validation failures on submit. Inputs use
aria-describedby to link to error / helper text.
Profile validation:
- Telephone numbers must match a permissive pattern that still rejects
obvious garbage (previously "abc-123-not-a-phone" was accepted).
- Postal codes must match an alphanumeric pattern of 3–10 chars
(previously "ABCDE" was accepted).
- Child date-of-birth is now validated via superRefine: it must be a
parseable date, not in the future, and not before 1900. Previously a
kid born in 2030 was accepted.
- The three Profil server actions now surface the first Zod issue
message instead of generic "Ungültige Eingabedaten." toasts.
Misc:
- "fuer" → "für" in the Adressbuch page subtitle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Server action echoes kitaName, the three module booleans, and the
Mindest-Verfügbarkeiten value on every error path so failed submits no
longer wipe what the user typed; OnboardingState gains an `attempt`
counter that drives a per-field remount key on the client.
- Schema now rejects min=0 when the Notdienst module is active (via
superRefine) — previously a kita could be created with 0 minimum days,
which is fachlich sinnlos. When the module is off, 0 stays valid.
- Validation error messages reworded from terse fragments ("Nicht
negativ.", "Bitte ganze Zahl.") to full sentences.
- Field error <p> elements gain role="alert" + aria-live="polite" so
screen readers announce them on submit.
- CardTitle now accepts as="h1" and the onboarding page uses it for
"Willkommen, …" — the page now has a real top-level heading.
- ModuleCheckbox uses aria-labelledby + aria-describedby so the
accessible name is just the module title; the longer description is
exposed as secondary info instead of being concatenated into the AN.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Server action now echoes firstName, lastName, email, and the privacy
checkbox state on every error path so failed submits don't wipe the form.
- New `attempt` counter on RegisterState drives a remount key per field,
bypassing React's default <form action> reset semantics.
- Error <p> elements gain role="alert" + aria-live="polite" so screen
readers announce validation failures live.
- Privacy checkbox now flags aria-invalid when not accepted and points to
the error message via aria-describedby.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>