Add web/ with React 19, TypeScript, Vite, React Router 7 and TanStack
Query 5. Scripts: dev, build (tsc --noEmit + vite build), preview,
typecheck and test (Vitest run, jsdom, Testing Library). The dev server
proxies /api, /auth and /media to http://localhost:8080. App renders a
placeholder "MealQuest" shell covered by a smoke test. package-lock.json
is committed; node_modules and dist stay ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Everything decided while designing MealQuest, written so you can paste it into another LLM. Items marked **[Decided]** were confirmed by the client. Items marked **[Design default]** were proposed by the designer and not challenged; treat them as the current plan, but they can be changed.
---
## 1. Product summary
MealQuest is a **mobile-first Progressive Web App (PWA)** for weekly dinner planning for one household. The household enters the dinners they make regularly. An AI assistant suggests new dinners, which the household accepts or declines with a swipe interface like a dating app. The app builds a weekly dinner plan, pushes it to **Google Calendar**, and generates a **shopping list** for the planned dinners. Shopping lists are kept as a **blog-style history** you can browse by week, month or year. The app can also suggest dinners from a list of ingredients on hand, and offers **quick dinner** ideas. It sends **push notifications** and **Google Chat** messages through a webhook. An **admin page** configures the AI model (LLM).
## 2. Users & access
- [Decided] **One shared household account.** No per-person profiles.
- [Decided] **Anyone in the household can open everything**, including the Admin settings.
- [Design default] The household is shown as a single identity ("Our kitchen · Shared household"). Settings changes apply to everyone.
## 3. Platforms
- [Decided] **Mobile first**, delivered as a **PWA** (installable, with a service worker and app notifications).
- [Decided] **Tablet and desktop layouts** too. On larger screens the focus is **reading ingredients and recipes, managing the calendar, and updating settings**.
- [Design default] Breakpoints: mobile < 768px (bottom nav), tablet 768–1199px (96px icon rail), desktop ≥ 1200px (208px sidebar). Tablet is designed in landscape, for kitchen-counter use.
- [Design default] Works offline for the current plan, shopping list and recipes.
## 4. Navigation
- [Decided] Bottom nav on mobile, five items in this order: **Home · Plan · Discover · Quick · Settings**.
- [Decided] The **Admin page lives inside Settings**. It is not a nav tab.
- [Design default] The Shopping list and Shopping history are reached from Plan and Home (not tabs). The same five items appear in the tablet rail and the desktop sidebar.
## 5. Onboarding — regular dinners
- [Decided] The user enters the dinners the household routinely has ("regulars"). The AI uses these to come up with new suggestions.
- [Design default] Three steps; step 2 is "What's on your usual rotation?" with free-text entry, removable chips and suggested common dinners. Step 3 asks for notification permission.
- [Design default] Regulars can be edited later in Settings → Regular dinners.
## 6. AI dinner suggestions (Discover / swipe)
- [Decided] The AI suggests **new dinners to try** based on the household's regulars.
- [Decided] **Swipe right / "Try it" = accept; swipe left / "Pass" = decline.** Buttons and swipe gestures both work.
- [Decided] **Accepted suggestions go into a "to try" pool** (named the **Quest log**) and get scheduled later, not right away.
- [Decided] Each suggestion card shows: **photo**, **why it was suggested** (referencing the household's regulars), and **difficulty**.
- [Design default] Declined suggestions are recorded so they aren't suggested again. A "Quest log · N" counter is shown on the screen. Suggestions arrive in batches; a push or Chat message announces new ones.
### Required animations [Decided]
- **Try it:** the card **wiggles, then flies off the right side** of the screen.
- **Pass:** the card **folds over and falls off to the left** of the screen.
- Exact timings and easing are in the developer handoff README. Summary: "Try it!" stamp pops in → ±4° wiggle (420ms) → small pull-back → fly right with a 28° tilt (480ms). Pass: folds on its left edge (rotateY to −80°, shading darkens) → drops and tumbles off left (720ms). The cards behind move forward afterward (300ms). Dragging past 110px triggers the same exits; otherwise the card springs back.
- [Decided] The **AI builds the week**, mixing **regulars and Quest-log meals**; the **user then adjusts** it (swaps days).
- [Decided] **No fixed rule** for how many new vs. regular dinners go in a week.
- [Decided] The plan covers **dinners** (one per day).
- [Decided] Chosen mobile layout: **draft board** (mockup 1f). It shows an AI note ("I mixed 5 of your regulars with 2 from your Quest log…"), a 2-column grid of day tiles with new dinners highlighted, tap a day to swap, and a "Looks good — push to Calendar" button.
- [Design default] Tablet and desktop: a 7-column week view; drag a dinner from the Quest log or Regulars panel onto a day to swap it in. Includes week navigation, "Rebuild week" and "Push to Calendar".
- [Design default] Crock-pot dinners show a "Start by [time]" hint.
## 8. Google Calendar
- [Decided] The weekly schedule is **placed in a Google Calendar**.
- [Decided] **The app is the source of truth and pushes to Google Calendar (one-way).** Edits made in Google Calendar do not come back into the app.
- [Design default] Connect once with Google sign-in (OAuth) in Settings → Google Calendar; one calendar event per dinner; sync status is shown ("Synced to Google Calendar 2 min ago").
## 9. Shopping list
- [Decided] Generated from the **ingredients needed for the dinners on the schedule**.
- [Decided] **Grouped by dinner** (not by store aisle).
- [Decided] Pantry / on-hand handling: **the user unchecks items they already have** on the list. There is **no separate pantry inventory**.
- [Design default] Checked = needs buying; unchecked = "have it" (struck through, left out of the count). Shows a count like "19 / 23" and can be sent to Google Chat.
## 10. Shopping history (blog format)
- [Decided] Shopping lists are shown in a **blog format**: **each weekly shopping list is a new post**.
- [Decided] Browse by **week / month / year** for historical reference.
- [Design default] Each post shows a week label ("Week 41 · Oct 5 – 11"), an AI-written title, the number of dinners and items, how many items were already on hand, and dinner chips. Past posts are read-only.
## 11. Cook from what I have (ingredients → ideas)
- [Decided] Generate **dinner ideas from a list of available ingredients**.
- [Design default] Ingredient chip input, an "Any time / Quick only" filter, and a "Find ideas" button. Results show how many of your ingredients each idea uses and what's missing, with "Cook tonight" and "Add to Quest log" actions.
## 12. Quick dinners
- [Decided] A way to generate **quick dinner ideas**. "Quick" means **cooked in a crock pot OR 30 minutes or less from prep to table**.
- [Decided] Available in **two places**: a **dedicated entry point** (Quick nav tab plus a Home shortcut) **and** as a **"Quick" filter** on suggestions / ingredient search.
- [Decided] Shown as **two tabs: Crock pot | 30 min or less**.
- [Design default] Each result shows time and difficulty, has a "+" to add to the Quest log, and a "Show me more" option.
## 13. Recipe / dinner detail
- [Decided] A recipe / dinner detail screen.
- [Design default] Photo, tags (Regular/Side quest, difficulty, time), "Why it was picked", ingredients with quantities, steps, "Add to this week", and a favorite (heart) button.
- [Design default] Tablet **kitchen reading mode**: large text, ingredient checkboxes ("3 of 9 set out"), current step highlighted, Previous/Next step buttons, a **Keep screen on** toggle and a text-size control.
## 14. Notifications (push + Google Chat)
- [Decided] The PWA sends **app (push) notifications**.
- [Decided] The app sends **messages to Google Chat using webhooks**.
- [Decided] Events that trigger messages: **New weekly plan ready · Shopping list ready · Day-of dinner reminder · New suggestions to swipe.**
- [Design default] Push and Chat can be switched on or off **separately for each event**. The day-of reminder time can be changed (default 4:30 pm). Settings include the webhook URL, connection status and a "Send test" button.
- [Design default] On iOS, push only works once the app is installed to the home screen, so show an install hint.
- [Decided] An admin page for configuring the LLM the app uses, including:
- **Provider and model picker**
- **API key management**
- **Temperature / creativity**
- **System prompt editor**
- [Design default] The API key is stored on the server and only the last 4 characters are shown, with a "Replace" button and "Verified" date. Temperature slider from 0 to 1, labeled "Familiar ↔ Adventurous". Reset and Save buttons.
- Not requested: usage/cost tracking, test playground, global dietary restrictions.
## 16. Settings home
- [Design default] Sections: Household (Regular dinners, Google Calendar connection), Alerts (Notifications & Google Chat), Admin (AI assistant). Desktop shows Notifications, Webhook and AI assistant together on one page.
- [Decided] The **purple pill in the bottom nav slides to the selected menu item**.
- [Design default] 420ms with a slight overshoot; the other icons glide to their new spots; the label fades in after 120ms.
## 19. Accessibility [Design default]
- Swiping is never the only way to act: there are always buttons, and keyboard ←/→ arrows work.
- Text contrast of at least 4.5:1; tap targets of at least 44px; toggles and checkboxes are announced correctly to screen readers.
## 20. Suggested tech stack [Design default]
React + TypeScript + Vite, vite-plugin-pwa, React Router, TanStack Query, Web Animations API or Framer Motion, lucide-react. The backend handles LLM calls, Google Calendar sign-in and sync, Google Chat webhook posts, and push notifications.
## 21. Core data (summary)
- **Dinner**: name, photo, minutes, method (stovetop/oven/crock pot/other), difficulty, ingredients (name and quantity), steps, source (regular or suggestion).
- **Suggestion**: dinner, reason ("why this?"), status (pending/accepted/declined).
- **Week plan**: week start date, one dinner per day (flagged if new), status (draft/synced), last calendar sync time.
- **Shopping list**: week, items grouped by dinner (each marked needed or have-it), when it was sent to Chat, AI-written post title.
- **Settings**: Push/Chat switch for each event, reminder time, webhook URL, calendar, AI settings (provider, model, temperature, system prompt, last 4 of API key, verified date).
- A dinner counts as quick if it is a crock-pot meal or takes 30 minutes or less.
## 22. Not yet designed / open items
- Empty, loading and error states (suggested patterns are in the handoff README).
- The swap picker for a mobile plan day (suggested: a bottom sheet listing the Quest log and Regulars).
- Settings → Household and Regular dinners management screens.
- Onboarding steps 1 and 3.
- A tablet version of Settings, and portrait tablet layouts.
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<div><b>Working from your answers:</b> one shared household account · Organic design system · playful, quest-flavored copy · bottom nav = Home, Plan, Discover, Settings.</div>
<div>Accepted suggestions go to a <b>Quest log</b> (to-try pool). The AI builds each week from routine dinners + Quest log picks; you swap days, then it pushes to Google Calendar (app is source of truth). Shopping lists are grouped by dinner; uncheck what you already have. Each week's list becomes a post in the archive.</div>
<div><b>Assumptions to confirm:</b> Shopping list and Quick dinners are reached from Home/Plan (not tabs) · Admin lives inside Settings · Photos are placeholders.</div>
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why this?</b> You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.</div>
<divstyle="padding:4px 20px 0;display:flex;align-items:center;justify-content:space-between"><divstyle="font-family:var(--font-heading);font-size:22px">Discover</div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">3 of 10 today</div></div>
<divstyle="font-family:var(--font-heading);font-size:26px;line-height:1.05">Crock pot chicken tikka masala</div>
<divstyle="font-size:13px;line-height:1.45;color:var(--color-neutral-800)">Because Butter chicken night is a household favorite — this one cooks itself while you work.</div>
</div>
</div>
</div>
<divstyle="display:flex;justify-content:space-between;padding:16px 34px 0;font-size:12px;font-weight:700;color:var(--color-neutral-700)"><span>← Pass</span><spanstyle="color:var(--color-accent-2-700)">Add to Quest log →</span></div>
<divstyle="margin:22px 20px 0;padding:22px;border-radius:34px;background:var(--color-surface);box-shadow:var(--shadow-md);display:flex;flex-direction:column;gap:16px">
<divstyle="padding:12px 14px;border-radius:4px 18px 18px 18px;background:var(--color-neutral-100);font-size:13px;line-height:1.45">Your Shrimp scampi gets 5 stars every time. Orzo makes it a one-pot night.</div>
</div>
</div>
<divstyle="display:flex;gap:10px;margin:20px 20px 0">
<divstyle="flex:1;height:52px;border-radius:999px;border:1.5px solid var(--color-divider);display:flex;align-items:center;justify-content:center;font-family:var(--font-heading);font-size:15px">Not for us</div>
<divstyle="margin:14px 20px 0;padding:10px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:center"><svgviewBox="0 0 24 24"width="16"height="16"style="flex:none;fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="M20 6 9 17l-5-5"></path></svg><span>5 regulars + 2 side quests · synced to Google Calendar</span></div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:6px">
<divstyle="padding:18px 20px 0;font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-neutral-700)">Coming up</div>
<divstyle="padding:8px 20px 0;display:flex;flex-direction:column;gap:10px">
<divstyle="padding:10px 14px;border-radius:4px 18px 18px 18px;background:var(--color-surface);font-size:13px;line-height:1.45">I mixed 5 of your regulars with 2 from your Quest log. Tap any day to swap it.</div>
</div>
<divstyle="margin:14px 20px 0;display:grid;grid-template-columns:1fr 1fr;gap:8px">
<divstyle="margin:14px 20px 0;height:50px;border-radius:999px;background:var(--color-accent);display:flex;align-items:center;justify-content:center;gap:8px;font-family:var(--font-heading);font-size:15px;color:var(--color-text)">Looks good — push to Calendar</div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-start">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700)">Friday, Oct 2</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Tonight's quest</div></div>
<divstyle="height:104px;padding:14px;border-radius:26px;background:var(--color-accent-2-300);color:var(--color-accent-2-900);display:flex;flex-direction:column;justify-content:space-between"><svgviewBox="0 0 24 24"width="22"height="22"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="11"cy="11"r="8"></circle><pathd="m21 21-4.3-4.3"></path></svg><spanstyle="font-family:var(--font-heading);font-size:16px;line-height:1.1">Cook from what I have</span></div>
</div>
<divstyle="margin:12px 20px 0;display:flex;flex-direction:column;gap:8px">
<divstyle="display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:20px;background:var(--color-neutral-100)"><svgviewBox="0 0 24 24"width="18"height="18"style="color:var(--color-accent-700);fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><circlecx="12"cy="12"r="10"></circle><pathd="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><spanstyle="flex:1;font-size:13px;font-weight:700">10 new side quests to swipe</span><svgviewBox="0 0 24 24"width="16"height="16"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m9 18 6-6-6-6"></path></svg></div>
<divstyle="padding:10px 20px 0;display:flex;gap:6px"><spanstyle="flex:1;height:6px;border-radius:999px;background:var(--color-accent)"></span><spanstyle="flex:1;height:6px;border-radius:999px;background:var(--color-accent)"></span><spanstyle="flex:1;height:6px;border-radius:999px;background:var(--color-neutral-300)"></span></div>
<divstyle="padding:26px 20px 0"><divstyle="font-size:12px;font-weight:700;color:var(--color-accent-700)">Step 2 of 3</div><divstyle="font-family:var(--font-heading);font-size:30px;line-height:1.08;margin-top:6px">What's on your usual rotation?</div><divstyle="font-size:14px;line-height:1.5;color:var(--color-neutral-800);margin-top:10px">Add the dinners your household makes on repeat. MealQuest builds suggestions from these.</div></div>
<divstyle="padding:6px 20px 0;display:flex;align-items:center;gap:10px"><divstyle="width:36px;height:36px;border-radius:50%;background:var(--color-surface);display:flex;align-items:center;justify-content:center"><svgviewBox="0 0 24 24"width="18"height="18"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m15 18-6-6 6-6"></path></svg></div><divstyle="font-family:var(--font-heading);font-size:22px">Cook from what I have</div></div>
<divstyle="margin:16px 20px 0;padding:12px;border-radius:26px;background:var(--color-surface);display:flex;flex-wrap:wrap;gap:6px">
<divstyle="padding:6px 20px 0;display:flex;align-items:center;gap:10px"><divstyle="width:36px;height:36px;border-radius:50%;background:var(--color-surface);display:flex;align-items:center;justify-content:center"><svgviewBox="0 0 24 24"width="18"height="18"style="fill:none;stroke:currentColor;stroke-width:2.75;stroke-linecap:round;stroke-linejoin:round"><pathd="m15 18-6-6 6-6"></path></svg></div><divstyle="font-family:var(--font-heading);font-size:24px">Quick dinners</div></div>
<divstyle="margin:16px 20px 0;padding:4px;border-radius:999px;background:var(--color-surface);display:grid;grid-template-columns:1fr 1fr;font-size:14px;font-weight:700;text-align:center"><spanstyle="padding:10px 0;color:var(--color-neutral-700)">Crock pot</span><spanstyle="padding:10px 0;border-radius:999px;background:var(--color-bg);box-shadow:var(--shadow-sm)">30 min or less</span></div>
<divstyle="padding:12px 20px 0;font-size:13px;color:var(--color-neutral-800)">Prep to table in 30 minutes or less, picked from your tastes.</div>
<divstyle="padding:14px 20px 0;display:flex;flex-direction:column;gap:10px">
<divstyle="padding:12px 14px;border-radius:18px;background:var(--color-accent-2-100);color:var(--color-accent-2-900);font-size:13px;line-height:1.45"><b>Why it was picked:</b> close cousin of your Beef tacos and Chicken stir-fry.</div>
<divstyle="padding:6px 20px 0;display:flex;justify-content:space-between;align-items:flex-end"><div><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Supply run · Oct 5–11</div><divstyle="font-family:var(--font-heading);font-size:28px;line-height:1.1">Shopping list</div></div><divstyle="font-size:13px;font-weight:700;color:var(--color-neutral-700)">19 / 23</div></div>
<divstyle="margin:10px 20px 0;font-size:12px;line-height:1.45;color:var(--color-neutral-800)">Uncheck anything you already have — it won't be counted.</div>
<divstyle="padding:12px 20px 0;display:flex;flex-direction:column;gap:12px">
<divstyle="display:flex;justify-content:space-between;align-items:baseline"><spanstyle="font-family:var(--font-heading);font-size:16px">Crock pot tikka masala</span><spanstyle="font-size:11px;font-weight:700;color:var(--color-neutral-700)">WED</span></div>
<divstyle="padding:20px 20px 0;font-family:var(--font-heading);font-size:18px">September 2026</div>
<divstyle="padding:10px 20px 0;display:flex;flex-direction:column;gap:10px">
<divstyle="padding:14px 16px;border-radius:22px;background:var(--color-neutral-100);display:flex;flex-direction:column;gap:4px"><divstyle="font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--color-neutral-700)">Week 40 · Sep 28 – Oct 4</div><divstyle="font-family:var(--font-heading);font-size:16px">Pizza, pot roast & the great orzo trial</div><divstyle="font-size:12px;color:var(--color-neutral-700)">7 dinners · 26 items</div></div>
<spanstyle="font-weight:700">New weekly plan ready</span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-accent-2-600);position:relative"><spanstyle="position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-accent-2-600);position:relative"><spanstyle="position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span>
<spanstyle="font-weight:700">Shopping list ready</span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-accent-2-600);position:relative"><spanstyle="position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-accent-2-600);position:relative"><spanstyle="position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span>
<spanstyle="font-weight:700">New suggestions to swipe</span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-accent-2-600);position:relative"><spanstyle="position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span><spanstyle="justify-self:center;width:38px;height:22px;border-radius:999px;background:var(--color-neutral-300);position:relative"><spanstyle="position:absolute;left:3px;top:3px;width:16px;height:16px;border-radius:50%;background:var(--color-bg)"></span></span>
</div>
<divstyle="margin:22px 20px 0;padding:16px;border-radius:26px;background:var(--color-surface);display:flex;flex-direction:column;gap:10px">
<divstyle="margin:12px 20px 0;padding:12px 14px;border-radius:18px;background:var(--color-neutral-100);font-size:12px;line-height:1.45;display:flex;gap:10px"><divstyle="flex:none;width:26px;height:26px;border-radius:50%;background:var(--color-accent);display:flex;align-items:center;justify-content:center;font-family:var(--font-heading);font-size:12px">Q</div><div><b>MealQuest</b> · preview<br>This week's plan is ready: Tacos, Bolognese, Tikka masala + 4 more. Open the plan →</div></div>
<divstyle="padding:6px 20px 0"><divstyle="font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--color-accent-700)">Admin</div><divstyle="font-family:var(--font-heading);font-size:26px;line-height:1.1">AI assistant</div></div>
<divstyle="padding:16px 20px 0;display:flex;flex-direction:column;gap:14px">
<div><divstyle="font-size:12px;font-weight:700;color:var(--color-neutral-700);margin-bottom:5px">System prompt</div><divstyle="height:150px;padding:12px 14px;border-radius:22px;background:var(--color-surface);border:1px solid var(--color-divider);font:12px/1.55 ui-monospace,Menlo,monospace;color:var(--color-neutral-900);overflow:hidden">You are MealQuest, a dinner planning assistant for one household. Suggest dinners similar to their regular rotation. Prefer weeknight-friendly recipes. Flag crock pot meals and anything ≤30 min as "quick"…</div></div>
<pclass="dv-next">Try next: "go with <aclass="dv-oid"href="#1a">1a</a> for swipe and <aclass="dv-oid"href="#1f">1f</a> for the plan" · "show the Quest log (to-try pool) screen" · "add a Settings home that links to admin"</p>
<divstyle="padding:24px 20px;display:flex;flex-direction:column;gap:8px"><divstyle="font-family:var(--font-heading);font-size:30px">{{ tab }}</div><divstyle="font-size:14px;color:#645c50">Placeholder: see the static mockups for this tab. Tap Discover to return to the card demo.</div></div>
<divstyle="font-size:14px;line-height:1.55;color:#474238">Live reference for the three signature animations. Tap the buttons, drag the card, or switch tabs. Exact keyframes are in the handoff README.</div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Nav pill slide</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Pill animates left + width to the tapped item, 420 ms, cubic-bezier(.34,1.4,.64,1). Other icons FLIP to their new spots on the same curve; label fades in after 120 ms.</div></div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Try it</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Stamp pops in. Card wiggles (±4°, 420 ms), pulls back slightly, then flies off right with a 28° tilt (480 ms, ease-in). Quest log pill bumps.</div></div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Pass</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Card folds over on its left edge (rotateY to −80°, shading darkens), then drops and tumbles off left (720 ms total).</div></div>
{name:'Korean beef bowls',level:1,diff:'Easy',why:'You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.'},
{name:'Crock pot chicken tikka masala',level:2,diff:'Medium',why:'Butter chicken night is a household favorite. This one cooks itself while you work.'},
{name:'Lemon garlic shrimp orzo',level:2,diff:'Medium',why:'Your Shrimp scampi is on repeat. Orzo makes it a one-pot night.'},
{name:'Turkey chili',level:1,diff:'Easy',why:'A lighter take on the chili you make every fall.'},
{name:'Thai basil chicken',level:2,diff:'Medium',why:'Close to your stir-fry, with a fresh herby kick.'}
Organic is warm, rounded and a little playful: a cream-and-sand ground with a terracotta accent and a sage second accent, Caprasimo display headings over Figtree, 16px radii that grow into pills and soft circular shapes. Photographs are washed so they sit back into the warm page instead of on top of it.
## How to use this
- Link the one stylesheet from every page — `<link rel="stylesheet" href="styles.css">` (adjust the relative path) — and take every color, font, spacing, radius and shadow from its variables (`var(--color-*)`, `var(--font-*)`, `var(--space-*)`, `var(--radius-*)`, `var(--shadow-*)`). Never hard-code a hex, a font name or a px value the tokens already carry.
- Build with the classes below rather than inventing parallel ones; the component pages are plain HTML, so view source and copy the markup.
-`templates/` holds starting points a consuming project can copy whole.
- The whole system was derived from `theme.json`. To change the look, edit the tokens at the top of `styles.css` — every page, the thumbnail and this guide read from them — and keep `theme.json` and the written guidance in step so they don't drift from what the CSS actually does.
## Direction
Left-aligned, asymmetric layouts. Flush-left headings; content hugs the left edge with whitespace on the right. Lean into round shapes — over-rounded containers, pill buttons (`border-radius: 999px`), soft circular accents. Wrap hero and inline images in the `.washed` class — desaturated, lower-contrast and lifted, so they sit back into the page rather than on top of it.
## Color
A light ground (`--color-bg`#f5ead8) with `--color-text`#201e1d and two accents — `--color-accent`#c67139 and `--color-accent-2`#7a8a5e. Each role carries a 100–900 tonal ramp (`--color-neutral-100` … `--color-accent-2-900`) generated in OKLCH on a shared perceptual lightness scale, so the same step of any ramp has the same visual weight. Use the light steps (100–300) for tinted fills, hovers and subtle borders, 500 as the role's base, and the dark steps (700–900) for text on tinted fills and for pressed states; prefer ramp steps over ad-hoc `color-mix()`. For elevation use `--shadow-sm/md/lg` (already tuned to the ground) rather than ad-hoc box-shadows.
## Type
Caprasimo for headings over Figtree for body text, loaded as `--font-heading` / `--font-body`. Density 1.10× and radius 16px are already baked into the `--space-*` / `--radius-*` scales — use the variables, not raw numbers.
## Icons
Use Lucide icons (https://lucide.dev), at stroke-width 2.75 for a rounder, heavier look throughout.
## Interaction states
Interactive states are themed, never browser defaults: give every interactive element a `:hover` tint and a pressed state from the accent ramp (one step past the base — `--color-accent-600` on a light ground, `--color-accent-400` on a dark one, or a `color-mix()` tint for outlined/ghost variants), and style keyboard focus with `:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }` — never leave the default blue focus ring.
## Components
| Class | What it is | Shown in |
| --- | --- | --- |
| `.btn` with `.btn-primary`, `.btn-secondary`, `.btn-ghost`, `.btn-icon`, `.btn-block` | Actions — the primary is a solid accent fill | components/buttons.html |
| `.tag` with `.tag-accent`, `.tag-accent-2`, `.tag-neutral`, `.tag-outline` | Small labels tinted from the ramps | components/buttons.html |
| `.field` + `label`, `.input`, `.radio` + `.dot`, `.seg` + `.seg-opt` | Form fields and choices on native elements — no script | components/forms.html |
| `.nav` + `.nav-brand` | The header bar | components/navigation.html |
| `.table` | Data tables with themed header and row rules | components/table.html |
| `.dialog-backdrop` + `.dialog` (+ `.dialog-title/-body/-actions`) | A modal at the top elevation | components/dialog.html |
| `.hr` | A horizontal rule — present, but this system prefers whitespace; avoid it | — |
| `.washed` | The image wrapper — every content photograph goes through it | foundations/image.html |
States are built in: hovers and pressed states come from the accent ramp, keyboard focus is the 2px accent `:focus-visible` ring, `::selection` is an accent tint, and disabled controls drop to 45% opacity. Don't restyle them per page. The accent-to-ground pair is tuned to at least 3:1 — enough for icons, large text and interface chrome, not for body copy — so for paragraph-size text in the accent use a deep ramp step (`--color-accent-700` on this ground) rather than the accent itself.
## Do
- Over-round: `--radius-lg` for containers, `border-radius: 999px` for buttons and inputs.
- Use soft shapes — circles and blobs — as decoration and imagery masks.
- Reach for the sage `--color-accent-2-*` ramp as a genuine second voice, not just a highlight.
- Wash photography with the `.washed` wrapper and keep its edges rounded.
## Don't
- Do not draw sharp corners or hairline-only geometry.
- Do not desaturate the palette into greys — warmth is the point.
- Do not use condensed or geometric display faces; Caprasimo is the only display voice.
- Do not crowd elements; the rounded shapes need air to read as soft.
## Files
-`styles.css` — the only stylesheet: the token sheet (`:root` variables, ramps, base type) plus the component layer. Link it from every page.
-`readme.md` — this guide.
-`theme.json` — the parameters these files were derived from (a machine-readable record of the theme).
-`thumbnail.html` — the project cover (brand mark + swatches).
-`foundations/type.html` — the type scale and the heading/body pairing at real sizes.
-`foundations/color.html` — color roles and the 100-900 tonal ramps, with usage notes.
-`foundations/layout.html` — the spacing scale, the grid and how edges are drawn.
-`foundations/icons.html` — the icon set at interface sizes, inline and in buttons.
-`foundations/image.html` — how photographs and figures are treated.
-`components/buttons.html` — buttons, icon buttons and tags in every variant and state.
-`components/forms.html` — text fields, radios and the segmented control on native elements.
-`components/cards.html` — content cards and the elevation steps.
-`components/navigation.html` — the header bar pattern.
-`components/table.html` — a data table with the themed header and row rules.
-`components/dialog.html` — a modal over its backdrop at the top elevation.
-`theme.html` — the theme's parameters rendered as a reference sheet.
-`templates/landing/` — a starter page consuming the system the intended way (`index.html`, its `ds-base.js` loader, and the vendored `image-slot.js` its photograph mounts).
-`assets/photo.jpg` — the reference photograph the imagery page treats.
<divstyle="padding:24px 20px;display:flex;flex-direction:column;gap:8px"><divstyle="font-family:var(--font-heading);font-size:30px">{{ tab }}</div><divstyle="font-size:14px;color:#645c50">Placeholder: see the static mockups for this tab. Tap Discover to return to the card demo.</div></div>
<divstyle="font-size:14px;line-height:1.55;color:#474238">Live reference for the three signature animations. Tap the buttons, drag the card, or switch tabs. Exact keyframes are in the handoff README.</div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Nav pill slide</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Pill animates left + width to the tapped item, 420 ms, cubic-bezier(.34,1.4,.64,1). Other icons FLIP to their new spots on the same curve; label fades in after 120 ms.</div></div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Try it</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Stamp pops in. Card wiggles (±4°, 420 ms), pulls back slightly, then flies off right with a 28° tilt (480 ms, ease-in). Quest log pill bumps.</div></div>
<divstyle="padding:18px 20px;border-radius:26px;background:#f9f6f1;display:flex;flex-direction:column;gap:6px"><divstyle="font-family:var(--font-heading);font-size:18px">Pass</div><divstyle="font-size:13px;line-height:1.5;color:#474238">Card folds over on its left edge (rotateY to −80°, shading darkens), then drops and tumbles off left (720 ms total).</div></div>
{name:'Korean beef bowls',level:1,diff:'Easy',why:'You make Chicken stir-fry and Beef tacos most weeks. Same flavors, sweet-savory twist.'},
{name:'Crock pot chicken tikka masala',level:2,diff:'Medium',why:'Butter chicken night is a household favorite. This one cooks itself while you work.'},
{name:'Lemon garlic shrimp orzo',level:2,diff:'Medium',why:'Your Shrimp scampi is on repeat. Orzo makes it a one-pot night.'},
{name:'Turkey chili',level:1,diff:'Easy',why:'A lighter take on the chili you make every fall.'},
{name:'Thai basil chicken',level:2,diff:'Medium',why:'Close to your stir-fry, with a fresh herby kick.'}
MealQuest helps one household plan weekly dinners. The household enters the dinners they make on repeat ("regulars"); an AI assistant suggests new dinners to try ("side quests"), which the household accepts or declines with a swipe-card UI. Accepted dinners go into a to-try pool (the "Quest log"). Each week the AI drafts a plan that mixes regulars with Quest-log picks; the household swaps days, then the plan is pushed to Google Calendar. A shopping list is generated from the planned dinners, grouped by dinner, minus anything the household unchecks as already on hand. Each week's list is archived as a "post" in a blog-style history (by week / month / year). Push notifications and Google Chat webhook messages announce key events. An admin area inside Settings configures the LLM.
### Product decisions (confirmed with the client)
| Topic | Decision |
|---|---|
| Users | One **shared household account** (no per-member profiles). Anyone in the household can edit everything, including Admin. |
| Swipe accept | Goes into the **Quest log** (to-try pool), scheduled later. |
| Suggestion card shows | Photo, **why it was suggested** (referencing regular dinners), **difficulty**. |
| Week building | **AI builds the week** mixing regulars + Quest-log meals; the user swaps/adjusts. No fixed new-vs-regular ratio. |
| Google Calendar | **One-way: app is source of truth**, pushes dinners to a Google Calendar. |
| Shopping list | All ingredients for planned dinners, **grouped by dinner**. The user **unchecks items they already have** (this is the only pantry mechanism — no persistent pantry). |
| History | **Each weekly shopping list is a new post**; filter Week / Month / Year. |
| Quick dinners | "Quick" = **crock pot** OR **≤ 30 min prep-to-table**. Shown as **two tabs** (Crock pot / 30 min or less). Reachable from a **bottom-nav tab** AND a Home shortcut, and as a "Quick only" filter in Cook-from-what-I-have. |
| Notifications (push + Google Chat) | New weekly plan ready · Shopping list ready · Day-of dinner reminder · New suggestions to swipe. Each event is toggled separately for Push and Chat. |
| Admin (LLM) | Provider + model picker · API key management · Temperature (creativity) · System prompt editor. Lives **inside Settings**. |
| Copy tone | Playful, quest-themed, but every label stays plain enough to understand. |
### Vocabulary (use consistently in UI copy)
- **Regulars** — the household's routine dinners.
- **Side quests** — AI dinner suggestions (Discover tab).
- **Quest log** — accepted suggestions waiting to be scheduled (to-try pool).
- **Supply run** — the current week's shopping list.
- **Supply archive** — shopping-list history.
## About the design files
The files in this bundle are **design references built in HTML** — static hi-fi mockups plus one interactive motion prototype. They show the intended look and behavior; they are **not production code to copy**. Recreate them in the target codebase using its established patterns. There is no existing codebase, so the recommended stack is:
- **React 18 + TypeScript + Vite**, `vite-plugin-pwa` (Workbox) for the service worker + manifest.
- Styling: CSS variables from `tokens.css` + CSS Modules or Tailwind configured to those variables. Do not hard-code hex values in components.
- Motion: **Web Animations API** (as in the prototype) or **Framer Motion** — the keyframes below translate 1:1.
- Routing: React Router. Data: TanStack Query against a small API (backend out of scope for this handoff; integration points listed under *State & data*).
## Fidelity
**High-fidelity.** Colors, type, radii, spacing, copy and layout are final. Recreate pixel-accurately. Photos are placeholders (striped boxes labelled "dish photo") — real recipe photography will be supplied and should be rendered through the Organic "washed" treatment (`filter: saturate(.6) contrast(.85) brightness(1.1) opacity(.94)`), with rounded corners.
- Grape fill (`--color-accent`) = primary buttons, active nav pill, selected segmented option, checked checkboxes, slider fill. **Always `--on-accent` text on it.**
- Grape small text (kickers, links) uses `--color-accent-700`.
- "Side quest"/new-dinner highlights: grape-100 fill + grape-300 inset ring (rows) or teal-200/300 fills (tiles). Tags: grape-100 bg / grape-800 text.
- Teal = positive/confirmation voice: "Why this?" boxes (teal-100 bg, teal-900 text), "Synced"/"Connected" status text (teal-800), toggles ON and "Try it" button (teal-600), Quest-log count pill (teal-200 bg, teal-800 text).
| `/settings/notifications` | Notifications & Google Chat | 1n |
| `/settings/ai` | Admin · AI assistant | 1o |
Desktop settings (2e) shows Notifications, Google Chat webhook and AI assistant on one page (two columns).
**Chosen mobile directions:** Discover = **1a** (card stack), Plan = **1f** (draft board). Mocks 1b, 1c, 1d, 1e are rejected alternatives — ignore them.
---
## Screens
All mobile screens: background `--color-bg`; status-bar area 40px; content side padding 20px; bottom nav overlays the last 94px, so scrollable content needs ≥ 100px bottom padding.
### 1g · Home
- Header: "Friday, Oct 2" (12px 700 neutral-700) over title "Tonight's quest". Right: 40px round bell button (surface) with 8px grape unread dot.
- Tonight card (surface, radius 32): 150px photo inset 10px, then dinner name (Bagel 22px), meta "Regular · 40 min", right-aligned dark pill button "Recipe" (`--color-text` bg, `--color-bg` text).
- Two 104px tiles, 2-col grid gap 10: **Quick dinner** (grape fill, zap icon, on-accent text) → `/quick`; **Cook from what I have** (teal-300 fill, teal-900 text, search icon) → `/cook-from-pantry`.
- Status rows (neutral-100, radius 20, 12px 14px): "10 new side quests to swipe" → Discover; "Shopping list ready · Oct 5–11" → Shopping. Icon in grape-700, chevron right.
### 1h · Onboarding — regular dinners
3 progress bars (6px pills, filled = grape). "Step 2 of 3" kicker, title "What's on your usual rotation?" (30px), helper "Add the dinners your household makes on repeat. MealQuest builds suggestions from these." Input pill (48px, surface) with 36px grape "+" button. "Your regulars · N": chips teal-200/teal-900 with "×". "Common picks": dashed-outline chips "+ Chili" etc. Fixed bottom primary button "Next: notifications" (52px).
### 1a · Discover — swipe (CHOSEN)
- Header: kicker "Discover", title "Side quests"; right pill "Quest log · 6" (teal-200/teal-800).
- Header: "Oct 5 – 11" (26px) + "Draft" tag (grape-100/800). After pushing, tag becomes "Synced".
- Assistant bubble: 32px grape "Q" avatar + bubble (surface, radius 4 18 18 18): "I mixed 5 of your regulars with 2 from your Quest log. Tap any day to swap it."
- Primary button "Looks good — push to Calendar" (50px).
- Tapping a tile opens a swap sheet (not mocked; use Quest log + Regulars lists from 2d's right panel as a bottom sheet).
### 1j · Quick dinners
Header with 36px grape zap circle + "Quick dinners". Segmented tabs (surface track, 4px padding; selected = bg + shadow-sm): **Crock pot | 30 min or less**. Helper line per tab ("Prep to table in 30 minutes or less, picked from your tastes." / crock-pot equivalent). Rows (neutral-100, radius 24): 64px round photo, name (Bagel 16px), "25 min · Medium", 36px teal "+" (adds to Quest log). Footer link "↻ Show me more" (grape-700). Nav: Quick active.
### 1i · Cook from what I have
Back button + title. Ingredient chip field (surface, radius 26; chips bg-colored "Chicken thighs ×"; trailing "Add ingredient…"). Segmented "Any time | Quick only" + dark "Find ideas" button. Result cards (neutral-100, radius 24): name + time, teal-800 line "Uses all 5 · missing: 1 lime", buttons "Cook tonight" (grape) and "Add to Quest log" (outline).
Mobile: 250px full-bleed photo with round back button; sheet overlaps by 28px (radius 32 top). Tags (Side quest / Easy / 30 min), title 28px, "Why it was picked" teal box, Ingredients list with qty right-aligned and dividers, sticky bottom "Add to this week" + heart button.
Tablet 2a: header (back, "Saturday, Oct 10 · Side quest", title 36px) with **Keep screen on** toggle (Screen Wake Lock API) and **text size** segmented A/A/A. Two columns `400px | 1fr`: Ingredients card with 22px checkboxes (checked = struck-through, "3 of 9 set out"); Steps list — completed step muted with check, **current step** highlighted (grape-100 bg, 2px grape-300 ring, number circle grape, text 22px), others 18px. "Previous / Next step" buttons bottom-right.
### 1l · Shopping list / 2b tablet / 2f desktop
Kicker "Supply run · Oct 5–11", title "Shopping list", count "19 / 23". Helper "Uncheck anything you already have — it won't be counted." One card per dinner (surface, radius 24): dinner name (Bagel 16px) + day (11px). Items: 20–22px checkbox (checked = grape fill w/ white check = **to buy**; unchecked = 2px neutral-400 outline, struck-through name, "have it" label). Status line: "Sent to Google Chat · Sat 8:00 am" (teal-800, message icon). Tablet/desktop: CSS `column-count: 3` masonry, actions "Archive" (outline) + "Send to Google Chat" (primary).
### 1m · Supply archive (and 2f right panel)
Segmented "Week | Month | Year". Month headings (Bagel 18px). Post cards: kicker "WEEK 41 · OCT 5 – 11", AI-written title e.g. "Tacos, tikka & a salmon finale", meta "7 dinners · 23 items · 4 already on hand", dinner chips. Current week post = grape-100 + grape-300 ring, "· Current". Tapping a post opens the frozen list (read-only).
- HOUSEHOLD: Regular dinners ("7 on rotation"), Google Calendar ("Connected · Dinners calendar").
- ALERTS: Notifications & Google Chat.
- ADMIN: AI assistant ("Anthropic · Claude Sonnet") + "Admin" tag; card has grape-300 inset ring.
### 1n · Notifications & Google Chat
Back + title. Grid `1fr 46px 46px`: Event | PUSH | CHAT with toggles (40×24 pill; ON teal-600, knob right; OFF neutral-300). Events: New weekly plan ready · Shopping list ready · Day-of dinner reminder ("at 4:30 pm", tappable time) · New suggestions to swipe. Google Chat webhook card: mono URL input (ellipsis), "Connected · Dinner Crew space", "Send test" button. Message preview bubble: "MealQuest · preview — This week's plan is ready: Tacos, Bolognese, Tikka masala + 4 more. Open the plan →".
### 1o · Admin · AI assistant
Back + kicker "Settings · Admin" + title "AI assistant". Provider + Model dropdown pills (2-col). API key: masked mono "sk-••••••••3f9a" + "Replace" chip; "Verified · Oct 1" (teal-800). Temperature slider 0–1 step 0.1 (8px track, grape fill, 24px knob with 3px grape ring), labels "Familiar ↔ Adventurous", value right. System prompt textarea (mono 12px, radius 22). Bottom: "Reset" (outline) + "Save changes" (primary). Store API keys server-side only; the client only ever sees the masked tail.
### 2c tablet / 2d desktop · Plan manager
Header: kicker "Week 41", title "Oct 5 – 11", prev/next circles (+ "This week" pill on desktop), actions "Shopping list · 28", "Rebuild week", "Push to Calendar" (primary). Status "Synced to Google Calendar 2 min ago" (teal-800). 7-column grid (`repeat(7, minmax(0,1fr))`, gap 12): day label + card (photo 96–110px, name Bagel 16–17px, time, crock-pot "Start by 12:30 pm" hint, tag Regular/Side quest, swap icon). Side-quest cards teal-200.
Desktop right panel (290px, left divider): segmented "Quest log · 6 | Regulars · 9", helper "Drag a dinner onto a day to swap it in.", draggable rows (48px photo, name, difficulty, 6-dot grip). **Drag state:** source row becomes a dashed ghost at 55% opacity; target day shows dashed 2.5px grape border on grape-100 with "Drop to swap / Replaces Pizza night"; dragged card floats with shadow-lg, rotate −3°. Tablet 2c shows the Quest log as a chip strip under the grid with the same drag behavior.
### 2e · Desktop settings
Title + "Changes apply to everyone in the household." Sub-tabs: Household · Regular dinners · **Notifications & AI**. Left column: Notifications matrix card, Google Chat webhook card. Right column: AI assistant card (same fields as 1o, prompt textarea flexes to fill).
---
## Motion
A working reference is in **`MealQuest Motion.dc.html`** (open in a browser; tap buttons, drag the card, switch tabs, toggle reduced motion). Implement with WAAPI or Framer Motion using these exact values.
### 1. Bottom-nav pill slide
One absolutely positioned grape pill (`top:10px; height:42px`) lives behind the nav items (items are `position:relative; z-index:1`).
1. On tap, record each item's `getBoundingClientRect().left` and the pill's current `left/width`.
2. Commit the new active tab (active item now renders its label, so items reflow).
3. Measure the active item's `offsetLeft/offsetWidth`; set the pill to it and animate **from old → new `left` + `width`, 420ms, `cubic-bezier(.34,1.4,.64,1)`** (slight overshoot).
4. FLIP every nav item: animate `translateX(oldLeft − newLeft) → 0` with the same duration/easing so icons glide instead of jumping.
- Release with **dx > 110px** → accept: skip the wiggle, fly from the current transform to `translate(150%,-60px) rotate(28deg); opacity 0`, 340ms, same throw easing.
- Release with **dx < −110px** → pass: run the Pass fold, prefixing the first two keyframes with the current drag transform.
- Otherwise snap back to `translate(0,0) rotate(0)`, 420ms `cubic-bezier(.34,1.4,.64,1)`; reset stamps.
- Lock input (`busy`) while any exit animation runs.
### 5. Deck advance
After an exit, cancel the exited card's animations, remove it, and promote the others: depth 1→0 and 2→1 animate from their previous depth transform to the new one, **300ms `cubic-bezier(.2,.8,.2,1)`**. Prefetch suggestions so the deck always has ≥ 3 cards.
### 6. Reduced motion
Respect `prefers-reduced-motion: reduce`: nav pill jumps instantly (no FLIP/overshoot); Try it / Pass become a 200ms opacity fade; no wiggle, fold or deck promotion.
### Other transitions (not prototyped; keep consistent)
- Plan: `selectedDay` for swap sheet, drag-and-drop source/target on tablet/desktop.
- Shopping list item toggles are optimistic and persisted per week; once the week ends, the list is frozen into the archive.
### Integration points (backend — out of scope, but the UI depends on them)
- **LLM** — suggestion generation, week drafting, ingredient-based ideas, quick ideas, archive post titles. Uses Admin settings. Never expose the API key to the client.
- **Google Calendar** — OAuth once (Settings → Google Calendar); "Push to Calendar" creates/updates one event per dinner (one-way).
- **Google Chat** — server POSTs to the stored incoming-webhook URL for enabled events; "Send test" posts a sample.
- **Web Push** — VAPID; request permission during onboarding step 3 ("notifications"), not on first load. iOS requires the PWA to be installed to the home screen — show an install hint.
- **PWA** — manifest (`name: MealQuest`, `theme_color: #5a358c`, `background_color: #f9f6f1`, `display: standalone`), offline cache for the current plan, shopping list and recipes (kitchen use).
### Empty / loading / error states (not mocked — follow the system)
- Deck empty: Bagel title "All caught up", body "New side quests arrive Sunday." + "Get more now" primary.
- Loading: pill-shaped skeletons in `--color-surface` with a slow 1.2s opacity pulse.
- Errors: inline teal/grape-toned banner (neutral-100 card, grape-700 text) with a retry button; webhook test failure shows the HTTP status under the URL field.
## Accessibility
- Swipe is never the only path: Pass / Try it buttons always present; also support ← / → keys on Discover.
- All text ≥ 4.5:1 (on-accent on grape ≈ 9:1). Hit targets ≥ 44px (nav items are 42px tall inside a 62px bar — keep the full bar height tappable).
- Toggles are `role="switch"`; checkboxes native inputs styled; nav items `aria-current="page"`.
## Assets
- Fonts: Bagel Fat One, Figtree (Google Fonts).
- Icons: Lucide.
- Photos: placeholders only — supply real dinner photos and apply the washed treatment.
- Base system: Organic design system (`_ds/.../styles.css`), overridden by `tokens.css`.
## Files
-`README.md` — this document.
-`tokens.css` — final design tokens (use these).
-`MealQuest Mockups v2.dc.html` — all screens. Section 2 = tablet & desktop (2a–2f); section 1 = mobile (1a–1p). Chosen mobile directions are badged "Chosen".
-`screenshots/` — PNG of every chosen screen: `mobile-1a…1p-*.png` (720×1520, 2× of a 360×760 phone), `tablet-2a…2c-*.png` (1180×820), `desktop-2d…2f-*.png` (1440×900). Rejected mobile alternatives (1b–1e) are not included. Note: the static screenshot of 1a doesn't show the two stacked cards behind the top card; see Motion → deck depth transforms.
-`support.js`, `_ds/organic-…/styles.css` — needed only to open the HTML references locally (serve the folder over a local web server, e.g. `npx serve`).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.