Accessibility

Target:
WCAG 2.2 Level AA
Current status:
Partially conforms
Last assessed:
August 18, 2026
Scope:
The public marketing site’s page templates, and the sign-in and account-recovery pages you can reach without an account — signing in, resetting a password, and the two-step verification screens. The client portal behind the sign-in is assessed separately; it is not covered by this statement.

Below is every criterion I’ve assessed, what I found, and — where I fall short — the measured number and the reason. Some rows say “not yet assessed.” That’s deliberate, and I’ve said why.

What I’m Aiming For

I don’t ship barriers. I sometimes accept reduced legibility.

These are promises about how I work, because those are the only kind I can keep:

  • Hard barriers are defects. If something is unreachable, unusable, or unlabeled, that’s a critical failure, not a trade-off. I fix it.
  • Reduced legibility is measured. Where I intentionally accept lower contrast for design reasons (like a muted timestamp or a tagline over a starfield), I name it, measure it, and list it on this page with its exact numbers.
  • Impact matters most. WCAG treats all Level AA criteria as equal, but I don’t. I categorize failures by whether they completely block someone or merely make something harder — and I never ship the first kind.
  • Testing is manual and real. I test by hand using real assistive technology, and I list precisely which tools I used and how.
  • Status is transparent. I state my exact targets, my current status against them, and the date I last checked.

If you run into a barrier or frustrating interaction, please reach out. I appreciate feedback, and making a fix is never a hassle.

How This Was Tested

Automated checkers catch roughly a third of real accessibility problems, and none of the ones that turn on meaning — whether alt text is accurate, whether a label describes its control, whether a live region says anything useful. So the methods below are hand passes, and each row in the table names the one behind it.

Screen reader
NVDA with Firefox on Windows, driven by hand. Transcripts captured for the criteria that turn on what gets announced.
Contrast
Computed with a WCAG relative-luminance implementation across every theme, surface, and foreground role, including translucent inks composited as they actually render. Ratios on this page are measured, not estimated.
Motion
Every animation checked against the reduced-motion preference, verified at runtime rather than by reading the stylesheet.
Keyboard
Tab traversal by hand: reachability, focus visibility, focus order, and whether the sticky header hides what’s focused.

Where a criterion has not been tested, its row says so. I’d rather show you a gap than a guess.

Conformance Record

55 criteria · 34 met · 0 partially met · 6 not applicable · 15 not yet assessed

“Not applicable” means the site has nothing the criterion governs — no video, no audio, no drag-and-drop. I’ve listed those rows rather than hiding them, because what a standard covers is worth seeing.

“Not yet assessed” means exactly that: These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing.

Perceivable

Perceivable — WCAG 2.2 Level A and AA criteria, with status, evidence, and assessment date
Criterion Level Status Evidence Assessed
1.1.1 Non-text Content A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.2.1 Audio-only and Video-only (Prerecorded) A Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.2.2 Captions (Prerecorded) A Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.2.3 Audio Description or Media Alternative (Prerecorded) A Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.2.4 Captions (Live) AA Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.2.5 Audio Description (Prerecorded) AA Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.3.1 Info and Relationships A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.3.2 Meaningful Sequence A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.3.3 Sensory Characteristics A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.3.4 Orientation AA Met Codebase census, 2026-08-18: zero orientation references in any stylesheet or script — no orientation media query hides or restricts content, no script locks orientation; all layouts are width-responsive only, so both orientations render. 2026-08-18
1.3.5 Identify Input Purpose AA Met Markup audit, 2026-08-18: every input collecting user information carries its correct autocomplete token — signin email/current-password, forgot-password email, reset/set-password new-password (both fields), MFA challenge one-time-code, contact form name/email/tel. 2026-08-18
1.4.1 Use of Color A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.4.2 Audio Control A Not applicable Docroot grep, 2026-08-17: no <video>, <audio>, or <track> elements anywhere in the tree; the two <canvas> elements are decorative and aria-hidden="true". 2026-08-17
1.4.3 Contrast (Minimum) AA Met tools/scripts/contrast.js (the gate of record, css-conventions.md § Verifying contrast), 2026-08-18: all 135 checks pass across the four theme contexts, translucent inks composited as rendered; lowest text pair 4.70:1 (placeholder ink in the warm field well). Scope: the token-resolved text/surface matrix — display text over non-uniform imagery is template-dependent and re-measured at the restyle. 2026-08-18
1.4.4 Resize Text AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.4.5 Images of Text AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.4.10 Reflow AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.4.11 Non-text Contrast AA Met tools/scripts/contrast.js, 2026-08-18: every non-text UI pair — focus indicators, field borders, select glyphs — at or above 3:1 in all four themes; lowest 3.19:1 (the select success check in the navy field well). 2026-08-18
1.4.12 Text Spacing AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
1.4.13 Content on Hover or Focus AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet

