# Spinner and progress

A spinner for short, unknown waits inside a control; a progress bar for jobs with a known size (cloth sync, bulk import) and an indeterminate bar for the page loader.

- **Group:** Status and feedback · **family:** `status-feedback` · **shadcn:** Progress
- **Build:** shadcn `Progress` (Radix Progress); spinner is a small local component.
- **In apps/admin today:** `ui/progress.tsx` exists. Add the indeterminate and ok/bad variants; spinner is new markup.
- **Client component:** no. 

## Content rules

- Count, not percent, when the unit is real: "120 of 214 cloths".

## Do

- Spinner inside the button that started the action.

## Don't

- A full-page spinner over content that could show skeletons.

## Motion

- Spinner: `kit-spin` 0.8s linear infinite; 2.4s under reduced motion (still turning so it reads as busy).
- Indeterminate bar: 38% segment slides on 1.5s `--ease-standard`.

## Accessibility

- **ARIA:** Progress: `role="progressbar"` with `aria-valuenow/min/max` and an `aria-label`; indeterminate omits `aria-valuenow`.
- **ARIA:** Spinner alone is `aria-hidden`; the text beside it carries the meaning.
- **Keyboard:** Not focusable.
- **Focus:** None.

## Tokens

`--motion-spin` `--ease-linear` `--motion-spin-reduced` `--r-pill` `--muted` `--primary` `--motion-sheet-in` `--motion-indeterminate` `--ease-standard` `--success` `--destructive` `--s-6` `--s-2` `--text-body` `--muted-foreground` `--info` `--s-3` `--w-semibold` `--text-card` `--font-voice` `--font-stretch-title` `--text-small` `--border` `--w-medium` `--secondary-border` `--w-regular` `--text-micro` `--font-code`

## Files

`spinner-progress.html` live specimen · `spinner-progress.css` kit rules · `spinner-progress.d.ts` props · full page: `docs/components/spinner-progress/` (phone: `m/`).
