# Build the "Model and effort switch" pattern: `ModelEffortPicker`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
A user-facing choice between speed, cost and depth, replacing a hidden routing decision.

Use it when: Products with a real quality-latency spread and users who feel the difference.

## What to build
A compact picker that lets a person choose between faster, cheaper and deeper answers, with each option described by its tradeoff rather than only a model name. It can re-ask the last question at the new setting and keep both answers. It renders as a button in a composer that opens a menu.

### Props
- `options`: Array<{ id: string; label: string; description: string; speed: string; cost: string; modelName?: string }>, e.g. { label: "Deep", description: "Works through the data step by step", speed: "about 40 s", cost: "6 credits" }.
- `selectedId`: string and `onSelect(id: string)`, the controlled choice.
- `effort?`: { levels: Array<{ id: string; label: string; description: string }>; selectedId: string; onSelect(id: string) }, an optional effort scale for options that support it.
- `balance?`: string, e.g. "412 credits left".
- `canRerun?`: boolean and `onRerun(id: string)`: re-ask the last question with the chosen option. The component never sends anything itself.
- `status`: "closed" | "open" | "rerunning".
- `onSwitchLogged?(from: string, to: string)`: called on every change so the parent can record it.

### States it must render
- Closed: the trigger shows the current option label and its speed, e.g. "Fast, about 2 s".
- Open: each option shows label, one-line tradeoff, speed and cost; the current one is checked; an underlying model name, if given, is secondary text.
- Effort expanded: for options with effort, a segmented scale with a line explaining the selected level.
- Rerunning: the trigger shows progress; the earlier answer stays in the thread.
- Unavailable option: dimmed with the reason, e.g. "Not enough credits".

### Interactions
- Choosing an option calls `onSelect` and `onSwitchLogged`, then closes the menu.
- If `canRerun`, the menu offers "Re-ask with Deep" which calls `onRerun`; it states that both answers will stay.
- Arrow keys move through options; Enter selects; Escape closes without change.

### Edge cases
- An option with no `description`: still render its speed and cost; never show a bare model name as the only text.
- Cost exceeding the balance: option disabled with the shortfall stated.
- The model lineup changes: options come from props, so labels stay tradeoff-based even when the model behind them changes.
- An "Auto" option: describe what it chooses between and show which one it used after each answer, if the parent supplies it.

## Must avoid
Cryptic model names as the only signal, forcing users to memorise a changing lineup.

## Engineering constraint
Describe the tradeoff in the label; log switch events as your clearest signal of unmet need.

## Accessibility
- The menu is a `listbox` or `menu` with `menuitemradio`s; each option's accessible name includes its speed and cost.
- Announce the new choice after selection, and announce re-run start and finish.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