Operable

Operable — WCAG 2.2 Level A and AA criteria, with status, evidence, and assessment date
Criterion Level Status Evidence Assessed
2.1.1 Keyboard A Met Hand tab-traversal (playwright-cli driving Edge against the php -S dev server), 2026-08-18: full 48-stop cycle over the homepage shared chrome — skip link, announcement bar, nav bar, nav overlay (opens on Enter, closes on Escape), FAQ disclosures (aria-expanded toggles on Enter), contact form, footer including the reduce-motion switch (aria-checked flips on Enter) — plus /signin, /forgot-password, and /mfa/challenge; the reset/set-password forms share the same auth partials and pattern. Every control reachable and operable; no pointer-only functionality found. 2026-08-18
2.1.2 No Keyboard Trap A Met Hand tab-traversal, 2026-08-18: every sweep cycles back to the document start with no stall (homepage 48 stops; signin; forgot-password; mfa/challenge); the nav overlay contains focus while open by design and releases on Escape or its Close button, returning focus to the trigger. 2026-08-18
2.1.4 Character Key Shortcuts A Met JS event census, 2026-08-18: the only literal key values handled site-wide are Tab, Enter, Space, and Escape — all in component-scoped handlers acting on the focused element; no printable-character shortcut is registered anywhere, so nothing conflicts with speech input or accidental keystrokes. 2026-08-18
2.2.1 Timing Adjustable A Met Assessment, 2026-08-18: the marketing pages impose no time limits; the pre-auth time limits that exist — password-reset token expiry and the rotating MFA code window — are security-essential limits under the criterion's essential exception, where extension would defeat the mechanism. No content or interaction expires on reading time. 2026-08-18
2.2.2 Pause, Stop, Hide A Met Hand verification, 2026-08-17: the reduce-motion switch (01-prd-founding-client-offer.md FR 32; assets/js/shared/motion/motion-toggle.js) is the required mechanism; both canvas starfields gate on it and respond to live preference changes (assets/js/founding-client/starfield.js:207, assets/js/shared/nav/star-field.js:155). Runtime re-confirmation via getAnimations() and a requestAnimationFrame census, 2026-08-18: with motion running (9 live animations, starfield at ~60fps), one keyboard press of the footer switch drops the census to zero animations and zero frames with no reload; under the OS reduced-motion preference the same census is zero from page load. 2026-08-18
2.3.1 Three Flashes or Below Threshold A Met Runtime animation census via getAnimations() (html-conventions.md § Reduced Motion is the method home), 2026-08-18: the site-wide inventory holds one-shot entrance animations (600–1400ms) and two infinite loops, fc-blink at 1000ms and fc-ping at 2400ms per cycle — nothing cycles faster than once per second, and no content strobes; the canvas starfields drift and twinkle without luminance flashing. Nothing approaches three flashes per second. 2026-08-18
2.4.1 Bypass Blocks A Met Hand verification with screenshots, 2026-08-18: the first Tab on the chrome-carrying pages reveals the "Skip to main content" link as a visible pill over the header; Enter moves the reading position to #main. The auth pages carry no repeated blocks to bypass. 2026-08-18
2.4.2 Page Titled A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
2.4.3 Focus Order A Met Hand tab-traversal, 2026-08-18: focus order follows the visual/DOM sequence on the homepage (chrome, hero, sections, contact form, footer), on the auth pages (first field receives load-time focus, then action, then secondary link), and within the nav overlay cycle. 2026-08-18
2.4.4 Link Purpose (In Context) A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
2.4.5 Multiple Ways AA Met Chrome audit, 2026-08-18: every page carries two independent link collections for locating the site's pages — the header nav with its full-menu overlay, and the footer link columns — each a list-of-links mechanism; the services and showcase index pages add browse paths. 2026-08-18
2.4.6 Headings and Labels AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
2.4.7 Focus Visible AA Met Hand tab-traversal with computed-style capture and screenshots, 2026-08-18: every focus stop renders a visible ring — a 3px outline on links, buttons, and controls; the form-field focus ring on inputs and textareas; and the custom radios style their rendered proxy from the visually-hidden input (screenshot-verified on the skip link, a text input, and a radio). 2026-08-18
2.4.11 Focus Not Obscured (Minimum) AA Met Fixed/sticky element census plus tab-traversal, 2026-08-18: the marketing header is position: static and the only fixed elements are the corner nav toggle and its full-screen overlay, so no persistent chrome can cover a focused element; the auth pages have no fixed chrome at all. 2026-08-18
2.5.1 Pointer Gestures A Met JS event census, 2026-08-18: zero touch, pointer-move, or gesture handlers in the codebase — no multipoint or path-based gesture exists; every interaction is a single activation. 2026-08-18
2.5.2 Pointer Cancellation A Met JS event census, 2026-08-18: no mousedown, pointerdown, or touchstart handler exists — every activation runs on the native click (up) event, the criterion's default-compliant path. 2026-08-18
2.5.3 Label in Name A Met aria-label census over the public scope, 2026-08-18: labels exist only on icon-only controls, landmarks, and decorative images — every control with visible text is named by that text. One failure found and fixed in the same pass: the header wordmark carried aria-label "Go to homepage" over visible text "BIG BANG VISIBILITY"; its accessible name now starts with the visible text, verified in the rendered DOM. 2026-08-18
2.5.4 Motion Actuation A Met JS event census, 2026-08-18: no devicemotion or deviceorientation listener exists; no functionality is triggered by device movement. 2026-08-18
2.5.7 Dragging Movements AA Met JS event census, 2026-08-18: no drag handlers, draggable attributes, or move-tracking listeners exist; no interaction requires a dragging movement. 2026-08-18
2.5.8 Target Size (Minimum) AA Met Computed-style sweep of every interactive element, 2026-08-18: standalone controls meet 24x24 — password toggle 36x36, nav links >=26px tall, buttons >=56px tall, radio targets are their 720x43 labels; the undersized text links (footer links 20px, announcement-bar link 19px, wordmark 17px) pass under the spacing exception — 24px circles centred on each do not intersect any neighbour (measured pitch >=29px). 2026-08-18

