// Solari · Landing · Animated Shopping loop (v3)
// Stars of the show:
//   1. Shopping list instantly made
//   2. Untoggle things you already have
//   3. Sorted nicely (by aisle)
//   4. Send multiple places (Instacart / Amazon / Print)
//
// Sequence: Plan view (real DayRow vocabulary) → tap Shop tab in nav → ShopList
// (sorted aisles, In-store + Send actions, demonstrate untoggle) → Send sheet
// (3 destinations) → end. Bottom tab bar always visible.

const { useState: useStateS, useEffect: useEffectS, useRef: useRefS } = React;

const SC = {
  ink:       'var(--ink-900, #1f1f1c)',
  ink2:      'var(--ink-700, #3b3b35)',
  ink3:      'var(--ink-500, #76736a)',
  ink4:      'var(--ink-400, #a39f93)',
  paper:     'var(--paper-50, #faf6e9)',
  paper2:    'var(--paper-100, #f3ecd6)',
  paper3:    'var(--paper-200, #e8dfcc)',
  paper4:    'var(--paper-300, #d8cfb8)',
  sage:      'var(--sage-700, #4f7a3a)',
  sage2:     'var(--sage-500, #6f9656)',
  sageWash:  'var(--sage-100, #e8efd9)',
  amberD:    'var(--amber-700, #c77a1f)',
  amberS:    'var(--amber-100, #f5e3c2)',
  clay:      'var(--terra-600, #b8542e)',
  moment:    'var(--moment, #6f8aa6)',
};

// ─── Choreography ──────────────────────────────────────────────
const SHOP_SEQUENCE = [
  { t: 0,     state: 'week',          caption: 'You’ve planned the week…' },
  { t: 1100,  state: 'week-tap-shop', caption: 'Tap Shopping.' },
  { t: 2200,  state: 'list-build',    caption: 'Your list. Instantly made.' },
  { t: 4200,  state: 'list-rest',     caption: 'Sorted by aisle.' },
  { t: 5000,  state: 'list-scroll',   caption: 'Scroll. It’s a long week.' },
  { t: 6300,  state: 'list-uncheck',  caption: 'Skip the staples you already have.' },
  { t: 9400,  state: 'list-after',    caption: 'Done. The rest you actually need.' },
  { t: 10800, state: 'list-tap-send', caption: 'Send it where you shop.' },
  { t: 12200, state: 'send-open',     caption: 'Three ways out.' },
  { t: 14000, state: 'send-rest',     caption: 'Your call.' },
];
const SHOP_LOOP = 16800;

