/* ============================================================================
   MOWDEW OWNER — Mobile app (on-the-go god mode)
   The owner's pocket control: see the money, nudge who owes, approve
   reschedules (route auto-updates), message customers, manage the book.
   Reuses owner data (BIZ, WORKERS, CUSTOMERS, RESCHEDULES, THREADS, PLANS).
   Screens: o_home · o_money · o_inbox · o_customers · o_customer · o_thread
   ========================================================================= */
const { useState: omState } = React;

/* small vertical pill (garden green / pool aqua) */
function MVert({ vert }) {
  const v = VERT(vert);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: v.c50, color: v.c700, border: `1px solid ${v.c100}`, borderRadius: 999, padding: '3px 9px 3px 6px', fontSize: 11, fontWeight: 700, flexShrink: 0 }}>
      <Icon name={v.icon} size={12} strokeWidth={2.3} />{v.name}
    </span>
  );
}

/* rich photo-backed stat card (bespoke imagery behind the number) */
function RichStat({ scene, eyebrow, value, sub, badge, badgeTone = 'mint', onClick, tall }) {
  const badgeBg = { mint: 'var(--green-500)', alert: 'var(--alert-500)', sky: 'var(--blue-500)', aqua: 'var(--aqua-500)' }[badgeTone] || 'var(--green-500)';
  return (
    <div onClick={onClick} style={{ position: 'relative', borderRadius: 'var(--radius-2xl)', overflow: 'hidden', minHeight: tall ? 132 : 116, padding: 14, cursor: onClick ? 'pointer' : 'default', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', color: '#fff', boxShadow: 'var(--shadow-md)' }}>
      <div style={{ position: 'absolute', inset: 0, backgroundImage: `url(assets/scenes/${scene}.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }} />
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(18,16,10,.12) 0%, rgba(18,16,10,.45) 55%, rgba(18,16,10,.78) 100%)' }} />
      <span style={{ position: 'absolute', top: 11, right: 11, width: 30, height: 30, borderRadius: 9, background: badgeBg, display: 'grid', placeItems: 'center', color: badgeTone === 'mint' ? '#fff' : '#fff', boxShadow: '0 2px 8px rgba(0,0,0,.25)' }}><Icon name={badge} size={17} strokeWidth={2.3} /></span>
      <div style={{ position: 'relative' }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9.5, letterSpacing: '.1em', color: 'rgba(255,255,255,.88)' }}>{eyebrow}</div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 25, letterSpacing: '-0.03em', marginTop: 3, textShadow: '0 1px 8px rgba(0,0,0,.3)' }}>{value}</div>
        <div style={{ fontSize: 11.5, color: 'rgba(255,255,255,.82)', marginTop: 1 }}>{sub}</div>
      </div>
    </div>
  );
}

/* the owner pulse — one dark statement band (money is the hero) + a calm
   white ops pair. Same visual language as the homeowner's ledger band.   */
function OwnerStatBand({ collected, collectedSub, owed, owedSub, onOwed, visitsValue, visitsSub, visitsLive = false, onVisits, homesValue, homesSub, onHomes }) {
  const billed = collected + owed;
  const pct = Math.round((collected / billed) * 100);
  return (
    <div>
      <div style={{ background: 'var(--green-800)', borderRadius: 'var(--radius-2xl)', padding: '16px 18px 15px', color: '#fff', position: 'relative', overflow: 'hidden', boxShadow: 'var(--shadow-md)' }}>
        <div style={{ display: 'flex', gap: 16 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.1em', color: 'rgba(255,255,255,.6)' }}>COLLECTED · MAY</div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 26, letterSpacing: '-0.03em', marginTop: 3 }}>{fmtMoney(collected)}</div>
            <div style={{ fontSize: 11.5, fontWeight: 600, color: 'rgba(255,255,255,.8)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{collectedSub}</div>
          </div>
          <div onClick={owed > 0 ? onOwed : undefined} style={{ flex: 1, minWidth: 0, paddingLeft: 16, borderLeft: '1px solid rgba(255,255,255,.16)', cursor: owed > 0 ? 'pointer' : 'default' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}><span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.1em', color: owed > 0 ? '#FF9E7D' : 'rgba(255,255,255,.6)' }}>OUTSTANDING</span>{owed > 0 && <Icon name="chevron-right" size={12} style={{ color: '#FF9E7D' }} />}</div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 26, letterSpacing: '-0.03em', marginTop: 3, color: owed > 0 ? '#FFB59A' : '#fff' }}>{fmtMoney(owed)}</div>
            <div style={{ fontSize: 11.5, fontWeight: 600, color: 'rgba(255,255,255,.8)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{owedSub}</div>
          </div>
        </div>
        <div style={{ marginTop: 13 }}>
          <div style={{ height: 6, borderRadius: 99, background: 'rgba(255,255,255,.2)', overflow: 'hidden' }}>
            <span style={{ display: 'block', height: '100%', width: `${pct}%`, background: 'var(--yellow-500)', transition: 'width .6s cubic-bezier(.22,1,.36,1)' }} />
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 7, fontFamily: 'var(--font-mono)', fontSize: 9.5, letterSpacing: '.04em', color: 'rgba(255,255,255,.55)' }}>
            <span>{pct}% COLLECTED</span><span>BILLED {fmtMoney(billed)}</span>
          </div>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 11, marginTop: 11 }}>
        {[
          { icon: 'route', bg: 'var(--blue-500)', eyebrow: 'VISITS TODAY', value: visitsValue, sub: visitsSub, live: visitsLive, onClick: onVisits },
          { icon: 'home', bg: 'var(--aqua-500)', eyebrow: 'ACTIVE HOMES', value: homesValue, sub: homesSub, onClick: onHomes },
        ].map(c => (
          <div key={c.eyebrow} onClick={c.onClick} className="card" style={{ padding: '13px 14px', cursor: c.onClick ? 'pointer' : 'default', minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ width: 30, height: 30, borderRadius: 9, background: c.bg, display: 'grid', placeItems: 'center', color: '#fff', flexShrink: 0 }}><Icon name={c.icon} size={16} strokeWidth={2.3} /></span>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '.12em', color: 'var(--ink-500)', whiteSpace: 'nowrap' }}>{c.eyebrow}</span>
              {c.live && <span className="tn-pulse" style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--blue-500)', marginLeft: 'auto', flexShrink: 0 }} />}
            </div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 24, letterSpacing: '-0.03em', marginTop: 9, lineHeight: 1 }}>{c.value}</div>
            <div style={{ fontSize: 11.5, color: 'var(--ink-500)', marginTop: 4, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.sub}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* the "all-clear" celebratory hero — shows when the book is fully caught up */
function AllClearHero() {
  return (
    <div style={{ position: 'relative', borderRadius: 'var(--radius-2xl)', overflow: 'hidden', padding: '18px 20px', color: '#fff', minHeight: 120, display: 'flex', alignItems: 'center', boxShadow: 'var(--shadow-md)' }}>
      <div style={{ position: 'absolute', inset: 0, backgroundImage: 'url(assets/scenes/lawn-after.png)', backgroundSize: 'cover', backgroundPosition: 'center' }} />
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(120deg, rgba(21,128,60,.86) 0%, rgba(16,140,73,.72) 55%, rgba(18,188,201,.5) 100%)' }} />
      <div style={{ position: 'relative', flex: 1 }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 12.5, background: 'rgba(255,255,255,.18)', border: '1px solid rgba(255,255,255,.28)', borderRadius: 99, padding: '4px 11px 4px 9px' }}><Icon name="check-circle" size={15} />All clear</span>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 23, letterSpacing: '-0.025em', marginTop: 10, lineHeight: 1.1, maxWidth: 220 }}>You're all caught up.</div>
        <div style={{ fontSize: 12.5, color: 'rgba(255,255,255,.85)', marginTop: 4 }}>Everyone's paid, every route is set.</div>
      </div>
      <div style={{ position: 'relative', flexShrink: 0 }}><Sprout size={86} mood="wink" /></div>
    </div>
  );
}

/* ============================== OWNER · HOME ========================== */
function OwnerHome({ go, openFab }) {
  const owing = CUSTOMERS.filter(c => c.balance > 0);
  const owed = owing.reduce((s, c) => s + c.balance, 0);
  const collected = 184000;
  const allClear = owed === 0 && RESCHEDULES.length === 0;
  return (
    <Screen padBottom={26} footer={<TabBar role="owner" active="o_home" go={go} onFab={openFab} />}>
      {/* header */}
      <div style={{ padding: '8px 18px 6px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <Logo size={34} />
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 12.5, color: 'var(--ink-500)', fontWeight: 600 }}>{BIZ.name}</div>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 21, letterSpacing: '-0.02em' }}>Good morning, Diego</div>
        </div>
        <NotifBell count={notifUnreadCount('owner')} onClick={() => go('o_notifs')} />
      </div>

      {/* money + ops — rich photo-backed stat cards (bespoke imagery) */}
      <div style={{ padding: '6px 18px 0' }}>
        {allClear ? <AllClearHero /> : (
          <OwnerStatBand
            collected={collected} collectedSub="28 invoices paid"
            owed={owed} owedSub={owed > 0 ? `${owing.length} invoices open` : 'All collected'} onOwed={() => go('o_money')}
            visitsValue="9" visitsSub="2 workers out · live" visitsLive onVisits={() => go('o_routes')}
            homesValue={String(BIZ.homes)} homesSub="21 garden · 17 pool" onHomes={() => go('o_customers')}
          />
        )}
      </div>

      {/* time to bill — owner-confirmed billing action item (hidden at zero) */}
      {runPending().length > 0 && (
        <div style={{ padding: '14px 18px 0' }}>
          <TimeToBillCard compact count={runPending().length} total={runTotal(CUSTOMERS)} onOpen={() => go('o_billing_run')} />
        </div>
      )}

      {/* needs you */}
      <div style={{ padding: '18px 18px 0' }}>
        <SectionHead tone="ink" icon="bell" style={{ marginBottom: 12 }}>Needs you</SectionHead>
        <div className="card" style={{ overflow: 'hidden' }}>
          <button onClick={() => go('o_inbox', { tab: 'approvals' })} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: 14, border: 'none', borderBottom: '1px solid var(--ink-100)', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--yellow-500)', display: 'grid', placeItems: 'center', color: 'var(--ink-900)', flexShrink: 0 }}><Icon name="calendar-check" size={19} /></span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5 }}>Reschedule requests</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>Approve, suggest a time, or move the stop</div>
            </div>
            <span style={{ background: 'var(--yellow-50)', color: 'var(--yellow-700)', borderRadius: 99, minWidth: 22, height: 22, padding: '0 7px', fontSize: 12.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>{needsOwnerCount()}</span>
            <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
          </button>
          <button onClick={() => go('o_money')} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: 14, border: 'none', borderBottom: '1px solid var(--ink-100)', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--alert-500)', display: 'grid', placeItems: 'center', color: '#fff', flexShrink: 0 }}><Icon name="nudge" size={19} /></span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5 }}>Unpaid invoices</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>{fmtMoney(owed)} outstanding · tap to nudge</div>
            </div>
            <span style={{ background: 'var(--alert-50)', color: 'var(--alert-700)', borderRadius: 99, minWidth: 22, height: 22, padding: '0 7px', fontSize: 12.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>{owing.length}</span>
            <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
          </button>
          <button onClick={() => go('o_inbox', { tab: 'messages' })} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: 14, border: 'none', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--blue-500)', display: 'grid', placeItems: 'center', color: '#fff', flexShrink: 0 }}><Icon name="message" size={19} /></span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5 }}>New messages</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>Emma, Tom</div>
            </div>
            <span style={{ background: 'var(--blue-50)', color: 'var(--blue-700)', borderRadius: 99, minWidth: 22, height: 22, padding: '0 7px', fontSize: 12.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>2</span>
            <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
          </button>
          {/* G6/G5 — field notes + photo'd requests (union: present in the app, now in the design too) */}
          <button onClick={() => go('o_inbox', { tab: 'notes' })} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: 14, border: 'none', borderTop: '1px solid var(--ink-100)', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--green-500)', display: 'grid', placeItems: 'center', color: '#fff', flexShrink: 0 }}><Icon name="file-text" size={19} /></span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5 }}>Field notes from the crew</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>Flags &amp; requests from the field</div>
            </div>
            <span style={{ background: 'var(--green-50)', color: 'var(--green-700)', borderRadius: 99, minWidth: 22, height: 22, padding: '0 7px', fontSize: 12.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>3</span>
            <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
          </button>
          <button onClick={() => go('o_requests')} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: 14, border: 'none', borderTop: '1px solid var(--ink-100)', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--aqua-500)', display: 'grid', placeItems: 'center', color: '#fff', flexShrink: 0 }}><Icon name="camera" size={19} /></span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5 }}>Requests to quote</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>Photos in — turn them into priced quotes</div>
            </div>
            <span style={{ background: 'var(--aqua-50)', color: 'var(--aqua-700)', borderRadius: 99, minWidth: 22, height: 22, padding: '0 7px', fontSize: 12.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>2</span>
            <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
          </button>
        </div>
      </div>

      {/* today's routes */}
      <div style={{ padding: '18px 18px 0' }}>
        <SectionHead tone="green" icon="route" style={{ marginBottom: 12 }} meta={<button onClick={() => go('o_routes')} className="btn btn-ghost" style={{ minHeight: 30, padding: '5px 9px', fontSize: 12.5 }}>Dispatch &amp; team<Icon name="arrow-right" size={14} /></button>}>Today's routes</SectionHead>
        <div style={{ display: 'grid', gap: 11 }}>
          {WORKERS.map(w => {
            const doneN = w.id === 'w1' ? 2 : 0;
            return (
              <div key={w.id} onClick={() => go('o_routes', { worker: w.id })} className="card" style={{ padding: 13, cursor: 'pointer' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginBottom: 10 }}>
                  <Avatar name={w.name} size={36} />
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 700, fontSize: 14 }}>{w.name}{w.you && <span style={{ color: 'var(--ink-400,#A8A498)', fontWeight: 500 }}> · you</span>}</div>
                    <div style={{ fontSize: 12, color: 'var(--ink-500)' }}>{w.role}</div>
                  </div>
                  <Chip tone={w.id === 'w1' ? 'live' : 'soon'} pulse={w.id === 'w1'}>{w.id === 'w1' ? 'On route' : 'Starts 11:00'}</Chip>
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  {Array.from({ length: w.today }).map((_, i) => (
                    <span key={i} style={{ flex: 1, height: 7, borderRadius: 99, background: i < doneN ? 'var(--green-500)' : i === doneN && w.id === 'w1' ? 'var(--blue-500)' : 'var(--ink-100)' }} />
                  ))}
                  <span style={{ marginLeft: 8, fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--ink-500)' }}>{doneN}/{w.today}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </Screen>
  );
}

/* ============================== OWNER · MONEY ========================= */
function OwnerMoneyM({ go, openFab, toast }) {
  const [nudged, setNudged] = omState({});
  const owing = CUSTOMERS.filter(c => c.balance > 0);
  const paid = CUSTOMERS.filter(c => c.balance === 0);
  const owed = owing.reduce((s, c) => s + c.balance, 0);
  const nudge = (c) => { setNudged(n => ({ ...n, [c.id]: true })); toast(`Nudge sent to ${c.name.split(' ')[0]}`, 'green'); };
  return (
    <Screen padBottom={26} footer={<TabBar role="owner" active="o_money" go={go} onFab={openFab} />}>
      <TopBar title="Money" big subtitle="Who's paid, who owes" />
      {/* time to bill — appears whenever ≥1 customer is due (hidden at zero) */}
      {runPending().length > 0 && (
        <div style={{ padding: '0 18px 12px' }}>
          <TimeToBillCard compact count={runPending().length} total={runTotal(CUSTOMERS)} onOpen={() => go('o_billing_run')} />
        </div>
      )}
      {/* summary */}
      <div style={{ padding: '0 18px', display: 'flex', gap: 10 }}>
        <div style={{ flex: 1, background: 'var(--green-700)', borderRadius: 'var(--radius-xl)', padding: 14, color: '#fff' }}>
          <div style={{ fontSize: 11.5, color: 'rgba(255,255,255,.8)', fontWeight: 600 }}>Collected · May</div>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 22, marginTop: 2 }}>{fmtMoney(184000)}</div>
        </div>
        <div className="card" style={{ flex: 1, padding: 14, borderColor: '#F8D3C5' }}>
          <div style={{ fontSize: 11.5, color: 'var(--ink-500)', fontWeight: 600 }}>Outstanding</div>
          <div style={{ marginTop: 2 }}><Amount cents={owed} size={22} tone="due" /></div>
        </div>
      </div>

      {/* owes you */}
      <div style={{ padding: '18px 18px 0' }}>
        <SectionHead tone="alert" icon="nudge" style={{ marginBottom: 12 }}>Owes you</SectionHead>
        <div style={{ display: 'grid', gap: 10 }}>
          {owing.map(c => (
            <div key={c.id} className="card" style={{ padding: 13 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
                <Avatar name={c.name} size={40} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 700, fontSize: 14.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</div>
                  <div style={{ fontSize: 12, color: 'var(--ink-500)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.addr}, {c.city} · {c.dueLabel}</div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <Amount cents={c.balance} size={16} tone="due" />
                  <div style={{ fontSize: 10.5, color: 'var(--ink-400,#A8A498)' }}>via {RAIL[c.rail].label}</div>
                </div>
              </div>
              <div style={{ display: 'flex', gap: 9, marginTop: 11 }}>
                <button onClick={() => go('o_customer', { id: c.id })} className="btn btn-secondary" style={{ flex: 1, minHeight: 42 }}>View</button>
                <button onClick={() => nudge(c)} disabled={nudged[c.id]} className={nudged[c.id] ? 'btn btn-secondary' : 'btn btn-primary'} style={{ flex: 1.3, minHeight: 42 }}><Icon name={nudged[c.id] ? 'check' : 'nudge'} size={17} />{nudged[c.id] ? 'Nudged' : 'Send nudge'}</button>
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* paid up */}
      <div style={{ padding: '18px 18px 0' }}>
        <SectionHead tone="green" icon="check-circle" style={{ marginBottom: 12 }}>Paid up</SectionHead>
        <div className="card" style={{ overflow: 'hidden' }}>
          {paid.slice(0, 5).map((c, i) => (
            <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '12px 14px', borderTop: i ? '1px solid var(--ink-100)' : 'none' }}>
              <Avatar name={c.name} size={34} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 700, fontSize: 13.5 }}>{c.name}</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-500)', display: 'flex', alignItems: 'center', gap: 5 }}><RailChip rail={c.rail} size={15} />{c.lastPaid}</div>
              </div>
              <Chip tone="done" icon="check">Paid</Chip>
            </div>
          ))}
        </div>
      </div>
    </Screen>
  );
}

/* ============================== OWNER · INBOX ========================= */
function OwnerInbox({ go, openFab, toast, params }) {
  const [tab, setTab] = omState(params.tab || 'approvals');
  const [resolved, setResolved] = omState({});
  const act = (r, ok) => {
    setResolved(s => ({ ...s, [r.id]: ok ? 'approved' : 'declined' }));
    const w = WORKERS.find(x => x.id === r.worker);
    if (ok) { toast(`Approved · ${w.name.split(' ')[0]}'s route updated`, 'green'); }
  };
  const declineMsg = (r) => {
    const c = CUSTOMERS.find(x => x.id === r.cust);
    const first = c.name.split(' ')[0];
    const when = r.to === 'skip' ? 'skip this week' : `move to ${r.to}`;
    const pre = `Hi ${first}, thanks for the heads up! I'm not able to ${when} this time — could we keep your regular ${r.from} visit? Happy to find another day that works for you. — Diego`;
    setResolved(s => ({ ...s, [r.id]: 'declined' }));
    go('o_thread', { id: r.cust, prefill: pre });
  };
  const threadIds = Object.keys(THREADS);
  return (
    <Screen padBottom={26} footer={<TabBar role="owner" active="o_inbox" go={go} onFab={openFab} />}>
      <TopBar title="Inbox" big subtitle="Approvals & customer messages" />
      {/* segmented */}
      <div style={{ padding: '0 18px 4px' }}>
        <div style={{ display: 'flex', gap: 7, background: 'var(--ink-50)', padding: 5, borderRadius: 14, border: '1px solid var(--ink-100)' }}>
          {[['approvals', 'Approvals', needsOwnerCount()], ['messages', 'Messages', 2]].map(([id, lb, n]) => (
            <button key={id} onClick={() => setTab(id)} style={{ flex: 1, padding: '10px 6px', borderRadius: 10, border: 'none', cursor: 'pointer', fontSize: 13.5, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7, background: tab === id ? '#fff' : 'transparent', color: tab === id ? 'var(--ink-900)' : 'var(--ink-500)', boxShadow: tab === id ? 'var(--shadow-sm)' : 'none' }}>
              {lb}<span style={{ background: tab === id ? 'var(--green-700)' : 'var(--ink-200)', color: '#fff', borderRadius: 99, minWidth: 18, height: 18, fontSize: 11, fontWeight: 800, display: 'grid', placeItems: 'center', padding: '0 5px' }}>{n}</span>
            </button>
          ))}
        </div>
      </div>

      {tab === 'approvals' ? (
        <div style={{ padding: '14px 18px 0' }}>
          <div onClick={() => go('o_requests')} className="card" style={{ padding: 13, display: 'flex', alignItems: 'center', gap: 11, cursor: 'pointer', borderColor: 'var(--aqua-100)', marginBottom: 12 }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--aqua-50)', display: 'grid', placeItems: 'center', color: 'var(--aqua-700)', flexShrink: 0 }}><Icon name="camera" size={19} /></span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 700, fontSize: 13.5 }}>Requests &amp; quotes</div>
              <div style={{ fontSize: 11.5, color: 'var(--ink-500)' }}>1 photo to quote · 1 awaiting approval</div>
            </div>
            <Icon name="chevron-right" size={17} style={{ color: 'var(--ink-300)', flexShrink: 0 }} />
          </div>
          <ReschedQueue compact go={go} toast={toast} />
        </div>
      ) : (
        <div style={{ padding: '14px 18px 0', display: 'grid', gap: 10 }}>
          {threadIds.concat(CUSTOMERS.filter(c => !threadIds.includes(c.id)).slice(0, 3).map(c => c.id)).map(id => {
            const c = CUSTOMERS.find(x => x.id === id);
            const last = (THREADS[id] || [])[(THREADS[id] || []).length - 1];
            return (
              <div key={id} onClick={() => go('o_thread', { id })} className="card" style={{ padding: 13, display: 'flex', alignItems: 'center', gap: 11, cursor: 'pointer' }}>
                <Avatar name={c.name} size={42} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}><span style={{ fontWeight: 700, fontSize: 14, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flexShrink: 1, minWidth: 0 }}>{c.name}</span><MVert vert={c.vert} /></div>
                  <div style={{ fontSize: 12.5, color: 'var(--ink-500)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', marginTop: 1 }}>{last ? last.t : 'Start a conversation'}</div>
                </div>
                <Icon name="chevron-right" size={18} style={{ color: 'var(--ink-300)' }} />
              </div>
            );
          })}
        </div>
      )}
    </Screen>
  );
}

/* ============================== OWNER · THREAD ======================= */
function OwnerThread({ go, params }) {
  const c = CUSTOMERS.find(x => x.id === params.id) || CUSTOMERS[1];
  const [extra, setExtra] = omState([]);
  const [draft, setDraft] = omState('');
  const msgs = [...(THREADS[c.id] || THREADS.c2), ...extra];
  const send = () => { if (!draft.trim()) return; setExtra(e => [...e, { from: 'owner', t: draft, at: 'now' }]); setDraft(''); };
  return (
    <Screen padBottom={0} footer={
      <div style={{ flexShrink: 0, padding: '12px 16px 20px', background: 'var(--surface)', borderTop: '1px solid var(--ink-100)', display: 'flex', gap: 9 }}>
        <input value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} placeholder="Write a reply…" style={{ flex: 1, padding: '12px 14px', border: '1px solid var(--ink-200)', borderRadius: 12, fontFamily: 'var(--font-body)', fontSize: 14, outline: 'none' }} />
        <button onClick={send} className="btn btn-primary" style={{ minHeight: 46, padding: '12px 16px' }}><Icon name="send" size={17} /></button>
      </div>}>
      <TopBar title={c.name} subtitle={`${c.addr} · ${c.city}`} onBack={() => go('o_inbox', { tab: 'messages' })} right={<button onClick={() => go('o_customer', { id: c.id })} style={{ width: 40, height: 40, borderRadius: 12, border: '1px solid var(--ink-100)', background: '#fff', display: 'grid', placeItems: 'center', cursor: 'pointer', color: 'var(--ink-700)' }}><Icon name="user" size={19} /></button>} />
      <div style={{ padding: '8px 18px 0', display: 'flex', flexDirection: 'column', gap: 10 }}>
        {msgs.map((m, i) => {
          if (m.from === 'sys') return <div key={i} style={{ alignSelf: 'center', background: 'var(--yellow-50)', border: '1px solid var(--yellow-100)', color: 'var(--yellow-700)', borderRadius: 99, padding: '6px 13px', fontSize: 11.5, fontWeight: 600, display: 'inline-flex', gap: 6, alignItems: 'center', textAlign: 'center' }}><Icon name="calendar-check" size={13} />{m.t}</div>;
          const me = m.from === 'owner';
          return (
            <div key={i} style={{ alignSelf: me ? 'flex-end' : 'flex-start', maxWidth: '78%' }}>
              <div style={{ background: me ? 'var(--green-700)' : '#fff', color: me ? '#fff' : 'var(--ink-900)', border: me ? 'none' : '1px solid var(--ink-100)', borderRadius: 16, borderBottomRightRadius: me ? 5 : 16, borderBottomLeftRadius: me ? 16 : 5, padding: '10px 13px', fontSize: 13.5, lineHeight: 1.45 }}>{m.t}</div>
              <div style={{ fontSize: 10.5, color: 'var(--ink-400,#A8A498)', marginTop: 3, textAlign: me ? 'right' : 'left', fontFamily: 'var(--font-mono)' }}>{m.at}</div>
            </div>
          );
        })}
      </div>
    </Screen>
  );
}

/* ============================== OWNER · CUSTOMERS ===================== */
function OwnerCustomersM({ go, openFab }) {
  const [q, setQ] = omState('');
  const [vf, setVf] = omState('all');
  const rows = CUSTOMERS.filter(c => (vf === 'all' || c.vert === vf) && (c.name.toLowerCase().includes(q.toLowerCase()) || c.addr.toLowerCase().includes(q.toLowerCase())));
  return (
    <Screen padBottom={26} footer={<TabBar role="owner" active="o_customers" go={go} onFab={openFab} />}>
      <TopBar title="Customers" big subtitle={`${CUSTOMERS.length} on the book`} right={<button onClick={() => go('o_new_customer')} style={{ width: 42, height: 42, borderRadius: 12, border: 'none', background: 'var(--green-700)', display: 'grid', placeItems: 'center', cursor: 'pointer', color: '#fff', boxShadow: 'var(--shadow-green)' }}><Icon name="plus" size={21} strokeWidth={2.4} /></button>} />
      {/* search */}
      <div style={{ padding: '0 18px 4px', position: 'relative' }}>
        <Icon name="search" size={19} style={{ position: 'absolute', left: 32, top: 13, color: 'var(--ink-300)' }} />
        <input value={q} onChange={e => setQ(e.target.value)} className="input" placeholder="Search name or address" style={{ paddingLeft: 44 }} />
      </div>
      {/* filter */}
      <div style={{ padding: '10px 18px 4px', display: 'flex', gap: 8 }}>
        {[['all', 'All'], ['garden', 'Garden'], ['pool', 'Pool']].map(([id, lb]) => (
          <button key={id} onClick={() => setVf(id)} style={{ padding: '8px 15px', borderRadius: 10, border: '1px solid', borderColor: vf === id ? 'transparent' : 'var(--ink-200)', cursor: 'pointer', fontSize: 13, fontWeight: 700, background: vf === id ? 'var(--ink-900)' : '#fff', color: vf === id ? '#fff' : 'var(--ink-700)' }}>{lb}</button>
        ))}
      </div>
      <div style={{ padding: '8px 18px 0', display: 'grid', gap: 10 }}>
        {rows.map(c => {
          const w = custWorker(c);
          return (
            <div key={c.id} onClick={() => go('o_customer', { id: c.id })} className="card" style={{ padding: 13, display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer' }}>
              <Avatar name={c.name} size={42} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}><span style={{ fontWeight: 700, fontSize: 14.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</span><MVert vert={c.vert} /></div>
                <div style={{ fontSize: 12, color: 'var(--ink-500)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.addr} · {w.name.split(' ')[0]}</div>
              </div>
              <div style={{ textAlign: 'right', flexShrink: 0 }}>
                {c.balance > 0 ? <Amount cents={c.balance} size={14} tone="due" /> : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: 'var(--green-700)', fontSize: 12, fontWeight: 700 }}><Icon name="check-circle" size={14} />Paid</span>}
              </div>
            </div>
          );
        })}
        {rows.length === 0 && <div style={{ textAlign: 'center', padding: '36px 0', color: 'var(--ink-500)', fontSize: 14 }}>No customers match.</div>}
      </div>
    </Screen>
  );
}

/* ============================== OWNER · CUSTOMER DETAIL =============== */
function OwnerCustomerM({ go, params, toast }) {
  const c = CUSTOMERS.find(x => x.id === params.id) || CUSTOMERS[1];
  const [wid, setWid] = omState(c.worker);
  const [reassign, setReassign] = omState(false);
  const w = WORKERS.find(x => x.id === wid) || custWorker(c);
  const v = VERT(c.vert);
  const scene = c.vert === 'pool' ? 'pool' : 'lawn';
  const visits = [
    { d: 'Mon, May 12', tin: '9:58 AM', tout: '10:22 AM', dur: '24 min' },
    { d: 'Mon, May 5', tin: '10:04 AM', tout: '10:31 AM', dur: '27 min' },
    { d: 'Mon, Apr 28', tin: '9:51 AM', tout: '10:13 AM', dur: '22 min' },
  ];
  const doReassign = (nw) => { setWid(nw.id); setReassign(false); toast(`${c.name.split(' ')[0]} reassigned to ${nw.name.split(' ')[0]} · routes rebalanced`, 'green'); };
  return (
    <Screen padBottom={26} footer={
      <ActionBar>
        <button onClick={() => go('o_thread', { id: c.id })} className="btn btn-secondary" style={{ flex: 1 }}><Icon name="message" size={18} />Message</button>
        {c.balance > 0
          ? <button onClick={() => toast(`Nudge sent to ${c.name.split(' ')[0]}`, 'green')} className="btn btn-primary" style={{ flex: 1.3 }}><Icon name="nudge" size={18} />Send nudge</button>
          : <button onClick={() => go('o_new_invoice', { id: c.id })} className="btn btn-primary" style={{ flex: 1.3 }}><Icon name="invoice" size={18} />New invoice</button>}
      </ActionBar>}>
      <TopBar title={c.name} subtitle={`${c.addr} · ${c.city}`} onBack={() => go('o_customers')} />
      {/* balance */}
      <div style={{ padding: '4px 18px 0' }}>
        <div className="card" style={{ padding: 16, background: c.balance > 0 ? 'var(--alert-50)' : 'var(--green-50)', borderColor: c.balance > 0 ? '#F8D3C5' : 'var(--green-100)', display: 'flex', alignItems: 'center', gap: 13 }}>
          <Avatar name={c.name} size={46} />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 12, color: 'var(--ink-500)', fontWeight: 600 }}>{c.balance > 0 ? 'Outstanding' : 'All settled'}</div>
            {c.balance > 0 ? <Amount cents={c.balance} size={24} tone="due" /> : <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 24, color: 'var(--green-700)' }}>$0.00</div>}
          </div>
          <MVert vert={c.vert} />
        </div>
      </div>

      {/* billing history — why the balance is what it is */}
      <div style={{ padding: '16px 18px 0' }}>
        <SectionHead tone={c.balance > 0 ? 'alert' : 'green'} icon="ledger" style={{ marginBottom: 12 }}>Billing history</SectionHead>
        <div className="card" style={{ overflow: 'hidden' }}>
          {(() => {
            const n = c.cadence === 'Weekly' ? 4 : c.cadence === 'Monthly' ? 1 : 2;
            const moTotal = c.price * n;
            const dueMonths = c.balance > 0 ? Math.max(1, Math.round(c.balance / moTotal)) : 0;
            const rows = [
              { m: 'May 2026', v: n, cents: moTotal, status: dueMonths >= 1 ? 'unpaid' : 'paid' },
              { m: 'Apr 2026', v: n, cents: moTotal, status: dueMonths >= 2 ? 'unpaid' : 'paid', on: 'Apr 30' },
              { m: 'Mar 2026', v: c.cadence === 'Weekly' ? 5 : n, cents: c.price * (c.cadence === 'Weekly' ? 5 : n), status: 'paid', on: 'Mar 28' },
            ];
            const runRow = BILLRUN.rows.find(rr => rr.cid === c.id);
            return rows.map((r, i) => {
              const unpaid = r.status === 'unpaid';
              const linked = i === 0 && runRow;
              return (
                <div key={i} onClick={() => linked && go('o_invoice', { inv: runRow.inv })} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', borderTop: i ? '1px solid var(--ink-100)' : 'none', cursor: linked ? 'pointer' : 'default' }}>
                  <span style={{ width: 36, height: 36, borderRadius: 10, background: unpaid ? 'var(--alert-50)' : 'var(--green-50)', display: 'grid', placeItems: 'center', color: unpaid ? 'var(--alert-700)' : 'var(--green-700)', flexShrink: 0 }}><Icon name={unpaid ? 'clock' : 'check-circle'} size={18} /></span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 700, fontSize: 13.5 }}>{r.m}</div>
                    <div style={{ fontSize: 12, color: 'var(--ink-500)' }}>{linked ? `${runRow.inv} · ` : ''}{r.v} visits{unpaid ? ` · due` : r.on ? ` · paid ${r.on} via ${RAIL[c.rail].label}` : ''}</div>
                  </div>
                  <div style={{ textAlign: 'right', flexShrink: 0 }}>
                    <Amount cents={r.cents} size={14} tone={unpaid ? 'due' : 'plain'} />
                    <div style={{ marginTop: 3 }}>{unpaid ? <Chip tone="alert">Unpaid</Chip> : <Chip tone="done" icon="check">Paid</Chip>}</div>
                  </div>
                </div>
              );
            });
          })()}
          {c.balance > 0 && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderTop: '2px solid var(--ink-100)', background: 'var(--alert-50)' }}>
              <Icon name="nudge" size={17} style={{ color: 'var(--alert-700)', flexShrink: 0 }} />
              <div style={{ flex: 1, fontSize: 12.5, color: 'var(--alert-700)', fontWeight: 600 }}>{fmtMoney(c.balance)} outstanding across the months above.</div>
              <button onClick={() => toast(`Nudge sent to ${c.name.split(' ')[0]}`, 'green')} className="btn btn-primary" style={{ minHeight: 36, padding: '8px 13px', fontSize: 12.5 }}>Nudge</button>
            </div>
          )}
        </div>
      </div>

      <div style={{ padding: '16px 18px 0' }}>
        <SectionHead tone={v.tone} icon={v.icon} style={{ marginBottom: 12 }} meta={`${c.cadence} visits`}>{c.svc}</SectionHead>
        {/* pricing & billing schedule — rate, frequency, bill day */}
        <BillingCardM c={c} toast={toast} />
        {/* scheduled work & repairs — approved-in-advance loop */}
        <OwnerWorkCardM c={c} go={go} />
        {/* pool water chemistry — history + trust signal */}
        {c.vert === 'pool' && (
          <div onClick={() => go('o_chem', { id: c.id })} className="card" style={{ marginTop: 10, padding: 13, cursor: 'pointer', borderColor: 'var(--aqua-100)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
              <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--aqua-50)', display: 'grid', placeItems: 'center', color: 'var(--aqua-700)', flexShrink: 0 }}><Icon name="flask" size={20} /></span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 700, fontSize: 13.5 }}>Water chemistry</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-500)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>8 visits · CYA trending high</div>
              </div>
              <Icon name="chevron-right" size={17} style={{ color: 'var(--ink-300)', flexShrink: 0 }} />
            </div>
            <div style={{ marginTop: 10 }}><LsiChip lsi={computeLSI({ ph: 7.4, temp: 80, ch: 300, alk: 100 })} /></div>
          </div>
        )}
        {/* equipment on the record */}
        {c.vert === 'pool' && (
          <div onClick={() => go('o_equipment', { id: c.id })} className="card" style={{ marginTop: 10, padding: 13, display: 'flex', alignItems: 'center', gap: 11, cursor: 'pointer', borderColor: 'var(--aqua-100)' }}>
            <span style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--aqua-50)', display: 'grid', placeItems: 'center', color: 'var(--aqua-700)', flexShrink: 0 }}><Icon name="flask" size={20} /></span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 700, fontSize: 13.5 }}>Equipment</div>
              <div style={{ fontSize: 11.5, color: 'var(--ink-500)' }}>5 parts · pump, filter, heater, salt cell, robot</div>
            </div>
            <Icon name="chevron-right" size={17} style={{ color: 'var(--ink-300)', flexShrink: 0 }} />
          </div>
        )}
        <div className="card" style={{ marginTop: 10, padding: 13, display: 'flex', alignItems: 'center', gap: 11 }}>
          <span style={{ width: 36, height: 36, borderRadius: 10, background: 'var(--ink-50)', display: 'grid', placeItems: 'center', color: 'var(--ink-700)' }}><Icon name="eye-off" size={18} /></span>
          <div style={{ flex: 1, fontSize: 12.5, color: 'var(--ink-600,#6E6B60)' }}>Pros see <b style={{ color: v.c700 }}>"{c.label}"</b> — never the name or price.</div>
        </div>
      </div>
      {/* assigned worker */}
      <div style={{ padding: '16px 18px 0' }}>
        <SectionHead tone="green" icon="users" style={{ marginBottom: 12 }}>Assigned to</SectionHead>
        <div className="card" style={{ padding: 13, display: 'flex', alignItems: 'center', gap: 11 }}>
          <Avatar name={w.name} size={40} />
          <div style={{ flex: 1 }}><div style={{ fontWeight: 700, fontSize: 14 }}>{w.name}</div><div style={{ fontSize: 12, color: 'var(--ink-500)' }}>{w.role}</div></div>
          <button onClick={() => setReassign(true)} className="btn btn-ghost" style={{ minHeight: 36, padding: '7px 11px', fontSize: 12.5 }}>Reassign</button>
        </div>
      </div>

      {/* reassign sheet */}
      <Sheet open={reassign} onClose={() => setReassign(false)} title="Reassign to a different Pro">
        <div style={{ fontSize: 13, color: 'var(--ink-500)', marginTop: -6, marginBottom: 14 }}>{c.name.split(' ')[0]}'s {v.name.toLowerCase()} service will move to the new Pro's route. Both Pros are notified and routes rebalance automatically.</div>
        <div style={{ display: 'grid', gap: 9 }}>
          {WORKERS.map(nw => {
            const on = wid === nw.id;
            return (
              <button key={nw.id} onClick={() => on ? null : doReassign(nw)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', borderRadius: 'var(--radius-lg)', border: on ? '2px solid var(--green-500)' : '1.5px solid var(--ink-100)', background: on ? 'var(--green-50)' : '#fff', cursor: on ? 'default' : 'pointer', textAlign: 'left' }}>
                <Avatar name={nw.name} size={42} />
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 700, fontSize: 15 }}>{nw.name}{nw.you ? ' · you' : ''}</div>
                  <div style={{ fontSize: 12.5, color: 'var(--ink-500)' }}>{nw.role} · {nw.today} stops today</div>
                </div>
                {on
                  ? <span style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--green-700)', display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="check-circle" size={15} />Current</span>
                  : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 12.5, fontWeight: 700, color: 'var(--ink-700)' }}>Assign<Icon name="arrow-right" size={15} /></span>}
              </button>
            );
          })}
        </div>
      </Sheet>
      {/* recent visits */}
      <div style={{ padding: '16px 18px 0' }}>
        <SectionHead tone="blue" icon="shield" style={{ marginBottom: 12 }} meta={`${w.name.split(' ')[0]} · last 3`}>Recent verified visits</SectionHead>
        <div className="card" style={{ overflow: 'hidden' }}>
          {visits.map((vi, i) => (
            <div key={i} onClick={() => go('h_visit', { id: 'v2' })} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', borderTop: i ? '1px solid var(--ink-100)' : 'none', cursor: 'pointer' }}>
              <div style={{ display: 'flex', gap: 3, flexShrink: 0 }}>
                <PhotoTile scene={scene + '-before'} height={42} radius={9} style={{ width: 32 }} />
                <PhotoTile scene={scene === 'pool' ? 'pool-clean' : 'lawn-after'} height={42} radius={9} style={{ width: 32 }} />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 700, fontSize: 13.5 }}>{vi.d}</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--ink-500)', marginTop: 1 }}><Icon name="clock" size={12} />{vi.tin}–{vi.tout} · {vi.dur} on-site</div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 4, flexShrink: 0 }}>
                <Amount cents={c.price} size={13} />
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10, fontWeight: 700, color: 'var(--blue-700)' }}><Icon name="shield" size={11} strokeWidth={2.4} />Verified</span>
              </div>
            </div>
          ))}
        </div>
      </div>
    </Screen>
  );
}