Understandable

Understandable — WCAG 2.2 Level A and AA criteria, with status, evidence, and assessment date
Criterion Level Status Evidence Assessed
3.1.1 Language of Page A Met Docroot grep, 2026-08-17: 18 <html lang="en"> tags across the docroot; the 8 apparent misses are <html> written as prose inside comment blocks. 2026-08-17
3.1.2 Language of Parts AA Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
3.2.1 On Focus A Met JS event census plus hand traversal, 2026-08-18: no focus listener in the public scope triggers navigation, submission, or any context change; the tab sweeps across the chrome and auth pages moved focus through every control with no side effects. 2026-08-18
3.2.2 On Input A Met JS event census, 2026-08-18: change/input listeners exist only for validation display, character counters, and phone formatting; no programmatic form.submit() or navigation assignment exists in the public scripts, so changing a control never changes context. 2026-08-18
3.2.3 Consistent Navigation AA Met Architecture verification plus rendered spot-checks, 2026-08-18: the header and footer are single shared PHP includes (includes/header.php, includes/footer.php), so navigation renders in identical order on every carrier page by construction; the auth pages omit the chrome entirely rather than reordering it. 2026-08-18
3.2.4 Consistent Identification AA Met Architecture verification, 2026-08-18: repeated components are single-source — the shared chrome partials, the shared contact-form include, and the shared form and button patterns — so the same function carries the same label and presentation on every page (the footer help cluster verified identical under the 3.2.6 pass). 2026-08-18
3.2.6 Consistent Help A Met Hand verification, 2026-08-17: the footer help cluster is identical on every page that carries the shared footer; pages without the footer (the auth pages) do not repeat the mechanism, which 3.2.6 permits — the criterion constrains ordering only where a help mechanism is repeated. 2026-08-17
3.3.1 Error Identification A Met Live verification, 2026-08-18: contact-form submission errors render a text summary plus per-field text errors naming each field's problem, with aria-invalid set on the failing fields; the auth pages render server-side errors as text in a role="alert" region ("That email and password didn't match. Please try again."). 2026-08-18
3.3.2 Labels or Instructions A Met Markup audit plus hand traversal, 2026-08-18: every field on the public forms carries a visible label element (signin, forgot/reset/set-password, MFA challenge, contact form including its radio group), with required marking and a format placeholder where input is constrained. 2026-08-18
3.3.3 Error Suggestion AA Met Live verification, 2026-08-18: validation messages state the correction, not just the failure — "Please include an '@' in the email address", "Please lengthen this text to 2 characters or more", "Please select a preferred contact method". 2026-08-18
3.3.4 Error Prevention (Legal, Financial, Data) AA Met Assessment, 2026-08-18: the public scope has no legal commitments or financial transactions; the one submission that modifies stored user data — setting or resetting a password — requires the value entered twice, the criterion's checked-and-confirmed mechanism. 2026-08-18
3.3.7 Redundant Entry A Met Flow audit, 2026-08-18: no pre-auth process asks for the same information twice — sign-in and the MFA challenge each collect their value once, and the reset flow carries identity in the token; the new-password confirmation field is a confirmation entry the criterion excepts. 2026-08-18
3.3.8 Accessible Authentication (Minimum) AA Met Hand verification, 2026-08-17: no paste-blocking anywhere in the tree; autocomplete="current-password" at signin.php:299, one-time-code at mfa/challenge.php:216 and mfa/setup.php:230, new-password in set-password and reset-password. Pre-auth flow in scope per 01-prd-accessibility-statement.md A1. 2026-08-17

