# Accessibility Conformance Report

## VPAT 2.4 Rev — WCAG Edition

---

| Field | Detail |
|---|---|
| **Product Name** | DWEL Public Marketing Website (dwel.digital) |
| **Product Version** | 1.0.0 |
| **Report Date** | April 22, 2026 |
| **Contact Information** | accessibility@dwel.digital |
| **Report Prepared By** | Dwel.Digital Engineering — Internal Accessibility Team |

---

## Executive Summary

The DWEL public marketing website (dwel.digital) is the employer-facing
information site for DWEL's Voice-First Care Orchestration Platform.
The site comprises 15 static marketing routes plus a 404 page, served
by a minimal Express static server. It is the entry point used by
HR / Total Rewards / Benefits buyers, working caregivers, and care
recipients evaluating the DWEL benefit. There is no authentication,
no persisted user data, and no third-party identity provider in scope
for this report.

This Accessibility Conformance Report evaluates **the public marketing
website only**. The authenticated DWEL application is excluded from
scope and is covered by a separate report
(`VPAT-DWEL-App-v2.0.0-WCAG22.md`).

The site was evaluated against **WCAG 2.2 Level A and Level AA**
success criteria using a combination of automated testing (`axe-core`
4.11 driven by Playwright + `@axe-core/playwright`, applied to every
route at three viewports and across all interaction states) and manual
testing (keyboard traversal, screen reader spot-check with VoiceOver,
contrast token audit, WCAG 2.2 new-criteria check, reduced-motion and
zoom checks). The full automated baseline and the manual checklist are
preserved in this repository at `reports/a11y-axe-final.{json,md}` and
`docs/accessibility-manual-checks.md` respectively.

**Overall finding:** The DWEL public marketing website v1.0.0
**Supports** WCAG 2.2 Level AA. The most recent automated run produced
**zero violations across 57 page-runs** (16 routes × 3 viewports plus
interaction states for the mobile menu, FAQ accordion, contact form
submission, and impact-calculator inputs). All custom-built components,
forms, navigation, video showcases, and content sections fully support
the applicable criteria. The two third-party scope carve-outs — the
YouTube embedded player on `/how-it-works` and the optional Cookiebot
consent banner — are documented under "Assumptions and Limitations"
and remain the responsibility of those upstream vendors. No Blocker-,
Critical-, or Serious-severity issues were identified within the
DWEL-authored scope.

---

## Evaluation Methods Used

1. **Automated Testing** — `axe-core` 4.11 invoked through
   `@axe-core/playwright` 2.x by `scripts/a11y-audit.ts`. The harness
   serves the production build out of `dist/public`, then visits every
   public route at three viewports (1280×800 desktop, 1024×768 tablet,
   375×812 mobile). For routes with interactive primitives (mobile
   menu open on every route at desktop, FAQ accordion expanded on
   `/faq`, contact form submission state on `/contact`, calculator
   value-changed state on `/impact-calculator`) axe is re-run after
   driving the interaction. The harness fails CI with a non-zero exit
   code if any WCAG 2.2 A or AA rule fires. Output:
   `reports/a11y-axe-final.{json,md}`.
2. **Manual Keyboard Testing** — Tab order, focus visibility, Escape
   key behavior, Enter/Space activation, arrow-key navigation in
   composite widgets (language switcher menu, FAQ accordion,
   calculator assumptions popover), skip-link operability, and
   absence of keyboard traps.
3. **Screen Reader Spot Check** — VoiceOver on macOS Sonoma + Safari
   was used on the six routes most likely to be used by an evaluator
   (`/`, `/employers`, `/how-it-works`, `/impact-calculator`, `/faq`,
   `/contact`) for landmark navigation, heading hierarchy, live region
   announcements, form label associations, and error message
   announcement.
4. **Visual Inspection** — Contrast ratio verification using browser
   DevTools and manual computation from the CSS custom-property HSL
   values in `client/src/index.css`. Focus indicator visibility in
   both light and dark modes. 200 % zoom and 320 px reflow checks.
5. **Code Review** — Static analysis of the React component tree under
   `client/src/pages/site-*.tsx` and `client/src/components/site/*` for
   `aria-hidden` on decorative icons, `aria-label` on icon-only
   buttons, role assignments, `aria-live` regions, `aria-expanded` /
   `aria-controls` pairs, `<title>` updates via `react-helmet-async`,
   `htmlFor` / `id` label associations, keyboard event handlers, and
   focus refs.

