- lib/toast.tsx (renamed from .ts for JSX): new showToast.undo(message,
onUndo, ms=5000) helper. Inline 'Undo' button dismisses the toast and
fires onUndo. Note: react-hot-toast 2.6 lacks onClose/onDismiss, so
expiry is silent — same effective behavior as confirm() declined.
- Dashboard.handleDelete: captures the full MealPlanItem before the
DELETE so Undo can re-fire meals.generateItem(planId, dayOfWeek,
mealType) and refill the slot (recipe may differ — see plan R4).
- Pantry.handleRemove: fully reversible — Undo re-fires pantry.add with
the original ingredient_id, quantity, and unit. New removeId state
scopes the spinner to the clicked row.
- Both confirm() call sites removed.
- App.tsx Navigation: whitespace-nowrap + px-2 sm:px-3 so all 4 links fit
on one line down to 360 px. aria-current='page' on the active link.
<nav aria-label='Primary'>, <main id='main-content'>.
- components/ui/Badge: optional icon and aria-label props. Dashboard
approval-status Badge passes aria-label='Approval status: approved'
(or the current value) so screen readers don't rely on color alone.
- ErrorBoundary already mounted at App.tsx:42 — verified, no code change.
- Review/sprint3-verification.md (new) + Review/ui-nielsen-audit.md and
fix-ui-audit.md updated with Sprint 3 status and deploy steps.
Build: npm run build (tsc + vite) green. tsc 0 errors.