An accordion folds a long answer into a list of questions. Each row is a trigger and the
panel under it opens in place, so a reader scans the questions first and reads only the
answer they came for, a support page, a group of settings, the line-item detail under an
order.

What separates it from a tab set is that the sections are not alternatives to each other:
they belong in one column, closing one is as reasonable as opening it, and nothing about
the page moves to a different place. The one mode it adds is whether more than a single
section may stand open.

```tsx demo="data-display/accordion-preview"
```

## Usage

```tsx
import { Accordion } from "@asheeui/web";

<Accordion
  items={[
    {
      id: "invoices",
      title: "Where are last year's invoices?",
      content: "Under Billing, then Invoices. Every year stays available.",
    },
    {
      id: "seats",
      title: "Can I add a seat mid-month?",
      content: "Yes, and the difference is charged at the next renewal.",
    },
  ]}
  defaultValue="invoices"
/>
```

An item is an `id`, a `title` and the `content` its panel reveals, plus a `subtitle` under
the title, an `icon` before it and `disabled`. The `id` is the key the open state is
compared against; an item without one is keyed by its position, which is what a list with
no ids means.

## Expansion and state

`allowMultiple` is the whole of the mode, and it is registered as `false`: opening a section
closes the one that was open. With it stated, several sections stay open at once. The mode
changes nothing about the trigger, the panels or the announcement, only how many keys the
state may hold.

`defaultValue` is where an uncontrolled accordion starts, and `value` with `onValueChange`
is the controlled pair. A controlled accordion renders exactly the keys it is given and
reports every change; an uncontrolled one keeps its own and reports them the same way, so a
page can start uncontrolled and take over later without changing anything else.
`onValueChange` always receives the complete set of open keys as an array, whichever shape
stated it, so a page has one thing to store.

```tsx demo="data-display/accordion-multiple"
```

The single-open rule is applied when the state changes rather than when it renders, which
is why a controlled `value` holding two keys draws two open panels even while
`allowMultiple` is false: the component renders the state it is handed, and the next press
is what folds it back to one.

## Treatments

Four variants decide the surface. `bordered` groups the items into one outlined container
with dividers; `separated` gives each item its own outlined block with space between them;
`ghost` draws transparent rows over hairlines; `flush` drops the container, the borders and
the dividers for a tight bare stack.

`size` sets the header's padding and the type scale, in the same three steps the fields
use. `radius` rounds the container where the variant has one and rounds the items in
`separated` and `ghost`; `flush` has no surface left to round. `disableAnimation` opens and
closes without the transition, the value a page states for a screenshot test, or for a
recording in which a section moving is noise rather than information. It is a cascade value
like the rest, so `components.accordion.disableAnimation` retunes every accordion at once.

```tsx demo="data-display/accordion-variants"
```

A closed panel is collapsed and inert rather than unmounted, so a form inside it keeps
whatever the reader had typed when they folded it away.

## Props

```props Accordion
```

`size` (`md`) and `allowMultiple` (`false`) are registered, so `components.accordion` states
the density and the mode once for the application.

`variant` and `radius` are deliberately not registered: `variant` resolves from the
application's `defaultVariant` and then from the accordion's own `separated`, and `radius`
from the application's `defaultRadius` and then `md`. The framework's default configuration
states a `faded` variant, which is a button treatment rather than an accordion one, so an
unconfigured application resolves to `separated`, the same treatment the component
documents.

`items`, `defaultValue`, `value`, `onValueChange`, `expandIcon` and the three class-name
overrides are read from the instance: the sections, which of them start open, and the node that
marks them are statements about one screen. `disableAnimation` is the exception, it is a
statement about the design, so it resolves through the cascade.

## Accessibility

- Every header is a real `<button type="button">` carrying `aria-expanded` and
  `aria-controls`, and every panel is a `<section>` labelled by its header. A reader is told
  the name of the region as well as whether it is open, and both identifiers are generated
  from one id, so they cannot drift apart.
- A closed panel is collapsed to zero height and marked `inert`, which takes its content out
  of the tab order and out of the accessibility tree without unmounting it. Opening the
  panel restores both, with whatever the content had kept.
- The default indicator is `aria-hidden`, but `expandIcon` and `item.icon` are drawn inside
  the trigger, so a node that carries text joins the header's accessible name. Hide a
  decorative icon, or give a meaningful one its text alternative.
- <kbd>ArrowDown</kbd> and <kbd>ArrowUp</kbd> move between headers, <kbd>Home</kbd> and
  <kbd>End</kbd> go to the first and last, and the movement wraps. Moving focus never opens a
  panel: the arrows are how a reader gets to a header, and the press is how it opens. A disabled
  header is skipped by the arrows and remains reachable by <kbd>Tab</kbd>.
- A `disabled` item carries `aria-disabled` rather than the native `disabled` attribute, so it
  stays focusable and findable, a reader can reach it and be told why it will not open, while
  the press is refused. (A `Button` follows the same rule.)

## Related

```related tabs, card, tooltip
```