const useChoreoS = (sequence, duration) => {
  const [t, setT] = useStateS(0);
  const startRef = useRefS(performance.now());
  useEffectS(() => {
    let raf;
    const tick = (now) => { setT((now - startRef.current) % duration); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [duration]);
  let current = sequence[0];
  for (const ev of sequence) { if (ev.t <= t) current = ev; else break; }
  return { t, state: current.state, caption: current.caption || '' };
};

// ─── Tiny glyphs ───────────────────────────────────────────────
const CarrotMark = ({ size = 18 }) => (
  <svg width={size} height={size} viewBox="0 0 32 32" fill="none">
    <path d="M16 8 C 12 14 10 22 12 27 C 16 28 22 24 24 18 C 22 14 18 10 16 8 Z" fill="#E29831" />
    <path d="M16 8 L13 4 M16 8 L17 3 M16 8 L19 4" stroke="#4F7A3A" strokeWidth="1.6" strokeLinecap="round" />
  </svg>
);
const ShopBag = ({ size = 16, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 32 32" fill="none"
    stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <path d="M5 7h22l-2 17a2 2 0 0 1-2 1.7H9a2 2 0 0 1-2-1.7L5 7z" />
    <path d="M11 7V5a5 5 0 0 1 10 0v2" />
  </svg>
);
const Sparkle = ({ size = 13, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
    <path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8"/>
  </svg>
);
const ChevR = ({ size = 13, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="9 18 15 12 9 6"/>
  </svg>
);
const ChevL = ({ size = 13, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="15 18 9 12 15 6"/>
  </svg>
);
const Arrow = ({ size = 13, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
    <line x1="5" y1="12" x2="19" y2="12"/><polyline points="13 5 20 12 13 19"/>
  </svg>
);

// ─── Tab bar (mirrors Hi-Fi A · TabBar) ────────────────────────
const TabIcon = ({ name, size = 22, color, stroke }) => {
  const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
  if (name === 'today') return <svg {...p}><circle cx="12" cy="12" r="4"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M5 19l2-2M17 7l2-2"/></svg>;
  if (name === 'plan')  return <svg {...p}><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>;
  if (name === 'book')  return <svg {...p}><path d="M5 4h11a3 3 0 0 1 3 3v13a1 1 0 0 1-1 1H8a3 3 0 0 1-3-3V4z"/><path d="M5 17a2 2 0 0 1 2-2h12"/></svg>;
  if (name === 'shop')  return <svg {...p}><path d="M5 7h14l-1.5 11a2 2 0 0 1-2 1.7H8.5a2 2 0 0 1-2-1.7L5 7z"/><path d="M9 7V5a3 3 0 0 1 6 0v2"/></svg>;
  return null;
};

const TabBar = ({ active, transitioningTo }) => {
  const tabs = [['today','Today'], ['plan','Plan'], ['book','Recipes'], ['shop','Shopping']];
  return (
    <div style={{
      position: 'absolute', bottom: 14, left: 14, right: 14,
      height: 58, borderRadius: 22,
      background: 'rgba(250,246,233,0.78)',
      backdropFilter: 'blur(20px) saturate(140%)',
      WebkitBackdropFilter: 'blur(20px) saturate(140%)',
      boxShadow: '0 1px 2px rgba(0,0,0,.04), 0 12px 28px rgba(0,0,0,.10), inset 0 0 0 1px rgba(31,31,28,.04)',
      display: 'flex', justifyContent: 'space-around', alignItems: 'center',
      padding: '0 8px', zIndex: 15,
    }}>
      {tabs.map(([k, label]) => {
        const isActive = active === k;
        const isTransitioning = transitioningTo === k;
        const color = (isActive || isTransitioning) ? SC.sage : SC.ink3;
        const stroke = (isActive || isTransitioning) ? 2 : 1.6;
        return (
          <div key={k} style={{
            display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
            gap: 3, color: (isActive || isTransitioning) ? SC.ink : SC.ink3,
            transition: 'color 280ms ease',
            position: 'relative',
          }}>
            <TabIcon name={k} size={22} color={color} stroke={stroke} />
            <span style={{
              fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 600,
              letterSpacing: '.04em',
            }}>{label}</span>
            {isTransitioning && (
              <div style={{
                position: 'absolute', top: -6, left: '50%', transform: 'translateX(-50%)',
                width: 38, height: 38, borderRadius: '50%',
                border: `1.5px solid ${SC.sage}`,
                opacity: 0.55, animation: 'shopRipple 700ms ease-out',
                pointerEvents: 'none',
              }} />
            )}
          </div>
        );
      })}
    </div>
  );
};

// ─── Type tile (matches Hi-Fi A · word-on-color square) ────────
const SHOP_TILE_TYPES = {
  cook:   { word: 'Cook',     bg: SC.sage,    fg: '#FAF6E9', tone: 'dark' },
  batch:  { word: 'Batch',    bg: SC.amberD,  fg: '#FAF6E9', tone: 'dark' },
  encore: { word: 'Repeat',   bg: SC.amberS,  fg: SC.amberD, tone: 'light' },
  order:  { word: 'Order In', bg: SC.clay,    fg: '#FAF6E9', tone: 'dark' },
  out:    { word: 'Going Out',bg: SC.ink,     fg: '#FAF6E9', tone: 'dark' },
  easy:   { word: 'Easy',     bg: '#dde7c8',  fg: SC.sage,   tone: 'light' },
  moment: { word: 'Moment',   bg: SC.moment,  fg: '#FAF6E9', tone: 'dark' },
};
const TypeTile = ({ kind = 'cook', size = 36 }) => {
  const s = SHOP_TILE_TYPES[kind] || SHOP_TILE_TYPES.cook;
  const isTwoWord = s.word.includes(' ');
  const radius = Math.max(6, Math.round(size * 0.22));
  const baseFs = isTwoWord ? 12 : (s.word.length >= 6 ? 13 : 15);
  const fs = Math.max(8, Math.round(baseFs * (size / 56)));
  return (
    <div style={{
      width: size, height: size, flexShrink: 0,
      borderRadius: radius, background: s.bg,
      boxShadow: s.tone === 'dark'
        ? 'inset 0 0 0 1px rgba(255,255,255,.18), 0 1px 2px rgba(31,31,28,.06)'
        : 'inset 0 0 0 1px rgba(31,31,28,.10), 0 1px 2px rgba(31,31,28,.04)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      position: 'relative', overflow: 'hidden',
    }}>
      <div style={{
        position: 'absolute', inset: 0,
        background: s.tone === 'dark'
          ? 'radial-gradient(circle at 30% 20%, rgba(255,255,255,.10), transparent 60%)'
          : 'radial-gradient(circle at 30% 20%, rgba(255,255,255,.45), transparent 60%)',
        pointerEvents: 'none',
      }} />
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)',
        fontSize: fs, lineHeight: 1.0, color: s.fg,
        letterSpacing: '-0.015em', textAlign: 'center', padding: '0 2px', position: 'relative',
      }}>
        {isTwoWord ? s.word.split(' ').map((w, i) => <div key={i}>{w}</div>) : s.word}
      </div>
    </div>
  );
};

// ─── Day row (matches Hi-Fi A · DayRow with past/today states) ─
const DayRow = ({ day, date, kind, name, time, sub, first, past, today, rating, kindIcon = true }) => (
  <div style={{
    display: 'flex', alignItems: 'center', gap: 10,
    padding: today ? '12px 8px' : '10px 8px',
    borderTop: first || today ? 0 : `1px solid ${SC.paper3}`,
    opacity: past ? 0.55 : 1,
    background: today ? 'rgba(79,122,58,0.05)' : 'transparent',
    borderRadius: today ? 12 : 0,
    margin: today ? '0 -4px' : 0,
  }}>
    <div style={{ width: 28, textAlign: 'center', flexShrink: 0 }}>
      <div style={{
        fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 700,
        letterSpacing: '0.12em', color: SC.ink3, textTransform: 'uppercase',
      }}>{day}</div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 15, lineHeight: 1,
        color: SC.ink, marginTop: 2,
      }}>{date}</div>
    </div>
    {kindIcon && <TypeTile kind={kind} size={34} />}
    <div style={{ minWidth: 0, flex: 1 }}>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 13, fontWeight: 600,
        color: SC.ink, lineHeight: 1.2,
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      }}>{name}</div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10.5, fontStyle: 'italic',
        color: SC.ink3, marginTop: 2,
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      }}>
        {past && <span style={{ color: SC.sage, fontStyle: 'normal', marginRight: 4 }}>✓</span>}
        {time} · {sub}
        {rating && <span style={{ color: SC.amberD, fontStyle: 'normal', marginLeft: 5 }}>· {rating}</span>}
      </div>
    </div>
  </div>
);