The full manual checklist with per-criterion pass status is captured in
`docs/accessibility-manual-checks.md` and is the evidence base for the
"Supports" determinations below.

---

## Applicable Standards and Guidelines

This report evaluates conformance to:

- **Web Content Accessibility Guidelines (WCAG) 2.2** — Level A and
  Level AA
- Published by the World Wide Web Consortium (W3C), December 2023

---

## Terms

| Term | Definition |
|---|---|
| **Supports** | The functionality of the product has at least one method that meets the criterion without known defects or meets with equivalent facilitation. |
| **Partially Supports** | Some functionality of the product does not meet the criterion. |
| **Does Not Support** | The majority of product functionality does not meet the criterion. |
| **Not Applicable** | The criterion is not relevant to the product. |

---

## Scope of Evaluation

This report covers the following public marketing routes, shared
layout primitives, and global states:

1. `/` — home / hero / hidden-tax overview
2. `/employers` — employer value proposition + ROI cards
3. `/caregivers` — caregiver value proposition
4. `/care-recipients` — care-recipient value proposition
5. `/how-it-works` — explainer video, chapters, screenshots
6. `/demo` — demo request form
7. `/impact-calculator` — interactive ROI calculator with charts
8. `/about` — about DWEL
9. `/trust` — trust, privacy, security pillars
10. `/faq` — frequently asked questions accordion
11. `/sources` — research sources cited across the site
12. `/contact` — contact form and email link
13. `/accessibility` — accessibility statement (this VPAT is linked here)
14. `/privacy` — privacy policy
15. `/terms` — terms of use
16. 404 — Not Found page (any non-routed URL)
17. Shared `SiteLayout` — sticky header, primary navigation, mobile
    menu, language switcher, theme switcher, footer
18. All accordion expand/collapse states, mobile menu open state,
    contact form validation/submission state, impact-calculator
    input-changed states, demo form validation state
19. Light mode and dark mode (theme toggle in the header)
20. Desktop (1280×800), tablet (1024×768), and mobile (375×812)
    breakpoints
21. English (`en`) and Spanish (`es`) localizations toggled via the
    in-header language switcher

**Excluded from scope:** the authenticated DWEL application
(separate report), email clients used to render contact replies, the
internal markup of the YouTube embedded player iframe on
`/how-it-works` (third party), the internal markup of the Cookiebot
consent banner when that vendor is configured (third party), Twilio
voice quality (no live audio is used on the marketing site).

---

## Assumptions and Limitations

1. **YouTube embedded player on `/how-it-works`** — The page hosts a
   YouTube video via the standard `<iframe>` embed. The `<iframe>` is
   given a meaningful `title` attribute, is keyboard-operable, and is
   placed inside a labelled section. The iframe's internal DOM
   (`#movie_player`, channel-avatar button, captions menu, etc.) is
   controlled by YouTube and cannot be modified by DWEL. The automated
   harness explicitly excludes `iframe` content from analysis (see
   `scripts/a11y-audit.ts`); conformance for the player's internal
   markup is the responsibility of YouTube / Google.
2. **Cookiebot consent banner** — When configured (gated by a
   build-time environment variable), Cookiebot injects its own DOM
   for the consent banner. DWEL configures Cookiebot to AA conformance
   via the vendor dashboard but does not author its markup. The site
   itself does not auto-trigger any non-essential script before
   consent is captured.
3. **Forms are frontend-only on this site.** The `/demo` and
   `/contact` forms are React frontends with placeholder submission
   handlers (the site has no API routes). Evaluation covers the form
   semantics, label associations, validation, error announcement,
   focus management, and the success / failure status messages.
4. **Browsers tested:** Chromium 125 (the engine used by the
   automated harness), Safari 17.6 + VoiceOver (manual screen reader
   spot check), Firefox 127 (manual keyboard pass).
5. **Animations:** The site uses `ScrollReveal` (opacity + translate
   entrance) and `AnimatedCounter` (numeric count-up) on hero and
   stat cards. Both honor `prefers-reduced-motion: reduce` and skip
   directly to the final state when the user has requested reduced
   motion. The audit harness scrolls each page once before invoking
   axe so that contrast is measured against the final visible state,
   not the entrance state.

---

## WCAG 2.2 Level A Conformance Table

