// screens-restaurant.jsx — restaurant detail, menu, cart, modifier modal

function RestaurantScreen({ app }) {
  const r = RESTAURANT_LOOKUP[app.activeRestaurantId];
  const menu = MENUS[app.activeRestaurantId] || GENERIC_MENU;
  const [loading, setLoading] = React.useState(true);
  const [activeCat, setActiveCat] = React.useState(menu[0]?.id);
  const [cartOpen, setCartOpen] = React.useState(false);
  const [modifierItem, setModifierItem] = React.useState(null);
  const [confirmSwap, setConfirmSwap] = React.useState(null); // {item, modifierState}
  const [favesOnly, setFavesOnly] = React.useState(false);
  const scrollRef = React.useRef(null);
  const menuLayout = app.tweaks.menuLayout || 'image-led'; // 'image-led' | 'list-led'
  const [mode, setMode] = React.useState('delivery'); // delivery | pickup
  const [groupOpen, setGroupOpen] = React.useState(false);
  const [allergyOpen, setAllergyOpen] = React.useState(false);
  const [menuFilter, setMenuFilter] = React.useState('all');
  const [trailOpen, setTrailOpen] = React.useState(false);

  React.useEffect(() => {
    setLoading(true);
    const t = setTimeout(() => setLoading(false), 600);
    return () => clearTimeout(t);
  }, [app.activeRestaurantId]);

  if (!r) {
    return (
      <Screen>
        <div style={{ padding: 40, textAlign: 'center' }}>
          <Bull size={72}/>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 18, marginTop: 16 }}>Restaurant not found</div>
          <div style={{ marginTop: 16 }}><Button onClick={() => app.nav('home')}>Back to home</Button></div>
        </div>
      </Screen>
    );
  }

  const cartForThis = app.cart.filter(c => c.restaurant_id === r.id);
  const cartItemCount = cartForThis.reduce((s,i) => s + i.quantity, 0);
  const cartTotal = cartForThis.reduce((s,i) => s + i.price * i.quantity, 0);

  // Favourites scoped to THIS restaurant's menu
  const menuItemIds = React.useMemo(() => new Set(menu.flatMap(sec => sec.items.map(it => it.id))), [menu]);
  const storeFavCount = [...(app.favourites || [])].filter(id => menuItemIds.has(id)).length;
  const storeSaved = app.isFavStore(r.id);

  // Gamification — derived, stable per restaurant
  const reorderCount = Math.round((r.reviews || 120) / 10) * 10;
  const TRAIL_STOPS = 5;
  const trailDone = 3;            // current rider's progress along the trail
  const trailFrac = trailDone / (TRAIL_STOPS - 1);

  const onAddRequest = (item) => {
    // cross-restaurant clearing prompt
    if (app.cart.length > 0 && app.cart[0].restaurant_id !== r.id) {
      setConfirmSwap({ item });
      return;
    }
    if (item.modifiers) {
      setModifierItem(item);
    } else {
      app.addToCart({ item, restaurant: r, modifiers: [] });
      app.toast(`${item.name} added`, 'success');
    }
  };

  const onConfirmModifier = (item, selected, computedPrice) => {
    app.addToCart({ item, restaurant: r, modifiers: selected, computedPrice });
    setModifierItem(null);
    app.toast(`${item.name} added`, 'success');
  };

  return (
    <Screen scroll={false}>
      {/* Scrollable content */}
      <div ref={scrollRef} style={{ flex: 1, overflow: 'auto', position: 'relative' }}>

        {/* Hero image */}
        <div data-lasso="restaurant-slug" data-slug={r.slug} style={{ height: 220, position: 'relative' }}>
          {loading
            ? <Skeleton h={220} r={0}/>
            : <>
                {r.heroArt
                  ? <FoodArt dish={r.heroArt} height={220} radius={0} style={{ width: '100%' }}/>
                  : <FoodPh height={220} hue={r.hue} radius={0}/>}
                <div data-field="restaurant-cover" style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(27,18,13,0.45) 0%, transparent 35%, rgba(245,239,231,1) 100%)' }}/>
              </>
          }

          {/* Floating actions over image */}
          <button onClick={() => app.back()} style={floatBtn(true, 16)}>
            <Ico.chevL c="var(--fg-primary)" s={20}/>
          </button>
          <button
            aria-pressed={storeSaved}
            onClick={() => {
              const added = app.toggleFavStore(r.id);
              app.toast(added ? `${r.name} saved to favourites` : `${r.name} removed`, added ? 'success' : 'info');
            }}
            style={{ ...floatBtn(true, undefined, 16), background: storeSaved ? 'var(--brand-orange)' : 'rgba(245,239,231,0.95)', transition: 'background 200ms var(--ease-out)' }}>
            <Ico.heart c={storeSaved ? '#fff' : 'var(--fg-primary)'} s={18} filled={storeSaved}/>
          </button>

          {/* Western "Wrangler's Pick" saddle ribbon */}
          {!loading && r.featured && r.featuredBadge && (
            <div data-field="hero-pick" style={{
              position: 'absolute', left: 0, bottom: 44, zIndex: 2,
              display: 'flex', alignItems: 'center', gap: 7,
              padding: '7px 14px 7px 16px',
              background: 'var(--brand-orange)', color: '#fff',
              borderRadius: '0 14px 14px 0',
              boxShadow: '0 6px 16px -4px rgba(193,59,31,0.55)',
            }}>
              <Ico.badge c="#FFE2C2" s={14}/>
              <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 11, letterSpacing: '0.09em', textTransform: 'uppercase' }}>{r.featuredBadge}</span>
            </div>
          )}

          {/* Sheriff-star rank medallion straddling the hero seam */}
          {!loading && (
            <div data-field="rank-medallion" style={{
              position: 'absolute', right: 20, bottom: -26, zIndex: 3,
              width: 74, height: 74,
              filter: 'drop-shadow(0 8px 16px rgba(27,18,13,0.4))',
            }}>
              <SheriffStar size={74} value={r.rating} sub="RATED"/>
            </div>
          )}
        </div>

        {/* Title block */}
        <div style={{ padding: '0 20px', marginTop: -28, position: 'relative', zIndex: 1 }}>
          {loading ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              <Skeleton w="60%" h={28}/>
              <Skeleton w="40%" h={14}/>
            </div>
          ) : (
            <>
              <div style={{ display: 'flex', gap: 6, marginBottom: 8, alignItems: 'center', flexWrap: 'wrap', paddingRight: 84 }}>
                <StatusPill kind={r.status}>{r.statusLabel}</StatusPill>
                <div style={{
                  display: 'inline-flex', alignItems: 'center', gap: 5,
                  padding: '4px 10px 4px 8px', borderRadius: 999,
                  background: 'rgba(46,139,78,0.12)',
                }}>
                  <Ico.refresh c="var(--live-green)" s={11}/>
                  <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 11, color: 'var(--live-green)' }}>{reorderCount}+ wranglers reordered</span>
                </div>
              </div>
              <div data-field="restaurant-name" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 28, letterSpacing: '-0.01em', lineHeight: 1.05, color: 'var(--fg-primary)', paddingRight: 84 }}>{r.name}</div>
              <div data-field="restaurant-tagline" style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)', marginTop: 4 }}>{r.tagline} · {r.reviews} ratings · {r.area}</div>

              {/* ── Trail Pass — gamified loyalty tracker (tap for bounties) ── */}
              <div data-lasso="trail-pass" onClick={() => setTrailOpen(true)} role="button" style={{
                marginTop: 16, borderRadius: 18, padding: '15px 16px 16px',
                background: '#2A1A12', cursor: 'pointer',
                position: 'relative', overflow: 'hidden',
                boxShadow: '0 10px 26px -10px rgba(27,18,13,0.5)',
              }}>
                {/* tooled-leather texture stack */}
                <div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'radial-gradient(120% 100% at 25% 0%, #4A2E1E 0%, #2A1A12 55%, #1C110A 100%)' }}/>
                <div aria-hidden="true" style={{ position: 'absolute', inset: 0, opacity: 0.5, backgroundImage: 'repeating-linear-gradient(115deg, rgba(255,225,190,0.05) 0 2px, transparent 2px 7px), repeating-linear-gradient(25deg, rgba(0,0,0,0.18) 0 1px, transparent 1px 9px)' }}/>
                <div aria-hidden="true" style={{ position: 'absolute', inset: 0, opacity: 0.06, backgroundImage: 'radial-gradient(circle, #F5EFE7 1px, transparent 1.6px)', backgroundSize: '13px 13px' }}/>
                <div aria-hidden="true" style={{ position: 'absolute', inset: 6, borderRadius: 13, border: '1.5px dashed rgba(242,140,27,0.4)', pointerEvents: 'none' }}/>
                <div style={{ position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 13 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <SheriffStar size={20}/>
                    <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 11, letterSpacing: '0.13em', textTransform: 'uppercase', color: 'var(--dust-cream)' }}>Trail Pass</span>
                  </div>
                  <span style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: '#C9B3A0' }}>{trailDone} of {TRAIL_STOPS} stops</span>
                </div>

                {/* trail track */}
                <div style={{ position: 'relative', height: 30, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 1px' }}>
                  <div style={{ position: 'absolute', left: 15, right: 15, top: '50%', borderTop: '2px dashed rgba(245,239,231,0.22)' }}/>
                  <div style={{ position: 'absolute', left: 15, top: '50%', borderTop: '2px solid var(--sun-orange)', width: `calc((100% - 30px) * ${trailFrac})` }}/>
                  {Array.from({ length: TRAIL_STOPS }).map((_, i) => {
                    const done = i < trailDone, current = i === trailDone;
                    const sz = current ? 30 : 26;
                    return (
                      <div key={i} style={{
                        position: 'relative', zIndex: 1, width: sz, height: sz, borderRadius: '50%',
                        display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                        background: done ? 'var(--sun-orange)' : current ? 'var(--brand-orange)' : '#3C2A1F',
                        border: done || current ? 'none' : '2px solid rgba(245,239,231,0.22)',
                        boxShadow: current ? '0 0 0 4px rgba(242,140,27,0.22)' : 'none',
                      }}>
                        {done ? <Ico.star c="#2A1A12" s={13}/>
                          : current ? <Ico.star c="#fff" s={14}/>
                          : i === TRAIL_STOPS - 1 ? <Ico.horseshoe c="rgba(245,239,231,0.5)" s={14}/>
                          : <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'rgba(245,239,231,0.35)' }}/>}
                      </div>
                    );
                  })}
                </div>

                <div style={{ position: 'relative', marginTop: 13, display: 'flex', alignItems: 'center', gap: 9 }}>
                  <div style={{ width: 28, height: 28, borderRadius: 9, background: 'rgba(242,140,27,0.16)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                    <Ico.horseshoe c="var(--sun-orange)" s={15}/>
                  </div>
                  <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--dust-cream)', lineHeight: 1.35, flex: 1 }}>
                    <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800 }}>{TRAIL_STOPS - trailDone} more rides</span> <span style={{ color: '#C9B3A0' }}>and a free side rides in on the house.</span>
                  </div>
                  <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '7px 12px', borderRadius: 10, background: 'var(--brand-orange)', flexShrink: 0, boxShadow: 'var(--shadow-orange)' }}>
                    <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 11, color: '#fff', letterSpacing: '0.04em' }}>Bounties</span>
                    <Ico.chev c="#fff" s={13}/>
                  </div>
                </div>
              </div>

              {/* Delivery / Pickup toggle + mode details + quick actions */}
              <div data-lasso="restaurant-service-stack" style={{
                marginTop: 14,
                padding: 6,
                borderRadius: 20,
                background: 'rgba(58,31,17,0.075)',
                border: '1px solid rgba(58,31,17,0.10)',
                boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.42), 0 12px 28px rgba(27,18,13,0.07)',
                display: 'flex',
                flexDirection: 'column',
                gap: '0.24rem',
              }}>
                <div data-lasso="mode-toggle" style={{ display: 'flex', gap: 4, padding: 4, background: 'rgba(245,239,231,0.72)', borderRadius: 16, border: '1px solid rgba(58,31,17,0.08)' }}>
                {[
                  { id: 'delivery', label: 'Delivery', icon: Ico.ride, meta: r.eta },
                  { id: 'pickup', label: 'Pickup', icon: Ico.bag, meta: r.distance || '1.2 mi' },
                ].map(opt => {
                  const on = mode === opt.id;
                  return (
                    <button key={opt.id} onClick={() => setMode(opt.id)} style={{
                      flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7,
                      padding: '10px 8px', borderRadius: 12, border: 'none', cursor: 'pointer',
                      background: on ? 'var(--bg-surface)' : 'transparent',
                      boxShadow: on ? 'var(--shadow-sm)' : 'none',
                    }}>
                      <opt.icon c={on ? 'var(--brand-orange)' : 'var(--warm-stone)'} s={17}/>
                      <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13, color: on ? 'var(--fg-primary)' : 'var(--warm-stone)' }}>{opt.label}</span>
                      <span style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: on ? 'var(--brand-orange)' : 'var(--warm-stone)' }}>· {opt.meta}</span>
                    </button>
                  );
                })}
              </div>

              {/* Mode-aware info bar */}
                <div data-lasso="info-bar" style={{
                  display: 'flex', alignItems: 'stretch',
                  background: 'rgba(255,255,255,0.74)', borderRadius: 16,
                  border: '1px solid rgba(58,31,17,0.08)', overflow: 'hidden',
                }}>
                {(mode === 'delivery'
                  ? [
                      { icon: <Ico.clock c="var(--horse-brown)" s={15}/>, value: r.eta, label: 'Arrives' },
                      { icon: <Ico.ride c="var(--brand-orange)" s={15}/>, value: r.deliveryFee === 0 ? 'Free' : `£${r.deliveryFee.toFixed(2)}`, label: `Min £${r.minOrder.toFixed(0)}` },
                      { icon: <Ico.pin c="var(--horse-brown)" s={15}/>, value: r.distance || '1.2 mi', label: r.area || 'Nearby' },
                    ]
                  : [
                      { icon: <Ico.clock c="var(--horse-brown)" s={15}/>, value: r.etaShort, label: 'Ready in' },
                      { icon: <Ico.bag c="var(--brand-orange)" s={15}/>, value: 'Free', label: 'No fee' },
                      { icon: <Ico.pin c="var(--horse-brown)" s={15}/>, value: r.distance || '1.2 mi', label: 'Walk to collect' },
                    ]
                ).map((s, i) => (
                  <React.Fragment key={i}>
                    {i > 0 && <div style={{ width: 0, borderLeft: '1.5px dashed var(--soft-line)', margin: '10px 0' }}/>}
                    <div data-field={`info-${i}`} style={{ flex: 1, padding: '11px 8px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3, textAlign: 'center' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                        {s.icon}
                        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--fg-primary)' }}>{s.value}</span>
                      </div>
                      <span style={{ fontFamily: 'var(--font-body)', fontSize: 10.5, color: 'var(--warm-stone)', letterSpacing: '0.02em' }}>{s.label}</span>
                    </div>
                  </React.Fragment>
                ))}
              </div>

                {/* Quick actions: group order + allergy guide */}
                <div data-lasso="service-action-row" style={{ display: 'flex', gap: 4 }}>
                  <ActionTile icon={<Ico.user c="var(--brand-orange)" s={18}/>} title="Group order" sub="Split one bag" onClick={() => setGroupOpen(true)}/>
                  <ActionTile icon={<Ico.leaf c="var(--live-green)" s={18}/>} title="Allergy guide" sub="What's inside" onClick={() => setAllergyOpen(true)}/>
                </div>
              </div>

              {/* Lasso perks — the stuff that beats the other guys */}
              <PerksBar/>
            </>
          )}
        </div>

        {/* Sticky category nav */}
        {!loading && (
          <div data-lasso="category-nav" style={{
            position: 'sticky', top: 0, zIndex: 5, marginTop: 18,
            background: 'var(--bg-app)', padding: '12px 0 8px',
            display: 'flex', gap: 8, overflowX: 'auto', scrollbarWidth: 'none',
            scrollSnapType: 'x proximity', scrollPaddingInline: 20,
          }}>
            <style>{`[data-lasso="category-nav"]::-webkit-scrollbar{display:none}`}</style>
            <div style={{ width: 12, flexShrink: 0 }}/>
            <button data-lasso="category-nav-faves" onClick={() => setFavesOnly(v => !v)} style={{
              padding: '8px 14px 8px 11px', borderRadius: 14, flexShrink: 0,
              background: favesOnly ? 'var(--brand-orange)' : 'var(--bg-surface)',
              color: favesOnly ? '#fff' : 'var(--fg-primary)',
              border: '1.5px solid ' + (favesOnly ? 'var(--brand-orange)' : 'var(--soft-line)'),
              fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 12, letterSpacing: '0.04em',
              whiteSpace: 'nowrap', cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 6,
              scrollSnapAlign: 'start',
            }}>
              <Ico.heart c={favesOnly ? '#fff' : 'var(--brand-orange)'} s={14} filled={favesOnly}/>
              Favourites
              {storeFavCount > 0 && (
                <span style={{
                  minWidth: 16, height: 16, borderRadius: 8, padding: '0 4px',
                  background: favesOnly ? 'rgba(255,255,255,0.25)' : 'var(--bg-warm)',
                  color: favesOnly ? '#fff' : 'var(--horse-brown)',
                  fontSize: 10, fontWeight: 900,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>{storeFavCount}</span>
              )}
            </button>
            {menu.map(sec => (
              <button key={sec.id} data-lasso="category-nav-item-template" onClick={() => {
                setFavesOnly(false);
                setActiveCat(sec.id);
                const el = document.getElementById(`sec-${sec.id}`);
                if (el && scrollRef.current) {
                  scrollRef.current.scrollTo({ top: el.offsetTop - 60, behavior: 'smooth' });
                }
              }} style={{
                padding: '8px 14px', borderRadius: 14, flexShrink: 0,
                background: activeCat === sec.id ? 'var(--dark-chocolate)' : 'var(--bg-surface)',
                color: activeCat === sec.id ? 'var(--dust-cream)' : 'var(--fg-primary)',
                border: '1.5px solid ' + (activeCat === sec.id ? 'var(--dark-chocolate)' : 'var(--soft-line)'),
                fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 12, letterSpacing: '0.04em',
                whiteSpace: 'nowrap', cursor: 'pointer',
                scrollSnapAlign: 'start',
              }}>{sec.name}</button>
            ))}
            <div style={{ width: 12, flexShrink: 0 }}/>
          </div>
        )}

        {/* Menu sections */}
        <div data-lasso="menu-container" style={{ padding: '8px 0 140px', display: 'flex', flexDirection: 'column', gap: 22 }}>
          {loading ? (
            [0,1].map(i => (
              <div key={i} style={{ padding: '0 20px', display: 'flex', flexDirection: 'column', gap: 10 }}>
                <Skeleton w="40%" h={12}/>
                {[0,1].map(j => (
                  <div key={j} style={{ background: 'var(--bg-surface)', borderRadius: 20, padding: 12, display: 'flex', gap: 12 }}>
                    <Skeleton w={88} h={88} r={14}/>
                    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6 }}>
                      <Skeleton w="70%" h={14}/>
                      <Skeleton w="100%" h={11}/>
                      <Skeleton w="40%" h={11}/>
                    </div>
                  </div>
                ))}
              </div>
            ))
          ) : (
            (() => {
              const visibleSecs = menu
                .map(sec => ({ ...sec, items: favesOnly ? sec.items.filter(it => app.isFavourite(it.id)) : sec.items }))
                .filter(sec => sec.items.length > 0);

              if (favesOnly && visibleSecs.length === 0) {
                return (
                  <div data-lasso="faves-empty" style={{ padding: '32px 28px', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
                    <div style={{ width: 56, height: 56, borderRadius: '50%', background: 'var(--bg-warm)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 6 }}>
                      <Ico.heart c="var(--brand-orange)" s={24}/>
                    </div>
                    <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 16, color: 'var(--fg-primary)' }}>No favourites yet</div>
                    <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)', lineHeight: 1.4, maxWidth: 220 }}>Tap the heart on any dish to save it here for next time.</div>
                    <button onClick={() => setFavesOnly(false)} style={{
                      marginTop: 10, padding: '9px 18px', borderRadius: 12, border: 'none', cursor: 'pointer',
                      background: 'var(--dark-chocolate)', color: 'var(--dust-cream)',
                      fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 12, letterSpacing: '0.04em',
                    }}>Browse the menu</button>
                  </div>
                );
              }

              const matchFilter = (it) => {
                switch (menuFilter) {
                  case 'popular': return !!it.popular;
                  case 'new': return !!it.new;
                  case 'veg': return (it.diet || []).includes('v');
                  case 'gf': return (it.diet || []).includes('gf');
                  case 'under10': return it.price < 10;
                  default: return true;
                }
              };

              return visibleSecs.map((sec, si) => {
                const items = menuLayout === 'image-led' ? sec.items.filter(matchFilter) : sec.items;
                return (
                  <React.Fragment key={sec.id}>
                    {menuLayout === 'image-led' && si === 1 && (
                      <MenuFilterSlider active={menuFilter} onChange={setMenuFilter}/>
                    )}
                    {menuLayout === 'image-led' && si === 1 && (
                      <UpsellRow title="Frequently added" subtitle="Crowd favourites" items={getAddOns(menu)} app={app} restaurant={r} onAdd={(it) => onAddRequest(it)}/>
                    )}
                    {items.length > 0 && (
                      <div id={`sec-${sec.id}`} data-lasso="menu-section-template">
                        <div style={{ padding: '0 20px 10px', display: 'flex', alignItems: 'center', gap: 8 }}>
                          <Eyebrow>{sec.name}</Eyebrow>
                          <div style={{ flex: 1, height: 1, background: 'var(--soft-line)' }}/>
                          <span style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--warm-stone)' }}>{items.length}</span>
                        </div>
                        {menuLayout === 'image-led' ? (
                          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, padding: '0 20px', alignItems: 'stretch' }}>
                            {items.map(it => {
                              const qty = app.cart.filter(c => c.item_id === it.id).reduce((s,c)=>s+c.quantity,0);
                              return <MenuCardBig key={it.id} item={it} qty={qty} app={app} onAdd={() => onAddRequest(it)}/>;
                            })}
                          </div>
                        ) : (
                          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, padding: '0 20px' }}>
                            {items.map(it => {
                              const qty = app.cart.filter(c => c.item_id === it.id).reduce((s,c)=>s+c.quantity,0);
                              return <MenuItemList key={it.id} item={it} qty={qty} app={app} onAdd={() => onAddRequest(it)}/>;
                            })}
                          </div>
                        )}
                      </div>
                    )}
                  </React.Fragment>
                );
              });
            })()
          )}
        </div>
      </div>

      {/* Sticky cart bar (mini) */}
      {cartItemCount > 0 && !cartOpen && (
        <div data-lasso="cart-toggle" onClick={() => setCartOpen(true)} style={{
          position: 'absolute', left: 12, right: 12, bottom: 18, zIndex: 100,
          background: 'var(--dark-chocolate)', borderRadius: 22, padding: '12px 14px',
          display: 'flex', alignItems: 'center', gap: 10, color: 'var(--dust-cream)',
          boxShadow: 'var(--shadow-lg)', cursor: 'pointer',
          animation: 'lasso-bag-pop 320ms var(--ease-out)',
        }}>
          <div style={{
            width: 36, height: 36, borderRadius: 10, background: 'var(--brand-orange)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 14,
          }}>{cartItemCount}</div>
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13 }}>View bag</div>
            <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: '#9F8979' }}>{cartItemCount} {cartItemCount===1?'item':'items'}</div>
          </div>
          <div data-lasso="cart-total" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 16 }}>£{cartTotal.toFixed(2)}</div>
          <div style={{ width: 42, height: 42, borderRadius: 14, background: 'var(--brand-orange)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Ico.arrow c="#fff" s={20}/>
          </div>
        </div>
      )}

      {/* Cart drawer */}
      <BottomSheet open={cartOpen} onClose={() => setCartOpen(false)} title="Your bag">
        <CartContents app={app} restaurant={r} mode={mode} onCheckout={() => { setCartOpen(false); app.nav('checkout'); }}/>
      </BottomSheet>

      {/* Modifier modal */}
      <ModifierModal
        item={modifierItem}
        modifierKey={modifierItem?.modifiers}
        onClose={() => setModifierItem(null)}
        onConfirm={onConfirmModifier}
      />

      {/* Cross-restaurant swap confirm */}
      <BottomSheet open={!!confirmSwap} onClose={() => setConfirmSwap(null)} title="Start a new bag?">
        <div style={{ padding: '0 20px 24px' }}>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 14, color: 'var(--fg-primary)', lineHeight: 1.5 }}>
            Your bag has items from <strong>{RESTAURANT_LOOKUP[app.cart[0]?.restaurant_id]?.name}</strong>. Adding from <strong>{r.name}</strong> will clear your current bag.
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 18 }}>
            <Button kind="accent" full onClick={() => {
              const item = confirmSwap.item;
              app.clearCart();
              setConfirmSwap(null);
              setTimeout(() => onAddRequest(item), 100);
            }}>Clear bag and add</Button>
            <Button kind="ghost" full onClick={() => setConfirmSwap(null)}>Keep current bag</Button>
          </div>
        </div>
      </BottomSheet>

      {/* Group order drawer */}
      <GroupOrderSheet open={groupOpen} onClose={() => setGroupOpen(false)} app={app} restaurant={r}/>

      {/* Allergy guide drawer */}
      <AllergyGuideSheet open={allergyOpen} onClose={() => setAllergyOpen(false)} app={app} menu={menu} onFilter={(f) => setMenuFilter(f)}/>

      {/* Trail Bounties — vendor UGC/referral challenges */}
      <VendorChallengesSheet open={trailOpen} onClose={() => setTrailOpen(false)} app={app} restaurant={r} trailDone={trailDone} trailTotal={TRAIL_STOPS}/>
    </Screen>
  );
}

