From f602307b5fe862783567d47507361856986c9b3a Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sun, 30 Aug 2026 13:08:44 -0700 Subject: [PATCH] fix(website): AnnouncementToast mobile presentation and a11y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remaining two toast items from the polish-arc deferred list: - Mobile width (findings §6): below 480px the 360px right-hugging card covered 327px of a 375px screen; it now presents as a centered bottom sheet with even 16px margins and tighter padding. - A11y: the root was role=alert + aria-live on interactive content (CTA button and email form) — now a non-modal role=dialog labelled by the title, which never steals focus on entry. Escape dismisses once focus is inside. The close button gets a hover state, a focus-visible ring, and a 44px hit target via ::after (findings §7). The 'sent' success message is role=status so the step swap is still announced. Verified in-browser at 375: 16px margins, close hit 46x50, Escape dismisses and persists the dismissal. nx test green, lint 0 errors, production build green. Co-Authored-By: Claude Opus 5 --- .../components/shared/AnnouncementToast.tsx | 16 ++++++++--- apps/website/src/styles/chrome.css | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/apps/website/src/components/shared/AnnouncementToast.tsx b/apps/website/src/components/shared/AnnouncementToast.tsx index ba86f79e2..1d1743673 100644 --- a/apps/website/src/components/shared/AnnouncementToast.tsx +++ b/apps/website/src/components/shared/AnnouncementToast.tsx @@ -85,11 +85,18 @@ export function AnnouncementToast() { if (!visible) return null; return ( + // Non-modal dialog, not role="alert": an alert/live region must not hold + // interactive content (the CTA button and email form live here), and + // assertive announcement of a marketing prompt is hostile. Focus is never + // stolen on entry; Escape dismisses once focus is inside.
{ + if (e.key === 'Escape') dismiss(); + }} > {/* Dismiss button */}