// screens-tracking.jsx — live order tracking (map-led + status-led variants)

const STATUS_PIPELINE = [
  { key: 'payment_pending',     label: 'Payment pending',     short: 'Payment',   step: 0 },
  { key: 'payment_confirmed',   label: 'Order confirmed',     short: 'Confirmed',   step: 1 },
  { key: 'sent_to_kitchen',     label: 'Sent to kitchen',     short: 'Sent',        step: 2 },
  { key: 'preparing',           label: 'Being prepared',      short: 'Cooking',     step: 3 },
  { key: 'ready_for_collection',label: 'Ready for pickup',    short: 'Ready',       step: 4 },
  { key: 'agent_assigned',      label: 'Rider assigned',      short: 'Assigned',    step: 5 },
  { key: 'agent_collected',     label: 'Order collected',     short: 'Picked up',   step: 6 },
  { key: 'en_route',            label: 'On the way',          short: 'En route',    step: 7 },
  { key: 'delivered',           label: 'Delivered',           short: 'Delivered',   step: 8 },
];

const STATUS_TO_BADGE = {
  payment_pending: 'amber', payment_confirmed: 'gold', sent_to_kitchen: 'blue',
  preparing: 'blue', ready_for_collection: 'gold', agent_assigned: 'orange',
  agent_collected: 'orange', en_route: 'orange', delivered: 'live', cancelled: 'red', refunded: 'gray',
};

const TRACKING_EVENTS = [
  { status: 'payment_pending', message: 'Payment confirmation required', time: 'Just now' },
  { status: 'payment_confirmed', message: 'Payment confirmed', time: 'Just now' },
  { status: 'sent_to_kitchen', message: 'Order sent to the kitchen', time: '1 min ago' },
  { status: 'preparing', message: 'Chef started prep · brisket on the smoke', time: '3 min ago' },
  { status: 'ready_for_collection', message: 'Order is bagged and ready', time: '12 min ago' },
  { status: 'agent_assigned', message: 'Diego accepted the ride', time: '14 min ago' },
  { status: 'agent_collected', message: 'Diego picked up your order', time: '16 min ago' },
  { status: 'en_route', message: 'Diego is 2 blocks away', time: '22 min ago' },
  { status: 'delivered', message: 'Order delivered. Hope you enjoyed it!', time: '27 min ago' },
];

// ─── Milestone theatre — brand-voice copy per step ──────────────
function theatreFor(step, r) {
  const name = r ? r.name : 'the kitchen';
  return {
    1: { line: "Order's roped.", sub: `Payment cleared. ${name} gets it next.` },
    2: { line: 'The kitchen heard the bell.', sub: `${name} has your ticket on the rail.` },
    3: { line: "Fire's up. Smoke's rolling.", sub: 'Your order is on the heat right now.' },
    4: { line: 'Boxed and waiting at the pass.', sub: 'Packed hot. A rider is being wrangled.' },
    5: { line: "Diego's saddling up.", sub: 'Your rider is heading to the kitchen.', quote: 'On my way to grab it, partner.' },
    6: { line: "He's got it. Hold tight.", sub: 'Order in the crate, wheels rolling.', quote: 'Smells incredible back here.' },
    7: { line: 'Dust on the horizon.', sub: 'Diego is closing in on Avebury Boulevard.', quote: 'Two corners out. Get the table set.' },
    8: { line: 'Much obliged. Dig in.', sub: 'Delivered hot. The trail ends at your door.' },
  }[step] || { line: 'On the trail.', sub: 'Your order is moving.' };
}

// ─── Delivered confetti burst ───────────────────────────────
function DeliveredConfetti() {
  return (
    <div aria-hidden="true" style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 0, pointerEvents: 'none', zIndex: 40 }}>
      <style>{`@keyframes lassoTrackConfetti { 0% { transform: translateY(-12px) rotate(0deg); opacity: 1; } 100% { transform: translateY(420px) rotate(560deg); opacity: 0; } }`}</style>
      {['#D85A14','#F28C1B','#F4E1C1','#5B240A','#2E8B4E','#D85A14','#F28C1B','#F4E1C1','#F28C1B','#D85A14','#F4E1C1','#2E8B4E'].map((c, i) => (
        <span key={i} style={{
          position: 'absolute', top: -10, left: `${5 + i * 8}%`,
          width: i % 3 === 0 ? 10 : 7, height: i % 2 === 0 ? 12 : 8,
          background: c, borderRadius: i % 3 === 0 ? '50%' : 2,
          animation: `lassoTrackConfetti ${1.5 + (i % 5) * 0.32}s ${0.05 + (i % 4) * 0.16}s cubic-bezier(.2,.6,.4,1) forwards`,
          opacity: 0,
        }}></span>
      ))}
    </div>
  );
}

function TrackingScreen({ app }) {
  const tweakStatus = app.tweaks.trackingStatus;
  const [autoStep, setAutoStep] = React.useState(1);
  const [reviewSubmitted, setReviewSubmitted] = React.useState(false);
  const [rating, setRating] = React.useState(0);
  const [activeSheet, setActiveSheet] = React.useState(null);
  const detailsOpen = activeSheet === 'details';
  const chatOpen = activeSheet === 'chat';
  const callOpen = activeSheet === 'call';
  const layout = app.tweaks.trackingLayout || 'map-led';

  // Auto-progress: only when tweakStatus is 'auto'
  React.useEffect(() => {
    if (tweakStatus && tweakStatus !== 'auto') return;
    const t = setInterval(() => setAutoStep(s => Math.min(s + 1, 8)), 3500);
    return () => clearInterval(t);
  }, [tweakStatus]);

  // Resolve current status
  const currentStep = React.useMemo(() => {
    if (tweakStatus && tweakStatus !== 'auto') {
      return STATUS_PIPELINE.find(s => s.key === tweakStatus)?.step ?? autoStep;
    }
    return autoStep;
  }, [tweakStatus, autoStep]);

  const currentStatus = STATUS_PIPELINE.find(s => s.step === currentStep) || STATUS_PIPELINE[0];
  const isDelivered = currentStatus.key === 'delivered';
  const isException = ['payment_pending', 'cancelled', 'refunded'].includes(tweakStatus);

  // Resolve order
  const order = app.activeOrder || {
    id: 'LSO-22141',
    restaurantId: 'rojo-smoke',
    items: [{ item_name: 'Brisket Tacos', quantity: 1 }, { item_name: 'Smoked Mac', quantity: 1 }, { item_name: 'House Lemonade', quantity: 1 }],
    total: 24.50,
    address: ADDRESSES[0],
  };
  const r = RESTAURANT_LOOKUP[order.restaurantId];

  // ETA calculation
  const etaMin = isDelivered ? 0 : Math.max(1, 25 - currentStep * 3);

  // Events to show — only ones at or before current step
  const visibleEvents = TRACKING_EVENTS
    .filter(e => (STATUS_PIPELINE.find(s => s.key === e.status)?.step || 0) <= currentStep)
    .reverse();

  if (isException) {
    return <TrackingExceptionScreen app={app} status={tweakStatus} order={order}/>;
  }

  const closeSheet = () => setActiveSheet(null);
  const sheetProps = {
    openDetails: () => setActiveSheet('details'),
    openChat: () => setActiveSheet('chat'),
    openCall: () => setActiveSheet('call'),
  };
  const sheets = (
    <>
      <OrderDetailsSheet open={detailsOpen} onClose={closeSheet} order={order} r={r} app={app} etaMin={etaMin} onHelp={() => setActiveSheet('chat')}/>
      <RiderChatSheet open={chatOpen} onClose={closeSheet} order={order} r={r} app={app} etaMin={etaMin} onCall={() => setActiveSheet('call')}/>
      <CallSheet open={callOpen} onClose={closeSheet} app={app}/>
    </>
  );

  if (layout === 'status-led') {
    return <>
      <TrackingStatusLed app={app} {...sheetProps} currentStatus={currentStatus} currentStep={currentStep} etaMin={etaMin} order={order} r={r} visibleEvents={visibleEvents} isDelivered={isDelivered} rating={rating} setRating={setRating} reviewSubmitted={reviewSubmitted} setReviewSubmitted={setReviewSubmitted}/>
      {sheets}
    </>;
  }

  return <>
    <TrackingMapLed app={app} {...sheetProps} currentStatus={currentStatus} currentStep={currentStep} etaMin={etaMin} order={order} r={r} visibleEvents={visibleEvents} isDelivered={isDelivered} rating={rating} setRating={setRating} reviewSubmitted={reviewSubmitted} setReviewSubmitted={setReviewSubmitted}/>
    {sheets}
  </>;
}