function floatBtn(round, left, right) {
  return {
    position: 'absolute', top: 12, left, right,
    width: 40, height: 40, borderRadius: round ? '50%' : 10,
    background: 'rgba(245,239,231,0.95)', backdropFilter: 'blur(8px)', border: 'none',
    display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
    boxShadow: 'var(--shadow-md)',
  };
}

// ─── Favourite (heart) button for meal cards ────────────────────────
function FavButton({ itemId, app, size = 34, overlay = false }) {
  const saved = app?.isFavourite?.(itemId) || false;
  const base = overlay
    ? {
        background: saved ? 'rgba(216,90,20,0.54)' : 'rgba(245,239,231,0.20)',
        border: saved ? '1px solid rgba(255,255,255,0.42)' : '1px solid rgba(255,255,255,0.30)',
        boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.32), 0 8px 24px rgba(27,18,13,0.20)',
        backdropFilter: 'blur(10px) saturate(1.45) brightness(1.08)',
        WebkitBackdropFilter: 'blur(10px) saturate(1.45) brightness(1.08)',
      }
    : {
        background: saved ? 'rgba(216,90,20,0.18)' : 'rgba(255,255,255,0.38)',
        border: '1px solid ' + (saved ? 'rgba(216,90,20,0.40)' : 'rgba(255,255,255,0.34)'),
        boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.34), 0 6px 18px rgba(27,18,13,0.12)',
        backdropFilter: 'blur(8px) saturate(1.35)',
        WebkitBackdropFilter: 'blur(8px) saturate(1.35)',
      };
  return (
    <button
      data-action="toggle-favourite"
      data-lasso="meal-fav-btn"
      aria-pressed={saved}
      aria-label={saved ? 'Remove from favourites' : 'Add to favourites'}
      onClick={(e) => {
        e.stopPropagation();
        const next = app?.toggleFavourite?.(itemId);
        app?.toast?.(next ? 'Saved to favourites' : 'Removed from favourites', next ? 'success' : 'info');
      }}
      style={{
        width: size, height: size, borderRadius: '50%', flexShrink: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
        transition: 'all 180ms var(--ease-out)',
        ...base,
      }}>
      <Ico.heart c={overlay ? (saved ? '#fff' : 'var(--horse-brown)') : (saved ? 'var(--brand-orange)' : 'var(--warm-stone)')} s={16} filled={saved}/>
    </button>
  );
}