/* ============================== OWNER · FAB SHEET ==================== */
function OwnerFabSheet({ open, onClose, go, toast }) {
  const items = [
    ['plus', 'green', 'Add customer', () => { go('o_new_customer'); }],
    ['invoice', 'green', 'New invoice', () => { go('o_new_invoice'); }],
    ['route', 'blue', 'Dispatch routes', () => { go('o_routes'); }],
    ['nudge', 'alert', 'Nudge all unpaid', () => { go('o_money'); }],
  ];
  return (
    <Sheet open={open} onClose={onClose} title="Quick actions">
      <div style={{ display: 'grid', gap: 9 }}>
        {items.map(([ic, tone, label, fn]) => (
          <button key={label} onClick={() => { onClose(); fn(); }} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '13px 14px', borderRadius: 'var(--radius-lg)', border: '1px solid var(--ink-100)', background: '#fff', cursor: 'pointer', textAlign: 'left' }}>
            <IconBadge icon={ic} tone={tone} size={40} />
            <span style={{ fontWeight: 700, fontSize: 15 }}>{label}</span>
            <Icon name="chevron-right" size={18} style={{ marginLeft: 'auto', color: 'var(--ink-300)' }} />
          </button>
        ))}
      </div>
    </Sheet>
  );
}

Object.assign(window, { OwnerHome, OwnerMoneyM, OwnerInbox, OwnerThread, OwnerCustomersM, OwnerCustomerM, OwnerFabSheet, MVert });
