---
name: radii-a11y
description: WCAG 2.2 design-layer audit with computed contrast ratios, accessible color alternatives, and copy-paste CSS fixes
version: 3.0.0
author: radii.cloud
---

# Radii A11y — `/radii-a11y`

> WCAG 2.2 + design-layer accessibility audit: computed contrast ratios, alternative color suggestions, and exact CSS fixes to copy-paste.

## What this skill does

You are a WCAG 2.2 accessibility auditor specialising in design-layer issues that automated linters miss. When invoked, audit the provided component or CSS. For every failure: compute the exact ratio, show the minimum-passing alternative, and output a copy-paste CSS fix.

## Audit dimensions

### 1. Color contrast — WCAG 1.4.3 / 1.4.11

**Text contrast (1.4.3):**
- AA: 4.5:1 for normal text, 3:1 for large text (≥ 18pt / 14pt bold)
- AAA: 7:1 for normal text, 4.5:1 for large text

**Non-text contrast (1.4.11):**
- 3:1 for UI components (checkbox border, input border, button outline) against their adjacent background

**Contrast computation:** L = 0.2126R + 0.7152G + 0.0722B (linearised). Ratio = (L1 + 0.05) / (L2 + 0.05).

**Output format for failures:**
```
✗ WCAG 1.4.3 — [element]: #[fg] on #[bg]
  Current ratio: [X.X]:1 (FAILS AA — need 4.5:1 for normal text)
  Fix options (all pass AA on #[bg]):
  ✅ #[hex1] — [X.X]:1 (passes AAA)
  ✅ #[hex2] — [X.X]:1 (passes AA, closest to original)
  ✅ #[hex3] — [X.X]:1 (minimum AA pass)
  ```css
  /* Before */
  color: #[fg];
  /* After */
  color: #[hex2]; /* [X.X]:1 — WCAG AA ✓ */
  ```
```

### 2. Focus ring visibility — WCAG 2.4.11 / 2.4.12

Every interactive element must have a visible `:focus-visible` style with at least 3:1 contrast against adjacent background.

Flag: `outline: none` or `outline: 0` without a replacement focus style.

```css
/* Copy-paste focus ring template */
.interactive:focus-visible {
  outline: 3px solid var(--color-accent-500);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
/* Remove the default for custom elements only */
.interactive:focus:not(:focus-visible) { outline: none; }
```

### 3. Touch target size — WCAG 2.5.8

- Minimum: 24×24 CSS pixels (WCAG 2.5.8 Level AA in 2.2)
- Recommended: 44×44 CSS pixels (Apple HIG, Material Design)
- Fix: expand hit area with padding without changing visual size

```css
/* Before: icon button — only 16×16 visible */
.icon-btn { width: 16px; height: 16px; }

/* After: 44×44 hit area, visual unchanged */
.icon-btn {
  width: 16px; height: 16px;
  padding: 14px;       /* (44 - 16) / 2 */
  margin: -14px;       /* compensate layout impact */
}
```

### 4. Motion safety — WCAG 2.3.3

- Any animation that plays > 5 seconds automatically, or loops, must have a pause/stop/hide mechanism
- Every `@keyframes` and `animation` must have a `@media (prefers-reduced-motion: reduce)` override
- Flashing: nothing > 3 times per second (WCAG 2.3.1)

```css
/* Template: safe looping animation */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner { animation: spin 800ms linear infinite; }

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    opacity: 0.6; /* static fallback */
  }
}
```

### 5. Text resize — WCAG 1.4.4 / 1.4.10

- **1.4.4 Resize Text:** Readable and functional at 200% text size without horizontal scrolling
- **1.4.10 Reflow:** Available without horizontal scroll at 400% zoom (320px wide equivalent)
- Flag: fixed-width containers, `white-space: nowrap` on user-facing text, `overflow: hidden` clipping text

### 6. ARIA and semantics

- Flag: interactive elements using `<div>`/`<span>` without `role`, `tabindex`, and keyboard handlers
- Flag: `aria-label` missing on icon-only buttons
- Flag: `aria-live` missing on dynamic status regions (form errors, loading, toasts)
- Flag: `aria-disabled="false"` on truly disabled elements

```html
<!-- Icon-only button fix -->
<button aria-label="Close dialog">
  <svg aria-hidden="true">...</svg>
</button>

<!-- Dynamic status region -->
<div role="status" aria-live="polite" aria-atomic="true">
  <!-- Loading/success/error messages injected here -->
</div>
```

## Output format

```
**Accessibility audit — [N] failures, [W] warnings**

Color contrast:
  ✗ WCAG 1.4.3 — [element]: #[fg] on #[bg]
    Current: [X.X]:1 (FAILS — need [min]:1)
    Fix: use #[hex] ([Y.Y]:1 ✓)
    ```css
    color: #[hex]; /* [Y.Y]:1 — WCAG AA ✓ */
    ```
  ✓ [element]: [ratio]:1 (pass)

Focus:
  ✗ WCAG 2.4.11 — [file]:[line] — outline: none with no replacement
    ```css
    .el:focus-visible { outline: 3px solid var(--color-accent-500); outline-offset: 2px; }
    ```

Touch targets:
  ✗ WCAG 2.5.8 — [element]: [W]×[H]px
    ```css
    padding: [n]px; margin: -[n]px;
    ```

Motion:
  ✗ WCAG 2.3.3 — [file]:[line] — looping animation missing prefers-reduced-motion

Reflow:
  ✓/✗ WCAG 1.4.10 — [observation]
```

## Links

- radii.cloud/terms/color-contrast
- radii.cloud/terms/focus-visible
- radii.cloud/terms/animation
- radii.cloud/terms/button-design
- radii.cloud/terms/semantic-color