function Stat({ icon, value, label }) {
  return (
    <div style={{ flex: 1, background: 'var(--bg-surface)', borderRadius: 16, padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 2, border: '1.5px solid var(--soft-line)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
        {icon}
        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 14, color: 'var(--fg-primary)' }}>{value}</span>
      </div>
      <div style={{ fontFamily: 'var(--font-body)', fontSize: 10.5, color: 'var(--warm-stone)' }}>{label}</div>
    </div>
  );
}

// ─── Menu item — image-led variant (with thumbnail) ─────────────────
function MenuItemImage({ item, qty, onAdd, app }) {
  return (
    <div data-lasso="menu-item-template" data-item-id={item.id} style={{
      display: 'flex', gap: 12, background: 'var(--bg-surface)', borderRadius: 20, padding: 12,
      alignItems: 'stretch', border: '1.5px solid var(--soft-line)', position: 'relative',
    }}>
      <div style={{ width: 92, flexShrink: 0, position: 'relative' }}>
        {item.art
          ? <FoodArt dish={item.art} height={92} radius={14}/>
          : <FoodPh height={92} hue={item.hue} radius={14} glyph={item.glyph}/>}
        {item.popular && (
          <div data-field="popular-badge" style={{ position: 'absolute', top: 6, left: 6 }}>
            <Pill bg="var(--dark-chocolate)" fg="var(--brand-orange)" style={{ fontSize: 9, padding: '3px 7px' }}>★ Popular</Pill>
          </div>
        )}
        {item.new && (
          <div data-field="new-badge" style={{ position: 'absolute', top: 6, left: 6 }}>
            <Pill bg="var(--brand-orange)" fg="#fff" style={{ fontSize: 9, padding: '3px 7px' }}>NEW</Pill>
          </div>
        )}
        <div style={{ position: 'absolute', bottom: 6, left: 6 }}>
          <FavButton itemId={item.id} app={app} size={24} overlay/>
        </div>
        {item.diet?.includes('v') && (
          <div data-field="vegan-badge" style={{ position: 'absolute', bottom: 6, right: 6 }}>
            <Pill bg="rgba(255,255,255,0.86)" fg="var(--live-green)" style={{ padding: '2px 6px', fontSize: 9, boxShadow: '0 2px 8px rgba(58,38,24,0.22)' }}><Ico.leaf c="var(--live-green)" s={10}/>V</Pill>
          </div>
        )}
      </div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>
        <div data-field="item-name" style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14.5, lineHeight: 1.2, color: 'var(--fg-primary)' }}>{item.name}</div>
        <div data-field="item-description" style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--warm-stone)', lineHeight: 1.4, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{item.desc}</div>
        <div style={{ marginTop: 'auto', display: 'flex', justifyContent: 'space-between', alignItems: 'center', paddingTop: 4 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <div data-field="item-price" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 14, color: 'var(--fg-primary)' }}>£{item.price.toFixed(2)}</div>
            {item.kcal > 0 && <div data-field="item-kcal" style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--warm-stone)' }}>{item.kcal} kcal</div>}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <button onClick={onAdd} style={{
            background: 'var(--brand-orange)', color: '#fff', border: 'none',
            width: 32, height: 32, borderRadius: 10, cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: 'var(--shadow-orange)', position: 'relative',
          }}>
            <Ico.plus c="#fff" s={18}/>
            {qty > 0 && (
              <span style={{
                position: 'absolute', top: -4, right: -4, minWidth: 16, height: 16, borderRadius: 8, padding: '0 4px',
                background: 'var(--dark-chocolate)', color: '#fff', border: '2px solid var(--bg-surface)',
                fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 9,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>{qty}</span>
            )}
          </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Menu item — list-led variant (no thumbnail, denser) ────────────
function MenuItemList({ item, qty, onAdd, app }) {
  return (
    <div data-lasso="menu-item-template" data-item-id={item.id} style={{
      display: 'flex', gap: 12, background: 'var(--bg-surface)', borderRadius: 16, padding: '14px 14px 14px 16px',
      alignItems: 'center', border: '1.5px solid var(--soft-line)',
    }}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <div data-field="item-name" style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 15, color: 'var(--fg-primary)' }}>{item.name}</div>
          {item.popular && <Pill bg="var(--bg-warm)" fg="var(--horse-brown)" style={{ fontSize: 9, padding: '2px 6px' }}>★</Pill>}
          {item.new && <Pill bg="var(--brand-orange)" fg="#fff" style={{ fontSize: 9, padding: '2px 6px' }}>NEW</Pill>}
        </div>
        <div data-field="item-description" style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--warm-stone)', lineHeight: 1.4 }}>{item.desc}</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
          <div data-field="item-price" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 13.5, color: 'var(--fg-primary)' }}>£{item.price.toFixed(2)}</div>
          {item.kcal > 0 && <div data-field="item-kcal" style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--warm-stone)' }}>· {item.kcal} kcal</div>}
        </div>
      </div>
      <FavButton itemId={item.id} app={app} size={36}/>
      <button onClick={onAdd} style={{
        background: 'var(--brand-orange)', color: '#fff', border: 'none',
        width: 36, height: 36, borderRadius: 12, cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        boxShadow: 'var(--shadow-orange)', position: 'relative', flexShrink: 0,
      }}>
        <Ico.plus c="#fff" s={20}/>
        {qty > 0 && (
          <span style={{
            position: 'absolute', top: -4, right: -4, minWidth: 16, height: 16, borderRadius: 8, padding: '0 4px',
            background: 'var(--dark-chocolate)', color: '#fff', border: '2px solid var(--bg-surface)',
            fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 9,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>{qty}</span>
        )}
      </button>
    </div>
  );
}