// ─── Stacked day (Sun = batch + something) ─────────────────────
const StackedDay = ({ day, date, items, past }) => (
  <div style={{
    display: 'flex', alignItems: 'flex-start', gap: 10,
    padding: '10px 8px',
    borderTop: 0,
    opacity: past ? 0.55 : 1,
  }}>
    <div style={{ width: 28, textAlign: 'center', flexShrink: 0, paddingTop: 3 }}>
      <div style={{
        fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 700,
        letterSpacing: '0.12em', color: SC.ink3, textTransform: 'uppercase',
      }}>{day}</div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 15, lineHeight: 1,
        color: SC.ink, marginTop: 2,
      }}>{date}</div>
    </div>
    <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 6 }}>
      {items.map((it, i) => (
        <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
          <TypeTile kind={it.kind} size={34} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 13, fontWeight: 600,
              color: SC.ink, lineHeight: 1.2,
              whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
            }}>{it.name}</div>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10.5, fontStyle: 'italic',
              color: SC.ink3, marginTop: 1,
              whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
            }}>
              {past && <span style={{ color: SC.sage, fontStyle: 'normal', marginRight: 3 }}>✓</span>}
              {it.time} · {it.sub}
            </div>
          </div>
        </div>
      ))}
    </div>
  </div>
);

