diff --git a/src/components/dashboard/__tests__/dashboard-header.test.tsx b/src/components/dashboard/__tests__/dashboard-header.test.tsx index 7746aaf6a..9b45f6014 100644 --- a/src/components/dashboard/__tests__/dashboard-header.test.tsx +++ b/src/components/dashboard/__tests__/dashboard-header.test.tsx @@ -43,4 +43,15 @@ describe(" — greeting", () => { // The title itself stays. expect(html).toContain("Dashboard"); }); + + // 2026-07-17 a11y audit (M4) — the dashboard is the app's landing surface + // and must expose a page-level `

`. It comes from the shared + // `PageHeader` the header renders, so a screen-reader user navigating by + // heading lands on a real page anchor (not the Today hero's muted `

` + // micro-label). No separate sr-only heading is added — that would double + // the `h1`. + it("renders a real page-level h1 with the dashboard title", () => { + const html = renderSSR( undefined} />); + expect(html).toMatch(/]*>Dashboard<\/h1>/); + }); }); diff --git a/src/components/insights/derived/coach-read-strip.tsx b/src/components/insights/derived/coach-read-strip.tsx index 8971fd4ea..94a847fee 100644 --- a/src/components/insights/derived/coach-read-strip.tsx +++ b/src/components/insights/derived/coach-read-strip.tsx @@ -123,6 +123,9 @@ export function CoachReadStrip({ diff --git a/src/components/insights/metric-target-summary.tsx b/src/components/insights/metric-target-summary.tsx index 41d4eec69..aec8c9079 100644 --- a/src/components/insights/metric-target-summary.tsx +++ b/src/components/insights/metric-target-summary.tsx @@ -316,6 +316,9 @@ function TargetReferencePanel({