// ─── Cart drawer contents ──────────────────────────────────────────
function CartContents({ app, restaurant: r, mode = 'delivery', onCheckout }) {
  const items = app.cart.filter(c => c.restaurant_id === r.id);
  const subtotal = items.reduce((s,i) => s + i.price * i.quantity, 0);
  const delivery = mode === 'pickup' ? 0 : r.deliveryFee;
  const discount = promoValue(app.promo, subtotal, delivery);
  const total = Math.max(0, subtotal + delivery - discount);
  const belowMin = subtotal < r.minOrder;

  if (items.length === 0) {
    return (
      <div style={{ padding: '0 20px 40px' }}>
        <EmptyState title="Empty bag" body="Add something from the menu to start your order." icon={<Bull size={48}/>}/>
      </div>
    );
  }

  return (
    <div data-lasso="cart-sidebar" style={{ padding: '0 20px 30px', display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* From */}
      <div style={{
        background: 'var(--bg-warm)', borderRadius: 14, padding: '10px 14px',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <Ico.bag c="var(--horse-brown)" s={18}/>
        <div style={{ flex: 1, fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--horse-brown)' }}>
          From <strong style={{ fontFamily: 'var(--font-display)', fontWeight: 800, color: 'var(--dark-chocolate)' }}>{r.name}</strong>
        </div>
        <Eyebrow color="var(--horse-brown)">{r.etaShort}</Eyebrow>
      </div>

      {/* Items */}
      <div data-lasso="cart-items" style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        {items.map(ci => (
          <CartRow key={ci.cart_id} item={ci} app={app}/>
        ))}
      </div>

      {/* Upsell — goes well with */}
      <UpsellRow
        title="Goes well with"
        subtitle="One tap to add"
        px={0}
        items={getAddOns(MENUS[r.id] || GENERIC_MENU).filter(it => !items.find(ci => ci.item_id === it.id))}
        app={app} restaurant={r}
        onAdd={(it) => { app.addToCart({ item: it, restaurant: r, modifiers: [] }); app.toast(`${it.name} added`, 'success'); }}
      />

      {/* Promo */}
      <CartPromo app={app}/>

      {/* Summary */}
      <div style={{ background: 'var(--bg-surface)', borderRadius: 16, padding: 14, display: 'flex', flexDirection: 'column', gap: 8, border: '1.5px solid var(--soft-line)' }}>
        <SummaryLine label="Subtotal" value={`£${subtotal.toFixed(2)}`}/>
        <SummaryLine label={mode === 'pickup' ? 'Pickup' : 'Delivery'} value={<span data-lasso="cart-delivery-fee">{mode === 'pickup' ? 'Free' : `£${delivery.toFixed(2)}`}</span>}/>
        {discount > 0 && (
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--live-green)' }}>{app.promo.code}</span>
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13, color: 'var(--live-green)' }}>−£{discount.toFixed(2)}</span>
          </div>
        )}
        <div style={{ height: 1, background: 'var(--soft-line)', margin: '4px 0' }}/>
        <SummaryLine label="Total" value={`£${total.toFixed(2)}`} bold/>
      </div>

      {/* Min order warning */}
      {belowMin && (
        <div data-lasso="cart-min-order-warning" style={{
          padding: '10px 14px', background: 'rgba(193,59,31,0.08)', borderRadius: 12,
          fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--delayed-red)',
        }}>Add £{(r.minOrder - subtotal).toFixed(2)} more to reach the £{r.minOrder.toFixed(2)} minimum order.</div>
      )}

      <Button data-lasso="checkout-btn" kind="accent" full size="lg" disabled={belowMin} onClick={onCheckout}>
        Checkout · £{total.toFixed(2)}
      </Button>
    </div>
  );
}