// ─── View 1 · Week / Plan (mirrors PlanSteady from A-plan.jsx) ─
const WeekView = () => (
  <div style={{ position: 'absolute', inset: 0, paddingTop: 44, background: SC.paper2 }}>
    {/* Header */}
    <div style={{ padding: '8px 18px 4px' }}>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        marginBottom: 4,
      }}>
        <ChevL size={12} color={SC.ink3} />
        <div style={{
          fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 700,
          letterSpacing: '0.16em', color: SC.ink3,
        }}>WEEK · MAY 4 → MAY 10</div>
        <ChevR size={12} color={SC.ink3} />
      </div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 26, lineHeight: 1.05,
        color: SC.ink, letterSpacing: '-0.02em', textAlign: 'center', marginTop: 6,
      }}>This <em style={{ color: SC.sage, fontStyle: 'italic' }}>week</em>.</div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 11, fontStyle: 'italic',
        color: SC.ink3, textAlign: 'center', marginTop: 4,
      }}>4 cook · 1 batch · 1 encore · 1 order in · 1 going out</div>
    </div>

    {/* Days */}
    <div style={{ padding: '10px 18px 0' }}>
      <div style={{
        background: SC.paper, borderRadius: 14,
        boxShadow: `inset 0 0 0 1px ${SC.paper3}`,
        padding: '4px 10px',
      }}>
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          padding: '6px 2px 4px',
        }}>
          <span style={{
            fontFamily: 'var(--font-sans, system-ui)', fontSize: 9.5, fontWeight: 700,
            letterSpacing: '0.16em', color: SC.sage,
          }}>SUN → SAT</span>
          <span style={{
            fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10, fontStyle: 'italic',
            color: SC.ink3,
          }}>seven nights, planned</span>
        </div>

        <StackedDay day="Sun" date="04" items={[
          { kind: 'batch',  name: 'Sunday roast chicken',  time: '50 min', sub: 'feeds Mon too' },
          { kind: 'encore', name: 'Roast wraps for lunch', time: '0 min',  sub: 'pack-ahead' },
        ]} />
        <DayRow day="Mon" date="05" kind="encore" name="Chicken & rice bowls"   time="15 min" sub="from Sunday's roast" />
        <DayRow day="Tue" date="06" kind="cook"   name="Cacio e pepe"           time="15 min" sub="Lily's favorite" />
        <DayRow day="Wed" date="07" kind="easy"   name="Stir-fry & rice"        time="20 min" sub="pantry meal" />
        <DayRow day="Thu" date="08" kind="cook"   name="Sheet-pan salmon"       time="30 min" sub="sage & lemon" />
        <DayRow day="Fri" date="09" kind="order"  name="Pizza night"            time="35 min" sub="order in · usual" />
        <DayRow day="Sat" date="10" kind="moment" name="Out with friends"       time="7pm"    sub="Lucia's" />
      </div>
    </div>

    <div style={{
      textAlign: 'center', padding: '10px 18px 0',
      fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10.5, fontStyle: 'italic',
      color: SC.ink3,
    }}>tap any day to swap · plans are alive</div>
  </div>
);