| Criteria | Conformance Level | Remarks and Explanations |
|---|---|---|
| **1.1.1 Non-text Content** | Supports | Decorative Lucide icons across header, footer, hero quad cards, value-prop cards, and trust pillars use `aria-hidden="true"`. Functional icon-only buttons (mobile menu trigger, language switcher trigger, theme toggle, calculator assumptions info) have descriptive `aria-label` text. The video poster image and content imagery use descriptive `alt` text via the `<VideoShowcase>` and `<ImageShowcase>` primitives. The DWEL wordmark logo in the header has accessible text. |
| **1.2.1 Audio-only and Video-only** | Not Applicable | The site does not serve pre-recorded audio-only content. The product overview videos on `/how-it-works` and the smaller marketing clips embedded via `<VideoShowcase>` are not video-only — they are paired with descriptive on-page copy and section headings. |
| **1.2.2 Captions (Prerecorded)** | Supports | The YouTube product overview video on `/how-it-works` is delivered with creator-uploaded captions enabled by default and a YouTube auto-caption fallback. Each shorter `<VideoShowcase>` clip is silent (no spoken audio) and is paired with descriptive textual context in the same section. |
| **1.2.3 Audio Description or Media Alternative** | Supports | The product overview video is supplemented by full textual chapters (`videoChapters`) and an explanatory section directly below the embed that describes the same content in prose, providing a media alternative. Shorter clips are silent and paired with prose. |
| **1.3.1 Info and Relationships** | Supports | Headings follow a logical hierarchy on every route: a single `<h1>` per page (set inside `<main id="main-content">`), `<h2>` for section headings, `<h3>` for sub-section headings. The `axe-core/heading-order` rule passes on all 16 routes after a remediation pass that reclassified `/trust` card headings to `<h2>` and the `/privacy` and `/terms` section headings to `<h2>` (with their sub-sections to `<h3>`). Form fields use shadcn `<Label htmlFor>` with explicit `id` associations. Lists in the FAQ and footer use semantic `<ul>` / `<li>` markup or shadcn Accordion which exposes the correct ARIA structure. Landmark roles (`<header>`, `<nav>`, `<main>`, `<footer>`) are unique per page. |
| **1.3.2 Meaningful Sequence** | Supports | DOM order matches visual presentation order across all 15 routes plus the 404 at all three viewports. Tab order follows the logical reading order. Mobile responsive layouts reflow without altering the logical sequence; the hero quadrant cards stack into a 2×2 grid on mobile but DOM order is preserved. |
| **1.3.3 Sensory Characteristics** | Supports | Instructions never rely solely on shape, color, size, or location. Stat cards always pair the numeric figure with a textual label. The "View sources" links use textual cues rather than purely visual ones. The calculator's "Assumptions" affordance pairs the info icon with the visible word "Assumptions" via `aria-label`. |
| **1.4.1 Use of Color** | Supports | Color is never the sole means of conveying information. Form validation errors are accompanied by text. Active navigation links are indicated by both color and an underline. The accordion expanded state is conveyed by chevron rotation, color, and an `aria-expanded` attribute. |
| **1.4.2 Audio Control** | Not Applicable | No audio plays automatically. The YouTube product overview requires explicit user activation. The `<VideoShowcase>` clips that may auto-play (only when `prefers-reduced-motion` is not set) are muted and have no audio track. |
| **2.1.1 Keyboard** | Supports | All custom interactive elements (header nav links, mobile menu trigger and overlay, language switcher menu, theme toggle, FAQ accordion triggers, demo form, contact form, calculator inputs and assumptions popover, video play affordance, footer links) are operable via Tab, Enter, Space, Escape, and arrow keys. Radix UI primitives wrapped by shadcn (`DropdownMenu`, `Accordion`, `Popover`, `Toast`) supply full keyboard support. |
| **2.1.2 No Keyboard Trap** | Supports | Focus is trapped within the open mobile menu, the language switcher, and the calculator assumptions popover (Radix behavior) with Escape to close and focus restoration to the trigger. No keyboard traps were identified in any tested flow. |
| **2.1.4 Character Key Shortcuts** | Not Applicable | The site does not implement single-character keyboard shortcuts. |
| **2.2.1 Timing Adjustable** | Supports | No time limits are imposed on form completion or any other interaction. Toast notifications announcing form success / failure remain visible long enough to be read and can be dismissed manually. |
| **2.2.2 Pause, Stop, Hide** | Supports | The animated counters on the home hero are short (≤ 1.5 s, monotonic, single-iteration) and complete on initial scroll-into-view; they do not auto-update further. Scroll-reveal entrance animations are one-time per element. Both honor `prefers-reduced-motion: reduce`. The `<VideoShowcase>` autoplay-when-not-reduced clips have no audio and present a visible pause control via the native HTML video controls. No marquee, ticker, or auto-updating content is present. |
| **2.3.1 Three Flashes or Below Threshold** | Supports | No content flashes more than three times per second. The animated counters are smooth numeric increments, not flashes. |
| **2.4.1 Bypass Blocks** | Supports | A skip-to-main-content link is the first focusable element in `SiteLayout`. It targets `#main-content`, becomes visible on focus, and meets contrast requirements. Each route renders content inside `<main id="main-content">`. |
| **2.4.2 Page Titled** | Supports | Every route sets a unique, descriptive `<title>` via the `<SEOHead>` component (`react-helmet-async`). Examples: "DWEL — Voice-First Care Orchestration", "For Employers — DWEL", "Impact Calculator — DWEL", "Frequently Asked Questions — DWEL", "Page Not Found — DWEL". |
| **2.4.3 Focus Order** | Supports | Focus order follows the visual layout on all tested routes at all three viewports. The mobile menu, language switcher, and calculator assumptions popover return focus to their trigger on close. |
| **2.4.4 Link Purpose (In Context)** | Supports | All links have descriptive text or `aria-label` text. Footer social icon links use `aria-label` (e.g. "DWEL on LinkedIn"). The "View sources" inline links carry their own text plus their containing section context. The header logo link has accessible text "DWEL — home". |
| **2.5.1 Pointer Gestures** | Supports | No multi-point or path-based gestures are required. All interactions can be completed with single-pointer actions (click / tap). |
| **2.5.2 Pointer Cancellation** | Supports | All click / tap actions fire on the `click` event (up event), not on pointer down. No actions complete on the down event alone. |
| **2.5.3 Label in Name** | Supports | Visible button labels match their accessible names. Buttons with icons and text use the visible text as the accessible name. Icon-only buttons (mobile menu, language switcher, theme toggle) use `aria-label` text that begins with or contains the visible context word ("Menu", "Language", "Theme"). |
| **2.5.4 Motion Actuation** | Not Applicable | No functionality is triggered by device motion or user motion. |
| **3.1.1 Language of Page** | Supports | The `<html>` element has `lang` set, and the `useViewPreferences` context updates `document.documentElement.lang` to `en` or `es` when the user toggles the language switcher. |
| **3.2.1 On Focus** | Supports | No change of context occurs when any component receives focus. Focus events trigger only visual focus indicators. |
| **3.2.2 On Input** | Supports | No change of context occurs on input without explicit user action. The impact-calculator updates its derived numbers and chart values when inputs change, which is a same-context update of a result region, not a context change. |
| **3.3.1 Error Identification** | Supports | Form validation errors on `/demo` and `/contact` are displayed as text adjacent to the failing field with `role="alert"` semantics provided by shadcn `<FormMessage>`. Submission failures display a toast with `role="status"` and a textual error message. |
| **3.3.2 Labels or Instructions** | Supports | All form fields use shadcn `<Label>` with `htmlFor` association. The calculator inputs (hourly rate, employee count, period selector) have visible labels and unit suffixes. The demo and contact forms use placeholder text only on masked / formatted inputs and `<SelectValue>` dropdowns, per the project's placeholder policy. |