// ─── Cart promo — input + earned codes, applied basket-wide ───────
function CartPromo({ app }) {
  const [open, setOpen] = React.useState(false);
  const [code, setCode] = React.useState('');
  const applied = app.promo;

  const applyCode = (raw) => {
    const q = raw.trim().toUpperCase();
    if (!q) return;
    const found = EARNED_PROMOS.find(p => p.code === q);
    if (found) {
      app.setPromo(found);
      app.toast(`${found.code} applied — ${found.label.toLowerCase()}`, 'success');
      setOpen(false); setCode('');
    } else {
      app.toast(`“${q}” isn’t a live code`, 'error');
    }
  };

  if (applied) {
    return (
      <div data-lasso="promo-applied" style={{
        display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px',
        background: 'rgba(46,139,78,0.08)', border: '1.5px solid rgba(46,139,78,0.35)', borderRadius: 14,
        animation: 'lasso-bag-pop 260ms var(--ease-out)',
      }}>
        <div style={{ width: 32, height: 32, borderRadius: 9, background: 'rgba(46,139,78,0.14)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <Ico.check c="var(--live-green)" s={16}/>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 12.5, letterSpacing: '0.06em', color: 'var(--fg-primary)' }}>{applied.code}</div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--live-green)', marginTop: 1 }}>{applied.label} · active</div>
        </div>
        <button onClick={() => { app.setPromo(null); app.toast('Promo removed', 'info'); }} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 6, display: 'flex' }}>
          <Ico.x c="var(--warm-stone)" s={15}/>
        </button>
      </div>
    );
  }

  return (
    <div data-lasso="promo-picker">
      {!open ? (
        <button onClick={() => setOpen(true)} style={{
          width: '100%', display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', boxSizing: 'border-box',
          background: 'var(--bg-surface)', border: '1.5px dashed var(--soft-line)', borderRadius: 14, cursor: 'pointer',
        }}>
          <Ico.ticket c="var(--brand-orange)" s={18}/>
          <span style={{ flex: 1, textAlign: 'left', fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13, color: 'var(--fg-primary)' }}>Add promo code</span>
          {EARNED_PROMOS.length > 0 && <Pill bg="var(--bg-warm)" fg="var(--brand-orange)" style={{ fontSize: 10 }}>{EARNED_PROMOS.length} earned</Pill>}
          <Ico.chev c="var(--warm-stone)" s={16}/>
        </button>
      ) : (
        <div style={{ background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 16, padding: 12, display: 'flex', flexDirection: 'column', gap: 10, animation: 'lasso-slide-up 220ms var(--ease-out)' }}>
          {/* input row */}
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', padding: '4px 4px 4px 12px', background: 'var(--bg-app)', borderRadius: 12, border: '1.5px solid var(--soft-line)' }}>
            <Ico.ticket c="var(--brand-orange)" s={16}/>
            <input
              value={code}
              onChange={e => setCode(e.target.value.toUpperCase())}
              onKeyDown={e => { if (e.key === 'Enter') applyCode(code); }}
              placeholder="Enter code"
              autoFocus
              style={{ flex: 1, minWidth: 0, border: 'none', outline: 'none', background: 'transparent', fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 13, letterSpacing: '0.08em', color: 'var(--fg-primary)', textTransform: 'uppercase' }}/>
            <Button kind="primary" size="sm" onClick={() => applyCode(code)}>Apply</Button>
          </div>
          {/* earned codes */}
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 10.5, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--warm-stone)', padding: '2px 2px 0' }}>Your codes</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {EARNED_PROMOS.map(p => (
              <button key={p.code} onClick={() => applyCode(p.code)} style={{
                display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderRadius: 12, cursor: 'pointer', textAlign: 'left',
                background: 'var(--bg-warm)', border: '1.5px dashed rgba(216,90,20,0.35)',
              }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 12, letterSpacing: '0.06em', color: 'var(--fg-primary)' }}>{p.code}</span>
                    <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 11, color: 'var(--brand-orange)' }}>{p.label}</span>
                  </div>
                  <div style={{ fontFamily: 'var(--font-body)', fontSize: 10.5, color: 'var(--warm-stone)', marginTop: 2 }}>{p.sub} · expires {p.expires}</div>
                </div>
                <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 11, color: 'var(--horse-brown)', flexShrink: 0 }}>Use →</span>
              </button>
            ))}
          </div>
          <button onClick={() => { setOpen(false); setCode(''); }} style={{ background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 11.5, color: 'var(--warm-stone)', padding: 2 }}>Cancel</button>
        </div>
      )}
    </div>
  );
}

