Completes offline Phase 1 (frontend). Generalises the POS-orders-only queue into
a reusable write engine and fixes the two correctness bugs in the old path.
- offline-db: generic `outbox` store (DB v3, order_queue/kv preserved) with
enqueue/list/update/remove + a persisted client→server id map.
- outbox.ts: drains in causal order — remaps local_* ids to server ids (blocking
an op until its creator syncs), sends each op with its idempotency key, and
classifies failures (offline → stop; 5xx / in-progress → retry; 4xx → poison
after 5 attempts). remap/blocked logic validated against representative cases.
- client: apiPost/Put/Patch/Delete take an optional idempotencyKey →
`Idempotency-Key` header; ApiClientError now carries HTTP status.
- submit-order: generates ONE idempotency key per submit, used for both the
online attempt and the queued replay → server de-dups (no more double-create);
offline create carries createsClientId so a later add-items remaps onto the
real order instead of spawning a second order.
- use-offline-sync: drains the outbox, one-time migrates legacy order_queue
items, invalidates queries after a successful sync.
tsc + production build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>