---

## WCAG 2.2 Level AA Conformance Table

| Criteria | Conformance Level | Remarks and Explanations |
|---|---|---|
| **1.3.4 Orientation** | Supports | The site is fully responsive and functional in both portrait and landscape orientations. No content is restricted to a single orientation. Layouts reflow at all tested breakpoints (375, 1024, 1280). |
| **1.3.5 Identify Input Purpose** | Supports | Form inputs use appropriate `type` attributes (`email`, `tel`, `text`, `number`) and `autocomplete` tokens (`name`, `email`, `tel`, `organization`) on the contact and demo forms. The calculator's numeric inputs use `inputMode="decimal"` for mobile keyboards. |
| **1.4.3 Contrast (Minimum)** | Supports | All text meets the 4.5:1 contrast ratio for normal text and 3:1 for large text. Light mode token verification: `--foreground` (HSL 200 20% 15%) on `--background` (HSL 180 20% 99%) ≈ 14.5:1; `--muted-foreground` was tightened from `200 10% 40%` to `200 10% 32%` to give ≈ 7.4:1 on the page background; `--primary` (HSL 181 91% 24%) gives white-on-primary ≈ 5.0:1 (the prior 27 % lightness produced ≈ 4.45:1 and was tightened in the same remediation pass); `text-primary` on `bg-primary/10` ≈ 4.6:1. Dark mode tokens spot-checked at ≥ 4.5:1 across the same pairs. The `axe-core/color-contrast` rule passes on all 16 routes at all three viewports. |
| **1.4.4 Resize Text** | Supports | Text resizes correctly up to 200 % browser zoom without loss of content or functionality. Tailwind utility classes use relative sizing that accommodates zoom. Verified across all 15 marketing routes plus 404 at desktop. |
| **1.4.5 Images of Text** | Supports | No images of text are used on the site. The DWEL wordmark is rendered as styled HTML / SVG text. All copy is rendered as actual text. |
| **1.4.10 Reflow** | Supports | At 320 CSS px width, all content reflows into a single column without horizontal scrolling. The sticky header collapses into a hamburger pattern. The impact-calculator chart container is the only horizontally-scrollable region, and that scroll is intentional and announced. |
| **1.4.11 Non-text Contrast** | Supports | UI component boundaries (buttons, inputs, accordion triggers, badges, card borders) meet the 3:1 contrast ratio against adjacent colors. Focus indicators use `--ring` with a 2 px outline plus 2 px offset, giving well above 3:1 against both light and dark backgrounds. Border tokens were verified directly against background tokens. |
| **1.4.12 Text Spacing** | Supports | Content remains visible and functional when text spacing is increased to WCAG-specified values (line-height 1.5×, letter-spacing 0.12 em, word-spacing 0.16 em, paragraph spacing 2×). No text is clipped in containers. Verified at desktop and mobile. |
| **1.4.13 Content on Hover or Focus** | Supports | Tooltip and popover content (calculator assumptions popover via Radix) is dismissible with Escape, hoverable without disappearing, and persistent until the user moves the pointer or focus away. Dropdown menus follow the same pattern. No hover-triggered content obscures other interactive elements. |
| **2.4.5 Multiple Ways** | Supports | Users can reach content through multiple methods: primary navigation in the header, the mobile menu, in-page anchor links (e.g. `#video-overview` from the home hero CTA, `#home` and `#employers` anchors on `/sources`), the footer link list, the sitemap implied by `client/src/App.tsx`, direct URL entry, and the 404 page's "Back to home" link. |
| **2.4.6 Headings and Labels** | Supports | Headings accurately describe the content they introduce. Each route has a single `<h1>` matching the page's primary topic. Section `<h2>` headings are descriptive (e.g. "The hidden tax of working caregivers", "How DWEL works"). Form labels clearly describe the expected input. |
| **2.4.7 Focus Visible** | Supports | All interactive elements display a visible focus indicator. The site uses a consistent focus ring (2 px outline in primary teal with 2 px offset) across buttons, links, inputs, accordion triggers, and dropdown menus. Focus visibility is maintained in both light and dark modes. The skip link becomes fully visible when focused. |
| **2.4.11 Focus Not Obscured (Minimum)** | Supports | The sticky header is 64 px tall; `scroll-padding-top` is set on the document so that focused elements activated by the skip link or in-page anchors land below the header rather than under it. The mobile menu overlay closes before focus is allowed to leave its bounds. Verified by tabbing through anchored sections on `/sources`, `/faq`, and `/how-it-works`. |
| **2.5.7 Dragging Movements** | Not Applicable | The site has no drag interactions. The recharts charts on `/impact-calculator` are read-only and do not require dragging. The `<VideoShowcase>` clips use the native HTML5 video element which is operable without dragging. |
| **2.5.8 Target Size (Minimum)** | Supports | All interactive targets meet the 24 × 24 CSS px minimum. shadcn Button defaults to `min-h-9` (36 px); `size="lg"` to `min-h-10` (40 px); `size="sm"` to `min-h-8` (32 px); `size="icon"` to 36 × 36 px. Header icon-only buttons (mobile menu, language, theme) are 36 × 36 px. Footer social icon links are 36 × 36 px. Inline links inside paragraphs fall under the 2.5.8 inline-text exception. |
| **3.1.2 Language of Parts** | Supports | The site is offered in English and Spanish via the in-header language switcher. When the user toggles the language, the `useViewPreferences` context updates `document.documentElement.lang` to match (`en` or `es`), and the entire visible content region is rendered in the selected language from the `client/src/lib/i18n/translations.ts` dictionary. There are no mixed-language regions that would require additional `lang` attributes on sub-elements. |
| **3.2.3 Consistent Navigation** | Supports | Navigation patterns are consistent across all 15 routes plus the 404. The header (logo, primary nav, language / theme switcher, "Get a Demo" CTA) appears in the same position and order on every page. The footer (sections of links, social icons, copyright, contact email) appears in the same position and order on every page. The mobile menu always opens from the same trigger and contains the same items. |
| **3.2.4 Consistent Identification** | Supports | Components with the same functionality are identified consistently. The "Get a Demo" CTA button uses the same label and visual treatment in the header on every page. "View sources" inline links use the same wording everywhere they appear. Social icon links use consistent `aria-label` patterns ("DWEL on LinkedIn", "DWEL on YouTube"). The contact email `info@dwel.digital` is presented identically on `/contact` and `/accessibility`. |
| **3.2.6 Consistent Help** | Supports | A persistent contact path is offered on every route via the footer's "Contact" link, which routes to `/contact`. The `/accessibility` page additionally surfaces the accessibility contact email and a link to this VPAT, satisfying the WCAG 2.2 expectation that help mechanisms appear in a consistent location across the site. |
| **3.3.3 Error Suggestion** | Supports | When input errors are detected on the demo or contact forms, suggestions for correction are provided. Email validation announces the expected format. Required field errors specify which field needs input. The phone-number field accepts common formats. |
| **3.3.4 Error Prevention (Legal, Financial, Data)** | Not Applicable | The marketing site does not process legal, financial, or sensitive personal data. The `/demo` and `/contact` forms collect non-sensitive contact information for sales follow-up only; users may freely re-submit. There are no irrevocable transactions on the site. |
| **3.3.7 Redundant Entry** | Supports | The site does not require users to re-enter information that was previously provided in the same session. The demo and contact forms are single-page forms with no multi-step retention requirement. |
| **3.3.8 Accessible Authentication (Minimum)** | Not Applicable | The marketing site has no authentication. All content is public. |
| **4.1.2 Name, Role, Value** | Supports | Custom interactive components expose name, role, and value through appropriate ARIA attributes. shadcn / Radix primitives (`DropdownMenu`, `Accordion`, `Popover`, `Toast`, `Form`) provide correct role and state information. The accordion triggers expose `aria-expanded` and `aria-controls`. The mobile menu trigger exposes `aria-expanded`. The language switcher items use `role="menuitem"`. Form inputs expose `aria-invalid` and `aria-describedby` when errors are present. The `axe-core/aria-prohibited-attr` and `axe-core/button-name` rules pass on all DWEL-authored DOM (the historical hits inside the YouTube iframe are excluded under the third-party scope carve-out). |
| **4.1.3 Status Messages** | Supports | Toast notifications use the shadcn Toast component with `role="status"` and `aria-live="polite"`. Form submission state is announced via the same channel. The impact-calculator's derived totals are updated inside an `aria-live="polite"` region so that screen reader users hear the recomputed numbers when an input changes. |