function CartRow({ item, app }) {
  const r = RESTAURANT_LOOKUP[item.restaurant_id];
  const modSummary = (item.modifiers || []).map(m => m.name).filter(n => !n.toLowerCase().includes('single') && !n.toLowerCase().includes('warm corn') && !n.toLowerCase().includes('whole milk')).slice(0, 2).join(', ');
  return (
    <div data-lasso="cart-item-template" data-cart-id={item.cart_id} style={{
      display: 'flex', gap: 10, padding: '10px 0', alignItems: 'flex-start',
      borderBottom: '1px solid var(--soft-line)',
    }}>
      <div style={{ width: 36, height: 36, borderRadius: 10, flexShrink: 0 }}>
        {item.art
          ? <FoodArt dish={item.art} height={36} radius={10}/>
          : <FoodPh height={36} hue={item.hue || r?.hue || 'orange'} radius={10}/>}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
          <div data-field="item-name" style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13.5, color: 'var(--fg-primary)', lineHeight: 1.25, flex: 1 }}>{item.item_name}</div>
          <div data-field="item-price" style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13, color: 'var(--fg-primary)' }}>£{(item.price * item.quantity).toFixed(2)}</div>
        </div>
        {modSummary && <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)', marginTop: 2 }}>+ {modSummary}</div>}
        <div style={{ marginTop: 6, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <Stepper value={item.quantity} onChange={(v) => v === 0 ? app.removeFromCart(item.cart_id) : app.updateCartQty(item.cart_id, v)} size="sm"/>
          <button data-action="remove-item" onClick={() => app.removeFromCart(item.cart_id)} style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 11, color: 'var(--warm-stone)', background: 'none', border: 'none', cursor: 'pointer' }}>Remove</button>
        </div>
      </div>
    </div>
  );
}

function SummaryLine({ label, value, bold }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between' }}>
      <span style={{ fontFamily: 'var(--font-body)', fontSize: bold ? 14 : 13, color: bold ? 'var(--fg-primary)' : 'var(--warm-stone)', fontWeight: bold ? 700 : 400 }}>{label}</span>
      <span style={{ fontFamily: 'var(--font-display)', fontWeight: bold ? 900 : 700, fontSize: bold ? 16 : 13, color: 'var(--fg-primary)' }}>{value}</span>
    </div>
  );
}

// ─── Modifier modal ─────────────────────────────────────────────────
function ModifierModal({ item, modifierKey, onClose, onConfirm }) {
  const cfg = modifierKey ? MODIFIERS[modifierKey] : null;

  const initial = React.useMemo(() => {
    if (!cfg) return {};
    const sel = {};
    cfg.groups.forEach(g => {
      sel[g.id] = g.options.filter(o => o.default).map(o => o.id);
    });
    return sel;
  }, [cfg, item?.id]);

  const [selected, setSelected] = React.useState(initial);
  React.useEffect(() => setSelected(initial), [initial]);

  if (!item || !cfg) return <BottomSheet open={false}/>;

  const toggle = (groupId, optId, max) => {
    setSelected(s => {
      const cur = s[groupId] || [];
      if (cur.includes(optId)) {
        return { ...s, [groupId]: cur.filter(i => i !== optId) };
      }
      if (max === 1) return { ...s, [groupId]: [optId] };
      if (cur.length >= max) return s;
      return { ...s, [groupId]: [...cur, optId] };
    });
  };

  const flatSelected = cfg.groups.flatMap(g => (selected[g.id] || []).map(oid => {
    const opt = g.options.find(o => o.id === oid);
    return opt ? { groupId: g.id, ...opt } : null;
  }).filter(Boolean));

  const extras = flatSelected.reduce((s, o) => s + (o.price || 0), 0);
  const totalPrice = item.price + extras;

  const allRequiredMet = cfg.groups.every(g => !g.required || (selected[g.id] || []).length > 0);

  return (
    <BottomSheet open={!!item} onClose={onClose}>
      <div data-lasso="modifier-modal" style={{ padding: '0 20px 24px' }}>
        {/* header */}
        <div style={{ marginBottom: 12 }}>
          <div data-lasso="modifier-modal-title" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 22, letterSpacing: '-0.01em', color: 'var(--fg-primary)' }}>{item.name}</div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)', marginTop: 4, lineHeight: 1.4 }}>{item.desc}</div>
        </div>

        <div data-lasso="modifier-modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
          {cfg.groups.map(g => {
            const sel = selected[g.id] || [];
            return (
              <div key={g.id}>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10 }}>
                  <div>
                    <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--fg-primary)' }}>{g.title}</div>
                    {g.desc && <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)', marginTop: 2 }}>{g.desc}</div>}
                  </div>
                  {g.required && <Pill bg="var(--bg-warm)" fg="var(--horse-brown)" style={{ fontSize: 9 }}>Required</Pill>}
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {g.options.map(opt => {
                    const on = sel.includes(opt.id);
                    return (
                      <label key={opt.id} onClick={() => toggle(g.id, opt.id, g.max)} style={{
                        display: 'flex', alignItems: 'center', gap: 12,
                        padding: '12px 14px', borderRadius: 14, cursor: 'pointer',
                        background: on ? 'var(--bg-warm)' : 'var(--bg-surface)',
                        border: '1.5px solid ' + (on ? 'var(--brand-orange)' : 'var(--soft-line)'),
                        transition: 'all 180ms var(--ease-out)',
                      }}>
                        <div style={{
                          width: 22, height: 22, borderRadius: g.max === 1 ? '50%' : 6, flexShrink: 0,
                          border: '2px solid ' + (on ? 'var(--brand-orange)' : 'var(--soft-line)'),
                          background: on ? 'var(--brand-orange)' : '#fff',
                          display: 'flex', alignItems: 'center', justifyContent: 'center',
                        }}>{on && <Ico.check c="#fff" s={14}/>}</div>
                        <div style={{ flex: 1, fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13.5, color: 'var(--fg-primary)' }}>{opt.name}</div>
                        {opt.price > 0 && <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12.5, color: 'var(--horse-brown)' }}>+£{opt.price.toFixed(2)}</div>}
                      </label>
                    );
                  })}
                </div>
              </div>
            );
          })}
        </div>

        <div style={{ marginTop: 22 }}>
          <Button data-lasso="modifier-confirm" kind="accent" full size="lg" disabled={!allRequiredMet} onClick={() => onConfirm(item, flatSelected, totalPrice)}>
            Add to bag · £{totalPrice.toFixed(2)}
          </Button>
        </div>
      </div>
    </BottomSheet>
  );
}

