Eight hotfix-ready UX/a11y findings from the v1.4.34.3 UX audit
land as one batch.
i18n leaks (3 primitives):
- Dialog + Sheet close-X carried hardcoded `<span sr-only>Close</span>`
so a German user heard 'Close, button' on every modal. Both lift
`useTranslations()` and read `common.close`.
- ChartSkeleton's sr-only loading announcement was English-only.
The component is already a client island; reads `charts.loadingLabel`
from each locale now. New key shipped in DE / EN / FR / ES / IT / PL.
- Notifications-section breadcrumb `<nav aria-label="Breadcrumb">`
was hardcoded. Routes through `t("nav.breadcrumb")` with a new
key in each locale.
Focus rings (mobile + tablet nav):
- Bottom-nav primary links + the More overflow trigger relied on a
`text-muted-foreground` → `text-primary` colour transition only;
keyboard / switch-control users saw no focus indicator at all.
Added `focus-visible:ring-ring/50 focus-visible:ring-2
focus-visible:outline-none focus-visible:ring-offset-2` matching
the v1.4.33 sidebar treatment.
- Mobile top-bar trigger had `focus:outline-none` without a
`focus-visible` replacement. Same treatment applied.
Tap-target floor (WCAG 2.5.5):
- Input / NativeSelect / Select / DateTimeInput were locked to
h-10 (40 px) on every viewport. Switched to `h-11 sm:h-10` so
mobile clears the 44 px floor while desktop keeps the 40 px norm
that the Button primitive already converged on in v1.4.33.
Admin chip-strip auto-scroll-into-view:
- The admin shell shipped 13 chips but lacked the
`scrollIntoView({inline: 'center'})` effect the settings shell
got in v1.4.33. Admins tapping a chip past the right edge landed
on the new page with the strip scrolled to the left and the
active chip off-screen. Copied the settings-shell pattern verbatim.
List-page subtitles on mobile:
- Measurements / Mood / Medications pages hid their descriptive
subtitle on `<sm` with `hidden sm:block`. Comparable apps keep
the subtitle on mobile because it doubles as contextual help.
Dropped the hide rule; the H1 still anchors the visual.
Insights empty-state CTA vocabulary:
- `ALLOWED_ADD_TYPES` on `/measurements` accepted tokens (`GLUCOSE`,
`TEMPERATURE`, `HEART_RATE`, `BMI`) that didn't match the
`MEASUREMENT_TYPES` enum the form uses. Several `/insights/*`
empty-state CTAs emitted those mismatched tokens and the dialog
silently failed to open. Replaced with a single source of truth
derived from `MEASUREMENT_TYPES` plus a normalisation map for
legacy tokens. Added BODY_TEMPERATURE to the form's enum row.
New unit test walks every `?add=` token emitted under
`src/app/insights/**` and asserts it resolves to a real form type.
The mobile bottom tab-bar bled into the bottom of the visible area on
/settings/account and /settings/ai per the runtime audit. The bar
previously rendered as bg-card/80 (80% opacity, translucent) and
relied on the inner flex row's h-16 alone for its height — without
a min-height floor on the outer nav, a future variant or any flex-
collapse quirk could let the surface shrink under the 64px floor the
auth-shell counts on.
Pin the bar at min-h-16 on the outer nav (defence in depth against
flex collapse) and switch the surface from bg-card/80 to a solid
bg-card. The safe-area inset and fixed bottom-anchor stay as they
were. Page shells that scroll content beneath the bar are still
responsible for reserving pb-16 + safe-area on their main column;
this change makes the bar itself robust so any future page-shell
oversight produces a hard occlusion (visibly broken on review)
rather than a translucent bleed (silently shipped). Bottom-nav SSR
test stays green (4/4) — five primary anchors, More button,
aria-haspopup, 44px tap-target floor.
Refs: .planning/round-v1433-audit-runtime.md F14
The 7-item bottom nav collapsed each touch target to ~50 px wide on
a 375 px viewport — only just-passing WCAG 2.5.5's 44 px floor and
visibly cramped on iPhone-13-mini-class screens. The mobile audit
(`.planning/phase-A5-mobile-findings.md`) recommended 5+More.
Primary strip keeps the four most-used surfaces plus Insights:
Home, Measurements, Mood, Medications, Insights. Targets and
Achievements move into a Radix `<Sheet>` triggered by a sixth
"More" entry. Order matches the v1.4.15 layout for the four core
items so muscle memory holds.
The More button mirrors the same `min-h-11 min-w-11` hit area;
`aria-haspopup="dialog"` + `aria-expanded` keeps screen-reader
behaviour tight; the sheet renders bottom-anchored with safe-area
padding so the inner links stay reachable above the iPhone home
indicator. Active styling lights the More entry whenever any of
its overflow children is the current route, so the user always
knows which strip-level link "owns" their position.
UX/a11y residuals from 2026-04-26 audit:
- bottom-nav: touch targets sized to WCAG 2.5.5 minimum (44x44 CSS px)
via min-h-11 min-w-11 on each Link. Nav height bumped to h-16 to
accommodate. Visual icon stays at 20px so design doesn't shift.
- phase-config-dialog: decorative coloured dot now aria-hidden because
the redundant text label ("Green"/"Yellow"/...) already conveys the
phase. Screen readers no longer announce a meaningless 'image' node.
- admin: 'Web Push' and 'Bug Report' labels were hard-coded English in
StatusItem and SettingsToggle calls; now go through t() with new
admin.integrationWebPush / admin.integrationBugReport keys (en + de).
- medication-card: false-positive en-CA / en-US locale audit findings
documented inline — those are intentional locale-independent helpers
(en-CA gives YYYY-MM-DD for day-comparison, en-US gives a parseable
string for the toBerlinDate timezone hack), not user-facing display.
Switch defaultLocale from "de" to "en" and make English the code-level
language throughout. All ~145 hardcoded German strings translated:
- API error messages (52 routes) now return English
- Zod validation messages in English
- Classification/analytics functions return English categories
- Notification type labels in English
- Component strings use i18n t() calls (heatmap, mood chart,
medication form, intake history, password strength, insights card)
- ~50 new i18n keys in both de.json and en.json
Route migration:
- /stimmung → /mood, /zielwerte → /targets (new pages)
- 301 redirects in proxy.ts for legacy URLs
- Sidebar + bottom nav updated
Bump version to 1.0.1.
HealthLog — personal health-tracking PWA with weight, blood pressure,
pulse, mood tracking, medication compliance, Withings integration,
doctor report PDF export, and Dracula-themed UI.