// ─── View 2 · Shop list ────────────────────────────────────────
const AISLES = [
  { lbl: 'AISLE 01', name: 'Produce', color: SC.sage, items: [
    { id: 'lemons',  n: 'Lemons',         q: '2',        f: 'Thu · salmon',  prefs: ['organic'] },
    { id: 'parsley', n: 'Parsley',        q: '1 bunch',  f: 'Sun · roast' },
    { id: 'garlic',  n: 'Garlic',         q: '1 head',   f: 'Thu · salmon' },
    { id: 'spinach', n: 'Baby spinach',   q: '5 oz',     f: 'auto · Tue stir-fry', auto: true, prefs: ['organic'] },
    { id: 'shallot', n: 'Shallots',       q: '3',        f: 'Thu · salmon' },
    { id: 'lettuce', n: 'Little gems',    q: '2 heads',  f: 'Wed · salad' },
    { id: 'ginger',  n: 'Ginger',         q: '1 knob',   f: 'Tue · stir-fry' },
    { id: 'scallion',n: 'Scallions',      q: '1 bunch',  f: 'Tue · stir-fry' },
  ]},
  { lbl: 'AISLE 02', name: 'Fish counter', color: SC.moment, items: [
    { id: 'salmon',  n: 'Salmon, skin-on', q: '4 fillets', f: 'Thu · dinner', prefs: ['wild'] },
  ]},
  { lbl: 'AISLE 03', name: 'Pantry', color: SC.clay, items: [
    { id: 'honey',   n: 'Honey',          q: '1 jar',    f: 'Wed · dressing' },           // unchecked
    { id: 'oil',     n: 'Olive oil',      q: '1 bottle', f: 'staple' },                  // unchecked
    { id: 'soy',     n: 'Soy sauce',      q: '1 bottle', f: 'Tue · stir-fry' },         // unchecked
    { id: 'sesame',  n: 'Sesame oil',     q: '1 bottle', f: 'Tue · stir-fry' },         // unchecked
    { id: 'salt',    n: 'Flaky salt',     q: '1 box',    f: 'staple' },                  // unchecked
    { id: 'pepper',  n: 'Black pepper',   q: '1 mill',   f: 'staple' },                  // unchecked
    { id: 'beans',   n: 'Cannellini',     q: '2 cans',   f: 'Sat · ribollita', prefs: ['Eden'] },
    { id: 'rice',    n: 'Long-grain rice', q: '1 lb',    f: 'auto · Tue stir-fry', auto: true },
    { id: 'paprika', n: 'Smoked paprika', q: '1 jar',    f: 'Sun · roast' },            // unchecked
    { id: 'thyme',   n: 'Dried thyme',    q: '1 jar',    f: 'Sun · roast' },            // unchecked
    { id: 'flour',   n: 'AP flour',       q: '5 lb',     f: 'staple' },                  // unchecked
    { id: 'pasta',   n: 'Spaghetti',      q: '1 lb',     f: 'Wed · cacio' },
  ]},
  { lbl: 'AISLE 04', name: 'Dairy', color: SC.amberD, items: [
    { id: 'parm',    n: 'Parmigiano',     q: 'wedge',    f: 'Wed · pasta', prefs: ['DOP'] },
    { id: 'butter',  n: 'Butter',         q: '1 stick',  f: 'Thu · salmon' },           // unchecked
    { id: 'eggs',    n: 'Eggs',           q: '1 dozen',  f: 'staple' },
    { id: 'milk',    n: 'Whole milk',     q: '1 gal',    f: 'staple' },                  // unchecked
  ]},
];
const TOTAL_ITEMS = AISLES.flatMap(a => a.items).length;
// Items already at home — staples + spices people commonly have stocked
const UNCHECKED_IDS = ['honey', 'oil', 'soy', 'sesame', 'salt', 'pepper', 'paprika', 'thyme', 'flour', 'butter', 'milk'];

