# Build the "Inline citations" pattern: `CitedAnswer`

## 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
Numbered or hovering markers that bind each claim to a retrievable source.

Use it when: Any factual, retrieval-backed, or high-stakes answer.

## What to build
Renders an AI answer whose claims carry numbered citation markers. Selecting a marker highlights exactly the words it supports and opens the cited passage (not just the document) in a source list, so checking a claim takes one click.

### Props
- `segments`: Array<{ text: string; citationIds?: string[] }>, the answer split into spans; a span with `citationIds` is a supported claim.
- `sources`: Array<{ id: string; title: string; meta?: string; url?: string; passage: string; highlight: [start: number, end: number] }>, where `highlight` is the character range inside `passage` that supports the claim.
- `selectedId?`: string and `onSelect(id: string | null)`, for controlled selection so a parent can sync other UI.
- `layout`: "side" | "below", where the source list renders; use "below" under 640 px.
- `showUnsupported?`: boolean, marks claims that have no citation.
- `onOpenSource?(id: string)`: opens the source at the passage anchor (a deep link), never at the top of the file.

### States it must render
- Default: answer text with small numbered markers after each supported claim; the source list shows titles and meta only.
- Claim selected: the supported span is highlighted, its marker is pressed, and the matching source expands to show the passage with the supporting words marked.
- Unsupported claim: with `showUnsupported`, a span without citations gets a subtle "no source" marker.
- Passage unavailable: a source without a passage says "Passage not available" and still links to the document.

### Interactions
- Clicking a marker or a source header selects it; clicking the selected one again clears the selection.
- Hovering a marker previews its highlight without changing the selection.
- Arrow keys move between markers when one has focus; Escape clears the selection.
- A claim with several citations shows adjacent markers (1, 2), each selectable on its own.

### Edge cases
- Two claims citing the same source: selecting either highlights only its own span, and the same passage.
- A claim that wraps across lines or list items: the highlight follows the text without breaking layout.
- A long passage: show about 300 characters around the highlight, with "Show full passage".
- A streaming answer: markers appear as segments arrive, without shifting earlier text.

## Must avoid
Citations that point at a whole document instead of the passage, so verifying costs more than rewriting.

## Engineering constraint
Return spans with offsets from retrieval, and deep-link to the anchor, not the file.

## Accessibility
- Markers are buttons with labels like "Source 2: Q3 retention review" and `aria-pressed`.
- The link between claim and passage is shown with more than colour (an underline or outline as well).

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