// ─── Image-first menu card (2-up grid) ──────────────────────────────
function MenuCardBig({ item, qty, onAdd, app }) {
  return (
    <div data-lasso="menu-item-template" data-item-id={item.id} style={{
      background: 'var(--bg-surface)', borderRadius: 18, overflow: 'hidden',
      border: '1.5px solid var(--soft-line)', display: 'flex', flexDirection: 'column',
    }}>
      <div style={{ position: 'relative' }}>
        {item.art
          ? <FoodArt dish={item.art} height={118} radius={0}/>
          : <FoodPh height={118} hue={item.hue} radius={0} glyph={item.glyph}/>}
        {item.popular && <div data-field="popular-badge" style={{ position: 'absolute', top: 8, left: 8 }}><Pill bg="var(--dark-chocolate)" fg="var(--brand-orange)" style={{ fontSize: 9, padding: '3px 7px' }}>★ Popular</Pill></div>}
        {item.new && <div data-field="new-badge" style={{ position: 'absolute', top: 8, left: 8 }}><Pill bg="var(--brand-orange)" fg="#fff" style={{ fontSize: 9, padding: '3px 7px' }}>NEW</Pill></div>}
        <div style={{ position: 'absolute', top: 8, right: 8 }}><FavButton itemId={item.id} app={app} size={28} overlay/></div>
        {item.diet?.includes('v') && <div data-field="vegan-badge" style={{ position: 'absolute', bottom: 8, left: 8 }}><Pill bg="rgba(255,255,255,0.9)" fg="var(--live-green)" style={{ padding: '2px 7px', fontSize: 9, boxShadow: '0 2px 8px rgba(58,38,24,0.22)' }}><Ico.leaf c="var(--live-green)" s={10}/>Vegan</Pill></div>}
      </div>
      <div style={{ padding: '10px 11px 12px', display: 'flex', flexDirection: 'column', gap: 4, flex: 1 }}>
        <div data-field="item-name" style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13.5, lineHeight: 1.2, color: 'var(--fg-primary)' }}>{item.name}</div>
        <div data-field="item-description" style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)', lineHeight: 1.35, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{item.desc}</div>
        <div style={{ marginTop: 'auto', paddingTop: 6, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <div data-field="item-price" style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 14, color: 'var(--fg-primary)' }}>£{item.price.toFixed(2)}</div>
            {item.kcal > 0 && <div data-field="item-kcal" style={{ fontFamily: 'var(--font-body)', fontSize: 10.5, color: 'var(--warm-stone)' }}>{item.kcal} kcal</div>}
          </div>
          <button onClick={onAdd} style={{
            background: 'var(--brand-orange)', color: '#fff', border: 'none', width: 34, height: 34, borderRadius: 11, cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: 'var(--shadow-orange)', position: 'relative',
          }}>
            <Ico.plus c="#fff" s={18}/>
            {qty > 0 && <span style={{ position: 'absolute', top: -5, right: -5, minWidth: 16, height: 16, borderRadius: 8, padding: '0 4px', background: 'var(--dark-chocolate)', color: '#fff', border: '2px solid var(--bg-surface)', fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 9, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{qty}</span>}
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Menu filter slider ─────────────────────────────────────────────
function MenuFilterSlider({ active, onChange }) {
  const filters = [
    { id: 'all', label: 'All' },
    { id: 'popular', label: '★ Popular' },
    { id: 'new', label: 'New' },
    { id: 'veg', label: 'Vegan' },
    { id: 'gf', label: 'Gluten-free' },
    { id: 'under10', label: 'Under £10' },
  ];
  return (
    <div>
      <div style={{ padding: '0 20px 8px', display: 'flex', alignItems: 'center', gap: 8 }}>
        <Ico.filter c="var(--horse-brown)" s={15}/>
        <Eyebrow>Filter the menu</Eyebrow>
      </div>
      <div data-lasso="menu-filter-slider" style={{ display: 'flex', gap: 8, overflowX: 'auto', padding: '0 20px 6px', scrollbarWidth: 'none', scrollSnapType: 'x proximity', scrollPaddingInline: 20 }}>
        <style>{`[data-lasso="menu-filter-slider"]::-webkit-scrollbar{display:none}`}</style>
        {filters.map(f => {
          const on = active === f.id;
          return (
            <button key={f.id} onClick={() => onChange(f.id)} style={{
              padding: '8px 14px', borderRadius: 14, flexShrink: 0, cursor: 'pointer',
              background: on ? 'var(--brand-orange)' : 'var(--bg-surface)',
              color: on ? '#fff' : 'var(--fg-primary)',
              border: '1.5px solid ' + (on ? 'var(--brand-orange)' : 'var(--soft-line)'),
              fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 12, letterSpacing: '0.04em', whiteSpace: 'nowrap',
              scrollSnapAlign: 'start',
            }}>{f.label}</button>
          );
        })}
      </div>
    </div>
  );
}

// ─── Upsell row — horizontal quick-add scroller ─────────────────────
function getAddOns(menu) {
  const out = [];
  (menu || []).forEach(sec => {
    if (/side|sip|shake|drink|sweet|pastr/i.test(sec.name)) sec.items.forEach(it => out.push(it));
  });
  if (out.length < 3) (menu || []).forEach(sec => sec.items.forEach(it => { if (it.price < 8 && !out.includes(it)) out.push(it); }));
  return out.slice(0, 6);
}

function UpsellRow({ title, subtitle, items, onAdd, px = 20 }) {
  if (!items || items.length === 0) return null;
  return (
    <div data-lasso="upsell-row">
      <div style={{ padding: `2px ${px}px 10px`, display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
          <Ico.plus c="var(--brand-orange)" s={15}/>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 15, color: 'var(--fg-primary)' }}>{title}</span>
        </div>
        {subtitle && <span style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)' }}>{subtitle}</span>}
      </div>
      <div data-lasso="upsell-scroller" style={{ display: 'flex', gap: 10, overflowX: 'auto', padding: `0 ${px}px 4px`, scrollbarWidth: 'none', scrollSnapType: 'x mandatory', scrollPaddingInline: px }}>
        <style>{`[data-lasso="upsell-scroller"]::-webkit-scrollbar{display:none}`}</style>
        {items.map(it => (
          <div key={it.id} style={{ width: 120, flexShrink: 0, background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 16, overflow: 'hidden', scrollSnapAlign: 'start', scrollSnapStop: 'always' }}>
            <div style={{ position: 'relative' }}>
              {it.art ? <FoodArt dish={it.art} height={72} radius={0}/> : <FoodPh height={72} hue={it.hue} radius={0} glyph={it.glyph}/>}
              <button onClick={() => onAdd(it)} style={{ position: 'absolute', bottom: 6, right: 6, width: 28, height: 28, borderRadius: 9, background: 'var(--brand-orange)', border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', boxShadow: 'var(--shadow-orange)' }}>
                <Ico.plus c="#fff" s={16}/>
              </button>
            </div>
            <div style={{ padding: '8px 9px 10px' }}>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, color: 'var(--fg-primary)', lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{it.name}</div>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 12, color: 'var(--horse-brown)', marginTop: 3 }}>£{it.price.toFixed(2)}</div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─── Quick action tile (group order / allergy guide) ────────────────
function ActionTile({ icon, title, sub, onClick }) {
  return (
    <button onClick={onClick} style={{
      flex: 1, display: 'flex', alignItems: 'center', gap: 10, padding: '12px 13px',
      background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 16, cursor: 'pointer', textAlign: 'left',
    }}>
      <div style={{ width: 36, height: 36, borderRadius: 11, background: 'var(--bg-warm)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{icon}</div>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13, color: 'var(--fg-primary)' }}>{title}</div>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--warm-stone)' }}>{sub}</div>
      </div>
    </button>
  );
}

// ─── Lasso perks strip ──────────────────────────────────────────────
function PerksBar() {
  const perks = [
    { icon: <Ico.refresh c="var(--live-green)" s={15}/>, label: 'No surge pricing' },
    { icon: <Ico.ride c="var(--brand-orange)" s={15}/>, label: 'Free delivery £20+' },
    { icon: <Ico.wallet c="var(--horse-brown)" s={15}/>, label: 'Price-locked menu' },
  ];
  return (
    <div data-lasso="perks-bar" style={{ display: 'flex', gap: 8, overflowX: 'auto', marginTop: 12, scrollbarWidth: 'none', scrollSnapType: 'x proximity' }}>
      <style>{`[data-lasso="perks-bar"]::-webkit-scrollbar{display:none}`}</style>
      {perks.map((p, i) => (
        <div key={i} style={{ flexShrink: 0, display: 'flex', alignItems: 'center', gap: 7, padding: '8px 12px', background: 'var(--bg-warm)', borderRadius: 12, border: '1.5px solid var(--soft-line)', scrollSnapAlign: 'start' }}>
          {p.icon}
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 11.5, color: 'var(--horse-brown)', whiteSpace: 'nowrap' }}>{p.label}</span>
        </div>
      ))}
    </div>
  );
}

// ─── Group order drawer (working) ───────────────────────────────────
function GroupOrderSheet({ open, onClose, app, restaurant }) {
  const [members, setMembers] = React.useState([
    { id: 'me', name: 'You (host)', initials: 'JM', you: true, items: 0, subtotal: 0 },
  ]);
  const [paymode, setPaymode] = React.useState('host');
  const pool = ['Maya', 'Cole', 'Dev', 'Priya', 'Wes'];
  const addMember = () => {
    setMembers(m => {
      const used = m.map(x => x.name);
      const next = pool.find(n => !used.includes(n));
      if (!next) { app.toast('Whole posse is here', 'info'); return m; }
      const items = 1 + Math.floor(Math.random() * 2);
      return [...m, { id: next, name: next, initials: next.slice(0, 2), items, subtotal: +(items * (8 + Math.random() * 6)).toFixed(2) }];
    });
  };
  const removeMember = (id) => setMembers(m => m.filter(x => x.id !== id));
  const total = members.reduce((s, x) => s + x.subtotal, 0);
  const link = `lasso.app/g/${restaurant.slug}-7K2`;
  const copy = () => { try { navigator.clipboard && navigator.clipboard.writeText(link); } catch (e) {} app.toast('Invite link copied', 'success'); };
  return (
    <BottomSheet open={open} onClose={onClose} title="Group order">
      <div style={{ padding: '0 20px 28px', display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)', lineHeight: 1.45 }}>
          Rope in the crew at <strong style={{ fontFamily: 'var(--font-display)', fontWeight: 800, color: 'var(--fg-primary)' }}>{restaurant.name}</strong>. Everyone adds their own picks to one bag.
        </div>
        {/* Invite link */}
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', background: 'var(--bg-warm)', border: '1.5px dashed var(--soft-line)', borderRadius: 14, padding: '10px 12px' }}>
          <Ico.ticket c="var(--brand-orange)" s={18}/>
          <span style={{ flex: 1, fontFamily: 'var(--font-mono, monospace)', fontSize: 12.5, color: 'var(--horse-brown)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{link}</span>
          <button onClick={copy} style={{ background: 'var(--dark-chocolate)', color: 'var(--dust-cream)', border: 'none', padding: '8px 14px', borderRadius: 10, fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, cursor: 'pointer' }}>Copy</button>
        </div>
        {/* Members */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {members.map(mem => (
            <div key={mem.id} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '10px 12px', background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 14 }}>
              <div style={{ width: 38, height: 38, borderRadius: '50%', background: mem.you ? 'linear-gradient(135deg,#F28C1B,#D85A14)' : 'var(--bg-warm)', color: mem.you ? '#fff' : 'var(--horse-brown)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 13, textTransform: 'uppercase', flexShrink: 0 }}>{mem.initials}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13.5, color: 'var(--fg-primary)' }}>{mem.name}</div>
                <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)' }}>{mem.items > 0 ? `${mem.items} item${mem.items > 1 ? 's' : ''} · £${mem.subtotal.toFixed(2)}` : 'Hasn’t ordered yet'}</div>
              </div>
              {!mem.you && <button onClick={() => removeMember(mem.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 6 }}><Ico.x c="var(--warm-stone)" s={16}/></button>}
            </div>
          ))}
          <button onClick={addMember} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, padding: 12, borderRadius: 14, border: '1.5px dashed var(--horse-brown)', background: 'transparent', cursor: 'pointer', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13, color: 'var(--horse-brown)' }}>
            <Ico.plus c="var(--horse-brown)" s={16}/> Invite someone
          </button>
        </div>
        {/* Pay mode */}
        <div style={{ display: 'flex', gap: 4, padding: 4, background: 'var(--bg-warm)', borderRadius: 14, border: '1.5px solid var(--soft-line)' }}>
          {[{ id: 'host', label: 'I’ll pay' }, { id: 'split', label: 'Everyone pays own' }].map(o => {
            const on = paymode === o.id;
            return <button key={o.id} onClick={() => setPaymode(o.id)} style={{ flex: 1, padding: 10, borderRadius: 10, border: 'none', cursor: 'pointer', background: on ? 'var(--bg-surface)' : 'transparent', boxShadow: on ? 'var(--shadow-sm)' : 'none', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12.5, color: on ? 'var(--fg-primary)' : 'var(--warm-stone)' }}>{o.label}</button>;
          })}
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
          <span style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)' }}>{members.length} in the group</span>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 18, color: 'var(--fg-primary)' }}>£{total.toFixed(2)}</span>
        </div>
        <Button kind="accent" full size="lg" onClick={() => { onClose(); app.toast('Group order started · invite sent', 'success'); }}>Start group order</Button>
      </div>
    </BottomSheet>
  );
}

// ─── Allergy guide drawer ───────────────────────────────────────────
const dietBtnStyle = { flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, padding: 12, borderRadius: 14, border: '1.5px solid var(--soft-line)', background: 'var(--bg-surface)', cursor: 'pointer', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12.5, color: 'var(--fg-primary)' };
function AllergyGuideSheet({ open, onClose, app, menu, onFilter }) {
  const allergens = [
    { id: 'gluten', label: 'Gluten', re: /bun|tortilla|brioche|sourdough|croissant|knot|pain|mac|bread|batter|noodle|pizza|wrap|sandwich|fries/i },
    { id: 'dairy', label: 'Dairy', re: /cheese|cream|milk|shake|butter|mac|aioli|horchata/i },
    { id: 'egg', label: 'Egg', re: /egg|aioli|brioche|batter/i },
    { id: 'soy', label: 'Soy', re: /soy|tofu|teriyaki/i },
    { id: 'nuts', label: 'Tree nuts', re: /almond|pecan|walnut|\bnut/i },
    { id: 'sesame', label: 'Sesame', re: /sesame|tahini/i },
  ];
  const all = (menu || []).flatMap(s => s.items);
  const count = (a) => all.filter(it => a.re.test(it.name + ' ' + (it.desc || ''))).length;
  return (
    <BottomSheet open={open} onClose={onClose} title="Allergy guide">
      <div style={{ padding: '0 20px 28px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)', lineHeight: 1.45 }}>
          Every kitchen on Lasso flags the major allergens. Tap a quick filter to see only dishes that suit you, or note the kitchen at checkout.
        </div>
        {/* Quick diet filters */}
        <div>
          <Eyebrow style={{ marginBottom: 8 }}>Quick filters</Eyebrow>
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={() => { onFilter('veg'); onClose(); app.toast('Showing vegan dishes', 'info'); }} style={dietBtnStyle}>
              <Ico.leaf c="var(--live-green)" s={15}/> Vegan only
            </button>
            <button onClick={() => { onFilter('gf'); onClose(); app.toast('Showing gluten-free dishes', 'info'); }} style={dietBtnStyle}>
              <Ico.check c="var(--horse-brown)" s={15}/> Gluten-free
            </button>
          </div>
        </div>
        {/* Allergen table */}
        <div>
          <Eyebrow style={{ marginBottom: 8 }}>On this menu</Eyebrow>
          <div style={{ background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 16, overflow: 'hidden' }}>
            {allergens.map((a, i) => (
              <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', borderTop: i > 0 ? '1px solid var(--soft-line)' : 'none' }}>
                <div style={{ width: 30, height: 30, borderRadius: 9, background: 'var(--bg-warm)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  <Ico.leaf c="var(--horse-brown)" s={15}/>
                </div>
                <div style={{ flex: 1, fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13.5, color: 'var(--fg-primary)' }}>{a.label}</div>
                <Pill bg="var(--bg-warm)" fg="var(--horse-brown)" style={{ fontSize: 11 }}>{count(a)} dishes</Pill>
              </div>
            ))}
          </div>
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start', padding: '12px 14px', background: 'rgba(46,139,78,0.08)', borderRadius: 14 }}>
          <Ico.check c="var(--live-green)" s={18}/>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--horse-brown)', lineHeight: 1.4 }}>
            Severe allergy? Add a note for the kitchen at checkout and we’ll confirm before they cook.
          </div>
        </div>
      </div>
    </BottomSheet>
  );
}

Object.assign(window, { RestaurantScreen, CartContents, ModifierModal, MenuCardBig, MenuFilterSlider, UpsellRow, GroupOrderSheet, AllergyGuideSheet, ActionTile, PerksBar, CartPromo,
  // shared with desktop
  FavButton, MenuItemImage, MenuItemList, getAddOns, Stat });