---

## Conformance Summary

| Level | Overall Conformance |
|---|---|
| **WCAG 2.2 Level A** | Supports |
| **WCAG 2.2 Level AA** | Supports |

The site demonstrates full conformance against the in-scope WCAG 2.2
A and AA criteria as evaluated. The most recent automated baseline
(`reports/a11y-axe-final.{json,md}`, 2026-04-22) reports **zero
violations across 57 page-runs** (16 routes × 3 viewports plus
interaction states). The accompanying manual checklist
(`docs/accessibility-manual-checks.md`) records every manual
criterion as Pass.

The third-party scope carve-outs documented under "Assumptions and
Limitations" — the YouTube embedded player and the optional Cookiebot
consent banner — are excluded from the DWEL-authored conformance
scope and are the responsibility of those upstream vendors.

---

## Appendix A: Routes, States, and Breakpoints Tested

### Routes Tested

| Route | Description | Audience |
|---|---|---|
| `/` | Home — hero, hidden-tax overview, value pillars | All |
| `/employers` | Employer ROI, business case, sources | HR / Total Rewards / Benefits buyers |
| `/caregivers` | Caregiver value proposition | Working caregivers |
| `/care-recipients` | Care-recipient value proposition | Care recipients and family |
| `/how-it-works` | Product overview video, chapters, screenshots | All |
| `/demo` | Demo request form | Buyers |
| `/impact-calculator` | Interactive ROI calculator with hours and dollar charts | Buyers |
| `/about` | Mission, team, vision | All |
| `/trust` | Trust, privacy, security pillars | All |
| `/faq` | Frequently asked questions accordion | All |
| `/sources` | Research sources cited across the site | All |
| `/contact` | Contact form and email link | All |
| `/accessibility` | Accessibility statement (links to this VPAT) | All |
| `/privacy` | Privacy policy | All |
| `/terms` | Terms of use | All |
| 404 | Not Found page | All |

