# Build the "Plan preview" pattern: `PlanPreview`

## 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
The intended sequence of steps, shown before execution and editable by the user.

Use it when: Multi-step agent work where a wrong plan is expensive to discover halfway through.

## What to build
An editable list of the steps an agent intends to take, shown before anything runs, with each step concrete enough to judge (the record, amount or file it touches) and labelled by what kind of effect it has. A person can remove optional steps or choose between variants, and the edited plan is exactly what runs. It renders in a chat reply or task panel ahead of a Run button.

### Props
- `plan`: { id: string; steps: Array<{ id: string; title: string; detail: string; effectLabel: string; required: boolean; included: boolean; variants?: Array<{ id: string; label: string }>; selectedVariantId?: string }> }, the same plan object the executor consumes.
- `onEditStep(stepId: string, change: { included?: boolean; variantId?: string })`: the parent updates the plan and passes it back; the component holds no private copy.
- `onReorder?(stepIds: string[])`: when reordering is allowed.
- `estimateLabel?`: string, e.g. "about 1 min".
- `status`: "proposed" | "running" | "done" | "error", controlled by the parent.
- `stepResults?`: Record<string, { state: "running" | "done" | "skipped" | "failed"; detail: string }>.
- `onRun(planId: string)` and `onRevise?(feedback: string)`: callbacks. The component never executes steps itself.

### States it must render
- Proposed: a badge "Plan ready, nothing has run", numbered steps each with a concrete title and detail ("Change seats from 12 to 14: +$48 a month from today") and an effect label ("read only", "billing", "customer", "internal").
- Edited: removed steps are struck through, chosen variants are shown, and the footer reads "4 steps, edited by you: charge card now, no customer email".
- Running: steps tick to done in the same list, with results matching what was shown; edits are locked.
- Done: each step shows its result, edited steps are marked "your edit", and removed steps show "Skipped, removed by you".
- Error: the failing step is marked and later steps show "Not run".

### Interactions
- Optional steps have a checkbox calling `onEditStep(id, { included })`; required steps have none and say why they are required.
- Variant choices (for example "Add to next invoice" or "Charge card now") are a segmented control calling `onEditStep(id, { variantId })`.
- Run calls `onRun(plan.id)` with the displayed plan; Revise opens a short text field and calls `onRevise`.
- Keyboard reordering, when enabled, uses buttons "Move up" and "Move down" on each step.

### Edge cases
- Steps too abstract to judge ("Update records") should be refused upstream; if a step lacks detail, show "No detail provided" so the gap is visible.
- Removing a step that later steps depend on: the parent marks dependents, and the component shows them as disabled with the reason.
- The plan changes while the person is editing (agent revises it): highlight changed steps and keep the person's edits where step ids still match.
- All optional steps removed: Run still works with the required steps and says how many remain.

## Must avoid
A plan generated for show that the executor ignores, or one too abstract to judge.

## Engineering constraint
Same plan object drives display and execution; edits must round-trip back into the run.

## Accessibility
- Steps are an ordered list; each checkbox and variant control is labelled with the step title.
- Announce the edited summary after each change and the result after Run.

## 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.