const ShopList = ({ subState, t, baseT }) => {
  const elapsed = Math.max(0, t - baseT);
  // Aisles cascade in during 'list-build'
  const aisleVisible = (idx) => subState === 'list-build' ? elapsed >= idx * 280 + 150 : true;

  // Bulk uncheck: all staples cross off together at one decisive moment.
  const uncheckOrder = UNCHECKED_IDS;
  const BULK_UNCHECK_AT = 900;
  const UNCHECK_PHASE_DURATION = 3100;

  // Pin the scroll so the 11 staples (top of pantry) are dead-center in viewport.
  // Aisle 1 (produce) ~8 items × ~36px = ~290px tall. Plus header gap. Pantry top ≈ 380px below scroll-zero.
  const SCROLL_AT_UNCHECK = 380;
  let scrollY = 0;
  if (subState === 'list-scroll') {
    const p = Math.min(1, elapsed / 1500);
    const eased = p < 0.5 ? 2*p*p : -1 + (4 - 2*p) * p;
    scrollY = eased * SCROLL_AT_UNCHECK;
  } else if (subState === 'list-uncheck' || subState === 'list-after') {
    scrollY = SCROLL_AT_UNCHECK;
  } else if (subState === 'list-tap-send') {
    // Scroll back to top so the Send action is visible when it gets tapped.
    scrollY = 0;
  }
  const uncheckedAt = (id) => {
    const idx = uncheckOrder.indexOf(id);
    if (idx < 0) return false;
    if (subState === 'list-after' || subState === 'list-tap-send') return true;
    if (subState !== 'list-uncheck') return false;
    return elapsed >= BULK_UNCHECK_AT;
  };
  const tappingItem = () => false;
  const showSkipPill = subState === 'list-uncheck';
  const skipPillTapping = subState === 'list-uncheck' && elapsed >= BULK_UNCHECK_AT - 350 && elapsed < BULK_UNCHECK_AT + 200;
  const offCount = uncheckOrder.filter(id => uncheckedAt(id)).length;
  const remaining = TOTAL_ITEMS - offCount;
  const headerSub = offCount === 0
    ? `${TOTAL_ITEMS} things · sorted by aisle.`
    : (subState === 'list-uncheck'
        ? `${remaining} things · ${offCount} already at home…`
        : `${remaining} things · ${offCount} already at home.`);

  // Tap pulse on Send-to-Instacart row
  const tappingSend = subState === 'list-tap-send';

  return (
    <div style={{
      position: 'absolute', inset: 0, paddingTop: 50,
      background: SC.paper2, overflow: 'hidden',
    }}>
      {/* Sticky header */}
      <div style={{ padding: '4px 18px 6px', background: SC.paper2, position: 'relative', zIndex: 5 }}>
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          marginBottom: 4,
        }}>
          <ChevL size={12} color={SC.ink3} />
          <div style={{
            fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 700,
            letterSpacing: '0.16em', color: SC.ink3,
          }}>WEEK OF · APR 27 → MAY 03</div>
          <ChevR size={12} color={SC.ink3} />
        </div>

        <div style={{
          display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
          gap: 10, marginBottom: 4,
        }}>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 22, lineHeight: 1.05,
              color: SC.ink, letterSpacing: '-0.02em', whiteSpace: 'nowrap',
            }}>Shopping <em style={{ color: SC.sage, fontStyle: 'italic' }}>list</em>.</div>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 11.5, fontStyle: 'italic',
              color: SC.ink3, marginTop: 3,
            }}>{headerSub}</div>
          </div>
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10, fontStyle: 'italic',
            color: SC.ink3,
          }}>
            <span style={{
              width: 22, height: 13, borderRadius: 999,
              background: SC.sage, position: 'relative', display: 'inline-block',
            }}>
              <span style={{
                position: 'absolute', top: 1.5, left: 10.5,
                width: 10, height: 10, borderRadius: '50%', background: SC.paper,
                boxShadow: '0 1px 1.5px rgba(0,0,0,.2)',
              }} />
            </span>
            sort
          </div>
        </div>
      </div>

      {/* Scroll body */}
      <div style={{
        position: 'absolute', top: 124, left: 0, right: 0, bottom: 86,
        overflow: 'hidden',
      }}>
        <div style={{
          padding: '6px 18px 12px',
          transform: `translateY(${-scrollY}px)`,
          transition: 'transform 1100ms cubic-bezier(.32,.72,0,1)',
        }}>
        {/* Action stack */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12, position: 'relative' }}>
          <div style={{
            background: SC.ink, color: SC.paper, padding: '11px 14px', borderRadius: 12,
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8,
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 13.5, fontWeight: 600 }}>
              <ShopBag size={14} color={SC.paper} />
              In-store mode
            </span>
            <span style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10, fontStyle: 'italic',
              color: SC.paper, opacity: 0.78,
            }}>big checks · stays awake</span>
          </div>
          <div style={{
            background: SC.paper, padding: '11px 14px', borderRadius: 12,
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            boxShadow: tappingSend
              ? `inset 0 0 0 1.5px ${SC.sage}, 0 4px 14px rgba(79,122,58,.16)`
              : `inset 0 0 0 1px ${SC.paper3}`,
            transform: tappingSend ? 'scale(1.01)' : 'scale(1)',
            transition: 'box-shadow 320ms ease, transform 320ms ease',
            position: 'relative',
          }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
              <Sparkle size={14} color={SC.sage} />
              <span>
                <div style={{ fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 13, fontWeight: 600, color: SC.ink }}>
                  Send list to…
                </div>
                <div style={{ fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10, fontStyle: 'italic', color: SC.ink3, marginTop: 1 }}>
                  Instacart · Amazon Fresh · text or notepad
                </div>
              </span>
            </span>
            <ChevR size={12} color={SC.ink3} />
            {tappingSend && (
              <div style={{
                position: 'absolute', right: 14, top: 8,
                width: 38, height: 38, borderRadius: '50%',
                border: `1.5px solid ${SC.sage}`,
                opacity: 0.55, animation: 'shopRipple 700ms ease-out',
                pointerEvents: 'none',
              }} />
            )}
          </div>
        </div>

        {/* Aisles */}
        {AISLES.map((aisle, ai) => {
          const visible = aisleVisible(ai);
          return (
            <div key={aisle.lbl} style={{
              opacity: visible ? 1 : 0,
              transform: visible ? 'translateY(0)' : 'translateY(8px)',
              transition: 'opacity 320ms ease, transform 380ms cubic-bezier(.34,1.4,.64,1)',
              marginBottom: 12,
            }}>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 4 }}>
                <span style={{
                  fontFamily: 'var(--font-sans, system-ui)', fontSize: 9, fontWeight: 700,
                  letterSpacing: '0.16em', color: SC.ink3,
                }}>{aisle.lbl}</span>
                <span style={{
                  fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 14, fontStyle: 'italic',
                  color: aisle.color,
                }}>{aisle.name}</span>
              </div>
              <div style={{
                background: SC.paper, borderRadius: 10, padding: '2px 10px',
                boxShadow: `inset 0 0 0 1px ${SC.paper3}`,
              }}>
                {aisle.items.map((it, i) => {
                  const isOff = uncheckedAt(it.id);
                  return (
                    <div key={it.id} style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: '9px 4px',
                      borderTop: i === 0 ? 0 : `1px solid ${SC.paper3}`,
                      opacity: isOff ? 0.45 : 1,
                      transition: 'opacity 320ms ease',
                      position: 'relative',
                    }}>
                      <span style={{
                        width: 18, height: 18, borderRadius: 5,
                        boxShadow: isOff ? 'none' : `inset 0 0 0 1.5px ${SC.ink4}`,
                        background: isOff ? SC.sage : 'transparent',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                        flexShrink: 0,
                        transition: 'background 280ms ease, box-shadow 280ms ease',
                      }}>
                        {isOff && (
                          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke={SC.paper} strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round">
                            <polyline points="20 6 9 17 4 12"/>
                          </svg>
                        )}
                      </span>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 5, flexWrap: 'nowrap', minWidth: 0 }}>
                          <span style={{
                            fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 13, fontWeight: 500,
                            color: SC.ink,
                            textDecorationLine: isOff ? 'line-through' : 'none',
                            textDecorationColor: SC.ink3,
                            transition: 'text-decoration-color 280ms ease',
                            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                            minWidth: 0, flexShrink: 1,
                          }}>{it.n}</span>
                          {it.auto && (
                            <span style={{
                              fontFamily: 'var(--font-sans, system-ui)', fontSize: 7.5, fontWeight: 700,
                              letterSpacing: '0.1em', textTransform: 'uppercase',
                              color: SC.amberD, background: SC.amberS,
                              padding: '1px 6px', borderRadius: 999,
                            }}>AUTO</span>
                          )}
                          {it.prefs && it.prefs.map(p => (
                            <span key={p} style={{
                              fontFamily: 'var(--font-sans, system-ui)', fontSize: 8.5, fontWeight: 500,
                              color: SC.sage, background: SC.sageWash,
                              padding: '1px 6px', borderRadius: 999,
                            }}>{p}</span>
                          ))}
                        </div>
                        <div style={{
                          fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10, fontStyle: 'italic',
                          color: SC.ink3, marginTop: 1,
                        }}>{isOff ? 'already at home' : `for ${it.f}`}</div>
                      </div>
                      <span style={{
                        fontFamily: 'var(--font-sans, system-ui)', fontSize: 10, color: SC.ink3,
                      }}>{it.q}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
        </div>
      </div>
    </div>
  );
};

// ─── View 3 · Send sheet (3 destinations) ──────────────────────
const SendSheet = () => (
  <div style={{ position: 'absolute', inset: 0, paddingTop: 50 }}>
    {/* Dimmed list peek */}
    <div style={{ position: 'absolute', inset: 0, paddingTop: 50,
      background: SC.paper2, opacity: 0.55, zIndex: -1 }} />
    <div style={{ position: 'absolute', inset: 0, background: 'rgba(31,31,28,0.42)' }} />

    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 86,
      background: SC.paper,
      borderTopLeftRadius: 22, borderTopRightRadius: 22,
      padding: '14px 18px 22px',
      boxShadow: '0 -10px 30px rgba(31,31,28,0.18)',
      animation: 'shopSheetIn 480ms cubic-bezier(.32,.72,0,1)',
    }}>
      <div style={{ width: 38, height: 4, borderRadius: 2,
        background: SC.paper4, margin: '0 auto 12px' }} />

      <div style={{
        fontFamily: 'var(--font-sans, system-ui)', fontSize: 9.5, fontWeight: 700,
        letterSpacing: '0.16em', color: SC.sage, marginBottom: 4,
      }}>SEND YOUR LIST</div>
      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 22, lineHeight: 1.1,
        color: SC.ink, letterSpacing: '-0.01em', marginBottom: 12,
      }}>Where to?</div>

      {[
        { id: 'instacart', icon: (
          <img src="assets/logo-instacart.png" alt="Instacart" style={{ width: 30, height: 30, objectFit: 'contain', display: 'block' }} />
        ),
          title: 'Instacart',
          sub: 'your prefs already applied · ~2-tap checkout',
          primary: true },
        { id: 'amazon', icon: (
          <img src="assets/logo-amazon-fresh.png" alt="Amazon Fresh" style={{ width: 30, height: 30, objectFit: 'contain', display: 'block' }} />
        ), title: 'Amazon Fresh', sub: 'next-day delivery to your door' },
        { id: 'text', icon: (
          <div style={{
            width: 30, height: 30, borderRadius: 8,
            background: SC.paper2,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: SC.ink2,
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
              <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
            </svg>
          </div>
        ), title: 'Text or copy to notepad', sub: 'send to your phone · or paste anywhere' },
      ].map(opt => (
        <div key={opt.id} style={{
          display: 'flex', alignItems: 'center', gap: 12,
          padding: '12px 14px', borderRadius: 12, marginBottom: 8,
          background: opt.primary ? SC.sageWash : SC.paper2,
          boxShadow: opt.primary ? `inset 0 0 0 1.5px ${SC.sage}` : 'none',
        }}>
          {opt.icon}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 14, fontWeight: 600,
              color: SC.ink, lineHeight: 1.2,
            }}>{opt.title}</div>
            <div style={{
              fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10.5, fontStyle: 'italic',
              color: SC.ink3, marginTop: 2,
            }}>{opt.sub}</div>
          </div>
          <ChevR size={14} color={opt.primary ? SC.sage : SC.ink3} />
        </div>
      ))}

      <div style={{
        fontFamily: 'var(--font-display, Georgia, serif)', fontSize: 10.5, fontStyle: 'italic',
        color: SC.ink3, textAlign: 'center', marginTop: 8,
      }}>{TOTAL_ITEMS - UNCHECKED_IDS.length} things · we never see your card or address</div>
    </div>
  </div>
);