### States Tested

- Default page state (post-navigation, scrolled to top)
- Mobile menu open (every route at desktop, exercised explicitly)
- FAQ accordion expanded (`/faq`)
- Contact form submission state — pending and post-submit toast
  (`/contact`)
- Impact-calculator inputs changed — both hours and dollars chart
  re-rendered (`/impact-calculator`)
- Light mode and dark mode (theme toggle in the header)
- English and Spanish (language toggle in the header)
- `prefers-reduced-motion: reduce` honored by `ScrollReveal` and
  `AnimatedCounter`

### Breakpoints Tested

| Breakpoint | Width × Height | Device Category |
|---|---|---|
| Mobile | 375 × 812 | iPhone SE / small phone |
| Tablet | 1024 × 768 | iPad landscape / small laptop |
| Desktop | 1280 × 800 | Standard laptop / desktop |

---

## Appendix B: Test Methodology

### Automated Testing

- **Tool:** `axe-core` 4.11 via `@axe-core/playwright` 2.x
- **Driver:** `scripts/a11y-audit.ts` (Playwright-controlled
  Chromium 125)
- **Scope:** Every route in Appendix A, at all three breakpoints,
  plus the interaction states listed under "States Tested"
- **Tags applied:** `wcag2a`, `wcag2aa`, `wcag21a`, `wcag21aa`,
  `wcag22aa`
