# WCAG 2.2 AAA Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Achieve WCAG 2.2 AAA conformance across all frontend components while preserving the existing dark-theme visual identity. **Architecture:** All changes are CSS + Svelte template only — no Rust backend changes. Theme tokens in `app.css` propagate through Tailwind's `@theme` system. Components use Svelte 5 runes (`$state`, `$derived`, `$effect`, `$props`). Accessibility patterns follow WAI-ARIA 1.2 (tablist, radiogroup, alertdialog, progressbar). **Tech Stack:** Svelte 5, Tailwind CSS v4 (`@theme` tokens in CSS, no config file), TypeScript, Web Animations API (`motion` library) **Note:** This project has no frontend test suite. Verification is done via `npm run build` (Vite build) and manual inspection. Each task ends with a build check and a commit. --- ### Task 1: Theme Tokens & Global Styles (`app.css`) **Files:** - Modify: `break-timer/src/app.css` (entire file) This is the foundation — all subsequent tasks depend on these token changes. **Step 1: Update theme tokens** In `app.css`, inside the `@theme { }` block (lines 3–20): - Change `--color-text-sec: #8a8a8a` → `--color-text-sec: #a8a8a8` (7.28:1 on black) - Change `--color-text-dim: #3a3a3a` → `--color-text-dim: #5c5c5c` (3.5:1 decorative) - Change `--color-border: #222222` → `--color-border: #3a3a3a` (2.63:1 non-text) - Change `--color-danger: #f85149` → `--color-danger: #ff6b6b` (7.41:1) - Add new token: `--color-input-border: #444444;` - Add new token: `--color-surface-lt: #1e1e1e;` **Step 2: Update body styles** In the `html, body` block (lines 22–35): - Change `user-select: none` to only apply on drag regions: - REMOVE `user-select: none;` and `-webkit-user-select: none;` from body - ADD a new rule for drag regions only: ```css [data-tauri-drag-region], [data-tauri-drag-region] * { user-select: none; -webkit-user-select: none; } ``` - Add `line-height: 1.625;` (leading-relaxed) to body for AAA 1.4.8 **Step 3: Enhance focus indicators** Replace the `:focus-visible` block (lines 73–76) with: ```css :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.3); } ``` The `box-shadow` provides a white fallback when the accent color has low contrast against dark backgrounds. **Step 4: Add skip link styles** After the `.sr-only` block, add: ```css .skip-link { position: absolute; top: -100%; left: 50%; transform: translateX(-50%); z-index: 10000; padding: 8px 16px; background: var(--color-accent); color: #000; font-size: 13px; font-weight: 600; border-radius: 0 0 8px 8px; text-decoration: none; transition: top 0.15s ease; } .skip-link:focus { top: 0; } ``` **Step 5: Verify build** Run: `cd break-timer && npm run build` Expected: Build succeeds with no errors. **Step 6: Commit** ```bash git add break-timer/src/app.css git commit -m "a11y: update theme tokens and global styles for WCAG AAA - Bump --color-text-sec to #a8a8a8 (7.28:1 contrast) - Bump --color-text-dim to #5c5c5c (3.5:1 decorative) - Bump --color-border to #3a3a3a (2.63:1 non-text) - Bump --color-danger to #ff6b6b (7.41:1) - Add --color-input-border and --color-surface-lt tokens - Add white shadow fallback on :focus-visible - Add leading-relaxed default line-height - Scope user-select:none to drag regions only - Add skip-link focus styles" ``` --- ### Task 2: App Shell (`App.svelte`) **Files:** - Modify: `break-timer/src/App.svelte` **Step 1: Add skip link** Inside the `
` element (line 87), add skip link as first child and an id target: ```svelte
... ``` Then on the zoom container `
` (line 92), add `id="main-content"`: ```svelte
{ const viewNames: Record = { dashboard: "Dashboard", breakScreen: "Break", settings: "Settings", stats: "Statistics", }; document.title = `Core Cooldown — ${viewNames[effectiveView] ?? "Dashboard"}`; }); ``` **Step 3: Verify build** Run: `cd break-timer && npm run build` **Step 4: Commit** ```bash git add break-timer/src/App.svelte git commit -m "a11y: add skip link and dynamic document title for WCAG AAA" ``` --- ### Task 3: Titlebar (`Titlebar.svelte`) **Files:** - Modify: `break-timer/src/lib/components/Titlebar.svelte` **Step 1: Wrap in header landmark** Change the outer `
` (line 8) to `
`. **Step 2: Enlarge traffic lights to meet 44px target size** Change each traffic light button from `h-[15px] w-[15px]` to `h-[20px] w-[20px]` visual size with `min-h-[44px] min-w-[44px]` hit area via padding. The trick: keep the visual circle at 20px but wrap in a 44px invisible tap area. Replace each button's class. For example the Maximize button (line 27): ```svelte ``` Apply the same pattern to Minimize and Close buttons. The gap between buttons changes from `gap-[8px]` to `gap-0` since the 44px buttons provide their own spacing. **Step 3: Verify build** Run: `cd break-timer && npm run build` **Step 4: Commit** ```bash git add break-timer/src/lib/components/Titlebar.svelte git commit -m "a11y: add header landmark and enlarge traffic lights to 44px hit areas" ``` --- ### Task 4: ToggleSwitch (`ToggleSwitch.svelte`) **Files:** - Modify: `break-timer/src/lib/components/ToggleSwitch.svelte` **Step 1: Enlarge to 52x28 and fix knob contrast** Change button dimensions from `h-[24px] w-[48px]` to `h-[28px] w-[52px]` with `min-h-[44px]` padding for hit area. Change the knob span from `h-[19px] w-[19px]` to `h-[22px] w-[22px]`. Change translate-x for ON state from `translate-x-[26px]` to `translate-x-[27px]`. Change mt from `mt-[2.5px]` to `mt-[3px]`. Change OFF knob color from `bg-[#444]` to `bg-[#666]` (better contrast). The button should have `min-h-[44px]` via a wrapper approach or padding. **Step 2: Verify build** Run: `cd break-timer && npm run build` **Step 3: Commit** ```bash git add break-timer/src/lib/components/ToggleSwitch.svelte git commit -m "a11y: enlarge toggle switch and improve OFF knob contrast" ``` --- ### Task 5: Stepper (`Stepper.svelte`) **Files:** - Modify: `break-timer/src/lib/components/Stepper.svelte` **Step 1: Enlarge buttons and fix contrast** Change both +/- button dimensions from `h-7 w-7` (28px) to `h-9 w-9` (36px) with `min-h-[44px] min-w-[44px]` padding. Change `bg-[#141414]` to `bg-[#1a1a1a] border border-[#3a3a3a]` for better non-text contrast. Change `text-[#8a8a8a]` to `text-text-sec` (uses updated theme token). **Step 2: Add keyboard hold-to-repeat** Add `onkeydown` handlers to both buttons that trigger the same `startHold`/`stopHold` logic for Enter, Space, ArrowUp, ArrowDown keys: ```typescript function handleKeydown(fn: () => void, e: KeyboardEvent) { if (["Enter", " ", "ArrowUp", "ArrowDown"].includes(e.key)) { e.preventDefault(); startHold(e.key === "ArrowDown" || e.key === "ArrowUp" ? fn : fn); } } function handleKeyup(e: KeyboardEvent) { if (["Enter", " ", "ArrowUp", "ArrowDown"].includes(e.key)) { stopHold(); } } ``` Add `onkeydown` and `onkeyup` to both buttons. The decrease button uses ArrowDown for decrement, the increase button uses ArrowUp for increment. **Step 3: Verify build** Run: `cd break-timer && npm run build` **Step 4: Commit** ```bash git add break-timer/src/lib/components/Stepper.svelte git commit -m "a11y: enlarge stepper buttons and add keyboard hold-to-repeat" ``` --- ### Task 6: Animation Actions (`animate.ts`) **Files:** - Modify: `break-timer/src/lib/utils/animate.ts` **Step 1: Add keyboard support to `pressable`** In the `pressable` function (line 117), after the mousedown/mouseup/mouseleave listeners (lines 143–145), add keydown/keyup for Enter and Space: ```typescript function onKeyDown(e: KeyboardEvent) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onDown(); } } function onKeyUp(e: KeyboardEvent) { if (e.key === "Enter" || e.key === " ") { onUp(); } } node.addEventListener("keydown", onKeyDown); node.addEventListener("keyup", onKeyUp); ``` Update `destroy()` to remove these listeners too. **Step 2: Add focus support to `glowHover`** In the `glowHover` function (line 165), after mouseenter/mouseleave listeners (lines 201–202), add focusin/focusout: ```typescript node.addEventListener("focusin", onEnter); node.addEventListener("focusout", onLeave); ``` Update `destroy()` to remove these listeners too. **Step 3: Verify build** Run: `cd break-timer && npm run build` **Step 4: Commit** ```bash git add break-timer/src/lib/utils/animate.ts git commit -m "a11y: add keyboard feedback to pressable and focus glow to glowHover" ``` --- ### Task 7: Dashboard (`Dashboard.svelte`) **Files:** - Modify: `break-timer/src/lib/components/Dashboard.svelte` **Step 1: Replace hardcoded `#8a8a8a` with theme token** Replace all `text-[#8a8a8a]` with `text-text-sec` throughout the file. There are ~10 instances on lines 180, 208, 216, 234, 241, 256, 301, 329, 361. Replace `border-[#222]` with `border-border` on the three bottom buttons (lines 302, 328, 360). **Step 2: Wrap bottom buttons in nav landmark** Around the three bottom action buttons (lines 296–382), wrap in: ```svelte ``` The three `
` blocks move inside the `