// ─── Map-led layout ────────────────────────────────────────────────
function TrackingMapLed({ app, openDetails, openChat, openCall, currentStatus, currentStep, etaMin, order, r, visibleEvents, isDelivered, rating, setRating, reviewSubmitted, setReviewSubmitted }) {
  return (
    <Screen scroll={false}>
      <div data-lasso="order-id" data-order-id={order.id} style={{ flex: 1, position: 'relative', overflow: 'hidden' }}>

        {/* Map area */}
        <div data-lasso="tracking-map" style={{ position: 'absolute', top: 0, left: 0, right: 0, height: '52%', overflow: 'hidden' }}>
          {window.L
            ? <LeafletTrackingMap progress={currentStep} riderHidden={currentStep < 6} delivered={isDelivered} etaMin={etaMin}/>
            : <MapIllustration progress={currentStep} riderHidden={currentStep < 6} delivered={isDelivered}/>}
          {/* Floating controls */}
          <button data-lasso="tracking-return-button" aria-label="Return to orders" onClick={() => app.back()} style={floatTrackBtn(16, undefined)}>
            <Ico.chevL c="#fff" s={20}/>
          </button>
          <div style={{
            position: 'absolute', top: 'max(18px, calc(env(safe-area-inset-top, 0px) + 14px))', right: 16, padding: '8px 14px', borderRadius: 999,
            background: 'rgba(255,255,255,0.94)', display: 'flex', alignItems: 'center', gap: 8,
            boxShadow: 'var(--shadow-md)', zIndex: 1000,
          }}>
            <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--brand-orange)', animation: 'lasso-pulse 1.4s infinite' }}/>
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, color: 'var(--fg-primary)' }}>Live</span>
          </div>
        </div>

        {/* Bottom sheet */}
        <div style={{
          position: 'absolute', top: '48%', left: 0, right: 0, bottom: 0,
          background: 'var(--bg-app)', borderRadius: '28px 28px 0 0',
          boxShadow: '0 -20px 40px -10px rgba(0,0,0,0.12)',
          display: 'flex', flexDirection: 'column', overflowY: 'auto',
          paddingBottom: 'max(104px, calc(env(safe-area-inset-bottom, 0px) + 104px))',
        }}>
          <div style={{ padding: '12px 0 4px', display: 'flex', justifyContent: 'center' }}>
            <div style={{ width: 44, height: 4, borderRadius: 2, background: 'var(--soft-line)' }}/>
          </div>

          <div data-lasso="tracking-sheet-content" style={{ padding: '16px 20px 28px', display: 'flex', flexDirection: 'column', gap: 18, position: 'relative' }}>
            {isDelivered && <DeliveredConfetti/>}
            {/* Hero status — milestone theatre */}
            {(() => { const th = theatreFor(currentStep, r); return (
            <div key={currentStep} style={{ animation: 'lasso-slide-up 380ms var(--ease-out)' }}>
              <Eyebrow color="var(--brand-orange)">{currentStatus.label}</Eyebrow>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 30, lineHeight: 1.02, letterSpacing: '-0.01em', marginTop: 6, color: 'var(--fg-primary)', textWrap: 'balance' }}>
                {th.line}
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 8, flexWrap: 'wrap' }}>
                <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--warm-stone)' }}>{th.sub}</div>
              </div>
              {!isDelivered && (
                <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, marginTop: 12, padding: '8px 15px', borderRadius: 999, background: 'var(--dark-chocolate)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--brand-orange)', animation: 'lasso-pulse 1.4s infinite' }}></span>
                  <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 13.5, color: 'var(--dust-cream)' }}><span data-field="eta">{etaMin}</span> min out</span>
                </div>
              )}
            </div>
            ); })()}

            {/* Compact progress */}
            <CompactProgress currentStep={currentStep}/>

            {/* Rider card — only when assigned */}
            {currentStep >= 5 && !isDelivered && <RiderCard onMsg={openChat} onCall={openCall} quote={theatreFor(currentStep, r).quote}/>}

            {/* Order summary line */}
            <div style={{
              background: 'var(--bg-surface)', borderRadius: 16, padding: 14,
              border: '1.5px solid var(--soft-line)', display: 'flex', alignItems: 'center', gap: 12,
            }}>
              <div style={{ width: 40, height: 40, borderRadius: 10, overflow: 'hidden' }}>
                <FoodPh height={40} hue={r.hue} radius={10}/>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13.5, color: 'var(--fg-primary)' }}>
                  From <span data-field="restaurant-name">{r.name}</span>
                </div>
                <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)' }}>
                  {order.items.length} items · <span data-field="order-total">£{order.total.toFixed(2)}</span>
                </div>
              </div>
              <button onClick={openDetails} style={{ background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, color: 'var(--brand-orange)' }}>Details</button>
            </div>

            {/* Timeline */}
            <Timeline events={visibleEvents}/>

            {/* Review prompt */}
            {isDelivered && !reviewSubmitted && (
              <ReviewPrompt r={r} rating={rating} setRating={setRating} onSubmit={() => { setReviewSubmitted(true); app.toast('Review submitted', 'success'); }}/>
            )}
            {isDelivered && reviewSubmitted && (
              <div style={{ padding: 16, background: 'rgba(46,139,78,0.1)', borderRadius: 16, display: 'flex', alignItems: 'center', gap: 12 }}>
                <Ico.check c="var(--live-green)" s={20}/>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13, color: 'var(--live-green)' }}>Thanks for the review.</div>
              </div>
            )}
          </div>
        </div>
      </div>
    </Screen>
  );
}

