[object Object]

← back to Dw Photo Capture

Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Photoshop board, behind basic-auth (TK-12344)

4ace5d45c2e66843caa898f552453912fb384840 · 2026-09-26 10:43:25 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk

Files touched

Diff

commit 4ace5d45c2e66843caa898f552453912fb384840
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Sep 26 10:43:25 2026 -0700

    Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Photoshop board, behind basic-auth (TK-12344)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk
---
 public/kid-simple/index.html                       | 187 +++++++
 .../kid-simple/renders/kid-simple-v7-v16-board.jpg | Bin 0 -> 1501686 bytes
 public/kid-simple/renders/v10-todays-inbox.png     | Bin 0 -> 115608 bytes
 public/kid-simple/renders/v11-bottom-sheet.png     | Bin 0 -> 301466 bytes
 public/kid-simple/renders/v12-hold-to-talk.png     | Bin 0 -> 555623 bytes
 public/kid-simple/renders/v13-sticker-book.png     | Bin 0 -> 201594 bytes
 public/kid-simple/renders/v14-ticket-printer.png   | Bin 0 -> 93527 bytes
 public/kid-simple/renders/v15-thumb-zone.png       | Bin 0 -> 198786 bytes
 public/kid-simple/renders/v16-widget-stack.png     | Bin 0 -> 106260 bytes
 public/kid-simple/renders/v7-scan-and-go.png       | Bin 0 -> 307129 bytes
 public/kid-simple/renders/v8-mode-dial.png         | Bin 0 -> 274678 bytes
 public/kid-simple/renders/v9-story-mode.png        | Bin 0 -> 107408 bytes
 public/kid-simple/v1-magic-camera.html             | 550 +++++++++++++++++++
 public/kid-simple/v10-todays-inbox.html            | 396 ++++++++++++++
 public/kid-simple/v11-bottom-sheet.html            | 397 ++++++++++++++
 public/kid-simple/v12-hold-to-talk.html            | 411 ++++++++++++++
 public/kid-simple/v13-sticker-book.html            | 409 ++++++++++++++
 public/kid-simple/v14-ticket-printer.html          | 344 ++++++++++++
 public/kid-simple/v15-thumb-zone.html              | 493 +++++++++++++++++
 public/kid-simple/v16-widget-stack.html            | 364 +++++++++++++
 public/kid-simple/v2-four-tiles.html               | 588 +++++++++++++++++++++
 public/kid-simple/v3-text-buddy.html               | 551 +++++++++++++++++++
 public/kid-simple/v4-level-up.html                 | 444 ++++++++++++++++
 public/kid-simple/v5-swipe-deck.html               | 490 +++++++++++++++++
 public/kid-simple/v6-one-thing.html                | 460 ++++++++++++++++
 public/kid-simple/v7-scan-and-go.html              | 324 ++++++++++++
 public/kid-simple/v8-mode-dial.html                | 354 +++++++++++++
 public/kid-simple/v9-story-mode.html               | 386 ++++++++++++++
 server.js                                          |  18 +
 29 files changed, 7166 insertions(+)

diff --git a/public/kid-simple/index.html b/public/kid-simple/index.html
new file mode 100644
index 0000000..b51a76c
--- /dev/null
+++ b/public/kid-simple/index.html
@@ -0,0 +1,187 @@
+<title>Photo Capture, Kid-Simple</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,500;6..72,600&family=Public+Sans:wght@400;600;700&display=swap">
+<style>
+:root{
+  --ground:#EDEFEC; --panel:#FFFFFF; --ink:#1E2320; --muted:#5E6A64;
+  --line:#D5DAD5; --gold:#9C7A33; --gold-soft:#F1E7D2; --sage:#4E7A64;
+  --good:#2F7D55; --warn:#A8651C; --bad:#A83A2E;
+  color-scheme:light;
+}
+@media (prefers-color-scheme: dark){
+  :root:not([data-theme="light"]){
+    --ground:#161A18; --panel:#1F2522; --ink:#E9ECE9; --muted:#9AA6A0;
+    --line:#333B37; --gold:#D6B26A; --gold-soft:#3A3120; --sage:#8DB8A2;
+    --good:#6CC495; --warn:#E0A35A; --bad:#E37E71; color-scheme:dark;
+  }
+}
+:root[data-theme="dark"]{
+  --ground:#161A18; --panel:#1F2522; --ink:#E9ECE9; --muted:#9AA6A0;
+  --line:#333B37; --gold:#D6B26A; --gold-soft:#3A3120; --sage:#8DB8A2;
+  --good:#6CC495; --warn:#E0A35A; --bad:#E37E71; color-scheme:dark;
+}
+body{background:var(--ground);color:var(--ink);font:16px/1.55 "Public Sans",system-ui,sans-serif;padding-inline:16px;padding-block:32px 64px}
+.wrap{max-width:1320px;margin:0 auto;display:flex;flex-direction:column;gap:32px}
+header{display:flex;flex-direction:column;gap:10px;max-width:68ch}
+.eyebrow{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--gold);font-weight:700}
+h1{font:600 clamp(30px,5vw,46px)/1.1 "Newsreader",Georgia,serif;margin:0;text-wrap:balance}
+h2{font:600 24px/1.2 "Newsreader",Georgia,serif;margin:0;text-wrap:balance}
+p{margin:0}
+.lede{color:var(--muted)}
+.jobs{display:flex;flex-wrap:wrap;gap:8px}
+.chip{border:1px solid var(--line);background:var(--panel);border-radius:999px;padding:4px 12px;font-size:14px}
+.verdict{background:var(--panel);border:1px solid var(--line);border-left:4px solid var(--gold);padding:18px 20px;display:flex;flex-direction:column;gap:6px;max-width:80ch}
+.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,400px),1fr));gap:40px 28px}
+.card{display:flex;flex-direction:column;gap:12px}
+.head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
+.tag{font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums}
+.score{font:700 14px/1 "Public Sans",sans-serif;padding:6px 10px;border-radius:999px;background:var(--gold-soft);color:var(--ink);white-space:nowrap}
+.score.top{background:var(--good);color:var(--panel)}
+.phone{width:100%;max-width:398px;aspect-ratio:390/780;border:4px solid var(--ink);border-radius:34px;overflow:hidden;background:#000}
+.phone iframe{width:100%;height:100%;border:0;display:block}
+.idea{color:var(--muted)}
+dl{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;margin:0;font-size:14px}
+dt{color:var(--muted)}
+dd{margin:0}
+.taps{font-variant-numeric:tabular-nums}
+.flaw{color:var(--bad)}
+a{color:var(--sage);font-weight:600}
+a:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
+footer{color:var(--muted);font-size:14px;max-width:80ch}
+</style>
+
+<div class="wrap">
+  <header>
+    <div class="eyebrow">photo.designerwallcoverings.com · redesign study</div>
+    <h1>Sixteen ways to make photo capture simple enough for a 13-year-old</h1>
+    <p class="lede">Today's app puts about 40 controls on one screen. Each version below keeps only the four real jobs, uses words a teenager knows, and makes the camera the hero. Every phone is a live, clickable mockup with pretend data — tap through it.</p>
+    <div class="jobs"><span class="chip">Add New Item</span><span class="chip">Update an Item</span><span class="chip">Find an Item</span><span class="chip">A Sample Came In</span></div>
+  </header>
+
+  <section class="verdict">
+    <h2>Round 2 pick: v4 Level Up</h2>
+    <p>After a second UX pass (Home + Back everywhere, a "good photo?" check after every shot, Undo after saving, a "no match" path, bigger text and targets), a separate reviewer re-tested all six. v4 came out cleanest: its Back/Home bar is always on screen, so no screen can strand you. Every defect the reviewer found in round 2 has been fixed in the mockups below. Tip: each one has a "Demo: show 'no match'" switch so you can see the failure path.</p>
+  </section>
+
+  <div class="grid">
+    <article class="card">
+      <div class="head"><h2>v4 · Level Up</h2><span class="score top">#1</span></div>
+      <div class="phone"><iframe src="v4-level-up.html" title="v4 Level Up mockup" loading="lazy"></iframe></div>
+      <p class="idea">Each job is a short game path — 2 or 3 levels, progress dots, confetti at the end.</p>
+      <dl><dt>Round 2 fixed</dt><dd>A timer could yank you back to "done" after you tapped Back; Undo after Update landed on the wrong screen</dd><dt>Watch for</dt><dd class="flaw">Confetti and levels may feel like a toy to older staff</dd></dl>
+      <a href="v4-level-up.html">Open full screen</a>
+    </article>
+
+    <article class="card">
+      <div class="head"><h2>v3 · Text Buddy</h2><span class="score">#2</span></div>
+      <div class="phone"><iframe src="v3-text-buddy.html" title="v3 Text Buddy mockup" loading="lazy"></iframe></div>
+      <p class="idea">The whole app is a text chat with "Sam," who asks one thing at a time with tap-to-reply chips.</p>
+      <dl><dt>Round 2 fixed</dt><dd>"Undo last" could replay a stale photo; some captions were under 17px</dd><dt>Watch for</dt><dd class="flaw">The undo-by-replay design is the most complex to build for real</dd></dl>
+      <a href="v3-text-buddy.html">Open full screen</a>
+    </article>
+
+    <article class="card">
+      <div class="head"><h2>v6 · One Thing At A Time</h2><span class="score">#3</span></div>
+      <div class="phone"><iframe src="v6-one-thing.html" title="v6 One Thing At A Time mockup" loading="lazy"></iframe></div>
+      <p class="idea">No menus at all: one big question and one to three full-width buttons per screen.</p>
+      <dl><dt>Round 2 fixed</dt><dd>Wrong job name, three different "again" buttons (now all "Do Another"), low-contrast secondary buttons</dd><dt>Watch for</dt><dd class="flaw">Most screens per job — slowest for a practiced user</dd></dl>
+      <a href="v6-one-thing.html">Open full screen</a>
+    </article>
+
+    <article class="card">
+      <div class="head"><h2>v1 · Magic Camera</h2><span class="score">#4</span></div>
+      <div class="phone"><iframe src="v1-magic-camera.html" title="v1 Magic Camera mockup" loading="lazy"></iframe></div>
+      <p class="idea">One giant shutter button first; after the shot it asks "What's this photo for?" with the four jobs.</p>
+      <dl><dt>Round 2 fixed</dt><dd>Undo after Save wiped the brand you picked; loading screens had no way out</dd><dt>Watch for</dt><dd class="flaw">Photo-first means Find by code still starts with the camera</dd></dl>
+      <a href="v1-magic-camera.html">Open full screen</a>
+    </article>
+
+    <article class="card">
+      <div class="head"><h2>v2 · Four Big Tiles</h2><span class="score">#5</span></div>
+      <div class="phone"><iframe src="v2-four-tiles.html" title="v2 Four Big Tiles mockup" loading="lazy"></iframe></div>
+      <p class="idea">A home screen of four big coloured tiles, one per job, like phone app icons.</p>
+      <dl><dt>Round 2 fixed</dt><dd>"Sample Arrived" renamed; grey subtitles failed contrast; three demo switches disagreed with each other; same Undo bug as v1</dd><dt>Watch for</dt><dd class="flaw">Plain — nothing guides you once you're inside a job</dd></dl>
+      <a href="v2-four-tiles.html">Open full screen</a>
+    </article>
+
+    <article class="card">
+      <div class="head"><h2>v5 · Swipe Deck</h2><span class="score">#6</span></div>
+      <div class="phone"><iframe src="v5-swipe-deck.html" title="v5 Swipe Deck mockup" loading="lazy"></iframe></div>
+      <p class="idea">Every step is a card: swipe right or tap ✓ for yes, swipe left or tap ✗ to redo.</p>
+      <dl><dt>Round 2 fixed</dt><dd>Crashed on "switch tab, then Back"; swipe hint was wrong on the Find screen</dd><dt>Watch for</dt><dd class="flaw">Swiping is hard one-handed while holding a sample</dd></dl>
+      <a href="v5-swipe-deck.html">Open full screen</a>
+    </article>
+  </div>
+
+
+  <section class="verdict" id="round3">
+    <h2>Round 3: ten more directions, v7–v16</h2>
+    <p>Built in parallel this morning (TK-12344), reviewed by a separate critic, fixed, then laid out as one Photoshop board. Not ranked yet.</p>
+    <p><a href="renders/kid-simple-v7-v16-board.jpg">Open the Photoshop board (JPG)</a></p>
+  </section>
+  <a href="renders/kid-simple-v7-v16-board.jpg"><img src="renders/kid-simple-v7-v16-board.jpg" alt="Photoshop board showing Kid-Simple versions 7 through 16 side by side" style="width:100%;height:auto;border:1px solid var(--line);border-radius:8px"></a>
+  <div class="grid">
+    <article class="card">
+      <div class="head"><h2>v7 · Scan &amp; Go</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v7-scan-and-go.html" title="v7 Scan &amp; Go mockup" loading="lazy"></iframe></div>
+      <p class="idea">A scanner viewfinder home: point at a tag or box; a match goes to Update or Sample, no match goes to Add New Item.</p>
+      <a href="v7-scan-and-go.html">Open full screen</a> · <a href="renders/v7-scan-and-go.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v8 · Mode Dial</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v8-mode-dial.html" title="v8 Mode Dial mockup" loading="lazy"></iframe></div>
+      <p class="idea">Camera home with a swipeable NEW / UPDATE / FIND / SAMPLE strip; the shutter's colour and label change with the mode.</p>
+      <a href="v8-mode-dial.html">Open full screen</a> · <a href="renders/v8-mode-dial.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v9 · Story Mode</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v9-story-mode.html" title="v9 Story Mode mockup" loading="lazy"></iframe></div>
+      <p class="idea">Instagram-style stories: pick a job ring, then tap right to continue and left to go back.</p>
+      <a href="v9-story-mode.html">Open full screen</a> · <a href="renders/v9-story-mode.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v10 · Today's Inbox</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v10-todays-inbox.html" title="v10 Today's Inbox mockup" loading="lazy"></iframe></div>
+      <p class="idea">Home is a to-do list of what's waiting (samples in, photos needed), plus a camera button for Add New Item.</p>
+      <a href="v10-todays-inbox.html">Open full screen</a> · <a href="renders/v10-todays-inbox.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v11 · Bottom Sheet</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v11-bottom-sheet.html" title="v11 Bottom Sheet mockup" loading="lazy"></iframe></div>
+      <p class="idea">Full-screen camera with a Maps-style pull-up sheet holding the four jobs.</p>
+      <a href="v11-bottom-sheet.html">Open full screen</a> · <a href="renders/v11-bottom-sheet.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v12 · Hold to Talk</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v12-hold-to-talk.html" title="v12 Hold to Talk mockup" loading="lazy"></iframe></div>
+      <p class="idea">Press and hold the mic and say what you're doing; big tap buttons are the fallback.</p>
+      <a href="v12-hold-to-talk.html">Open full screen</a> · <a href="renders/v12-hold-to-talk.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v13 · Sticker Book</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v13-sticker-book.html" title="v13 Sticker Book mockup" loading="lazy"></iframe></div>
+      <p class="idea">Scrapbook look: take a photo, then drag the polaroid onto one of four job stickers (or just tap a sticker).</p>
+      <a href="v13-sticker-book.html">Open full screen</a> · <a href="renders/v13-sticker-book.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v14 · Ticket Printer</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v14-ticket-printer.html" title="v14 Ticket Printer mockup" loading="lazy"></iframe></div>
+      <p class="idea">Four arcade keys; each finished job prints a little thermal-paper ticket.</p>
+      <a href="v14-ticket-printer.html">Open full screen</a> · <a href="renders/v14-ticket-printer.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v15 · Thumb Zone</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v15-thumb-zone.html" title="v15 Thumb Zone mockup" loading="lazy"></iframe></div>
+      <p class="idea">Shoot first; every control lives in the bottom third where your thumb reaches; hold-to-confirm rings.</p>
+      <a href="v15-thumb-zone.html">Open full screen</a> · <a href="renders/v15-thumb-zone.png">Photoshop render</a>
+    </article>
+    <article class="card">
+      <div class="head"><h2>v16 · Widget Stack</h2><span class="tag">round 3</span></div>
+      <div class="phone"><iframe src="v16-widget-stack.html" title="v16 Widget Stack mockup" loading="lazy"></iframe></div>
+      <p class="idea">iPhone-style widgets (Samples Waiting, Need Updates, Last Added, Find) that open in place and count down as you work.</p>
+      <a href="v16-widget-stack.html">Open full screen</a> · <a href="renders/v16-widget-stack.png">Photoshop render</a>
+    </article>
+  </div>
+
+  <footer>Mockups only — nothing here talks to the real catalog, camera, or FileMaker. Ranking is the independent reviewer's round-2 order for a 13-year-old.</footer>
+</div>
diff --git a/public/kid-simple/renders/kid-simple-v7-v16-board.jpg b/public/kid-simple/renders/kid-simple-v7-v16-board.jpg
new file mode 100644
index 0000000..6687aea
Binary files /dev/null and b/public/kid-simple/renders/kid-simple-v7-v16-board.jpg differ
diff --git a/public/kid-simple/renders/v10-todays-inbox.png b/public/kid-simple/renders/v10-todays-inbox.png
new file mode 100644
index 0000000..e1e4741
Binary files /dev/null and b/public/kid-simple/renders/v10-todays-inbox.png differ
diff --git a/public/kid-simple/renders/v11-bottom-sheet.png b/public/kid-simple/renders/v11-bottom-sheet.png
new file mode 100644
index 0000000..1899ecb
Binary files /dev/null and b/public/kid-simple/renders/v11-bottom-sheet.png differ
diff --git a/public/kid-simple/renders/v12-hold-to-talk.png b/public/kid-simple/renders/v12-hold-to-talk.png
new file mode 100644
index 0000000..f9b1aeb
Binary files /dev/null and b/public/kid-simple/renders/v12-hold-to-talk.png differ
diff --git a/public/kid-simple/renders/v13-sticker-book.png b/public/kid-simple/renders/v13-sticker-book.png
new file mode 100644
index 0000000..f948227
Binary files /dev/null and b/public/kid-simple/renders/v13-sticker-book.png differ
diff --git a/public/kid-simple/renders/v14-ticket-printer.png b/public/kid-simple/renders/v14-ticket-printer.png
new file mode 100644
index 0000000..b4b12cc
Binary files /dev/null and b/public/kid-simple/renders/v14-ticket-printer.png differ
diff --git a/public/kid-simple/renders/v15-thumb-zone.png b/public/kid-simple/renders/v15-thumb-zone.png
new file mode 100644
index 0000000..68e158c
Binary files /dev/null and b/public/kid-simple/renders/v15-thumb-zone.png differ
diff --git a/public/kid-simple/renders/v16-widget-stack.png b/public/kid-simple/renders/v16-widget-stack.png
new file mode 100644
index 0000000..6f0987c
Binary files /dev/null and b/public/kid-simple/renders/v16-widget-stack.png differ
diff --git a/public/kid-simple/renders/v7-scan-and-go.png b/public/kid-simple/renders/v7-scan-and-go.png
new file mode 100644
index 0000000..62747c1
Binary files /dev/null and b/public/kid-simple/renders/v7-scan-and-go.png differ
diff --git a/public/kid-simple/renders/v8-mode-dial.png b/public/kid-simple/renders/v8-mode-dial.png
new file mode 100644
index 0000000..93654dd
Binary files /dev/null and b/public/kid-simple/renders/v8-mode-dial.png differ
diff --git a/public/kid-simple/renders/v9-story-mode.png b/public/kid-simple/renders/v9-story-mode.png
new file mode 100644
index 0000000..09d0bbb
Binary files /dev/null and b/public/kid-simple/renders/v9-story-mode.png differ
diff --git a/public/kid-simple/v1-magic-camera.html b/public/kid-simple/v1-magic-camera.html
new file mode 100644
index 0000000..4eb4317
--- /dev/null
+++ b/public/kid-simple/v1-magic-camera.html
@@ -0,0 +1,550 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>v1 — Magic Camera</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --charcoal:#1C1C1E;
+    --gold:#C9A24B;
+    --cream:#FDFBF7;
+    --green:#3FA66B;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#0a0a0a;font-family:'Inter',sans-serif;}
+  .stage{
+    width:390px;height:780px;margin:24px auto;position:relative;
+    background:var(--charcoal);border-radius:36px;overflow:hidden;
+    box-shadow:0 20px 60px rgba(0,0,0,.5);border:8px solid #000;
+  }
+  .screen{
+    position:absolute;inset:0;display:none;flex-direction:column;
+    background:var(--charcoal);color:var(--cream);
+  }
+  .screen.active{display:flex;}
+  .light{background:var(--cream);color:var(--charcoal);}
+  h1,h2,h3{font-family:'Fraunces',serif;margin:0;}
+  .dw-mark{
+    position:absolute;top:18px;left:18px;font-family:'Fraunces',serif;
+    font-weight:700;font-size:15px;letter-spacing:1px;color:var(--cream);opacity:.85;z-index:5;
+  }
+  .hint{
+    position:absolute;top:56px;left:0;right:0;text-align:center;
+    font-size:17px;color:var(--cream);opacity:.9;z-index:5;
+  }
+  .demo-toggle{
+    position:absolute;top:86px;left:0;right:0;text-align:center;z-index:5;
+    font-size:14px;color:var(--cream);opacity:.7;display:flex;align-items:center;justify-content:center;gap:8px;
+  }
+  .demo-toggle input{width:18px;height:18px;}
+  .viewfinder{
+    position:absolute;inset:0;
+    background:
+      repeating-linear-gradient(135deg, #232326 0 40px, #1c1c1e 40px 80px);
+  }
+  .shutter-wrap{
+    position:absolute;bottom:48px;left:0;right:0;display:flex;justify-content:center;z-index:5;
+  }
+  .shutter{
+    width:96px;height:96px;border-radius:50%;background:var(--gold);
+    border:6px solid var(--cream);cursor:pointer;font-size:40px;
+    display:flex;align-items:center;justify-content:center;
+    box-shadow:0 8px 24px rgba(0,0,0,.4);
+  }
+  .shutter:active, .btn:active, .brand-tile:active, .nav-btn:active, .chip:active{transform:scale(.97);}
+  .shutter:focus-visible, button:focus-visible, .card-btn:focus-visible, .brand-tile:focus-visible, input:focus-visible{
+    outline:3px solid var(--gold);outline-offset:2px;
+  }
+  .btn:disabled{opacity:.4;cursor:not-allowed;}
+  .demo-caption{font-size:14px;opacity:.6;margin-top:-8px;}
+  .looking-wrap{align-items:center;justify-content:center;gap:18px;}
+  .looking-wrap .spinner{
+    width:64px;height:64px;border-radius:50%;
+    border:6px solid rgba(255,255,255,.15);border-top-color:var(--gold);
+    animation:spin 1s linear infinite;
+  }
+  @keyframes spin{to{transform:rotate(360deg);}}
+  .looking-wrap p{font-size:19px;}
+  /* topbar: always-there way out */
+  .topbar{
+    display:flex;align-items:center;justify-content:space-between;gap:10px;
+    padding:14px 16px;flex-shrink:0;z-index:6;
+  }
+  .nav-btn{
+    min-height:56px;min-width:56px;border-radius:14px;border:2px solid rgba(253,251,247,.4);
+    background:transparent;color:var(--cream);font-family:'Inter',sans-serif;font-size:17px;
+    font-weight:600;cursor:pointer;padding:0 16px;display:flex;align-items:center;gap:6px;
+  }
+  .light .nav-btn{border-color:#ddd4c2;color:var(--charcoal);}
+  .step-indicator{padding:0 24px;font-size:17px;opacity:.7;flex-shrink:0;}
+  .content{padding:8px 24px 24px;display:flex;flex-direction:column;gap:16px;flex:1;overflow-y:auto;}
+  .actions{margin-top:auto;display:flex;flex-direction:column-reverse;gap:12px;padding-top:16px;}
+  .swatch{
+    width:100%;height:200px;border-radius:18px;margin-top:4px;
+    background:
+      repeating-linear-gradient(45deg,#8FAE8B 0 22px,#B9CBB2 22px 44px),
+      linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;
+  }
+  .swatch.blue{background:
+      repeating-linear-gradient(45deg,#7C93B0 0 22px,#B3C3D6 22px 44px),
+      linear-gradient(135deg,#7C93B0,#5f7692);
+    background-blend-mode:multiply;}
+  .thumb{width:96px;height:96px;border-radius:14px;flex-shrink:0;
+    background:repeating-linear-gradient(45deg,#8FAE8B 0 16px,#B9CBB2 16px 32px),linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;}
+  .item-title{font-size:22px;font-weight:700;}
+  .item-sub{font-size:17px;opacity:.75;}
+  .btn{
+    min-height:56px;border-radius:16px;border:none;font-family:'Inter',sans-serif;
+    font-size:18px;font-weight:600;cursor:pointer;padding:0 20px;width:100%;
+  }
+  .btn-primary{background:var(--gold);color:#1C1C1E;}
+  .btn-secondary{background:transparent;color:var(--cream);border:2px solid rgba(253,251,247,.4);}
+  .btn-light-primary{background:var(--gold);color:#1C1C1E;}
+  .btn-light-secondary{background:#ece7dd;color:var(--charcoal);border:2px solid #ddd4c2;}
+  .btn-success{background:var(--green);color:#fff;}
+  .btn-link{background:none;border:none;color:var(--cream);text-decoration:underline;font-size:17px;min-height:44px;cursor:pointer;font-family:'Inter',sans-serif;}
+  .light .btn-link{color:var(--charcoal);}
+  .search-bar{background:#2a2a2d;border:2px solid #3a3a3d;border-radius:14px;padding:0 14px;display:flex;align-items:center;}
+  .search-bar input{background:none;border:none;color:var(--cream);font-size:17px;padding:14px 8px;width:100%;font-family:'Inter',sans-serif;}
+  .search-bar input::placeholder{color:rgba(253,251,247,.5);}
+  .section-label{font-size:14px;opacity:.6;text-transform:uppercase;letter-spacing:.5px;margin-top:4px;}
+  .brand-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
+  .brand-tile{
+    background:#2a2a2d;border:2px solid #3a3a3d;border-radius:14px;
+    min-height:72px;display:flex;align-items:center;justify-content:center;
+    font-size:17px;font-weight:600;color:var(--cream);cursor:pointer;text-align:center;padding:8px;
+  }
+  .brand-tile:hover{border-color:var(--gold);}
+  .brand-tile.selected{border-color:var(--gold);background:#3a331f;box-shadow:inset 0 0 0 2px var(--gold);}
+  .brand-tile.hidden{display:none;}
+  .center-flex{align-items:center;justify-content:center;text-align:center;}
+  .big-emoji{font-size:64px;}
+  .pick-list{display:flex;flex-direction:column;gap:14px;margin-top:8px;}
+  .home-hdr{text-align:center;font-size:17px;margin-top:4px;}
+  .done-row{display:flex;gap:14px;align-items:center;}
+  .done-facts{font-size:16px;line-height:1.5;}
+  .done-facts strong{font-size:18px;}
+  .toast{
+    position:absolute;left:16px;right:16px;bottom:24px;background:#2a2a2d;color:var(--cream);
+    border-radius:14px;padding:14px 18px;display:none;align-items:center;justify-content:space-between;
+    gap:12px;box-shadow:0 8px 24px rgba(0,0,0,.5);z-index:20;font-size:17px;border:2px solid var(--gold);
+  }
+  .toast.show{display:flex;}
+  .toast button{background:none;border:none;color:var(--gold);font-weight:700;font-size:17px;cursor:pointer;min-height:56px;min-width:56px;padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    .looking-wrap .spinner{animation:none;border-top-color:var(--gold);}
+    *{transition:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="stage" id="stage">
+
+  <!-- HOME -->
+  <div class="screen active" id="home">
+    <div class="dw-mark">DW</div>
+    <div class="hint">Point at anything and tap 📸</div>
+    <label class="demo-toggle"><input type="checkbox" id="demoToggle" onchange="demoNoMatch=this.checked"> Demo: show "no match"</label>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap">
+      <button class="shutter" id="shutterBtn" aria-label="Shoot photo">📸</button>
+    </div>
+  </div>
+
+  <!-- PHOTO CHECK (generic, reused after every shot) -->
+  <div class="screen center-flex" id="photoCheck">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content center-flex">
+      <div class="thumb" id="photoCheckThumb" style="width:220px;height:220px;"></div>
+      <p style="font-size:18px;" aria-live="polite">Looks good?</p>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="photoLooksGood()">Looks good</button>
+        <button class="btn btn-secondary" onclick="goBack()">Retake</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- LOOKING -->
+  <div class="screen looking-wrap" id="looking">
+    <div class="topbar" style="position:absolute;top:0;left:0;right:0;">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="spinner"></div>
+    <p aria-live="polite">Looking for matches…</p>
+  </div>
+
+  <!-- WHAT'S THIS FOR -->
+  <div class="screen" id="whatFor">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <h2>What's this photo for?</h2>
+      <div class="pick-list">
+        <button class="btn btn-primary" onclick="chooseJob('add')">Add New Item</button>
+        <button class="btn btn-primary" onclick="chooseJob('update')">Update an Item</button>
+        <button class="btn btn-primary" onclick="chooseJob('find')">Find an Item</button>
+        <button class="btn btn-primary" onclick="chooseJob('sample')">A Sample Came In</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- ADD: BRAND GRID -->
+  <div class="screen" id="addBrand">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <h3>Which brand?</h3>
+      <div class="search-bar"><input type="text" id="brandSearch" placeholder="Search brands…" oninput="filterBrands()" aria-label="Search brands"></div>
+      <div class="section-label">Recent</div>
+      <div class="brand-grid" id="recentBrands">
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'York')" onkeydown="onBrandKey(event,this,'York')">York</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Kravet')" onkeydown="onBrandKey(event,this,'Kravet')">Kravet</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Thibaut')" onkeydown="onBrandKey(event,this,'Thibaut')">Thibaut</div>
+      </div>
+      <div class="section-label">All Brands</div>
+      <div class="brand-grid" id="allBrands">
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Brewster')" onkeydown="onBrandKey(event,this,'Brewster')">Brewster</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Cole &amp; Son')" onkeydown="onBrandKey(event,this,'Cole &amp; Son')">Cole &amp; Son</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Mulberry')" onkeydown="onBrandKey(event,this,'Mulberry')">Mulberry</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Other / Unsure')" onkeydown="onBrandKey(event,this,'Other / Unsure')">Other / Unsure</div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-primary" id="saveDraftBtn" disabled onclick="saveDraft()">Save as Draft</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- GENERIC DONE SCREEN -->
+  <div class="screen light" id="doneScreen">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <div class="done-row">
+        <div class="thumb" id="doneThumb"></div>
+        <div class="done-facts">
+          <strong id="doneTitle"></strong><br>
+          code <span id="doneCode"></span> · <span id="doneBrand"></span><br>
+          <span id="doneAction"></span>
+        </div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-light-primary" onclick="goHome()">Do Another</button>
+        <button class="btn btn-light-secondary" onclick="goHome()">Home</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: MATCH -->
+  <div class="screen" id="updateMatch">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="step-indicator">Step 1 of 2</div>
+    <div class="content">
+      <h2>Found a Match</h2>
+      <div class="swatch blue"></div>
+      <div class="item-title">Palm Damask — Sage</div>
+      <div class="item-sub">code DW-10423 · York</div>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="go('updateCam2')">Yes, that's right</button>
+        <button class="btn btn-secondary" onclick="showNoMatch('update')">Not this item</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: TAKE NEW PHOTO -->
+  <div class="screen" id="updateCam2">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="step-indicator">Step 2 of 2</div>
+    <div class="hint" style="position:static;margin:12px 0;">Take the new photo</div>
+    <div class="viewfinder" style="position:relative;flex:1;"></div>
+    <div class="shutter-wrap" style="position:absolute;bottom:48px;left:0;right:0;">
+      <button class="shutter" onclick="showPhotoCheck('UPDATE_SAVE')" aria-label="Shoot new photo">📸</button>
+    </div>
+  </div>
+
+  <!-- GENERIC NO MATCH -->
+  <div class="screen" id="noMatch">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content center-flex">
+      <div class="big-emoji">🤔</div>
+      <h2 aria-live="polite">No match found</h2>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="noMatchTryAgain()">Try again</button>
+        <button class="btn btn-secondary" onclick="go('typeCode')">Type the code instead</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- GENERIC TYPE CODE -->
+  <div class="screen" id="typeCode">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <h3>Type the item's code</h3>
+      <div class="search-bar"><input type="text" id="codeInput" placeholder="e.g. DW-10423" aria-label="Type the item code"></div>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="codeSubmit()">Find It</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- FIND: MATCH -->
+  <div class="screen" id="findMatch">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <h2>Best Match</h2>
+      <div class="swatch"></div>
+      <div class="item-title">Palm Damask — Sage</div>
+      <div class="item-sub">code DW-10423 · York</div>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="finishFind()">Yes, that's right</button>
+        <button class="btn btn-secondary" onclick="showNoMatch('find')">Not this item</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: MATCH -->
+  <div class="screen" id="sampleMatch">
+    <div class="topbar">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="content">
+      <h2>Sample Matched</h2>
+      <div class="swatch"></div>
+      <div class="item-title">Palm Damask — Sage</div>
+      <div class="item-sub">code DW-10423 · York</div>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="markReceived()">Mark It Received</button>
+        <button class="btn btn-secondary" onclick="showNoMatch('sample')">Not this item</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: PRINTING -->
+  <div class="screen looking-wrap" id="samplePrinting">
+    <div class="topbar" style="position:absolute;top:0;left:0;right:0;">
+      <button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button>
+      <button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button>
+    </div>
+    <div class="spinner"></div>
+    <p aria-live="polite">Printing your sticker…</p>
+  </div>
+
+</div>
+
+<!-- TOAST (undo) -->
+<div class="toast" id="toast" role="status" aria-live="polite">
+  <span id="toastText">Saved</span>
+  <button onclick="undoAction()">Undo</button>
+</div>
+
+<script>
+  let historyStack = ['home'];
+  let selectedBrand = null;
+  let currentJob = null;
+  let demoNoMatch = false;
+  let photoCheckNext = null;
+  let noMatchJob = null;
+  let toastTimer = null;
+  let undoTarget = null;
+
+  function render(id){
+    document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
+    document.getElementById(id).classList.add('active');
+  }
+
+  function go(id){
+    historyStack.push(id);
+    render(id);
+    onEnter(id);
+  }
+
+  function goBack(){
+    if(historyStack.length > 1){
+      historyStack.pop();
+      render(historyStack[historyStack.length - 1]);
+    } else {
+      goHome();
+    }
+  }
+
+  function goHome(){
+    historyStack = ['home'];
+    render('home');
+  }
+
+  function onEnter(id){
+    if(id === 'addBrand'){
+      selectedBrand = null;
+      document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
+      document.getElementById('saveDraftBtn').disabled = true;
+      document.getElementById('brandSearch').value = '';
+      filterBrands();
+    }
+  }
+
+  function showPhotoCheck(nextId){
+    photoCheckNext = nextId;
+    go('photoCheck');
+  }
+
+  function photoLooksGood(){
+    // remove photoCheck from the history stack so Back skips it cleanly
+    historyStack.pop();
+    if(photoCheckNext === 'HOME_SHOT'){ afterHomeShot(); return; }
+    if(photoCheckNext === 'UPDATE_SAVE'){ updateSave(); return; }
+    go(photoCheckNext);
+  }
+
+  function chooseJob(job){
+    currentJob = job;
+    if(job === 'add'){ go('addBrand'); }
+    else if(job === 'update'){ demoNoMatch ? showNoMatch('update') : go('updateMatch'); }
+    else if(job === 'find'){ demoNoMatch ? showNoMatch('find') : go('findMatch'); }
+    else if(job === 'sample'){ demoNoMatch ? showNoMatch('sample') : go('sampleMatch'); }
+  }
+
+  function showNoMatch(job){
+    noMatchJob = job;
+    go('noMatch');
+  }
+
+  function noMatchTryAgain(){
+    // back out to the camera to reshoot
+    historyStack = ['home'];
+    render('home');
+  }
+
+  function codeSubmit(){
+    if(noMatchJob === 'update'){ go('updateCam2'); }
+    else if(noMatchJob === 'find'){ finishFind(); }
+    else if(noMatchJob === 'sample'){ markReceived(); }
+    else { goHome(); }
+  }
+
+  function selectBrand(el, name){
+    document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
+    el.classList.add('selected');
+    selectedBrand = name;
+    document.getElementById('saveDraftBtn').disabled = false;
+  }
+
+  function onBrandKey(evt, el, name){
+    if(evt.key === 'Enter' || evt.key === ' '){
+      evt.preventDefault();
+      selectBrand(el, name);
+    }
+  }
+
+  function filterBrands(){
+    const q = document.getElementById('brandSearch').value.trim().toLowerCase();
+    document.querySelectorAll('#allBrands .brand-tile').forEach(t=>{
+      t.classList.toggle('hidden', q.length > 0 && !t.textContent.toLowerCase().includes(q));
+    });
+  }
+
+  function randomCode(){ return 'DW-' + Math.floor(10000 + Math.random() * 89999); }
+
+  function showDone(opts){
+    document.getElementById('doneThumb').className = 'thumb' + (opts.blue ? ' blue' : '');
+    document.getElementById('doneTitle').textContent = opts.name;
+    document.getElementById('doneCode').textContent = opts.code;
+    document.getElementById('doneBrand').textContent = opts.brand;
+    document.getElementById('doneAction').textContent = opts.action;
+    historyStack = ['home', 'doneScreen'];
+    render('doneScreen');
+  }
+
+  function saveDraft(){
+    if(!selectedBrand) return;
+    showToast('Saved · Undo', 'addBrand');
+    showDone({name:'New Item', code: randomCode(), brand: selectedBrand, action:'Saved as a draft'});
+  }
+
+  function updateSave(){
+    showToast('Updated · Undo', 'updateMatch');
+    showDone({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Updated the photo', blue:true});
+  }
+
+  function finishFind(){
+    showDone({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Found it'});
+  }
+
+  function markReceived(){
+    go('samplePrinting');
+    var fromScreen = 'samplePrinting';
+    setTimeout(function(){
+      if(historyStack[historyStack.length - 1] !== fromScreen) return;
+      showToast('Saved · Undo', 'sampleMatch');
+      showDone({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Marked as received'});
+    }, 1100);
+  }
+
+  function showToast(text, backTarget){
+    document.getElementById('toastText').textContent = text;
+    undoTarget = backTarget;
+    const t = document.getElementById('toast');
+    t.classList.add('show');
+    clearTimeout(toastTimer);
+    toastTimer = setTimeout(function(){ t.classList.remove('show'); }, 5000);
+  }
+
+  function undoAction(){
+    document.getElementById('toast').classList.remove('show');
+    clearTimeout(toastTimer);
+    if(undoTarget){
+      historyStack = ['home', undoTarget];
+      render(undoTarget);
+      // NOTE: do NOT call onEnter() here — undo must restore the confirm
+      // screen with the prior selection intact, not reset it (onEnter('addBrand')
+      // clears selectedBrand for a fresh forward-navigation entry only).
+    }
+  }
+
+  document.getElementById('shutterBtn').addEventListener('click', function(){
+    showPhotoCheck('HOME_SHOT');
+  });
+
+  // after the very first shot on Home, go looking then ask what it's for
+  function afterHomeShot(){
+    historyStack.push('looking');
+    render('looking');
+    var fromScreen = 'looking';
+    setTimeout(function(){
+      if(historyStack[historyStack.length - 1] !== fromScreen) return;
+      historyStack.pop();
+      go('whatFor');
+    }, 700);
+  }
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v10-todays-inbox.html b/public/kid-simple/v10-todays-inbox.html
new file mode 100644
index 0000000..20f7c4a
--- /dev/null
+++ b/public/kid-simple/v10-todays-inbox.html
@@ -0,0 +1,396 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v10 — Today's Inbox</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,500;6..72,600;6..72,700&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#F3EEE4; --card:#FFFFFF; --ink:#24211C; --muted:#8A8171;
+    --brass:#A9772F; --brass-ink:#3A2A0E;
+    --terracotta:#B85C38; --terracotta-bg:#F3E1D6;
+    --teal:#4F7A73; --teal-bg:#DEEAE7;
+    --plum:#6B4E71; --plum-bg:#E9E0EB;
+    --green:#4C8C6B; --green-bg:#DCEEE3;
+    --line:#E7DFCF;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ccc;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--bg); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; padding:26px 22px 30px; overflow-y:auto; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+
+  /* ---- Home / Inbox ---- */
+  .inbox-header{ margin-bottom:18px; }
+  .inbox-eyebrow{ font-size:14px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); margin:0 0 2px; }
+  .inbox-title{ font-family:'Newsreader',serif; font-weight:600; font-size:34px; line-height:1.1; margin:0; color:var(--ink); }
+  .inbox-sub{ font-size:15px; color:var(--muted); margin:8px 0 0; }
+
+  .rowlist{ display:flex; flex-direction:column; gap:12px; margin-top:20px; }
+  .row{
+    display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
+    background:var(--card); border:1px solid var(--line); border-radius:20px; padding:12px 16px;
+    text-align:left; box-shadow:0 2px 6px rgba(36,33,28,.05);
+  }
+  .row:focus-visible, .bigbtn:focus-visible, .linktext:focus-visible, .fab:focus-visible, .brandrow:focus-visible{
+    outline:3px solid #2B6CB0; outline-offset:2px;
+  }
+  .badge{
+    flex:0 0 auto; width:52px; height:52px; border-radius:16px; display:flex; align-items:center;
+    justify-content:center; font-size:24px;
+  }
+  .badge.terracotta{ background:var(--terracotta-bg); }
+  .badge.teal{ background:var(--teal-bg); }
+  .badge.plum{ background:var(--plum-bg); }
+  .row-text{ flex:1; min-width:0; }
+  .row-title{ font-size:17px; font-weight:800; margin:0; color:var(--ink); }
+  .row-sub{ font-size:14px; color:var(--muted); margin:2px 0 0; }
+  .chev{ font-size:20px; color:var(--muted); flex:0 0 auto; }
+
+  .caughtup{
+    display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
+    background:var(--green-bg); border:1px solid transparent; border-radius:20px; padding:12px 16px;
+  }
+  .caughtup .badge{ background:#fff; }
+  .caughtup .row-title{ color:#2C5C42; }
+  .caughtup .row-sub{ color:#4C8C6B; }
+
+  .fab{
+    position:absolute; right:20px; bottom:26px; z-index:20;
+    width:68px; height:68px; border-radius:50%; background:var(--brass); border:4px solid #fff;
+    color:#fff; font-size:26px; display:flex; align-items:center; justify-content:center;
+    box-shadow:0 10px 22px rgba(169,119,47,.45);
+  }
+  .fab-label{
+    position:absolute; right:20px; bottom:98px; z-index:20; background:var(--ink); color:#fff;
+    font-size:12px; font-weight:700; padding:6px 10px; border-radius:10px; opacity:.88;
+  }
+
+  /* ---- Shared question / answer patterns ---- */
+  .topbar{ display:flex; align-items:center; gap:10px; margin-bottom:10px; min-height:56px; }
+  .backbtn{
+    background:none; border:none; color:var(--muted); font-size:15px; font-weight:700;
+    min-height:56px; padding:6px 4px; display:flex; align-items:center; gap:4px;
+  }
+  .question{
+    font-family:'Newsreader',serif; font-weight:600; font-size:28px; line-height:1.2;
+    margin:6px 0 20px; color:var(--ink);
+  }
+  .answers{ flex:1; display:flex; flex-direction:column; gap:14px; }
+  .bigbtn{
+    width:100%; min-height:64px; border-radius:18px; font-size:18px; font-weight:800;
+    background:#fff; border:2px solid var(--line); color:var(--ink); padding:12px 18px;
+  }
+  .bigbtn-primary{ background:var(--brass); border:2px solid var(--brass); color:#fff; }
+  .bigbtn-secondary{ background:#fff; border:2px solid var(--muted); color:var(--muted); }
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline;
+    text-align:center; min-height:56px; width:100%; font-weight:700;
+  }
+
+  /* ---- Queue lists (samples / photos) ---- */
+  .queuelist{ display:flex; flex-direction:column; gap:12px; }
+  .queuecard{
+    display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
+    background:#fff; border:1px solid var(--line); border-radius:20px; padding:12px 14px; text-align:left;
+  }
+  .swatch{ flex:0 0 auto; width:52px; height:52px; border-radius:14px; }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 10px,#6f8f6b 10px 20px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#B85C38 0 10px,#96482a 10px 20px);}
+  .sw3{background:radial-gradient(circle at 30% 30%, #A9772F 0 8px, #E9D9BD 9px 20px);}
+  .sw4{background:repeating-linear-gradient(90deg,#6B4E71 0 9px,#54394f 9px 18px);}
+  .sw5{background:radial-gradient(circle at 60% 40%, #4F7A73 0 9px, #DCEEE3 10px 22px);}
+  .qc-text{ flex:1; min-width:0; }
+  .qc-title{ font-size:16px; font-weight:800; margin:0; }
+  .qc-sub{ font-size:13px; color:var(--muted); margin:2px 0 0; }
+
+  .itemname{ font-size:21px; font-weight:800; margin:14px 0 0; text-align:center; }
+  .itemmeta{ font-size:15px; color:var(--muted); margin:4px 0 0; text-align:center; }
+  .swatch.big{ width:100%; height:170px; border-radius:20px; margin:0 auto; }
+
+  /* ---- Camera ---- */
+  .camwrap{ flex:1; display:flex; flex-direction:column; padding:0; margin:-26px -22px -30px; }
+  .camview{
+    flex:1; background:#1c1c1e; position:relative; display:flex; align-items:center; justify-content:center;
+    color:#fff; min-height:520px;
+  }
+  .camview .hint{
+    position:absolute; top:44px; left:20px; right:20px; text-align:center;
+    font-family:'Newsreader',serif; font-size:25px; font-weight:600; color:#fdfbf7;
+  }
+  .camview .status{ font-size:17px; font-weight:700; color:#e9dfca; }
+  .shutter{
+    position:absolute; bottom:34px; left:50%; transform:translateX(-50%);
+    width:88px; height:88px; border-radius:50%; background:var(--brass); border:6px solid #fff;
+    font-size:32px; display:flex; align-items:center; justify-content:center;
+  }
+  .camback{
+    position:absolute; top:16px; left:16px; z-index:5; min-width:56px; min-height:56px;
+    background:rgba(255,255,255,.16); border:none; border-radius:12px; color:#fff; font-size:14px; font-weight:700;
+  }
+
+  .center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:10px; }
+
+  /* ---- Brand list ---- */
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
+  .brandrow{
+    width:100%; min-height:60px; border-radius:16px; background:#fff; border:2px solid var(--line);
+    font-size:17px; font-weight:700; color:var(--ink); padding:10px 16px; text-align:left;
+  }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+
+let samplesWaiting = [
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw4'},
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Harbor Stripe', color:'Rust', code:'DW-71190', sw:'sw2'},
+];
+let photosNeeded = [
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+  {name:'Meadow Grid', color:'Moss', code:'DW-33982', sw:'sw5'},
+];
+const FIND_ITEMS = [
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw4'},
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+
+const state = { screen:'home', brand:null, newItemSw:'sw1', sampleIdx:0, photoIdx:0, findIdx:0, activeItem:null };
+
+function go(screen){ state.screen = screen; render(); }
+
+function cameraScreen(hint, onShoot, backTo){
+  return `<div class="camwrap"><div class="camview">
+    ${backTo ? `<button class="camback" onclick="go('${backTo}')">‹ Inbox</button>` : ''}
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    <button class="shutter" aria-label="Take photo" onclick="${onShoot}">📸</button>
+  </div></div>`;
+}
+function shoot(cb){
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(()=>{ cb(); }, 650);
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  let html = '';
+
+  // ---------------- HOME ----------------
+  if(state.screen==='home'){
+    const today = new Date();
+    const dateStr = today.toLocaleDateString(undefined,{weekday:'long', month:'long', day:'numeric'});
+    html += `<div class="inbox-header">
+        <p class="inbox-eyebrow">DW · Today's Inbox</p>
+        <h1 class="inbox-title">${dateStr}</h1>
+        <p class="inbox-sub">Here's what's waiting on you.</p>
+      </div>
+      <div class="rowlist">`;
+
+    if(samplesWaiting.length){
+      html += `<button class="row" onclick="go('sample-queue')">
+        <div class="badge terracotta">📦</div>
+        <div class="row-text">
+          <p class="row-title">${samplesWaiting.length} sample${samplesWaiting.length>1?'s':''} came in</p>
+          <p class="row-sub">Tap to check ${samplesWaiting.length>1?'them':'it'} in</p>
+        </div>
+        <div class="chev">›</div>
+      </button>`;
+    }
+    if(photosNeeded.length){
+      html += `<button class="row" onclick="go('update-queue')">
+        <div class="badge teal">🔄</div>
+        <div class="row-text">
+          <p class="row-title">${photosNeeded.length} item${photosNeeded.length>1?'s':''} need${photosNeeded.length>1?'':'s'} new photos</p>
+          <p class="row-sub">Tap to update ${photosNeeded.length>1?'them':'it'}</p>
+        </div>
+        <div class="chev">›</div>
+      </button>`;
+    }
+    if(!samplesWaiting.length && !photosNeeded.length){
+      html += `<div class="caughtup">
+        <div class="badge">🎉</div>
+        <div class="row-text">
+          <p class="row-title">All caught up!</p>
+          <p class="row-sub">Nothing waiting right now</p>
+        </div>
+      </div>`;
+    }
+    html += `<button class="row" onclick="state.findIdx=0; go('find-method')">
+        <div class="badge plum">🔍</div>
+        <div class="row-text">
+          <p class="row-title">Find an item</p>
+          <p class="row-sub">Scan, talk, or type</p>
+        </div>
+        <div class="chev">›</div>
+      </button>`;
+    html += `</div>`;
+    html += `<div class="fab-label">Add new</div>
+      <button class="fab" aria-label="Add a new item" onclick="go('new-cam')">📸</button>`;
+  }
+
+  // ---------------- ADD NEW ITEM (via FAB) ----------------
+  else if(state.screen==='new-cam'){
+    html += cameraScreen('Take a photo of it.', "shoot(()=>go('new-brand'))", 'home');
+  }
+  else if(state.screen==='new-brand'){
+    html += `<h1 class="question">Which brand is it?</h1><div class="brandlist">`;
+    BRANDS.forEach(b=>{ html += `<button class="brandrow" onclick="state.brand='${b}'; go('new-save')">${b}</button>`; });
+    html += `</div>`;
+  }
+  else if(state.screen==='new-save'){
+    html += `<h1 class="question">Save it?</h1>
+      <div class="swatch big ${state.newItemSw}"></div>
+      <p class="itemmeta">${state.brand}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="go('new-done')">Save as Draft</button>
+        <button class="linktext" onclick="go('new-cam')">Retake Photo</button>
+      </div>`;
+  }
+  else if(state.screen==='new-done'){
+    html += `<div class="center"><h1 class="question">Saved! 🎉</h1></div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="go('new-cam')">Add Another</button>
+        <button class="linktext" onclick="go('home')">Back to Inbox</button>
+      </div>`;
+  }
+
+  // ---------------- SAMPLE QUEUE (row 1) ----------------
+  else if(state.screen==='sample-queue'){
+    html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
+      <h1 class="question">Samples waiting (${samplesWaiting.length})</h1>
+      <div class="queuelist">`;
+    samplesWaiting.forEach((it,i)=>{
+      html += `<button class="queuecard" onclick="state.sampleIdx=${i}; go('sample-confirm')">
+        <div class="swatch ${it.sw}"></div>
+        <div class="qc-text"><p class="qc-title">${it.name} — ${it.color}</p><p class="qc-sub">code ${it.code}</p></div>
+        <div class="chev">›</div>
+      </button>`;
+    });
+    html += `</div>`;
+  }
+  else if(state.screen==='sample-confirm'){
+    const it = samplesWaiting[state.sampleIdx];
+    html += `<div class="topbar"><button class="backbtn" onclick="go('sample-queue')">‹ Back</button></div>
+      <h1 class="question">Mark it received?</h1>
+      <div class="swatch big ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="go('sample-printing')">Yes, Mark Received</button>
+      </div>`;
+  }
+  else if(state.screen==='sample-printing'){
+    html += `<div class="center"><h1 class="question">Printing your sticker…</h1><p class="itemmeta">🖨️ One sec…</p></div>`;
+    setTimeout(()=>{ if(state.screen==='sample-printing'){
+      samplesWaiting.splice(state.sampleIdx,1);
+      if(state.sampleIdx>=samplesWaiting.length) state.sampleIdx = 0;
+      go('sample-done');
+    } }, 1000);
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="center"><h1 class="question">Received! ✅</h1></div>
+      <div class="answers">
+        ${samplesWaiting.length ? `<button class="bigbtn bigbtn-primary" onclick="go('sample-queue')">Next Sample</button>` : ''}
+        <button class="linktext" onclick="go('home')">Back to Inbox</button>
+      </div>`;
+  }
+
+  // ---------------- UPDATE QUEUE (row 2) ----------------
+  else if(state.screen==='update-queue'){
+    html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
+      <h1 class="question">Items needing photos (${photosNeeded.length})</h1>
+      <div class="queuelist">`;
+    photosNeeded.forEach((it,i)=>{
+      html += `<button class="queuecard" onclick="state.photoIdx=${i}; go('update-cam')">
+        <div class="swatch ${it.sw}"></div>
+        <div class="qc-text"><p class="qc-title">${it.name} — ${it.color}</p><p class="qc-sub">code ${it.code}</p></div>
+        <div class="chev">›</div>
+      </button>`;
+    });
+    html += `</div>`;
+  }
+  else if(state.screen==='update-cam'){
+    const it = photosNeeded[state.photoIdx];
+    html += cameraScreen(`Take a new photo of ${it.name}.`, "shoot(()=>go('update-done'))", 'update-queue');
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="center"><h1 class="question">Updated! ✅</h1></div>`;
+    photosNeeded.splice(state.photoIdx,1);
+    if(state.photoIdx>=photosNeeded.length) state.photoIdx = 0;
+    html += `<div class="answers">
+        ${photosNeeded.length ? `<button class="bigbtn bigbtn-primary" onclick="go('update-queue')">Next Item</button>` : ''}
+        <button class="linktext" onclick="go('home')">Back to Inbox</button>
+      </div>`;
+  }
+
+  // ---------------- FIND AN ITEM (row 3) ----------------
+  else if(state.screen==='find-method'){
+    html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
+      <h1 class="question">How do you want to find it?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="go('find-result')">📷 Scan</button>
+        <button class="bigbtn" onclick="go('find-result')">🎤 Talk</button>
+        <button class="bigbtn" onclick="go('find-result')">⌨️ Type</button>
+      </div>`;
+  }
+  else if(state.screen==='find-result'){
+    const it = FIND_ITEMS[state.findIdx];
+    html += `<div class="topbar"><button class="backbtn" onclick="go('find-method')">‹ Back</button></div>
+      <h1 class="question">Which one is it?</h1>
+      <div class="swatch big ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
+      </div>`;
+  }
+  else if(state.screen==='find-detail'){
+    html += `<div class="center">
+        <h1 class="question" style="font-size:24px; margin-bottom:12px;">${state.activeItem.name}</h1>
+        <div class="swatch big ${state.activeItem.sw}" style="max-width:240px;"></div>
+        <p class="itemmeta">${state.activeItem.color} · code ${state.activeItem.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam-fromfind')">Update This</button>
+        <button class="bigbtn bigbtn-secondary" onclick="state.findIdx=0; go('find-method')">Search Again</button>
+        <button class="linktext" onclick="go('home')">Back to Inbox</button>
+      </div>`;
+  }
+  else if(state.screen==='update-cam-fromfind'){
+    html += cameraScreen(`Take the new photo of ${state.activeItem.name}.`, "shoot(()=>go('find-updated'))", 'find-detail');
+  }
+  else if(state.screen==='find-updated'){
+    html += `<div class="center"><h1 class="question">Updated! ✅</h1></div>
+      <button class="bigbtn bigbtn-primary" onclick="go('home')">Back to Inbox</button>`;
+  }
+
+  s.innerHTML = html;
+}
+function pickResult(){ state.activeItem = FIND_ITEMS[state.findIdx]; go('find-detail'); }
+function nextResult(){
+  if(state.findIdx < FIND_ITEMS.length-1){ state.findIdx++; go('find-result'); }
+  else { state.findIdx = 0; go('find-result'); }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v11-bottom-sheet.html b/public/kid-simple/v11-bottom-sheet.html
new file mode 100644
index 0000000..cf649b5
--- /dev/null
+++ b/public/kid-simple/v11-bottom-sheet.html
@@ -0,0 +1,397 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v11 — Bottom Sheet</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,500;6..72,600;6..72,700&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --cream:#FFF8ED; --ink:#241E17; --copper:#B5652D; --copper-ink:#3A200D;
+    --olive:#6B7660; --forest:#4F8B6B; --line:#EAE0CE; --muted:#8A8074;
+    --camdark:#15130F;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; height:780px; background:var(--camdark); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.32); position:relative; isolation:isolate;
+  }
+
+  /* ---------- camera backdrop (always full-bleed, hero) ---------- */
+  .camera-bg{
+    position:absolute; inset:0;
+    background:
+      radial-gradient(120% 90% at 50% 8%, #2a251d 0%, #15130f 55%, #0e0c09 100%);
+  }
+  .cam-grid{ position:absolute; inset:0; opacity:.16;
+    background-image:
+      linear-gradient(rgba(255,255,255,.5) 1px, transparent 1px),
+      linear-gradient(90deg, rgba(255,255,255,.5) 1px, transparent 1px);
+    background-size:33.33% 33.33%;
+  }
+  .cam-corner{ position:absolute; width:34px; height:34px; border-color:#F3E7CC; opacity:.85; }
+  .cam-corner.tl{ top:56px; left:20px; border-top:3px solid; border-left:3px solid; border-radius:6px 0 0 0;}
+  .cam-corner.tr{ top:56px; right:20px; border-top:3px solid; border-right:3px solid; border-radius:0 6px 0 0;}
+  .mark{
+    position:absolute; top:18px; left:20px; color:#F3E7CC; font-family:'Manrope',sans-serif;
+    font-weight:800; font-size:13px; letter-spacing:.14em; opacity:.92;
+  }
+  .live-pill{
+    position:absolute; top:18px; right:20px; display:flex; align-items:center; gap:6px;
+    background:rgba(0,0,0,.35); border:1px solid rgba(255,255,255,.25); border-radius:20px;
+    padding:5px 12px 5px 9px; color:#F3E7CC; font-size:12px; font-weight:700; letter-spacing:.06em;
+  }
+  .live-dot{ width:8px; height:8px; border-radius:50%; background:#E2543A; box-shadow:0 0 0 3px rgba(226,84,58,.28); }
+  .cam-hint{
+    position:absolute; left:24px; right:24px; top:110px; text-align:center;
+    font-family:'Newsreader',serif; font-weight:600; font-size:25px; line-height:1.28;
+    color:#FBF3E3; text-shadow:0 2px 14px rgba(0,0,0,.5);
+  }
+  .cam-status{
+    position:absolute; left:0; right:0; text-align:center; color:#D8CBB0; font-size:14px; font-weight:600;
+    letter-spacing:.03em;
+  }
+
+  /* shutter floats above the sheet, only present on "shoot" steps */
+  .shutter{
+    position:absolute; left:50%; transform:translateX(-50%);
+    width:78px; height:78px; border-radius:50%; background:var(--copper);
+    border:5px solid #FBF3E3; display:flex; align-items:center; justify-content:center;
+    font-size:28px; box-shadow:0 8px 22px rgba(0,0,0,.4); z-index:5;
+  }
+  .shutter:focus-visible{ outline:3px solid #2B6CB0; outline-offset:3px; }
+  .shutter[disabled]{ opacity:.55; }
+
+  /* ---------- bottom sheet ---------- */
+  .sheet{
+    position:absolute; left:0; right:0; bottom:0; z-index:10;
+    background:var(--cream); border-radius:26px 26px 0 0;
+    box-shadow:0 -12px 30px rgba(0,0,0,.28);
+    display:flex; flex-direction:column;
+    transition:height .32s cubic-bezier(.22,.9,.32,1);
+    height:340px; touch-action:none;
+  }
+  .sheet.full{ height:640px; }
+  .handle-wrap{
+    display:flex; flex-direction:column; align-items:center; padding:10px 0 4px; cursor:grab; flex:0 0 auto;
+  }
+  .handle-bar{ width:44px; height:5px; border-radius:4px; background:#DDD1B8; }
+  .sheet-body{ flex:1; min-height:0; overflow-y:auto; padding:6px 24px 26px; }
+
+  .home-fab{
+    position:absolute; top:14px; left:14px; z-index:20; min-width:56px; min-height:56px;
+    border-radius:16px; background:rgba(20,17,12,.55); border:1px solid rgba(255,255,255,.25); color:#FBF3E3;
+    font-size:14px; font-weight:700; display:none; align-items:center; justify-content:center; gap:4px;
+    padding:0 12px; backdrop-filter: blur(2px);
+  }
+  .home-fab:focus-visible{ outline:3px solid #7EC0E8; outline-offset:2px; }
+
+  h1.q{
+    font-family:'Newsreader',serif; font-weight:600; font-size:26px; line-height:1.2;
+    margin:8px 0 18px; color:var(--ink); text-align:left;
+  }
+  h1.q.center{ text-align:center; }
+  .sub{ font-size:14px; color:var(--muted); margin:-12px 0 16px; font-weight:600; }
+
+  .rows{ display:flex; flex-direction:column; gap:12px; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+
+  .row-btn{
+    width:100%; min-height:64px; border-radius:18px; border:2px solid var(--line); background:#fff;
+    display:flex; align-items:center; gap:14px; padding:10px 16px; text-align:left;
+    font-size:17px; font-weight:700; color:var(--ink);
+  }
+  .row-btn .ic{ font-size:26px; width:36px; text-align:center; flex:0 0 auto; }
+  .row-btn:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+
+  .bigbtn{
+    width:100%; min-height:60px; border-radius:16px; font-size:17px; font-weight:800;
+    background:#fff; border:2px solid var(--line); color:var(--ink); padding:10px 16px;
+  }
+  .bigbtn.primary{ background:var(--copper); border-color:var(--copper); color:#FFF6E9; }
+  .bigbtn.secondary{ background:#fff; border-color:var(--olive); color:var(--olive); }
+  .bigbtn:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:15px; text-decoration:underline;
+    text-align:center; min-height:56px; width:100%; font-weight:600;
+  }
+
+  .brandlist{ display:flex; flex-direction:column; gap:10px; }
+  .brandlist .row-btn{ font-size:16px; min-height:58px; }
+
+  .swatch{ width:100%; height:150px; border-radius:16px; margin-bottom:12px; }
+  .swatch.sm{ width:120px; height:120px; margin:0 auto 14px; }
+  .sw1{background:repeating-linear-gradient(45deg,#B5652D 0 18px,#96501f 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#6B7660 0 16px,#565f4d 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A96A 0 14px,#c48f4a 14px 28px);}
+  .itemname{ font-size:19px; font-weight:800; margin:0; text-align:center; }
+  .itemmeta{ font-size:14px; color:var(--muted); margin:4px 0 0; text-align:center; font-weight:600; }
+
+  .center-wrap{ display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:160px; gap:6px; }
+  .done-emoji{ font-size:44px; }
+</style>
+</head>
+<body>
+<div class="phone" id="phone">
+  <div class="camera-bg">
+    <div class="cam-grid"></div>
+    <div class="mark">DW · CAPTURE</div>
+    <div class="live-pill"><span class="live-dot"></span>LIVE</div>
+    <div class="cam-corner tl"></div>
+    <div class="cam-corner tr"></div>
+    <div class="cam-hint" id="camHint"></div>
+    <div class="cam-status" id="camStatus" style="bottom:378px;"></div>
+    <button class="shutter" id="shutterBtn" style="bottom:364px;" aria-label="Take photo" onclick="handleShoot()">📸</button>
+  </div>
+
+  <button class="home-fab" id="homeFab" aria-label="Home" onclick="go('home')">⌂ Home</button>
+
+  <div class="sheet" id="sheet">
+    <div class="handle-wrap" id="handleWrap">
+      <div class="handle-bar"></div>
+    </div>
+    <div class="sheet-body" id="sheetBody" role="main"></div>
+  </div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+
+const state = { screen:'home', job:null, item:null, brand:null, resultIndex:0 };
+
+// screen -> {sheet: 'peek'|'full', cam:{hint,status,shutter:bool}}
+function meta(screen){
+  const M = {
+    'home':        {sheet:'peek', cam:{hint:'', status:'', shutter:false}},
+    'new-cam':     {sheet:'peek', cam:{hint:'Take a photo of it', status:'Tap the shutter', shutter:true}},
+    'new-brand':   {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'new-review':  {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'new-done':    {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'update-cam':  {sheet:'peek', cam:{hint:'Scan the label or pattern', status:'Tap the shutter', shutter:true}},
+    'update-match':{sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'update-cam2': {sheet:'peek', cam:{hint:'Take the new photo', status:'Tap the shutter', shutter:true}},
+    'update-done': {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'find-method': {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'find-result': {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'find-exhausted':{sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'find-detail': {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'sample-cam':  {sheet:'peek', cam:{hint:'Scan the box label', status:'Tap the shutter', shutter:true}},
+    'sample-match':{sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'sample-printing':{sheet:'full', cam:{hint:'', status:'', shutter:false}},
+    'sample-done': {sheet:'full', cam:{hint:'', status:'', shutter:false}},
+  };
+  return M[screen];
+}
+
+function go(screen){ state.screen = screen; render(); }
+function startJob(job){
+  state.job = job; state.item=null; state.brand=null; state.resultIndex=0;
+  const map = {new:'new-cam', update:'update-cam', find:'find-method', sample:'sample-cam'};
+  go(map[job]);
+}
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+
+let shootTarget = null;
+function armShoot(nextScreen){ shootTarget = nextScreen; }
+function handleShoot(){
+  if(!shootTarget) return;
+  const btn = document.getElementById('shutterBtn');
+  const st = document.getElementById('camStatus');
+  btn.disabled = true;
+  st.textContent = 'Snapping…';
+  const dest = shootTarget;
+  setTimeout(()=>{ state.item = randomItem(); go(dest); }, 650);
+}
+
+function bodyHTML(){
+  const s = state.screen;
+
+  if(s==='home'){
+    return `<h1 class="q">What are we doing?</h1>
+      <p class="sub">Pick one to get started</p>
+      <div class="rows">
+        <button class="row-btn" onclick="startJob('new')"><span class="ic">🆕</span>Add New Item</button>
+        <button class="row-btn" onclick="startJob('update')"><span class="ic">🔄</span>Update an Item</button>
+        <button class="row-btn" onclick="startJob('find')"><span class="ic">🔍</span>Find an Item</button>
+        <button class="row-btn" onclick="startJob('sample')"><span class="ic">📦</span>A Sample Came In</button>
+      </div>`;
+  }
+
+  if(s==='new-cam' || s==='update-cam' || s==='update-cam2' || s==='sample-cam'){
+    return `<p class="sub" style="margin-top:8px;">Point the camera above, then tap the shutter</p>`;
+  }
+
+  if(s==='new-brand'){
+    return `<h1 class="q">Which brand is it?</h1><div class="brandlist">` +
+      BRANDS.map(b=>`<button class="row-btn" onclick="state.brand='${b}'; go('new-review')">${b}</button>`).join('') +
+      `</div>`;
+  }
+  if(s==='new-review'){
+    return `<h1 class="q center">Save it?</h1>
+      <div class="swatch sm ${state.item.sw}"></div>
+      <p class="itemmeta" style="margin-bottom:18px;">${state.brand} · code ${state.item.code}</p>
+      <div class="rows">
+        <button class="bigbtn primary" onclick="go('new-done')">Save as Draft</button>
+        <button class="linktext" onclick="go('new-cam')">Retake Photo</button>
+      </div>`;
+  }
+  if(s==='new-done'){
+    return `<div class="center-wrap"><div class="done-emoji">🎉</div><h1 class="q center">Saved!</h1></div>
+      <div class="rows">
+        <button class="bigbtn primary" onclick="startJob('new')">Add Another</button>
+        <button class="linktext" onclick="go('home')">Back Home</button>
+      </div>`;
+  }
+
+  if(s==='update-match'){
+    return `<h1 class="q center">Is this it?</h1>
+      <div class="swatch sm ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta" style="margin-bottom:16px;">code ${state.item.code}</p>
+      <div class="rows">
+        <button class="bigbtn primary" onclick="go('update-cam2')">Yes</button>
+        <button class="bigbtn secondary" onclick="go('update-cam')">No, Let Me Search</button>
+      </div>`;
+  }
+  if(s==='update-done'){
+    return `<div class="center-wrap"><div class="done-emoji">✅</div><h1 class="q center">Updated!</h1></div>
+      <div class="rows"><button class="bigbtn primary" onclick="go('home')">Back Home</button></div>`;
+  }
+
+  if(s==='find-method'){
+    return `<h1 class="q">How do you want to find it?</h1>
+      <div class="rows">
+        <button class="row-btn" onclick="go('find-result')"><span class="ic">📷</span>Scan the Label</button>
+        <button class="row-btn" onclick="go('find-result')"><span class="ic">🎤</span>Say the Name</button>
+        <button class="row-btn" onclick="go('find-result')"><span class="ic">⌨️</span>Type It</button>
+      </div>`;
+  }
+  if(s==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    return `<h1 class="q center">Which one is it?</h1>
+      <div class="swatch sm ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta" style="margin-bottom:16px;">code ${it.code}</p>
+      <div class="rows">
+        <button class="bigbtn primary" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn secondary" onclick="nextResult()">Next Result</button>
+      </div>`;
+  }
+  if(s==='find-exhausted'){
+    return `<h1 class="q">That's all — try another way?</h1>
+      <div class="rows">
+        <button class="row-btn" onclick="state.resultIndex=0; go('find-result')"><span class="ic">📷</span>Scan the Label</button>
+        <button class="row-btn" onclick="state.resultIndex=0; go('find-result')"><span class="ic">🎤</span>Say the Name</button>
+        <button class="row-btn" onclick="state.resultIndex=0; go('find-result')"><span class="ic">⌨️</span>Type It</button>
+      </div>`;
+  }
+  if(s==='find-detail'){
+    return `<div class="center-wrap">
+        <h1 class="q center" style="font-size:22px; margin-bottom:12px;">${state.item.name}</h1>
+        <div class="swatch sm ${state.item.sw}"></div>
+        <p class="itemmeta" style="margin-bottom:16px;">${state.item.color} · code ${state.item.code}</p>
+      </div>
+      <div class="rows">
+        <button class="bigbtn primary" onclick="go('update-cam2')">Update This</button>
+        <button class="bigbtn secondary" onclick="go('find-method')">Search Again</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  if(s==='sample-match'){
+    return `<h1 class="q center">Mark it received?</h1>
+      <div class="swatch sm ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta" style="margin-bottom:16px;">code ${state.item.code}</p>
+      <div class="rows"><button class="bigbtn primary" onclick="go('sample-printing')">Yes, Mark Received</button></div>`;
+  }
+  if(s==='sample-printing'){
+    setTimeout(()=>{ if(state.screen==='sample-printing') go('sample-done'); }, 1000);
+    return `<div class="center-wrap"><div class="done-emoji">🖨️</div><h1 class="q center">Printing your sticker…</h1></div>`;
+  }
+  if(s==='sample-done'){
+    return `<div class="center-wrap"><div class="done-emoji">✅</div><h1 class="q center">Done!</h1></div>
+      <div class="rows"><button class="bigbtn primary" onclick="go('home')">Back Home</button></div>`;
+  }
+  return '';
+}
+
+function render(){
+  const m = meta(state.screen);
+  const sheet = document.getElementById('sheet');
+  const fab = document.getElementById('homeFab');
+  const camHint = document.getElementById('camHint');
+  const camStatus = document.getElementById('camStatus');
+  const shutterBtn = document.getElementById('shutterBtn');
+
+  sheet.classList.toggle('full', m.sheet === 'full');
+  fab.style.display = state.screen === 'home' ? 'none' : 'flex';
+
+  camHint.textContent = m.cam.hint;
+  camStatus.textContent = m.cam.status;
+  if(m.cam.shutter){
+    shutterBtn.style.display = 'flex';
+    shutterBtn.disabled = false;
+    const nextMap = {'new-cam':'new-brand', 'update-cam':'update-match', 'update-cam2':'update-done', 'sample-cam':'sample-match'};
+    armShoot(nextMap[state.screen]);
+  } else {
+    shutterBtn.style.display = 'none';
+    shootTarget = null;
+  }
+
+  document.getElementById('sheetBody').innerHTML = bodyHTML();
+}
+
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-detail'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; go('find-result'); }
+  else { go('find-exhausted'); }
+}
+
+/* ---- draggable handle: free-drag between peek(340) and full(640), snaps on release ---- */
+(function(){
+  const sheet = document.getElementById('sheet');
+  const handle = document.getElementById('handleWrap');
+  const PEEK = 340, FULL = 640;
+  let dragging = false, startY = 0, startH = PEEK;
+
+  function clamp(v){ return Math.max(PEEK-40, Math.min(FULL+20, v)); }
+
+  handle.addEventListener('pointerdown', (e)=>{
+    dragging = true;
+    startY = e.clientY;
+    startH = sheet.getBoundingClientRect().height;
+    sheet.style.transition = 'none';
+    handle.setPointerCapture(e.pointerId);
+  });
+  handle.addEventListener('pointermove', (e)=>{
+    if(!dragging) return;
+    const dy = startY - e.clientY;
+    sheet.style.height = clamp(startH + dy) + 'px';
+  });
+  function endDrag(){
+    if(!dragging) return;
+    dragging = false;
+    sheet.style.transition = '';
+    const h = sheet.getBoundingClientRect().height;
+    const snapFull = h > (PEEK+FULL)/2;
+    sheet.style.height = '';
+    sheet.classList.toggle('full', snapFull);
+  }
+  handle.addEventListener('pointerup', endDrag);
+  handle.addEventListener('pointercancel', endDrag);
+})();
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v12-hold-to-talk.html b/public/kid-simple/v12-hold-to-talk.html
new file mode 100644
index 0000000..58565a2
--- /dev/null
+++ b/public/kid-simple/v12-hold-to-talk.html
@@ -0,0 +1,411 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v12 — Hold-to-Talk</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#F7EFE4; --ink:#2A2118; --panel:#FFFFFF; --line:#E7DCC9;
+    --accent:#B5502E; --accent-dark:#8C3A1F; --teal:#2F5D57; --teal-dark:#20403C;
+    --amber:#CE8B3C; --success:#4F8F6D; --cam:#181F1D; --muted:#8A7F6E;
+  }
+  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; height:780px; background:var(--bg); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+    user-select:none;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; overflow-y:auto; position:relative; }
+  h1,h2{ font-family:'Cormorant Garamond', serif; margin:0; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+
+  /* ---- Home ---- */
+  .homeWrap{ flex:1; display:flex; flex-direction:column; background:var(--cam); color:#F7EFE4; position:relative; }
+  .homeWrap .grain{
+    position:absolute; inset:0;
+    background:
+      radial-gradient(circle at 20% 15%, rgba(47,93,87,.55), transparent 55%),
+      radial-gradient(circle at 85% 80%, rgba(181,80,46,.35), transparent 55%);
+  }
+  .dwmark{ position:relative; z-index:2; padding:22px 24px 0; font-size:12px; letter-spacing:.22em; text-transform:uppercase; color:#CBB79A; font-weight:700; }
+  .captionWrap{ position:relative; z-index:2; padding:18px 22px 0; flex:0 0 auto; }
+  .captionPill{
+    background:rgba(255,255,255,.06); border:1px solid rgba(247,239,228,.18); border-radius:20px;
+    padding:16px 18px; min-height:64px; display:flex; align-items:center; gap:12px; backdrop-filter:blur(2px);
+  }
+  .captionDot{ width:10px; height:10px; border-radius:50%; background:var(--muted); flex:0 0 auto; transition:background .2s; }
+  .captionDot.live{ background:var(--accent); box-shadow:0 0 0 0 rgba(181,80,46,.6); animation:pulseDot 1s infinite; }
+  @keyframes pulseDot{ 0%{box-shadow:0 0 0 0 rgba(181,80,46,.55);} 70%{box-shadow:0 0 0 9px rgba(181,80,46,0);} 100%{box-shadow:0 0 0 0 rgba(181,80,46,0);} }
+  .captionText{ font-size:17px; font-weight:600; line-height:1.35; color:#F7EFE4; }
+  .captionText.idle{ color:#CBB79A; font-weight:500; font-size:16px; }
+
+  .holdArea{ position:relative; z-index:2; flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:18px; padding:10px 24px; }
+  .holdHint{ font-family:'Cormorant Garamond',serif; font-size:26px; font-weight:600; text-align:center; color:#F7EFE4; margin:0 0 4px; }
+  .holdSub{ font-size:14px; color:#CBB79A; text-align:center; margin-top:-10px; }
+  .micBtnWrap{ position:relative; width:168px; height:168px; display:flex; align-items:center; justify-content:center; }
+  .ring{ position:absolute; inset:0; border-radius:50%; border:2px solid rgba(181,80,46,.0); transition:all .25s; }
+  .micBtnWrap.listening .ring{ border-color:rgba(181,80,46,.55); animation:ringGrow 1.1s ease-out infinite; }
+  @keyframes ringGrow{ 0%{ transform:scale(.82); opacity:.9;} 100%{ transform:scale(1.28); opacity:0;} }
+  .micBtn{
+    width:132px; height:132px; border-radius:50%; background:var(--accent); border:6px solid #F7EFE4;
+    display:flex; align-items:center; justify-content:center; font-size:52px; color:#fff;
+    box-shadow:0 10px 26px rgba(0,0,0,.4); transition:transform .12s, background .2s;
+  }
+  .micBtnWrap.listening .micBtn{ background:var(--accent-dark); transform:scale(1.06); }
+  .micBtn:focus-visible{ outline:3px solid #F2C879; outline-offset:4px; }
+
+  .fallbackWrap{ position:relative; z-index:2; padding:10px 20px 22px; }
+  .fallbackLabel{ text-align:center; font-size:13px; color:#8F8272; margin:0 0 10px; letter-spacing:.04em; }
+  .chipGrid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
+  .chip{
+    min-height:58px; border-radius:16px; background:rgba(255,255,255,.07); border:1.5px solid rgba(247,239,228,.22);
+    color:#F7EFE4; font-size:14.5px; font-weight:700; padding:8px 10px; text-align:center; line-height:1.25;
+  }
+  .chip:active{ background:rgba(255,255,255,.16); }
+
+  /* ---- generic content screens ---- */
+  .pad{ flex:1; display:flex; flex-direction:column; padding:30px 24px 26px; background:var(--bg); }
+  .kicker{ font-size:12.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--teal); margin:0 0 8px; }
+  .question{ font-family:'Cormorant Garamond',serif; font-weight:600; font-size:30px; line-height:1.2; margin:0 0 22px; color:var(--ink); }
+
+  .bigbtn{
+    width:100%; min-height:60px; border-radius:16px; font-size:18px; font-weight:700;
+    background:var(--panel); border:2px solid var(--line); color:var(--ink); padding:12px 18px; margin-bottom:12px;
+  }
+  .bigbtn-primary{ background:var(--accent); border:2px solid var(--accent); color:#fff; }
+  .bigbtn-secondary{ background:#fff; border:2px solid var(--muted); color:var(--muted); }
+  .bigbtn:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline;
+    text-align:center; min-height:48px; width:100%;
+  }
+
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
+  .brandcard{
+    width:100%; min-height:64px; border-radius:16px; background:#fff; border:2px solid var(--line);
+    display:flex; align-items:center; gap:14px; padding:10px 14px; font-size:18px; font-weight:700; color:var(--ink);
+  }
+  .swatch{ width:44px; height:44px; border-radius:12px; flex:0 0 auto; }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 9px,#6f9169 9px 18px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 8px,#5d7897 8px 16px);}
+  .sw3{background:repeating-linear-gradient(90deg,#CE8B3C 0 7px,#b0722a 7px 14px);}
+  .sw4{background:repeating-linear-gradient(135deg,#B5502E 0 8px,#8c3a1f 8px 16px);}
+
+  .itemcard{ background:#fff; border:2px solid var(--line); border-radius:20px; padding:20px; display:flex; flex-direction:column; align-items:center; gap:10px; margin-bottom:20px; }
+  .itemcard .swatch.big{ width:100%; height:150px; border-radius:16px; }
+  .itemname{ font-size:21px; font-weight:800; margin:2px 0 0; text-align:center; }
+  .itemmeta{ font-size:15px; color:var(--muted); margin:0; text-align:center; }
+
+  /* camera screens */
+  .camwrap{ flex:1; display:flex; flex-direction:column; position:relative; background:var(--cam); }
+  .camview{ flex:1; position:relative; display:flex; align-items:center; justify-content:center; color:#fff; }
+  .camview .hint{
+    position:absolute; top:44px; left:20px; right:20px; text-align:center;
+    font-family:'Cormorant Garamond',serif; font-size:27px; font-weight:600; color:#F7EFE4;
+  }
+  .camview .flashmsg{ font-size:16px; font-weight:600; color:#CBB79A; }
+  .shutter{
+    position:absolute; bottom:36px; left:50%; transform:translateX(-50%);
+    width:88px; height:88px; border-radius:50%; background:var(--accent); border:6px solid #fff;
+    font-size:32px; display:flex; align-items:center; justify-content:center; color:#fff;
+  }
+  .shutter:focus-visible{ outline:3px solid #F2C879; outline-offset:4px; }
+
+  .doneWrap{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px; padding:30px; background:var(--bg); text-align:center; }
+  .doneBadge{ width:96px; height:96px; border-radius:50%; background:var(--success); display:flex; align-items:center; justify-content:center; font-size:44px; color:#fff; }
+  .doneTitle{ font-family:'Cormorant Garamond',serif; font-size:30px; font-weight:700; margin:0; }
+
+  .homefab{
+    position:absolute; top:16px; left:16px; z-index:30; min-width:56px; min-height:56px;
+    border-radius:16px; background:rgba(255,255,255,.94); border:2px solid var(--line); color:var(--ink);
+    font-size:14px; font-weight:700; display:none; align-items:center; justify-content:center; gap:4px;
+    padding:0 12px; box-shadow:0 4px 10px rgba(0,0,0,.16);
+  }
+  .homefab.onDark{ background:rgba(0,0,0,.4); border-color:rgba(255,255,255,.3); color:#fff; }
+  .homefab:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .btnrow{ display:flex; gap:10px; width:100%; }
+  .btnrow .bigbtn{ flex:1; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <button class="homefab" id="homeFab" aria-label="Home" onclick="go('home')">⌂ Home</button>
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const BRANDS = [
+  {name:'Thibaut', sw:'sw1'},
+  {name:'Kravet', sw:'sw2'},
+  {name:'Cole & Son', sw:'sw3'},
+  {name:'Groundworks', sw:'sw4'},
+];
+const MATCH_ITEM = {name:'Palm Damask', color:'Sage', code:'item 10423', sw:'sw1'};
+const RESULTS = [
+  {name:'Palm Damask', color:'Sage', code:'item 10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'item 88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'item 55071', sw:'sw3'},
+];
+
+const PHRASES = [
+  { steps:['Mm...', 'I have a...', 'I have a new...', '"Add a new item"'], go:'addCam' },
+  { steps:['Hmm...', 'I need to...', 'I need to update...', '"Update an item"'], go:'updScan' },
+  { steps:['Umm...', 'Where is...', 'Where is that...', '"Find an item"'], go:'findMethod' },
+  { steps:['So...', 'A box just...', 'A box just came...', '"A sample came in"'], go:'sampScan' },
+];
+let phraseIdx = 0;
+let holding = false, capStep = 0, capTimer = null, finishTimer = null;
+
+function esc(s){ return s; }
+
+const screen = document.getElementById('screen');
+const homeFab = document.getElementById('homeFab');
+
+function go(name, data){
+  clearHold();
+  homeFab.style.display = (name === 'home') ? 'none' : 'flex';
+  const dark = ['addCam','updScan','updCam2','sampScan'].includes(name);
+  homeFab.classList.toggle('onDark', dark);
+  screen.innerHTML = RENDER[name](data || {});
+  screen.scrollTop = 0;
+}
+
+function clearHold(){
+  holding = false; capStep = 0;
+  if(capTimer){ clearInterval(capTimer); capTimer = null; }
+  if(finishTimer){ clearTimeout(finishTimer); finishTimer = null; }
+}
+
+function startHold(){
+  if(holding) return;
+  holding = true; capStep = 0;
+  const wrap = document.getElementById('micWrap');
+  const dot = document.getElementById('capDot');
+  const txt = document.getElementById('capText');
+  if(wrap) wrap.classList.add('listening');
+  if(dot) dot.classList.add('live');
+  const phrase = PHRASES[phraseIdx];
+  txt.textContent = phrase.steps[0];
+  txt.classList.remove('idle');
+  capTimer = setInterval(()=>{
+    capStep++;
+    if(capStep >= phrase.steps.length){
+      clearInterval(capTimer); capTimer = null;
+      finishTimer = setTimeout(()=>{
+        const nextRoute = phrase.go;
+        phraseIdx = (phraseIdx + 1) % PHRASES.length;
+        clearHold();
+        go(nextRoute);
+      }, 480);
+      return;
+    }
+    txt.textContent = phrase.steps[capStep];
+  }, 380);
+}
+
+function endHold(){
+  if(!holding) return;
+  const finishedFully = capTimer === null && finishTimer !== null;
+  if(finishedFully){ return; } // let the auto-navigate finish
+  clearHold();
+  const wrap = document.getElementById('micWrap');
+  const dot = document.getElementById('capDot');
+  const txt = document.getElementById('capText');
+  if(wrap) wrap.classList.remove('listening');
+  if(dot) dot.classList.remove('live');
+  if(txt){
+    txt.textContent = "Didn't quite catch that — try again, or tap a job below";
+    txt.classList.remove('idle');
+    setTimeout(()=>{
+      if(document.getElementById('capText') === txt){
+        txt.textContent = 'Hold the button & tell me what you need';
+        txt.classList.add('idle');
+      }
+    }, 1700);
+  }
+}
+
+const RENDER = {
+  home: () => `
+    <div class="homeWrap">
+      <div class="grain"></div>
+      <div class="dwmark">Designer Wallcoverings</div>
+      <div class="captionWrap">
+        <div class="captionPill">
+          <div class="captionDot" id="capDot"></div>
+          <div class="captionText idle" id="capText">Hold the button & tell me what you need</div>
+        </div>
+      </div>
+      <div class="holdArea">
+        <p class="holdHint">Press &amp; hold, then say it</p>
+        <div class="micBtnWrap" id="micWrap">
+          <div class="ring"></div>
+          <button class="micBtn" id="micBtn" aria-label="Hold and talk"
+            onpointerdown="startHold()" onpointerup="endHold()" onpointerleave="endHold()" onpointercancel="endHold()">🎙️</button>
+        </div>
+        <p class="holdSub">"new item" · "update" · "find" · "sample came in"</p>
+      </div>
+      <div class="fallbackWrap">
+        <p class="fallbackLabel">OR TAP INSTEAD</p>
+        <div class="chipGrid">
+          <button class="chip" onclick="go('addCam')">Add a New Item</button>
+          <button class="chip" onclick="go('updScan')">Update an Item</button>
+          <button class="chip" onclick="go('findMethod')">Find an Item</button>
+          <button class="chip" onclick="go('sampScan')">A Sample Came In</button>
+        </div>
+      </div>
+    </div>
+  `,
+
+  addCam: () => `
+    <div class="camwrap">
+      <div class="camview">
+        <div class="hint">Take a photo of it.</div>
+        <div class="flashmsg">Point the camera at the sample</div>
+        <button class="shutter" aria-label="Shoot photo" onclick="go('addBrand')">📸</button>
+      </div>
+    </div>
+  `,
+  addBrand: () => `
+    <div class="pad">
+      <p class="kicker">Add a new item</p>
+      <h2 class="question">Which brand is it?</h2>
+      <div class="brandlist">
+        ${BRANDS.map(b => `<button class="brandcard" onclick="go('addSave')"><span class="swatch ${b.sw}"></span>${b.name}</button>`).join('')}
+      </div>
+    </div>
+  `,
+  addSave: () => `
+    <div class="pad">
+      <p class="kicker">Add a new item</p>
+      <h2 class="question">Save it?</h2>
+      <div class="itemcard">
+        <div class="swatch big sw1"></div>
+        <p class="itemname">New Sample</p>
+        <p class="itemmeta">Thibaut · Draft</p>
+      </div>
+      <button class="bigbtn bigbtn-primary" onclick="go('addDone')">Save as Draft</button>
+      <button class="linktext" onclick="go('addCam')">Retake Photo</button>
+    </div>
+  `,
+  addDone: () => `
+    <div class="doneWrap">
+      <div class="doneBadge">🎉</div>
+      <h2 class="doneTitle">Saved!</h2>
+      <div class="btnrow">
+        <button class="bigbtn bigbtn-secondary" onclick="go('addCam')">Add Another</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('home')">Home</button>
+      </div>
+    </div>
+  `,
+
+  updScan: () => `
+    <div class="camwrap">
+      <div class="camview">
+        <div class="hint">Show me the label or pattern.</div>
+        <div class="flashmsg">Scan it in the frame</div>
+        <button class="shutter" aria-label="Shoot photo" onclick="go('updMatch')">📸</button>
+      </div>
+    </div>
+  `,
+  updMatch: () => `
+    <div class="pad">
+      <p class="kicker">Update an item</p>
+      <h2 class="question">Found it — is this the one?</h2>
+      <div class="itemcard">
+        <div class="swatch big ${MATCH_ITEM.sw}"></div>
+        <p class="itemname">${MATCH_ITEM.name}</p>
+        <p class="itemmeta">${MATCH_ITEM.color} · ${MATCH_ITEM.code}</p>
+      </div>
+      <button class="bigbtn bigbtn-primary" onclick="go('updCam2')">Yes</button>
+      <button class="bigbtn bigbtn-secondary" onclick="go('findMethod')">No, Let Me Search</button>
+    </div>
+  `,
+  updCam2: () => `
+    <div class="camwrap">
+      <div class="camview">
+        <div class="hint">Take the new photo.</div>
+        <div class="flashmsg">This replaces the old one</div>
+        <button class="shutter" aria-label="Shoot photo" onclick="go('updDone')">📸</button>
+      </div>
+    </div>
+  `,
+  updDone: () => `
+    <div class="doneWrap">
+      <div class="doneBadge">✅</div>
+      <h2 class="doneTitle">Updated!</h2>
+      <button class="bigbtn bigbtn-primary" onclick="go('home')">Home</button>
+    </div>
+  `,
+
+  findMethod: () => `
+    <div class="pad">
+      <p class="kicker">Find an item</p>
+      <h2 class="question">How do you want to find it?</h2>
+      <button class="bigbtn" onclick="go('findResults')">📷 Scan the Label</button>
+      <button class="bigbtn" onclick="go('findResults')">🎤 Say the Name</button>
+      <button class="bigbtn" onclick="go('findResults')">⌨️ Type It</button>
+    </div>
+  `,
+  findResults: () => `
+    <div class="pad">
+      <p class="kicker">Find an item</p>
+      <h2 class="question">Which one is it?</h2>
+      <div class="brandlist">
+        ${RESULTS.map(r => `<button class="brandcard" onclick="go('findDetail')"><span class="swatch ${r.sw}"></span>${r.name}</button>`).join('')}
+      </div>
+    </div>
+  `,
+  findDetail: () => `
+    <div class="pad">
+      <p class="kicker">Find an item</p>
+      <div class="itemcard">
+        <div class="swatch big ${MATCH_ITEM.sw}"></div>
+        <p class="itemname">${MATCH_ITEM.name}</p>
+        <p class="itemmeta">${MATCH_ITEM.color} · ${MATCH_ITEM.code}</p>
+      </div>
+      <button class="bigbtn bigbtn-primary" onclick="go('updCam2')">Update This</button>
+      <button class="bigbtn bigbtn-secondary" onclick="go('findMethod')">Search Again</button>
+    </div>
+  `,
+
+  sampScan: () => `
+    <div class="camwrap">
+      <div class="camview">
+        <div class="hint">Scan the box label.</div>
+        <div class="flashmsg">Line it up in the frame</div>
+        <button class="shutter" aria-label="Shoot photo" onclick="go('sampMatch')">📸</button>
+      </div>
+    </div>
+  `,
+  sampMatch: () => `
+    <div class="pad">
+      <p class="kicker">A sample came in</p>
+      <h2 class="question">Mark it received?</h2>
+      <div class="itemcard">
+        <div class="swatch big ${MATCH_ITEM.sw}"></div>
+        <p class="itemname">${MATCH_ITEM.name}</p>
+        <p class="itemmeta">${MATCH_ITEM.color} · ${MATCH_ITEM.code}</p>
+      </div>
+      <button class="bigbtn bigbtn-primary" onclick="go('sampDone')">Yes, Mark Received</button>
+    </div>
+  `,
+  sampDone: () => `
+    <div class="doneWrap">
+      <div class="doneBadge">✅</div>
+      <h2 class="doneTitle">Printing your sticker...<br>Done!</h2>
+      <button class="bigbtn bigbtn-primary" onclick="go('home')">Home</button>
+    </div>
+  `,
+};
+
+go('home');
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v13-sticker-book.html b/public/kid-simple/v13-sticker-book.html
new file mode 100644
index 0000000..2d23b8f
--- /dev/null
+++ b/public/kid-simple/v13-sticker-book.html
@@ -0,0 +1,409 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v13 — Sticker Book</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=Poppins:wght@400;500;600;700;800&family=Caveat:wght@600;700&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#EFE3CF;        /* kraft paper */
+    --paper:#FBF6EC;     /* cream card */
+    --ink:#2E2620;       /* deep coffee */
+    --muted:#8C7C68;     /* taupe */
+    --gold:#A8763A;      /* brass CTA */
+    --teal:#5F9A91;      /* New Item sticker */
+    --rose:#C97B6B;      /* Update sticker */
+    --honey:#B98D3E;     /* Find sticker */
+    --olive:#86A466;     /* Sample sticker */
+    --green:#4C9A6A;     /* success */
+    --cam:#2E2620;       /* camera bg */
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ccc;font-family:'Poppins',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--bg);
+    background-image:
+      radial-gradient(rgba(255,255,255,.35) 1px, transparent 1px);
+    background-size:14px 14px;
+    border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; padding:26px 22px 26px; overflow-y:auto; position:relative; }
+
+  /* ---- home ---- */
+  .wordmark{ font-family:'DM Serif Display', serif; font-size:13px; letter-spacing:.14em; color:var(--muted); text-transform:uppercase; margin:0 0 6px; }
+  .title{ font-family:'DM Serif Display', serif; font-size:32px; margin:0 0 4px; color:var(--ink); }
+  .subtitle{ font-family:'Caveat', cursive; font-weight:700; font-size:20px; color:var(--gold); margin:0 0 14px; }
+
+  .booth{
+    background:var(--cam); border-radius:22px; padding:18px 16px 54px; position:relative;
+    display:flex; flex-direction:column; align-items:center; margin-bottom:34px;
+  }
+  .lens{
+    width:74px; height:74px; border-radius:50%; background:radial-gradient(circle at 35% 32%, #6b6660, #17130f 70%);
+    border:5px solid #46403a; margin-bottom:10px;
+  }
+  .boothtext{ color:#F3ECDD; font-size:14px; font-weight:500; text-align:center; margin:0 0 2px; }
+  .boothhint{ color:#c9bfae; font-size:12px; text-align:center; margin:0; }
+  .shutter{
+    position:absolute; left:50%; bottom:-30px; transform:translateX(-50%);
+    width:72px; height:72px; border-radius:50%; background:var(--gold); border:5px solid var(--paper);
+    font-size:28px; display:flex; align-items:center; justify-content:center; box-shadow:0 8px 16px rgba(0,0,0,.3);
+    cursor:pointer;
+  }
+  .shutter:focus-visible{ outline:3px solid #2B6CB0; outline-offset:3px; }
+
+  .dropzone{ min-height:98px; display:flex; align-items:center; justify-content:center; margin-bottom:10px; }
+  .dropzone .placeholder{
+    font-family:'Caveat', cursive; font-size:18px; color:var(--muted); text-align:center; padding:0 20px;
+    border:2px dashed #cfc2ab; border-radius:14px; width:100%; min-height:70px; display:flex; align-items:center; justify-content:center;
+  }
+  .polaroid{
+    width:104px; background:#fff; padding:8px 8px 16px; border-radius:5px; box-shadow:0 10px 18px rgba(0,0,0,.28);
+    transform:rotate(-6deg); touch-action:none; user-select:none; cursor:grab; position:relative; z-index:5;
+  }
+  .polaroid.dragging{ cursor:grabbing; transform:rotate(0deg) scale(1.06); }
+  .polaroid .shot{ width:100%; height:82px; border-radius:2px; }
+  .polaroid .cap{ font-family:'Caveat', cursive; font-weight:700; font-size:14px; text-align:center; color:#3a3a3a; margin-top:5px; }
+  .ps1{background:repeating-linear-gradient(45deg,#8FAE8B 0 12px,#7c9c78 12px 24px);}
+  .ps2{background:repeating-linear-gradient(-45deg,#7C93B0 0 11px,#617a99 11px 22px);}
+  .ps3{background:repeating-linear-gradient(90deg,#D9A441 0 10px,#c98f2c 10px 20px);}
+
+  .stickerlabel{ font-size:13px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; margin:0 0 10px; text-align:center; }
+  .stickers{ display:grid; grid-template-columns:1fr 1fr; gap:16px; }
+  .sticker{
+    aspect-ratio:1/1; border-radius:50%; display:flex; flex-direction:column; align-items:center; justify-content:center;
+    gap:4px; color:#fff; font-family:'Poppins',sans-serif; font-weight:700; font-size:14px; text-align:center;
+    border:4px dashed rgba(255,255,255,.55); box-shadow:0 10px 18px rgba(0,0,0,.18), inset 0 0 0 6px rgba(255,255,255,.12);
+    cursor:pointer; position:relative; min-height:56px; min-width:56px; padding:8px; transition:transform .15s, box-shadow .15s;
+    -webkit-tap-highlight-color:transparent;
+  }
+  .sticker .emoji{ font-size:32px; }
+  .sticker:nth-child(1){ background:var(--teal); transform:rotate(-4deg); }
+  .sticker:nth-child(2){ background:var(--rose); transform:rotate(3deg); }
+  .sticker:nth-child(3){ background:var(--honey); transform:rotate(3deg); }
+  .sticker:nth-child(4){ background:var(--olive); transform:rotate(-3deg); }
+  .sticker.dropready{ transform:scale(1.1) rotate(0deg) !important; box-shadow:0 0 0 6px rgba(255,255,255,.55), 0 16px 24px rgba(0,0,0,.3); }
+  .sticker:focus-visible{ outline:3px solid #2B6CB0; outline-offset:4px; }
+
+  /* ---- shared flow screens ---- */
+  .question{ font-family:'DM Serif Display', serif; font-size:28px; line-height:1.2; text-align:center; margin:6px 0 24px; color:var(--ink); }
+  .answers{ flex:1; display:flex; flex-direction:column; gap:14px; }
+  button{ font-family:'Poppins',sans-serif; cursor:pointer; }
+  .bigbtn{
+    width:100%; min-height:60px; border-radius:16px; font-size:17px; font-weight:700;
+    background:var(--paper); border:2px solid #e2d6c0; color:var(--ink); padding:10px 16px;
+  }
+  .bigbtn-primary{ background:var(--gold); border:2px solid var(--gold); color:#fff; }
+  .bigbtn-secondary{ background:var(--paper); border:2px solid var(--muted); color:var(--muted); }
+  .bigbtn:focus-visible, .linktext:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline;
+    text-align:center; min-height:56px; width:100%;
+  }
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
+  .swatch{ width:100%; height:150px; border-radius:16px; margin-bottom:8px; }
+  .swatch.small{ height:110px; }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 18px,#7c9c78 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#617a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A441 0 14px,#c98f2c 14px 28px);}
+  .itemname{ font-size:19px; font-weight:800; margin:0; text-align:center; }
+  .itemmeta{ font-size:15px; color:var(--muted); margin:4px 0 0; text-align:center; }
+
+  .camwrap{ flex:1; display:flex; flex-direction:column; padding:0; margin:-26px -22px -26px; }
+  .camview{
+    flex:1; background:var(--cam); position:relative; display:flex; align-items:center; justify-content:center;
+    color:#fff; min-height:480px;
+  }
+  .camview .hint{
+    position:absolute; top:36px; left:20px; right:20px; text-align:center;
+    font-family:'DM Serif Display', serif; font-size:25px; color:#F3ECDD;
+  }
+  .camview .status{ font-size:16px; font-weight:600; color:#d9cdb8; }
+  .camview .shutter2{
+    position:absolute; bottom:32px; left:50%; transform:translateX(-50%);
+    width:82px; height:82px; border-radius:50%; background:var(--gold); border:6px solid #fff;
+    font-size:30px; display:flex; align-items:center; justify-content:center; box-shadow:0 8px 16px rgba(0,0,0,.3);
+  }
+  .center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:10px; }
+  .homefab{
+    position:absolute; top:14px; left:14px; z-index:20; min-width:56px; min-height:56px;
+    border-radius:16px; background:rgba(255,255,255,.94); border:2px solid #e2d6c0; color:var(--ink);
+    font-size:14px; font-weight:700; display:none; align-items:center; justify-content:center; gap:4px;
+    padding:0 12px; box-shadow:0 4px 10px rgba(0,0,0,.15);
+  }
+  .homefab:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <button class="homefab" id="homeFab" aria-label="Home" onclick="go('home')">⌂ Home</button>
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const POLA_SWATCH = ['ps1','ps2','ps3'];
+
+const state = { screen:'home', job:null, item:null, brand:null, resultIndex:0, photoTaken:false, polaSwatch:'ps1' };
+
+function go(screen){ state.screen = screen; render(); }
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+
+function shootHome(){
+  state.photoTaken = true;
+  state.polaSwatch = POLA_SWATCH[Math.floor(Math.random()*POLA_SWATCH.length)];
+  render();
+}
+
+function startJobFromSticker(job, hasPhoto){
+  if(hasPhoto){ state.item = randomItem(); }
+  state.photoTaken = false;
+  state.job = job; state.brand = null; state.resultIndex = 0;
+  const jumpMap = { new:'new-brand', update:'update-match', find:'find-result', sample:'sample-match' };
+  const startMap = { new:'new-cam', update:'update-cam', find:'find-method', sample:'sample-cam' };
+  go(hasPhoto ? jumpMap[job] : startMap[job]);
+}
+function stickerTap(job){
+  const hadPhoto = state.photoTaken;
+  startJobFromSticker(job, hadPhoto);
+}
+
+/* ---- drag the polaroid onto a sticker ---- */
+let dragEl = null, dragStartX = 0, dragStartY = 0, dragElLeft = 0, dragElTop = 0;
+function onPolaroidPointerDown(e){
+  dragEl = e.currentTarget;
+  const rect = dragEl.getBoundingClientRect();
+  dragElLeft = rect.left; dragElTop = rect.top;
+  dragStartX = e.clientX; dragStartY = e.clientY;
+  dragEl.setPointerCapture(e.pointerId);
+  dragEl.classList.add('dragging');
+  dragEl.style.position = 'fixed';
+  dragEl.style.left = dragElLeft + 'px';
+  dragEl.style.top = dragElTop + 'px';
+  dragEl.style.margin = '0';
+  window.addEventListener('pointermove', onPolaroidMove);
+  window.addEventListener('pointerup', onPolaroidUp);
+}
+function stickerUnderPoint(x, y){
+  const el = document.elementFromPoint(x, y);
+  return el && el.closest ? el.closest('.sticker') : null;
+}
+function onPolaroidMove(e){
+  if(!dragEl) return;
+  const dx = e.clientX - dragStartX;
+  const dy = e.clientY - dragStartY;
+  dragEl.style.left = (dragElLeft + dx) + 'px';
+  dragEl.style.top = (dragElTop + dy) + 'px';
+  document.querySelectorAll('.sticker').forEach(s=>s.classList.remove('dropready'));
+  const st = stickerUnderPoint(e.clientX, e.clientY);
+  if(st) st.classList.add('dropready');
+}
+function onPolaroidUp(e){
+  window.removeEventListener('pointermove', onPolaroidMove);
+  window.removeEventListener('pointerup', onPolaroidUp);
+  const st = stickerUnderPoint(e.clientX, e.clientY);
+  document.querySelectorAll('.sticker').forEach(s=>s.classList.remove('dropready'));
+  dragEl = null;
+  if(st){
+    startJobFromSticker(st.dataset.job, true);
+  } else {
+    render(); // snap back to its resting spot
+  }
+}
+
+function cameraScreen(hint, onShoot){
+  return `<div class="camwrap"><div class="camview">
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    <button class="shutter2" aria-label="Take photo" onclick="${onShoot}">📸</button>
+  </div></div>`;
+}
+function shoot(cb){
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter2');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(()=>{ state.item = randomItem(); cb(); }, 650);
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  const fab = document.getElementById('homeFab');
+  fab.style.display = state.screen==='home' ? 'none' : 'flex';
+  let html = '';
+
+  if(state.screen==='home'){
+    html += `
+      <p class="wordmark">Designer Wallcoverings</p>
+      <h1 class="title">📖 Sticker Book</h1>
+      <p class="subtitle">${state.photoTaken ? 'Drag your photo onto a sticker!' : 'Snap a photo, then stick it on a job.'}</p>
+
+      <div class="booth">
+        <div class="lens"></div>
+        <p class="boothtext">Point at anything</p>
+        <p class="boothhint">then tap the button below</p>
+        <button class="shutter" aria-label="Take a photo" onclick="shootHome()">📸</button>
+      </div>
+
+      <div class="dropzone">
+        ${state.photoTaken
+          ? `<div class="polaroid ${state.polaSwatch === 'pola' ? '' : ''}" onpointerdown="onPolaroidPointerDown(event)">
+               <div class="shot ${state.polaSwatch}"></div>
+               <div class="cap">your photo!</div>
+             </div>`
+          : `<div class="placeholder">your photo shows up here ✂️</div>`}
+      </div>
+
+      <p class="stickerlabel">or just tap a sticker</p>
+      <div class="stickers">
+        <div class="sticker" data-job="new" tabindex="0" role="button" aria-label="Add a New Item"
+             onclick="stickerTap('new')" onkeydown="if(event.key==='Enter')stickerTap('new')">
+          <span class="emoji">🆕</span><span>New Item</span>
+        </div>
+        <div class="sticker" data-job="update" tabindex="0" role="button" aria-label="Update an Item"
+             onclick="stickerTap('update')" onkeydown="if(event.key==='Enter')stickerTap('update')">
+          <span class="emoji">🔄</span><span>Update</span>
+        </div>
+        <div class="sticker" data-job="find" tabindex="0" role="button" aria-label="Find an Item"
+             onclick="stickerTap('find')" onkeydown="if(event.key==='Enter')stickerTap('find')">
+          <span class="emoji">🔍</span><span>Find It</span>
+        </div>
+        <div class="sticker" data-job="sample" tabindex="0" role="button" aria-label="A Sample Came In"
+             onclick="stickerTap('sample')" onkeydown="if(event.key==='Enter')stickerTap('sample')">
+          <span class="emoji">📦</span><span>Sample In</span>
+        </div>
+      </div>`;
+  }
+
+  /* ---- Add New Item ---- */
+  else if(state.screen==='new-cam'){
+    html += cameraScreen('Take a photo of it.', "shoot(()=>go('new-brand'))");
+  }
+  else if(state.screen==='new-brand'){
+    html += `<h1 class="question">Which brand is it?</h1><div class="brandlist">`;
+    BRANDS.forEach(b=>{ html += `<button class="bigbtn" onclick="state.brand='${b}'; go('new-save')">${b}</button>`; });
+    html += `</div>`;
+  }
+  else if(state.screen==='new-save'){
+    html += `<h1 class="question">Save it?</h1>
+      <div class="swatch small ${state.item.sw}"></div>
+      <p class="itemmeta">${state.brand} · code ${state.item.code}</p>
+      <div class="answers" style="margin-top:18px;">
+        <button class="bigbtn bigbtn-primary" onclick="go('new-done')">Save as Draft</button>
+        <button class="linktext" onclick="go('new-cam')">Retake Photo</button>
+      </div>`;
+  }
+  else if(state.screen==='new-done'){
+    html += `<div class="center"><h1 class="question">Saved! 🎉</h1></div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="go('new-cam')">Add Another</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  /* ---- Update an Item ---- */
+  else if(state.screen==='update-cam'){
+    html += cameraScreen('Scan the label or pattern.', "shoot(()=>go('update-match'))");
+  }
+  else if(state.screen==='update-match'){
+    html += `<h1 class="question">Is this it?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="answers" style="margin-top:18px;">
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Yes</button>
+        <button class="bigbtn bigbtn-secondary" onclick="go('update-cam')">No, Let Me Search</button>
+      </div>`;
+  }
+  else if(state.screen==='update-cam2'){
+    html += cameraScreen('Take the new photo.', "shoot(()=>go('update-done'))");
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="center"><h1 class="question">Updated! ✅</h1></div>
+      <button class="bigbtn bigbtn-primary" onclick="go('home')">Back Home</button>`;
+  }
+
+  /* ---- Find an Item ---- */
+  else if(state.screen==='find-method'){
+    html += `<h1 class="question">How do you want to find it?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="go('find-result')">📷 Scan the Label</button>
+        <button class="bigbtn" onclick="go('find-result')">🎤 Say the Name</button>
+        <button class="bigbtn" onclick="go('find-result')">⌨️ Type It</button>
+      </div>`;
+  }
+  else if(state.screen==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    html += `<h1 class="question">Which one is it?</h1>
+      <div class="swatch ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="answers" style="margin-top:18px;">
+        <button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
+      </div>`;
+  }
+  else if(state.screen==='find-exhausted'){
+    html += `<h1 class="question">That's all — try another way?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">📷 Scan the Label</button>
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">🎤 Say the Name</button>
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">⌨️ Type It</button>
+      </div>`;
+  }
+  else if(state.screen==='find-detail'){
+    html += `<div class="center">
+        <h1 class="question" style="font-size:24px; margin-bottom:12px;">${state.item.name}</h1>
+        <div class="swatch ${state.item.sw}" style="width:240px;"></div>
+        <p class="itemmeta">${state.item.color} · code ${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Update This</button>
+        <button class="bigbtn bigbtn-secondary" onclick="go('find-method')">Search Again</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  /* ---- A Sample Came In ---- */
+  else if(state.screen==='sample-cam'){
+    html += cameraScreen('Scan the box label.', "shoot(()=>go('sample-match'))");
+  }
+  else if(state.screen==='sample-match'){
+    html += `<h1 class="question">Mark it received?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="answers" style="margin-top:18px;">
+        <button class="bigbtn bigbtn-primary" onclick="go('sample-printing')">Yes, Mark Received</button>
+      </div>`;
+  }
+  else if(state.screen==='sample-printing'){
+    html += `<div class="center"><h1 class="question">Printing your sticker…</h1><p class="itemmeta">🖨️ One sec…</p></div>`;
+    setTimeout(()=>{ if(state.screen==='sample-printing') go('sample-done'); }, 1000);
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="center"><h1 class="question">Done! ✅</h1></div>
+      <button class="bigbtn bigbtn-primary" onclick="go('home')">Back Home</button>`;
+  }
+
+  s.innerHTML = html;
+}
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-detail'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; go('find-result'); }
+  else { go('find-exhausted'); }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v14-ticket-printer.html b/public/kid-simple/v14-ticket-printer.html
new file mode 100644
index 0000000..354f756
--- /dev/null
+++ b/public/kid-simple/v14-ticket-printer.html
@@ -0,0 +1,344 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v14 — Ticket Printer</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&family=Courier+Prime:wght@400;700&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#F6F1E7; --ink:#241F1C; --paper:#FFFDF6; --muted:#8A7F70;
+    --chassis:#23343B; --slot:#0F1A1E; --lamp:#7FD858;
+    --new:#B5502D; --update:#3C6E71; --find:#B08D3E; --sample:#6B4E71;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Fredoka',sans-serif;color:var(--ink);}
+  body{display:flex;align-items:flex-start;justify-content:center;min-height:100vh;padding:20px 0;}
+  .phone{
+    width:390px;min-height:780px;background:var(--bg);border-radius:36px;overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28);display:flex;flex-direction:column;position:relative;
+  }
+  #screen{flex:1;display:flex;flex-direction:column;position:relative;overflow-y:auto;}
+  button{font-family:'Fredoka',sans-serif;cursor:pointer;border:none;}
+  button:focus-visible, .linktext:focus-visible{outline:3px solid #2B6CB0;outline-offset:2px;}
+
+  /* ---- home fab ---- */
+  .homefab{
+    position:absolute;top:14px;left:14px;z-index:30;min-width:56px;min-height:56px;
+    border-radius:16px;background:rgba(255,255,255,.94);border:2px solid #e7e1d0;color:var(--ink);
+    font-size:14px;font-weight:700;display:none;align-items:center;justify-content:center;gap:4px;
+    padding:0 12px;box-shadow:0 4px 10px rgba(0,0,0,.18);
+  }
+
+  /* ---- printer chassis (home) ---- */
+  .printer-top{background:var(--chassis);padding:24px 22px 20px;border-radius:0 0 30px 30px;position:relative;}
+  .chassis-row{display:flex;align-items:center;justify-content:space-between;}
+  .dw-mark{color:var(--paper);font-weight:700;font-size:13px;letter-spacing:2.5px;opacity:.8;}
+  .lamp{width:12px;height:12px;border-radius:50%;background:var(--lamp);box-shadow:0 0 9px var(--lamp);}
+  .chassis-title{color:var(--paper);font-weight:700;font-size:26px;text-align:center;margin:12px 0 18px;letter-spacing:.3px;}
+  .slot{background:var(--slot);height:24px;border-radius:6px;margin:0 14px;position:relative;box-shadow:inset 0 3px 7px rgba(0,0,0,.6);}
+  .paper-peek{position:absolute;left:50%;transform:translateX(-50%);top:-3px;width:64%;height:8px;background:var(--paper);border-radius:2px 2px 0 0;opacity:.4;}
+  .readout{color:var(--paper);opacity:.72;text-align:center;font-size:13px;margin:14px 0 0;font-family:'Courier Prime',monospace;letter-spacing:.3px;}
+
+  /* ---- keypad (home) ---- */
+  .keypad{padding:22px;display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;gap:16px;flex:1;}
+  .key{
+    border-radius:24px;color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;
+    gap:10px;font-weight:700;font-size:17px;text-align:center;
+    box-shadow:0 6px 0 rgba(0,0,0,.2), 0 12px 20px rgba(0,0,0,.14);
+  }
+  .key:active{transform:translateY(5px);box-shadow:0 1px 0 rgba(0,0,0,.2);}
+  .key .key-icon{font-size:40px;line-height:1;}
+  .key-new{background:var(--new);}
+  .key-update{background:var(--update);}
+  .key-find{background:var(--find);color:#2B2109;}
+  .key-sample{background:var(--sample);}
+  .keypad-hint{grid-column:1/3;text-align:center;color:var(--muted);font-size:13px;font-family:'Courier Prime',monospace;align-self:end;}
+
+  /* ---- generic padded question screen ---- */
+  .pad{padding:32px 24px 28px;display:flex;flex-direction:column;flex:1;}
+  .q{font-weight:600;font-size:25px;line-height:1.28;text-align:center;margin:4px 0 24px;}
+  .stack{display:flex;flex-direction:column;gap:14px;}
+  .rowbtn{
+    width:100%;min-height:64px;border-radius:18px;font-size:18px;font-weight:700;
+    background:#fff;border:2px solid #e9e1d0;color:var(--ink);padding:12px 16px;
+  }
+  .accent-new{background:var(--new)!important;color:#fff!important;border-color:var(--new)!important;}
+  .accent-update{background:var(--update)!important;color:#fff!important;border-color:var(--update)!important;}
+  .accent-find{background:var(--find)!important;color:#2B2109!important;border-color:var(--find)!important;}
+  .accent-sample{background:var(--sample)!important;color:#fff!important;border-color:var(--sample)!important;}
+  .linktext{
+    background:none;border:none;color:var(--muted);font-size:16px;text-decoration:underline;
+    text-align:center;min-height:56px;width:100%;font-family:'Fredoka',sans-serif;
+  }
+  .brandlist{display:flex;flex-direction:column;gap:12px;overflow-y:auto;}
+
+  /* ---- swatch (mock item art) ---- */
+  .swatch{width:100%;height:110px;border-radius:14px;margin-bottom:10px;}
+  .sw1{background:repeating-linear-gradient(45deg,#B5502D 0 16px,#8f3f22 16px 32px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#3C6E71 0 16px,#2c5254 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#B08D3E 0 14px,#8f712c 14px 28px);}
+  .itemname{font-size:19px;font-weight:700;margin:0;text-align:center;}
+  .itemmeta{font-size:15px;color:#6d6459;margin:4px 0 0;text-align:center;font-family:'Courier Prime',monospace;}
+
+  /* ---- camera ---- */
+  .camwrap{flex:1;display:flex;flex-direction:column;}
+  .camview{flex:1;background:#12181B;position:relative;display:flex;align-items:center;justify-content:center;color:#fff;min-height:520px;}
+  .camview .tag{position:absolute;top:18px;left:18px;padding:7px 14px;border-radius:20px;font-weight:700;font-size:12.5px;letter-spacing:.4px;color:#fff;}
+  .camview .hint{position:absolute;top:66px;left:20px;right:20px;text-align:center;font-weight:600;font-size:25px;color:var(--paper);}
+  .camview .status{font-family:'Courier Prime',monospace;font-size:14px;color:#cfc6b5;}
+  .shutter{
+    position:absolute;bottom:32px;left:50%;transform:translateX(-50%);
+    width:92px;height:92px;border-radius:50%;background:var(--paper);border:6px solid rgba(255,255,255,.15);
+    font-size:34px;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 18px rgba(0,0,0,.45);
+  }
+
+  /* ---- ticket dock + ticket paper ---- */
+  .ticket-dock{background:var(--chassis);padding:20px 22px 30px;position:relative;border-radius:0 0 30px 30px;}
+  .ticket-dock .slot{margin:0 10px;}
+  .ticket-dock .paper-peek.out{opacity:1;height:34px;top:-3px;transition:height .5s ease, opacity .5s ease;}
+  .dockmsg{color:var(--paper);text-align:center;font-family:'Courier Prime',monospace;font-size:13.5px;margin:14px 0 0;opacity:.85;}
+  .ticket{
+    background:var(--paper);margin:-14px 22px 0;padding:24px 20px 20px;position:relative;
+    box-shadow:0 12px 24px rgba(0,0,0,.16);
+    clip-path:polygon(0% 0%,100% 0%,100% 90%,95% 100%,90% 90%,85% 100%,80% 90%,75% 100%,70% 90%,65% 100%,60% 90%,55% 100%,50% 90%,45% 100%,40% 90%,35% 100%,30% 90%,25% 100%,20% 90%,15% 100%,10% 90%,5% 100%,0% 90%);
+  }
+  .ticket-mono{font-family:'Courier Prime',monospace;font-size:13.5px;line-height:1.85;color:#2b2620;white-space:pre-wrap;text-align:center;}
+  .ticket-head{font-weight:700;font-size:15px;letter-spacing:.5px;}
+  .ticket-cta{padding:26px 24px 24px;display:flex;flex-direction:column;gap:14px;}
+  .center{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;gap:10px;}
+</style>
+</head>
+<body>
+<div class="phone">
+  <button class="homefab" id="homeFab" aria-label="Home" onclick="go('home')">⌂ Home</button>
+  <div id="screen" role="main"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const TAG = {new:{cls:'accent-new', label:'🆕 NEW ITEM'}, update:{cls:'accent-update', label:'🔄 UPDATE'},
+             find:{cls:'accent-find', label:'🔍 FIND'}, sample:{cls:'accent-sample', label:'📦 SAMPLE IN'}};
+
+const state = { screen:'home', job:null, item:null, brand:null, resultIndex:0, printed:false };
+
+function go(screen){
+  state.screen = screen;
+  if(screen.endsWith('-ticket')){
+    state.printed = false;
+    render();
+    setTimeout(()=>{ if(state.screen===screen){ state.printed = true; render(); } }, 800);
+    return;
+  }
+  render();
+}
+function startJob(job){
+  state.job = job; state.item=null; state.brand=null; state.resultIndex=0;
+  const map = {new:'new-cam', update:'update-cam', find:'find-cam', sample:'sample-cam'};
+  go(map[job]);
+}
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+function stamp(){
+  return new Date().toLocaleString(undefined,{month:'2-digit',day:'2-digit',hour:'numeric',minute:'2-digit'});
+}
+
+function cameraScreen(hint, onShootExpr){
+  const t = TAG[state.job];
+  return `<div class="camwrap"><div class="camview">
+    <div class="tag ${t.cls}">${t.label}</div>
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    <button class="shutter" aria-label="Take photo" onclick="${onShootExpr}">📸</button>
+  </div></div>`;
+}
+function shoot(cb){
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(()=>{ state.item = randomItem(); cb(); }, 700);
+}
+
+function ticketDock(msg){
+  return `<div class="ticket-dock">
+    <div class="chassis-row"><span class="dw-mark">DW</span><span class="lamp"></span></div>
+    <div class="slot"><div class="paper-peek ${state.printed?'out':''}"></div></div>
+    <p class="dockmsg">${state.printed ? 'Ticket printed! 🖨️' : msg}</p>
+  </div>`;
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  const fab = document.getElementById('homeFab');
+  fab.style.display = state.screen==='home' ? 'none' : 'flex';
+  let html = '';
+
+  if(state.screen==='home'){
+    html += `<div class="printer-top">
+        <div class="chassis-row"><span class="dw-mark">DW</span><span class="lamp" aria-hidden="true"></span></div>
+        <div class="chassis-title">TICKET PRINTER</div>
+        <div class="slot"><div class="paper-peek"></div></div>
+        <p class="readout">Ready — pick a job to print a ticket.</p>
+      </div>
+      <div class="keypad">
+        <button class="key key-new" onclick="startJob('new')"><span class="key-icon">🆕</span><span>New Item</span></button>
+        <button class="key key-update" onclick="startJob('update')"><span class="key-icon">🔄</span><span>Update</span></button>
+        <button class="key key-find" onclick="startJob('find')"><span class="key-icon">🔍</span><span>Find</span></button>
+        <button class="key key-sample" onclick="startJob('sample')"><span class="key-icon">📦</span><span>Sample In</span></button>
+        <p class="keypad-hint">every job prints a ticket</p>
+      </div>`;
+  }
+
+  /* ---------- NEW ITEM ---------- */
+  else if(state.screen==='new-cam'){
+    html += cameraScreen('Take a photo of it.', "shoot(()=>go('new-brand'))");
+  }
+  else if(state.screen==='new-brand'){
+    html += `<div class="pad"><h1 class="q">Which brand is it?</h1><div class="brandlist">`;
+    BRANDS.forEach(b=>{ html += `<button class="rowbtn" onclick="state.brand='${b}'; go('new-ticket')">${b}</button>`; });
+    html += `</div></div>`;
+  }
+  else if(state.screen==='new-ticket'){
+    html += ticketDock('Printing your ticket…');
+    if(state.printed){
+      html += `<div class="ticket">
+          <div class="swatch ${state.item.sw}"></div>
+          <p class="ticket-mono"><span class="ticket-head">★ NEW ITEM ADDED ★</span>
+BRAND:  ${state.brand}
+CODE:   ${state.item.code}
+DATE:   ${stamp()}
+
+  thanks — nice work!</p>
+        </div>
+        <div class="ticket-cta">
+          <button class="rowbtn accent-new" onclick="startJob('new')">Print Another</button>
+          <button class="linktext" onclick="go('home')">Home</button>
+        </div>`;
+    }
+  }
+
+  /* ---------- UPDATE ---------- */
+  else if(state.screen==='update-cam'){
+    html += cameraScreen('Scan the label or pattern.', "shoot(()=>go('update-match'))");
+  }
+  else if(state.screen==='update-match'){
+    html += `<div class="pad"><h1 class="q">Is this it?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="stack" style="margin-top:22px;">
+        <button class="rowbtn accent-update" onclick="go('update-cam2')">Yes, That's It</button>
+        <button class="rowbtn" onclick="go('update-cam')">No, Scan Again</button>
+      </div></div>`;
+  }
+  else if(state.screen==='update-cam2'){
+    html += cameraScreen('Take the new photo.', "shoot(()=>go('update-ticket'))");
+  }
+  else if(state.screen==='update-ticket'){
+    html += ticketDock('Printing your ticket…');
+    if(state.printed){
+      html += `<div class="ticket">
+          <div class="swatch ${state.item.sw}"></div>
+          <p class="ticket-mono"><span class="ticket-head">★ ITEM UPDATED ★</span>
+ITEM:   ${state.item.name}
+CODE:   ${state.item.code}
+DATE:   ${stamp()}
+
+    all set!</p>
+        </div>
+        <div class="ticket-cta">
+          <button class="rowbtn accent-update" onclick="go('home')">Back Home</button>
+        </div>`;
+    }
+  }
+
+  /* ---------- FIND ---------- */
+  else if(state.screen==='find-cam'){
+    html += cameraScreen('Scan it to find the item.', "shoot(()=>{ state.resultIndex=0; go('find-result'); })");
+  }
+  else if(state.screen==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    html += `<div class="pad"><h1 class="q">Is this the one?</h1>
+      <div class="swatch ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="stack" style="margin-top:22px;">
+        <button class="rowbtn accent-find" onclick="pickResult()">Yes, This One</button>
+        <button class="rowbtn" onclick="nextResult()">Next Result</button>
+      </div></div>`;
+  }
+  else if(state.screen==='find-exhausted'){
+    html += `<div class="pad center"><h1 class="q">That's everything. Try scanning again?</h1>
+      <button class="rowbtn accent-find" onclick="go('find-cam')">Scan Again</button>
+    </div>`;
+  }
+  else if(state.screen==='find-ticket'){
+    html += ticketDock('Printing your ticket…');
+    if(state.printed){
+      html += `<div class="ticket">
+          <div class="swatch ${state.item.sw}"></div>
+          <p class="ticket-mono"><span class="ticket-head">★ HERE'S YOUR ITEM ★</span>
+ITEM:   ${state.item.name}
+CODE:   ${state.item.code}
+DATE:   ${stamp()}
+
+    found it!</p>
+        </div>
+        <div class="ticket-cta">
+          <button class="rowbtn accent-update" onclick="go('update-cam2')">Update This</button>
+          <button class="rowbtn" onclick="go('find-cam')">Search Again</button>
+          <button class="linktext" onclick="go('home')">Home</button>
+        </div>`;
+    }
+  }
+
+  /* ---------- SAMPLE ---------- */
+  else if(state.screen==='sample-cam'){
+    html += cameraScreen('Scan the box label.', "shoot(()=>go('sample-match'))");
+  }
+  else if(state.screen==='sample-match'){
+    html += `<div class="pad"><h1 class="q">Mark it received?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="stack" style="margin-top:22px;">
+        <button class="rowbtn accent-sample" onclick="go('sample-ticket')">Yes, Mark Received</button>
+      </div></div>`;
+  }
+  else if(state.screen==='sample-ticket'){
+    html += ticketDock('Printing your ticket…');
+    if(state.printed){
+      html += `<div class="ticket">
+          <div class="swatch ${state.item.sw}"></div>
+          <p class="ticket-mono"><span class="ticket-head">★ SAMPLE RECEIVED ★</span>
+ITEM:   ${state.item.name}
+CODE:   ${state.item.code}
+DATE:   ${stamp()}
+
+  sticker printed! ✅</p>
+        </div>
+        <div class="ticket-cta">
+          <button class="rowbtn accent-sample" onclick="go('home')">Back Home</button>
+        </div>`;
+    }
+  }
+
+  s.innerHTML = html;
+}
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-ticket'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; go('find-result'); }
+  else { go('find-exhausted'); }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v15-thumb-zone.html b/public/kid-simple/v15-thumb-zone.html
new file mode 100644
index 0000000..f25313c
--- /dev/null
+++ b/public/kid-simple/v15-thumb-zone.html
@@ -0,0 +1,493 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v15 — Thumb Zone (Shoot-First / One-Thumb Confirm)</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Spectral:wght@500;600;700&family=Manrope:wght@400;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --stage:#07070A;
+    --panel:#18120E;
+    --panel-edge:#241A13;
+    --line:#3A2C20;
+    --ink:#F6EFE4;
+    --muted:#A9998A;
+    --accent:#FF8A42;
+    --accent-ink:#2B1206;
+    --success:#5FCE8B;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#000;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; height:780px; background:var(--stage); border-radius:36px;
+    overflow:hidden; box-shadow:0 24px 60px rgba(0,0,0,.5); display:flex; flex-direction:column;
+    position:relative;
+  }
+
+  /* ---------- STAGE (top two-thirds: camera is ALWAYS live, in every state) ---------- */
+  .stage{
+    flex:1; min-height:0; background:radial-gradient(120% 90% at 50% 0%, #101015 0%, #07070A 60%);
+    position:relative; display:flex; flex-direction:column; overflow:hidden;
+  }
+  .stage-topbar{
+    display:flex; align-items:center; justify-content:space-between; padding:16px 20px 0;
+    font-family:'Manrope'; font-size:12px; font-weight:700; letter-spacing:.08em; color:var(--muted);
+  }
+  .stage-topbar .dw{ color:var(--accent); font-weight:800; }
+  .live-dot{ display:inline-flex; align-items:center; gap:6px; }
+  .live-dot span.dot{ width:7px; height:7px; border-radius:50%; background:var(--accent); box-shadow:0 0 8px var(--accent); animation:pulse 1.6s ease-in-out infinite; }
+  @keyframes pulse{ 0%,100%{opacity:1;} 50%{opacity:.35;} }
+  .stage-body{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:14px 26px; gap:14px; text-align:center; }
+  .stage-hint{ font-family:'Spectral',serif; font-weight:600; font-size:23px; line-height:1.3; color:var(--ink); max-width:300px; }
+  .stage-status{ font-family:'Manrope'; font-size:14px; font-weight:700; color:var(--muted); letter-spacing:.03em; }
+
+  .viewfinder{ width:230px; height:230px; position:relative; display:flex; align-items:center; justify-content:center; }
+  .corner{ position:absolute; width:34px; height:34px; border-color:var(--accent); }
+  .corner.tl{ top:0; left:0; border-top:3px solid; border-left:3px solid; border-radius:10px 0 0 0; }
+  .corner.tr{ top:0; right:0; border-top:3px solid; border-right:3px solid; border-radius:0 10px 0 0; }
+  .corner.bl{ bottom:0; left:0; border-bottom:3px solid; border-left:3px solid; border-radius:0 0 0 10px; }
+  .corner.br{ bottom:0; right:0; border-bottom:3px solid; border-right:3px solid; border-radius:0 0 10px 0; }
+  .viewfinder .glyph{ font-size:44px; opacity:.9; }
+
+  .idle-orb{
+    width:150px; height:150px; border-radius:50%;
+    background:radial-gradient(circle at 35% 30%, rgba(255,138,66,.35), rgba(255,138,66,0) 65%);
+    border:2px solid var(--line); display:flex; align-items:center; justify-content:center; font-size:46px;
+  }
+
+  .swatch-card{
+    width:190px; height:190px; border-radius:24px; box-shadow:0 14px 30px rgba(0,0,0,.5);
+    display:flex; align-items:flex-end; justify-content:center; position:relative; overflow:hidden;
+  }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 18px,#5f7a5c 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#4c637f 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A441 0 14px,#a9711f 14px 28px);}
+  .item-caption{ margin-top:2px; }
+  .item-name{ font-family:'Spectral',serif; font-weight:700; font-size:20px; margin:0; color:var(--ink); }
+  .item-meta{ font-family:'Manrope'; font-size:13px; color:var(--muted); margin:4px 0 0; }
+
+  .big-emoji{ font-size:60px; }
+
+  /* toast, floats over the still-live stage */
+  .toast{
+    position:absolute; left:50%; bottom:14px; transform:translateX(-50%);
+    background:rgba(20,14,10,.94); border:2px solid var(--accent); border-radius:999px;
+    padding:10px 20px; font-weight:800; font-size:14px; display:flex; align-items:center; gap:8px;
+    box-shadow:0 10px 24px rgba(0,0,0,.4); white-space:nowrap;
+  }
+
+  /* ---------- THUMB CONTROLLER (bottom third: the ONE persistent panel) ---------- */
+  .panel{
+    background:linear-gradient(180deg, var(--panel-edge), var(--panel));
+    border-top:1px solid var(--line);
+    border-radius:26px 26px 0 0;
+    padding:16px 20px 24px;
+    display:flex; flex-direction:column; gap:12px;
+    min-height:298px;
+    box-shadow:0 -18px 40px rgba(0,0,0,.35);
+    position:relative;
+  }
+  .panel-head{ display:flex; align-items:center; gap:12px; }
+  .home-btn{
+    flex:0 0 auto; width:56px; height:56px; border-radius:16px; background:#241A13;
+    border:2px solid var(--line); color:var(--muted); font-size:20px; display:flex;
+    align-items:center; justify-content:center; cursor:pointer;
+  }
+  .home-btn:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+  .panel-title{ font-family:'Spectral',serif; font-weight:600; font-size:21px; line-height:1.25; color:var(--ink); flex:1; }
+
+  .panel-body{ flex:1; display:flex; flex-direction:column; gap:12px; justify-content:center; }
+
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+  .pbtn{
+    width:100%; min-height:60px; border-radius:16px; font-size:17px; font-weight:800;
+    background:#241A13; border:2px solid var(--line); color:var(--ink); padding:10px 16px;
+  }
+  .pbtn-primary{ background:var(--accent); border-color:var(--accent); color:var(--accent-ink); }
+  .pbtn-secondary{ background:transparent; border-color:var(--line); color:var(--muted); }
+  .pbtn:focus-visible, .home-btn:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+
+  .chip-row{ display:flex; gap:10px; overflow-x:auto; padding:4px 2px 8px; scroll-snap-type:x proximity; }
+  .chip{
+    flex:0 0 auto; scroll-snap-align:start; min-height:56px; padding:0 20px; border-radius:999px;
+    background:#241A13; border:2px solid var(--line); color:var(--ink); font-size:15px; font-weight:700;
+    display:flex; align-items:center; white-space:nowrap;
+  }
+  .chip:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+
+  .shutter-wrap{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; flex:1; }
+  .shutter{
+    width:84px; height:84px; border-radius:50%; background:var(--accent); border:5px solid #4A2C16;
+    font-size:30px; display:flex; align-items:center; justify-content:center; box-shadow:0 0 0 6px rgba(255,138,66,.16);
+  }
+  .shutter-caption{ font-size:13px; font-weight:700; color:var(--muted); letter-spacing:.03em; }
+
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:15px; text-decoration:underline;
+    text-align:center; min-height:56px; min-width:56px; width:100%;
+  }
+  .linktext:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+
+  /* pull-up find drawer tab, lives on the LIVE screen */
+  .drawer-tab{
+    width:100%; min-height:56px; border-radius:16px; background:transparent;
+    border:2px dashed var(--line); color:var(--muted); font-weight:800; font-size:15px;
+    display:flex; align-items:center; justify-content:center; gap:8px;
+  }
+  .drawer-tab .chev{ color:var(--accent); }
+
+  /* the vertical 3-option thumb picker (post-shot job wheel) */
+  .picker-hint{ text-align:center; font-size:12px; font-weight:800; letter-spacing:.08em; color:var(--muted); text-transform:uppercase; }
+  .picker-stack{ display:flex; flex-direction:column; gap:10px; touch-action:pan-y; }
+  .picker-card{
+    min-height:64px; width:100%; border-radius:16px; background:#241A13; border:2px solid var(--line);
+    display:flex; align-items:center; gap:14px; padding:0 18px; font-weight:800; font-size:16px; color:var(--ink);
+    text-align:left;
+  }
+  .picker-card .ic{ font-size:26px; }
+  .picker-card.likely{ border-color:var(--accent); background:linear-gradient(135deg, rgba(255,138,66,.20), #241A13); }
+  .picker-card.likely::after{ content:'MOST LIKELY'; margin-left:auto; font-size:10px; letter-spacing:.06em; color:var(--accent); font-weight:800; }
+  .picker-card:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+
+  /* hold-to-confirm ring, replaces every yes/no screen */
+  .hold-wrap{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; flex:1; }
+  .hold-ring{
+    --pct:0%;
+    width:104px; height:104px; border-radius:50%; padding:6px; border:none;
+    background:conic-gradient(var(--accent) var(--pct), #2A1F17 var(--pct));
+    display:flex; align-items:center; justify-content:center; transition:box-shadow .15s;
+  }
+  .hold-ring.holding{ box-shadow:0 0 0 8px rgba(255,138,66,.14); }
+  .hold-ring-inner{
+    width:100%; height:100%; border-radius:50%; background:#18120E; border:2px solid var(--line);
+    display:flex; align-items:center; justify-content:center; text-align:center; padding:6px;
+    font-size:13px; font-weight:800; color:var(--ink); line-height:1.2;
+  }
+  .hold-caption{ font-size:13px; font-weight:700; color:var(--muted); letter-spacing:.02em; text-align:center; }
+
+  /* mini persistent shutter FAB — sits on the stage/panel seam in every non-idle state */
+  .mini-fab{
+    position:absolute; top:-28px; right:22px; width:64px; height:64px; border-radius:50%;
+    background:var(--accent); border:4px solid #4A2C16; color:var(--accent-ink); font-size:24px;
+    display:flex; align-items:center; justify-content:center; box-shadow:0 8px 18px rgba(0,0,0,.4); z-index:5;
+  }
+  .mini-fab:focus-visible{ outline:3px solid #6FB8FF; outline-offset:2px; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="stage" id="stage"></div>
+  <div class="panel" id="panel"></div>
+</div>
+
+<script>
+/* ---------------------------------------------------------------------
+   NEW MODEL: "shoot first, one-thumb confirm"
+   - Camera is ALWAYS live on the stage, in every state.
+   - The bottom panel is a single persistent thumb controller.
+   - Tap the shutter (big one on the idle screen, or the mini FAB seam
+     button everywhere else) from ANY state to take a shot.
+   - After a shot taken from idle, the panel morphs into a vertical
+     3-option thumb PICKER (swipe up/down or tap) offering the most
+     likely job first, instead of a menu screen.
+   - Every yes/no decision is a HOLD-TO-CONFIRM ring (0.6s) instead of
+     a Yes/No screen.
+   - Find is a pull-up search drawer from the panel, not its own flow.
+--------------------------------------------------------------------- */
+
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const JOB_META = {
+  new:    {ic:'🆕', label:'Add New Item'},
+  update: {ic:'🔄', label:'Update an Item'},
+  sample: {ic:'📦', label:'Sample Came In'},
+};
+
+const state = {
+  screen:'live',      // live | picker | new-brand | new-confirm |
+                       // update-confirm | update-shoot | update-save |
+                       // find-drawer | find-result | find-detail |
+                       // sample-confirm | sample-printing
+  job:null, item:null, brand:null, findIndex:0,
+  pickerOrder:['new','update','sample'],
+  toast:null, toastTimer:null,
+};
+
+function go(screen){ state.screen = screen; render(); }
+
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+
+/* the ONE shoot action — captures pretend data */
+function shoot(cb){ state.item = randomItem(); cb && cb(); }
+
+/* tapping the shutter from idle (or the persistent mini-FAB anywhere else)
+   always leads to the picker: shoot first, decide the job second */
+function mainShoot(){
+  shoot(()=>{
+    const likely = state.job || 'new';
+    state.pickerOrder = ['new','update','sample'];
+    state.pickerOrder.sort((a,b)=> (a===likely?-1:0) - (b===likely?-1:0));
+    go('picker');
+  });
+}
+
+function choosePicker(job){
+  state.job = job;
+  if(job==='new') go('new-brand');
+  else if(job==='update') go('update-confirm');
+  else if(job==='sample') go('sample-confirm');
+}
+function swipePicker(dir){
+  const o = state.pickerOrder;
+  if(dir>0) o.push(o.shift()); else o.unshift(o.pop());
+  render();
+}
+
+function chooseBrand(b){ state.brand = b; go('new-confirm'); }
+function completeNew(){ state.toast = {emoji:'🎉', text:'Saved!'}; state.job=null; go('live'); }
+
+function confirmUpdateMatch(){ go('update-shoot'); }
+function shootUpdate(){ shoot(()=> go('update-save')); }
+function completeUpdateSave(){ state.toast = {emoji:'✅', text:'Updated!'}; state.job=null; go('live'); }
+
+function openFindDrawer(){ go('find-drawer'); }
+function startFind(){ state.findIndex = 0; go('find-result'); }
+function nextFindResult(){ state.findIndex = (state.findIndex+1) % MOCK_ITEMS.length; render(); }
+function confirmFindMatch(){ go('find-detail'); }
+function updateFromFind(){ go('update-shoot'); }
+
+function confirmSampleReceived(){
+  go('sample-printing');
+  setTimeout(()=>{ state.toast = {emoji:'✅', text:'Received!'}; state.job=null; go('live'); }, 1100);
+}
+
+/* ---------- stage fragments (camera is always "live" behind everything) ---------- */
+function stageTopbar(){
+  return `<div class="stage-topbar"><span class="dw">DW</span><span class="live-dot"><span class="dot"></span>LIVE</span></div>`;
+}
+function stageLive(){
+  return `${stageTopbar()}
+    <div class="stage-body">
+      <div class="idle-orb">📷</div>
+      <div class="stage-hint">Ready when you are.</div>
+    </div>`;
+}
+function stageViewfinder(hint){
+  return `${stageTopbar()}
+    <div class="stage-body">
+      <div class="stage-hint">${hint}</div>
+      <div class="viewfinder">
+        <div class="corner tl"></div><div class="corner tr"></div>
+        <div class="corner bl"></div><div class="corner br"></div>
+        <span class="glyph">🖼️</span>
+      </div>
+    </div>`;
+}
+function stageCaptured(caption){
+  const it = state.item || MOCK_ITEMS[0];
+  return `${stageTopbar()}
+    <div class="stage-body">
+      <div class="swatch-card ${it.sw}"></div>
+      <div class="item-caption">
+        <p class="item-name">${it.name} — ${it.color}</p>
+        <p class="item-meta">${caption}</p>
+      </div>
+    </div>`;
+}
+function stageMessage(emoji, text, sub){
+  return `${stageTopbar()}
+    <div class="stage-body">
+      <div class="big-emoji">${emoji}</div>
+      <div class="stage-hint">${text}</div>
+      ${sub ? `<div class="stage-status">${sub}</div>` : ''}
+    </div>`;
+}
+function toastHTML(){
+  return state.toast ? `<div class="toast">${state.toast.emoji} ${state.toast.text}</div>` : '';
+}
+
+/* ---------- panel fragments ---------- */
+function homeBtn(){ return `<button class="home-btn" aria-label="Home" onclick="go('live')">⌂</button>`; }
+function panelHead(title){
+  return `<div class="panel-head">${state.screen!=='live' ? homeBtn() : ''}<div class="panel-title">${title}</div></div>`;
+}
+function miniFabHTML(){
+  return `<button class="mini-fab" aria-label="Take a new photo" onclick="mainShoot()">📸</button>`;
+}
+function holdRingHTML(id, label, sub){
+  return `<div class="hold-wrap">
+    <button type="button" class="hold-ring" id="${id}"><span class="hold-ring-inner">${label}</span></button>
+    <div class="hold-caption">${sub}</div>
+  </div>`;
+}
+function pickerCardHTML(job, isLikely){
+  const m = JOB_META[job];
+  return `<button class="picker-card ${isLikely?'likely':''}" onclick="choosePicker('${job}')">
+    <span class="ic">${m.ic}</span><span>${m.label}</span>
+  </button>`;
+}
+
+/* ---------- hold-to-confirm mechanics ---------- */
+function attachHold(btnId, duration, onComplete){
+  const btn = document.getElementById(btnId);
+  if(!btn) return;
+  let raf=null, startTs=null, done=false;
+  function frame(ts){
+    if(startTs===null) startTs = ts;
+    const pct = Math.min(1, (ts-startTs)/duration);
+    btn.style.setProperty('--pct', (pct*100)+'%');
+    if(pct>=1 && !done){ done=true; setTimeout(onComplete, 100); }
+    else if(!done){ raf = requestAnimationFrame(frame); }
+  }
+  function start(e){ e.preventDefault(); if(done) return; startTs=null; btn.classList.add('holding'); raf=requestAnimationFrame(frame); }
+  function cancel(){ if(done) return; if(raf) cancelAnimationFrame(raf); startTs=null; btn.classList.remove('holding'); btn.style.setProperty('--pct','0%'); }
+  btn.addEventListener('pointerdown', start);
+  btn.addEventListener('pointerup', cancel);
+  btn.addEventListener('pointerleave', cancel);
+  btn.addEventListener('pointercancel', cancel);
+}
+function wirePickerSwipe(){
+  const el = document.querySelector('.picker-stack');
+  if(!el) return;
+  let startY = null;
+  el.addEventListener('touchstart', e=>{ startY = e.touches[0].clientY; }, {passive:true});
+  el.addEventListener('touchend', e=>{
+    if(startY===null) return;
+    const dy = e.changedTouches[0].clientY - startY;
+    if(Math.abs(dy) > 24) swipePicker(dy<0 ? 1 : -1);
+    startY = null;
+  }, {passive:true});
+}
+function wireInteractive(){
+  if(state.screen==='picker') wirePickerSwipe();
+  if(state.screen==='new-confirm') attachHold('holdNew', 600, completeNew);
+  if(state.screen==='update-confirm') attachHold('holdMatch', 600, confirmUpdateMatch);
+  if(state.screen==='update-save') attachHold('holdUpdateSave', 600, completeUpdateSave);
+  if(state.screen==='find-result') attachHold('holdFind', 600, confirmFindMatch);
+  if(state.screen==='sample-confirm') attachHold('holdSample', 600, confirmSampleReceived);
+}
+
+/* ---------- render ---------- */
+function render(){
+  const stage = document.getElementById('stage');
+  const panel = document.getElementById('panel');
+  let s = '', p = '';
+
+  if(state.screen==='live'){
+    s = stageLive();
+    p = `${panelHead('Point & shoot')}
+      <div class="panel-body">
+        <div class="shutter-wrap">
+          <button class="shutter" aria-label="Take photo" onclick="mainShoot()">📸</button>
+          <div class="shutter-caption">Tap the shutter — we'll ask what it's for</div>
+        </div>
+        <button class="drawer-tab" onclick="openFindDrawer()">🔎 Find an item <span class="chev">▲</span></button>
+      </div>`;
+  }
+
+  else if(state.screen==='picker'){
+    s = stageCaptured('What was that for?');
+    p = `${panelHead("Got it — what's this for?")}
+      <div class="panel-body">
+        <div class="picker-hint">↕ swipe or tap to pick</div>
+        <div class="picker-stack">${state.pickerOrder.map((j,i)=>pickerCardHTML(j, i===0)).join('')}</div>
+      </div>`;
+  }
+
+  else if(state.screen==='new-brand'){
+    s = stageCaptured('New item spotted');
+    p = `${miniFabHTML()}${panelHead('Which brand is it?')}
+      <div class="panel-body">
+        <div class="chip-row">${BRANDS.map(b=>`<button class="chip" onclick="chooseBrand('${b}')">${b}</button>`).join('')}</div>
+      </div>`;
+  }
+  else if(state.screen==='new-confirm'){
+    s = stageCaptured(state.brand || 'Ready to save');
+    p = `${miniFabHTML()}${panelHead('Save this item?')}
+      <div class="panel-body">${holdRingHTML('holdNew', 'HOLD<br>TO SAVE', 'Press and hold 0.6s to confirm')}</div>`;
+  }
+
+  else if(state.screen==='update-confirm'){
+    s = stageCaptured('Is this the item?');
+    p = `${miniFabHTML()}${panelHead('Confirm the match')}
+      <div class="panel-body">
+        ${holdRingHTML('holdMatch', "HOLD —<br>YES", 'Hold if this is the right item')}
+        <button class="linktext" onclick="mainShoot()">Not this — reshoot</button>
+      </div>`;
+  }
+  else if(state.screen==='update-shoot'){
+    s = stageViewfinder('Point at the replacement, then tap shutter.');
+    p = `${panelHead('Shoot the new photo')}
+      <div class="panel-body">
+        <div class="shutter-wrap">
+          <button class="shutter" aria-label="Take photo" onclick="shootUpdate()">📸</button>
+          <div class="shutter-caption">Tap the shutter to capture</div>
+        </div>
+      </div>`;
+  }
+  else if(state.screen==='update-save'){
+    s = stageCaptured('Ready to save the update');
+    p = `${miniFabHTML()}${panelHead('Save the update?')}
+      <div class="panel-body">${holdRingHTML('holdUpdateSave', 'HOLD<br>TO SAVE', 'Press and hold 0.6s to confirm')}</div>`;
+  }
+
+  else if(state.screen==='find-drawer'){
+    s = stageLive();
+    p = `${panelHead('Find an item')}
+      <div class="panel-body">
+        <button class="pbtn" onclick="startFind()">📷 Scan the Label</button>
+        <button class="pbtn" onclick="startFind()">🎤 Say the Name</button>
+        <button class="pbtn" onclick="startFind()">⌨️ Type It</button>
+      </div>`;
+  }
+  else if(state.screen==='find-result'){
+    state.item = MOCK_ITEMS[state.findIndex];
+    s = stageCaptured('Is this the one?');
+    p = `${miniFabHTML()}${panelHead('Confirm the item')}
+      <div class="panel-body">
+        ${holdRingHTML('holdFind', "HOLD —<br>IT'S THIS", 'Hold to confirm this match')}
+        <button class="linktext" onclick="nextFindResult()">Show Next Result</button>
+      </div>`;
+  }
+  else if(state.screen==='find-detail'){
+    s = stageCaptured('Confirmed match');
+    p = `${panelHead(state.item.name)}
+      <div class="panel-body">
+        <button class="pbtn pbtn-primary" onclick="updateFromFind()">Update This</button>
+        <button class="pbtn pbtn-secondary" onclick="go('find-drawer')">Search Again</button>
+      </div>`;
+  }
+
+  else if(state.screen==='sample-confirm'){
+    s = stageCaptured('Mark this sample received?');
+    p = `${miniFabHTML()}${panelHead('Sample received?')}
+      <div class="panel-body">${holdRingHTML('holdSample', 'HOLD TO<br>CONFIRM', 'Hold to mark it received')}</div>`;
+  }
+  else if(state.screen==='sample-printing'){
+    s = stageMessage('🖨️', 'Printing your sticker…', 'One sec…');
+    p = `${panelHead('Printing')}<div class="panel-body"></div>`;
+  }
+
+  if(state.toast) s += toastHTML();
+
+  stage.innerHTML = s;
+  panel.innerHTML = p;
+  wireInteractive();
+
+  if(state.toast && !state.toastTimer){
+    state.toastTimer = setTimeout(()=>{ state.toast=null; state.toastTimer=null; render(); }, 1800);
+  }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v16-widget-stack.html b/public/kid-simple/v16-widget-stack.html
new file mode 100644
index 0000000..9f055a7
--- /dev/null
+++ b/public/kid-simple/v16-widget-stack.html
@@ -0,0 +1,364 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v16 — Widget Stack</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Manrope:wght@400;500;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#F4EEE4; --card:#FFFFFF; --ink:#2B241D; --muted:#8A7F6F; --line:#E7DFD1;
+    --rust:#BD5B34; --teal:#2F6259; --plum:#5B3A5E; --gold:#C79A46; --green:#3F8F5F;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--bg); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; padding:22px 20px 26px; overflow-y:auto; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+  h1,h2{ margin:0; }
+  .question{
+    font-family:'Cormorant Garamond',serif; font-weight:700; font-size:26px; line-height:1.18;
+    text-align:center; margin:0 0 14px; color:var(--ink);
+  }
+  .rows{ display:flex; flex-direction:column; gap:12px; margin-top:14px; }
+  .bigbtn{
+    width:100%; min-height:56px; border-radius:18px; font-size:17px; font-weight:700;
+    background:#fff; border:2px solid var(--line); color:var(--ink); padding:12px 18px;
+  }
+  .bigbtn-primary{ background:var(--accent,var(--gold)); border:2px solid var(--accent,var(--gold)); color:#fff; }
+  .bigbtn-secondary{ background:#fff; border:2px solid var(--muted); color:var(--muted); }
+  .bigbtn:focus-visible, .linktext:focus-visible, .widget:focus-visible, .navchip:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{
+    background:none; border:none; color:var(--muted); font-size:15.5px; text-decoration:underline;
+    text-align:center; min-height:56px; width:100%;
+  }
+
+  /* ---------- Home: widget stack (collapsed) ---------- */
+  .topbar{ display:flex; align-items:baseline; justify-content:space-between; padding:6px 2px 18px; }
+  .dw{ font-family:'Cormorant Garamond',serif; font-weight:700; font-size:20px; letter-spacing:.02em; }
+  .today{ font-size:12px; color:var(--muted); font-weight:600; }
+  .widgetstack{ display:flex; flex-direction:column; gap:14px; }
+  .widget{
+    background:var(--card); border-radius:26px; padding:18px 18px 16px; box-shadow:0 8px 22px rgba(43,36,29,.08);
+    border:1px solid var(--line); text-align:left; transition:transform .12s ease; -webkit-tap-highlight-color:transparent;
+  }
+  .widget:active{ transform:scale(.98); }
+  .widget-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
+  .chip{
+    width:44px; height:44px; border-radius:14px; background:var(--accent); color:#fff; font-size:21px;
+    display:flex; align-items:center; justify-content:center; flex:none;
+  }
+  .widget-num{ font-family:'Cormorant Garamond',serif; font-weight:700; font-size:38px; color:var(--ink); }
+  .widget-thumb{ width:44px; height:44px; border-radius:12px; flex:none; }
+  .widget-label{ font-size:16px; font-weight:800; margin:2px 0 2px; }
+  .widget-sub{ font-size:13.5px; color:var(--muted); margin-bottom:14px; }
+  .widget-btn{
+    width:100%; min-height:56px; border-radius:14px; border:none; background:var(--accent); color:#fff;
+    font-size:15.5px; font-weight:800; letter-spacing:.01em;
+  }
+
+  .sw1{background:repeating-linear-gradient(45deg,#BD5B34 0 16px,#a04b29 16px 32px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#2F6259 0 14px,#254f47 14px 28px);}
+  .sw3{background:repeating-linear-gradient(90deg,#5B3A5E 0 14px,#48304a 14px 28px);}
+  .swatch{ width:100%; height:120px; border-radius:16px; margin-bottom:10px; }
+  .swatch.small{ height:90px; }
+
+  .itemname{ font-size:18px; font-weight:800; margin:0; text-align:center; }
+  .itemmeta{ font-size:14.5px; color:var(--muted); margin:4px 0 0; text-align:center; }
+
+  /* ---------- Expand-in-place: chip row for the OTHER widgets ---------- */
+  .chiprow{ display:flex; gap:10px; margin-bottom:14px; }
+  .navchip{
+    flex:1; min-height:56px; min-width:56px; border-radius:16px; background:#fff;
+    border:2px solid var(--line); border-top:4px solid var(--accent,var(--gold));
+    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
+    font-size:11px; font-weight:800; color:var(--ink); padding:6px 4px;
+  }
+  .navchip .navicon{ font-size:19px; line-height:1; }
+
+  /* ---------- The expanded widget card — job happens IN HERE ---------- */
+  .expandedcard{
+    background:var(--card); border-radius:26px; padding:18px 18px 20px; box-shadow:0 12px 30px rgba(43,36,29,.14);
+    border:2px solid var(--accent,var(--gold)); flex:1; display:flex; flex-direction:column;
+  }
+  .expandedcard .widget-top{ margin-bottom:6px; }
+  .dots{ display:flex; gap:6px; margin-left:auto; align-items:center; }
+  .dot{ width:8px; height:8px; border-radius:50%; background:var(--line); }
+  .dot.active{ background:var(--accent,var(--gold)); }
+  .stepbody{ margin-top:8px; display:flex; flex-direction:column; flex:1; }
+  .miniCenter{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:8px; text-align:center; }
+
+  /* inline camera viewport, lives INSIDE the card (not full-bleed) */
+  .camview{
+    background:#1c1c1e; position:relative; display:flex; align-items:center; justify-content:center;
+    color:#fff; min-height:200px; border-radius:20px; overflow:hidden; margin-bottom:4px;
+  }
+  .camview .hint{
+    position:absolute; top:18px; left:14px; right:14px; text-align:center;
+    font-family:'Cormorant Garamond',serif; font-size:20px; font-weight:700; color:#fdfbf7;
+  }
+  .camview .status{ font-size:15px; font-weight:700; color:#f0e8d8; }
+  .shutter{
+    position:absolute; bottom:16px; left:50%; transform:translateX(-50%);
+    width:72px; height:72px; border-radius:50%; background:var(--accent,var(--gold)); border:5px solid #fff;
+    font-size:26px; display:flex; align-items:center; justify-content:center;
+  }
+  .altrow{ display:flex; gap:10px; margin-top:12px; }
+  .altrow .linktext{ flex:1; border:2px solid var(--line); border-radius:14px; font-size:13.5px; text-decoration:none; font-weight:700; }
+  .brandrows{ display:flex; flex-direction:column; gap:10px; max-height:280px; overflow-y:auto; padding-right:2px; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const ACCENT = { new:'#C79A46', update:'#2F6259', find:'#5B3A5E', sample:'#BD5B34', home:'#8A7F6F' };
+const JOB_META = {
+  sample:{ icon:'📦', short:'Samples', title:'Log a Sample' },
+  update:{ icon:'🔄', short:'Updates', title:'Update an Item' },
+  new:   { icon:'🆕', short:'New',     title:'Add New Item' },
+  find:  { icon:'🔍', short:'Find',    title:'Find an Item' },
+};
+// Card-local step lists, per job — each job is a stack of IN-CARD steps, not full screens.
+const STEPS = {
+  sample:['cam','confirm','printing','done'],
+  update:['cam','confirm','cam2','done'],
+  new:   ['cam','brand','save','done'],
+  find:  ['cam','result','detail'],
+};
+
+let counts = { sample:3, update:2 };
+let lastAdded = { ...MOCK_ITEMS[0] };
+
+// state.expanded = which widget card is currently open in place (or null = home stack).
+// state.step = the CARD-LOCAL step within that widget. Nothing here is a full screen.
+const state = { expanded:null, step:null, item:null, brand:null, resultIndex:0, exhausted:false };
+
+function accentFor(job){ return ACCENT[job] || '#C79A46'; }
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+
+function openWidget(job){
+  state.expanded = job; state.item = null; state.brand = null; state.resultIndex = 0; state.exhausted = false;
+  state.step = 'cam'; // every job's first in-card step is always the camera
+  render();
+}
+function switchWidget(job){ openWidget(job); }
+function closeWidget(){ state.expanded = null; state.step = null; render(); }
+function go(step){ state.step = step; render(); }
+
+function shootInline(cb){
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(()=>{ state.item = state.item || randomItem(); cb(); }, 700);
+}
+function cameraCard(hint, onShoot){
+  return `<div class="camview">
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    <button class="shutter" aria-label="Take photo" onclick="${onShoot}">📸</button>
+  </div>`;
+}
+function dots(job){
+  const steps = STEPS[job]; const idx = steps.indexOf(state.step);
+  return `<div class="dots">${steps.map((s,i)=>`<span class="dot${i===idx?' active':''}"></span>`).join('')}</div>`;
+}
+
+/* ---------- job bodies: the job happens INSIDE the expanded card ---------- */
+function sampleBody(){
+  if(state.step==='cam') return cameraCard('Scan the box label.', "shootInline(()=>go('confirm'))");
+  if(state.step==='confirm') return `
+    <p class="itemname">${state.item.name} — ${state.item.color}</p>
+    <div class="swatch small ${state.item.sw}"></div>
+    <p class="itemmeta">code ${state.item.code}</p>
+    <div class="rows"><button class="bigbtn bigbtn-primary" onclick="go('printing')">Mark Received</button></div>`;
+  if(state.step==='printing') return `<div class="miniCenter"><p class="itemmeta">🖨️ Printing your sticker…</p></div>`;
+  if(state.step==='done'){
+    if(counts.sample>0) return `
+      <div class="miniCenter"><p class="itemname">Logged! ✅</p><p class="itemmeta">Samples Waiting: ${counts.sample}</p></div>
+      <div class="rows">
+        <button class="bigbtn bigbtn-primary" onclick="openWidget('sample')">Next sample (${counts.sample} left) →</button>
+        <button class="linktext" onclick="closeWidget()">Close</button>
+      </div>`;
+    return `
+      <div class="miniCenter"><p class="itemname">All caught up! 🎉</p><p class="itemmeta">No samples waiting.</p></div>
+      <div class="rows"><button class="bigbtn bigbtn-primary" onclick="closeWidget()">Close</button></div>`;
+  }
+}
+function finishSample(){ counts.sample = Math.max(0, counts.sample-1); state.step='done'; render(); }
+
+function updateBody(){
+  if(state.step==='cam') return cameraCard('Scan the label or pattern.', "shootInline(()=>go('confirm'))");
+  if(state.step==='confirm') return `
+    <p class="itemname">${state.item.name} — ${state.item.color}</p>
+    <div class="swatch small ${state.item.sw}"></div>
+    <p class="itemmeta">code ${state.item.code}</p>
+    <div class="rows">
+      <button class="bigbtn bigbtn-primary" onclick="go('cam2')">Yes, That's It</button>
+      <button class="bigbtn bigbtn-secondary" onclick="state.item=null; go('cam')">No, Scan Again</button>
+    </div>`;
+  if(state.step==='cam2') return cameraCard('Take the new photo.', "shootInline(()=>finishUpdate())");
+  if(state.step==='done') return `
+    <div class="miniCenter"><p class="itemname">Updated! ✅</p><p class="itemmeta">Need Updates: ${counts.update} left</p></div>
+    <div class="rows"><button class="bigbtn bigbtn-primary" onclick="closeWidget()">Close</button></div>`;
+}
+function finishUpdate(){ counts.update = Math.max(0, counts.update-1); state.step='done'; render(); }
+
+function newBody(){
+  if(state.step==='cam') return cameraCard('Take a photo of it.', "shootInline(()=>go('brand'))");
+  if(state.step==='brand') return `
+    <p class="question" style="font-size:20px;">Which brand?</p>
+    <div class="brandrows">${BRANDS.map(b=>`<button class="bigbtn" onclick="state.brand='${b}'; go('save')">${b}</button>`).join('')}</div>`;
+  if(state.step==='save') return `
+    <div class="swatch small ${state.item.sw}"></div>
+    <p class="itemmeta">${state.brand} · code ${state.item.code}</p>
+    <div class="rows">
+      <button class="bigbtn bigbtn-primary" onclick="finishNew()">Save as Draft</button>
+      <button class="linktext" onclick="go('cam')">Retake Photo</button>
+    </div>`;
+  if(state.step==='done') return `
+    <div class="miniCenter"><p class="itemname">Saved! 🎉</p><p class="itemmeta">${lastAdded.name} · ${lastAdded.color}</p></div>
+    <div class="rows">
+      <button class="bigbtn bigbtn-primary" onclick="openWidget('new')">Add Another</button>
+      <button class="linktext" onclick="closeWidget()">Close</button>
+    </div>`;
+}
+function finishNew(){ lastAdded = { ...state.item, brand: state.brand }; state.step='done'; render(); }
+
+function findBody(){
+  if(state.step==='cam') return `
+    ${cameraCard('Scan the label to find it.', "shootInline(()=>go('result'))")}
+    <div class="altrow">
+      <button class="linktext" onclick="state.item=randomItem(); go('result')">🎤 Say the Name</button>
+      <button class="linktext" onclick="state.item=randomItem(); go('result')">⌨️ Type It</button>
+    </div>`;
+  if(state.step==='result'){
+    if(state.exhausted) return `
+      <div class="miniCenter"><p class="itemname">That's everything.</p><p class="itemmeta">Try another way?</p></div>
+      <div class="altrow" style="margin-top:6px;">
+        <button class="linktext" onclick="state.exhausted=false; state.resultIndex=0; go('cam')">📷 Scan</button>
+        <button class="linktext" onclick="state.exhausted=false; state.resultIndex=0; state.item=randomItem(); go('result')">🎤 Say</button>
+        <button class="linktext" onclick="state.exhausted=false; state.resultIndex=0; state.item=randomItem(); go('result')">⌨️ Type</button>
+      </div>`;
+    const it = MOCK_ITEMS[state.resultIndex];
+    return `
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <div class="swatch small ${it.sw}"></div>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="rows">
+        <button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
+      </div>`;
+  }
+  if(state.step==='detail') return `
+    <div class="swatch small ${state.item.sw}"></div>
+    <p class="itemname">${state.item.name}</p>
+    <p class="itemmeta">${state.item.color} · code ${state.item.code}</p>
+    <div class="rows">
+      <button class="bigbtn bigbtn-primary" onclick="openWidgetForUpdateFromFind(state.item)">Update This</button>
+      <button class="bigbtn bigbtn-secondary" onclick="state.resultIndex=0; state.exhausted=false; go('cam')">Search Again</button>
+      <button class="linktext" onclick="closeWidget()">Close</button>
+    </div>`;
+}
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('detail'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; render(); }
+  else { state.exhausted = true; render(); }
+}
+// Cross-job jump: Find already knows the item, so Update skips straight to its "new photo" step.
+function openWidgetForUpdateFromFind(item){
+  state.expanded='update'; state.item=item; state.brand=null; state.resultIndex=0; state.exhausted=false;
+  state.step='cam2'; render();
+}
+
+function stepBody(){
+  if(state.expanded==='sample') return sampleBody();
+  if(state.expanded==='update') return updateBody();
+  if(state.expanded==='new')    return newBody();
+  if(state.expanded==='find')   return findBody();
+  return '';
+}
+
+function chipRowHtml(){
+  const jobs = ['sample','update','new','find'].filter(j=>j!==state.expanded);
+  return `<div class="chiprow">
+    <button class="navchip" style="--accent:${accentFor('home')}" onclick="closeWidget()"><span class="navicon">⌂</span><span>Home</span></button>
+    ${jobs.map(j=>`<button class="navchip" style="--accent:${accentFor(j)}" onclick="switchWidget('${j}')"><span class="navicon">${JOB_META[j].icon}</span><span>${JOB_META[j].short}</span></button>`).join('')}
+  </div>`;
+}
+function expandedCardHtml(){
+  return `<div class="expandedcard" style="--accent:${accentFor(state.expanded)}">
+    <div class="widget-top"><div class="chip">${JOB_META[state.expanded].icon}</div>${dots(state.expanded)}</div>
+    <div class="widget-label">${JOB_META[state.expanded].title}</div>
+    <div class="stepbody">${stepBody()}</div>
+  </div>`;
+}
+
+function homeHtml(){
+  return `
+    <div class="topbar"><span class="dw">Designer Wallcoverings</span><span class="today">Today · Updated now</span></div>
+    <div class="widgetstack">
+      <div class="widget widget-lg" style="--accent:${ACCENT.sample}" tabindex="0" role="button" onclick="openWidget('sample')">
+        <div class="widget-top"><div class="chip">📦</div><div class="widget-num">${counts.sample}</div></div>
+        <div class="widget-label">Samples Waiting</div>
+        <div class="widget-sub">Ready to scan &amp; log</div>
+        <button class="widget-btn" onclick="event.stopPropagation(); openWidget('sample')">Log a Sample →</button>
+      </div>
+
+      <div class="widget widget-md" style="--accent:${ACCENT.update}" tabindex="0" role="button" onclick="openWidget('update')">
+        <div class="widget-top"><div class="chip">🔄</div><div class="widget-num">${counts.update}</div></div>
+        <div class="widget-label">Need Updates</div>
+        <div class="widget-sub">New photos needed</div>
+        <button class="widget-btn" onclick="event.stopPropagation(); openWidget('update')">Update an Item →</button>
+      </div>
+
+      <div class="widget widget-md" style="--accent:${ACCENT.new}" tabindex="0" role="button" onclick="openWidget('new')">
+        <div class="widget-top"><div class="chip">🆕</div><div class="widget-thumb ${lastAdded.sw}"></div></div>
+        <div class="widget-label">Last Added</div>
+        <div class="widget-sub">${lastAdded.name} · ${lastAdded.color}</div>
+        <button class="widget-btn" onclick="event.stopPropagation(); openWidget('new')">Add New Item →</button>
+      </div>
+
+      <div class="widget widget-sm" style="--accent:${ACCENT.find}" tabindex="0" role="button" onclick="openWidget('find')">
+        <div class="widget-top"><div class="chip">🔍</div></div>
+        <div class="widget-label">Find an Item</div>
+        <div class="widget-sub">Search everything you've added</div>
+        <button class="widget-btn" onclick="event.stopPropagation(); openWidget('find')">Find an Item →</button>
+      </div>
+    </div>`;
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  s.style.setProperty('--accent', accentFor(state.expanded || 'home'));
+  let html = '';
+  if(!state.expanded){
+    html = homeHtml();
+  } else {
+    html = chipRowHtml() + expandedCardHtml();
+  }
+  s.innerHTML = html;
+  if(state.expanded==='sample' && state.step==='printing'){
+    setTimeout(()=>{ if(state.expanded==='sample' && state.step==='printing'){ finishSample(); } }, 900);
+  }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v2-four-tiles.html b/public/kid-simple/v2-four-tiles.html
new file mode 100644
index 0000000..3ad12c1
--- /dev/null
+++ b/public/kid-simple/v2-four-tiles.html
@@ -0,0 +1,588 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>v2 — Four Big Tiles</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600;700&family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --bg:#F7F3EC;
+    --add:#8FAE8B;
+    --update:#7C93B0;
+    --find:#C97B5B;
+    --sample:#9C6B1F;
+    --text:#2B2B2B;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#0a0a0a;font-family:'DM Sans',sans-serif;}
+  .stage{
+    width:390px;height:780px;margin:24px auto;position:relative;
+    background:var(--bg);border-radius:36px;overflow:hidden;
+    box-shadow:0 20px 60px rgba(0,0,0,.5);border:8px solid #000;color:var(--text);
+  }
+  .screen{position:absolute;inset:0;display:none;flex-direction:column;background:var(--bg);}
+  .screen.active{display:flex;}
+  h1,h2,h3{font-family:'Fraunces',serif;margin:0;color:var(--text);}
+  .pad{padding:8px 22px 22px;display:flex;flex-direction:column;gap:16px;flex:1;overflow-y:auto;}
+  .home-title{text-align:center;font-size:24px;margin:24px 0 0;}
+  .tile-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;padding:16px 20px;flex:1;}
+  .tile{
+    border-radius:20px;min-height:140px;display:flex;flex-direction:column;align-items:center;
+    justify-content:center;gap:10px;color:#fff;cursor:pointer;font-size:18px;font-weight:700;
+    text-align:center;padding:12px;border:none;
+  }
+  .tile:active, .btn:active, .thumb-card:active, .brand-tile:active, .nav-btn:active{transform:scale(.97);}
+  .tile:focus-visible, button:focus-visible, .thumb-card:focus-visible, .brand-tile:focus-visible, input:focus-visible{outline:3px solid #2B2B2B;outline-offset:3px;}
+  .btn:disabled{opacity:.4;cursor:not-allowed;}
+  .topbar{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 16px;flex-shrink:0;z-index:6;}
+  .nav-btn{
+    min-height:56px;min-width:56px;border-radius:14px;border:2px solid #ddd4c2;background:#fff;
+    font-size:17px;font-weight:600;cursor:pointer;color:var(--text);padding:0 16px;
+    display:flex;align-items:center;gap:6px;font-family:'DM Sans',sans-serif;
+  }
+  .camera-screen .nav-btn{background:rgba(255,255,255,.92);}
+  .step-indicator{padding:0 22px;font-size:16px;opacity:.7;flex-shrink:0;}
+  .tile .icon{font-size:44px;}
+  .tile.add{background:var(--add);}
+  .tile.update{background:var(--update);}
+  .tile.find{background:var(--find);}
+  .tile.sample{background:var(--sample);}
+
+  .camera-screen{background:#1c1c1e;color:#fff;position:relative;}
+  .camera-screen .hint{position:absolute;top:80px;left:0;right:0;text-align:center;font-size:17px;z-index:2;}
+  .viewfinder{position:absolute;inset:0;background:repeating-linear-gradient(135deg,#2a2a2c 0 40px,#1c1c1e 40px 80px);}
+  .shutter-wrap{position:absolute;bottom:48px;left:0;right:0;display:flex;justify-content:center;z-index:2;}
+  .shutter{
+    width:88px;height:88px;border-radius:50%;background:#fff;border:6px solid var(--sample);
+    font-size:36px;cursor:pointer;display:flex;align-items:center;justify-content:center;
+  }
+  .demo-toggle{position:absolute;bottom:150px;left:0;right:0;text-align:center;z-index:2;
+    font-size:14px;color:#fff;opacity:.75;display:flex;align-items:center;justify-content:center;gap:8px;}
+  .demo-toggle input{width:18px;height:18px;}
+
+  .btn{min-height:56px;border-radius:16px;border:none;font-family:'DM Sans',sans-serif;
+    font-size:18px;font-weight:700;cursor:pointer;padding:0 20px;width:100%;}
+  .btn-primary{background:var(--add);color:#fff;}
+  .btn-update{background:var(--update);color:#fff;}
+  .btn-find{background:var(--find);color:#fff;}
+  .btn-sample{background:var(--sample);color:#fff;}
+  .btn-secondary{background:#fff;color:var(--text);border:2px solid #ddd4c2;}
+
+  .actions{margin-top:auto;display:flex;flex-direction:column-reverse;gap:12px;padding-top:16px;}
+  .search-bar{background:#fff;border-radius:14px;padding:0 16px;border:2px solid #e6dfd2;display:flex;align-items:center;}
+  .search-bar input{border:none;background:none;font-size:17px;color:var(--text);padding:14px 6px;width:100%;font-family:'DM Sans',sans-serif;}
+  .search-bar input::placeholder{color:#6B6156;}
+  .section-label{font-size:14px;opacity:.65;text-transform:uppercase;letter-spacing:.5px;}
+  .brand-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
+  .brand-tile{
+    background:#fff;border:2px solid #e6dfd2;border-radius:14px;min-height:72px;
+    display:flex;align-items:center;justify-content:center;font-size:17px;font-weight:600;
+    cursor:pointer;text-align:center;padding:8px;
+  }
+  .brand-tile:hover{border-color:var(--add);}
+  .brand-tile.selected{border-color:var(--add);background:#eef5ec;box-shadow:inset 0 0 0 2px var(--add);}
+  .brand-tile.hidden{display:none;}
+
+  .card{background:#fff;border-radius:18px;padding:20px;box-shadow:0 4px 16px rgba(0,0,0,.08);}
+  .swatch{
+    width:100%;height:180px;border-radius:14px;margin-bottom:12px;
+    background:repeating-linear-gradient(45deg,#8FAE8B 0 22px,#B9CBB2 22px 44px),linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;
+  }
+  .swatch.blue{background:repeating-linear-gradient(45deg,#7C93B0 0 22px,#B3C3D6 22px 44px),linear-gradient(135deg,#7C93B0,#5f7692);background-blend-mode:multiply;}
+  .swatch.small{height:120px;}
+  .thumb{width:96px;height:96px;border-radius:12px;flex-shrink:0;
+    background:repeating-linear-gradient(45deg,#8FAE8B 0 16px,#B9CBB2 16px 32px),linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;}
+  .item-title{font-size:20px;font-weight:700;}
+  .item-sub{font-size:17px;color:#6B6156;}
+
+  .center-flex{align-items:center;justify-content:center;text-align:center;}
+  .big-emoji{font-size:60px;}
+
+  .thumb-list{display:flex;flex-direction:column;gap:12px;overflow-y:auto;}
+  .thumb-card{
+    display:flex;gap:12px;background:#fff;border-radius:14px;padding:10px;border:2px solid #e6dfd2;
+    cursor:pointer;align-items:center;min-height:56px;
+  }
+  .thumb-sw{width:64px;height:64px;border-radius:10px;flex-shrink:0;
+    background:repeating-linear-gradient(45deg,#C97B5B 0 14px,#e0a184 14px 28px);}
+  .thumb-text .item-title{font-size:16px;}
+  .done-row{display:flex;gap:14px;align-items:center;}
+  .done-facts{font-size:17px;line-height:1.5;}
+  .done-facts strong{font-size:18px;}
+  .toast{
+    position:absolute;left:16px;right:16px;bottom:24px;background:#2B2B2B;color:#fff;
+    border-radius:14px;padding:14px 18px;display:none;align-items:center;justify-content:space-between;
+    gap:12px;box-shadow:0 8px 24px rgba(0,0,0,.35);z-index:20;font-size:17px;border:2px solid var(--sample);
+  }
+  .toast.show{display:flex;}
+  .toast button{background:none;border:none;color:#F4D48A;font-weight:700;font-size:17px;cursor:pointer;min-height:56px;min-width:56px;padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    *{transition:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="stage">
+
+  <!-- HOME -->
+  <div class="screen active" id="home">
+    <div class="home-title">What are we doing?</div>
+    <div class="tile-grid">
+      <button class="tile add" onclick="go('addCamera')"><span class="icon">🆕</span>Add New Item</button>
+      <button class="tile update" onclick="go('updateCamera1')"><span class="icon">🔄</span>Update an Item</button>
+      <button class="tile find" onclick="go('findMethods')"><span class="icon">🔍</span>Find an Item</button>
+      <button class="tile sample" onclick="go('sampleCamera')"><span class="icon">📦</span>A Sample Came In</button>
+    </div>
+  </div>
+
+  <!-- ADD: CAMERA -->
+  <div class="screen camera-screen" id="addCamera">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="hint">Take a photo of the sample</div>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap"><button class="shutter" onclick="showPhotoCheck('addBrand')" aria-label="Shoot photo">📸</button></div>
+  </div>
+
+  <!-- PHOTO CHECK (generic) -->
+  <div class="screen center-flex" id="photoCheck">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad center-flex">
+      <div class="thumb" id="photoCheckThumb" style="width:200px;height:200px;"></div>
+      <p style="font-size:18px;" aria-live="polite">Looks good?</p>
+      <div class="actions">
+        <button class="btn btn-primary" onclick="photoLooksGood()">Looks good</button>
+        <button class="btn btn-secondary" onclick="goBack()">Retake</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- ADD: BRAND GRID -->
+  <div class="screen" id="addBrand">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h3>Which brand?</h3>
+      <div class="search-bar"><input type="text" id="brandSearch" placeholder="Search brands…" oninput="filterBrands()" aria-label="Search brands"></div>
+      <div class="section-label">Recent</div>
+      <div class="brand-grid" id="recentBrands">
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'York')" onkeydown="onBrandKey(event,this,'York')">York</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Kravet')" onkeydown="onBrandKey(event,this,'Kravet')">Kravet</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Thibaut')" onkeydown="onBrandKey(event,this,'Thibaut')">Thibaut</div>
+      </div>
+      <div class="section-label">All Brands</div>
+      <div class="brand-grid" id="allBrands">
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Brewster')" onkeydown="onBrandKey(event,this,'Brewster')">Brewster</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Cole &amp; Son')" onkeydown="onBrandKey(event,this,'Cole &amp; Son')">Cole &amp; Son</div>
+        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Mulberry')" onkeydown="onBrandKey(event,this,'Mulberry')">Mulberry</div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-primary" id="saveDraftBtn" disabled onclick="saveDraft()">Save as Draft</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- GENERIC DONE -->
+  <div class="screen center-flex" id="doneScreen">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <div class="done-row">
+        <div class="thumb" id="doneThumb"></div>
+        <div class="done-facts">
+          <strong id="doneTitle"></strong><br>
+          code <span id="doneCode"></span> · <span id="doneBrand"></span><br>
+          <span id="doneAction"></span>
+        </div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-primary" id="doneRepeatBtn" onclick="goHome()">Do Another</button>
+        <button class="btn btn-secondary" onclick="goHome()">Home</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: CAMERA 1 -->
+  <div class="screen camera-screen" id="updateCamera1">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="step-indicator" style="color:#fff;opacity:.75;">Step 1 of 2</div>
+    <div class="hint">Take a photo of the label or pattern</div>
+    <label class="demo-toggle"><input type="checkbox" id="demoToggle" onchange="setDemoToggle(this.checked)"> Demo: show "no match"</label>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap"><button class="shutter" onclick="showPhotoCheck('afterUpdateShot')" aria-label="Shoot photo">📸</button></div>
+  </div>
+
+  <!-- UPDATE: MATCH CARD -->
+  <div class="screen" id="updateMatch">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="step-indicator">Step 1 of 2</div>
+    <div class="pad">
+      <div class="card">
+        <div class="swatch blue"></div>
+        <div class="item-title">Palm Damask — Sage</div>
+        <div class="item-sub">code DW-10423 · York</div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-update" onclick="go('updateCamera2')">Yes, this one</button>
+        <button class="btn btn-secondary" onclick="go('updateTyping')">Search by typing instead</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: TYPE SEARCH FALLBACK -->
+  <div class="screen" id="updateTyping">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h2>Type the item name or code</h2>
+      <div class="search-bar"><input type="text" id="updateTypeInput" placeholder="Palm Damask…" aria-label="Type the item name or code"></div>
+      <div class="actions">
+        <button class="btn btn-update" onclick="go('updateCamera2')">Found It</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: NO MATCH -->
+  <div class="screen center-flex" id="updateNoMatch">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad center-flex">
+      <div class="big-emoji">🤔</div>
+      <h2 aria-live="polite">No match found</h2>
+      <div class="actions">
+        <button class="btn btn-update" onclick="go('updateCamera1')">Try again</button>
+        <button class="btn btn-secondary" onclick="go('updateTyping')">Type the code instead</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- UPDATE: CAMERA 2 -->
+  <div class="screen camera-screen" id="updateCamera2">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="step-indicator" style="color:#fff;opacity:.75;">Step 2 of 2</div>
+    <div class="hint">Take the new photo</div>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap"><button class="shutter" onclick="showPhotoCheck('updateSave')" aria-label="Shoot new photo">📸</button></div>
+  </div>
+
+  <!-- FIND: METHODS -->
+  <div class="screen" id="findMethods">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h3>How do you want to find it?</h3>
+      <button class="btn btn-find" onclick="findScan()">📷 Scan the Label</button>
+      <button class="btn btn-find" onclick="go('findResults')">🎤 Say the Name</button>
+      <button class="btn btn-find" onclick="go('findResults')">⌨️ Type It</button>
+      <label style="font-size:14px;opacity:.7;display:flex;align-items:center;gap:8px;margin-top:8px;">
+        <input type="checkbox" id="demoToggleFind" onchange="setDemoToggle(this.checked)" style="width:18px;height:18px;"> Demo: show "no match"
+      </label>
+    </div>
+  </div>
+
+  <!-- FIND: SCAN CAMERA -->
+  <div class="screen camera-screen" id="findCamera">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="hint">Scan the label</div>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap"><button class="shutter" onclick="showPhotoCheck('findResults')" aria-label="Scan label">📸</button></div>
+  </div>
+
+  <!-- FIND: RESULTS -->
+  <div class="screen" id="findResults">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h3 aria-live="polite">Results</h3>
+      <div class="thumb-list" id="findResultsList"></div>
+      <div id="findNoResults" style="display:none;" class="center-flex">
+        <div class="big-emoji">🤔</div>
+        <h2>No match found</h2>
+        <div class="actions">
+          <button class="btn btn-find" onclick="go('findMethods')">Try again</button>
+          <button class="btn btn-secondary" onclick="go('findTyping')">Type the code instead</button>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- FIND: TYPE CODE (no-match fallback) -->
+  <div class="screen" id="findTyping">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h3>Type the item's code</h3>
+      <div class="search-bar"><input type="text" placeholder="e.g. DW-10423" aria-label="Type the item code"></div>
+      <div class="actions">
+        <button class="btn btn-find" onclick="go('findDetail')">Find It</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- FIND: DETAIL -->
+  <div class="screen" id="findDetail">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <div class="card">
+        <div class="swatch"></div>
+        <div class="item-title" id="findDetailTitle">Palm Damask — Sage</div>
+        <div class="item-sub" id="findDetailSub">code DW-10423 · York</div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-update" onclick="go('updateCamera2')">Update This</button>
+        <button class="btn btn-secondary" onclick="go('findMethods')">Back to Search</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: CAMERA -->
+  <div class="screen camera-screen" id="sampleCamera">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="hint">Scan the label on the box</div>
+    <label class="demo-toggle"><input type="checkbox" id="demoToggleSample" onchange="setDemoToggle(this.checked)"> Demo: show "no match"</label>
+    <div class="viewfinder"></div>
+    <div class="shutter-wrap"><button class="shutter" onclick="showPhotoCheck('afterSampleShot')" aria-label="Scan box">📸</button></div>
+  </div>
+
+  <!-- SAMPLE: MATCH -->
+  <div class="screen" id="sampleMatch">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <div class="card">
+        <div class="swatch small"></div>
+        <div class="item-title">Palm Damask — Sage</div>
+        <div class="item-sub">code DW-10423 · York</div>
+      </div>
+      <div class="actions">
+        <button class="btn btn-sample" onclick="markReceived()">Yes, Mark Received</button>
+        <button class="btn btn-secondary" onclick="go('sampleNoMatch')">Not this item</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: NO MATCH -->
+  <div class="screen center-flex" id="sampleNoMatch">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad center-flex">
+      <div class="big-emoji">🤔</div>
+      <h2 aria-live="polite">No match found</h2>
+      <div class="actions">
+        <button class="btn btn-sample" onclick="go('sampleCamera')">Try again</button>
+        <button class="btn btn-secondary" onclick="go('sampleTyping')">Type the code instead</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: TYPE CODE -->
+  <div class="screen" id="sampleTyping">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad">
+      <h3>Type the item's code</h3>
+      <div class="search-bar"><input type="text" placeholder="e.g. DW-10423" aria-label="Type the item code"></div>
+      <div class="actions">
+        <button class="btn btn-sample" onclick="markReceived()">Find It</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- SAMPLE: PRINTING -->
+  <div class="screen center-flex camera-screen" id="samplePrinting">
+    <div class="topbar"><button class="nav-btn" onclick="goBack()" aria-label="Back">‹ Back</button><button class="nav-btn" onclick="goHome()" aria-label="Home">⌂ Home</button></div>
+    <div class="pad center-flex">
+      <div class="big-emoji">🖨️</div>
+      <p style="font-size:18px;" aria-live="polite">Printing sticker…</p>
+    </div>
+  </div>
+
+</div>
+
+<!-- TOAST (undo) -->
+<div class="toast" id="toast" role="status" aria-live="polite">
+  <span id="toastText">Saved</span>
+  <button onclick="undoAction()">Undo</button>
+</div>
+
+<script>
+  let historyStack = ['home'];
+  let selectedBrand = null;
+  let demoNoMatch = false;
+  let photoCheckNext = null;
+  let toastTimer = null;
+  let undoTarget = null;
+  let findResultCounter = 0;
+
+  function render(id){
+    document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
+    document.getElementById(id).classList.add('active');
+  }
+
+  function go(id){
+    historyStack.push(id);
+    render(id);
+    onEnter(id);
+  }
+
+  function goBack(){
+    if(historyStack.length > 1){
+      historyStack.pop();
+      render(historyStack[historyStack.length - 1]);
+    } else {
+      goHome();
+    }
+  }
+
+  function goHome(){ historyStack = ['home']; render('home'); }
+
+  function onEnter(id){
+    if(id === 'addBrand'){
+      selectedBrand = null;
+      document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
+      document.getElementById('saveDraftBtn').disabled = true;
+      document.getElementById('brandSearch').value = '';
+      filterBrands();
+    }
+    if(id === 'findResults'){ renderFindResults(); }
+    if(id === 'updateCamera1' || id === 'findMethods' || id === 'sampleCamera'){ syncDemoToggles(); }
+  }
+
+  // the three demo "no match" checkboxes all reflect ONE shared boolean
+  function setDemoToggle(checked){
+    demoNoMatch = checked;
+    syncDemoToggles();
+  }
+  function syncDemoToggles(){
+    ['demoToggle','demoToggleFind','demoToggleSample'].forEach(function(id){
+      const el = document.getElementById(id);
+      if(el) el.checked = demoNoMatch;
+    });
+  }
+
+  function showPhotoCheck(nextId){
+    photoCheckNext = nextId;
+    go('photoCheck');
+  }
+
+  function photoLooksGood(){
+    historyStack.pop(); // drop photoCheck
+    if(photoCheckNext === 'afterUpdateShot'){ afterUpdateShot(); return; }
+    if(photoCheckNext === 'afterSampleShot'){ afterSampleShot(); return; }
+    if(photoCheckNext === 'updateSave'){ updateSave(); return; }
+    if(photoCheckNext === 'findResults'){ go('findResults'); return; }
+    go(photoCheckNext);
+  }
+
+  function afterUpdateShot(){
+    demoNoMatch ? go('updateNoMatch') : go('updateMatch');
+  }
+  function afterSampleShot(){
+    demoNoMatch ? go('sampleNoMatch') : go('sampleMatch');
+  }
+
+  function findScan(){ go('findCamera'); }
+
+  function renderFindResults(){
+    const list = document.getElementById('findResultsList');
+    const empty = document.getElementById('findNoResults');
+    findResultCounter++;
+    const miss = demoNoMatch;
+    if(miss){
+      list.style.display = 'none';
+      empty.style.display = 'flex';
+      return;
+    }
+    list.style.display = 'flex';
+    empty.style.display = 'none';
+    const items = [
+      {name:'Palm Damask — Sage', code:'DW-10423', brand:'York', bg:'repeating-linear-gradient(45deg,#C97B5B 0 14px,#e0a184 14px 28px)'},
+      {name:'Meadow Stripe — Gold', code:'DW-20115', brand:'Kravet', bg:'repeating-linear-gradient(45deg,#B8842A 0 14px,#eec076 14px 28px)'},
+      {name:'Coastal Weave — Blue', code:'DW-30871', brand:'Thibaut', bg:'repeating-linear-gradient(45deg,#7C93B0 0 14px,#a9bcd3 14px 28px)'},
+    ];
+    list.innerHTML = '';
+    items.forEach(it=>{
+      const card = document.createElement('div');
+      card.className = 'thumb-card';
+      card.tabIndex = 0;
+      card.setAttribute('role','button');
+      card.innerHTML = '<div class="thumb-sw" style="background:'+it.bg+';"></div><div class="thumb-text"><div class="item-title">'+it.name+'</div><div class="item-sub">code '+it.code+'</div></div>';
+      card.onclick = () => {
+        document.getElementById('findDetailTitle').textContent = it.name;
+        document.getElementById('findDetailSub').textContent = 'code ' + it.code + ' · ' + it.brand;
+        go('findDetail');
+      };
+      list.appendChild(card);
+    });
+  }
+
+  function selectBrand(el, name){
+    document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
+    el.classList.add('selected');
+    selectedBrand = name;
+    document.getElementById('saveDraftBtn').disabled = false;
+  }
+
+  function onBrandKey(evt, el, name){
+    if(evt.key === 'Enter' || evt.key === ' '){
+      evt.preventDefault();
+      selectBrand(el, name);
+    }
+  }
+
+  function filterBrands(){
+    const q = document.getElementById('brandSearch').value.trim().toLowerCase();
+    document.querySelectorAll('#allBrands .brand-tile').forEach(t=>{
+      t.classList.toggle('hidden', q.length > 0 && !t.textContent.toLowerCase().includes(q));
+    });
+  }
+
+  function randomCode(){ return 'DW-' + Math.floor(10000 + Math.random() * 89999); }
+
+  function showDone(opts){
+    document.getElementById('doneThumb').className = 'thumb' + (opts.blue ? ' blue' : '');
+    document.getElementById('doneTitle').textContent = opts.name;
+    document.getElementById('doneCode').textContent = opts.code;
+    document.getElementById('doneBrand').textContent = opts.brand;
+    document.getElementById('doneAction').textContent = opts.action;
+    historyStack = ['home', 'doneScreen'];
+    render('doneScreen');
+  }
+
+  function saveDraft(){
+    if(!selectedBrand) return;
+    showToast('Saved · Undo', 'addBrand');
+    showDone({name:'New Item', code: randomCode(), brand: selectedBrand, action:'Saved as a draft'});
+  }
+
+  function updateSave(){
+    showToast('Saved · Undo', 'updateMatch');
+    showDone({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Updated the photo', blue:true});
+  }
+
+  function markReceived(){
+    go('samplePrinting');
+    var fromScreen = 'samplePrinting';
+    setTimeout(function(){
+      if(historyStack[historyStack.length - 1] !== fromScreen) return;
+      showToast('Saved · Undo', 'sampleMatch');
+      showDone({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Marked as received'});
+    }, 1100);
+  }
+
+  function showToast(text, backTarget){
+    document.getElementById('toastText').textContent = text;
+    undoTarget = backTarget;
+    const t = document.getElementById('toast');
+    t.classList.add('show');
+    clearTimeout(toastTimer);
+    toastTimer = setTimeout(function(){ t.classList.remove('show'); }, 5000);
+  }
+
+  function undoAction(){
+    document.getElementById('toast').classList.remove('show');
+    clearTimeout(toastTimer);
+    if(undoTarget){
+      historyStack = ['home', undoTarget];
+      render(undoTarget);
+      // NOTE: do NOT call onEnter() here — undo must restore the confirm
+      // screen with the prior selection intact, not reset it (onEnter('addBrand')
+      // clears selectedBrand for a fresh forward-navigation entry only).
+    }
+  }
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v3-text-buddy.html b/public/kid-simple/v3-text-buddy.html
new file mode 100644
index 0000000..95d45af
--- /dev/null
+++ b/public/kid-simple/v3-text-buddy.html
@@ -0,0 +1,551 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>v3 — Text Buddy</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --paper:#EFEAE3;
+    --gold:#C9A24B;
+    --sage:#DCE8DA;
+    --text:#2B2B2B;
+    --muted:#6B6255;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#0a0a0a;font-family:'Inter',sans-serif;}
+  .stage{
+    width:390px;height:780px;margin:24px auto;position:relative;
+    background:var(--paper);border-radius:36px;overflow:hidden;
+    box-shadow:0 20px 60px rgba(0,0,0,.5);border:8px solid #000;color:var(--text);
+    display:flex;flex-direction:column;
+  }
+  header{
+    display:flex;flex-direction:column;gap:8px;
+    padding:14px 16px 10px;border-bottom:1px solid #ded6c8;background:var(--paper);flex-shrink:0;
+  }
+  .header-top{display:flex;align-items:center;justify-content:space-between;}
+  header .wordmark{font-family:'Fraunces',serif;font-weight:700;font-size:18px;}
+  header .sam-label{font-size:14px;color:var(--muted);margin-top:2px;}
+  .header-actions{display:flex;gap:10px;}
+  .nav-btn{
+    flex:1;min-height:56px;background:#fff;border:2px solid #ded6c8;border-radius:14px;padding:0 10px;
+    font-size:17px;font-weight:600;cursor:pointer;color:var(--text);font-family:'Inter',sans-serif;
+  }
+  .nav-btn:disabled{opacity:.4;cursor:not-allowed;}
+  .nav-btn:focus-visible, .chip:focus-visible, .thumb-card:focus-visible, .result-card:focus-visible, input:focus-visible{outline:3px solid var(--gold);outline-offset:2px;}
+  .nav-btn:active, .chip:active, .result-card:active, .cam-bubble:active{transform:scale(.97);}
+  .demo-toggle-inline{font-size:14px;color:var(--muted);display:flex;align-items:center;gap:8px;}
+  .demo-toggle-inline input{width:18px;height:18px;}
+  #thread{
+    flex:1;overflow-y:auto;padding:18px 16px 24px;display:flex;flex-direction:column;gap:12px;
+  }
+  .bubble{
+    max-width:78%;padding:14px 16px;border-radius:16px;font-size:17px;line-height:1.4;
+  }
+  .sam{
+    align-self:flex-start;background:#fff;border-left:5px solid var(--gold);
+    border-radius:4px 16px 16px 16px;
+  }
+  .user{
+    align-self:flex-end;background:var(--sage);border-radius:16px 4px 16px 16px;
+  }
+  .step-note{align-self:flex-start;font-size:14px;color:var(--muted);padding:0 4px;}
+  .chips{display:flex;flex-wrap:wrap;gap:10px;align-self:flex-start;max-width:92%;}
+  .chip{
+    min-height:56px;padding:0 18px;border-radius:20px;background:#fff;border:2px solid var(--gold);
+    color:var(--text);font-size:17px;font-weight:600;cursor:pointer;
+  }
+  .cam-bubble{
+    align-self:flex-start;background:#fff;border:2px dashed var(--gold);border-radius:16px;
+    padding:18px;display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;
+    min-width:180px;min-height:56px;
+  }
+  .cam-bubble .cam-icon{font-size:40px;}
+  .cam-bubble .cam-label{font-size:17px;color:var(--muted);}
+  .swatch-bubble{
+    align-self:flex-end;width:180px;height:130px;border-radius:14px;
+    background:repeating-linear-gradient(45deg,#8FAE8B 0 20px,#B9CBB2 20px 40px),linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;
+  }
+  .result-card{
+    align-self:flex-start;display:flex;gap:10px;background:#fff;border-radius:14px;padding:10px;
+    border:2px solid #ded6c8;cursor:pointer;max-width:88%;align-items:center;min-height:56px;
+  }
+  .result-card .thumb{width:56px;height:56px;border-radius:10px;flex-shrink:0;
+    background:repeating-linear-gradient(45deg,#C97B5B 0 12px,#e0a184 12px 24px);}
+  .result-card .rc-title{font-size:16px;font-weight:700;}
+  .result-card .rc-sub{font-size:17px;color:var(--muted);}
+  .full-item{
+    align-self:flex-start;background:#fff;border-radius:16px;padding:14px;border:2px solid #ded6c8;max-width:88%;
+  }
+  .full-item .swatch{width:100%;height:150px;border-radius:12px;margin-bottom:10px;
+    background:repeating-linear-gradient(45deg,#8FAE8B 0 20px,#B9CBB2 20px 40px),linear-gradient(135deg,#8FAE8B,#6f8d6c);
+    background-blend-mode:multiply;}
+  .full-item .swatch.blue{background:repeating-linear-gradient(45deg,#7C93B0 0 20px,#B3C3D6 20px 40px),linear-gradient(135deg,#7C93B0,#5f7692);background-blend-mode:multiply;}
+  .full-item .rc-title{font-size:18px;font-weight:700;}
+  .full-item .rc-sub{font-size:17px;color:var(--muted);}
+  .search-mock{
+    align-self:flex-start;background:#fff;border-radius:14px;padding:14px 16px;font-size:17px;
+    color:var(--muted);border:2px solid #ded6c8;min-width:220px;
+  }
+  .text-input{
+    width:100%;border:none;outline:none;font-size:17px;font-family:'Inter',sans-serif;
+    background:transparent;color:var(--text);min-height:24px;
+  }
+  .spinner-inline{display:inline-block;width:16px;height:16px;border-radius:50%;
+    border:3px solid rgba(0,0,0,.12);border-top-color:var(--gold);animation:spin 1s linear infinite;margin-right:8px;vertical-align:-3px;}
+  @keyframes spin{to{transform:rotate(360deg);}}
+  .toast{
+    position:absolute;left:16px;right:16px;bottom:16px;background:#2B2B2B;color:#fff;
+    border-radius:14px;padding:14px 18px;display:none;align-items:center;justify-content:space-between;
+    gap:12px;box-shadow:0 8px 24px rgba(0,0,0,.35);z-index:20;font-size:17px;border:2px solid var(--gold);
+  }
+  .toast.show{display:flex;}
+  .toast button{background:none;border:none;color:#F4D48A;font-weight:700;font-size:17px;cursor:pointer;min-height:56px;min-width:56px;padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    .spinner-inline{animation:none;border-top-color:var(--gold);}
+    *{transition:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="stage">
+  <header>
+    <div class="header-top">
+      <div>
+        <div class="wordmark">DW</div>
+        <div class="sam-label">chatting with Sam</div>
+      </div>
+    </div>
+    <div class="header-actions">
+      <button class="nav-btn" id="undoBtn" onclick="undoLast()" aria-label="Undo last">‹ Undo last</button>
+      <button class="nav-btn" onclick="resetChat()" aria-label="New chat">⌂ New chat</button>
+    </div>
+    <label class="demo-toggle-inline"><input type="checkbox" id="demoToggle" onchange="demoNoMatch=this.checked"> Demo: show "no match"</label>
+  </header>
+  <div id="thread" aria-live="polite"></div>
+</div>
+
+<!-- TOAST (undo) -->
+<div class="toast" id="toast" role="status" aria-live="polite">
+  <span id="toastText">Saved</span>
+  <button onclick="toastUndo()">Undo</button>
+</div>
+
+<script>
+  const thread = document.getElementById('thread');
+  let demoNoMatch = false;
+  let stepStack = [];
+  let toastTimer = null;
+
+  function scrollBottom(){ thread.scrollTop = thread.scrollHeight; }
+
+  function setUndoEnabled(){
+    document.getElementById('undoBtn').disabled = stepStack.length === 0;
+  }
+
+  // Anything "awaiting a tap" (chips, camera prompt, brand picker, result list,
+  // type-a-code box) is tagged .pending-ui. pushStep always clears it first, so
+  // both a real click AND an undo-replay land on a clean, non-duplicated screen.
+  function clearPendingUI(){
+    document.querySelectorAll('#thread .pending-ui').forEach(el => el.remove());
+  }
+
+  function pushStep(fn){
+    clearPendingUI();
+    fn();
+    stepStack.push(fn);
+    setUndoEnabled();
+  }
+
+  function undoLast(){
+    if(stepStack.length === 0) return;
+    hideToast();
+    stepStack.pop();
+    const keep = stepStack;
+    stepStack = [];
+    thread.innerHTML = '';
+    startHome();
+    keep.forEach(pushStep);
+    setUndoEnabled();
+  }
+
+  function toastUndo(){ undoLast(); }
+
+  function resetChat(){
+    hideToast();
+    stepStack = [];
+    thread.innerHTML = '';
+    startHome();
+    setUndoEnabled();
+  }
+
+  function addSam(text){
+    const el = document.createElement('div');
+    el.className = 'bubble sam';
+    el.innerHTML = text;
+    thread.appendChild(el);
+    scrollBottom();
+    return el;
+  }
+  function addUser(text){
+    const el = document.createElement('div');
+    el.className = 'bubble user';
+    el.innerHTML = text;
+    thread.appendChild(el);
+    scrollBottom();
+    return el;
+  }
+  function addStepNote(text){
+    const el = document.createElement('div');
+    el.className = 'step-note';
+    el.textContent = text;
+    thread.appendChild(el);
+    scrollBottom();
+  }
+  function addChips(options){
+    const wrap = document.createElement('div');
+    wrap.className = 'chips pending-ui';
+    options.forEach(opt => {
+      const b = document.createElement('button');
+      b.className = 'chip';
+      b.textContent = opt.label;
+      b.onclick = () => pushStep(opt.action);
+      wrap.appendChild(b);
+    });
+    thread.appendChild(wrap);
+    scrollBottom();
+    return wrap;
+  }
+  function addCameraBubble(onShot){
+    function showCameraStep(){
+      const el = document.createElement('div');
+      el.className = 'cam-bubble pending-ui';
+      el.setAttribute('role','button');
+      el.tabIndex = 0;
+      el.innerHTML = '<div class="cam-icon">📸</div><div class="cam-label">Tap to shoot</div>';
+      // shoot is a recorded step (pushStep, not a bare onclick) so tapping the
+      // shutter has its own undo point. Its "Looks good"/"Retake" actions never
+      // hold onto a closed-over DOM node — they re-query the live tree by the
+      // '.shot-pending' marker at click time, so a replay (which rebuilds the
+      // #thread DOM from scratch) never touches a node from a destroyed tree.
+      const shoot = () => {
+        const photo = addUser('<div class="swatch-bubble"></div>');
+        photo.classList.add('shot-pending');
+        const looking = addSam('<span class="spinner-inline"></span>Looking…');
+        setTimeout(() => {
+          looking.remove();
+          addSam("Here's what I got — good?");
+          addChips([
+            {label:'Looks good', action: () => {
+              const p = thread.querySelector('.shot-pending');
+              if(p) p.classList.remove('shot-pending');
+              onShot();
+            }},
+            {label:'Retake', action: () => {
+              const p = thread.querySelector('.shot-pending');
+              if(p) p.remove();
+              showCameraStep();
+            }},
+          ]);
+        }, 900);
+      };
+      el.onclick = () => pushStep(shoot);
+      el.onkeydown = (e) => { if(e.key === 'Enter' || e.key === ' '){ e.preventDefault(); pushStep(shoot); } };
+      thread.appendChild(el);
+      scrollBottom();
+    }
+    showCameraStep();
+  }
+  function addDoneCard(opts){
+    const el = document.createElement('div');
+    el.className = 'full-item';
+    el.innerHTML = '<div class="swatch'+(opts.blue ? ' blue' : '')+'"></div>'+
+      '<div class="rc-title">'+opts.name+'</div>'+
+      '<div class="rc-sub">code '+opts.code+' · '+opts.brand+'</div>'+
+      '<div class="rc-sub" style="margin-top:6px;">'+opts.action+'</div>';
+    thread.appendChild(el);
+    scrollBottom();
+  }
+  function randomCode(){ return 'DW-' + Math.floor(10000 + Math.random() * 89999); }
+
+  function showToast(text){
+    document.getElementById('toastText').textContent = text;
+    const t = document.getElementById('toast');
+    t.classList.add('show');
+    clearTimeout(toastTimer);
+    toastTimer = setTimeout(hideToast, 5000);
+  }
+  function hideToast(){
+    document.getElementById('toast').classList.remove('show');
+    clearTimeout(toastTimer);
+  }
+
+  function startHome(){
+    thread.innerHTML = '';
+    addSam('Hey! What are we doing today?');
+    addChips([
+      {label:'Add New Item', action: flowAddStart},
+      {label:'Update an Item', action: flowUpdateStart},
+      {label:'Find an Item', action: flowFindStart},
+      {label:'A Sample Came In', action: flowSampleStart},
+    ]);
+  }
+
+  // ---------- ADD NEW ITEM ----------
+  function flowAddStart(){
+    addUser('Add New Item');
+    addSam('Cool, snap a photo of it 📸');
+    addCameraBubble(() => {
+      addSam('Which brand?');
+      addBrandPicker((brand) => addAddSaved(brand));
+    });
+  }
+  function addBrandPicker(onPick){
+    const recent = ['York', 'Kravet', 'Thibaut'];
+    const all = ['Brewster', 'Cole & Son', 'Mulberry', 'Other / Unsure'];
+    const wrap = document.createElement('div');
+    wrap.className = 'pending-ui';
+    wrap.style.cssText = 'align-self:flex-start;width:100%;display:flex;flex-direction:column;gap:10px;';
+    wrap.innerHTML =
+      '<div class="search-mock" style="width:100%;"><input type="text" class="text-input" id="brandSearchInput" placeholder="Search brands…" aria-label="Search brands"></div>'+
+      '<div class="step-note">Recent</div>'+
+      '<div class="chips" id="recentChipsRow"></div>'+
+      '<div class="step-note">All Brands</div>'+
+      '<div class="chips" id="allChipsRow"></div>';
+    thread.appendChild(wrap);
+    const recentRow = wrap.querySelector('#recentChipsRow');
+    const allRow = wrap.querySelector('#allChipsRow');
+    function addBrandChip(row, name){
+      const b = document.createElement('button');
+      b.className = 'chip';
+      b.textContent = name;
+      b.onclick = () => pushStep(() => { addUser(name); onPick(name); });
+      row.appendChild(b);
+    }
+    recent.forEach(n => addBrandChip(recentRow, n));
+    all.forEach(n => addBrandChip(allRow, n));
+    scrollBottom();
+    wrap.querySelector('#brandSearchInput').addEventListener('input', function(){
+      const q = this.value.trim().toLowerCase();
+      Array.from(allRow.children).forEach(b => {
+        b.style.display = (q.length === 0 || b.textContent.toLowerCase().includes(q)) ? '' : 'none';
+      });
+    });
+  }
+  function addAddSaved(brand){
+    showToast('Saved · Undo');
+    addSam('Saved it as a draft! 🎉');
+    addDoneCard({name:'New Item', code: randomCode(), brand: brand, action:'Saved as a draft'});
+    addChips([
+      {label:'Do Another', action: () => { addUser('Do Another'); flowAddStart(); }},
+      {label:'Home', action: () => { addUser('Home'); resetChat(); }},
+    ]);
+  }
+
+  // ---------- UPDATE AN ITEM ----------
+  function flowUpdateStart(){
+    addUser('Update an Item');
+    addStepNote('Step 1 of 2');
+    addSam('Show me the label or pattern');
+    addCameraBubble(() => {
+      if(demoNoMatch){
+        showNoMatch(
+          () => { addUser('Try again'); flowUpdateStart(); },
+          () => { addUser('Type the code instead'); updateTypeSearch(); }
+        );
+        return;
+      }
+      updateConfirm();
+    });
+  }
+  function updateConfirm(){
+    addSam("Found it — Palm Damask — Sage, code DW-10423. That the one?");
+    addChips([
+      {label:"Yep, that's it", action: () => {
+        addUser("Yep, that's it");
+        updateNewPhoto();
+      }},
+      {label:'Nope, let me search', action: () => {
+        addUser('Nope, let me search');
+        updateTypeSearch();
+      }},
+    ]);
+  }
+  function updateTypeSearch(){
+    addSam('No problem — type the name or code:');
+    const el = document.createElement('div');
+    el.className = 'search-mock pending-ui';
+    el.innerHTML = '<input type="text" class="text-input" enterkeyhint="search" placeholder="Palm Damask…" aria-label="Type the item name or code">';
+    thread.appendChild(el);
+    scrollBottom();
+    const searchInput = el.querySelector('input');
+    const sendIt = () => {
+      const val = searchInput.value.trim() || 'Palm Damask';
+      pushStep(() => {
+        addUser(val);
+        addSam("Great — Palm Damask — Sage, code DW-10423. That the one?");
+        addChips([{label:"Yep, that's it", action: () => { addUser("Yep, that's it"); updateNewPhoto(); }}]);
+      });
+    };
+    searchInput.addEventListener('keydown', (e) => { if(e.key === 'Enter'){ e.preventDefault(); sendIt(); } });
+    addChips([{label:'Send', action: sendIt}]);
+  }
+  function updateNewPhoto(){
+    addStepNote('Step 2 of 2');
+    addSam('Send me the new photo');
+    addCameraBubble(() => {
+      showToast('Saved · Undo');
+      addSam('Updated! ✅');
+      addDoneCard({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Updated the photo', blue:true});
+      addChips([
+        {label:'Do Another', action: () => { addUser('Do Another'); flowUpdateStart(); }},
+        {label:'Home', action: () => { addUser('Home'); resetChat(); }},
+      ]);
+    });
+  }
+
+  // ---------- FIND AN ITEM ----------
+  function flowFindStart(){
+    addUser('Find an Item');
+    findAskMethod();
+  }
+  function findAskMethod(){
+    addSam('How do you want to search? 📷 label 🎤 voice ⌨️ type');
+    addChips([
+      {label:'📷 label', action: () => { addUser('📷 label'); findShowResults(); }},
+      {label:'🎤 voice', action: () => { addUser('🎤 voice'); findShowResults(); }},
+      {label:'⌨️ type', action: () => { addUser('⌨️ type'); findShowResults(); }},
+    ]);
+  }
+  function findShowResults(){
+    if(demoNoMatch){
+      showNoMatch(
+        () => { addUser('Try again'); findAskMethod(); },
+        () => { addUser('Type the code instead'); findTypeSearch(); }
+      );
+      return;
+    }
+    addSam("Here's what I found:");
+    const items = [
+      {name:'Palm Damask — Sage', code:'DW-10423', brand:'York'},
+      {name:'Meadow Stripe — Gold', code:'DW-20115', brand:'Kravet'},
+      {name:'Coastal Weave — Blue', code:'DW-30871', brand:'Thibaut'},
+    ];
+    const listWrap = document.createElement('div');
+    listWrap.className = 'pending-ui';
+    listWrap.style.cssText = 'display:flex;flex-direction:column;gap:10px;align-self:flex-start;width:100%;';
+    items.forEach(it => {
+      const card = document.createElement('div');
+      card.className = 'result-card';
+      card.tabIndex = 0;
+      card.setAttribute('role','button');
+      card.innerHTML = '<div class="thumb"></div><div><div class="rc-title">'+it.name+'</div><div class="rc-sub">code '+it.code+'</div></div>';
+      const pick = () => pushStep(() => { addUser(it.name); findShowDetail(it); });
+      card.onclick = pick;
+      card.onkeydown = (e) => { if(e.key === 'Enter' || e.key === ' '){ e.preventDefault(); pick(); } };
+      listWrap.appendChild(card);
+    });
+    thread.appendChild(listWrap);
+    scrollBottom();
+  }
+  function findTypeSearch(){
+    addSam('Type the item name or code:');
+    const el = document.createElement('div');
+    el.className = 'search-mock pending-ui';
+    el.innerHTML = '<input type="text" class="text-input" enterkeyhint="search" placeholder="DW-10423" aria-label="Type the item code">';
+    thread.appendChild(el);
+    scrollBottom();
+    const searchInput = el.querySelector('input');
+    const sendIt = () => {
+      const val = searchInput.value.trim() || 'DW-10423';
+      pushStep(() => {
+        addUser(val);
+        findShowDetail({name:'Palm Damask — Sage', code:'DW-10423', brand:'York'});
+      });
+    };
+    searchInput.addEventListener('keydown', (e) => { if(e.key === 'Enter'){ e.preventDefault(); sendIt(); } });
+    addChips([{label:'Send', action: sendIt}]);
+  }
+  function findShowDetail(it){
+    addSam('Found it —');
+    addDoneCard({name:it.name, code:it.code, brand:it.brand, action:'Found it'});
+    addChips([
+      {label:'Update This', action: () => {
+        addUser('Update This');
+        updateNewPhoto();
+      }},
+      {label:'Search Again', action: () => { addUser('Search Again'); findAskMethod(); }},
+    ]);
+  }
+
+  // ---------- SAMPLE IN ----------
+  function flowSampleStart(){
+    addUser('A Sample Came In');
+    addSam('Scan the box label');
+    addCameraBubble(() => {
+      if(demoNoMatch){
+        showNoMatch(
+          () => { addUser('Try again'); flowSampleStart(); },
+          () => { addUser('Type the code instead'); sampleTypeSearch(); }
+        );
+        return;
+      }
+      sampleConfirm();
+    });
+  }
+  function sampleConfirm(){
+    addSam('Found it — mark it received?');
+    addChips([
+      {label:'Yes', action: () => { addUser('Yes'); sampleFinish(); }},
+    ]);
+  }
+  function sampleTypeSearch(){
+    addSam('Type the item name or code:');
+    const el = document.createElement('div');
+    el.className = 'search-mock pending-ui';
+    el.innerHTML = '<input type="text" class="text-input" enterkeyhint="search" placeholder="DW-10423" aria-label="Type the item code">';
+    thread.appendChild(el);
+    scrollBottom();
+    const searchInput = el.querySelector('input');
+    const sendIt = () => {
+      const val = searchInput.value.trim() || 'DW-10423';
+      pushStep(() => {
+        addUser(val);
+        sampleConfirm();
+      });
+    };
+    searchInput.addEventListener('keydown', (e) => { if(e.key === 'Enter'){ e.preventDefault(); sendIt(); } });
+    addChips([{label:'Send', action: sendIt}]);
+  }
+  function sampleFinish(){
+    const printing = addSam('<span class="spinner-inline"></span>Printing your sticker now 🖨️');
+    setTimeout(() => {
+      printing.remove();
+      showToast('Saved · Undo');
+      addSam('All set! ✅');
+      addDoneCard({name:'Palm Damask — Sage', code:'DW-10423', brand:'York', action:'Marked as received'});
+      addChips([
+        {label:'Do Another', action: () => { addUser('Do Another'); flowSampleStart(); }},
+        {label:'Home', action: () => { addUser('Home'); resetChat(); }},
+      ]);
+    }, 1200);
+  }
+
+  // ---------- SHARED NO-MATCH ----------
+  function showNoMatch(tryAgainFn, typeItFn){
+    addSam("Hmm, I couldn't find a match.");
+    addChips([
+      {label:'Try again', action: tryAgainFn},
+      {label:'Type the code instead', action: typeItFn},
+    ]);
+  }
+
+  startHome();
+  setUndoEnabled();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v4-level-up.html b/public/kid-simple/v4-level-up.html
new file mode 100644
index 0000000..1813a6d
--- /dev/null
+++ b/public/kid-simple/v4-level-up.html
@@ -0,0 +1,444 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v4 — Level Up</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700&family=Nunito:wght@500;700;800;900&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --plum:#4A2E4E; --gold:#E8B84B; --cream:#F5EFE6; --green:#59B37A;
+    --ink:#2B2B2B;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Nunito',sans-serif;color:var(--ink);}
+  body{display:flex;align-items:flex-start;justify-content:center;min-height:100vh;padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--cream);
+    border-radius:36px; overflow:hidden; box-shadow:0 24px 60px rgba(0,0,0,.28);
+    display:flex; flex-direction:column; position:relative;
+  }
+  header{
+    background:var(--plum); color:#fff; padding:12px 14px; gap:8px;
+    display:flex; align-items:center; justify-content:space-between; min-height:56px;
+  }
+  header .mark{font-family:'Fraunces',serif; font-weight:700; font-size:18px; letter-spacing:.5px;}
+  .navbtn{
+    background:rgba(255,255,255,.14);border:none;color:#fff;font-size:16px;font-weight:800;cursor:pointer;
+    min-width:56px;min-height:56px;line-height:1;border-radius:14px; padding:0 14px;
+    font-family:'Nunito',sans-serif; display:inline-flex; align-items:center; justify-content:center; gap:4px;
+  }
+  .navbtn:hover{background:rgba(255,255,255,.24);}
+  .navbtn:active{transform:scale(.97);}
+  .screen{flex:1; display:flex; flex-direction:column; gap:16px; padding:22px 20px 28px; overflow-y:auto;}
+  h1.title{font-family:'Fraunces',serif; font-weight:700; font-size:26px; margin:0 0 2px; color:var(--plum);}
+  p.sub{margin:0; font-size:17px; color:#4a4a4a;}
+  .dots{display:flex; gap:8px; margin:4px 0 6px;}
+  .dots span{width:16px;height:16px;border-radius:50%;background:#e2d9c9;border:2px solid #d8cdb8;}
+  .dots span.filled{background:var(--gold); border-color:var(--gold);}
+  button{font-family:'Nunito',sans-serif; cursor:pointer;}
+  .btn{
+    min-height:56px; width:100%; border-radius:18px; font-size:18px; font-weight:800;
+    border:none; display:flex; align-items:center; justify-content:center; gap:8px; padding:0 16px;
+  }
+  .btn:active{transform:scale(.97);}
+  .btn-primary{background:var(--gold); color:#3a2a06;}
+  .btn-secondary{background:#fff; color:var(--plum); border:2px solid var(--plum);}
+  .btn-ghost{background:transparent; color:var(--plum); text-decoration:underline; min-height:44px;}
+  .btn:focus-visible, a:focus-visible, .brandcard:focus-visible, .resultcard:focus-visible,
+  .navbtn:focus-visible, .demotoggle:focus-visible, .codeinput:focus-visible, .searchbox:focus-visible,
+  .toastundo:focus-visible{
+    outline:3px solid #2B6CB0; outline-offset:2px;
+  }
+  .card{background:#fff; border-radius:20px; padding:18px; box-shadow:0 6px 18px rgba(0,0,0,.08);}
+  .levelcard{background:#fff; border-radius:20px; padding:18px; display:flex; flex-direction:column; gap:10px; box-shadow:0 6px 18px rgba(0,0,0,.08);}
+  .levelcard h2{margin:0; font-family:'Fraunces',serif; font-size:20px; color:var(--plum);}
+  .levelcard .startrow{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:8px;}
+  .camview{
+    flex:1; min-height:260px; background:#1c1c1e; border-radius:20px; position:relative;
+    display:flex; align-items:center; justify-content:center; color:#eee; overflow:hidden;
+  }
+  .camview .hint{position:absolute; top:14px; left:0; right:0; text-align:center; font-size:15px; color:#f0e8d8;}
+  .camview .status{font-size:20px; font-weight:700;}
+  .shutter{
+    position:absolute; bottom:20px; left:50%; transform:translateX(-50%);
+    width:76px; height:76px; border-radius:50%; background:var(--gold); border:5px solid #fff;
+    font-size:30px; display:flex; align-items:center; justify-content:center;
+  }
+  .shutter:active{transform:translateX(-50%) scale(.97);}
+  .swatch{width:100%; height:180px; border-radius:16px;}
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 18px,#7c9c78 18px 36px), radial-gradient(circle at 30% 30%, #a9c7a4, transparent 60%);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#617a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A441 0 14px,#c98f2c 14px 28px), radial-gradient(circle at 70% 40%, #e9c06b, transparent 55%);}
+  .brandgrid{display:grid; grid-template-columns:1fr 1fr; gap:12px;}
+  .brandcard{
+    min-height:64px; border-radius:16px; background:#fff; border:2px solid #e3d9c6;
+    font-size:17px; font-weight:700; color:var(--plum); display:flex; align-items:center; justify-content:center; text-align:center; padding:8px;
+  }
+  .brandcard:active{transform:scale(.97);}
+  .brandcard.selected{border-color:var(--gold); background:#fff7e6;}
+  .sectionlabel{margin:0; font-size:14px; font-weight:800; letter-spacing:.04em; text-transform:uppercase; color:#8a7a5a;}
+  .searchbox{
+    width:100%; min-height:56px; border-radius:16px; border:2px solid #e3d9c6; padding:0 16px;
+    font-size:17px; font-family:'Nunito',sans-serif; background:#fff; color:var(--ink);
+  }
+  .codeinput{
+    width:100%; min-height:56px; border-radius:16px; border:2px solid #e3d9c6; padding:0 16px;
+    font-size:17px; font-family:'Nunito',sans-serif; background:#fff; color:var(--ink);
+  }
+  .demotoggle{
+    background:none; border:2px dashed #cbbfa0; color:#4a4a4a; font-size:17px; font-weight:700;
+    border-radius:12px; padding:8px 12px; min-height:56px; align-self:flex-start;
+  }
+  .demotoggle:active{transform:scale(.97);}
+  .itemname{font-size:19px; font-weight:800; margin:0 0 2px;}
+  .itemmeta{font-size:17px; color:#5a5a5a; margin:0;}
+  .resultlist{display:flex; flex-direction:column; gap:10px;}
+  .resultcard{
+    display:flex; gap:12px; align-items:center; background:#fff; border-radius:16px; padding:10px;
+    border:2px solid #eee; min-height:72px; text-align:left; width:100%;
+  }
+  .resultcard:active{transform:scale(.97);}
+  .resultcard .thumb{width:52px; height:52px; border-radius:10px; flex:none;}
+  .confetti-banner{
+    background:var(--green); color:#fff; border-radius:18px; padding:18px; text-align:center;
+    font-family:'Fraunces',serif; font-size:22px; font-weight:700;
+  }
+  .row{display:flex; gap:12px;}
+  .row .btn{flex:1;}
+  .homegrid{display:flex; flex-direction:column; gap:16px;}
+  .sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;}
+  .toast{
+    position:absolute; left:16px; right:16px; bottom:16px; background:#232323; color:#fff;
+    border-radius:14px; padding:14px 18px; display:flex; align-items:center; justify-content:space-between;
+    gap:12px; font-size:16px; font-weight:700; opacity:0; transform:translateY(12px); pointer-events:none;
+    transition:opacity .25s ease, transform .25s ease; z-index:30;
+  }
+  .toast.show{opacity:1; transform:translateY(0); pointer-events:auto;}
+  .toastundo{background:none; border:none; color:var(--gold); font-weight:800; font-size:16px; min-height:56px; padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    *{transition:none !important; animation:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="phone">
+  <header>
+    <button class="navbtn" aria-label="Back" onclick="goBack()" id="backBtn">‹ Back</button>
+    <span class="mark">DW · Photo</span>
+    <button class="navbtn" aria-label="Home" onclick="go('home')" id="homeBtnTop">⌂ Home</button>
+  </header>
+  <div class="screen" id="screen" role="main"></div>
+  <div class="toast" id="toast" role="status"></div>
+  <div class="sr-only" id="live" aria-live="polite"></div>
+</div>
+
+<script>
+const JOBS = [
+  {id:'new', title:'Add New Item', emoji:'🆕', levels:3},
+  {id:'update', title:'Update an Item', emoji:'🔄', levels:3},
+  {id:'find', title:'Find an Item', emoji:'🔍', levels:2},
+  {id:'sample', title:'A Sample Came In', emoji:'📦', levels:2},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const RECENT_BRANDS = BRANDS.slice(0,3);
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1', brand:'York Wallcoverings'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2', brand:'Cole & Son'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3', brand:'Thibaut'},
+];
+const DONE_TOAST = {'new-done':'Saved','update-done':'Updated','sample-done':'Marked Received'};
+
+const state = {screen:'home', job:null, brand:null, item:null, demoNoMatch:false, checkNext:null, checkRetake:null, confirmScreen:null};
+let historyStack = [];
+let toastTimer = null;
+
+function announce(text){ const el=document.getElementById('live'); if(el) el.textContent = text; }
+
+function go(screen){
+  if(screen==='home'){ historyStack = []; }
+  else if(state.screen && state.screen!==screen){
+    if(String(screen).endsWith('-done')) state.confirmScreen = state.screen;
+    historyStack.push(state.screen);
+  }
+  state.screen = screen;
+  render();
+}
+function goReplace(screen){ state.screen = screen; render(); }
+function goBack(){
+  if(historyStack.length){ state.screen = historyStack.pop(); render(); }
+  else go('home');
+}
+function startJob(id){ state.job = id; state.brand=null; state.item=null; go(id+'-1'); }
+function jobTitle(){ return JOBS.find(j=>j.id===state.job).title; }
+function jobLevels(){ return JOBS.find(j=>j.id===state.job).levels; }
+
+function dots(filled){
+  const total = jobLevels();
+  let out = '<div class="dots">';
+  for(let i=1;i<=total;i++) out += `<span class="${i<=filled?'filled':''}"></span>`;
+  out += '</div>';
+  return out;
+}
+function levelFromScreen(scr){ const m = /-(\d+)$/.exec(scr||''); return m ? parseInt(m[1],10) : null; }
+
+function levelHeader(n, name){
+  return `<h1 class="title">${jobTitle()}</h1>${dots(n)}<p class="sub"><strong>Level ${n} of ${jobLevels()}</strong> — ${name}</p>`;
+}
+
+function cameraScreen(hint, onShoot){
+  return `
+    <div class="camview">
+      <div class="hint">${hint}</div>
+      <div class="status" id="camStatus">Tap the shutter</div>
+      <button class="shutter" aria-label="Snap It" onclick="${onShoot}">📸</button>
+    </div>`;
+}
+function shoot(cb, loadingLabel){
+  const fromScreen = state.screen;
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  announce('Snapping photo…');
+  setTimeout(()=>{
+    if(state.screen!==fromScreen) return; // user navigated away mid-shot
+    const item = MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)];
+    state.item = item;
+    if(loadingLabel){
+      if(st) st.textContent = loadingLabel;
+      announce(loadingLabel);
+      setTimeout(()=>{ if(state.screen===fromScreen) cb(); }, 500);
+    } else cb();
+  }, 700);
+}
+function shootThen(nextScreen, retakeScreen){
+  shoot(()=>{ state.checkNext=nextScreen; state.checkRetake=retakeScreen; go('photocheck'); });
+}
+function shootOrMiss(nextScreen, retakeScreen, missScreen, loadingLabel){
+  shoot(()=>{
+    if(state.demoNoMatch){ go(missScreen); return; }
+    state.checkNext=nextScreen; state.checkRetake=retakeScreen; go('photocheck');
+  }, loadingLabel);
+}
+function finishCheck(){
+  const next = state.checkNext;
+  go(next);
+  if(next==='update-done') state.confirmScreen = 'update-3';
+  if(DONE_TOAST[next]) showToast(DONE_TOAST[next]);
+}
+function toggleDemo(){ state.demoNoMatch = !state.demoNoMatch; render(); }
+function demoToggleHtml(){
+  return `<button class="demotoggle" aria-pressed="${state.demoNoMatch}" onclick="toggleDemo()">Demo: show "no match" ${state.demoNoMatch?'✅ On':'⬜ Off'}</button>`;
+}
+function tryFind(){
+  go('find-loading');
+  announce('Looking for matches…');
+  setTimeout(()=>{ if(state.screen==='find-loading') goReplace(state.demoNoMatch ? 'find-nomatch' : 'find-2'); }, 600);
+}
+function filterBrands(q){
+  q = q.trim().toLowerCase();
+  const recentWrap = document.getElementById('brandRecent');
+  if(recentWrap) recentWrap.style.display = q ? 'none' : '';
+  const full = document.getElementById('brandFullGrid');
+  if(!full) return;
+  full.querySelectorAll('.brandcard').forEach(btn=>{
+    btn.style.display = btn.textContent.toLowerCase().includes(q) ? '' : 'none';
+  });
+}
+function showToast(msg){
+  const t = document.getElementById('toast');
+  t.innerHTML = `${msg} <button class="toastundo" onclick="undoLast()">Undo</button>`;
+  t.classList.add('show');
+  announce(msg + '. Undo available for 5 seconds.');
+  clearTimeout(toastTimer);
+  toastTimer = setTimeout(()=>{ t.classList.remove('show'); }, 5000);
+}
+function undoLast(){
+  const t = document.getElementById('toast');
+  t.classList.remove('show');
+  clearTimeout(toastTimer);
+  if(state.confirmScreen) go(state.confirmScreen);
+}
+function saveDraft(){ go('new-done'); showToast('Saved'); }
+function markReceived(){
+  const fromScreen = state.screen;
+  const btn = document.getElementById('markReceivedBtn');
+  if(btn){ btn.disabled = true; btn.textContent = 'Printing sticker…'; }
+  announce('Printing sticker…');
+  setTimeout(()=>{
+    if(state.screen!==fromScreen) return; // user navigated away mid-print
+    go('sample-done'); showToast('Marked Received');
+  }, 700);
+}
+
+function brandGridHtml(nextScreen){
+  let html = `<input type="text" class="searchbox" id="brandSearch" placeholder="Search brands…" aria-label="Search brands" oninput="filterBrands(this.value)">`;
+  html += `<div id="brandRecent"><p class="sectionlabel">Recent</p><div class="brandgrid">`;
+  RECENT_BRANDS.forEach(b=>{ html += `<button class="brandcard" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div></div>`;
+  html += `<p class="sectionlabel">All Brands</p><div class="brandgrid" id="brandFullGrid">`;
+  BRANDS.forEach(b=>{ html += `<button class="brandcard" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div>`;
+  return html;
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  let html = '';
+  const onHome = state.screen==='home';
+  document.getElementById('homeBtnTop').style.display = onHome ? 'none' : 'inline-flex';
+  document.getElementById('backBtn').style.display = onHome ? 'none' : 'inline-flex';
+
+  if(state.screen==='home'){
+    html += `<h1 class="title">Pick a Job</h1><p class="sub">Every job is a quick level path.</p>
+    <div class="homegrid">`;
+    JOBS.forEach(j=>{
+      html += `<div class="levelcard">
+        <h2>${j.emoji} ${j.title}</h2>
+        <p class="sub">Level 1 of ${j.levels}</p>
+        <div class="startrow">
+          ${dots(0)}
+          <button class="btn btn-primary" style="width:auto;min-width:110px;" onclick="startJob('${j.id}')">Start</button>
+        </div>
+      </div>`;
+    });
+    html += `</div>`;
+  }
+
+  else if(state.screen==='photocheck'){
+    const lvl = levelFromScreen(state.checkRetake);
+    html += lvl ? levelHeader(lvl, 'Photo Check') : `<h1 class="title">Photo Check</h1>`;
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div></div>`;
+    html += `<p class="sub">Does this look right?</p>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go(state.checkRetake)">Retake</button><button class="btn btn-primary" onclick="finishCheck()">Looks good</button></div>`;
+  }
+
+  else if(state.screen==='new-1'){
+    html += levelHeader(1,'Snap It');
+    html += cameraScreen('Take a photo of the sample', "shootThen('new-2','new-1')");
+  }
+  else if(state.screen==='new-2'){
+    html += levelHeader(2,'Pick the Brand');
+    html += brandGridHtml('new-3');
+  }
+  else if(state.screen==='new-3'){
+    html += levelHeader(3,'Save It');
+    html += `<div class="card">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">Brand: ${state.brand} · code ${state.item.code}</p>
+    </div>`;
+    html += `<button class="btn btn-primary" onclick="saveDraft()">Save as Draft ⭐</button>`;
+  }
+  else if(state.screen==='new-done'){
+    html += `<div class="confetti-banner">🎉 +10 points! Nice work</div>`;
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.brand} · Code: ${state.item.code}</p><p class="itemmeta">Saved as a new item draft.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('new')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  else if(state.screen==='update-1'){
+    html += levelHeader(1,'Find It');
+    html += `<p class="sub">Scan the label, or search by typing.</p>`;
+    html += cameraScreen('Show me the label or pattern', "shootOrMiss('update-2','update-1','update-nomatch','Looking for matches…')");
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='update-nomatch'){
+    html += `<h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('update-1')">Try again</button><button class="btn btn-primary" onclick="go('update-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='update-typecode'){
+    html += `<h1 class="title">Type the Code</h1>`;
+    html += `<input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('update-2')">Find</button>`;
+  }
+  else if(state.screen==='update-2'){
+    html += levelHeader(2,'Confirm It');
+    html += `<div class="card">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+    </div>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('update-1')">No, search again</button><button class="btn btn-primary" onclick="go('update-3')">Yes, that's it</button></div>`;
+  }
+  else if(state.screen==='update-3'){
+    html += levelHeader(3,'Snap the New Photo');
+    html += cameraScreen('Take the new photo', "shootThen('update-done','update-3')");
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="confetti-banner">✅ Updated!</div>`;
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p><p class="itemmeta">Photo updated.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('update')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  else if(state.screen==='find-1'){
+    html += levelHeader(1,'Search');
+    html += `<div class="row" style="flex-direction:column;">
+      <button class="btn btn-secondary" onclick="tryFind()">📷 Scan</button>
+      <button class="btn btn-secondary" onclick="tryFind()">🎤 Voice</button>
+      <button class="btn btn-secondary" onclick="tryFind()">⌨️ Type</button>
+    </div>`;
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='find-loading'){
+    html += `<div class="card" style="text-align:center;"><p class="sub">Looking for matches…</p></div>`;
+  }
+  else if(state.screen==='find-nomatch'){
+    html += `<h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('find-1')">Try again</button><button class="btn btn-primary" onclick="go('find-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='find-typecode'){
+    html += `<h1 class="title">Type the Code</h1>`;
+    html += `<input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('find-done')">Find</button>`;
+  }
+  else if(state.screen==='find-2'){
+    html += levelHeader(2,'Pick It');
+    html += `<div class="resultlist">`;
+    MOCK_ITEMS.forEach((it,i)=>{
+      html += `<button class="resultcard" onclick="state.item=MOCK_ITEMS[${i}]; go('find-done')">
+        <div class="thumb ${it.sw}"></div>
+        <div><p class="itemname" style="font-size:17px;">${it.name} — ${it.color}</p><p class="itemmeta">code ${it.code}</p></div>
+      </button>`;
+    });
+    html += `</div>`;
+  }
+  else if(state.screen==='find-done'){
+    html += `<h1 class="title">Found It</h1>`;
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('find')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  else if(state.screen==='sample-1'){
+    html += levelHeader(1,'Scan the Box');
+    html += cameraScreen('Scan the label on the box', "shootOrMiss('sample-2','sample-1','sample-nomatch','Looking for matches…')");
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='sample-nomatch'){
+    html += `<h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('sample-1')">Try again</button><button class="btn btn-primary" onclick="go('sample-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='sample-typecode'){
+    html += `<h1 class="title">Type the Code</h1>`;
+    html += `<input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('sample-2')">Find</button>`;
+  }
+  else if(state.screen==='sample-2'){
+    html += levelHeader(2,'Confirm & Print');
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">code ${state.item.code}</p></div>`;
+    html += `<button class="btn btn-primary" id="markReceivedBtn" onclick="markReceived()">Mark It Received</button>`;
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="confetti-banner">🖨️ Sticker printed! +10 points</div>`;
+    html += `<div class="card"><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p><p class="itemmeta">Marked received.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('sample')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  s.innerHTML = html;
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v5-swipe-deck.html b/public/kid-simple/v5-swipe-deck.html
new file mode 100644
index 0000000..90273fe
--- /dev/null
+++ b/public/kid-simple/v5-swipe-deck.html
@@ -0,0 +1,490 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v5 — Swipe Deck</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700&family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{ --blush:#F4EDE7; --green:#3FA66B; --red:#C0503F; --gold:#C9A24B; --gold-text:#7A5C22; --ink:#2B2B2B; }
+  *{box-sizing:border-box; touch-action:pan-y;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Inter',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--blush); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  header{ padding:10px 14px; display:flex; align-items:center; justify-content:space-between; gap:8px; }
+  header .mark{ font-family:'Fraunces',serif; font-weight:700; font-size:18px; color:var(--gold-text); }
+  .navbtn{
+    background:#fff; border:2px solid #e6dccb; color:var(--ink); font-size:15px; font-weight:800; cursor:pointer;
+    min-width:56px; min-height:56px; border-radius:14px; padding:0 14px; font-family:'Inter',sans-serif;
+    display:inline-flex; align-items:center; justify-content:center; gap:4px;
+  }
+  .navbtn:active{transform:scale(.97);}
+  .screen-area{ flex:1; position:relative; display:flex; align-items:center; justify-content:center; padding:14px 18px; overflow:hidden; }
+  .inner{ width:100%; display:flex; flex-direction:column; gap:14px; }
+  h1.title{ font-family:'Fraunces',serif; font-weight:700; font-size:24px; margin:0 0 4px; text-align:center; }
+  p.sub{ margin:0; font-size:17px; color:#555; text-align:center; }
+  .steplabel{ text-align:center; font-size:14px; font-weight:800; letter-spacing:.03em; text-transform:uppercase; color:#a08a5a; margin:0; }
+  .card{
+    background:#fff; border-radius:22px; padding:20px; box-shadow:0 10px 28px rgba(0,0,0,.14);
+    display:flex; flex-direction:column; gap:12px; user-select:none;
+  }
+  .card.swiper{ cursor:grab; will-change:transform, opacity; }
+  .card.swiper:active{ cursor:grabbing; }
+  .itemname{ font-size:20px; font-weight:800; margin:0; }
+  .itemmeta{ font-size:17px; color:#555; margin:0; }
+  .swatch{ width:100%; height:170px; border-radius:16px; }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 18px,#7c9c78 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#617a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A441 0 14px,#c98f2c 14px 28px);}
+  .camview{
+    height:280px; background:#1c1c1e; border-radius:20px; position:relative;
+    display:flex; align-items:center; justify-content:center; color:#eee;
+  }
+  .camview .hint{position:absolute; top:14px; left:0; right:0; text-align:center; font-size:15px; color:#f0e8d8;}
+  .camview .status{ font-size:19px; font-weight:700; }
+  .shutter{
+    position:absolute; bottom:18px; left:50%; transform:translateX(-50%);
+    width:74px; height:74px; border-radius:50%; background:var(--gold); border:5px solid #fff; font-size:28px;
+    display:flex; align-items:center; justify-content:center;
+  }
+  .shutter:active{transform:translateX(-50%) scale(.97);}
+  button{ font-family:'Inter',sans-serif; cursor:pointer; }
+  .btn{ min-height:56px; width:100%; border-radius:18px; font-size:18px; font-weight:700; border:none;
+    display:flex; align-items:center; justify-content:center; gap:8px; padding:0 16px; }
+  .btn:active{transform:scale(.97);}
+  .btn-primary{ background:var(--gold); color:#3a2a06; }
+  .btn-secondary{ background:#fff; color:var(--ink); border:2px solid #ddd; }
+  .btn:focus-visible, .brandcard:focus-visible, .tabbtn:focus-visible, .navbtn:focus-visible,
+  .demotoggle:focus-visible, .codeinput:focus-visible, .searchbox:focus-visible, .toastundo:focus-visible,
+  .circle:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .row{ display:flex; gap:12px; }
+  .row .btn{ flex:1; }
+  .swipebtns{ display:flex; justify-content:center; gap:36px; margin-top:6px; }
+  .circlewrap{ display:flex; flex-direction:column; align-items:center; gap:6px; }
+  .circle{
+    width:64px; height:64px; border-radius:50%; border:none; font-size:26px; font-weight:800;
+    display:flex; align-items:center; justify-content:center; box-shadow:0 6px 14px rgba(0,0,0,.15);
+  }
+  .circle:active{transform:scale(.97);}
+  .circle.reject{ background:#fff; color:var(--red); border:3px solid var(--red); }
+  .circle.accept{ background:#fff; color:var(--green); border:3px solid var(--green); }
+  .circle-label{ font-size:14px; font-weight:700; color:#555; }
+  .brandgrid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
+  .brandcard{ min-height:60px; border-radius:14px; background:#fff; border:2px solid #e6dccb; font-size:16px; font-weight:700; }
+  .brandcard:active{transform:scale(.97);}
+  .sectionlabel{ margin:0; font-size:14px; font-weight:800; letter-spacing:.04em; text-transform:uppercase; color:#8a7a5a; }
+  .searchbox, .codeinput{
+    width:100%; min-height:56px; border-radius:16px; border:2px solid #e6dccb; padding:0 16px;
+    font-size:17px; font-family:'Inter',sans-serif; background:#fff; color:var(--ink);
+  }
+  .demotoggle{
+    background:none; border:2px dashed #cbbfa0; color:#4a4a4a; font-size:17px; font-weight:700;
+    border-radius:12px; padding:8px 12px; min-height:56px; align-self:center;
+  }
+  .demotoggle:active{transform:scale(.97);}
+  .resultlabel{ position:absolute; top:10px; left:10px; background:rgba(0,0,0,.55); color:#fff; font-size:13px; padding:4px 10px; border-radius:999px; }
+  .swipehint{ background:#232323; color:#fff; border-radius:16px; padding:16px; text-align:center; display:flex; flex-direction:column; gap:12px; font-size:15px; font-weight:600; }
+  .bottombar{
+    display:flex; justify-content:space-around; align-items:center; padding:10px 6px 16px;
+    background:#fff; border-top:1px solid #eee;
+  }
+  .tabbtn{
+    background:none; border:none; display:flex; flex-direction:column; align-items:center; gap:4px;
+    min-width:64px; min-height:56px; font-size:12px; font-weight:700; color:#7a7a7a;
+  }
+  .tabbtn:active{transform:scale(.97);}
+  .tabbtn .ic{ font-size:24px; }
+  .tabbtn.active{ color:var(--gold-text); }
+  .sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;}
+  .toast{
+    position:absolute; left:16px; right:16px; bottom:96px; background:#232323; color:#fff;
+    border-radius:14px; padding:14px 18px; display:flex; align-items:center; justify-content:space-between;
+    gap:12px; font-size:16px; font-weight:700; opacity:0; transform:translateY(12px); pointer-events:none;
+    transition:opacity .25s ease, transform .25s ease; z-index:30;
+  }
+  .toast.show{opacity:1; transform:translateY(0); pointer-events:auto;}
+  .toastundo{background:none; border:none; color:var(--gold); font-weight:800; font-size:16px; min-height:56px; padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    *{transition:none !important; animation:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="phone">
+  <header>
+    <button class="navbtn" aria-label="Back" onclick="goBack()" id="backBtn">‹ Back</button>
+    <span class="mark">DW · Photo</span>
+    <button class="navbtn" aria-label="Home" onclick="go('home')" id="homeBtnTop">⌂ Home</button>
+  </header>
+  <div class="screen-area" id="screen"></div>
+  <div class="toast" id="toast" role="status"></div>
+  <div class="sr-only" id="live" aria-live="polite"></div>
+  <div class="bottombar">
+    <button class="tabbtn" onclick="startJob('new')" id="tab-new"><span class="ic">🆕</span>New</button>
+    <button class="tabbtn" onclick="startJob('update')" id="tab-update"><span class="ic">🔄</span>Update</button>
+    <button class="tabbtn" onclick="startJob('find')" id="tab-find"><span class="ic">🔍</span>Find</button>
+    <button class="tabbtn" onclick="startJob('sample')" id="tab-sample"><span class="ic">📦</span>Sample</button>
+  </div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1', brand:'York Wallcoverings'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2', brand:'Cole & Son'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3', brand:'Thibaut'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const RECENT_BRANDS = BRANDS.slice(0,3);
+const STEP_MAP = {
+  'new-cam':[1,4], 'new-review':[2,4], 'new-brand':[3,4], 'new-savecheck':[4,4],
+  'update-scan':[1,4], 'update-match':[2,4], 'update-newphoto':[3,4], 'update-review':[4,4],
+  'find-method':[1,3], 'find-stack':[2,3], 'find-detail':[3,3],
+  'sample-scan':[1,3], 'sample-match':[2,3], 'sample-printing':[3,3],
+};
+// screens that render around state.item — if item is missing (e.g. a job switch
+// mid-flow nulled it while an old screen was still in historyStack), render()
+// must not throw; it routes home instead.
+const ITEM_SCREENS = ['new-review','new-savecheck','new-done','update-match','update-review','update-done','find-detail','sample-match','sample-done'];
+
+const state = { screen:'home', job:null, item:null, brand:null, resultIndex:0, demoNoMatch:false, confirmScreen:null };
+let currentSwiper = null;
+let historyStack = [];
+let toastTimer = null;
+let hintShown = false;
+
+function announce(text){ const el=document.getElementById('live'); if(el) el.textContent = text; }
+function go(screen){
+  if(screen==='home'){ historyStack = []; }
+  else if(state.screen && state.screen!==screen){ historyStack.push(state.screen); }
+  state.screen = screen; render();
+}
+function goReplace(screen){ state.screen = screen; render(); }
+function goBack(){
+  if(historyStack.length){ state.screen = historyStack.pop(); render(); }
+  else go('home');
+}
+function startJob(job){
+  state.job = job; state.item=null; state.brand=null; state.resultIndex=0;
+  // switching jobs (incl. via the always-visible bottom tab bar) is a fresh
+  // start — any screens left in historyStack belong to the old job and may
+  // reference state (item/brand) that just got cleared. Clear the stack AND
+  // use goReplace (not go) so the old screen never gets re-pushed as a back
+  // target — Back from a freshly-started job always lands on Home.
+  historyStack = [];
+  const map = {new:'new-cam', update:'update-scan', find:'find-method', sample:'sample-scan'};
+  goReplace(map[job]);
+}
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+function stepLabel(){ const m = STEP_MAP[state.screen]; return m ? `<p class="steplabel">Card ${m[0]} of ${m[1]}</p>` : ''; }
+function toggleDemo(){ state.demoNoMatch = !state.demoNoMatch; render(); }
+function demoToggleHtml(){
+  return `<button class="demotoggle" aria-pressed="${state.demoNoMatch}" onclick="toggleDemo()">Demo: show "no match" ${state.demoNoMatch?'✅ On':'⬜ Off'}</button>`;
+}
+function maybeHint(text){
+  if(hintShown) return '';
+  hintShown = true;
+  text = text || 'Swipe right = yes, left = redo<br>(or tap the buttons)';
+  return `<div class="swipehint" role="note"><p>${text}</p><button class="btn btn-primary" style="width:auto;min-width:120px;align-self:center;" onclick="this.closest('.swipehint').remove()">Got it</button></div>`;
+}
+
+function shoot(cb, loadingLabel){
+  const fromScreen = state.screen;
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  announce('Snapping photo…');
+  setTimeout(()=>{
+    if(state.screen!==fromScreen) return; // user navigated away mid-shot
+    state.item = randomItem();
+    if(loadingLabel){ if(st) st.textContent = loadingLabel; announce(loadingLabel); setTimeout(()=>{ if(state.screen===fromScreen) cb(); }, 500); }
+    else cb();
+  }, 700);
+}
+function afterUpdateScan(){ state.demoNoMatch ? go('update-nomatch') : go('update-match'); }
+function afterSampleScan(){ state.demoNoMatch ? go('sample-nomatch') : go('sample-match'); }
+function tryFindMethod(){
+  go('find-loading');
+  announce('Looking for matches…');
+  setTimeout(()=>{ if(state.screen==='find-loading') goReplace(state.demoNoMatch ? 'find-nomatch' : 'find-stack'); }, 600);
+}
+
+function swipeButtons(rejectAria, acceptAria){
+  acceptAria = acceptAria || 'Yes';
+  return `<div class="swipebtns">
+    <div class="circlewrap">
+      <button class="circle reject" aria-label="${rejectAria}" onclick="currentSwiper.swipeLeft()">✗</button>
+      <span class="circle-label">Redo</span>
+    </div>
+    <div class="circlewrap">
+      <button class="circle accept" aria-label="${acceptAria}" onclick="currentSwiper.swipeRight()">✓</button>
+      <span class="circle-label">Yes</span>
+    </div>
+  </div>`;
+}
+function cameraCard(hint, onShoot){
+  return `<div class="camview">
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    <button class="shutter" aria-label="Snap It" onclick="${onShoot}">📸</button>
+  </div>`;
+}
+function brandGridHtml(nextScreen){
+  let html = `<input type="text" class="searchbox" placeholder="Search brands…" aria-label="Search brands" oninput="filterBrands(this.value)">`;
+  html += `<div id="brandRecent"><p class="sectionlabel">Recent</p><div class="brandgrid">`;
+  RECENT_BRANDS.forEach(b=>{ html += `<button class="brandcard" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div></div>`;
+  html += `<p class="sectionlabel">All Brands</p><div class="brandgrid" id="brandFullGrid">`;
+  BRANDS.forEach(b=>{ html += `<button class="brandcard" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div>`;
+  return html;
+}
+function filterBrands(q){
+  q = q.trim().toLowerCase();
+  const recentWrap = document.getElementById('brandRecent');
+  if(recentWrap) recentWrap.style.display = q ? 'none' : '';
+  const full = document.getElementById('brandFullGrid');
+  if(!full) return;
+  full.querySelectorAll('.brandcard').forEach(btn=>{
+    btn.style.display = btn.textContent.toLowerCase().includes(q) ? '' : 'none';
+  });
+}
+function showToast(msg){
+  const t = document.getElementById('toast');
+  t.innerHTML = `${msg} <button class="toastundo" onclick="undoLast()">Undo</button>`;
+  t.classList.add('show');
+  announce(msg + '. Undo available for 5 seconds.');
+  clearTimeout(toastTimer);
+  toastTimer = setTimeout(()=>{ t.classList.remove('show'); }, 5000);
+}
+function undoLast(){
+  const t = document.getElementById('toast');
+  t.classList.remove('show');
+  clearTimeout(toastTimer);
+  if(state.confirmScreen) go(state.confirmScreen);
+}
+function saveDraft(){ state.confirmScreen='new-savecheck'; go('new-done'); showToast('Saved'); }
+function finishUpdate(){ state.confirmScreen='update-review'; go('update-done'); showToast('Updated'); }
+
+// generic pointer-drag swipe; buttons call swipeRight()/swipeLeft() on the returned handle
+function attachSwipe(el, onRight, onLeft){
+  let startX=0, dragging=false, dx=0;
+  function down(e){ dragging=true; startX=e.clientX; el.style.transition='none'; el.setPointerCapture && el.setPointerCapture(e.pointerId); }
+  function move(e){ if(!dragging) return; dx = e.clientX-startX;
+    el.style.transform = `translateX(${dx}px) rotate(${dx/18}deg)`;
+    el.style.opacity = 1 - Math.min(Math.abs(dx)/450,.5);
+  }
+  function up(){ if(!dragging) return; dragging=false;
+    el.style.transition='transform .25s ease, opacity .25s ease';
+    if(dx>90) flyOut(1,onRight); else if(dx<-90) flyOut(-1,onLeft); else { el.style.transform=''; el.style.opacity=1; }
+    dx=0;
+  }
+  function flyOut(dir,cb){
+    el.style.transform = `translateX(${dir*520}px) rotate(${dir*28}deg)`;
+    el.style.opacity=0;
+    setTimeout(()=>{ if(cb) cb(); }, 200);
+  }
+  el.addEventListener('pointerdown', down);
+  el.addEventListener('pointermove', move);
+  el.addEventListener('pointerup', up);
+  el.addEventListener('pointercancel', up);
+  const handle = { swipeRight:()=>flyOut(1,onRight), swipeLeft:()=>flyOut(-1,onLeft) };
+  return handle;
+}
+
+function render(){
+  // defensive: never let a screen render around missing item/brand state —
+  // route home instead of throwing (e.g. tab-switch mid-flow, or any other
+  // path that leaves a stale screen pointing at cleared state).
+  if(ITEM_SCREENS.includes(state.screen) && !state.item){
+    state.screen = 'home';
+    historyStack = [];
+  }
+  const s = document.getElementById('screen');
+  const onHome = state.screen==='home';
+  document.getElementById('backBtn').style.display = onHome ? 'none' : 'inline-flex';
+  document.getElementById('homeBtnTop').style.display = onHome ? 'none' : 'inline-flex';
+  ['new','update','find','sample'].forEach(j=>{
+    document.getElementById('tab-'+j).classList.toggle('active', state.job===j);
+  });
+  let html = '<div class="inner">';
+
+  if(state.screen==='home'){
+    html += `<div class="card" style="text-align:center; align-items:center;">
+      <h1 class="title">Ready when you are</h1>
+      <p class="sub">Pick a job below to get started.</p>
+    </div>`;
+  }
+
+  else if(state.screen==='new-cam'){
+    html += stepLabel() + `<h1 class="title">Add New Item</h1>` + cameraCard('Take a photo of the sample', "shoot(()=>go('new-review'))");
+  }
+  else if(state.screen==='new-review'){
+    html += stepLabel();
+    html += maybeHint();
+    html += `<p class="sub">Swipe or tap to decide</p>`;
+    html += `<div class="card swiper" id="swipeCard">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+    </div>`;
+    html += swipeButtons('Retake', 'Looks Good');
+  }
+  else if(state.screen==='new-brand'){
+    html += stepLabel() + `<h1 class="title">Which Brand?</h1>` + brandGridHtml('new-savecheck');
+  }
+  else if(state.screen==='new-savecheck'){
+    html += stepLabel();
+    html += `<div class="card">
+      <h1 class="title" style="font-size:20px;">Save this?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">${state.brand} · code ${state.item.code}</p>
+    </div>`;
+    html += `<button class="btn btn-primary" onclick="saveDraft()">Save as Draft</button>`;
+  }
+  else if(state.screen==='new-done'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">Saved! 🎉</h1><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.brand} · Code: ${state.item.code}</p><p class="itemmeta">Saved as a draft.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('new')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  else if(state.screen==='update-scan'){
+    html += stepLabel() + `<h1 class="title">Update an Item</h1>` + cameraCard('Show me the label or pattern', "shoot(afterUpdateScan,'Looking for matches…')");
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='update-nomatch'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p></div>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('update-scan')">Try again</button><button class="btn btn-primary" onclick="go('update-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='update-typecode'){
+    html += `<div class="card"><h1 class="title" style="font-size:20px;">Type the Code</h1><input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code"></div>`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('update-match')">Find</button>`;
+  }
+  else if(state.screen==='update-match'){
+    html += stepLabel();
+    html += maybeHint();
+    html += `<p class="sub">Is this it?</p>`;
+    html += `<div class="card swiper" id="swipeCard">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+    </div>`;
+    html += swipeButtons('Not it', "Yes, that's it");
+  }
+  else if(state.screen==='update-newphoto'){
+    html += stepLabel() + `<h1 class="title">New Photo</h1>` + cameraCard('Take the new photo', "shoot(()=>go('update-review'))");
+  }
+  else if(state.screen==='update-review'){
+    html += stepLabel();
+    html += maybeHint();
+    html += `<p class="sub">Swipe right to confirm</p>`;
+    html += `<div class="card swiper" id="swipeCard">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+    </div>`;
+    html += swipeButtons('Retake', 'Looks Good');
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">Updated! ✅</h1><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p><p class="itemmeta">Photo updated.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('update')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  else if(state.screen==='find-method'){
+    html += stepLabel() + `<h1 class="title">Find an Item</h1>`;
+    html += `<button class="btn btn-secondary" onclick="tryFindMethod()">Scan the Label</button>`;
+    html += `<button class="btn btn-secondary" onclick="tryFindMethod()">Say the Name</button>`;
+    html += `<button class="btn btn-secondary" onclick="tryFindMethod()">Type It</button>`;
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='find-loading'){
+    html += `<div class="card" style="text-align:center;"><p class="sub">Looking for matches…</p></div>`;
+  }
+  else if(state.screen==='find-nomatch'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p></div>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('find-method')">Try again</button><button class="btn btn-primary" onclick="go('find-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='find-typecode'){
+    html += `<div class="card"><h1 class="title" style="font-size:20px;">Type the Code</h1><input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code"></div>`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('find-detail')">Find</button>`;
+  }
+  else if(state.screen==='find-stack'){
+    const it = MOCK_ITEMS[state.resultIndex % MOCK_ITEMS.length];
+    html += stepLabel();
+    html += maybeHint('Swipe right = pick this one, left = skip');
+    html += `<p class="sub">Swipe ✗ to skip, ✓ or tap to pick</p>`;
+    html += `<div class="card swiper" id="swipeCard" onclick="pickResult()" style="position:relative;">
+      <span class="resultlabel">${(state.resultIndex%MOCK_ITEMS.length)+1} of ${MOCK_ITEMS.length}</span>
+      <div class="swatch ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+    </div>`;
+    html += swipeButtons('Skip', 'Pick this one');
+  }
+  else if(state.screen==='find-detail'){
+    html += stepLabel();
+    html += `<div class="card" style="text-align:center;"><h1 class="title" style="font-size:20px;">${state.item.name}</h1><div class="swatch ${state.item.sw}"></div><p class="itemmeta">${state.item.color} · code ${state.item.code} · ${state.item.brand}</p></div>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('find-stack')">Back</button><button class="btn btn-primary" onclick="go('update-newphoto')">Update This</button></div>`;
+  }
+
+  else if(state.screen==='sample-scan'){
+    html += stepLabel() + `<h1 class="title">A Sample Came In</h1>` + cameraCard('Scan the label on the box', "shoot(afterSampleScan,'Looking for matches…')");
+    html += demoToggleHtml();
+  }
+  else if(state.screen==='sample-nomatch'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">No Match Found</h1><p class="sub">We couldn't find a matching item.</p></div>`;
+    html += `<div class="row"><button class="btn btn-secondary" onclick="go('sample-scan')">Try again</button><button class="btn btn-primary" onclick="go('sample-typecode')">Type the code instead</button></div>`;
+  }
+  else if(state.screen==='sample-typecode'){
+    html += `<div class="card"><h1 class="title" style="font-size:20px;">Type the Code</h1><input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code"></div>`;
+    html += `<button class="btn btn-primary" onclick="state.item=MOCK_ITEMS[0]; go('sample-match')">Find</button>`;
+  }
+  else if(state.screen==='sample-match'){
+    html += stepLabel();
+    html += maybeHint();
+    html += `<p class="sub">Mark Received?</p>`;
+    html += `<div class="card swiper" id="swipeCard">
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+    </div>`;
+    html += swipeButtons('Not it, rescan', 'Mark Received');
+  }
+  else if(state.screen==='sample-printing'){
+    html += stepLabel();
+    html += `<div class="card" style="text-align:center;"><h1 class="title" style="font-size:20px;">Printing sticker…</h1><p class="sub">🖨️ One sec…</p></div>`;
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="card" style="text-align:center;"><h1 class="title">Done! ✅</h1><div class="swatch ${state.item.sw}"></div><p class="itemname">${state.item.name} — ${state.item.color}</p><p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p><p class="itemmeta">Sticker printed and item received.</p></div>`;
+    html += `<div class="row"><button class="btn btn-primary" onclick="startJob('sample')">Do Another</button><button class="btn btn-secondary" onclick="go('home')">Home</button></div>`;
+  }
+
+  html += '</div>';
+  s.innerHTML = html;
+
+  const swipeEl = document.getElementById('swipeCard');
+  if(swipeEl){
+    if(state.screen==='new-review'){ currentSwiper = attachSwipe(swipeEl, ()=>go('new-brand'), ()=>go('new-cam')); }
+    else if(state.screen==='update-match'){ currentSwiper = attachSwipe(swipeEl, ()=>go('update-newphoto'), ()=>go('update-scan')); }
+    else if(state.screen==='update-review'){ currentSwiper = attachSwipe(swipeEl, finishUpdate, ()=>go('update-newphoto')); }
+    else if(state.screen==='find-stack'){ currentSwiper = attachSwipe(swipeEl, pickResult, skipResult); }
+    else if(state.screen==='sample-match'){ currentSwiper = attachSwipe(swipeEl, markReceived, ()=>go('sample-scan')); }
+  }
+}
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex % MOCK_ITEMS.length]; go('find-detail'); }
+function skipResult(){ state.resultIndex++; go('find-stack'); }
+function markReceived(){
+  state.confirmScreen = 'sample-match';
+  go('sample-printing');
+  announce('Printing sticker…');
+  setTimeout(()=>{ if(state.screen==='sample-printing'){ go('sample-done'); showToast('Marked Received'); } }, 900);
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v6-one-thing.html b/public/kid-simple/v6-one-thing.html
new file mode 100644
index 0000000..6d04237
--- /dev/null
+++ b/public/kid-simple/v6-one-thing.html
@@ -0,0 +1,460 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v6 — One Thing At A Time</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700&family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{ --bg:#FBF9F6; --ink:#232323; --gold:#C9A24B; --taupe:#8A8074; --taupe-text:#6B6156; --green:#3FA66B; }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Inter',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--bg); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; padding:36px 26px 30px; overflow-y:auto; }
+  .stepline{ text-align:center; font-size:14px; font-weight:800; letter-spacing:.03em; text-transform:uppercase; color:var(--taupe-text); margin:0 0 8px; }
+  .question{
+    font-family:'Fraunces',serif; font-weight:600; font-size:34px; line-height:1.18;
+    text-align:center; margin:6px 0 30px; color:var(--ink);
+  }
+  .answers{ flex:1; display:flex; flex-direction:column; gap:16px; }
+  button{ font-family:'Inter',sans-serif; cursor:pointer; }
+  .bigbtn{
+    width:100%; min-height:64px; border-radius:18px; font-size:19px; font-weight:700;
+    background:#fff; border:2px solid #e7e1d6; color:var(--ink); padding:12px 18px;
+  }
+  .bigbtn:active{transform:scale(.97);}
+  .bigbtn-primary{ background:var(--gold); border:2px solid var(--gold); color:#3a2a06; }
+  .bigbtn-secondary{ background:#fff; border:2px solid var(--taupe); color:var(--taupe-text); }
+  .bigbtn:focus-visible, .linktext:focus-visible, .navfab:focus-visible, .demotoggle:focus-visible,
+  .codeinput:focus-visible, .searchbox:focus-visible, .toastundo:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{
+    background:none; border:none; color:var(--taupe-text); font-size:17px; text-decoration:underline;
+    text-align:center; min-height:44px; width:100%;
+  }
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; max-height:420px; }
+  .searchbox, .codeinput{
+    width:100%; min-height:56px; border-radius:16px; border:2px solid #e7e1d6; padding:0 16px;
+    font-size:17px; font-family:'Inter',sans-serif; background:#fff; color:var(--ink); margin-bottom:6px;
+  }
+  .sectionlabel{ margin:14px 0 0; font-size:14px; font-weight:800; letter-spacing:.04em; text-transform:uppercase; color:var(--taupe-text); }
+  .demotoggle{
+    background:none; border:2px dashed #cbbfa0; color:#4a4a4a; font-size:17px; font-weight:700;
+    border-radius:12px; padding:8px 12px; min-height:56px; align-self:center; margin-top:10px;
+  }
+  .demotoggle:active{transform:scale(.97);}
+  .demotoggle-dark{
+    position:absolute; top:96px; left:20px; right:20px; text-align:center;
+    background:rgba(255,255,255,.14); border:2px dashed rgba(255,255,255,.45); color:#f5efe6;
+    font-size:17px; font-weight:700; border-radius:12px; padding:8px 12px; min-height:56px;
+  }
+  .demotoggle-dark:active{transform:scale(.97);}
+  .swatch{ width:100%; height:170px; border-radius:18px; margin-bottom:8px; }
+  .swatch.small{ height:120px; }
+  .sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 18px,#7c9c78 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#617a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#D9A441 0 14px,#c98f2c 14px 28px);}
+  .itemname{ font-size:20px; font-weight:800; margin:0; text-align:center; }
+  .itemmeta{ font-size:17px; color:#666; margin:4px 0 0; text-align:center; }
+  .camwrap{ flex:1; display:flex; flex-direction:column; padding:0; margin:-36px -26px -30px; }
+  .camview{
+    flex:1; background:#1c1c1e; position:relative; display:flex; align-items:center; justify-content:center;
+    color:#fff; min-height:520px;
+  }
+  .camview .hint{
+    position:absolute; top:40px; left:20px; right:20px; text-align:center;
+    font-family:'Fraunces',serif; font-size:28px; font-weight:600; color:#fdfbf7;
+  }
+  .camview .status{ font-size:19px; font-weight:700; color:#f0e8d8; }
+  .shutter{
+    position:absolute; bottom:34px; left:50%; transform:translateX(-50%);
+    width:90px; height:90px; border-radius:50%; background:var(--gold); border:6px solid #fff;
+    font-size:34px; display:flex; align-items:center; justify-content:center;
+  }
+  .shutter:active{transform:translateX(-50%) scale(.97);}
+  .center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:10px; }
+  .navcluster{
+    position:absolute; top:14px; left:14px; z-index:20; display:none; gap:8px;
+  }
+  .navfab{
+    min-width:56px; min-height:56px; border-radius:16px; background:rgba(255,255,255,.94); border:2px solid #e7e1d6; color:var(--ink);
+    font-size:15px; font-weight:700; display:flex; align-items:center; justify-content:center; gap:4px;
+    padding:0 12px; box-shadow:0 4px 10px rgba(0,0,0,.12);
+  }
+  .navfab:active{transform:scale(.97);}
+  .sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;}
+  .toast{
+    position:absolute; left:16px; right:16px; bottom:16px; background:#232323; color:#fff;
+    border-radius:14px; padding:14px 18px; display:flex; align-items:center; justify-content:space-between;
+    gap:12px; font-size:16px; font-weight:700; opacity:0; transform:translateY(12px); pointer-events:none;
+    transition:opacity .25s ease, transform .25s ease; z-index:30;
+  }
+  .toast.show{opacity:1; transform:translateY(0); pointer-events:auto;}
+  .toastundo{background:none; border:none; color:var(--gold); font-weight:800; font-size:16px; min-height:56px; padding:0 6px;}
+  @media (prefers-reduced-motion: reduce){
+    *{transition:none !important; animation:none !important;}
+  }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="navcluster" id="navCluster">
+    <button class="navfab" aria-label="Back" onclick="goBack()">‹ Back</button>
+    <button class="navfab" aria-label="Home" onclick="go('home')">⌂ Home</button>
+  </div>
+  <div class="screen" id="screen" role="main"></div>
+  <div class="toast" id="toast" role="status"></div>
+  <div class="sr-only" id="live" aria-live="polite"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1', brand:'York Wallcoverings'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2', brand:'Cole & Son'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3', brand:'Thibaut'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+const RECENT_BRANDS = BRANDS.slice(0,3);
+const DONE_TOAST = {'new-done':'Saved','update-done':'Updated','sample-done':'Marked Received'};
+const STEP_MAP = {
+  'new-brand':[2,3], 'new-save':[3,3],
+  'update-match':[2,3],
+  'find-method':[1,3], 'find-result':[2,3], 'find-detail':[3,3],
+  'sample-match':[2,2],
+};
+const PHOTOCHECK_STEP = { 'new-cam':[1,3], 'update-cam2':[3,3] };
+
+const state = { screen:'home', job:null, item:null, brand:null, resultIndex:0, demoNoMatch:false, checkNext:null, checkRetake:null, confirmScreen:null };
+let historyStack = [];
+let toastTimer = null;
+
+function announce(text){ const el=document.getElementById('live'); if(el) el.textContent = text; }
+function go(screen){
+  if(screen==='home'){ historyStack = []; }
+  else if(state.screen && state.screen!==screen){ historyStack.push(state.screen); }
+  state.screen = screen;
+  render();
+}
+function goReplace(screen){ state.screen = screen; render(); }
+function goBack(){
+  if(historyStack.length){ state.screen = historyStack.pop(); render(); }
+  else go('home');
+}
+function startJob(job){
+  state.job = job; state.item=null; state.brand=null; state.resultIndex=0;
+  const map = {new:'new-cam', update:'update-cam', find:'find-method', sample:'sample-cam'};
+  go(map[job]);
+}
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+function stepLine(){ const m = STEP_MAP[state.screen]; return m ? `<p class="stepline">Step ${m[0]} of ${m[1]}</p>` : ''; }
+function toggleDemo(){ state.demoNoMatch = !state.demoNoMatch; render(); }
+function demoToggleHtml(dark){
+  const cls = dark ? 'demotoggle-dark' : 'demotoggle';
+  return `<button class="${cls}" aria-pressed="${state.demoNoMatch}" onclick="toggleDemo()">Demo: show "no match" ${state.demoNoMatch?'✅ On':'⬜ Off'}</button>`;
+}
+
+function cameraScreen(hint, onShoot, extra){
+  return `<div class="camwrap"><div class="camview">
+    <div class="hint">${hint}</div>
+    <div class="status" id="camStatus">Tap the shutter</div>
+    ${extra||''}
+    <button class="shutter" aria-label="Take photo" onclick="${onShoot}">📸</button>
+  </div></div>`;
+}
+function shoot(cb, loadingLabel){
+  const fromScreen = state.screen;
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  announce('Snapping photo…');
+  setTimeout(()=>{
+    if(state.screen!==fromScreen) return; // user navigated away mid-shot
+    state.item = randomItem();
+    if(loadingLabel){ if(st) st.textContent = loadingLabel; announce(loadingLabel); setTimeout(()=>{ if(state.screen===fromScreen) cb(); }, 500); }
+    else cb();
+  }, 700);
+}
+function shootThen(nextScreen, retakeScreen){
+  shoot(()=>{ state.checkNext=nextScreen; state.checkRetake=retakeScreen; go('photocheck'); });
+}
+function shootOrMiss(nextScreen, retakeScreen, missScreen, loadingLabel){
+  shoot(()=>{
+    if(state.demoNoMatch){ go(missScreen); return; }
+    go(nextScreen);
+  }, loadingLabel);
+}
+function performAction(next, toastMsg){
+  state.confirmScreen = state.screen;
+  go(next);
+  if(toastMsg) showToast(toastMsg);
+}
+function finishCheck(){ performAction(state.checkNext, DONE_TOAST[state.checkNext]); }
+function markReceived(){
+  state.confirmScreen = state.screen;
+  go('sample-printing');
+  announce('Printing sticker…');
+}
+function tryFind(){
+  go('find-loading');
+  announce('Looking for matches…');
+  setTimeout(()=>{ if(state.screen==='find-loading') goReplace(state.demoNoMatch ? 'find-nomatch' : 'find-result'); }, 600);
+}
+function filterBrands(q){
+  q = q.trim().toLowerCase();
+  const recentWrap = document.getElementById('brandRecent');
+  if(recentWrap) recentWrap.style.display = q ? 'none' : '';
+  const full = document.getElementById('brandFullList');
+  if(!full) return;
+  full.querySelectorAll('button').forEach(btn=>{
+    btn.style.display = btn.textContent.toLowerCase().includes(q) ? '' : 'none';
+  });
+}
+function showToast(msg){
+  const t = document.getElementById('toast');
+  t.innerHTML = `${msg} <button class="toastundo" onclick="undoLast()">Undo</button>`;
+  t.classList.add('show');
+  announce(msg + '. Undo available for 5 seconds.');
+  clearTimeout(toastTimer);
+  toastTimer = setTimeout(()=>{ t.classList.remove('show'); }, 5000);
+}
+function undoLast(){
+  const t = document.getElementById('toast');
+  t.classList.remove('show');
+  clearTimeout(toastTimer);
+  if(state.confirmScreen) go(state.confirmScreen);
+}
+function brandListHtml(nextScreen){
+  let html = `<input type="text" class="searchbox" placeholder="Search brands…" aria-label="Search brands" oninput="filterBrands(this.value)">`;
+  html += `<div id="brandRecent"><p class="sectionlabel">Recent</p><div class="brandlist">`;
+  RECENT_BRANDS.forEach(b=>{ html += `<button class="bigbtn" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div></div>`;
+  html += `<p class="sectionlabel">All Brands</p><div class="brandlist" id="brandFullList">`;
+  BRANDS.forEach(b=>{ html += `<button class="bigbtn" onclick="state.brand='${b}'; go('${nextScreen}')">${b}</button>`; });
+  html += `</div>`;
+  return html;
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  const nav = document.getElementById('navCluster');
+  nav.style.display = state.screen==='home' ? 'none' : 'flex';
+  let html = '';
+
+  if(state.screen==='home'){
+    html += `<h1 class="question">What do you need to do?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="startJob('new')">Add New Item</button>
+        <button class="bigbtn" onclick="startJob('update')">Update an Item</button>
+        <button class="bigbtn" onclick="startJob('find')">Find an Item</button>
+        <button class="bigbtn" onclick="startJob('sample')">A Sample Came In</button>
+      </div>`;
+  }
+
+  else if(state.screen==='photocheck'){
+    const st = PHOTOCHECK_STEP[state.checkRetake];
+    html += st ? `<p class="stepline">Step ${st[0]} of ${st[1]}</p>` : '';
+    html += `<h1 class="question">Does this look right?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <div class="answers" style="margin-top:20px;">
+        <button class="linktext" onclick="go(state.checkRetake)">Retake Photo</button>
+        <button class="bigbtn bigbtn-primary" onclick="finishCheck()">Looks Good</button>
+      </div>`;
+  }
+
+  else if(state.screen==='new-cam'){
+    html += cameraScreen('Take a photo of it.', "shootThen('new-brand','new-cam')");
+  }
+  else if(state.screen==='new-brand'){
+    html += stepLine() + `<h1 class="question">Which brand is it?</h1>` + brandListHtml('new-save');
+  }
+  else if(state.screen==='new-save'){
+    html += stepLine();
+    html += `<h1 class="question">Save it?</h1>
+      <div class="swatch small ${state.item.sw}"></div>
+      <p class="itemmeta">${state.brand} · code ${state.item.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="linktext" onclick="go('new-cam')">Retake Photo</button>
+        <button class="bigbtn bigbtn-primary" onclick="performAction('new-done','Saved')">Save as Draft</button>
+      </div>`;
+  }
+  else if(state.screen==='new-done'){
+    html += `<div class="center">
+        <h1 class="question">Saved! 🎉</h1>
+        <div class="swatch small ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">Brand: ${state.brand} · Code: ${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="startJob('new')">Do Another</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  else if(state.screen==='update-cam'){
+    html += cameraScreen('Scan the label or pattern.', "shootOrMiss('update-match','update-cam','update-nomatch','Looking for matches…')", demoToggleHtml(true));
+  }
+  else if(state.screen==='update-nomatch'){
+    html += `<h1 class="question">No match found.</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="go('update-cam')">Try again</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('update-typecode')">Type the code instead</button>
+      </div>`;
+  }
+  else if(state.screen==='update-typecode'){
+    html += `<h1 class="question">Type the code.</h1>
+      <input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="state.item=MOCK_ITEMS[0]; go('update-match')">Find</button>
+      </div>`;
+  }
+  else if(state.screen==='update-match'){
+    html += stepLine();
+    html += `<h1 class="question">Is this it?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-secondary" onclick="go('update-cam')">No, Let Me Search</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Yes</button>
+      </div>`;
+  }
+  else if(state.screen==='update-cam2'){
+    html += cameraScreen('Take the new photo.', "shootThen('update-done','update-cam2')");
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="center">
+        <h1 class="question">Updated! ✅</h1>
+        <div class="swatch small ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="startJob('update')">Do Another</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  else if(state.screen==='find-method'){
+    html += stepLine();
+    html += `<h1 class="question">How do you want to find it?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="tryFind()">Scan</button>
+        <button class="bigbtn" onclick="tryFind()">Talk</button>
+        <button class="bigbtn" onclick="tryFind()">Type</button>
+      </div>`;
+    html += demoToggleHtml(false);
+  }
+  else if(state.screen==='find-loading'){
+    html += `<div class="center"><h1 class="question">Looking for matches…</h1></div>`;
+  }
+  else if(state.screen==='find-nomatch'){
+    html += `<h1 class="question">No match found.</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="go('find-method')">Try again</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('find-typecode')">Type the code instead</button>
+      </div>`;
+  }
+  else if(state.screen==='find-typecode'){
+    html += `<h1 class="question">Type the code.</h1>
+      <input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="state.item=MOCK_ITEMS[0]; go('find-detail')">Find</button>
+      </div>`;
+  }
+  else if(state.screen==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    html += stepLine();
+    html += `<h1 class="question">Which one is it?</h1>
+      <div class="swatch ${it.sw}"></div>
+      <p class="itemname">${it.name} — ${it.color}</p>
+      <p class="itemmeta">code ${it.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
+        <button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
+      </div>`;
+  }
+  else if(state.screen==='find-exhausted'){
+    html += `<h1 class="question">That's all — try another way?</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">Scan</button>
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">Talk</button>
+        <button class="bigbtn" onclick="state.resultIndex=0; go('find-result')">Type</button>
+      </div>`;
+  }
+  else if(state.screen==='find-detail'){
+    html += stepLine();
+    html += `<div class="center">
+        <h1 class="question" style="font-size:26px; margin-bottom:14px;">${state.item.name}</h1>
+        <div class="swatch ${state.item.sw}" style="width:260px;"></div>
+        <p class="itemmeta">${state.item.color} · code ${state.item.code} · ${state.item.brand}</p>
+      </div>
+      <div class="answers">
+        <button class="linktext" onclick="go('home')">Home</button>
+        <button class="bigbtn bigbtn-secondary" onclick="go('find-method')">Search Again</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Update This</button>
+      </div>`;
+  }
+
+  else if(state.screen==='sample-cam'){
+    html += cameraScreen('Scan the box label.', "shootOrMiss('sample-match','sample-cam','sample-nomatch','Looking for matches…')", demoToggleHtml(true));
+  }
+  else if(state.screen==='sample-nomatch'){
+    html += `<h1 class="question">No match found.</h1>
+      <div class="answers">
+        <button class="bigbtn" onclick="go('sample-cam')">Try again</button>
+        <button class="bigbtn bigbtn-primary" onclick="go('sample-typecode')">Type the code instead</button>
+      </div>`;
+  }
+  else if(state.screen==='sample-typecode'){
+    html += `<h1 class="question">Type the code.</h1>
+      <input type="text" class="codeinput" placeholder="e.g. DW-10423" aria-label="Item code">
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-primary" onclick="state.item=MOCK_ITEMS[0]; go('sample-match')">Find</button>
+      </div>`;
+  }
+  else if(state.screen==='sample-match'){
+    html += stepLine();
+    html += `<h1 class="question">Mark it received?</h1>
+      <div class="swatch ${state.item.sw}"></div>
+      <p class="itemname">${state.item.name} — ${state.item.color}</p>
+      <p class="itemmeta">code ${state.item.code}</p>
+      <div class="answers" style="margin-top:20px;">
+        <button class="bigbtn bigbtn-secondary" onclick="go('sample-cam')">No, Scan Again</button>
+        <button class="bigbtn bigbtn-primary" onclick="markReceived()">Yes, Mark Received</button>
+      </div>`;
+  }
+  else if(state.screen==='sample-printing'){
+    html += `<div class="center"><h1 class="question">Printing your sticker…</h1><p class="itemmeta">🖨️ One sec…</p></div>`;
+    setTimeout(()=>{ if(state.screen==='sample-printing'){ go('sample-done'); showToast('Marked Received'); } }, 1100);
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="center">
+        <h1 class="question">Done! ✅</h1>
+        <div class="swatch small ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">Brand: ${state.item.brand} · Code: ${state.item.code}</p>
+        <p class="itemmeta">Sticker printed and item received.</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn bigbtn-primary" onclick="startJob('sample')">Do Another</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div>`;
+  }
+
+  s.innerHTML = html;
+}
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-detail'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; go('find-result'); }
+  else { go('find-exhausted'); }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v7-scan-and-go.html b/public/kid-simple/v7-scan-and-go.html
new file mode 100644
index 0000000..333ee91
--- /dev/null
+++ b/public/kid-simple/v7-scan-and-go.html
@@ -0,0 +1,324 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v7 — Scan &amp; Go</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Spectral:wght@500;600;700&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --teal:#0F3D3E; --teal-2:#164C4D; --copper:#C7784F; --copper-dark:#9B5A38;
+    --parchment:#F6EFE4; --ink:#2E2A26; --muted:#8A7F6E; --sage:#5C8F6B;
+    --line:#E7DDCB;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#d9d3c8;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--parchment); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.30); display:flex; flex-direction:column; position:relative;
+  }
+  .screen{ flex:1; display:flex; flex-direction:column; }
+  h1,h2{ font-family:'Spectral',serif; margin:0; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+
+  /* ---- viewfinder (dark scan screens) ---- */
+  .viewfinder{
+    flex:1; min-height:780px; background:radial-gradient(120% 90% at 50% 0%, #1a5152 0%, var(--teal) 55%, #0A2C2D 100%);
+    display:flex; flex-direction:column; align-items:center; color:#F6EFE4; position:relative; overflow:hidden;
+    padding:44px 24px 30px;
+  }
+  .dw-mark{ position:absolute; top:16px; left:20px; font-size:12px; letter-spacing:2px; color:rgba(246,239,228,.55); font-weight:700; }
+  .hint-top{
+    font-family:'Spectral',serif; font-weight:600; font-size:22px; line-height:1.3; text-align:center;
+    margin:14px 0 22px; color:#FBF7F0;
+  }
+  .scan-frame{
+    width:220px; height:220px; position:relative; margin:6px auto 20px; flex-shrink:0;
+  }
+  .scan-frame .corner{ position:absolute; width:36px; height:36px; border-color:var(--copper); border-style:solid; }
+  .corner.tl{ top:0; left:0; border-width:5px 0 0 5px; border-top-left-radius:10px; }
+  .corner.tr{ top:0; right:0; border-width:5px 5px 0 0; border-top-right-radius:10px; }
+  .corner.bl{ bottom:0; left:0; border-width:0 0 5px 5px; border-bottom-left-radius:10px; }
+  .corner.br{ bottom:0; right:0; border-width:0 5px 5px 0; border-bottom-right-radius:10px; }
+  .scan-frame .tag-icon{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:64px; opacity:.9; }
+  .scanline{
+    position:absolute; left:8px; right:8px; height:3px; background:linear-gradient(90deg, transparent, #FFD9B0, transparent);
+    box-shadow:0 0 12px 2px rgba(255,178,110,.7); animation:sweep 1.8s ease-in-out infinite;
+  }
+  @keyframes sweep{ 0%{top:6px;} 50%{top:206px;} 100%{top:6px;} }
+  .scan-status{ min-height:22px; font-size:15px; font-weight:700; color:#FFD9B0; text-align:center; margin-bottom:14px; }
+
+  .toggle-row{ display:flex; gap:10px; width:100%; margin-bottom:18px; }
+  .toggle-btn{
+    flex:1; min-height:56px; border-radius:16px; border:2px solid rgba(246,239,228,.28); background:rgba(246,239,228,.08);
+    color:#F6EFE4; font-size:15px; font-weight:700; display:flex; align-items:center; justify-content:center; gap:6px;
+  }
+  .toggle-btn.active{ background:var(--copper); border-color:var(--copper); color:#2A1608; }
+  .toggle-btn:focus-visible{ outline:3px solid #6fd3d6; outline-offset:2px; }
+
+  .scanbtn{
+    width:100%; min-height:68px; border-radius:22px; background:var(--copper); border:none; color:#2A1608;
+    font-size:20px; font-weight:800; letter-spacing:.3px; box-shadow:0 10px 24px rgba(199,120,79,.35);
+  }
+  .scanbtn:disabled{ opacity:.7; }
+  .scanbtn:focus-visible{ outline:3px solid #6fd3d6; outline-offset:2px; }
+
+  .vf-link{
+    margin-top:16px; background:none; border:none; color:#D9CFC0; font-size:16px; text-decoration:underline;
+    min-height:56px; width:100%;
+  }
+  .vf-link:focus-visible{ outline:3px solid #6fd3d6; outline-offset:2px; }
+
+  .shutter-wrap{ flex:1; display:flex; align-items:flex-end; justify-content:center; padding-bottom:26px; width:100%; }
+  .shutter{
+    width:92px; height:92px; border-radius:50%; background:var(--copper); border:6px solid #F6EFE4;
+    font-size:36px; display:flex; align-items:center; justify-content:center; box-shadow:0 10px 26px rgba(0,0,0,.35);
+  }
+  .shutter:focus-visible{ outline:3px solid #6fd3d6; outline-offset:2px; }
+
+  /* ---- card / content screens (warm parchment) ---- */
+  .card-screen{ flex:1; display:flex; flex-direction:column; padding:34px 26px 28px; background:var(--parchment); }
+  .topbar{ display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
+  .homefab{
+    min-width:52px; min-height:52px; border-radius:14px; background:#fff; border:2px solid var(--line);
+    color:var(--ink); font-size:14px; font-weight:700; display:flex; align-items:center; justify-content:center; gap:4px;
+    padding:0 12px;
+  }
+  .homefab:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .kicker{ font-size:13px; font-weight:800; letter-spacing:1.5px; text-transform:uppercase; color:var(--copper-dark); margin:2px 0 8px; }
+  .headline{ font-size:28px; font-weight:600; line-height:1.22; color:var(--ink); margin:0 0 22px; }
+
+  .item-card{
+    background:#fff; border:2px solid var(--line); border-radius:22px; padding:20px; display:flex; flex-direction:column;
+    align-items:center; gap:10px; margin-bottom:22px;
+  }
+  .swatch{ width:100%; height:150px; border-radius:16px; }
+  .sw1{background:repeating-linear-gradient(45deg,#5C8F6B 0 18px,#4c7a5a 18px 36px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#617a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#C7784F 0 14px,#9B5A38 14px 28px);}
+  .itemname{ font-size:20px; font-weight:800; margin:0; text-align:center; }
+  .itemmeta{ font-size:15px; color:var(--muted); margin:0; text-align:center; }
+
+  .stack{ display:flex; flex-direction:column; gap:14px; }
+  .btn{
+    width:100%; min-height:60px; border-radius:18px; font-size:18px; font-weight:800; padding:10px 16px;
+    border:2px solid var(--line); background:#fff; color:var(--ink);
+  }
+  .btn-primary{ background:var(--copper); border-color:var(--copper); color:#2A1608; }
+  .btn-secondary{ background:var(--teal); border-color:var(--teal); color:#F6EFE4; }
+  .btn:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .link{
+    background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline;
+    min-height:56px; width:100%; margin-top:6px;
+  }
+  .link:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+
+  .suggest-row{
+    display:flex; align-items:center; gap:14px; background:#fff; border:2px solid var(--line); border-radius:18px;
+    padding:12px 14px; min-height:64px; width:100%; text-align:left; margin-bottom:12px;
+  }
+  .suggest-row .sw-mini{ width:52px; height:52px; border-radius:12px; flex-shrink:0; }
+  .suggest-row .txt{ display:flex; flex-direction:column; gap:2px; }
+  .suggest-row .txt b{ font-size:16px; }
+  .suggest-row .txt span{ font-size:13px; color:var(--muted); }
+
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
+  .brand-row{
+    width:100%; min-height:60px; border-radius:16px; border:2px solid var(--line); background:#fff; color:var(--ink);
+    font-size:17px; font-weight:700; text-align:left; padding:0 18px;
+  }
+
+  .center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:14px; text-align:center; }
+  .bigcheck{ font-size:56px; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+
+const state = { screen:'home', simMode:'known', item:null };
+
+function go(screen){ state.screen = screen; render(); }
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+function homeFab(){ return `<div class="topbar"><button class="homefab" onclick="go('home')">⌂ Home</button><span></span></div>`; }
+
+function doScan(){
+  const btn = document.getElementById('scanBtn');
+  const st = document.getElementById('scanStatus');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Scanning…';
+  setTimeout(()=>{
+    if(state.simMode==='known'){ state.item = randomItem(); go('scan-match'); }
+    else { go('scan-nomatch'); }
+  }, 850);
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  let html = '';
+
+  if(state.screen==='home'){
+    html += `<div class="viewfinder">
+      <div class="dw-mark">DESIGNER WALLCOVERINGS</div>
+      <div class="hint-top">Point your camera<br>at a tag or box</div>
+      <div class="scan-frame">
+        <div class="corner tl"></div><div class="corner tr"></div>
+        <div class="corner bl"></div><div class="corner br"></div>
+        <div class="tag-icon">${state.simMode==='known' ? '🏷️' : '🆕'}</div>
+        <div class="scanline"></div>
+      </div>
+      <div class="scan-status" id="scanStatus">&nbsp;</div>
+      <div class="toggle-row">
+        <button class="toggle-btn ${state.simMode==='known'?'active':''}" onclick="state.simMode='known'; render();">🏷️ Known Tag</button>
+        <button class="toggle-btn ${state.simMode!=='known'?'active':''}" onclick="state.simMode='new'; render();">🆕 New Item</button>
+      </div>
+      <button class="scanbtn" id="scanBtn" onclick="doScan()">Tap to Scan</button>
+      <button class="vf-link" onclick="go('find-search')">Or type a code instead</button>
+    </div>`;
+  }
+
+  else if(state.screen==='scan-match'){
+    html += `<div class="card-screen">${homeFab()}
+      <div class="kicker">Found It</div>
+      <h1 class="headline">What do you want to do?</h1>
+      <div class="item-card">
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">code ${state.item.code}</p>
+      </div>
+      <div class="stack">
+        <button class="btn btn-primary" onclick="go('update-camera')">Update It</button>
+        <button class="btn btn-secondary" onclick="go('sample-printing')">Sample Just Arrived</button>
+        <button class="link" onclick="go('home')">Not this one — scan again</button>
+      </div>
+    </div>`;
+  }
+
+  else if(state.screen==='scan-nomatch'){
+    html += `<div class="card-screen">${homeFab()}
+      <div class="center" style="flex:none; margin:30px 0 26px;">
+        <div class="bigcheck">🔎</div>
+        <h1 class="headline" style="margin-bottom:0;">Hmm, we don't<br>recognize this one.</h1>
+      </div>
+      <div class="stack">
+        <button class="btn btn-primary" onclick="go('add-brand')">Add It as New</button>
+        <button class="link" onclick="go('home')">Scan Again</button>
+      </div>
+    </div>`;
+  }
+
+  else if(state.screen==='add-camera'){
+    html += cameraScreen('Take a photo of it.', "add-brand");
+  }
+  else if(state.screen==='add-brand'){
+    html += `<div class="card-screen">${homeFab()}
+      <div class="kicker">Almost Done</div>
+      <h1 class="headline">Which brand is it?</h1>
+      <div class="brandlist">${BRANDS.map(b=>`<button class="brand-row" onclick="go('add-done')">${b}</button>`).join('')}</div>
+    </div>`;
+  }
+  else if(state.screen==='add-done'){
+    html += `<div class="card-screen"><div class="center">
+      <div class="bigcheck">🎉</div>
+      <h1 class="headline" style="margin-bottom:0;">Saved as a new item!</h1>
+      <div class="stack" style="width:100%; margin-top:18px;">
+        <button class="btn btn-primary" onclick="go('home')">Scan Something Else</button>
+      </div>
+    </div></div>`;
+  }
+
+  else if(state.screen==='update-camera'){
+    html += cameraScreen('Take the new photo.', "update-done");
+  }
+  else if(state.screen==='update-done'){
+    html += `<div class="card-screen"><div class="center">
+      <div class="bigcheck">✅</div>
+      <h1 class="headline" style="margin-bottom:0;">Updated!</h1>
+      <div class="stack" style="width:100%; margin-top:18px;">
+        <button class="btn btn-primary" onclick="go('home')">Scan Something Else</button>
+      </div>
+    </div></div>`;
+  }
+
+  else if(state.screen==='sample-printing'){
+    html += `<div class="card-screen"><div class="center">
+      <div class="bigcheck">🖨️</div>
+      <h1 class="headline" style="margin-bottom:0;">Printing your sticker…</h1>
+    </div></div>`;
+    setTimeout(()=>{ if(state.screen==='sample-printing') go('sample-done'); }, 1100);
+  }
+  else if(state.screen==='sample-done'){
+    html += `<div class="card-screen"><div class="center">
+      <div class="bigcheck">✅</div>
+      <h1 class="headline" style="margin-bottom:0;">Done! Sample marked received.</h1>
+      <div class="stack" style="width:100%; margin-top:18px;">
+        <button class="btn btn-primary" onclick="go('home')">Scan Something Else</button>
+      </div>
+    </div></div>`;
+  }
+
+  else if(state.screen==='find-search'){
+    html += `<div class="card-screen">${homeFab()}
+      <div class="kicker">Find An Item</div>
+      <h1 class="headline">Which one are you<br>looking for?</h1>
+      ${MOCK_ITEMS.map(it=>`
+        <button class="suggest-row" onclick='findPick("${it.code}")'>
+          <div class="sw-mini ${it.sw}"></div>
+          <div class="txt"><b>${it.name}</b><span>${it.color} · code ${it.code}</span></div>
+        </button>`).join('')}
+      <button class="vf-link" style="color:var(--muted); margin-top:4px;" onclick="go('home')">Scan instead</button>
+    </div>`;
+  }
+  else if(state.screen==='find-detail'){
+    html += `<div class="card-screen">${homeFab()}
+      <div class="kicker">Here It Is</div>
+      <div class="item-card">
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">code ${state.item.code}</p>
+      </div>
+      <div class="stack">
+        <button class="btn btn-primary" onclick="go('update-camera')">Update This</button>
+        <button class="btn btn-secondary" onclick="go('find-search')">Search Again</button>
+      </div>
+    </div>`;
+  }
+
+  s.innerHTML = html;
+}
+
+function cameraScreen(hint, nextScreen){
+  return `<div class="viewfinder" style="padding-top:56px;">
+    <div class="dw-mark">DESIGNER WALLCOVERINGS</div>
+    <div class="hint-top">${hint}</div>
+    <div class="shutter-wrap">
+      <button class="shutter" aria-label="Take photo" onclick="shoot('${nextScreen}')">📸</button>
+    </div>
+  </div>`;
+}
+function shoot(nextScreen){
+  const btn = document.querySelector('.shutter');
+  if(btn){ btn.disabled = true; btn.style.opacity = .6; }
+  setTimeout(()=> go(nextScreen), 650);
+}
+function findPick(code){
+  state.item = MOCK_ITEMS.find(i=>i.code===code);
+  go('find-detail');
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v8-mode-dial.html b/public/kid-simple/v8-mode-dial.html
new file mode 100644
index 0000000..773b843
--- /dev/null
+++ b/public/kid-simple/v8-mode-dial.html
@@ -0,0 +1,354 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v8 — Mode Dial</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700;9..144,800&family=Manrope:wght@400;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --navy:#141B2E; --navy2:#1E2740; --cream:#F6EFE4; --ink:#241C14; --muted:#8B8172;
+    --copper:#C97B3F; --copper-ink:#3A200C;
+    --teal:#4F8A8B; --teal-ink:#0D2626;
+    --plum:#8B5A8F; --plum-ink:#2B0F2C;
+    --mustard:#D4A24C; --mustard-ink:#3A2707;
+    --green:#4C9A6A;
+  }
+  *{box-sizing:border-box;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; min-height:780px; background:var(--cream); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
+  }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+  .screen{ flex:1; display:flex; flex-direction:column; position:relative; }
+
+  /* ---------- HOME: camera + mode dial ---------- */
+  .cam{
+    flex:1; background:
+      radial-gradient(120px 120px at 78% 22%, rgba(201,123,63,.28), transparent 60%),
+      radial-gradient(160px 160px at 15% 68%, rgba(79,138,139,.22), transparent 60%),
+      radial-gradient(220px 220px at 60% 85%, rgba(139,90,143,.20), transparent 60%),
+      linear-gradient(180deg, var(--navy) 0%, var(--navy2) 100%);
+    position:relative; display:flex; flex-direction:column; color:var(--cream); min-height:780px;
+  }
+  .dwmark{ position:absolute; top:18px; left:20px; font-family:'Fraunces',serif; font-weight:700; font-size:14px;
+    letter-spacing:.14em; color:rgba(246,239,228,.72); }
+  .reticle{
+    position:absolute; top:50%; left:50%; transform:translate(-50%,-58%);
+    width:200px; height:200px; border:2px solid rgba(246,239,228,.28); border-radius:28px;
+  }
+  .reticle::before,.reticle::after{ content:''; position:absolute; width:22px; height:22px; border-color:rgba(246,239,228,.65); }
+  .reticle::before{ top:-2px; left:-2px; border-top:3px solid; border-left:3px solid; border-radius:6px 0 0 0; }
+  .reticle::after{ bottom:-2px; right:-2px; border-bottom:3px solid; border-right:3px solid; border-radius:0 0 6px 0; }
+
+  .hint{
+    position:absolute; top:52px; left:20px; right:20px; text-align:center;
+    font-family:'Fraunces',serif; font-weight:600; font-size:21px; color:var(--cream);
+  }
+  .hint .sub{ display:block; margin-top:4px; font-family:'Manrope',sans-serif; font-weight:600; font-size:14px; color:rgba(246,239,228,.68); }
+
+  .dialdock{ position:absolute; left:0; right:0; bottom:0; padding:0 0 30px; display:flex; flex-direction:column; align-items:center; gap:16px; }
+  .modestrip{
+    display:flex; gap:10px; overflow-x:auto; scroll-snap-type:x proximity; padding:4px 20px;
+    max-width:390px; -webkit-overflow-scrolling:touch;
+  }
+  .modestrip::-webkit-scrollbar{ display:none; }
+  .modepill{
+    scroll-snap-align:center; flex:0 0 auto; min-height:56px; padding:0 18px; border-radius:18px;
+    background:rgba(255,255,255,.10); border:2px solid rgba(255,255,255,.16); color:rgba(246,239,228,.62);
+    font-weight:800; font-size:13px; letter-spacing:.10em; display:flex; align-items:center; gap:8px;
+  }
+  .modepill .ic{ font-size:18px; }
+  .modepill.active{ background:rgba(255,255,255,.16); color:var(--cream); }
+  .modepill.active[data-m="new"]{ border-color:var(--copper); box-shadow:0 0 0 1px var(--copper) inset; }
+  .modepill.active[data-m="update"]{ border-color:var(--teal); box-shadow:0 0 0 1px var(--teal) inset; }
+  .modepill.active[data-m="find"]{ border-color:var(--plum); box-shadow:0 0 0 1px var(--plum) inset; }
+  .modepill.active[data-m="sample"]{ border-color:var(--mustard); box-shadow:0 0 0 1px var(--mustard) inset; }
+  .modepill:focus-visible{ outline:3px solid #fff; outline-offset:2px; }
+
+  .shutterwrap{ display:flex; flex-direction:column; align-items:center; gap:10px; }
+  .shutterlabel{ font-weight:800; font-size:15px; color:var(--cream); }
+  .shutter{
+    width:96px; height:96px; border-radius:50%; border:6px solid rgba(255,255,255,.9);
+    display:flex; align-items:center; justify-content:center; font-size:36px; color:#fff;
+    transition:transform .08s ease;
+  }
+  .shutter:active{ transform:scale(.94); }
+  .shutter:focus-visible{ outline:3px solid #fff; outline-offset:4px; }
+  .flash{ position:absolute; inset:0; background:#fff; opacity:0; pointer-events:none; }
+  .flash.go{ animation:flashfx .5s ease; }
+  @keyframes flashfx{ 0%{opacity:0;} 12%{opacity:.9;} 100%{opacity:0;} }
+
+  /* ---------- generic light screens ---------- */
+  .pad{ padding:60px 26px 30px; flex:1; display:flex; flex-direction:column; }
+  .backbar{
+    position:absolute; top:14px; left:14px; z-index:5; min-width:56px; min-height:56px;
+    border-radius:14px; background:#fff; border:2px solid #EBE3D6; color:var(--ink);
+    font-size:14px; font-weight:800; display:flex; align-items:center; justify-content:center; gap:4px;
+    padding:0 14px;
+  }
+  .backbar:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .question{ font-family:'Fraunces',serif; font-weight:700; font-size:28px; line-height:1.2; margin:6px 0 22px; }
+  .answers{ display:flex; flex-direction:column; gap:14px; margin-top:auto; }
+  .bigbtn{
+    width:100%; min-height:60px; border-radius:18px; font-size:18px; font-weight:800;
+    background:#fff; border:2px solid #EBE3D6; color:var(--ink); padding:12px 18px;
+  }
+  .bigbtn-secondary{ background:#fff; color:var(--muted); border:2px solid #E3DACB; }
+  .bigbtn:focus-visible{ outline:3px solid #2B6CB0; outline-offset:2px; }
+  .linktext{ background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline; min-height:56px; }
+
+  .brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
+
+  .card{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:6px; margin:8px 0 24px; }
+  .swatch{ width:100%; max-width:260px; height:170px; border-radius:18px; }
+  .sw1{background:repeating-linear-gradient(45deg,#C9A24B 0 16px,#b98a2e 16px 32px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#7C93B0 0 16px,#5f7a99 16px 32px);}
+  .sw3{background:repeating-linear-gradient(90deg,#8FAE8B 0 14px,#729070 14px 28px);}
+  .sw4{background:repeating-linear-gradient(135deg,#C0785F 0 15px,#a85f47 15px 30px);}
+  .itemname{ font-size:19px; font-weight:800; margin:2px 0 0; }
+  .itemmeta{ font-size:15px; color:var(--muted); margin:2px 0 0; }
+
+  .center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:8px; text-align:center; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const MODES = {
+  new:    { label:'NEW',    icon:'🆕', color:'var(--copper)',  ink:'var(--copper-ink)',  shutterIcon:'📸', hint:'Point at anything new.', sub:'Tap to add a new item' },
+  update: { label:'UPDATE', icon:'🔄', color:'var(--teal)',    ink:'var(--teal-ink)',    shutterIcon:'📷', hint:'Scan the label or pattern.', sub:'Tap to update an item' },
+  find:   { label:'FIND',   icon:'🔍', color:'var(--plum)',    ink:'var(--plum-ink)',    shutterIcon:'🔎', hint:'Scan to find a match.', sub:'Tap to find an item' },
+  sample: { label:'SAMPLE', icon:'📦', color:'var(--mustard)', ink:'var(--mustard-ink)', shutterIcon:'📦', hint:'Scan the box label.', sub:'Tap to log a sample' },
+};
+const MODE_ORDER = ['new','update','find','sample'];
+
+const MOCK_ITEMS = [
+  { name:'Harbor Stripe', color:'Indigo', code:'item 4471', sw:'sw2' },
+  { name:'Fern & Fable',  color:'Moss',   code:'item 2093', sw:'sw3' },
+  { name:'Ember Weave',   color:'Rust',   code:'item 6650', sw:'sw4' },
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+
+const state = { screen:'home', mode:'new', job:null, item:null, brand:null, resultIndex:0, shooting:false };
+
+function go(screen){ state.screen = screen; render(); }
+function setMode(m){ state.mode = m; render(); }
+
+function accent(job){
+  return (MODES[job] || MODES.new).color;
+}
+function accentInk(job){
+  return (MODES[job] || MODES.new).ink;
+}
+
+function shootFromHome(){
+  if(state.shooting) return;
+  state.shooting = true;
+  state.job = state.mode;
+  render();
+  setTimeout(()=>{
+    state.shooting = false;
+    state.item = randomItem();
+    if(state.mode==='new') go('new-brand');
+    else if(state.mode==='update') go('update-match');
+    else if(state.mode==='find'){ state.resultIndex = 0; go('find-result'); }
+    else if(state.mode==='sample') go('sample-match');
+  }, 650);
+}
+function shootPlain(cb){
+  const st = document.getElementById('camStatus2');
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(cb, 650);
+}
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+
+function backBtn(target){
+  return `<button class="backbar" onclick="go('${target}')">‹ Camera</button>`;
+}
+
+function plainCamera(hint, onShoot, backTarget){
+  return `<div class="cam" style="min-height:auto; flex:1;">
+      ${backBtn(backTarget)}
+      <div class="hint" style="top:70px;">${hint}</div>
+      <div class="dialdock" style="position:static; margin-top:auto; padding-bottom:40px;">
+        <div class="shutterwrap">
+          <span class="shutterlabel" id="camStatus2">Tap to shoot</span>
+          <button class="shutter" style="background:${accent(state.job)};" aria-label="Take photo" onclick="${onShoot}">📸</button>
+        </div>
+      </div>
+    </div>`;
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  let html = '';
+
+  if(state.screen==='home'){
+    const m = MODES[state.mode];
+    let pills = '';
+    MODE_ORDER.forEach(key=>{
+      const mm = MODES[key];
+      pills += `<button class="modepill ${key===state.mode?'active':''}" data-m="${key}" onclick="setMode('${key}')" aria-pressed="${key===state.mode}">
+        <span class="ic">${mm.icon}</span>${mm.label}</button>`;
+    });
+    html = `<div class="cam">
+      <div class="flash" id="flash"></div>
+      <div class="dwmark">DW · PHOTO</div>
+      <div class="reticle" aria-hidden="true"></div>
+      <div class="hint">${m.hint}<span class="sub">${m.sub}</span></div>
+      <div class="dialdock">
+        <div class="modestrip" role="tablist" aria-label="Choose what you're doing">${pills}</div>
+        <div class="shutterwrap">
+          <span class="shutterlabel">${state.shooting ? 'Snapping…' : m.label + ' MODE'}</span>
+          <button class="shutter" style="background:${m.color};" aria-label="Shoot for ${m.label}" onclick="shootFromHome()" ${state.shooting?'disabled':''}>${m.shutterIcon}</button>
+        </div>
+      </div>
+    </div>`;
+    s.innerHTML = html;
+    if(state.shooting){
+      const f = document.getElementById('flash');
+      if(f){ f.classList.remove('go'); void f.offsetWidth; f.classList.add('go'); }
+    }
+    return;
+  }
+
+  // ---- NEW ----
+  if(state.screen==='new-brand'){
+    html = `<div class="pad">${backBtn('home')}
+      <h1 class="question">Which brand is it?</h1>
+      <div class="brandlist">`;
+    BRANDS.forEach(b=>{ html += `<button class="bigbtn" onclick="state.brand='${b}'; go('new-save')">${b}</button>`; });
+    html += `</div></div>`;
+  }
+  else if(state.screen==='new-save'){
+    html = `<div class="pad">${backBtn('new-brand')}
+      <h1 class="question">Save it?</h1>
+      <div class="card">
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemmeta">${state.brand} · ${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('new')}; border-color:${accent('new')}; color:#fff;" onclick="go('new-done')">Save as Draft</button>
+        <button class="linktext" onclick="go('home')">Retake Photo</button>
+      </div></div>`;
+  }
+  else if(state.screen==='new-done'){
+    html = `<div class="pad"><div class="center">
+        <h1 class="question">Saved! 🎉</h1>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('new')}; border-color:${accent('new')}; color:#fff;" onclick="setMode('new'); go('home')">Add Another</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div></div>`;
+  }
+
+  // ---- UPDATE ----
+  else if(state.screen==='update-match'){
+    html = `<div class="pad">${backBtn('home')}
+      <h1 class="question">Is this it?</h1>
+      <div class="card">
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('update')}; border-color:${accent('update')}; color:#fff;" onclick="go('update-cam2')">Yes, That's It</button>
+        <button class="bigbtn bigbtn-secondary" onclick="go('home')">No, Let Me Search</button>
+      </div></div>`;
+  }
+  else if(state.screen==='update-cam2'){
+    html = plainCamera('Take the new photo.', "shootPlain(()=>go('update-done'))", 'update-match');
+  }
+  else if(state.screen==='update-done'){
+    html = `<div class="pad"><div class="center">
+        <h1 class="question">Updated! ✅</h1>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('update')}; border-color:${accent('update')}; color:#fff;" onclick="go('home')">Home</button>
+      </div></div>`;
+  }
+
+  // ---- FIND ----
+  else if(state.screen==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    html = `<div class="pad">${backBtn('home')}
+      <h1 class="question">Is this the one?</h1>
+      <div class="card">
+        <div class="swatch ${it.sw}"></div>
+        <p class="itemname">${it.name} — ${it.color}</p>
+        <p class="itemmeta">${it.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('find')}; border-color:${accent('find')}; color:#fff;" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
+      </div></div>`;
+  }
+  else if(state.screen==='find-exhausted'){
+    html = `<div class="pad">${backBtn('home')}
+      <h1 class="question">That's all we found.</h1>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('find')}; border-color:${accent('find')}; color:#fff;" onclick="state.resultIndex=0; go('find-result')">Try Again</button>
+        <button class="linktext" onclick="go('home')">Home</button>
+      </div></div>`;
+  }
+  else if(state.screen==='find-detail'){
+    html = `<div class="pad"><div class="center">
+        <h1 class="question" style="font-size:24px;">${state.item.name}</h1>
+        <div class="swatch ${state.item.sw}" style="max-width:220px;"></div>
+        <p class="itemmeta">${state.item.color} · ${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('update')}; border-color:${accent('update')}; color:#fff;" onclick="setMode('update'); go('update-cam2')">Update This</button>
+        <button class="bigbtn bigbtn-secondary" onclick="setMode('find'); go('home')">Search Again</button>
+      </div></div>`;
+  }
+
+  // ---- SAMPLE ----
+  else if(state.screen==='sample-match'){
+    html = `<div class="pad">${backBtn('home')}
+      <h1 class="question">Mark it received?</h1>
+      <div class="card">
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">${state.item.code}</p>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('sample')}; border-color:${accent('sample')}; color:#fff;" onclick="go('sample-printing')">Yes, Mark Received</button>
+      </div></div>`;
+  }
+  else if(state.screen==='sample-printing'){
+    html = `<div class="pad"><div class="center">
+        <h1 class="question">Printing your sticker…</h1>
+        <p class="itemmeta">🖨️ One sec…</p>
+      </div></div>`;
+    setTimeout(()=>{ if(state.screen==='sample-printing') go('sample-done'); }, 1000);
+  }
+  else if(state.screen==='sample-done'){
+    html = `<div class="pad"><div class="center">
+        <h1 class="question">Done! ✅</h1>
+      </div>
+      <div class="answers">
+        <button class="bigbtn" style="background:${accent('sample')}; border-color:${accent('sample')}; color:#fff;" onclick="go('home')">Home</button>
+      </div></div>`;
+  }
+
+  s.innerHTML = html;
+}
+
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-detail'); }
+function nextResult(){
+  if(state.resultIndex < MOCK_ITEMS.length-1){ state.resultIndex++; go('find-result'); }
+  else { go('find-exhausted'); }
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/public/kid-simple/v9-story-mode.html b/public/kid-simple/v9-story-mode.html
new file mode 100644
index 0000000..4f13389
--- /dev/null
+++ b/public/kid-simple/v9-story-mode.html
@@ -0,0 +1,386 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<title>v9 — Story Mode</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600;700;800&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
+<style>
+  :root{
+    --parchment:#F6F1EA; --ink:#2A2320;
+    --canvas:#201A1D; --cream:#FBF4EC; --muted:rgba(251,244,236,.58);
+    --accent:#E0764A; --accent-ink:#3A1F12;
+    --success:#6FA98A; --track:rgba(255,255,255,.22);
+    --ring-new:#E0764A; --ring-update:#3E7C7C; --ring-find:#C97A96; --ring-sample:#8A9B5E;
+  }
+  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
+  html,body{margin:0;padding:0;background:#ddd;font-family:'Manrope',sans-serif;color:var(--ink);}
+  body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
+  .phone{
+    width:390px; height:780px; background:var(--parchment); border-radius:36px; overflow:hidden;
+    box-shadow:0 24px 60px rgba(0,0,0,.28); position:relative; display:flex; flex-direction:column;
+  }
+  .screen{ flex:1; position:relative; overflow:hidden; }
+  h1,h2{ font-family:'Playfair Display',serif; margin:0; }
+  button{ font-family:'Manrope',sans-serif; cursor:pointer; }
+
+  /* ---------- HOME (light chrome, story selector) ---------- */
+  .home{ height:100%; display:flex; flex-direction:column; padding:34px 26px 30px; }
+  .home-mark{ font-family:'Playfair Display',serif; font-weight:800; font-size:15px; letter-spacing:.14em; color:#8A7F6E; }
+  .home-sub{ font-size:12px; letter-spacing:.16em; text-transform:uppercase; color:#B5A896; margin-top:2px; }
+  .home-headline{ font-size:30px; font-weight:700; line-height:1.2; margin:26px 0 8px; color:var(--ink); }
+  .home-hint{ font-size:15px; color:#8A7F6E; margin:0 0 26px; }
+  .storygrid{ display:grid; grid-template-columns:1fr 1fr; gap:20px; flex:1; }
+  .storytile{
+    background:none; border:none; padding:0; display:flex; flex-direction:column; align-items:center;
+    justify-content:flex-start; gap:12px; min-height:130px;
+  }
+  .ring{
+    width:92px; height:92px; border-radius:50%; padding:4px; display:flex; align-items:center; justify-content:center;
+  }
+  .ring-inner{
+    width:100%; height:100%; border-radius:50%; background:var(--canvas); display:flex; align-items:center;
+    justify-content:center; font-size:34px;
+  }
+  .r-new{ background:conic-gradient(from -40deg, var(--ring-new), #F4C79A, var(--ring-new)); }
+  .r-update{ background:conic-gradient(from -40deg, var(--ring-update), #A9D3CF, var(--ring-update)); }
+  .r-find{ background:conic-gradient(from -40deg, var(--ring-find), #EFC7D4, var(--ring-find)); }
+  .r-sample{ background:conic-gradient(from -40deg, var(--ring-sample), #D9E2B8, var(--ring-sample)); }
+  .storytile .label{ font-size:14.5px; font-weight:700; color:var(--ink); text-align:center; line-height:1.25; }
+  .storytile:focus-visible .ring-inner{ outline:3px solid #2B6CB0; outline-offset:2px; }
+
+  /* ---------- STORY (dark canvas) ---------- */
+  .story{ position:absolute; inset:0; background:var(--canvas); display:flex; flex-direction:column; color:var(--cream); }
+  .story.cam{ background:radial-gradient(120% 90% at 50% 0%, #2c2428 0%, #171214 75%); }
+  .progressrow{ display:flex; gap:6px; padding:16px 16px 0; z-index:30; }
+  .seg{ flex:1; height:4px; border-radius:3px; background:var(--track); overflow:hidden; }
+  .seg i{ display:block; height:100%; width:0%; background:var(--accent); border-radius:3px; }
+  .seg.done i{ width:100%; }
+  .seg.now i{ width:100%; }
+  .storytop{ display:flex; align-items:center; justify-content:space-between; padding:10px 10px 0 16px; z-index:30; }
+  .storytop .who{ font-size:12.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); }
+  .exitbtn{
+    width:56px; height:56px; border-radius:50%; background:rgba(0,0,0,.28); border:none; color:var(--cream);
+    font-size:20px; display:flex; align-items:center; justify-content:center;
+  }
+  .exitbtn:focus-visible{ outline:3px solid #7EB6E8; outline-offset:2px; }
+
+  .tapzone{ position:absolute; top:64px; bottom:150px; width:17%; background:none; border:none; z-index:5; padding:0; }
+  .tapzone.left{ left:0; }
+  .tapzone.right{ right:0; }
+  .tapzone .chev{ position:absolute; top:50%; transform:translateY(-50%); font-size:22px; color:rgba(255,255,255,.30); }
+  .tapzone.left .chev{ left:8px; }
+  .tapzone.right .chev{ right:8px; }
+
+  .framebody{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:10px 30px; text-align:center; position:relative; z-index:8; gap:10px; }
+  .framebody .cue{ font-size:12.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--accent); margin-bottom:2px; }
+  .framebody h2{ font-size:27px; font-weight:700; line-height:1.24; color:var(--cream); text-shadow:0 2px 14px rgba(0,0,0,.35); }
+  .framebody .sub{ font-size:15px; color:var(--muted); margin-top:2px; }
+
+  .frameactions{ position:relative; z-index:10; padding:14px 22px 26px; display:flex; flex-direction:column; gap:12px; }
+  .bigbtn{
+    width:100%; min-height:58px; border-radius:18px; font-size:17.5px; font-weight:700;
+    border:2px solid rgba(255,255,255,.18); background:rgba(255,255,255,.08); color:var(--cream); padding:10px 16px;
+  }
+  .bigbtn-primary{ background:var(--accent); border-color:var(--accent); color:var(--accent-ink); }
+  .bigbtn-ghost{ background:none; border:2px solid rgba(255,255,255,.3); color:var(--muted); }
+  .bigbtn:focus-visible{ outline:3px solid #7EB6E8; outline-offset:2px; }
+
+  .shutterwrap{ position:relative; z-index:10; display:flex; justify-content:center; padding-bottom:30px; }
+  .shutter{
+    width:88px; height:88px; border-radius:50%; background:var(--accent); border:6px solid rgba(255,255,255,.85);
+    font-size:32px; display:flex; align-items:center; justify-content:center; color:var(--accent-ink);
+  }
+  .shutter:disabled{ opacity:.55; }
+  .shutter:focus-visible{ outline:3px solid #7EB6E8; outline-offset:4px; }
+
+  .brandlist{ width:100%; display:flex; flex-direction:column; gap:12px; overflow-y:auto; max-height:390px; padding:2px 2px 4px; }
+  .brandbtn{
+    width:100%; min-height:58px; border-radius:16px; background:rgba(255,255,255,.07); border:2px solid rgba(255,255,255,.16);
+    color:var(--cream); font-size:16.5px; font-weight:700; padding:10px 18px; text-align:left;
+  }
+  .brandbtn:focus-visible{ outline:3px solid #7EB6E8; outline-offset:2px; }
+
+  .swatch{ width:180px; height:130px; border-radius:16px; margin:4px auto 2px; box-shadow:0 10px 26px rgba(0,0,0,.35); }
+  .sw1{background:repeating-linear-gradient(45deg,#E0764A 0 16px,#c25f37 16px 32px);}
+  .sw2{background:repeating-linear-gradient(-45deg,#3E7C7C 0 14px,#2f6161 14px 28px);}
+  .sw3{background:repeating-linear-gradient(90deg,#C97A96 0 14px,#b05f7c 14px 28px);}
+  .itemname{ font-size:19px; font-weight:800; margin:0; color:var(--cream); }
+  .itemmeta{ font-size:14.5px; color:var(--muted); margin:2px 0 0; }
+
+  .doneflash{ font-size:52px; }
+</style>
+</head>
+<body>
+<div class="phone">
+  <div class="screen" id="screen" role="main"></div>
+</div>
+
+<script>
+const MOCK_ITEMS = [
+  {name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
+  {name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw2'},
+  {name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
+];
+const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
+
+const state = { screen:'home', item:null, brand:null, resultIndex:0 };
+
+function randomItem(){ return MOCK_ITEMS[Math.floor(Math.random()*MOCK_ITEMS.length)]; }
+function go(screen){ state.screen = screen; render(); }
+function startJob(job){
+  state.item=null; state.brand=null; state.resultIndex=0;
+  const map = {new:'new-cam', update:'update-cam', find:'find-method', sample:'sample-cam'};
+  go(map[job]);
+}
+
+/* progress-bar position tables: [index(1-based), total] per screen key */
+const POS = {
+  'new-cam':[1,3], 'new-brand':[2,3], 'new-review':[3,3],
+  'update-cam':[1,3], 'update-match':[2,3], 'update-cam2':[3,3],
+  'find-method':[1,3], 'find-result':[2,3], 'find-detail':[3,3],
+  'sample-cam':[1,3], 'sample-match':[2,3], 'sample-printing':[3,3],
+};
+
+function progressRow(){
+  const p = POS[state.screen];
+  if(!p) return '';
+  const [idx,total] = p;
+  let segs = '';
+  for(let i=1;i<=total;i++){
+    segs += `<div class="seg ${i<idx?'done':(i===idx?'now':'')}"><i></i></div>`;
+  }
+  return `<div class="progressrow">${segs}</div>`;
+}
+
+function tapZones(leftFn, rightFn){
+  const l = leftFn ? `<button class="tapzone left" aria-label="Back" onclick="${leftFn}"><span class="chev">‹</span></button>` : '';
+  const r = rightFn ? `<button class="tapzone right" aria-label="Continue" onclick="${rightFn}"><span class="chev">›</span></button>` : '';
+  return l+r;
+}
+
+function storyShell(canvasClass, innerHtml, opts){
+  opts = opts || {};
+  const exit = `<button class="exitbtn" aria-label="Exit story" onclick="go('home')">✕</button>`;
+  return `<div class="story ${canvasClass||''}">
+      ${progressRow()}
+      <div class="storytop"><span class="who">${opts.who||''}</span>${exit}</div>
+      ${tapZones(opts.tapLeft, opts.tapRight)}
+      ${innerHtml}
+    </div>`;
+}
+
+function shoot(cb){
+  const st = document.getElementById('camStatus');
+  const btn = document.querySelector('.shutter');
+  if(btn) btn.disabled = true;
+  if(st) st.textContent = 'Snapping…';
+  setTimeout(()=>{ state.item = randomItem(); cb(); }, 650);
+}
+
+function cameraFrame(who, cue, question, hint, onShoot, tapLeft){
+  return storyShell('cam', `
+    <div class="framebody">
+      <div class="cue">${cue}</div>
+      <h2>${question}</h2>
+      <p class="sub" id="camStatus">${hint}</p>
+    </div>
+    <div class="shutterwrap"><button class="shutter" aria-label="Take photo" onclick="${onShoot}">📸</button></div>
+  `, {who, tapLeft, tapRight:onShoot});
+}
+
+function render(){
+  const s = document.getElementById('screen');
+  let html = '';
+
+  if(state.screen==='home'){
+    html = `<div class="home">
+      <div class="home-mark">DW</div>
+      <div class="home-sub">Story Mode</div>
+      <h1 class="home-headline">Pick your story</h1>
+      <p class="home-hint">Tap one to start — swipe through, tap ‹ › to move around.</p>
+      <div class="storygrid">
+        <button class="storytile" onclick="startJob('new')">
+          <div class="ring r-new"><div class="ring-inner">🆕</div></div>
+          <div class="label">Add New Item</div>
+        </button>
+        <button class="storytile" onclick="startJob('update')">
+          <div class="ring r-update"><div class="ring-inner">🔄</div></div>
+          <div class="label">Update an Item</div>
+        </button>
+        <button class="storytile" onclick="startJob('find')">
+          <div class="ring r-find"><div class="ring-inner">🔍</div></div>
+          <div class="label">Find an Item</div>
+        </button>
+        <button class="storytile" onclick="startJob('sample')">
+          <div class="ring r-sample"><div class="ring-inner">📦</div></div>
+          <div class="label">A Sample Came In</div>
+        </button>
+      </div>
+    </div>`;
+  }
+
+  /* ---------------- ADD NEW ITEM ---------------- */
+  else if(state.screen==='new-cam'){
+    html = cameraFrame('Add New Item','Frame 1','Take a photo of it','Tap the shutter (or tap the right edge)', "shoot(()=>go('new-brand'))");
+  }
+  else if(state.screen==='new-brand'){
+    let list = '';
+    BRANDS.forEach(b=>{ list += `<button class="brandbtn" onclick="state.brand='${b}'; go('new-review')">${b}</button>`; });
+    html = storyShell('', `
+      <div class="framebody" style="justify-content:flex-start; padding-top:20px;">
+        <div class="cue">Frame 2</div>
+        <h2>Which brand is it?</h2>
+        <div class="brandlist">${list}</div>
+      </div>
+    `, {who:'Add New Item', tapLeft:"go('new-cam')"});
+  }
+  else if(state.screen==='new-review'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 3</div>
+        <h2>Save it?</h2>
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemmeta">${state.brand} · code ${state.item.code}</p>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="go('new-done')">Save as Draft</button>
+        <button class="bigbtn bigbtn-ghost" onclick="go('new-cam')">Retake Photo</button>
+      </div>
+    `, {who:'Add New Item', tapLeft:"go('new-brand')", tapRight:"go('new-done')"});
+  }
+  else if(state.screen==='new-done'){
+    html = doneFrame('Add New Item', '🎉', 'Saved!', 'Add Another', "startJob('new')");
+  }
+
+  /* ---------------- UPDATE AN ITEM ---------------- */
+  else if(state.screen==='update-cam'){
+    html = cameraFrame('Update an Item','Frame 1','Scan the label or pattern','Tap the shutter (or tap the right edge)', "shoot(()=>go('update-match'))");
+  }
+  else if(state.screen==='update-match'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 2</div>
+        <h2>Is this it?</h2>
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">code ${state.item.code}</p>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Yes</button>
+        <button class="bigbtn bigbtn-ghost" onclick="go('update-cam')">No, Let Me Search</button>
+      </div>
+    `, {who:'Update an Item', tapLeft:"go('update-cam')", tapRight:"go('update-cam2')"});
+  }
+  else if(state.screen==='update-cam2'){
+    html = cameraFrame('Update an Item','Frame 3','Take the new photo','Tap the shutter (or tap the right edge)', "shoot(()=>go('update-done'))", "go('update-match')");
+  }
+  else if(state.screen==='update-done'){
+    html = doneFrame('Update an Item', '✅', 'Updated!', 'Back Home', "go('home')");
+  }
+
+  /* ---------------- FIND AN ITEM ---------------- */
+  else if(state.screen==='find-method'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 1</div>
+        <h2>How do you want to find it?</h2>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn" onclick="go('find-result')">📷 Scan the Label</button>
+        <button class="bigbtn" onclick="go('find-result')">🎤 Say the Name</button>
+        <button class="bigbtn" onclick="go('find-result')">⌨️ Type It</button>
+      </div>
+    `, {who:'Find an Item', tapLeft:"go('home')"});
+  }
+  else if(state.screen==='find-result'){
+    const it = MOCK_ITEMS[state.resultIndex];
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 2</div>
+        <h2>Is this the one?</h2>
+        <div class="swatch ${it.sw}"></div>
+        <p class="itemname">${it.name} — ${it.color}</p>
+        <p class="itemmeta">code ${it.code}</p>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
+        <button class="bigbtn bigbtn-ghost" onclick="nextResult()">Next Result</button>
+      </div>
+    `, {who:'Find an Item', tapLeft:"go('find-method')", tapRight:"nextResult()"});
+  }
+  else if(state.screen==='find-detail'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 3</div>
+        <h2>${state.item.name}</h2>
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemmeta">${state.item.color} · code ${state.item.code}</p>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="go('update-cam2')">Update This</button>
+        <button class="bigbtn bigbtn-ghost" onclick="go('find-method')">Search Again</button>
+      </div>
+    `, {who:'Find an Item', tapLeft:"go('find-result')"});
+  }
+
+  /* ---------------- A SAMPLE CAME IN ---------------- */
+  else if(state.screen==='sample-cam'){
+    html = cameraFrame('A Sample Came In','Frame 1','Scan the box label','Tap the shutter (or tap the right edge)', "shoot(()=>go('sample-match'))");
+  }
+  else if(state.screen==='sample-match'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 2</div>
+        <h2>Mark it received?</h2>
+        <div class="swatch ${state.item.sw}"></div>
+        <p class="itemname">${state.item.name} — ${state.item.color}</p>
+        <p class="itemmeta">code ${state.item.code}</p>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="go('sample-printing')">Yes, Mark Received</button>
+      </div>
+    `, {who:'A Sample Came In', tapLeft:"go('sample-cam')", tapRight:"go('sample-printing')"});
+  }
+  else if(state.screen==='sample-printing'){
+    html = storyShell('', `
+      <div class="framebody">
+        <div class="cue">Frame 3</div>
+        <h2>Printing your sticker…</h2>
+        <p class="sub">🖨️ One sec…</p>
+      </div>
+    `, {who:'A Sample Came In'});
+    setTimeout(()=>{ if(state.screen==='sample-printing') go('sample-done'); }, 1000);
+  }
+  else if(state.screen==='sample-done'){
+    html = doneFrame('A Sample Came In', '✅', 'Done!', 'Back Home', "go('home')");
+  }
+
+  s.innerHTML = html;
+}
+
+function doneFrame(who, emoji, title, btnLabel, btnAction){
+  return storyShell('', `
+      <div class="framebody">
+        <div class="doneflash">${emoji}</div>
+        <h2>${title}</h2>
+      </div>
+      <div class="frameactions">
+        <button class="bigbtn bigbtn-primary" onclick="${btnAction}">${btnLabel}</button>
+        <button class="bigbtn bigbtn-ghost" onclick="go('home')">Home</button>
+      </div>
+    `, {who});
+}
+
+function pickResult(){ state.item = MOCK_ITEMS[state.resultIndex]; go('find-detail'); }
+function nextResult(){
+  state.resultIndex = (state.resultIndex + 1) % MOCK_ITEMS.length;
+  go('find-result');
+}
+
+render();
+</script>
+</body>
+</html>
diff --git a/server.js b/server.js
index 4abf2cb..eff859b 100644
--- a/server.js
+++ b/server.js
@@ -2431,6 +2431,24 @@ load();
     return res.end(fs.readFileSync(fp));
   }
 
+  // ── Kid-Simple redesign review page (TK-12344): static mockups v1–v16 + the Photoshop board.
+  //    Same bounded posture as /js/: fixed dir, basename-only (+ one renders/ subdir), extension
+  //    allowlist, path-traversal guard, behind the app basic-auth. Mockups only — no API calls.
+  if (_p === '/kid-simple') { res.writeHead(301, { Location: '/kid-simple/' }); return res.end(); }
+  if (_p.startsWith('/kid-simple/')) {
+    let name = _p.slice('/kid-simple/'.length) || 'index.html';
+    const m = /^(renders\/)?([A-Za-z0-9._-]+\.(html|png|jpg))$/.exec(name);
+    if (!m || name.includes('..')) return send(res, 404, { err: 'not found' });
+    const KDIR = path.join(ROOT, 'public/kid-simple');
+    const fp = path.join(KDIR, name);
+    if (!fp.startsWith(KDIR + path.sep) || !fs.existsSync(fp) || !fs.statSync(fp).isFile()) {
+      return send(res, 404, { err: 'not found' });
+    }
+    const type = { html: 'text/html; charset=utf-8', png: 'image/png', jpg: 'image/jpeg' }[m[3]];
+    res.writeHead(200, { 'Content-Type': type, 'Cache-Control': m[3] === 'html' ? 'no-store' : 'max-age=3600' });
+    return res.end(fs.readFileSync(fp));
+  }
+
   // App icons + PWA manifest — make "Add to Home Screen" a real app (clean DW icon, fullscreen).
   if (u.pathname === '/icon-180.png' || u.pathname === '/icon-192.png' || u.pathname === '/icon-512.png' || u.pathname === '/apple-touch-icon.png') {
     const f = path.join(ROOT, 'public', u.pathname === '/apple-touch-icon.png' ? 'icon-180.png' : path.basename(u.pathname));

← ac13489 Untrack runtime build counter data/build.json and gitignore  ·  back to Dw Photo Capture  ·  Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Au 6e2c3f2 →