- **Exit code:** Non-zero if any rule fires; zero otherwise
- **Artifacts:** `reports/a11y-axe-final.{json,md}` (snapshot of the
  most recent passing run) and `reports/a11y-axe.{json,md}` (most
  recent run, used as a working file)

### Manual Keyboard Testing

- **Scope:** Every interactive element on every route
- **Protocol:** Tab through all focusable elements; verify Enter /
  Space activation; verify Escape dismissal of dropdowns / popovers /
  the mobile menu; verify arrow-key navigation in the language menu;
  verify skip-link operability; verify no keyboard traps
- **Tools:** Chromium DevTools accessibility panel for focus order
  inspection

### Screen Reader Spot Check

- **Primary:** VoiceOver on macOS Sonoma + Safari 17.6
- **Routes:** `/`, `/employers`, `/how-it-works`, `/impact-calculator`,
  `/faq`, `/contact`
- **Protocol:** Navigate by landmarks, headings, form controls;
  verify live region announcements for form submission and calculator
  result updates; verify form label associations; verify error
  announcement timing

### Visual Inspection

- **Contrast:** Manual computation from CSS custom-property HSL
  values in `client/src/index.css`, cross-checked against the
  automated `axe-core/color-contrast` results
- **Focus visibility:** Visual inspection of focus ring color, width,
  and offset in both light and dark modes
- **Reflow:** Browser zoom to 200 % and emulator widths down to
  320 px on all 16 routes

### Code Review

- **Scope:** Every route component in `client/src/pages/site-*.tsx`,
  the `SiteLayout` and its sub-components in
  `client/src/components/site/*` and `client/src/components/header/*`,
  and every shared primitive consumed from
  `client/src/components/ui/*`
- **Focus areas:** `aria-hidden` on decorative elements, `aria-label`
  on icon-only buttons, `role` attributes, `aria-live` regions,
  `aria-expanded` / `aria-controls` pairs, `<title>` updates via
  `react-helmet-async`, `htmlFor` / `id` label associations, keyboard
  event handlers, focus refs