// ─── Status-led layout (no big map; full status focus) ─────────────
// ─── Fullscreen driver map overlay ────────────────────────────
function FullMapOverlay({ open, onClose, currentStep, isDelivered, etaMin }) {
  if (!open) return null;
  const layer = document.getElementById('lasso-sheet-layer');
  const content = (
    <div style={{ position: 'absolute', inset: 0, zIndex: 380, background: '#EFE5D5', animation: 'lasso-fade-in 220ms var(--ease-out)', pointerEvents: 'auto' }}>
      <div style={{ position: 'absolute', inset: 0 }}>
        {window.L
          ? <LeafletTrackingMap progress={currentStep} riderHidden={currentStep < 6} delivered={isDelivered} etaMin={etaMin}/>
          : <MapIllustration progress={currentStep} riderHidden={currentStep < 6} delivered={isDelivered}/>}
      </div>
      <button onClick={onClose} aria-label="Close map" style={{
        position: 'absolute', top: 16, left: 16, width: 42, height: 42, borderRadius: 15, zIndex: 5,
        border: 'none', background: '#1B120D', display: 'flex', alignItems: 'center', justifyContent: 'center',
        cursor: 'pointer', boxShadow: 'var(--shadow-md)',
      }}><Ico.x c="#F5EFE7" s={18}/></button>
      {!isDelivered && (
        <div style={{ position: 'absolute', bottom: 22, left: '50%', transform: 'translateX(-50%)', zIndex: 5, display: 'inline-flex', alignItems: 'center', gap: 9, padding: '11px 20px', borderRadius: 999, background: '#1B120D', boxShadow: 'var(--shadow-lg)' }}>
          <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--brand-orange)', animation: 'lasso-pulse 1.4s infinite' }}></span>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 14, color: '#F5EFE7' }}>Diego · {etaMin} min out</span>
        </div>
      )}
    </div>
  );
  return layer ? ReactDOM.createPortal(content, layer) : content;
}

function TrackingStatusLed({ app, openDetails, openChat, openCall, currentStatus, currentStep, etaMin, order, r, visibleEvents, isDelivered, rating, setRating, reviewSubmitted, setReviewSubmitted }) {
  const [mapOpen, setMapOpen] = React.useState(false);
  return (
    <Screen scroll={false}>
      <div data-lasso="order-id" data-order-id={order.id} style={{ flex: 1, overflow: 'auto' }}>
        {/* Top bar */}
        <div style={{ padding: '12px 20px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <button onClick={() => app.back()} style={{
            width: 40, height: 40, borderRadius: 14, border: '1.5px solid var(--soft-line)',
            background: 'var(--bg-surface)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
          }}><Ico.chevL c="var(--fg-primary)" s={20}/></button>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 17 }}>Order #{order.id}</div>
          <div style={{ width: 40 }}/>
        </div>

        {/* Big status hero — milestone theatre */}
        <div style={{ padding: '12px 20px 16px', position: 'relative' }}>
          {isDelivered && <DeliveredConfetti/>}
          {(() => { const th = theatreFor(currentStep, r); return (
          <div style={{
            background: 'var(--dark-chocolate)', borderRadius: 28, padding: 24,
            color: 'var(--dust-cream)', position: 'relative', overflow: 'hidden',
          }}>
            <div style={{ position: 'absolute', right: -10, bottom: -20, opacity: 0.4 }}>
              <Bull size={120}/>
            </div>
            <div key={currentStep} style={{ position: 'relative', animation: 'lasso-slide-up 380ms var(--ease-out)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                <StatusPill kind={STATUS_TO_BADGE[currentStatus.key]}>{currentStatus.short}</StatusPill>
                {!isDelivered && (
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 12.5, color: 'var(--sun-orange)' }}>
                    <span style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--sun-orange)', animation: 'lasso-pulse 1.4s infinite' }}></span>
                    {etaMin} min out
                  </span>
                )}
              </div>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 32, lineHeight: 1.0, letterSpacing: '-0.01em', marginTop: 14, textWrap: 'balance' }}>
                {th.line}
              </div>
              <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: '#C9B7AA', marginTop: 8, maxWidth: '78%' }}>
                {th.sub}
              </div>
              <button onClick={() => setMapOpen(true)} style={{
                marginTop: 16, display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer',
                background: 'rgba(245,239,231,0.1)', border: '1px solid rgba(245,239,231,0.2)', borderRadius: 12,
                padding: '10px 16px', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12.5, color: 'var(--dust-cream)',
              }}><Ico.pin c="var(--sun-orange)" s={14}/> View the ride on the map</button>
            </div>
          </div>
          ); })()}
        </div>

        {/* Stepper */}
        <div style={{ padding: '0 20px 20px' }}>
          <VerticalProgress currentStep={currentStep}/>
        </div>

        {/* Rider — if assigned */}
        {currentStep >= 5 && !isDelivered && (
          <div style={{ padding: '0 20px 16px' }}><RiderCard onMsg={openChat} onCall={openCall} quote={theatreFor(currentStep, r).quote}/></div>
        )}

        {/* Order summary */}
        <div style={{ padding: '0 20px 16px' }}>
          <div onClick={openDetails} role="button" style={{
            background: 'var(--bg-surface)', borderRadius: 16, padding: 16, cursor: 'pointer',
            border: '1.5px solid var(--soft-line)', display: 'flex', flexDirection: 'column', gap: 10,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{ width: 40, height: 40, borderRadius: 10, overflow: 'hidden' }}>
                <FoodPh height={40} hue={r.hue} radius={10}/>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--fg-primary)' }}>{r.name}</div>
                <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)' }}>{order.items.length} items · £{order.total.toFixed(2)}</div>
              </div>
            </div>
            <div style={{ height: 1, background: 'var(--soft-line)' }}/>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Ico.pin c="var(--horse-brown)" s={14}/>
              <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--warm-stone)' }}>{order.address.line1}, {order.address.city}</div>
            </div>
          </div>
        </div>

        {/* Timeline */}
        <div style={{ padding: '0 20px 30px' }}>
          <Eyebrow style={{ marginBottom: 10 }}>Activity</Eyebrow>
          <Timeline events={visibleEvents}/>

          {isDelivered && !reviewSubmitted && (
            <div style={{ marginTop: 16 }}>
              <ReviewPrompt r={r} rating={rating} setRating={setRating} onSubmit={() => { setReviewSubmitted(true); app.toast('Review submitted', 'success'); }}/>
            </div>
          )}
        </div>
        <FullMapOverlay open={mapOpen} onClose={() => setMapOpen(false)} currentStep={currentStep} isDelivered={isDelivered} etaMin={etaMin}/>
      </div>
    </Screen>
  );
}