Robust

Robust — WCAG 2.2 Level A and AA criteria, with status, evidence, and assessment date
Criterion Level Status Evidence Assessed
4.1.2 Name, Role, Value A Not yet assessed These criteria depend on page markup that’s currently being rebuilt. I’ll assess the new templates rather than the ones I’m replacing. Not yet
4.1.3 Status Messages AA Met NVDA 2026.1.1 + Firefox 153.0.4 transcript, 2026-08-18 (knowledge/audit/nvda/2026-08-billing-live-region.md, appendix): submitting the contact form with invalid fields announced the role="alert" summary — "Please fix the errors below before submitting." — without the alert receiving focus, and the first invalid field's inline error was announced with the field. Status messages reach assistive technology without a focus change. 2026-08-18

Where I Fall Short, and Why

Each of these is a deliberate choice, not an oversight. The measured number is there so you can judge it yourself.

Nothing is currently recorded as an accepted shortfall.

If this list ever runs past five or six entries, that’s not a set of design decisions any more — it’s a palette problem, and the fix belongs in the design tokens rather than in a seventh entry here.

A Real Defect, Found and Fixed

This is the part I’d want to see on someone else’s page, so here it is. In August 2026 I ran a screen-reader pass over a billing panel that had already shipped. It passed every mechanical check. It was still wrong.

A live region announced a figure without the label that gave it meaning — the screen reader spoke a bare dollar amount with nothing to say what it measured. The cause was a default: aria-atomic is false unless you set it, so only the part that changed got announced, and the label beside it stayed silent.

The bug was invisible on first render. When the panel appeared, the whole region was new, so everything announced together and it sounded correct. Only the second update exposed it. Any test that checked once and stopped would have passed.

The transcripts below are NVDA’s own speech log, re-captured against a local fixture chosen for the cleanest possible probe: the project change swaps to a project with nothing invoiced yet, so exactly one value changes — and in the broken build it arrives as a bare empty-state word instead of a labeled fact. Same mechanism, sharpest contrast.

Before

combo box  expanded
Test Website Build  list
Test Website Build  3 of 3
Test Lead Project (unpriced)  not selected  2 of 3
Nothing yet
Project *  combo box  Test Lead Project (unpriced)  collapsed  required

After

combo box  expanded
Test Website Build  list
Test Website Build  3 of 3
Test Lead Project (unpriced)  2 of 3
Project price: Not set  Payment structure: Not set  Invoiced so far: Nothing yet
Project *  combo box  Test Lead Project (unpriced)  collapsed  required

Fixed, shipped, and written into my HTML conventions as a rule so the next live region gets it right by default.

Most people claiming accessibility competence have never opened a screen reader. This is what happens when you do.

What’s Already In Place

  • Every animation respects your reduced-motion setting, and there’s a switch in the footer of every page if you’d rather turn motion off without changing your system preference.
  • A skip link, and a visible focus indicator on everything you can reach with a keyboard.
  • Semantic headings and landmarks, so you can navigate by structure instead of scrolling.
  • Text alternatives on images that carry meaning, and none on the ones that are decoration.
  • No third-party fonts, scripts, or trackers. Nothing on this site depends on another company’s server being fast or reachable.

Found a Problem?

Tell me. I’d rather hear about it than have it sit here unrecorded.

Email me directly: hello@bigbangvisibility.com. I’ve put email first on purpose. If the thing that’s broken is a form, a form is a poor way to report it.

There’s also a contact form, if you’d prefer it.

I’ll reply within five business days, and I’ll tell you what I found — including if I’ve decided not to change it, and why.