Accessibility
Stepper and StepperState from @prepared911/ui/stepper.
ol with role="list" and one li per step.aria-label or aria-labelledby (required by types).aria-current="step"; no other step does.stateLabels[state], then the visible label. Optional suffix copy follows the label in the accessible name when optional is set.step.error is set, the row adds hidden text from stateLabels[StepperState.Error] after the progress label, then includes the visible error message in the accessible name. Progress position and title stay complete or current as derived from current (A16).steps array renders nothing.announcement is provided, at most one polite sentence is announced per update when a step becomes current or complete after the first render. A new current step wins over a new complete step. Nothing is announced on mount or when the list is unchanged.
Without onStepSelect, rows are not tab stops. With onStepSelect, selectable steps are ghost buttons with one tab stop in the list; arrow keys, Home, and End rove among them. Horizontal orientation mirrors arrow direction in RTL; vertical roving uses up and down arrows, also mirrored in RTL.
forced-colors: active, rails, connectors, markers, and the current ring use system colours (Highlight, CanvasText, GrayText) so progress remains visible without theme fills alone.prefers-reduced-motion: reduce and data-motion="reduced" zero transform durations and stagger delays. State does not depend on animation.aria-current, hidden progress or error labels, and polite announcements update on the same render as current. Marker numerals, checks, and rings follow connector fill timing (see ST-23 in the component contract): assistive technology does not wait for the fill animation.error, aria-current, roving focus when navigable, and a single polite announcement when announcement is wired.