// ─── Main ──────────────────────────────────────────────────────
const ShopAnimatedPhone = () => {
  const { t, state, caption } = useChoreoS(SHOP_SEQUENCE, SHOP_LOOP);

  // View routing
  let view = 'week';
  if (state.startsWith('list-')) view = 'list';
  else if (state.startsWith('send-')) view = 'send';

  // Tab bar state
  const tabActive = view === 'week' ? 'plan' : 'shop';
  const tabTransitioning = state === 'week-tap-shop' ? 'shop' : null;

  // List-view base time for cascade
  let listBaseT = 0;
  if (view === 'list') {
    const ev = SHOP_SEQUENCE.find(e => e.state === 'list-build');
    listBaseT = ev ? ev.t : 0;
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 28 }}>
      <PhoneShell>
        <div style={{ position: 'relative', height: '100%', overflow: 'hidden' }}>
          {view === 'week' && <WeekView />}
          {view === 'list' && <ShopList subState={state} t={t} baseT={listBaseT} />}
          {view === 'send' && <SendSheet />}

          {window.LandingTabBar
            ? <window.LandingTabBar active={tabActive} transitioningTo={tabTransitioning} />
            : <TabBar active={tabActive} transitioningTo={tabTransitioning} />}
        </div>
      </PhoneShell>

      {/* Caption — lifted out of the phone, editorial italic */}
      <div style={{
        maxWidth: 360, textAlign: 'center',
        fontFamily: 'var(--font-display, Georgia, serif)',
        fontSize: 18, fontStyle: 'italic',
        color: SC.ink, lineHeight: 1.35, letterSpacing: '-0.01em',
        minHeight: 56, padding: '0 16px',
      }}>{caption}</div>
    </div>
  );
};

// ─── Mount ─────────────────────────────────────────────────────
const mountShopPhone = () => {
  const el = document.getElementById('shop-anim-mount');
  if (!el) return;
  ReactDOM.createRoot(el).render(<ShopAnimatedPhone />);
};
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', mountShopPhone);
} else {
  mountShopPhone();
}

// Keyframes
(function injectShopKeyframes() {
  if (document.getElementById('shop-anim-keyframes')) return;
  const s = document.createElement('style');
  s.id = 'shop-anim-keyframes';
  s.textContent = `
    @keyframes shopRipple { from { transform: scale(0.6); opacity: 0.7; } to { transform: scale(1.6); opacity: 0; } }
    @keyframes shopSheetIn { from { transform: translateY(40%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
  `;
  document.head.appendChild(s);
})();