// ─── Exception screen (pending payment, cancelled, refunded) ───────
function TrackingExceptionScreen({ app, status, order }) {
  const conf = {
    payment_pending: { kind: 'amber', title: 'Payment pending', body: 'Your order is held until payment is confirmed.', cta: 'Refresh', tone: 'wait' },
    cancelled: { kind: 'red', title: 'Order cancelled', body: 'Your order was cancelled. Any charge will be reversed.', cta: 'Order again', tone: 'bad' },
    refunded: { kind: 'gray', title: 'Order refunded', body: 'A refund has been issued and will reach your card in 3–5 days.', cta: 'Back to home', tone: 'neutral' },
  }[status];

  return (
    <Screen>
      <div style={{ padding: '12px 20px' }}>
        <button onClick={() => app.back()} style={{
          width: 40, height: 40, borderRadius: 14, border: '1.5px solid var(--soft-line)',
          background: 'var(--bg-surface)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
        }}><Ico.chevL c="var(--fg-primary)" s={20}/></button>
      </div>
      <div style={{ padding: '20px 20px 40px', flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', gap: 16 }}>
        <div style={{
          width: 100, height: 100, borderRadius: '50%',
          background: conf.tone === 'bad' ? 'rgba(193,59,31,0.15)' : conf.tone === 'wait' ? 'rgba(242,140,27,0.15)' : 'rgba(124,103,91,0.15)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <Bull size={62}/>
        </div>
        <div>
          <StatusPill kind={conf.kind}>{status.replace('_', ' ')}</StatusPill>
        </div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 28, letterSpacing: '-0.01em', maxWidth: 260 }}>{conf.title}</div>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 14, color: 'var(--warm-stone)', maxWidth: 280, lineHeight: 1.5 }}>{conf.body}</div>
        <div style={{ marginTop: 12, fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--warm-stone)' }}>Order #{order.id}</div>
        <div style={{ width: '100%', maxWidth: 280, marginTop: 8 }}>
          <Button kind="primary" full onClick={() => app.nav('home')}>{conf.cta}</Button>
        </div>
      </div>
    </Screen>
  );
}

// ─── Compact horizontal progress ───────────────────────────────────
function CompactProgress({ currentStep }) {
  // Compress the 8-step pipeline into 5 visual steps
  const steps = [
    { label: 'Placed', step: 1 },
    { label: 'Cooking', step: 3 },
    { label: 'Picked up', step: 6 },
    { label: 'On the way', step: 7 },
    { label: 'Delivered', step: 8 },
  ];
  return (
    <div data-lasso="status-stepper" style={{ display: 'flex', alignItems: 'flex-start', gap: 0 }}>
      {steps.map((s, i) => {
        const done = currentStep > s.step;
        const cur = currentStep >= s.step && (i === steps.length - 1 || currentStep < steps[i+1].step);
        const isLast = i === steps.length - 1;
        return (
          <React.Fragment key={s.label}>
            <div data-step={STATUS_PIPELINE.find(p => p.step === s.step)?.key} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', minWidth: 56 }}>
              <div style={{
                width: 26, height: 26, borderRadius: '50%',
                background: done ? 'var(--brand-orange)' : (cur ? 'var(--dark-chocolate)' : 'var(--soft-line)'),
                color: done ? '#fff' : (cur ? 'var(--brand-orange)' : 'var(--warm-stone)'),
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 11,
                boxShadow: cur ? '0 0 0 4px rgba(216,90,20,0.18)' : 'none',
                transition: 'all 320ms var(--ease-out)',
              }}>{done ? <Ico.check c="#fff" s={13}/> : (i+1)}</div>
              <div style={{
                fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 8.5, letterSpacing: '0.06em',
                textTransform: 'uppercase', marginTop: 6, textAlign: 'center',
                color: (done||cur) ? 'var(--fg-primary)' : 'var(--warm-stone)',
              }}>{s.label}</div>
            </div>
            {!isLast && (
              <div style={{
                flex: 1, height: 3, background: 'var(--soft-line)',
                margin: '11.5px -2px 0', borderRadius: 2, position: 'relative',
                overflow: 'hidden',
              }}>
                <div style={{
                  position: 'absolute', top: 0, left: 0, bottom: 0,
                  background: 'var(--brand-orange)',
                  width: currentStep > s.step ? '100%' : currentStep === s.step ? '50%' : '0%',
                  transition: 'width 600ms var(--ease-out)',
                }}/>
              </div>
            )}
          </React.Fragment>
        );
      })}
    </div>
  );
}

// ─── Vertical progress (status-led layout) ─────────────────────────
function VerticalProgress({ currentStep }) {
  const steps = [
    { label: 'Order confirmed', step: 1, key: 'payment_confirmed' },
    { label: 'In the kitchen', step: 3, key: 'preparing' },
    { label: 'Picked up by rider', step: 6, key: 'agent_collected' },
    { label: 'On the way', step: 7, key: 'en_route' },
    { label: 'Delivered', step: 8, key: 'delivered' },
  ];
  return (
    <div data-lasso="status-stepper" style={{
      background: 'var(--bg-surface)', borderRadius: 18, padding: 18, border: '1.5px solid var(--soft-line)',
    }}>
      <Eyebrow style={{ marginBottom: 14 }}>Progress</Eyebrow>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
        {steps.map((s, i) => {
          const done = currentStep > s.step;
          const cur = currentStep >= s.step && (i === steps.length - 1 || currentStep < steps[i+1].step);
          const future = currentStep < s.step;
          return (
            <div data-step={s.key} key={s.key} style={{ display: 'flex', gap: 12, position: 'relative', paddingBottom: i < steps.length - 1 ? 18 : 0 }}>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                <div style={{
                  width: 28, height: 28, borderRadius: '50%', flexShrink: 0,
                  background: done ? 'var(--brand-orange)' : (cur ? 'var(--dark-chocolate)' : 'var(--soft-line)'),
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  boxShadow: cur ? '0 0 0 4px rgba(216,90,20,0.18)' : 'none',
                  transition: 'all 320ms var(--ease-out)',
                }}>
                  {done && <Ico.check c="#fff" s={14}/>}
                  {cur && <div style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--brand-orange)', animation: 'lasso-pulse 1.4s infinite' }}/>}
                </div>
                {i < steps.length - 1 && (
                  <div style={{ width: 2, flex: 1, marginTop: 4, background: done ? 'var(--brand-orange)' : 'var(--soft-line)', transition: 'background 320ms var(--ease-out)' }}/>
                )}
              </div>
              <div style={{ flex: 1, paddingTop: 4 }}>
                <div style={{
                  fontFamily: 'var(--font-display)', fontWeight: cur ? 900 : 700, fontSize: 14,
                  color: future ? 'var(--warm-stone)' : 'var(--fg-primary)',
                }}>{s.label}</div>
                {cur && <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--brand-orange)', marginTop: 2, fontWeight: 600 }}>Happening now</div>}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Timeline ──────────────────────────────────────────────────────
function Timeline({ events }) {
  return (
    <div data-lasso="tracking-timeline" style={{
      background: 'var(--bg-surface)', borderRadius: 16, padding: 14, border: '1.5px solid var(--soft-line)',
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      {events.map((e, i) => (
        <div key={i} data-lasso="tracking-event-template" data-status={e.status} style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
          <div style={{ width: 8, height: 8, borderRadius: '50%', background: i === 0 ? 'var(--brand-orange)' : 'var(--soft-line)', marginTop: 6, flexShrink: 0 }}/>
          <div style={{ flex: 1 }}>
            <div data-field="event-message" style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--fg-primary)', lineHeight: 1.4 }}>{e.message}</div>
            <div data-field="event-time" style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 10, color: 'var(--warm-stone)', textTransform: 'uppercase', letterSpacing: '0.06em', marginTop: 2 }}>{e.time}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ─── Rider card ────────────────────────────────────────────────────
function RiderCard({ onMsg, onCall, quote }) {
  return (
    <div style={{ background: 'var(--dark-chocolate)', borderRadius: 20, padding: 12, display: 'flex', alignItems: 'center', gap: 12 }}>
      <div style={{ width: 48, height: 48, borderRadius: '50%', background: 'linear-gradient(135deg,#F4E1C1,#F28C1B)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Bull size={28} variant="twotone"/>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--dust-cream)' }}>Diego Morales</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3 }}>
            <Ico.star c="var(--sun-orange)" s={10}/>
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 10.5, color: 'var(--desert-sand)' }}>4.9 · 312 rides</span>
          </span>
        </div>
        {quote
          ? <div key={quote} style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: '#C9B7AA', fontStyle: 'italic', marginTop: 3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', animation: 'lasso-slide-up 320ms var(--ease-out)' }}>“{quote}”</div>
          : <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: '#9F8979', marginTop: 3 }}>Your courier · trail veteran</div>}
      </div>
      <button onClick={onMsg} aria-label="Message about this order" style={{ width: 40, height: 40, borderRadius: '50%', border: 'none', background: 'var(--brand-orange)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', boxShadow: 'var(--shadow-orange)' }}>
        <Ico.msg c="#fff" s={18}/>
      </button>
      <button onClick={onCall} aria-label="Call" style={{ width: 40, height: 40, borderRadius: '50%', border: '1.5px solid #2A1C14', background: 'transparent', color: 'var(--dust-cream)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
        <Ico.phone c="var(--dust-cream)" s={18}/>
      </button>
    </div>
  );
}

// ─── Review prompt ─────────────────────────────────────────────────
function ReviewPrompt({ r, rating, setRating, onSubmit }) {
  const [comment, setComment] = React.useState('');
  const [tip, setTip] = React.useState(0);
  return (
    <div data-lasso="review-prompt" style={{
      background: 'var(--bg-surface)', borderRadius: 18, padding: 18, border: '1.5px solid var(--soft-line)',
      display: 'flex', flexDirection: 'column', gap: 12,
    }}>
      <div>
        <Eyebrow color="var(--brand-orange)">How was it?</Eyebrow>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 20, marginTop: 4 }}>Rate {r.name}</div>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--warm-stone)', marginTop: 2 }}>Your honest take helps the kitchen and rider.</div>
      </div>
      <div data-lasso="review-form" style={{ display: 'flex', gap: 8, justifyContent: 'center', padding: '6px 0' }}>
        {[1,2,3,4,5].map(n => (
          <button key={n} onClick={() => setRating(n)} style={{
            background: 'transparent', border: 'none', cursor: 'pointer', padding: 4,
            transform: rating >= n ? 'scale(1.1)' : 'scale(1)',
            transition: 'transform 180ms var(--ease-out)',
          }}>
            <Ico.star c={rating >= n ? 'var(--sun-orange)' : 'var(--soft-line)'} s={32}/>
          </button>
        ))}
      </div>
      <textarea
        placeholder="Optional · share a note"
        value={comment} onChange={e => setComment(e.target.value)}
        style={{
          width: '100%', minHeight: 70, padding: 12, borderRadius: 12,
          border: '1.5px solid var(--soft-line)', resize: 'none',
          fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--fg-primary)',
          outline: 'none', background: 'var(--bg-app)',
        }}/>
      {/* Last-chance rider tip — appears once they've rated, while the glow is warm */}
      {rating > 0 && (
        <div data-lasso="post-tip" style={{ background: 'var(--bg-warm)', border: '1.5px dashed rgba(216,90,20,0.4)', borderRadius: 14, padding: 12, animation: 'lasso-slide-up 260ms var(--ease-out)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
            <div style={{ width: 34, height: 34, borderRadius: '50%', background: 'linear-gradient(135deg,#F4E1C1,#F28C1B)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Bull size={20} variant="twotone"/>
            </div>
            <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--fg-secondary)', lineHeight: 1.4 }}>
              <strong style={{ fontFamily: 'var(--font-display)', fontWeight: 800, color: 'var(--fg-primary)' }}>Diego got it there.</strong> One last chance to hook him up — 100% goes to him.
            </div>
          </div>
          <div style={{ display: 'flex', gap: 7 }}>
            {[0, 1, 2, 3].map(t => {
              const on = t === tip;
              return (
                <button key={t} onClick={() => setTip(t)} style={{
                  flex: 1, padding: '10px 4px', borderRadius: 11, cursor: 'pointer',
                  background: on ? 'var(--dark-chocolate)' : 'var(--bg-surface)',
                  color: on ? 'var(--dust-cream)' : 'var(--fg-primary)',
                  border: '1.5px solid ' + (on ? 'var(--dark-chocolate)' : 'var(--soft-line)'),
                  fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 13,
                  transition: 'all 160ms var(--ease-out)', transform: on ? 'scale(1.05)' : 'scale(1)',
                }}>{t === 0 ? 'No tip' : `£${t}`}</button>
              );
            })}
          </div>
        </div>
      )}
      <Button kind="accent" full disabled={rating === 0} onClick={onSubmit}>
        {tip > 0 ? `Submit · +£${tip} tip for Diego` : 'Submit review'}
      </Button>
    </div>
  );
}

function floatTrackBtn(left, right) {
  return {
    position: 'absolute',
    top: 'max(18px, calc(env(safe-area-inset-top, 0px) + 14px))',
    left,
    right,
    width: 42,
    height: 42,
    borderRadius: '50%',
    background: 'var(--dark-chocolate)',
    border: '1px solid rgba(255,255,255,0.18)',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    cursor: 'pointer',
    boxShadow: '0 14px 30px rgba(27,18,13,0.34)',
    zIndex: 1000,
  };
}

// ─── Map illustration ──────────────────────────────────────────────
function MapIllustration({ progress = 1, riderHidden = false, delivered = false }) {
  // riderHidden when before pickup
  // Animate rider along route based on progress
  // Path goes from (60,460) → (200,380) → (320,150)
  // Step 1-5: rider at start (store)
  // Step 6: rider just picked up
  // Step 7: rider in transit (midway)
  // Step 8: at home

  let riderX = 60, riderY = 460;
  if (progress === 6) { riderX = 60; riderY = 460; }
  else if (progress === 7) { riderX = 200; riderY = 380; }
  else if (progress === 8) { riderX = 320; riderY = 150; }

  return (
    <svg viewBox="0 0 400 600" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <rect width="400" height="600" fill="#EFE5D5"/>

      {/* road outlines */}
      <g stroke="#E0D2BB" strokeLinecap="round" fill="none">
        <line x1="-20" y1="120" x2="420" y2="160" strokeWidth="24"/>
        <line x1="-20" y1="320" x2="420" y2="280" strokeWidth="30"/>
        <line x1="-20" y1="490" x2="420" y2="510" strokeWidth="20"/>
        <line x1="80"  y1="-20" x2="120"  y2="620" strokeWidth="22"/>
        <line x1="240" y1="-20" x2="270"  y2="620" strokeWidth="28"/>
        <line x1="360" y1="-20" x2="380"  y2="620" strokeWidth="16"/>
      </g>
      <g stroke="#fff" strokeLinecap="round">
        <line x1="-20" y1="120" x2="420" y2="160" strokeWidth="18"/>
        <line x1="-20" y1="320" x2="420" y2="280" strokeWidth="22"/>
        <line x1="-20" y1="490" x2="420" y2="510" strokeWidth="14"/>
        <line x1="80"  y1="-20" x2="120"  y2="620" strokeWidth="16"/>
        <line x1="240" y1="-20" x2="270"  y2="620" strokeWidth="22"/>
        <line x1="360" y1="-20" x2="380"  y2="620" strokeWidth="10"/>
      </g>

      {/* Buildings */}
      <g fill="#E2D4BD">
        <rect x="20" y="180" width="50" height="80" rx="4"/>
        <rect x="140" y="200" width="80" height="60" rx="4"/>
        <rect x="290" y="180" width="60" height="70" rx="4"/>
        <rect x="20" y="350" width="50" height="100" rx="4"/>
        <rect x="140" y="350" width="80" height="100" rx="4"/>
        <rect x="290" y="350" width="60" height="100" rx="4"/>
      </g>
      <g fill="#D6C5A9">
        <rect x="22" y="182" width="50" height="14" rx="3"/>
        <rect x="142" y="202" width="80" height="14" rx="3"/>
        <rect x="292" y="182" width="60" height="14" rx="3"/>
      </g>

      {/* Greenery */}
      <g fill="#A8B978" opacity="0.55">
        <circle cx="380" cy="80" r="22"/>
        <circle cx="395" cy="100" r="18"/>
        <circle cx="40" cy="550" r="20"/>
        <circle cx="150" cy="540" r="18"/>
      </g>

      {/* Route — completed portion */}
      <path
        d="M 60 460 Q 130 400 200 380 T 320 150"
        stroke="#D85A14" strokeWidth="5" strokeLinecap="round" fill="none"
        style={{
          strokeDasharray: 360,
          strokeDashoffset: delivered ? 0 : (progress >= 7 ? 100 : progress >= 6 ? 280 : 360),
          transition: 'stroke-dashoffset 800ms var(--ease-out)',
        }}/>
      {/* Future portion (dashed) */}
      <path d="M 60 460 Q 130 400 200 380 T 320 150" stroke="#D85A14" strokeWidth="5" strokeLinecap="round" strokeDasharray="3 8" fill="none" opacity="0.35"/>

      {/* Store pin */}
      <g transform="translate(60 460)">
        <circle cx="0" cy="0" r="14" fill="#1B120D"/>
        <circle cx="0" cy="0" r="6" fill="#F28C1B"/>
      </g>

      {/* Home pin */}
      <g transform="translate(320 150)">
        <path d="M0 -22 Q 12 -22 12 -10 Q 12 4 0 14 Q -12 4 -12 -10 Q -12 -22 0 -22 Z" fill="#1B120D"/>
        <circle cx="0" cy="-10" r="5" fill="#EFE5D5"/>
      </g>

      {/* Rider — slides smoothly */}
      {!riderHidden && (
        <g style={{ transform: `translate(${riderX}px, ${riderY}px)`, transition: 'transform 1200ms var(--ease-out)' }}>
          <circle r="22" fill="#fff"/>
          <circle r="22" fill="none" stroke="#1B120D" strokeWidth="2.5"/>
          <circle r="26" fill="none" stroke="#D85A14" strokeWidth="2" opacity="0.5">
            <animate attributeName="r" values="22;30;22" dur="2s" repeatCount="indefinite"/>
            <animate attributeName="opacity" values="0.5;0;0.5" dur="2s" repeatCount="indefinite"/>
          </circle>
          <image href={(window.__resources && window.__resources.bullTwotone) || "assets/bull-twotone.png"} x="-16" y="-14" width="32" height="28"/>
        </g>
      )}
    </svg>
  );
}

// ─── Order details sheet ───────────────────────────────────────────
function OrderDetailsSheet({ open, onClose, order, r, app, etaMin, onHelp }) {
  const items = order.items || [];
  const qtyOf = (it) => it.quantity || 1;
  const priceOf = (it) => it.price != null ? it.price * qtyOf(it) : null;
  const knownTotal = order.total || 0;
  return (
    <BottomSheet open={open} onClose={onClose} title="Order details">
      <div data-lasso="order-details-content" style={{ padding: '0 20px max(120px, calc(env(safe-area-inset-bottom, 0px) + 120px))', display: 'flex', flexDirection: 'column', gap: 16 }}>
        {/* From */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', background: 'var(--bg-warm)', borderRadius: 16 }}>
          <div style={{ width: 42, height: 42, borderRadius: 12, overflow: 'hidden', flexShrink: 0 }}><FoodPh height={42} hue={r.hue} radius={12}/></div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--fg-primary)' }}>{r.name}</div>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--warm-stone)', marginTop: 2 }}>#{order.id}</div>
          </div>
          {etaMin > 0
            ? <Pill bg="var(--dark-chocolate)" fg="var(--brand-orange)">{etaMin} min</Pill>
            : <StatusPill kind="live" dot={false}>Delivered</StatusPill>}
        </div>
        {/* Items */}
        <div style={{ background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 16, padding: '4px 14px' }}>
          {items.map((it, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'baseline', gap: 10, padding: '11px 0', borderTop: i > 0 ? '1px solid var(--soft-line)' : 'none' }}>
              <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, color: 'var(--brand-orange)', width: 22, flexShrink: 0 }}>{qtyOf(it)}×</span>
              <span style={{ flex: 1, fontFamily: 'var(--font-body)', fontSize: 13.5, color: 'var(--fg-primary)' }}>{it.item_name || it.name}</span>
              {priceOf(it) != null && <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13, color: 'var(--fg-primary)' }}>£{priceOf(it).toFixed(2)}</span>}
            </div>
          ))}
          <div style={{ display: 'flex', justifyContent: 'space-between', padding: '12px 0', borderTop: '1.5px dashed var(--soft-line)' }}>
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 14, fontWeight: 700, color: 'var(--fg-primary)' }}>Total</span>
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 16, color: 'var(--fg-primary)' }}>£{knownTotal.toFixed(2)}</span>
          </div>
        </div>
        {/* Delivery meta */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, padding: '2px 4px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <Ico.pin c="var(--horse-brown)" s={15}/>
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--warm-stone)' }}>{order.address ? `${order.address.line1}, ${order.address.city}` : '353 Avebury Boulevard, Milton Keynes'}</span>
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <Ico.card c="var(--horse-brown)" s={15}/>
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--warm-stone)' }}>Visa · 4242</span>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          <Button kind="ghost" full onClick={onHelp}>Get help</Button>
          <Button kind="primary" full onClick={onClose}>Done</Button>
        </div>
      </div>
    </BottomSheet>
  );
}