---

## Appendix C: Detailed Findings

The most recent automated run produced **zero violations**. No
DWEL-authored issues at Blocker, Critical, Serious, Moderate, or Minor
severity were identified. The following items are recorded for
transparency and are out of scope for the DWEL-authored conformance
determinations.

### Item DWL-SITE-A11Y-001 — YouTube embedded player (third party)

| Field | Detail |
|---|---|
| **Item ID** | DWL-SITE-A11Y-001 |
| **Severity** | Out of DWEL scope (third-party carve-out) |
| **WCAG Criterion** | 4.1.2 Name, Role, Value (and others if YouTube changes its widget) |
| **Route/Component** | `/how-it-works` — YouTube `<iframe>` embed of the product overview video |
| **Detection Source** | Automated (axe-core) prior to scope carve-out |
| **Description** | axe-core, when allowed to traverse the cross-origin frame, reports `aria-prohibited-attr` and `button-name` violations against the YouTube player's internal `#movie_player` `<div>` and `ytmVideoInfoChannelAvatar` `<button>`. These elements are emitted by YouTube and cannot be modified by DWEL. |
| **Mitigation** | The `<iframe>` element itself is given a meaningful `title`, is keyboard-operable, and is placed inside a labelled section. The audit harness explicitly excludes `iframe` content from analysis. |
| **Status** | Accepted as third-party scope carve-out. |

### Item DWL-SITE-A11Y-002 — Cookiebot consent banner (third party)

| Field | Detail |
|---|---|
| **Item ID** | DWL-SITE-A11Y-002 |
| **Severity** | Out of DWEL scope (third-party carve-out) |
| **WCAG Criterion** | Various, depending on Cookiebot configuration |
| **Route/Component** | All routes when Cookiebot is enabled at build time |
| **Detection Source** | Manual |
| **Description** | When configured, Cookiebot injects its own DOM for the consent banner. DWEL configures Cookiebot for AA conformance via the vendor dashboard but does not author the banner markup. |
| **Mitigation** | The site does not auto-trigger any non-essential script before consent is captured. |
| **Status** | Accepted as third-party scope carve-out. |

---

## Appendix D: Open Questions and Items Not Fully Verified

| # | Item | Reason | Status |
|---|---|---|---|
| 1 | YouTube player internal accessibility | Third-party widget; internal markup is controlled by YouTube. | Out of DWEL scope |
| 2 | Cookiebot consent banner internals | Third-party widget; internal markup is controlled by Cookiebot. | Out of DWEL scope |
| 3 | Email-client rendering of replies to `info@dwel.digital` | Email client accessibility is the responsibility of the recipient's mail client. | Out of WCAG scope |
| 4 | Browsers other than Chromium 125 / Safari 17.6 / Firefox 127 | Older browsers were not part of the test matrix. The site uses standards-based markup and progressively enhanced ES2020+ JavaScript. | Not Verified |
| 5 | Screen readers other than VoiceOver | NVDA and JAWS spot checks were not performed for this report; planned for the next audit cycle. | Partially Verified |

---

## Final Compliance Statement

**What is verified:** The DWEL public marketing website v1.0.0 has
been evaluated against WCAG 2.2 Level A and Level AA success criteria
across 16 routes (15 marketing pages plus the 404 page), 3 viewports
(375 / 1024 / 1280), 2 color modes (light / dark), 2 languages
(English / Spanish), and the documented interaction states. The most
recent automated `axe-core` run produced zero WCAG 2.2 A or AA
violations. Manual keyboard, screen reader spot-check, contrast,
WCAG 2.2 new-criteria, reduced-motion, and 200 % zoom / 320 px reflow
checks all pass.

**What is partially verified:** Screen reader coverage in this report
is limited to VoiceOver on Safari. NVDA on Windows and JAWS spot
checks are planned for the next audit cycle.

**What remains untested or open:** The internal markup of the YouTube
embedded player on `/how-it-works` and the optional Cookiebot consent
banner are controlled by their respective third-party vendors and
fall outside the DWEL-authored conformance scope.

---

*This report was prepared in accordance with the VPAT 2.4 Rev WCAG
Edition format. It reflects the state of the DWEL public marketing
website v1.0.0 as evaluated on April 22, 2026.*
