Make this component genuinely accessible: **[component name and file path]**

Adding ARIA attributes until the linter goes quiet is not the job. Most of the fix is usually semantics and focus, and most bad ARIA is worse than none.

## 1. Semantics before attributes

Check what it is built from. A `div` with an `onclick` becomes a `button`. A list of things becomes a `ul`. A disclosure becomes a `button` carrying `aria-expanded="true|false"` for its state, and `aria-controls="<id>"` to point at the region it opens — two different attributes doing two different jobs.

Every ARIA attribute you keep, justify to me. If a native element does the same job, use the native element and delete the attribute — the browser already handles the states, the keyboard and the announcements, and your version will not.

## 2. Keyboard

Work through it with the mouse unplugged:

- Everything interactive is reachable by <kbd>Tab</kbd>, in the order it appears on screen — reachable, which for a composite widget means the widget takes one tab stop and the arrow keys move within it, not a stop per item.
- Each control answers the keys its native equivalent answers: a button on <kbd>Enter</kbd> and <kbd>Space</kbd>, a link on <kbd>Enter</kbd> alone. Do not bind <kbd>Space</kbd> on a link — it scrolls the page, and readers expect that.
- <kbd>Escape</kbd> closes anything that overlays, and focus returns to whatever opened it.
- Composite widgets — tabs, menus, listboxes — use arrow keys with one tab stop, not a tab stop per item.
- No keyboard trap, except a modal dialog, where the trap is the point.
- Visible focus on every stop. `:focus-visible`, never `outline: none` with nothing to replace it.

## 3. Screen reader

- Every control has an accessible name that says what it does. A `title` can act as a fallback name, but do not rely on it: it draws a tooltip that needs a pointer, so it reaches neither a keyboard nor a touch screen. Put the name in the markup — a visible label, or visually hidden text when the visible label is an icon — and keep `title` for at most a hover convenience.
- State changes that matter are announced, once. For a result count or a save confirmation, put `role="status"` on a small dedicated region that holds just that sentence. Wrapping a whole list in `aria-live` is the blunter instrument: what gets read depends on `aria-atomic` and on how the list mutates, so it is easy to end up re-announcing far more than changed.
- Icons that carry no information get `aria-hidden="true"`.

## 4. The rest

- **Contrast**: 4.5:1 for body text and 3:1 for large text, where large means at least 24px regular or about 18.7px bold. A visual cue that is the only thing identifying a control needs 3:1; purely decorative edges do not. Check the hover and focus states too, which is usually where it fails. Disabled controls are exempt under WCAG — check them anyway and tell me what you find, but report it as a judgement call, not a failure.
- **Reduced motion**: honour `prefers-reduced-motion: reduce`, for scripted animation as well as CSS transitions. For a small transition, shortening it is fine; for anything that moves a long way or scales, remove the movement or swap it for a fade, because a fast large movement still triggers what the setting exists to prevent. Always leave the element in its final state.
- **Unique ids per instance.** Two of these on one page must not collide. In Svelte 5 use `$props.id()` rather than a module-level counter.
- **Cleanup.** Every listener and timer removed when the component is destroyed.
- **SSR safety.** No `window` or `document` at module scope or during render.

## 5. Verify

Tab through it and tell me the focus order you observed. Run an automated check (axe or similar) and report what it says — but do not stop at a clean automated result, because it cannot tell you whether the focus order makes sense or whether the accessible name is accurate.

Finish with: what you changed, what ARIA you deleted and why, the contrast numbers for each state, and anything still wrong that needs a design decision from me.