// ─── Rider / order chat — messages route to the Lasso care crew ────
const CHAT_QUICK_REPLIES = ['Where\u2019s my order?', 'Leave it at the door', 'Missing an item', 'Wrong address on order'];
const CHAT_CANNED = {
  'Where\u2019s my order?': 'Diego\u2019s on the trail — about {eta} min out. You can watch him live on the map.',
  'Leave it at the door': 'Done. We\u2019ve flagged your order contact-free — Diego will drop it at the door and ping you.',
  'Missing an item': 'Sorry about that. Tell us what\u2019s missing and we\u2019ll refund it to your wallet within the hour.',
  'Wrong address on order': 'No panic. We can redirect while Diego\u2019s still riding — confirm the right address here.',
};

function RiderChatSheet({ open, onClose, order, r, app, etaMin }) {
  const [msgs, setMsgs] = React.useState([
    { from: 'cc', text: `Howdy Jordan — this is the Lasso care crew. We\u2019re watching order #${order.id} with you. What do you need?`, time: 'now' },
  ]);
  const [draft, setDraft] = React.useState('');
  const scrollRef = React.useRef(null);
  React.useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = msgs.length > 1 ? scrollRef.current.scrollHeight : 0;
    }
  }, [msgs, open]);

  const send = (text) => {
    const t = text.trim();
    if (!t) return;
    setMsgs(m => [...m, { from: 'me', text: t, time: 'now' }]);
    setDraft('');
    setTimeout(() => {
      const canned = CHAT_CANNED[t] || 'Got it — a wrangler from the care crew is on it. We\u2019ll reply here in under a minute.';
      setMsgs(m => [...m, { from: 'cc', text: canned.replace('{eta}', String(etaMin || 5)), time: 'now' }]);
    }, 900);
  };

  if (!open) return null;
  const layer = document.getElementById('lasso-sheet-layer');
  const body = (
    <div data-lasso="rider-chat-overlay" style={{ position: 'fixed', inset: 0, zIndex: 560, pointerEvents: 'auto' }}>
      <div onClick={onClose} style={{ position: 'absolute', inset: 0, background: 'rgba(27,18,13,0.34)' }}/>
      <div className="lasso-sheet" style={{
        position: 'absolute',
        left: 0,
        right: 0,
        top: 'max(76px, calc(env(safe-area-inset-top, 0px) + 70px))',
        bottom: 0,
        zIndex: 1,
        background: 'var(--bg-app)',
        borderRadius: '28px 28px 0 0',
        boxShadow: '0 -20px 50px -10px rgba(0,0,0,0.35)',
        display: 'flex',
        flexDirection: 'column',
      }}>
      <div onClick={onClose} title="Close" style={{ padding: '12px 0 4px', display: 'flex', justifyContent: 'center', flexShrink: 0, cursor: 'pointer' }}>
        <div style={{ width: 44, height: 4, borderRadius: 2, background: 'var(--soft-line)' }}/>
      </div>
      <div data-lasso="rider-chat-content" style={{ padding: '0 0 max(18px, env(safe-area-inset-bottom, 0px))', display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
        {/* Chat header — rider + order context */}
        <div data-lasso="rider-chat-header" style={{ margin: '0 20px', background: 'var(--dark-chocolate)', borderRadius: 18, padding: 12, color: 'var(--dust-cream)', flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
            <div style={{ position: 'relative', flexShrink: 0 }}>
              <div style={{ width: 44, height: 44, borderRadius: '50%', background: 'linear-gradient(135deg,#F4E1C1,#F28C1B)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Bull size={26} variant="twotone"/>
              </div>
              <span style={{ position: 'absolute', bottom: 0, right: 0, width: 11, height: 11, borderRadius: '50%', background: 'var(--live-green)', border: '2px solid var(--dark-chocolate)' }}/>
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14 }}>Diego Morales</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginTop: 2 }}>
                <Ico.star c="var(--sun-orange)" s={10}/>
                <span style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: '#9F8979' }}>4.9 · 312 rides · replies via care crew</span>
              </div>
            </div>
            {etaMin > 0 && <Pill bg="var(--brand-orange)" fg="#fff">{etaMin} min out</Pill>}
          </div>
          {/* order context strip */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, padding: '8px 10px', background: 'rgba(255,255,255,0.06)', borderRadius: 12 }}>
            <Ico.bag c="var(--sun-orange)" s={14}/>
            <span style={{ flex: 1, fontFamily: 'var(--font-body)', fontSize: 11.5, color: '#C9B7AA', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
              {r.name} · {(order.items || []).length} items · £{order.total.toFixed(2)}
            </span>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, color: '#9F8979' }}>#{order.id}</span>
          </div>
        </div>

        {/* Messages */}
        <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: '14px 20px 6px', display: 'flex', flexDirection: 'column', gap: 8 }}>
          <div style={{ alignSelf: 'center', fontFamily: 'var(--font-body)', fontSize: 10.5, color: 'var(--warm-stone)', padding: '2px 10px', background: 'var(--bg-warm)', borderRadius: 999 }}>
            Messages go to the Lasso care crew — not the rider’s phone
          </div>
          {msgs.map((m, i) => (
            <div key={i} style={{
              alignSelf: m.from === 'me' ? 'flex-end' : 'flex-start', maxWidth: '80%',
              padding: '10px 13px', lineHeight: 1.45,
              background: m.from === 'me' ? 'var(--brand-orange)' : 'var(--bg-surface)',
              color: m.from === 'me' ? '#fff' : 'var(--fg-primary)',
              border: m.from === 'me' ? 'none' : '1.5px solid var(--soft-line)',
              borderRadius: m.from === 'me' ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
              fontFamily: 'var(--font-body)', fontSize: 13,
              animation: 'lasso-slide-up 220ms var(--ease-out)',
            }}>{m.text}</div>
          ))}
        </div>

        {/* Quick replies */}
        <div style={{ display: 'flex', gap: 8, overflowX: 'auto', padding: '10px 20px 8px', scrollbarWidth: 'none' }}>
          {CHAT_QUICK_REPLIES.map(q => (
            <button key={q} onClick={() => send(q)} style={{
              flexShrink: 0, padding: '8px 13px', borderRadius: 999, cursor: 'pointer',
              background: 'var(--bg-warm)', border: '1.5px solid var(--soft-line)',
              fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 11.5, color: 'var(--horse-brown)', whiteSpace: 'nowrap',
            }}>{q}</button>
          ))}
        </div>

        {/* Composer */}
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', margin: '6px 20px 0', padding: '5px 5px 5px 14px', background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)', borderRadius: 999 }}>
          <input
            value={draft}
            onChange={e => setDraft(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter') send(draft); }}
            placeholder="Message about this order…"
            style={{ flex: 1, minWidth: 0, border: 'none', outline: 'none', background: 'transparent', fontFamily: 'var(--font-body)', fontSize: 13.5, color: 'var(--fg-primary)' }}/>
          <button onClick={() => send(draft)} disabled={!draft.trim()} aria-label="Send" style={{
            width: 40, height: 40, borderRadius: '50%', border: 'none', cursor: draft.trim() ? 'pointer' : 'default',
            background: draft.trim() ? 'var(--brand-orange)' : 'var(--soft-line)', display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: draft.trim() ? 'var(--shadow-orange)' : 'none', transition: 'all 180ms var(--ease-out)',
          }}><Ico.arrow c="#fff" s={18}/></button>
        </div>
      </div>
      </div>
    </div>
  );
  return layer ? ReactDOM.createPortal(body, layer) : body;
}

