The seed-packet capture backend has been live since #94 (POST /seed-lots/scan and /seed-lots/from-packet, with /capabilities reporting `vision`), but there was no UI, so the feature Steve asked for — "take a picture of a packet and it auto-creates" — was unreachable. This adds the mobile-first UI. - Entry point in the Plants catalog ("Scan a packet"), shown only where `capabilities.vision` is on — so it's never a dead button on an instance with no vision model. Adds `vision` to the capabilities schema (both flags now default false, so a partial response hides a feature rather than failing parse). - ScanPacketModal: two phases in one dialog. Capture uses a file input with `accept="image/*" capture="environment"` so a phone opens the camera directly (also picks an existing photo; HEIC is handled server-side). Review shows the extracted fields read-only for context, then an editable confirm — pick a ranked existing candidate (with its match reason) or create a new variety prefilled from the packet. Nothing commits blind, which is the whole point of the backend's never-auto-create design. - New data layer (lib/seedPacket.ts): zod schemas mirroring the backend (SeedPacket / PacketProposal / PacketResult), the scan + confirm mutations, and the pure prefill helpers (newPlantDefaults / lotDefaults) — unit-tested, since the prefill mapping (unknown category, missing spacing, seed-count→unit) is where the bugs hide. - api.ts learns to send FormData as multipart (no JSON content-type) for the scan upload, via a new api.postForm. Frontend only; no backend or route change. Last open child of epic #96. Live camera→vision→proposal verification needs a vision-configured instance (the flow is model-gated and unreachable locally, same as the assistant); the confirm half and all prefill logic are covered by tests. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