---
convoy: scanner-desktop-layout
brief_number: 2
depends_on: []
recommended_model: composer-2.5-fast
model_tier: fast
files:
  - components/scanner/ScannerTips.js
  - test/components/ScannerTips.test.js
cross_brief_commitments:
  - brief: 6
    description: |
      Brief 6 mounts `<ScannerTips />` in the desktop page header row (md+ only)
      beside "Card Scanner" title. This brief ships the self-contained modal +
      trigger button; no page wiring here.
---

# Brief 2: Scanner Tips modal

## Goal (1 sentence)

Ship a desktop Scanner Tips control that opens a glass `<Modal>` with five convoy-authored tips.

## Files in scope (do not edit anything else)

- `components/scanner/ScannerTips.js`
- `test/components/ScannerTips.test.js`

## Conventions to follow

- Use `Modal` + `Button` from `components/ui` — no custom scrim (`ui-and-theming.mdc`).
- Glass panel recipe: `--glass-surface-low` via `GlassSurface` inside modal body if needed.
- Copy locked (Design direction + IA):

| # | Tip |
| --- | --- |
| 1 | **Good lighting** — avoid glare on foil cards. |
| 2 | **Fill the frame** with one card; keep corners visible. |
| 3 | **Hold still** until Auto-detect locks the match. |
| 4 | **Use Batch Scan** for a pile of photos from your gallery. |
| 5 | **Switch camera** if the image is dark or mirrored. |

- Modal title: **Scanner Tips**. Trigger: ghost `Button` with lightbulb SVG + label **Scanner Tips** (visible text for 2.5.3 Label in Name).
- Dismiss: close control, Esc, scrim click — standard `<Modal>` behavior.
- No hex in `.js`; tokens only.
- Test pattern: `test/components/ScannerCheckoutSheet.test.js` (vitest + jsdom + RTL).

## Implementation shape

```js
export default function ScannerTips({ className = '' }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="ghost" onClick={() => setOpen(true)} /* lightbulb + Scanner Tips */ />
      <Modal open={open} onClose={() => setOpen(false)} title="Scanner Tips" size="md">
        <ol className="space-y-4 text-sm" style={{ color: 'var(--text-secondary)' }}>
          {/* five <li> with <strong> lead + em dash body */}
        </ol>
      </Modal>
    </>
  );
}
```

Component is self-contained — no props required v1.

## Acceptance criteria

- [ ] Trigger shows lightbulb icon + **Scanner Tips** visible label
- [ ] Modal lists exactly five tips with locked copy
- [ ] Uses `<Modal>` primitive (no `fixed inset-0 bg-black` shell)
- [ ] Opening/closing traps focus per existing Modal behavior
- [ ] tests: trigger opens modal, all five tips visible, close dismisses
- [ ] no scope expansion (do not edit files outside `files:` above)

## Rationale (≤3 sentences)

Tips are a standalone surface (C3) with no queue or camera dependencies. Shipping the modal in isolation lets Brief 6 wire it into the header without blocking other parallel work. Five tips exceed popover length — Modal is Design-locked.
