# Build the "Multimodal drop zone" pattern: `AttachmentDropZone`

## 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
One input that accepts text, files, images, audio and screen captures as equal citizens.

Use it when: Whenever the user's evidence lives outside the app and describing it is lossy.

## What to build
One input area that accepts text plus files, images, audio and screenshots, and shows each attachment with its own upload and parse status. A person can see what will be sent, remove anything, and cancel slow uploads before asking. It renders as part of a chat composer or request form.

### Props
- `attachments`: Array<{ id: string; name: string; kind: "image" | "pdf" | "audio" | "table" | "text" | "other"; size: number; status: "uploading" | "parsing" | "ready" | "failed" | "unsupported"; progress?: number; summary?: string; error?: string; thumbnail?: string }>, controlled by the parent.
- `accept`: Array<{ kind: string; mimeTypes: string[]; maxBytes: number }>, what can be added and size limits, shown as a hint.
- `onAdd(files: File[])`: called on drop, paste or picker selection. The component never uploads or parses itself.
- `onRemove(id: string)`, `onCancel(id: string)` and `onRetry(id: string)`: per-attachment callbacks.
- `text`: string and `onTextChange(text: string)`, the message typed alongside.
- `onSend()`: enabled only when nothing is still uploading or parsing, or when the parent allows sending without pending items.
- `maxAttachments?`: number.

### States it must render
- Empty: the input with a hint listing accepted kinds ("Images, PDF, audio, CSV") and an add button.
- Drag over: the whole area is outlined with "Drop to attach".
- Uploading: a chip per file with progress and Cancel.
- Parsing: the chip says what is being read, e.g. "Reading 3 pages".
- Ready: each chip shows a thumbnail or icon and what was understood, e.g. "2 invoices found" or "0:42 audio, transcribed".
- Failed or unsupported: the chip stays in place with the reason and Retry or Remove; it is never silently dropped.

### Interactions
- Drop, paste or the add button calls `onAdd` with the files; rejected types still appear as unsupported chips with the reason.
- Each chip has Remove (and Cancel while uploading) calling the matching callback.
- Send is disabled while any attachment is uploading or parsing, with a note naming how many are pending.

### Edge cases
- A file that uploads but cannot be parsed: status failed with the parse error, so the person knows the model will not see it.
- A file over `maxBytes`: unsupported immediately, with the limit stated, before any upload starts.
- Exceeding `maxAttachments`: extra files are listed as not added, with the limit.
- Duplicate drop of the same file: show it once and say it was already attached.

## Must avoid
Accepting an upload then silently ignoring it, or failing at parse time with no per-file state.

## Engineering constraint
Show per-attachment parse status; large files need progressive upload with a cancel affordance.

## Accessibility
- The drop zone is not the only way in: a real file input button is always present and labelled.
- Each status change per attachment is announced politely with the file name, e.g. "invoice.pdf ready, 2 invoices found".

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