diff --git a/messages/de.json b/messages/de.json
index 98a22e99b..e76f04971 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} Pens übrig · ~{weeks} Wochen Reichweite",
"glp1InventoryLow": "Niedriger Bestand — bald nachbestellen",
"glp1LogSideEffect": "Nebenwirkung loggen",
+ "injectionSiteBodyOutlineAriaLabel": "Körperumriss",
+ "injectionSitePickerAriaLabel": "Injektionsstelle auswählen",
"siteAbdomenLeft": "Bauch, unten links",
"siteAbdomenRight": "Bauch, unten rechts",
"siteAbdomenUpperLeft": "Bauch, oben links",
diff --git a/messages/en.json b/messages/en.json
index c63da8fa7..fcc96abec 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} pens left · ~{weeks} weeks of supply",
"glp1InventoryLow": "Low stock — refill soon",
"glp1LogSideEffect": "Log side effect",
+ "injectionSiteBodyOutlineAriaLabel": "Body outline",
+ "injectionSitePickerAriaLabel": "Injection site picker",
"siteAbdomenLeft": "Abdomen, lower left",
"siteAbdomenRight": "Abdomen, lower right",
"siteAbdomenUpperLeft": "Abdomen, upper left",
diff --git a/messages/es.json b/messages/es.json
index dcefbb9f9..84b1a3401 100644
--- a/messages/es.json
+++ b/messages/es.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} pens left · ~{weeks} weeks of supply",
"glp1InventoryLow": "Low stock — refill soon",
"glp1LogSideEffect": "Log side effect",
+ "injectionSiteBodyOutlineAriaLabel": "Silueta del cuerpo",
+ "injectionSitePickerAriaLabel": "Selector de sitio de inyección",
"siteAbdomenLeft": "Abdomen, lower left",
"siteAbdomenRight": "Abdomen, lower right",
"siteAbdomenUpperLeft": "Abdomen, upper left",
diff --git a/messages/fr.json b/messages/fr.json
index f51755eda..391fb2282 100644
--- a/messages/fr.json
+++ b/messages/fr.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} pens left · ~{weeks} weeks of supply",
"glp1InventoryLow": "Low stock — refill soon",
"glp1LogSideEffect": "Log side effect",
+ "injectionSiteBodyOutlineAriaLabel": "Silhouette du corps",
+ "injectionSitePickerAriaLabel": "Sélecteur de site d'injection",
"siteAbdomenLeft": "Abdomen, lower left",
"siteAbdomenRight": "Abdomen, lower right",
"siteAbdomenUpperLeft": "Abdomen, upper left",
diff --git a/messages/it.json b/messages/it.json
index 67b02a25b..e1b616912 100644
--- a/messages/it.json
+++ b/messages/it.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} pens left · ~{weeks} weeks of supply",
"glp1InventoryLow": "Low stock — refill soon",
"glp1LogSideEffect": "Log side effect",
+ "injectionSiteBodyOutlineAriaLabel": "Sagoma del corpo",
+ "injectionSitePickerAriaLabel": "Selettore del sito di iniezione",
"siteAbdomenLeft": "Abdomen, lower left",
"siteAbdomenRight": "Abdomen, lower right",
"siteAbdomenUpperLeft": "Abdomen, upper left",
diff --git a/messages/pl.json b/messages/pl.json
index f2a472673..569f95b3b 100644
--- a/messages/pl.json
+++ b/messages/pl.json
@@ -573,6 +573,8 @@
"glp1Inventory": "{pens} pens left · ~{weeks} weeks of supply",
"glp1InventoryLow": "Low stock — refill soon",
"glp1LogSideEffect": "Log side effect",
+ "injectionSiteBodyOutlineAriaLabel": "Sylwetka ciała",
+ "injectionSitePickerAriaLabel": "Wybór miejsca iniekcji",
"siteAbdomenLeft": "Abdomen, lower left",
"siteAbdomenRight": "Abdomen, lower right",
"siteAbdomenUpperLeft": "Abdomen, upper left",
diff --git a/src/components/i18n/maintainership-banner.tsx b/src/components/i18n/maintainership-banner.tsx
index 64acbe73a..329c678ec 100644
--- a/src/components/i18n/maintainership-banner.tsx
+++ b/src/components/i18n/maintainership-banner.tsx
@@ -109,7 +109,9 @@ export function MaintainershipBanner() {
type="button"
onClick={handleDismiss}
aria-label={t("i18n.maintainershipBanner.dismiss")}
- className="hover:text-foreground -mr-1 -mt-0.5 shrink-0 rounded-sm p-1 transition-colors"
+ // 44×44 touch-target floor (WCAG 2.5.5). The icon stays small —
+ // the surrounding hit area is what the user actually taps.
+ className="hover:text-foreground focus-visible:ring-ring/50 -mr-2 inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-sm transition-colors focus-visible:ring-2 focus-visible:outline-none"
>
diff --git a/src/components/insights/insights-tab-strip.tsx b/src/components/insights/insights-tab-strip.tsx
index dbf4b5743..e989a6a82 100644
--- a/src/components/insights/insights-tab-strip.tsx
+++ b/src/components/insights/insights-tab-strip.tsx
@@ -130,7 +130,10 @@ export function InsightsTabStrip({
data-slot="insights-tab-strip-pill"
data-active={isActive ? "true" : undefined}
className={cn(
- "shrink-0 rounded-full border px-3 py-1 text-xs font-medium transition-colors",
+ // 44px touch-target floor (W8.3) — pills are primary
+ // navigation; the regenerate icon-button to the right
+ // already meets the same minimum.
+ "inline-flex min-h-11 shrink-0 items-center rounded-full border px-3 py-1 text-xs font-medium transition-colors",
"focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
isActive
? "border-primary bg-primary/10 text-primary"
@@ -151,11 +154,10 @@ export function InsightsTabStrip({
title={regenerateLabel}
data-slot="insights-tab-strip-regenerate"
className={cn(
- // 44×44 touch target — Marc directive 2026-05-14. The
- // pill row above sits 28px tall; the button breaks the
- // band height intentionally so the touch target meets
- // the WCAG 2.5.5 minimum without forcing the pills to
- // grow.
+ // 44×44 touch target — same WCAG 2.5.5 floor the pill row
+ // now honours via `min-h-11`. The button stays circular so
+ // its visual weight matches the existing top-bar icon
+ // buttons.
"inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full",
"text-muted-foreground hover:text-foreground hover:bg-accent",
"transition-colors",
diff --git a/src/components/insights/sub-page-shell.tsx b/src/components/insights/sub-page-shell.tsx
index cc8abfc7a..3699d1068 100644
--- a/src/components/insights/sub-page-shell.tsx
+++ b/src/components/insights/sub-page-shell.tsx
@@ -68,7 +68,11 @@ export function SubPageShell({
tabIndex={-1}
className={cn(
"text-xl font-semibold sm:text-2xl",
- "focus-visible:outline-none",
+ // a11y: sighted-keyboard users (e.g. "Skip to content")
+ // need a visible focus indicator on the programmatic
+ // `headingRef.focus()` call below. Match the focus ring
+ // vocabulary used on insights pills + Coach affordances.
+ "rounded-sm focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
)}
>
{title}
diff --git a/src/components/medications/injection-site-picker.tsx b/src/components/medications/injection-site-picker.tsx
index 735dd3470..f4246728a 100644
--- a/src/components/medications/injection-site-picker.tsx
+++ b/src/components/medications/injection-site-picker.tsx
@@ -51,13 +51,13 @@ export function InjectionSitePicker({