// ─── Call sheet ────────────────────────────────────────────────────
function CallSheet({ open, onClose, app }) {
  return (
    <BottomSheet open={open} onClose={onClose} title="Ring someone" maxHeight="calc(100% - 96px)">
      <div style={{ padding: '0 20px max(112px, calc(env(safe-area-inset-bottom, 0px) + 112px))', display: 'flex', flexDirection: 'column', gap: 10 }}>
        {[
          { id: 'rider', label: 'Diego (your rider)', sub: 'Via masked number — he\u2019s riding, keep it short', icon: <Ico.ride c="var(--brand-orange)" s={18}/> },
          { id: 'crew', label: 'Lasso care crew', sub: '24/7 · answers in under 30 seconds', icon: <Bull size={20}/> },
          { id: 'kitchen', label: 'The kitchen', sub: 'For allergy or prep questions', icon: <Ico.flame c="var(--brand-orange)" s={18}/> },
        ].map(o => (
          <button key={o.id} onClick={() => { onClose(); app.toast(`Connecting you — masked line, your number stays private`, 'info'); }} style={{
            display: 'flex', alignItems: 'center', gap: 12, padding: 14, borderRadius: 14, cursor: 'pointer', textAlign: 'left',
            background: 'var(--bg-surface)', border: '1.5px solid var(--soft-line)',
          }}>
            <div style={{ width: 40, height: 40, borderRadius: 12, background: 'var(--bg-warm)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{o.icon}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 14, color: 'var(--fg-primary)' }}>{o.label}</div>
              <div style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--warm-stone)', marginTop: 2 }}>{o.sub}</div>
            </div>
            <Ico.phone c="var(--brand-orange)" s={18}/>
          </button>
        ))}
      </div>
    </BottomSheet>
  );
}

// ─── Real Leaflet tracking map — live tiles, road route, animated rider ─
// Route hand-traced around Central Milton Keynes so the rider visibly follows local roads.
const LT_STORE = [52.0409, -0.7547];
const LT_HOME  = [52.0378, -0.7605];
const LT_ROUTE = [
  [52.0409, -0.7547], [52.0401, -0.7558], [52.0393, -0.7571],
  [52.0386, -0.7584], [52.0380, -0.7593], [52.0378, -0.7605],
];
function ltPointAt(frac) {
  // interpolate along LT_ROUTE by cumulative distance
  const d = [];
  let total = 0;
  for (let i = 1; i < LT_ROUTE.length; i++) {
    const dx = LT_ROUTE[i][0] - LT_ROUTE[i-1][0], dy = LT_ROUTE[i][1] - LT_ROUTE[i-1][1];
    total += Math.sqrt(dx*dx + dy*dy);
    d.push(total);
  }
  const target = Math.max(0, Math.min(1, frac)) * total;
  for (let i = 0; i < d.length; i++) {
    const prev = i === 0 ? 0 : d[i-1];
    if (target <= d[i]) {
      const t = (target - prev) / (d[i] - prev || 1);
      const a = LT_ROUTE[i], b = LT_ROUTE[i+1];
      return [a[0] + (b[0]-a[0]) * t, a[1] + (b[1]-a[1]) * t];
    }
  }
  return LT_ROUTE[LT_ROUTE.length - 1];
}

function LeafletTrackingMap({ progress, riderHidden, delivered, etaMin }) {
  const elRef = React.useRef(null);
  const mapRef = React.useRef(null);
  const layersRef = React.useRef({});
  const fracRef = React.useRef(0);

  // target route fraction per pipeline step
  const targetFrac = delivered ? 1 : progress >= 8 ? 1 : progress === 7 ? 0.58 : progress === 6 ? 0.04 : 0;

  React.useEffect(() => {
    if (!window.L || !elRef.current || mapRef.current) return;
    const map = L.map(elRef.current, { zoomControl: false, attributionControl: true, minZoom: 12, maxZoom: 18 });
    mapRef.current = map;
    L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
      subdomains: 'abcd', maxZoom: 19, attribution: '© OpenStreetMap © CARTO',
    }).addTo(map);
    map.fitBounds(L.latLngBounds(LT_ROUTE).pad(0.18));

    // remaining route (dashed) + completed route (solid orange)
    const dashed = L.polyline(LT_ROUTE, { color: '#D85A14', weight: 4, opacity: 0.32, dashArray: '2 9', lineCap: 'round' }).addTo(map);
    const done = L.polyline([LT_ROUTE[0]], { color: '#D85A14', weight: 5, opacity: 0.95, lineCap: 'round' }).addTo(map);

    // store pin
    L.marker(LT_STORE, { icon: L.divIcon({ className: 'lt-icon', iconSize: [30, 30], iconAnchor: [15, 15],
      html: '<div class="lt-storepin"><span></span></div>' }) }).addTo(map).bindTooltip('Rojo & Smoke', { direction: 'top', offset: [0, -14] });
    // home pin
    L.marker(LT_HOME, { icon: L.divIcon({ className: 'lt-icon', iconSize: [32, 38], iconAnchor: [16, 34],
      html: '<div class="lt-homepin"><svg width="32" height="38" viewBox="0 0 32 38"><path d="M16 1C24 1 30 7 30 15c0 9-10 18-14 22C12 33 2 24 2 15 2 7 8 1 16 1z" fill="#1B120D" stroke="#F5EFE7" stroke-width="2"/><circle cx="16" cy="14" r="5" fill="#EFE5D5"/></svg></div>' }) }).addTo(map).bindTooltip('You · Avebury Boulevard', { direction: 'top', offset: [0, -30] });
    // driver marker
    const driver = L.marker(LT_ROUTE[0], { icon: L.divIcon({ className: 'lt-icon lt-driver-icon', iconSize: [44, 44], iconAnchor: [22, 22],
      html: '<div class="lt-driver"><span class="ping"></span><div class="core"><svg width="24" height="21" viewBox="0 0 24 21"><path d="M2 3c2 4 5 6 7 6h6c2 0 5-2 7-6-3 1-5 1-7 3h-6C7 4 5 4 2 3zm10 8c-2.5 0-4 2-4 4.5S9.5 20 12 20s4-2 4-4.5S14.5 11 12 11z" fill="#D85A14"/></svg></div></div>' }) }).addTo(map);

    layersRef.current = { done, driver };
    setTimeout(() => map.invalidateSize(), 250);
    return () => { map.remove(); mapRef.current = null; };
  }, []);

  // ease displayed fraction toward the target so the rider creeps along roads
  React.useEffect(() => {
    if (!mapRef.current) return;
    const tick = () => {
      const f = fracRef.current;
      const next = Math.abs(targetFrac - f) < 0.004 ? targetFrac : f + (targetFrac - f) * 0.22;
      fracRef.current = next;
      const { done, driver } = layersRef.current;
      if (!done || !driver) return;
      // rebuild completed portion of the polyline
      const pts = [LT_ROUTE[0]];
      const total = 1; // use fraction-space sampling
      for (let s = 0.02; s <= next; s += 0.02) pts.push(ltPointAt(s));
      pts.push(ltPointAt(next));
      done.setLatLngs(pts);
      driver.setLatLng(ltPointAt(next));
      driver.setOpacity(riderHidden ? 0 : 1);
    };
    tick();
    const iv = setInterval(tick, 1500);
    return () => clearInterval(iv);
  }, [targetFrac, riderHidden]);

  return <div ref={elRef} className="lasso-track-map" style={{ width: '100%', height: '100%' }}></div>;
}

Object.assign(window, { TrackingScreen, MapIllustration, LeafletTrackingMap, STATUS_PIPELINE, STATUS_TO_BADGE, TRACKING_EVENTS, VerticalProgress, CompactProgress, Timeline, RiderCard,
  // shared with desktop
  theatreFor, RiderChatSheet, CallSheet, OrderDetailsSheet, DeliveredConfetti });
