# سند ۳۱ — ممیزی دسترس‌پذیری واقعی (موج ۲ · سند ۲۹ §۲.۴)

**نسخه:** 1.11.0 · **تاریخ:** ۲۰۲۶-۰۹-۲۶ · **ابزار:** `scripts/a11y-audit.mjs` (`npm run test:a11y`)

## ۱. روش

- سرور موقت + Playwright در **۱۰ حالت**: خانه(زبان) · خانه(ساخت کودک) · نقشه · مودال ایستگاه · بازی حرف‌پاپ · گالری واژه (سافاری) · اتاق جوایز · مودال تنظیمات · گیت ریاضی والد · صفحه‌ی والدین.
- در هر حالت: **axe-core** (WCAG 2.0/2.1 AA + best-practice) + سنجش **هدف لمسی** همه‌ی عناصر تعاملی DOM (خطای سخت <24px = WCAG 2.5.8 · هشدار <44px = الزام بازی‌های کودک سند ۲۹).
- **کیبورد** صفحه‌ی والدین: همه‌ی دکمه‌ها قابل Tab + نشانگر فوکوس پیدا.
- دو نکته‌ی فنی سنجش پایدار: (۱) انتظار برای پایان انیمیشن‌های CSS با سقف ۲ث (انیمیشن‌های بی‌نهایت مثل pulse-ring معلق نمی‌کنند) + `emulateMedia(reducedMotion)` برای انیمیشن‌های GSAP؛ (۲) انتظار برای `opacity=1` ریشه‌ی صفحه/مودال — سنجش وسط محو شدن، رنگ‌های blend شده می‌دهد (منبع کاذب‌های کنتراست در اجرای اول).
- **چرا axe به‌جای Lighthouse a11y روی ۵ مسیر:** اپ SPA است و حالت‌ها (نقشه/بازی/گالری/والدین) URL جدا ندارند؛ axe در همان حالت‌های تعاملی اجرا می‌شود و ابرمجموعه‌ی قواعد LH a11y را پوشش می‌دهد. Lighthouse a11y روی `/` = **۱۰۰** (میانه‌ی ۳ اجرا).

## ۲. یافته‌ها و اصلاحات (همه اعمال شد)

### کنتراست (WCAG 1.4.3)
| عنصر | قبل | بعد |
|---|---|---|
| متن دکمه‌های `.btn-kid` (coral/teal/green/yellow) | سفید روی رنگ روشن = **1.9–2.6** | جوهری `--c-ink` = **5.0–8.9** |
| `.btn-kid.purple` / `.action-card.purple` | سفید/جوهری روی #9B5DE5 = 4.1/2.1 | سفید روی `--c-purple-d` = **6.2** |
| زیرنویس `.action-text i` | opacity 0.92 → 4.45 | بدون opacity = **5.0** |
| `.station.current/.done` و `.mastered-chip` و `.bubble` و `.fall-letter` | سفید روی سبز/مرجانی = 1.9–2.6 | جوهری = **5.0+** |
| هایلایت حرف `.wc-text .hl` | #FF7B54 روی سفید = 2.6 | `--c-primary-ink` #C24A1D = **4.9** |

### نام و نقش (WCAG 4.1.2 / 1.3.1)
- دکمه‌های انتخاب رنگ کودک: `aria-label` با نام رنگ در ۵ زبان (۳۰ کلید i18n جدید: `home.color.coral/teal/yellow/purple/green/blue`).
- `#set-lang` (select) و `#gate-ans` (input): `aria-label` + کلید `parents.gate.ansLabel` در ۵ زبان.
- فرم ورود والدین: `<label for="p-email/p-pass">` (قبلاً label‌های ناپیوسته).
- همه‌ی مودال‌ها (`showModal`): پارامتر `ariaLabel` → `aria-label` روی `.modal-card` (تنظیمات/ایستگاه/…).
- نوار پیشرفت قصه‌ها: `aria-label` + `aria-valuenow/max`.
- چیپ بازی قفل: `aria-disabled="true"` (axe از عناصر غیرفعال کنتراست نمی‌خواهد؛ نکته‌ی قفل با کلیک حفظ شد).

### ساختار و ناوبری
- `<div id="app">` → **`<main id="app">`** (landmark اصلی) · `<main class="home-hero">` تودرتو → `<section>`.
- h1 در همه‌ی صفحه‌های اصلی (نقشه/اتاق/والدین×۳ نما/بازی) + h2 به‌جای h3 برای ترتیب سرفصل درست · `.sr-only` به CSS اضافه شد.
- کیبورد والدین: **۷/۷ دکمه قابل Tab · ۰ بدون نشانگر فوکوس**.

### هدف لمسی
- `.btn-kid.small` 40→**44px** (شنیدن نام حرف، حساب والدین، ریست، گیت، خروج سافاری) · `.link-btn` (تغییر زبان) → min-height **44px**.
- چک‌باکس‌ها: تنظیمات 26→30px · «مرا به خاطر بسپار» 18→**24px**.

## ۳. هشدارهای باقی‌مانده (قابل‌قبول — مستند)

| مورد | اندازه | دلیل قبول |
|---|---|---|
| `#set-sound` / `#set-motion` | 30×30 | کل ردیفِ تنظیمات (44px+) هدف کلیک است (label دور input) · والد-محور · ≥ آستانه‌ی WCAG 2.5.8 (24px) |
| `#p-remember` | 24×24 | داخل `label.remember-row` بزرگ · والد-محور |

## ۴. نتیجه‌ی گیت‌ها (اجرای پایانی)

- `npm run test:a11y` → **قبول · ۰ نقض سخت · ۳ هشدار** (بالا) — خروج nonzero در CI اگر نقض سخت باشد (`A11Y_STRICT=1` هشدارها را هم رد کند).
- واحد/یکپارچه **۲۱۶/۲۱۶** · e2e **۲۵/۲۵** · Lighthouse: کارایی **۸۳** (≥۸۳) · a11y/BP/SEO **۱۰۰**.
