# yujin.a11y.* verbs (F107) -- screen reader + voice-first

The `yujin.a11y.*` namespace gives the brain three
panel-dispatch verbs to drive the accessibility surface of any
adopter app. Fetch this doctrine via `yujin.doctrine.discover`
when the user mentions screen reader / accessibility / voice
announce / focus / aria.

## Catalog

| Verb | Use when |
|---|---|
| `yujin.a11y.announce` | A status / error / async completion needs to reach screen-reader users + the voice loop |
| `yujin.a11y.focus`    | Keyboard focus needs to land on a specific element (after open modal, after async load) |
| `yujin.a11y.label`    | An element needs a screen-reader description, optional shortcut + role hints |

All three are `policy: unrestricted`, `side_effects: ['dom']`,
`handler_side: panel`.

## Args -- quick reference

```
yujin.a11y.announce   {text, politeness?:'polite'|'assertive', speak?, locale?}
yujin.a11y.focus      {slug, scroll?, announce?}
yujin.a11y.label      {slug, description, shortcut?, role?}
```

`slug` is the NAC-3 element slug (the value of the `data-nac-slug`
attribute the adopter declared at source). It MUST match
`[a-z0-9][a-z0-9._-]*` -- no spaces, no `/`, max 120 chars.

## When to announce

- After a destructive action completed -> `announce({text: '...
  eliminado', politeness:'assertive'})`.
- After a long-running task finished -> `announce({text:'Deploy
  listo', speak:true})` to also TTS it.
- For ambient progress -> default `politeness:'polite'` so the
  screen reader does not interrupt.

## When to focus

- After opening a modal: focus the modal's primary button
  (`scroll:true, announce:true` by default).
- After loading new content into a region: focus the heading
  so screen-reader users know where they are.
- NEVER force focus mid-typing -- the user's keyboard input wins.

## When to label

- The adopter forgot to ship a `data-nac-label` -- the assistant
  can patch the live a11y tree without forcing a source edit.
- A shortcut or role hint helps disambiguate (two buttons with
  the same visible text).

## Don't

- Don't fire `announce` for visual-only chatter ("rendered the
  pizarron tab"). The screen reader gets EVERY announce -- noisy
  is worse than silent.
- Don't use `focus` to scroll the page for sighted users; use the
  panel scroll API instead.
- Don't invent verbs like `yujin.a11y.read-page` -- only the three
  above exist.

## Voice-first integration

`announce` with `speak: true` forwards the text to the existing
voice loop (Yujin TTS gateway or BYOK provider). Locale defaults
to the user's voice config; pass `locale: 'es-AR'` to override
for an individual announcement.

## Mobile

The React-Native adapter consumes the same payloads:
- `aria-live polite/assertive` -> `AccessibilityInfo.announceForAccessibility`
- `focus` -> native `setAccessibilityFocus` ref
- `label` -> `accessibilityLabel` + `accessibilityHint`
