// screens-account.jsx — Profile, Vouchers, Login (OTP), AgeGate

// ─────────────────────────────────────────────────────────────
// PROFILE
// ─────────────────────────────────────────────────────────────
const ScreenProfile = ({ user, onBack, onLogin, onLogout, onOpenVouchers, onOpenHistory, onOpenKtp, navbar }) => {
  if (!user) {
    return <ScreenLoginPrompt onBack={onBack} onLogin={onLogin} />;
  }
  return (
    <div className="app">
      <Topbar title="Akun Saya" />
      <div className="app-scroll">
        {/* Header */}
        <div style={{
          margin: '0 16px 14px',
          padding: 16, borderRadius: 18,
          background: 'linear-gradient(135deg, var(--eb-navy) 0%, var(--eb-navy-700) 100%)',
          color: '#fff',
          position: 'relative', overflow: 'hidden',
        }}>
          {/* bee dot pattern */}
          <div style={{
            position: 'absolute', inset: 0, opacity: 0.18,
            backgroundImage: 'radial-gradient(circle, var(--eb-amber) 1px, transparent 1px)',
            backgroundSize: '20px 20px',
          }} />
          <div style={{ position: 'relative', display: 'flex', alignItems: 'center', gap: 14 }}>
            <div style={{
              width: 60, height: 60, borderRadius: 18,
              background: 'var(--eb-amber)', color: 'var(--eb-navy)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              fontFamily: 'IBM Plex Mono', fontWeight: 700, fontSize: 22,
              boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.4)',
            }}>{user.initials}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 17, fontWeight: 700 }}>{user.name}</div>
              <div style={{ fontSize: 12, opacity: 0.7, marginTop: 2 }}>{user.phone}</div>
              <div style={{
                display: 'inline-flex', alignItems: 'center', gap: 4, marginTop: 6,
                fontSize: 10, padding: '2px 8px', borderRadius: 999,
                background: 'rgba(31,138,91,0.3)', border: '1px solid rgba(31,138,91,0.5)',
                fontWeight: 600,
              }}>
                <Icon name="shield" size={10} stroke={2.5} />
                Verified 21+
              </div>
            </div>
          </div>
          <div style={{
            position: 'relative', marginTop: 14, paddingTop: 12,
            borderTop: '1px solid rgba(255,255,255,0.15)',
            display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8,
          }}>
            <div>
              <div style={{ fontSize: 10, opacity: 0.6, textTransform: 'uppercase', letterSpacing: '0.04em', whiteSpace: 'nowrap' }}>Transaksi</div>
              <div style={{ fontFamily: 'IBM Plex Mono', fontWeight: 700, fontSize: 18, marginTop: 2 }}>{user.transactions}</div>
            </div>
            <div>
              <div style={{ fontSize: 10, opacity: 0.6, textTransform: 'uppercase', letterSpacing: '0.04em', whiteSpace: 'nowrap' }}>Voucher</div>
              <div style={{ fontFamily: 'IBM Plex Mono', fontWeight: 700, fontSize: 18, marginTop: 2 }}>{user.vouchers.length}</div>
            </div>
            <div>
              <div style={{ fontSize: 10, opacity: 0.6, textTransform: 'uppercase', letterSpacing: '0.04em', whiteSpace: 'nowrap' }}>Member</div>
              <div style={{ fontFamily: 'IBM Plex Mono', fontWeight: 700, fontSize: 18, marginTop: 2 }}>{user.joinedDays}<span style={{ fontSize: 11, opacity: 0.7, marginLeft: 3, fontFamily: 'Inter' }}>hari</span></div>
            </div>
          </div>
        </div>

        {/* Voucher highlight */}
        <div style={{ padding: '0 16px 14px' }}>
          <button onClick={onOpenVouchers} className="voucher-card" style={{ width: '100%', textAlign: 'left' }}>
            <div className="voucher-icon">
              <Icon name="ticket" size={26} />
            </div>
            <div style={{ flex: 1, paddingLeft: 12 }}>
              <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--eb-navy)', textTransform: 'uppercase', letterSpacing: '0.06em', opacity: 0.65 }}>
                Voucher saya
              </div>
              <div className="price" style={{ fontSize: 18, color: 'var(--eb-navy)', marginTop: 2 }}>
                {fmtRp(user.vouchers.reduce((s,v) => s+v.amount, 0))}
              </div>
              <div style={{ fontSize: 11, color: 'var(--eb-navy)', opacity: 0.65, marginTop: 2 }}>
                {user.vouchers.length} voucher aktif · Lihat semua
              </div>
            </div>
            <Icon name="chevron" size={16} color="var(--eb-navy)" />
          </button>
        </div>

        {/* Menu */}
        <div style={{ padding: '0 16px 14px' }}>
          <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
            <MenuRow icon="package" label="Riwayat transaksi" detail="23 transaksi" onClick={onOpenHistory} />
            <MenuRow icon="shield" label="Verifikasi KTP"
              detail={user.verifiedAge ? 'Terverifikasi' : 'Belum diverifikasi'}
              detailColor={user.verifiedAge ? 'var(--eb-success)' : 'var(--eb-warn)'}
              onClick={onOpenKtp} />
          </div>
        </div>

        <div style={{ padding: '0 16px 14px' }}>
          <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
            <MenuRow icon="bell" label="Notifikasi" />
            <MenuRow icon="help" label="Bantuan & FAQ" />
            <MenuRow icon="info" label={`Tentang ${(window.BRAND && window.BRAND.name) || 'Elektrobee'}`} />
          </div>
        </div>

        <div style={{ padding: '0 16px 24px' }}>
          <button onClick={onLogout} className="btn btn-ghost btn-block" style={{ color: 'var(--eb-danger)' }}>
            Keluar
          </button>
          <div style={{ textAlign: 'center', fontSize: 11, color: 'var(--eb-faint)', marginTop: 14, fontFamily: 'IBM Plex Mono' }}>
            v0.1.0 · {(window.BRAND && window.BRAND.name) || 'Elektrobee'} MVP
          </div>
        </div>

        <div style={{ height: 30 }} />
      </div>
      {navbar}
    </div>
  );
};

const MenuRow = ({ icon, label, detail, detailColor, onClick }) => (
  <button onClick={onClick} style={{
    width: '100%',
    display: 'flex', alignItems: 'center', gap: 12,
    padding: '13px 14px', textAlign: 'left',
    borderBottom: '1px solid var(--eb-line-soft)',
  }}>
    <div style={{
      width: 32, height: 32, borderRadius: 8,
      background: 'var(--eb-bg-muted)', color: 'var(--eb-navy)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
    }}>
      <Icon name={icon} size={16} />
    </div>
    <span style={{
      flex: 1, fontSize: 14, fontWeight: 500, color: 'var(--eb-ink)',
      minWidth: 0, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
    }}>{label}</span>
    {detail && (
      <span style={{
        fontSize: 12, color: detailColor || 'var(--eb-muted)',
        whiteSpace: 'nowrap', flexShrink: 0,
      }}>{detail}</span>
    )}
    <Icon name="chevron" size={14} color="var(--eb-faint)" />
  </button>
);

// ─────────────────────────────────────────────────────────────
// LOGIN PROMPT — for guest users
// ─────────────────────────────────────────────────────────────
const ScreenLoginPrompt = ({ onBack, onLogin }) => {
  return (
    <div className="app">
      <Topbar title="Akun" onBack={onBack} />
      <div className="app-scroll">
        <div style={{ padding: '24px 24px 14px', textAlign: 'center' }}>
          <div style={{
            display: 'inline-flex', padding: 18, borderRadius: 24,
            background: 'var(--eb-amber-soft)', color: 'var(--eb-amber-strong)',
          }}>
            <Icon name="ticket" size={36} />
          </div>
          <div style={{ fontSize: 22, fontWeight: 700, marginTop: 18, color: 'var(--eb-ink)', letterSpacing: '-0.02em', textWrap: 'pretty' }}>
            Daftar untuk dapat diskon
          </div>
          <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.45, textWrap: 'pretty' }}>
            Klaim voucher penggantian, simpan riwayat belanja, dan akses produk khusus 21+.
            Cuma 30 detik pakai nomor HP.
          </div>
        </div>

        <div style={{ padding: '14px 16px 0' }}>
          <div className="card" style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
            {[
              { icon: 'ticket', t: 'Voucher otomatis', d: 'Setiap barang yang gagal keluar diganti voucher' },
              { icon: 'sparkle', t: 'Diskon & promo', d: 'Rp 10.000 untuk transaksi pertama setelah daftar' },
              { icon: 'shield', t: 'Akses 21+', d: 'Beli produk dewasa setelah verifikasi KTP' },
              { icon: 'clock', t: 'Belanja lebih cepat', d: 'Pesan ulang favorit cuma 1 tap' },
            ].map((b, i) => (
              <div key={i} style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
                <div style={{
                  width: 28, height: 28, borderRadius: 8,
                  background: 'var(--eb-navy)', color: 'var(--eb-amber)',
                  display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                }}>
                  <Icon name={b.icon} size={14} />
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 13, fontWeight: 600 }}>{b.t}</div>
                  <div style={{ fontSize: 11, color: 'var(--eb-muted)', marginTop: 2 }}>{b.d}</div>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div style={{ height: 90 }} />
      </div>

      <div className="bottom-bar">
        <button className="btn btn-primary btn-block" onClick={onLogin}>
          <Icon name="phone" size={18} />
          Daftar / Masuk dengan No. HP
        </button>
        <div style={{ fontSize: 10, color: 'var(--eb-faint)', textAlign: 'center', marginTop: 8, lineHeight: 1.45 }}>
          Dengan daftar kamu setuju dengan <u>Syarat & Ketentuan</u> dan <u>Kebijakan Privasi</u>
        </div>
      </div>
    </div>
  );
};

// ─────────────────────────────────────────────────────────────
// VOUCHERS
// ─────────────────────────────────────────────────────────────
const ScreenVouchers = ({ user, onBack, navbar }) => {
  const [tab, setTab] = React.useState('active');
  const [code, setCode] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [outcome, setOutcome] = React.useState(null);
  const [claimedToast, setClaimedToast] = React.useState(null);
  const [newIds, setNewIds] = React.useState([]);
  const [claimed, setClaimed] = React.useState([]);

  const vouchers = [...claimed, ...(user?.vouchers || [])];

  const submit = () => {
    if (!code.trim() || submitting) return;
    setSubmitting(true);
    setOutcome(null);
    setTimeout(() => {
      const res = lookupVoucherCode(code);
      setSubmitting(false);
      setOutcome(res);
      if (res && res.ok) {
        const id = 'v-' + Date.now();
        const newV = { id, amount: res.amount, reason: res.reason, expires: res.expires, code: code.trim().toUpperCase(), active: true };
        setClaimed(prev => [newV, ...prev]);
        setNewIds(prev => [...prev, id]);
        setClaimedToast({ amount: res.amount });
        setCode('');
        setTab('active');
        setTimeout(() => setClaimedToast(null), 3200);
        setTimeout(() => setNewIds(prev => prev.filter(x => x !== id)), 5000);
      }
    }, 700);
  };

  const errMsg = outcome && !outcome.ok ? (
    outcome.error === 'not_found'     ? 'Kode tidak ditemukan. Periksa kembali.' :
    outcome.error === 'expired'       ? `Kode ini kedaluwarsa pada ${outcome.since}.` :
    outcome.error === 'already'       ? `Kode sudah kamu klaim pada ${outcome.since}.` :
    outcome.error === 'max_per_user'  ? 'Kamu sudah mencapai batas klaim kode ini.' :
    outcome.error === 'campaign_full' ? 'Kuota kode ini sudah habis.' :
    'Terjadi kesalahan.'
  ) : null;

  return (
    <div className="app">
      <Topbar title="Voucher Saya" sub={`${vouchers.length} voucher aktif`} onBack={onBack} />

      <div className="app-scroll">
        {claimedToast && (
          <div className="voucher-toast">
            <div style={{
              width: 32, height: 32, borderRadius: 16,
              background: 'var(--eb-success)', color: '#fff',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              flexShrink: 0,
            }}>
              <Icon name="check" size={18} stroke={3} />
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 13 }}>Berhasil diklaim</div>
              <div style={{ fontSize: 11, opacity: 0.75 }}>Voucher {fmtRp(claimedToast.amount)} sudah masuk</div>
            </div>
          </div>
        )}

        <div style={{ padding: '4px 16px 14px' }}>
          <div className="claim-card">
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
              <div style={{
                width: 34, height: 34, borderRadius: 9,
                background: 'var(--eb-amber)', color: 'var(--eb-navy)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                flexShrink: 0,
              }}>
                <Icon name="ticket" size={18} />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--eb-ink)' }}>Punya kode voucher?</div>
                <div style={{ fontSize: 11, color: 'var(--eb-muted)', marginTop: 1 }}>Masukkan kode untuk klaim langsung.</div>
              </div>
            </div>

            <div className={`claim-input ${outcome && !outcome.ok ? 'error' : ''}`}>
              <input
                type="text"
                placeholder="WELCOME10K"
                value={code}
                onChange={e => { setCode(e.target.value.toUpperCase()); if (outcome) setOutcome(null); }}
                onKeyDown={e => e.key === 'Enter' && submit()}
                autoCapitalize="characters"
                spellCheck={false}
                disabled={submitting}
              />
              <button onClick={submit} disabled={!code.trim() || submitting}
                className="btn btn-primary btn-sm" style={{ height: 36, flexShrink: 0, minWidth: 78 }}>
                {submitting ? (
                  <span className="loader" style={{ color: 'var(--eb-navy)' }}>
                    <span /><span /><span />
                  </span>
                ) : 'Klaim'}
              </button>
            </div>

            {errMsg && (
              <div style={{
                marginTop: 8, padding: '8px 10px',
                background: 'var(--eb-danger-soft)', borderRadius: 9,
                color: 'var(--eb-danger)', fontSize: 12, fontWeight: 500,
                display: 'flex', alignItems: 'center', gap: 6,
              }}>
                <Icon name="info" size={14} />
                <span>{errMsg}</span>
              </div>
            )}

            <div style={{ fontSize: 10, color: 'var(--eb-faint)', marginTop: 10, lineHeight: 1.5 }}>
              Coba kode demo: <b>WELCOME10K</b>, <b>MALAM5RB</b>, <b>EXPIRED2024</b>, <b>EB5K-9JX2</b>
            </div>
          </div>
        </div>

        <div className="tabs">
          <button className="tab" data-active={tab === 'active'} onClick={() => setTab('active')}>Aktif ({vouchers.length})</button>
          <button className="tab" data-active={tab === 'used'} onClick={() => setTab('used')}>Terpakai</button>
          <button className="tab" data-active={tab === 'expired'} onClick={() => setTab('expired')}>Kedaluwarsa</button>
        </div>

        <div style={{ padding: '14px 16px 30px', display: 'flex', flexDirection: 'column', gap: 10 }}>
          {tab === 'active' && vouchers.map(v => (
            <div key={v.id} className="voucher-card" style={{
              background: 'linear-gradient(135deg, #FDF1D6 0%, #FFD58A 100%)',
              position: 'relative',
            }}>
              {newIds.includes(v.id) && (
                <span className="voucher-new-pill">BARU</span>
              )}
              <div className="voucher-icon">
                <Icon name="ticket" size={26} />
              </div>
              <div style={{ flex: 1, paddingLeft: 12 }}>
                <div className="price" style={{ fontSize: 20, color: 'var(--eb-navy)' }}>{fmtRp(v.amount)}</div>
                <div style={{ fontSize: 11, color: 'var(--eb-navy)', opacity: 0.75, marginTop: 2 }}>{v.reason}</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6 }}>
                  <span style={{
                    padding: '2px 6px', borderRadius: 4,
                    background: 'var(--eb-navy)', color: 'var(--eb-amber)',
                    fontFamily: 'IBM Plex Mono', fontSize: 9, fontWeight: 700,
                  }}>{v.code}</span>
                  <span style={{ fontSize: 10, color: 'var(--eb-navy)', opacity: 0.55 }}>s/d {v.expires}</span>
                </div>
              </div>
            </div>
          ))}
          {tab === 'used' && (
            <div className="empty"><div>Belum ada voucher terpakai.</div></div>
          )}
          {tab === 'expired' && (
            <div className="empty"><div>Belum ada voucher kedaluwarsa.</div></div>
          )}

          <div style={{ marginTop: 14, padding: 14, borderRadius: 14, background: 'var(--eb-bg-muted)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
              <Icon name="info" size={16} color="var(--eb-muted)" />
              <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--eb-muted)', whiteSpace: 'nowrap' }}>Cara pakai voucher</span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--eb-muted)', lineHeight: 1.5 }}>
              Pilih voucher saat checkout. Hanya 1 voucher per transaksi. Jika ada produk gagal dispense,
              voucher penggantian otomatis masuk dalam beberapa detik.
            </div>
          </div>
        </div>
      </div>
      {navbar}
    </div>
  );
};

// ─────────────────────────────────────────────────────────────
// AGE GATE SHEET — when guest taps 21+ item
// ─────────────────────────────────────────────────────────────
const AgeGateSheet = ({ open, product, onClose, onRegister, isLoggedIn }) => {
  if (!open) return null;
  return (
    <BottomSheet open={open} onClose={onClose}>
      <div style={{ padding: '4px 24px 24px' }}>
        <div style={{
          display: 'inline-flex', padding: 14, borderRadius: 18,
          background: '#2C3447', color: 'var(--eb-amber)',
        }}>
          <Icon name="shield" size={28} />
        </div>
        <div style={{ fontSize: 20, fontWeight: 700, marginTop: 14, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
          Verifikasi usia diperlukan
        </div>
        <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.5, textWrap: 'pretty' }}>
          {product?.name && <><b style={{ color: 'var(--eb-ink)' }}>{product.name}</b> termasuk produk khusus 21+. </>}
          Sesuai peraturan, kamu perlu verifikasi usia dengan KTP sebelum bisa membeli.
        </div>

        <div style={{
          marginTop: 18, padding: 14, borderRadius: 14,
          background: 'var(--eb-bg-muted)',
          display: 'flex', flexDirection: 'column', gap: 12,
        }}>
          {[
            { n: 1, t: isLoggedIn ? 'Upload foto KTP' : 'Daftar dengan No. HP' },
            { n: 2, t: isLoggedIn ? 'Verifikasi otomatis 30 detik' : 'Upload foto KTP' },
            { n: 3, t: 'Beli produk 21+ kapan pun' },
          ].map(s => (
            <div key={s.n} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <span style={{
                width: 24, height: 24, borderRadius: 12,
                background: 'var(--eb-navy)', color: '#fff',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontWeight: 700, fontSize: 11, fontFamily: 'IBM Plex Mono',
              }}>{s.n}</span>
              <span style={{ fontSize: 13, color: 'var(--eb-ink-2)' }}>{s.t}</span>
            </div>
          ))}
        </div>

        <div style={{ display: 'flex', gap: 10, marginTop: 18 }}>
          <button className="btn btn-ghost" style={{ flex: 1 }} onClick={onClose}>Nanti saja</button>
          <button className="btn btn-primary" style={{ flex: 1.4 }} onClick={onRegister}>
            {isLoggedIn ? 'Verifikasi sekarang' : 'Daftar — 30 detik'}
          </button>
        </div>
        <div style={{ fontSize: 10, color: 'var(--eb-faint)', textAlign: 'center', marginTop: 12, lineHeight: 1.45 }}>
          KTP hanya disimpan untuk verifikasi usia. Foto dapat dihapus kapan saja.
        </div>
      </div>
    </BottomSheet>
  );
};

// ─────────────────────────────────────────────────────────────
// LOGIN — OTP flow (one screen, two states)
// ─────────────────────────────────────────────────────────────
const ScreenLogin = ({ onBack, onLoggedIn }) => {
  const [step, setStep] = React.useState('phone'); // phone | otp
  const [phone, setPhone] = React.useState('');
  const [otp, setOtp] = React.useState('');
  const [resend, setResend] = React.useState(30);

  React.useEffect(() => {
    if (step === 'otp' && resend > 0) {
      const t = setTimeout(() => setResend(r => r - 1), 1000);
      return () => clearTimeout(t);
    }
  }, [step, resend]);

  const valid = phone.replace(/\D/g, '').length >= 9;

  return (
    <div className="app">
      <Topbar title={step === 'phone' ? 'Masuk / Daftar' : 'Verifikasi OTP'} onBack={() => step === 'otp' ? setStep('phone') : onBack()} />
      <div className="app-scroll" style={{ padding: '8px 20px 30px' }}>
        {step === 'phone' && (
          <>
            <div style={{ fontSize: 20, fontWeight: 700, marginTop: 8, color: 'var(--eb-ink)', letterSpacing: '-0.02em', textWrap: 'pretty' }}>
              Masukkan nomor HP
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 6 }}>
              Kami kirim kode OTP via SMS. Tidak perlu password.
            </div>

            <div style={{
              marginTop: 24, padding: 0,
              border: '1.5px solid var(--eb-line)', borderRadius: 14,
              background: 'var(--eb-bg-elev)',
              display: 'flex', alignItems: 'center', overflow: 'hidden',
            }}>
              <div style={{
                padding: '14px 14px', borderRight: '1px solid var(--eb-line)',
                fontFamily: 'IBM Plex Mono', fontWeight: 600, color: 'var(--eb-ink)',
              }}>+62</div>
              <input
                type="tel"
                placeholder="812 3456 7890"
                value={phone}
                onChange={e => setPhone(e.target.value)}
                autoFocus
                style={{
                  flex: 1, height: 50, padding: '0 14px',
                  border: 0, background: 'transparent',
                  font: 'inherit', fontSize: 18, fontFamily: 'IBM Plex Mono',
                  color: 'var(--eb-ink)', letterSpacing: '0.02em',
                  outline: 'none',
                }}
              />
            </div>

            <div style={{ marginTop: 28 }}>
              <button className="btn btn-primary btn-block" disabled={!valid} onClick={() => setStep('otp')}>
                Kirim OTP
                <Icon name="arrow-right" size={16} stroke={2.5} />
              </button>
            </div>

            <div style={{ marginTop: 18, fontSize: 11, color: 'var(--eb-faint)', textAlign: 'center', lineHeight: 1.45 }}>
              Dengan melanjutkan kamu setuju dengan <u>Syarat & Ketentuan</u><br/>dan <u>Kebijakan Privasi</u> {(window.BRAND && window.BRAND.name) || 'Elektrobee'}.
            </div>
          </>
        )}
        {step === 'otp' && (
          <>
            <div style={{ fontSize: 20, fontWeight: 700, marginTop: 8, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
              Masukkan kode OTP
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 6 }}>
              Kami sudah kirim 6 digit ke <b style={{ color: 'var(--eb-ink)' }}>+62 {phone}</b>
            </div>

            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 8,
              marginTop: 28,
            }}>
              {Array.from({ length: 6 }).map((_, i) => {
                const ch = otp[i] || '';
                const active = i === otp.length;
                return (
                  <div key={i} style={{
                    aspectRatio: '1 / 1.2',
                    border: `1.5px solid ${active ? 'var(--eb-amber)' : 'var(--eb-line)'}`,
                    borderRadius: 12,
                    background: 'var(--eb-bg-elev)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontFamily: 'IBM Plex Mono', fontWeight: 700, fontSize: 24,
                    color: 'var(--eb-navy)',
                    boxShadow: active ? '0 0 0 4px rgba(var(--eb-amber-rgb), 0.18)' : 'none',
                    transition: 'all 0.12s ease',
                  }}>
                    {ch}
                  </div>
                );
              })}
            </div>

            {/* Numpad */}
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8,
              marginTop: 28,
            }}>
              {['1','2','3','4','5','6','7','8','9','','0','⌫'].map((k, i) => {
                if (k === '') return <div key={i} />;
                return (
                  <button key={i} onClick={() => {
                    if (k === '⌫') setOtp(o => o.slice(0, -1));
                    else if (otp.length < 6) {
                      const newOtp = otp + k;
                      setOtp(newOtp);
                      if (newOtp.length === 6) {
                        setTimeout(onLoggedIn, 400);
                      }
                    }
                  }} style={{
                    height: 52, borderRadius: 14,
                    background: 'var(--eb-bg-elev)',
                    border: '1px solid var(--eb-line-soft)',
                    fontFamily: 'IBM Plex Mono', fontWeight: 600, fontSize: 22,
                    color: 'var(--eb-ink)',
                  }}>
                    {k}
                  </button>
                );
              })}
            </div>

            <div style={{ marginTop: 18, textAlign: 'center', fontSize: 12, color: 'var(--eb-muted)' }}>
              {resend > 0 ? (
                <>Kirim ulang OTP dalam {resend}s</>
              ) : (
                <button style={{ color: 'var(--eb-info)', fontWeight: 600 }} onClick={() => setResend(30)}>
                  Kirim ulang OTP
                </button>
              )}
            </div>
          </>
        )}
      </div>
    </div>
  );
};

// ─────────────────────────────────────────────────────────────
// VOUCHER PICKER SHEET — at checkout
// ─────────────────────────────────────────────────────────────
const VoucherPickerSheet = ({ open, user, current, onPick, onClose }) => {
  if (!open || !user) return null;
  return (
    <BottomSheet open={open} onClose={onClose}>
      <div style={{ padding: '4px 16px 14px' }}>
        <div style={{ fontSize: 18, fontWeight: 700, color: 'var(--eb-ink)', padding: '6px 4px 12px', letterSpacing: '-0.01em' }}>
          Pilih voucher
        </div>
        <button onClick={() => onPick(null)} className="card" style={{
          width: '100%', padding: 12, marginBottom: 10,
          display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left',
          borderColor: !current ? 'var(--eb-navy)' : 'var(--eb-line-soft)',
          borderWidth: !current ? 2 : 1,
          borderStyle: 'solid',
        }}>
          <div style={{
            width: 18, height: 18, borderRadius: 9,
            border: `2px solid ${!current ? 'var(--eb-navy)' : 'var(--eb-line)'}`,
            background: !current ? 'var(--eb-navy)' : 'transparent',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            flexShrink: 0,
          }}>
            {!current && <span style={{ width: 6, height: 6, background: '#fff', borderRadius: 3 }} />}
          </div>
          <span style={{ fontSize: 14, fontWeight: 600 }}>Tidak pakai voucher</span>
        </button>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {user.vouchers.map(v => {
            const selected = current === v.id;
            return (
              <button key={v.id} onClick={() => onPick(v.id)} style={{
                padding: 0, textAlign: 'left',
                border: 'none', background: 'transparent',
              }}>
                <div className="voucher-card" style={{
                  background: 'linear-gradient(135deg, #FDF1D6 0%, #FFD58A 100%)',
                  boxShadow: selected ? '0 0 0 2px var(--eb-navy)' : 'none',
                }}>
                  <div className="voucher-icon">
                    <Icon name="ticket" size={22} />
                  </div>
                  <div style={{ flex: 1, paddingLeft: 12 }}>
                    <div className="price" style={{ fontSize: 17, color: 'var(--eb-navy)' }}>{fmtRp(v.amount)}</div>
                    <div style={{ fontSize: 11, color: 'var(--eb-navy)', opacity: 0.7, marginTop: 2 }}>{v.reason}</div>
                  </div>
                  <div style={{
                    width: 18, height: 18, borderRadius: 9,
                    border: `2px solid ${selected ? 'var(--eb-navy)' : 'rgba(var(--eb-navy-rgb), 0.3)'}`,
                    background: selected ? 'var(--eb-navy)' : 'transparent',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    flexShrink: 0, marginRight: 4,
                  }}>
                    {selected && <span style={{ width: 6, height: 6, background: '#fff', borderRadius: 3 }} />}
                  </div>
                </div>
              </button>
            );
          })}
        </div>
        <div style={{ marginTop: 14, padding: '4px 4px 12px', fontSize: 11, color: 'var(--eb-faint)', textAlign: 'center' }}>
          Hanya 1 voucher per transaksi
        </div>
      </div>
    </BottomSheet>
  );
};

// ─────────────────────────────────────────────────────────────
// RIWAYAT (transaction history)
// ─────────────────────────────────────────────────────────────
const ScreenRiwayat = ({ user, onBack, onOpenTx, onLogin, navbar }) => {
  if (!user) {
    return (
      <div className="app">
        <Topbar title="Riwayat" onBack={onBack} />
        <div className="empty" style={{ paddingTop: 60 }}>
          <Icon name="package" size={32} color="var(--eb-faint)" />
          <div style={{ marginTop: 10, fontWeight: 600, color: 'var(--eb-ink)' }}>Belum ada riwayat</div>
          <div style={{ fontSize: 12, marginTop: 4 }}>Daftar untuk simpan riwayat transaksi</div>
          <button className="btn btn-primary btn-sm" onClick={onLogin} style={{ marginTop: 16 }}>
            Masuk / Daftar
          </button>
        </div>
        {navbar}
      </div>
    );
  }

  const [q, setQ] = React.useState('');
  const [filter, setFilter] = React.useState('all'); // all | perhatian | voucher | cl-<id>
  const [sort, setSort] = React.useState('newest');  // newest | oldest | amount
  const [sortOpen, setSortOpen] = React.useState(false);
  const [monthIdx, setMonthIdx] = React.useState(0); // 0 = Mei (current), 1 = April, 2 = Maret
  const months = ['Mei 2026', 'April 2026', 'Maret 2026'];
  const currentMonth = months[monthIdx];

  // For prototype: only show data for current month; empty for others
  const monthHasData = monthIdx === 0;
  const allTx = monthHasData ? MOCK_RECENT_TX : [];

  // Derive adaptive chips
  const refundCount = allTx.filter(tx => tx.vouchered > 0 || tx.status === 'partial').length;
  const clusterCounts = allTx.reduce((acc, tx) => {
    acc[tx.cluster] = (acc[tx.cluster] || 0) + 1;
    return acc;
  }, {});
  const clusterChips = Object.entries(clusterCounts).map(([name, count]) => ({ id: 'cl-' + name, label: name, count }));

  // Filter
  let txs = allTx;
  if (q.trim()) {
    const needle = q.trim().toLowerCase();
    txs = txs.filter(tx =>
      tx.items.toLowerCase().includes(needle) ||
      tx.cluster.toLowerCase().includes(needle) ||
      tx.at.toLowerCase().includes(needle)
    );
  }
  if (filter === 'refund') txs = txs.filter(tx => tx.vouchered > 0 || tx.status === 'partial');
  else if (filter.startsWith('cl-')) txs = txs.filter(tx => ('cl-' + tx.cluster) === filter);

  // Sort
  // For prototype, "newest" matches current array order. "oldest" reverses. "amount" sorts by total desc.
  if (sort === 'oldest') txs = [...txs].reverse();
  else if (sort === 'amount') txs = [...txs].sort((a, b) => b.total - a.total);

  const sortLabel = { newest: 'Terbaru', oldest: 'Terlama', amount: 'Nominal terbesar' }[sort];

  // Group by day (only when sorting by date; flat list for amount)
  const grouped = sort === 'amount' ? null : txs.reduce((acc, tx) => {
    const day = tx.at.split('·')[0].trim();
    (acc[day] = acc[day] || []).push(tx);
    return acc;
  }, {});

  return (
    <div className="app">
      <Topbar title="Riwayat" sub={`${allTx.length} transaksi · ${currentMonth}`} onBack={onBack} />

      <div className="app-scroll">
        {/* Search */}
        <div style={{ padding: '0 16px 10px' }}>
          <div className="search" style={{ margin: 0 }}>
            <Icon name="search" size={18} color="var(--eb-faint)" />
            <input
              placeholder="Cari produk, mesin, tanggal…"
              value={q}
              onChange={e => setQ(e.target.value)}
            />
            {q && (
              <button onClick={() => setQ('')}>
                <Icon name="close" size={16} color="var(--eb-faint)" />
              </button>
            )}
          </div>
        </div>

        {/* Month switcher + Sort */}
        <div style={{
          padding: '0 16px 10px',
          display: 'flex', alignItems: 'center', gap: 8,
        }}>
          <div className="month-switcher">
            <button
              className="month-switch-btn"
              onClick={() => setMonthIdx(i => i + 1)}
              disabled={monthIdx >= months.length - 1}
              aria-label="Bulan sebelumnya"
            >
              <Icon name="back" size={16} stroke={2.5} />
            </button>
            <span className="month-switch-label">
              {currentMonth}
              <span className="month-switch-count">{allTx.length}</span>
            </span>
            <button
              className="month-switch-btn"
              onClick={() => setMonthIdx(i => i - 1)}
              disabled={monthIdx <= 0}
              aria-label="Bulan selanjutnya"
            >
              <Icon name="chevron" size={16} stroke={2.5} />
            </button>
          </div>
          <button className="sort-btn" onClick={() => setSortOpen(true)}>
            <Icon name="sort" size={14} />
            <span>{sortLabel}</span>
          </button>
        </div>

        {/* Adaptive filter chips */}
        {allTx.length > 0 && (
          <div className="chip-row" style={{ padding: '2px 16px 12px' }}>
            <button className="chip" data-active={filter === 'all'} onClick={() => setFilter('all')}>
              Semua ({allTx.length})
            </button>
            {refundCount > 0 && (
              <button className="chip"
                data-active={filter === 'refund'}
                onClick={() => setFilter('refund')}>
                <Icon name="ticket" size={12} />
                Refund ({refundCount})
              </button>
            )}
            {clusterChips.map(c => (
              <button key={c.id} className="chip"
                data-active={filter === c.id}
                onClick={() => setFilter(c.id)}>
                <Icon name="pin" size={12} />
                {c.label} ({c.count})
              </button>
            ))}
          </div>
        )}

        {/* List */}
        {!monthHasData ? (
          <div className="empty" style={{ padding: '60px 24px' }}>
            <Icon name="package" size={28} color="var(--eb-faint)" />
            <div style={{ marginTop: 10, fontWeight: 600, color: 'var(--eb-ink)' }}>Belum ada transaksi</div>
            <div style={{ fontSize: 12, marginTop: 4 }}>Tidak ada transaksi di {currentMonth}</div>
          </div>
        ) : txs.length === 0 ? (
          <div className="empty" style={{ padding: '40px 24px' }}>
            <Icon name="search" size={28} color="var(--eb-faint)" />
            <div style={{ marginTop: 10, fontWeight: 600, color: 'var(--eb-ink)' }}>
              {q ? 'Tidak ada hasil' : 'Filter ini kosong'}
            </div>
            <div style={{ fontSize: 12, marginTop: 4 }}>
              {q ? `Tidak ditemukan untuk "${q}"` : 'Coba filter lain'}
            </div>
            {(q || filter !== 'all') && (
              <button className="btn btn-ghost btn-sm" style={{ marginTop: 14 }}
                onClick={() => { setQ(''); setFilter('all'); }}>
                Reset filter
              </button>
            )}
          </div>
        ) : sort === 'amount' ? (
          // Flat list
          <div style={{ margin: '0 16px 0', borderRadius: 14, overflow: 'hidden', background: 'var(--eb-bg-elev)', border: '1px solid var(--eb-line-soft)' }}>
            {txs.map((tx, idx) => (
              <TxRow key={tx.id} tx={tx} isFirst={idx === 0} onTap={() => onOpenTx && onOpenTx(tx)} />
            ))}
          </div>
        ) : (
          // Grouped by day
          Object.entries(grouped).map(([day, list]) => (
            <div key={day} style={{ padding: '0 0 12px' }}>
              <div style={{ padding: '4px 16px 8px', fontSize: 11, fontWeight: 600, color: 'var(--eb-muted)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                {day}
              </div>
              <div style={{ margin: '0 16px', borderRadius: 14, overflow: 'hidden', background: 'var(--eb-bg-elev)', border: '1px solid var(--eb-line-soft)' }}>
                {list.map((tx, idx) => (
                  <TxRow key={tx.id} tx={tx} isFirst={idx === 0} onTap={() => onOpenTx && onOpenTx(tx)} />
                ))}
              </div>
            </div>
          ))
        )}

        {/* Footer count */}
        {monthHasData && txs.length > 0 && (
          <div style={{ padding: '14px 16px 24px', textAlign: 'center', fontSize: 11, color: 'var(--eb-faint)' }}>
            {txs.length} transaksi {filter !== 'all' || q ? 'sesuai filter' : `di ${currentMonth}`}
          </div>
        )}

        <div style={{ height: 12 }} />
      </div>

      {/* Sort sheet */}
      <BottomSheet open={sortOpen} onClose={() => setSortOpen(false)}>
        <div style={{ padding: '4px 16px 16px' }}>
          <div style={{ fontSize: 18, fontWeight: 700, color: 'var(--eb-ink)', padding: '6px 4px 12px', letterSpacing: '-0.01em' }}>
            Urutkan transaksi
          </div>
          {[
            { id: 'newest', label: 'Terbaru dulu', desc: 'Default — transaksi paling baru di atas' },
            { id: 'oldest', label: 'Terlama dulu', desc: 'Transaksi paling lama di atas' },
            { id: 'amount', label: 'Nominal terbesar', desc: 'Total bayar tertinggi di atas' },
          ].map(opt => (
            <button key={opt.id} onClick={() => { setSort(opt.id); setSortOpen(false); }}
              className="card" style={{
                width: '100%', padding: 14, marginBottom: 8, textAlign: 'left',
                display: 'flex', alignItems: 'center', gap: 12,
                borderColor: sort === opt.id ? 'var(--eb-navy)' : 'var(--eb-line-soft)',
                borderWidth: sort === opt.id ? 2 : 1, borderStyle: 'solid',
              }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--eb-ink)' }}>{opt.label}</div>
                <div style={{ fontSize: 11, color: 'var(--eb-muted)', marginTop: 2 }}>{opt.desc}</div>
              </div>
              <div style={{
                width: 20, height: 20, borderRadius: 10,
                border: `2px solid ${sort === opt.id ? 'var(--eb-navy)' : 'var(--eb-line)'}`,
                background: sort === opt.id ? 'var(--eb-navy)' : 'transparent',
                display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
              }}>
                {sort === opt.id && <Icon name="check" size={12} stroke={3} color="#fff" />}
              </div>
            </button>
          ))}
        </div>
      </BottomSheet>

      {navbar}
    </div>
  );
};

// Single transaction row
const TxRow = ({ tx, isFirst, onTap }) => (
  <button onClick={onTap} style={{
    width: '100%',
    display: 'flex', alignItems: 'center', gap: 12, padding: 12,
    textAlign: 'left',
    borderTop: isFirst ? 'none' : '1px solid var(--eb-line-soft)',
  }}>
    <div style={{
      width: 38, height: 38, borderRadius: 10,
      background: tx.status === 'partial' ? 'var(--eb-warn-soft)' : 'var(--eb-success-soft)',
      color: tx.status === 'partial' ? 'var(--eb-warn)' : 'var(--eb-success)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      flexShrink: 0,
    }}>
      <Icon name={tx.status === 'partial' ? 'info' : 'check'} size={16} stroke={2.5} />
    </div>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{
        fontSize: 13, fontWeight: 600, color: 'var(--eb-ink)',
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      }}>{tx.items}</div>
      <div style={{ fontSize: 11, color: 'var(--eb-muted)', marginTop: 1, display: 'flex', gap: 4, alignItems: 'center' }}>
        <span>{tx.at.split('·')[1]?.trim() || tx.at}</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{tx.cluster}</span>
      </div>
      {tx.vouchered > 0 && (
        <div style={{ fontSize: 10, color: 'var(--eb-amber-strong)', fontWeight: 600, marginTop: 3, display: 'inline-flex', alignItems: 'center', gap: 3 }}>
          <Icon name="ticket" size={10} />
          Voucher {fmtRp(tx.vouchered)} diterima
        </div>
      )}
    </div>
    <div style={{ textAlign: 'right', flexShrink: 0 }}>
      <span className="price" style={{ fontSize: 13 }}>{fmtRp(tx.total)}</span>
    </div>
  </button>
);

// ─────────────────────────────────────────────────────────────
// CARI (search) SCREEN
// ─────────────────────────────────────────────────────────────
const ScreenCari = ({ onBack, onOpenProduct, onOpenMap, navbar, initialQuery = '' }) => {
  const [q, setQ] = React.useState(initialQuery);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (initialQuery) return;
    // autofocus on open
    setTimeout(() => inputRef.current?.focus(), 60);
  }, []);

  const norm = q.trim().toLowerCase();
  const results = norm ? MOCK_PRODUCTS.filter(p =>
    p.name.toLowerCase().includes(norm) || p.brand.toLowerCase().includes(norm)
  ) : [];

  return (
    <div className="app">
      <div className="topbar" style={{ paddingBottom: 12 }}>
        <button className="icon-btn ghost" onClick={onBack} style={{ flexShrink: 0 }}>
          <Icon name="back" size={20} />
        </button>
        <div className="search" style={{
          flex: 1, margin: '0 0 0 8px', height: 40,
        }}>
          <Icon name="search" size={18} color="var(--eb-faint)" />
          <input
            ref={inputRef}
            placeholder="Cari produk · obat, kopi, mi, snack…"
            value={q}
            onChange={e => setQ(e.target.value)}
          />
          {q && (
            <button onClick={() => setQ('')} style={{ flexShrink: 0 }}>
              <Icon name="close" size={16} color="var(--eb-faint)" />
            </button>
          )}
        </div>
      </div>

      <div className="app-scroll">
        {/* Peta entry card — always at top */}
        <div style={{ padding: '0 16px 14px' }}>
          <button onClick={onOpenMap} className="card" style={{
            width: '100%', padding: 12,
            display: 'flex', alignItems: 'center', gap: 12,
            textAlign: 'left',
            background: 'linear-gradient(135deg, var(--eb-navy) 0%, var(--eb-navy-700) 100%)',
            border: 'none', color: '#fff',
          }}>
            <div style={{
              width: 44, height: 44, borderRadius: 12,
              background: 'rgba(var(--eb-amber-rgb), 0.2)', color: 'var(--eb-amber)',
              display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
            }}>
              <Icon name="pin" size={22} />
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 700, color: '#fff' }}>Peta semua mesin</div>
              <div style={{ fontSize: 11, color: 'rgba(255,255,255,0.7)', marginTop: 2 }}>
                Lihat lokasi & isi setiap mesin {(window.BRAND && window.BRAND.name) || 'Elektrobee'}
              </div>
            </div>
            <Icon name="chevron" size={18} color="rgba(255,255,255,0.6)" />
          </button>
        </div>

        {/* EMPTY STATE */}
        {!norm && (
          <>
            <div className="section"><span className="section-title">Pencarian populer</span></div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, padding: '0 16px 12px' }}>
              {MOCK_POPULAR_SEARCHES.map(term => (
                <button key={term} className="chip" onClick={() => setQ(term)}>
                  <Icon name="search" size={12} color="var(--eb-muted)" />
                  {term}
                </button>
              ))}
            </div>

            <div className="section">
              <span className="section-title">Pencarian terakhir</span>
              <span className="section-action">Hapus</span>
            </div>
            <div className="list" style={{ margin: '0 16px 16px', borderRadius: 14, overflow: 'hidden', border: '1px solid var(--eb-line-soft)' }}>
              {MOCK_RECENT_SEARCHES.map((term, i) => (
                <button key={i} className="list-row" onClick={() => setQ(term)} style={{ width: '100%', textAlign: 'left' }}>
                  <Icon name="clock" size={16} color="var(--eb-faint)" />
                  <span style={{ flex: 1, fontSize: 14, color: 'var(--eb-ink)' }}>{term}</span>
                  <Icon name="arrow-right" size={14} color="var(--eb-faint)" />
                </button>
              ))}
            </div>

            <div className="section"><span className="section-title">Produk populer</span></div>
            <div className="product-grid">
              {MOCK_POPULAR_IDS.slice(0, 6).map(id => {
                const p = MOCK_PRODUCTS.find(x => x.id === id);
                if (!p) return null;
                return <SearchResultCard key={p.id} product={p} onTap={onOpenProduct} />;
              })}
            </div>
          </>
        )}

        {/* RESULTS */}
        {norm && (
          <>
            <div style={{ padding: '4px 16px 10px', fontSize: 12, color: 'var(--eb-muted)' }}>
              {results.length} produk untuk <b style={{ color: 'var(--eb-ink)' }}>"{q}"</b>
            </div>

            {results.length === 0 ? (
              <div className="empty" style={{ paddingTop: 60 }}>
                <Icon name="search" size={32} color="var(--eb-faint)" />
                <div style={{ marginTop: 10, fontWeight: 600, color: 'var(--eb-ink)' }}>Tidak ditemukan</div>
                <div style={{ fontSize: 12, marginTop: 4 }}>Coba kata kunci lain</div>
              </div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8, padding: '0 16px 12px' }}>
                {results.map(p => (
                  <SearchResultRow key={p.id} product={p} onTap={onOpenProduct} />
                ))}
              </div>
            )}

            {/* Recommendations strip — always at bottom of search results */}
            {results.length > 0 && (() => {
              const seed = results[0].id;
              const rec = getRelatedProducts(seed, 6);
              return rec.length > 0 ? (
                <>
                  <div className="section" style={{ paddingTop: 14 }}>
                    <span className="section-title">Mungkin kamu juga cari</span>
                  </div>
                  <div className="hscroll" style={{ paddingBottom: 14 }}>
                    {rec.map(p => (
                      <button key={p.id} className="popular-card" onClick={() => onOpenProduct(p)}>
                        <ProductThumb product={p} />
                        <div className="popular-card-body">
                          <div className="popular-card-name">{p.name}</div>
                          <div className="popular-card-meta">{p.brand}</div>
                          <span className="price popular-card-price">{fmtRp(p.price)}</span>
                        </div>
                      </button>
                    ))}
                  </div>
                </>
              ) : null;
            })()}
          </>
        )}

        <div style={{ height: 24 }} />
      </div>
      {navbar}
    </div>
  );
};

// Search result row — list style, shows machine count
const SearchResultRow = ({ product, onTap }) => {
  const clusters = MOCK_CLUSTERS_FOR_PRODUCT(product.id).filter(c => c.stock > 0);
  const nearestDist = clusters.length ? clusters.reduce((min, c) => c.distance < min ? c.distance : min, Infinity) : null;
  const fmtDist = (m) => m == null ? '—' : m < 1000 ? `${m} m` : `${(m/1000).toFixed(1).replace('.', ',')} km`;

  return (
    <button className="search-row" onClick={() => onTap(product)}>
      <ProductThumb product={product} size={56} />
      <div className="search-row-body">
        <div className="search-row-name">{product.name}</div>
        <div className="search-row-meta">
          <span>{product.brand}</span>
          <span style={{ opacity: 0.4 }}>·</span>
          <span>{product.unit}</span>
        </div>
        <div className="search-row-foot">
          {product.isAdult && <span className="pill pill-21">21+</span>}
          {clusters.length > 0 ? (
            <>
              <span className="pill pill-stock-ok" style={{ background: 'var(--eb-amber-soft)', color: 'var(--eb-amber-strong)' }}>
                <Icon name="pin" size={10} />
                {clusters.length} mesin
              </span>
              <span style={{ fontSize: 11, color: 'var(--eb-muted)', fontFamily: 'IBM Plex Mono', fontWeight: 500 }}>
                terdekat {fmtDist(nearestDist)}
              </span>
            </>
          ) : (
            <span className="pill pill-stock-out">Habis semua</span>
          )}
        </div>
      </div>
      <div className="search-row-right">
        <span className="price" style={{ fontSize: 14 }}>{fmtRp(product.price)}</span>
        <Icon name="chevron" size={14} color="var(--eb-faint)" />
      </div>
    </button>
  );
};

// Compact grid card for popular section on Cari empty state
const SearchResultCard = ({ product, onTap }) => (
  <button className="product-card" onClick={() => onTap(product)}>
    <ProductThumb product={product} />
    <div style={{ display: 'flex', flexDirection: 'column', gap: 3, minWidth: 0 }}>
      <div className="product-name">{product.name}</div>
      <div className="product-meta">{product.brand}</div>
    </div>
    <div className="product-price-row">
      <span className="price">{fmtRp(product.price)}</span>
    </div>
  </button>
);

// ─────────────────────────────────────────────────────────────
// PRODUCT DETAIL (full screen, from Cari) — wayfinder, not store
// ─────────────────────────────────────────────────────────────
const ScreenProductDetail = ({ product, onBack, onScan, onOpenProduct, onOpenMap, locOn }) => {
  if (!product) return null;
  const clusters = MOCK_CLUSTERS_FOR_PRODUCT(product.id);
  const inStock = clusters.filter(c => c.stock > 0);
  const totalStock = inStock.reduce((s, c) => s + c.stock, 0);
  const related = getRelatedProducts(product.id, 6);
  const [notify, setNotify] = React.useState(false);

  const fmtDist = (m) => m < 1000 ? `${m} m` : `${(m/1000).toFixed(1).replace('.', ',')} km`;
  const walkMin = (m) => Math.max(1, Math.round(m / 80)); // 80 m/min walking

  return (
    <div className="app">
      <Topbar
        title={product.name}
        sub={product.brand}
        onBack={onBack}
      />

      <div className="app-scroll">
        {/* Hero */}
        <div style={{ padding: '8px 16px 14px', display: 'flex', gap: 14 }}>
          <ProductThumb product={product} size={108} />
          <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 4 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 10, color: 'var(--eb-muted)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                {product.brand}
              </span>
              {product.isAdult && <span className="pill pill-21">21+</span>}
            </div>
            <div style={{ fontSize: 18, fontWeight: 700, lineHeight: 1.15, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
              {product.name}
            </div>
            <div style={{ fontSize: 12, color: 'var(--eb-muted)' }}>{product.unit}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginTop: 'auto' }}>
              <span className="price" style={{ fontSize: 22, color: 'var(--eb-navy)' }}>{fmtRp(product.price)}</span>
            </div>
          </div>
        </div>

        {/* Availability summary */}
        <div style={{ padding: '0 16px 14px' }}>
          {inStock.length > 0 ? (
            <div className="status-row">
              <span className="dot" style={{ background: 'var(--eb-success)' }} />
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>
                  Tersedia di {inStock.length} mesin · total {totalStock} pcs
                </div>
                <div style={{ fontSize: 11, color: 'var(--eb-muted)' }}>
                  Stok per mesin diperbarui beberapa detik lalu
                </div>
              </div>
            </div>
          ) : (
            <div className="status-row" style={{ background: 'var(--eb-warn-soft)', borderColor: 'transparent' }}>
              <span className="dot" style={{ background: 'var(--eb-warn)' }} />
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--eb-warn)' }}>
                  Belum tersedia di mesin manapun
                </div>
                <div style={{ fontSize: 11, color: 'var(--eb-muted)' }}>
                  Kami akan beri tahu kalau ada
                </div>
              </div>
              <button onClick={() => setNotify(!notify)} className="twk-toggle" data-on={notify ? '1' : '0'}
                style={{ flexShrink: 0 }}>
                <i />
              </button>
            </div>
          )}
        </div>

        {/* MAP */}
        {inStock.length > 0 && (
          <div style={{ padding: '0 16px 14px' }}>
            <div className="map-preview">
              <MapPreview clusters={inStock} userLoc={locOn ? MOCK_USER_LOCATION : null} onTap={onOpenMap} />
              {!locOn && (
                <div className="map-locoff">
                  <Icon name="pin" size={16} />
                  <span>Aktifkan lokasi untuk lihat jarak akurat</span>
                </div>
              )}
            </div>
          </div>
        )}

        {/* Cluster list */}
        {inStock.length > 0 && (
          <>
            <div className="section">
              <span className="section-title">Mesin terdekat</span>
              {locOn && <span className="section-action">Urutkan jarak</span>}
            </div>
            <div style={{ padding: '0 16px 14px', display: 'flex', flexDirection: 'column', gap: 8 }}>
              {inStock.map(cl => (
                <div key={cl.id} className="machine-row">
                  <div className="machine-row-icon">
                    <Icon name="pin" size={18} />
                  </div>
                  <div className="machine-row-body">
                    <div className="machine-row-name">{cl.name}</div>
                    <div className="machine-row-area">{cl.area}</div>
                    <div className="machine-row-foot">
                      <span className="pill pill-stock-ok" style={{
                        background: cl.stock <= 5 ? 'var(--eb-warn-soft)' : 'var(--eb-success-soft)',
                        color: cl.stock <= 5 ? 'var(--eb-warn)' : 'var(--eb-success)',
                      }}>
                        {cl.stock <= 5 ? `Tinggal ${cl.stock}` : `Stok ${cl.stock}+`}
                      </span>
                      {locOn ? (
                        <span style={{ fontSize: 11, color: 'var(--eb-muted)', fontFamily: 'IBM Plex Mono', fontWeight: 500 }}>
                          {fmtDist(cl.distance)} · {walkMin(cl.distance)} mnt jalan
                        </span>
                      ) : (
                        <span style={{ fontSize: 11, color: 'var(--eb-muted)' }}>
                          {cl.area.split('·')[1]?.trim() || cl.area}
                        </span>
                      )}
                    </div>
                  </div>
                  <Icon name="chevron" size={16} color="var(--eb-faint)" />
                </div>
              ))}
            </div>
          </>
        )}

        {/* Related products */}
        {related.length > 0 && (
          <>
            <div className="section">
              <span className="section-title">Mungkin kamu cari</span>
            </div>
            <div className="hscroll" style={{ paddingBottom: 24 }}>
              {related.map(p => (
                <button key={p.id} className="popular-card" onClick={() => onOpenProduct(p)}>
                  <ProductThumb product={p} />
                  <div className="popular-card-body">
                    <div className="popular-card-name">{p.name}</div>
                    <div className="popular-card-meta">{p.brand}</div>
                    <span className="price popular-card-price">{fmtRp(p.price)}</span>
                  </div>
                </button>
              ))}
            </div>
          </>
        )}

        <div style={{ height: 110 }} />
      </div>

      {/* Sticky CTA */}
      {inStock.length > 0 && (
        <div className="bottom-bar">
          <button className="btn btn-primary btn-block" onClick={onScan}>
            <Icon name="qr" size={18} />
            Pindai QR atau Tap NFC di mesin
          </button>
          <div style={{ fontSize: 10, color: 'var(--eb-faint)', textAlign: 'center', marginTop: 8, lineHeight: 1.4 }}>
            Belanja hanya bisa setelah kamu berada di lokasi mesin
          </div>
        </div>
      )}
    </div>
  );
};

// ─────────────────────────────────────────────────────────────
// MAP PREVIEW — Leaflet with brand-tuned tiles + pins
// ─────────────────────────────────────────────────────────────
const MapPreview = ({ clusters, userLoc, onTap }) => {
  const mapRef = React.useRef(null);
  const [ready, setReady] = React.useState(false);

  // Lazy-load Leaflet CSS + JS once
  React.useEffect(() => {
    if (window.L) { setReady(true); return; }
    const css = document.createElement('link');
    css.rel = 'stylesheet';
    css.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
    css.integrity = 'sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=';
    css.crossOrigin = '';
    document.head.appendChild(css);

    const js = document.createElement('script');
    js.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
    js.integrity = 'sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=';
    js.crossOrigin = '';
    js.onload = () => setReady(true);
    document.head.appendChild(js);
  }, []);

  // Init map
  React.useEffect(() => {
    if (!ready || !mapRef.current) return;
    const L = window.L;
    if (mapRef.current._leaflet_id) return; // already initialized

    // Center: average of all cluster lat/lngs
    const center = clusters.length
      ? [
          clusters.reduce((s, c) => s + c.lat, 0) / clusters.length,
          clusters.reduce((s, c) => s + c.lng, 0) / clusters.length,
        ]
      : [-6.2088, 106.8456]; // Jakarta default

    const map = L.map(mapRef.current, {
      zoomControl: false, attributionControl: false,
      dragging: false, scrollWheelZoom: false, doubleClickZoom: false, touchZoom: false,
    }).setView(center, 11);

    // Brand-tuned tiles — CARTO dark matter looks too cold; we use a custom
    // Stadia/CartoDB style that complements navy + amber
    L.tileLayer('https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png', {
      maxZoom: 19, subdomains: 'abcd',
    }).addTo(map);
    L.tileLayer('https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}{r}.png', {
      maxZoom: 19, subdomains: 'abcd',
    }).addTo(map);

    // Pins
    const pinIcon = (n) => L.divIcon({
      className: 'eb-pin',
      html: `<div class="eb-pin-inner">${n}</div>`,
      iconSize: [32, 36], iconAnchor: [16, 36],
    });
    clusters.forEach((cl, i) => {
      L.marker([cl.lat, cl.lng], { icon: pinIcon(i + 1) }).addTo(map);
    });

    // User dot
    if (userLoc) {
      const userIcon = L.divIcon({
        className: 'eb-user',
        html: '<div class="eb-user-dot"></div><div class="eb-user-pulse"></div>',
        iconSize: [20, 20], iconAnchor: [10, 10],
      });
      L.marker([userLoc.lat, userLoc.lng], { icon: userIcon }).addTo(map);
    }

    // Fit bounds
    const points = [...clusters.map(c => [c.lat, c.lng])];
    if (userLoc) points.push([userLoc.lat, userLoc.lng]);
    if (points.length > 1) {
      map.fitBounds(points, { padding: [30, 30], maxZoom: 14 });
    }
  }, [ready, clusters, userLoc]);

  return (
    <button className="map-preview-frame" onClick={onTap}>
      <div ref={mapRef} className="map-preview-canvas" />
      <div className="map-preview-overlay">
        <span className="map-preview-cta">
          <Icon name="pin" size={12} /> Lihat peta lengkap
        </span>
      </div>
    </button>
  );
};

// ─────────────────────────────────────────────────────────────
// KTP VERIFICATION FLOW
// State machine: intro → ktp-capture → ktp-review → selfie-capture →
//                selfie-review → submitting → outcome(success|rejected)
// First submission rejects (demo); second succeeds.
// ─────────────────────────────────────────────────────────────
const ScreenKtp = ({ user, onBack, onVerified }) => {
  const [step, setStep] = React.useState(user?.verifiedAge ? 'verified' : 'intro');
  const [attempts, setAttempts] = React.useState(0);
  const go = (s) => setStep(s);

  React.useEffect(() => {
    if (step === 'submitting') {
      const t = setTimeout(() => {
        const next = attempts === 1 ? 'rejected' : 'success';
        setStep(next);
        if (next === 'success') onVerified && onVerified();
      }, 2200);
      return () => clearTimeout(t);
    }
  }, [step, attempts]);

  const stepIdx = {
    'intro': 0,
    'ktp-capture': 1, 'ktp-review': 1,
    'selfie-capture': 2, 'selfie-review': 2,
    'submitting': 3,
  }[step];

  if (step === 'verified') {
    return (
      <div className="app">
        <Topbar title="Verifikasi KTP" onBack={onBack} />
        <div className="app-scroll">
          <div style={{ padding: '24px 24px 14px', textAlign: 'center' }}>
            <div style={{
              display: 'inline-flex', padding: 18, borderRadius: 28,
              background: 'var(--eb-success-soft)', color: 'var(--eb-success)',
            }}>
              <Icon name="shield" size={42} stroke={2} />
            </div>
            <div style={{ fontSize: 20, fontWeight: 700, marginTop: 16, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
              Akun kamu terverifikasi
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.5 }}>
              Kamu bisa membeli produk khusus 21+ di semua mesin {(window.BRAND && window.BRAND.name) || 'Elektrobee'}.
            </div>
          </div>

          <div style={{ padding: '14px 16px 0' }}>
            <div className="card" style={{ padding: 16 }}>
              <KtpInfoRow k="Nama" v={user.name} />
              <KtpInfoRow k="No. KTP" v="3174 0823 4567 ••••" mono />
              <KtpInfoRow k="Tgl. lahir" v="14 Mar 1995" />
              <KtpInfoRow k="Diverifikasi" v="12 Apr 2026" />
            </div>
          </div>

          <div style={{ padding: '14px 16px' }}>
            <div style={{
              padding: 12, borderRadius: 12, background: 'var(--eb-bg-muted)',
              fontSize: 12, color: 'var(--eb-muted)', lineHeight: 1.5,
              display: 'flex', gap: 10, alignItems: 'flex-start',
            }}>
              <Icon name="info" size={16} color="var(--eb-muted)" />
              <span>Data KTP kamu dienkripsi dan hanya dipakai untuk verifikasi usia. Hapus kapan saja di pengaturan.</span>
            </div>
          </div>

          <div style={{ padding: '14px 16px 30px' }}>
            <button className="btn btn-ghost btn-block" style={{ color: 'var(--eb-danger)' }}>
              Hapus data KTP
            </button>
          </div>
        </div>
      </div>
    );
  }

  if (step === 'intro') {
    return (
      <div className="app">
        <Topbar title="Verifikasi KTP" onBack={onBack} />
        <KtpProgress current={stepIdx} />
        <div className="app-scroll">
          <div style={{ padding: '12px 24px 14px', textAlign: 'center' }}>
            <div style={{
              display: 'inline-flex', padding: 16, borderRadius: 24,
              background: 'var(--eb-amber-soft)', color: 'var(--eb-amber-strong)',
            }}>
              <Icon name="shield" size={34} />
            </div>
            <div style={{ fontSize: 20, fontWeight: 700, marginTop: 14, color: 'var(--eb-ink)', letterSpacing: '-0.02em', textWrap: 'pretty' }}>
              Buka akses produk 21+
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.5, textWrap: 'pretty' }}>
              Verifikasi usia cuma 1 menit. Foto KTP + selfie sambil pegang KTP.
            </div>
          </div>

          <div style={{ padding: '14px 16px 0' }}>
            <div className="card" style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
              {[
                { icon: 'card',   t: 'Foto KTP',            d: 'Pastikan terlihat jelas dan tidak buram' },
                { icon: 'user',   t: 'Selfie + KTP',        d: 'Sambil pegang KTP, foto wajah kamu' },
                { icon: 'check',  t: 'Verifikasi otomatis', d: 'Hasil keluar dalam ±5 menit' },
              ].map((s, i) => (
                <div key={i} style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
                  <div style={{
                    width: 32, height: 32, borderRadius: 9,
                    background: 'var(--eb-navy)', color: 'var(--eb-amber)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                  }}>
                    <Icon name={s.icon} size={16} />
                  </div>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--eb-ink)' }}>{s.t}</div>
                    <div style={{ fontSize: 11, color: 'var(--eb-muted)', marginTop: 2 }}>{s.d}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>

          <div style={{ padding: '14px 16px 0' }}>
            <div style={{
              padding: 12, borderRadius: 12, background: 'var(--eb-bg-muted)',
              fontSize: 12, color: 'var(--eb-muted)', lineHeight: 1.5,
              display: 'flex', gap: 10, alignItems: 'flex-start',
            }}>
              <Icon name="lock" size={16} color="var(--eb-muted)" />
              <span>
                Data KTP dienkripsi end-to-end. Dipakai hanya untuk verifikasi usia, otomatis dihapus jika kamu hapus akun. <u>Selengkapnya</u>
              </span>
            </div>
          </div>

          <div style={{ height: 100 }} />
        </div>
        <div className="bottom-bar">
          <button className="btn btn-primary btn-block" onClick={() => go('ktp-capture')}>
            Mulai verifikasi
            <Icon name="arrow-right" size={16} stroke={2.5} />
          </button>
        </div>
      </div>
    );
  }

  if (step === 'ktp-capture') {
    return (
      <div className="app" style={{ background: '#000' }}>
        <KtpCameraFrame
          title="Foto KTP kamu"
          onBack={() => go('intro')}
          ratio={1.586}
          subtitle="Pastikan seluruh KTP masuk ke dalam kotak"
          onCapture={() => go('ktp-review')}
        />
      </div>
    );
  }

  if (step === 'ktp-review') {
    return (
      <div className="app">
        <Topbar title="Periksa foto KTP" onBack={() => go('ktp-capture')} />
        <KtpProgress current={stepIdx} />
        <div className="app-scroll">
          <div style={{ padding: '12px 16px 14px' }}>
            <div className="ktp-preview" style={{ aspectRatio: '1.586 / 1' }}>
              <KtpFakeCard />
            </div>
            <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--eb-ink)', marginTop: 14 }}>
              Foto sudah jelas?
            </div>
            <div style={{ fontSize: 12, color: 'var(--eb-muted)', marginTop: 6, lineHeight: 1.5 }}>
              Pastikan NIK, nama, dan tanggal lahir bisa terbaca. Jangan ada pantulan atau jari menutupi info.
            </div>
            <div style={{ marginTop: 14, padding: 12, borderRadius: 12, background: 'var(--eb-success-soft)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--eb-success)', fontWeight: 600 }}>
                <Icon name="check" size={14} stroke={3} />
                Auto-detect: NIK 3174 0823 4567 ••••
              </div>
            </div>
          </div>
          <div style={{ height: 100 }} />
        </div>
        <div className="bottom-bar" style={{ display: 'flex', gap: 10 }}>
          <button className="btn btn-ghost" style={{ flex: 1 }} onClick={() => go('ktp-capture')}>
            Ulangi foto
          </button>
          <button className="btn btn-primary" style={{ flex: 1.5 }} onClick={() => go('selfie-capture')}>
            Lanjut · selfie
            <Icon name="arrow-right" size={16} stroke={2.5} />
          </button>
        </div>
      </div>
    );
  }

  if (step === 'selfie-capture') {
    return (
      <div className="app" style={{ background: '#000' }}>
        <KtpCameraFrame
          title="Selfie sambil pegang KTP"
          subtitle="Pastikan wajah dan KTP terlihat jelas"
          onBack={() => go('ktp-review')}
          shape="circle"
          onCapture={() => go('selfie-review')}
        />
      </div>
    );
  }

  if (step === 'selfie-review') {
    return (
      <div className="app">
        <Topbar title="Periksa selfie" onBack={() => go('selfie-capture')} />
        <KtpProgress current={stepIdx} />
        <div className="app-scroll">
          <div style={{ padding: '12px 16px 14px' }}>
            <div className="ktp-preview" style={{ aspectRatio: '4 / 5' }}>
              <KtpFakeSelfie />
            </div>
            <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--eb-ink)', marginTop: 14 }}>
              Wajah dan KTP terlihat jelas?
            </div>
            <div style={{ fontSize: 12, color: 'var(--eb-muted)', marginTop: 6, lineHeight: 1.5 }}>
              Wajah harus utuh dan tidak tertutup. KTP harus terbaca dan tidak tertukar dengan KTP orang lain.
            </div>
            <div style={{ marginTop: 14, padding: 12, borderRadius: 12, background: 'var(--eb-success-soft)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--eb-success)', fontWeight: 600 }}>
                <Icon name="check" size={14} stroke={3} />
                Wajah & KTP terdeteksi
              </div>
            </div>
          </div>
          <div style={{ height: 100 }} />
        </div>
        <div className="bottom-bar" style={{ display: 'flex', gap: 10 }}>
          <button className="btn btn-ghost" style={{ flex: 1 }} onClick={() => go('selfie-capture')}>
            Ulangi
          </button>
          <button className="btn btn-primary" style={{ flex: 1.5 }} onClick={() => { setAttempts(a => a + 1); go('submitting'); }}>
            Kirim untuk verifikasi
            <Icon name="arrow-right" size={16} stroke={2.5} />
          </button>
        </div>
      </div>
    );
  }

  if (step === 'submitting') {
    return (
      <div className="app">
        <Topbar title="Memverifikasi" />
        <div className="app-scroll">
          <div style={{ padding: '60px 24px 0', textAlign: 'center' }}>
            <div style={{
              display: 'inline-flex', padding: 20, borderRadius: 32,
              background: 'var(--eb-amber-soft)', color: 'var(--eb-amber-strong)',
              animation: 'ktp-pulse 1.6s ease-in-out infinite',
            }}>
              <Icon name="shield" size={42} />
            </div>
            <div style={{ fontSize: 18, fontWeight: 700, marginTop: 16, color: 'var(--eb-ink)' }}>
              Sedang memverifikasi
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 6, lineHeight: 1.5 }}>
              Tim {(window.BRAND && window.BRAND.name) || 'Elektrobee'} sedang memeriksa foto kamu. Mohon tunggu sebentar.
            </div>
            <div className="loader" style={{ marginTop: 24, color: 'var(--eb-amber-strong)' }}>
              <span /><span /><span />
            </div>
          </div>
        </div>
      </div>
    );
  }

  if (step === 'rejected') {
    return (
      <div className="app">
        <Topbar title="Verifikasi gagal" onBack={onBack} />
        <div className="app-scroll">
          <div style={{ padding: '40px 24px 14px', textAlign: 'center' }}>
            <div style={{
              display: 'inline-flex', padding: 18, borderRadius: 28,
              background: 'var(--eb-danger-soft)', color: 'var(--eb-danger)',
            }}>
              <Icon name="close" size={36} stroke={3} />
            </div>
            <div style={{ fontSize: 20, fontWeight: 700, marginTop: 16, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
              KTP tidak terbaca jelas
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.5, textWrap: 'pretty' }}>
              NIK pada foto KTP tidak bisa kami baca. Coba ambil foto di tempat yang lebih terang.
            </div>
          </div>

          <div style={{ padding: '14px 16px 0' }}>
            <div className="card" style={{ padding: 14 }}>
              <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--eb-muted)', textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 10 }}>
                Tips ambil foto KTP
              </div>
              {[
                'Pakai cahaya terang, hindari bayangan',
                'KTP datar, tidak miring atau bengkok',
                'Bersihkan permukaan KTP dulu',
                'Hindari pantulan cahaya pada hologram',
              ].map((t, i) => (
                <div key={i} style={{ display: 'flex', gap: 8, padding: '4px 0', fontSize: 13, color: 'var(--eb-ink-2)', alignItems: 'flex-start' }}>
                  <Icon name="check" size={14} color="var(--eb-success)" stroke={3} />
                  <span>{t}</span>
                </div>
              ))}
            </div>
          </div>

          <div style={{ height: 100 }} />
        </div>
        <div className="bottom-bar" style={{ display: 'flex', gap: 10 }}>
          <button className="btn btn-ghost" style={{ flex: 1 }} onClick={onBack}>
            Nanti saja
          </button>
          <button className="btn btn-primary" style={{ flex: 1.5 }} onClick={() => go('ktp-capture')}>
            <Icon name="refresh" size={16} />
            Coba lagi
          </button>
        </div>
      </div>
    );
  }

  if (step === 'success') {
    return (
      <div className="app">
        <Topbar title="Verifikasi berhasil" />
        <div className="app-scroll">
          <div style={{ padding: '40px 24px 14px', textAlign: 'center' }}>
            <div style={{
              display: 'inline-flex', padding: 18, borderRadius: 28,
              background: 'var(--eb-success-soft)', color: 'var(--eb-success)',
              animation: 'ktp-pop 0.4s cubic-bezier(.2,.7,.3,1.2)',
            }}>
              <Icon name="check" size={42} stroke={3} />
            </div>
            <div style={{ fontSize: 22, fontWeight: 700, marginTop: 16, color: 'var(--eb-ink)', letterSpacing: '-0.02em' }}>
              Akun terverifikasi
            </div>
            <div style={{ fontSize: 13, color: 'var(--eb-muted)', marginTop: 8, lineHeight: 1.5 }}>
              Kamu sekarang bisa beli produk 21+ di semua mesin {(window.BRAND && window.BRAND.name) || 'Elektrobee'}.
            </div>
          </div>

          <div style={{ padding: '14px 16px 0' }}>
            <div style={{
              padding: 16, borderRadius: 16,
              background: 'linear-gradient(135deg, #2DAB73 0%, #186443 100%)',
              color: '#fff', display: 'flex', alignItems: 'center', gap: 12,
            }}>
              <div style={{
                width: 44, height: 44, borderRadius: 12,
                background: 'rgba(255,255,255,0.16)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <Icon name="shield" size={20} />
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 14, fontWeight: 700 }}>Verified 21+</div>
                <div style={{ fontSize: 11, opacity: 0.85, marginTop: 2 }}>Status akun kamu sudah upgrade</div>
              </div>
            </div>
          </div>

          <div style={{ height: 100 }} />
        </div>
        <div className="bottom-bar">
          <button className="btn btn-primary btn-block" onClick={onBack}>
            Selesai
            <Icon name="arrow-right" size={16} stroke={2.5} />
          </button>
        </div>
      </div>
    );
  }

  return null;
};

const KtpInfoRow = ({ k, v, mono }) => (
  <div className="ktp-info-row">
    <span className="ktp-info-k">{k}</span>
    <span className={`ktp-info-v ${mono ? 'mono' : ''}`}>{v}</span>
  </div>
);

const KtpProgress = ({ current }) => (
  <div className="ktp-progress">
    {['Mulai', 'KTP', 'Selfie', 'Kirim'].map((label, i) => (
      <React.Fragment key={i}>
        <div className="ktp-progress-step" data-state={
          i < current ? 'done' : i === current ? 'active' : 'todo'
        }>
          <span className="ktp-progress-dot">
            {i < current ? <Icon name="check" size={10} stroke={3} /> : i + 1}
          </span>
          <span className="ktp-progress-label">{label}</span>
        </div>
        {i < 3 && <div className="ktp-progress-line" data-done={i < current} />}
      </React.Fragment>
    ))}
  </div>
);

const KtpCameraFrame = ({ title, subtitle, onBack, onCapture, ratio = 1.586, shape = 'rect' }) => (
  <>
    <div style={{
      position: 'absolute', top: 0, left: 0, right: 0,
      padding: '52px 16px 0',
      display: 'flex', justifyContent: 'space-between', alignItems: 'center',
      zIndex: 10,
    }}>
      <button onClick={onBack} className="icon-btn" style={{
        background: 'rgba(0,0,0,0.45)', color: '#fff', border: '1px solid rgba(255,255,255,0.18)',
      }}>
        <Icon name="back" size={20} />
      </button>
      <div style={{
        padding: '6px 14px', borderRadius: 999,
        background: 'rgba(0,0,0,0.5)', color: '#fff', fontSize: 12, fontWeight: 600,
        border: '1px solid rgba(255,255,255,0.15)', whiteSpace: 'nowrap',
      }}>{title}</div>
      <div style={{ width: 36 }} />
    </div>

    <div style={{
      position: 'absolute', inset: 0,
      background: 'radial-gradient(circle at center, #2a3148 0%, #0a0d18 80%)',
      overflow: 'hidden',
    }}>
      <div style={{
        position: 'absolute', inset: 0, opacity: 0.08,
        backgroundImage:
          'linear-gradient(rgba(255,255,255,0.4) 1px, transparent 1px),' +
          'linear-gradient(90deg, rgba(255,255,255,0.4) 1px, transparent 1px)',
        backgroundSize: '32px 32px',
      }} />
    </div>

    <div className="ktp-mask">
      <div className="ktp-mask-cutout" style={shape === 'circle' ? {
        width: '78%', maxWidth: 280, aspectRatio: '4 / 5', borderRadius: '50% / 40%',
      } : {
        width: '88%', maxWidth: 320, aspectRatio: ratio,
      }}>
        <span className="ktp-corner tl" />
        <span className="ktp-corner tr" />
        <span className="ktp-corner bl" />
        <span className="ktp-corner br" />
        {shape !== 'circle' && <span className="ktp-scanline" />}
      </div>
    </div>

    <div style={{
      position: 'absolute', left: 16, right: 16,
      bottom: 130, textAlign: 'center', zIndex: 10,
      color: '#fff', fontSize: 13, fontWeight: 500,
      textShadow: '0 1px 4px rgba(0,0,0,0.6)',
    }}>{subtitle}</div>

    <div style={{
      position: 'absolute', bottom: 36, left: 0, right: 0,
      display: 'flex', justifyContent: 'center', zIndex: 10,
    }}>
      <button onClick={onCapture} className="ktp-shutter">
        <span className="ktp-shutter-inner" />
      </button>
    </div>
  </>
);

const KtpFakeCard = () => (
  <svg viewBox="0 0 320 200" style={{ width: '100%', height: '100%', display: 'block' }}>
    <defs>
      <linearGradient id="ktpBg" x1="0" y1="0" x2="1" y2="1">
        <stop offset="0%" stopColor="#E8EBF0"/>
        <stop offset="100%" stopColor="#C8CDD8"/>
      </linearGradient>
    </defs>
    <rect width="320" height="200" rx="12" fill="url(#ktpBg)"/>
    <text x="160" y="22" textAnchor="middle" fontFamily="Inter" fontSize="10" fontWeight="700" fill="#042147" letterSpacing="2">PROVINSI DKI JAKARTA</text>
    <text x="160" y="34" textAnchor="middle" fontFamily="Inter" fontSize="8" fontWeight="600" fill="#042147" letterSpacing="1">KOTA JAKARTA PUSAT</text>
    <line x1="60" y1="40" x2="260" y2="40" stroke="#042147" strokeWidth="0.5"/>
    <text x="14" y="58" fontFamily="Inter" fontSize="7" fill="#666">NIK</text>
    <text x="40" y="58" fontFamily="IBM Plex Mono" fontSize="11" fontWeight="700" fill="#042147">: 3174 0823 4567 ••••</text>
    {[
      ['Nama', 'ANDI PRAKOSO', 80],
      ['Tempat/Tgl. Lahir', 'JAKARTA, 14-03-1995', 92],
      ['Jenis Kelamin', 'LAKI-LAKI', 104],
      ['Alamat', 'JL. ANGGREK CAKRA NO. 27', 116],
      ['RT/RW', '004/008', 128],
      ['Kel/Desa', 'SLIPI', 140],
      ['Kecamatan', 'PALMERAH', 152],
      ['Agama', 'ISLAM', 164],
      ['Status Perkawinan', 'BELUM KAWIN', 176],
    ].map(([k, v, y], i) => (
      <g key={i}>
        <text x="14" y={y} fontFamily="Inter" fontSize="6" fill="#666">{k}</text>
        <text x="92" y={y} fontFamily="IBM Plex Mono" fontSize="7" fontWeight="600" fill="#042147">: {v}</text>
      </g>
    ))}
    <rect x="240" y="50" width="70" height="90" rx="4" fill="#9EA8B8"/>
    <circle cx="275" cy="80" r="11" fill="#7C8493"/>
    <path d="M256 130 Q275 105 294 130 Z" fill="#7C8493"/>
    <line x1="240" y1="172" x2="310" y2="172" stroke="#7C8493" strokeWidth="0.5"/>
    <text x="275" y="185" textAnchor="middle" fontFamily="Inter" fontSize="6" fill="#666">SLIPI, 14-03-2020</text>
  </svg>
);

const KtpFakeSelfie = () => (
  <svg viewBox="0 0 320 400" style={{ width: '100%', height: '100%', display: 'block' }}>
    <defs>
      <linearGradient id="selfieBg" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor="#5dbbf5"/>
        <stop offset="50%" stopColor="#a3d4ee"/>
        <stop offset="100%" stopColor="#e5d4ad"/>
      </linearGradient>
      <radialGradient id="faceGrad" cx="0.5" cy="0.4" r="0.5">
        <stop offset="0%" stopColor="#f4d8b3"/>
        <stop offset="100%" stopColor="#c79a6e"/>
      </radialGradient>
    </defs>
    <rect width="320" height="400" rx="12" fill="url(#selfieBg)"/>
    <ellipse cx="160" cy="140" rx="62" ry="74" fill="url(#faceGrad)"/>
    <path d="M100 110 Q100 60 160 60 Q220 60 220 110 Q210 90 160 88 Q110 90 100 110 Z" fill="#1a1208"/>
    <ellipse cx="138" cy="138" rx="4" ry="3" fill="#2a1f10"/>
    <ellipse cx="182" cy="138" rx="4" ry="3" fill="#2a1f10"/>
    <path d="M160 148 Q156 165 160 168" stroke="#a0734a" strokeWidth="1.5" fill="none"/>
    <path d="M145 178 Q160 188 175 178" stroke="#7c4828" strokeWidth="1.8" fill="none"/>
    <path d="M80 240 Q90 220 130 215 L190 215 Q230 220 240 240 L240 400 L80 400 Z" fill="#042147"/>
    <g transform="translate(100 270) rotate(-8)">
      <rect width="120" height="76" rx="6" fill="#E8EBF0" stroke="#bbb" strokeWidth="0.6"/>
      <text x="60" y="14" textAnchor="middle" fontFamily="Inter" fontSize="6" fontWeight="700" fill="#042147" letterSpacing="1">DKI JAKARTA</text>
      <rect x="92" y="20" width="22" height="28" rx="2" fill="#9EA8B8"/>
      <line x1="8" y1="24" x2="86" y2="24" stroke="#aab" strokeWidth="0.4"/>
      <line x1="8" y1="32" x2="86" y2="32" stroke="#aab" strokeWidth="0.4"/>
      <line x1="8" y1="40" x2="86" y2="40" stroke="#aab" strokeWidth="0.4"/>
      <line x1="8" y1="48" x2="86" y2="48" stroke="#aab" strokeWidth="0.4"/>
      <line x1="8" y1="56" x2="86" y2="56" stroke="#aab" strokeWidth="0.4"/>
      <line x1="8" y1="64" x2="60" y2="64" stroke="#aab" strokeWidth="0.4"/>
    </g>
    <ellipse cx="105" cy="312" rx="22" ry="14" fill="#c79a6e"/>
    <ellipse cx="218" cy="295" rx="20" ry="13" fill="#c79a6e"/>
    <rect x="100" y="65" width="120" height="150" rx="8" fill="none" stroke="#1F8A5B" strokeWidth="2" strokeDasharray="4 3" opacity="0.65"/>
    <rect x="90" y="262" width="146" height="92" rx="8" fill="none" stroke="#1F8A5B" strokeWidth="2" strokeDasharray="4 3" opacity="0.65"/>
  </svg>
);

Object.assign(window, {
  ScreenProfile, ScreenLoginPrompt, ScreenVouchers, AgeGateSheet, ScreenLogin,
  VoucherPickerSheet, ScreenRiwayat,
  ScreenCari, SearchResultRow, SearchResultCard,
  ScreenProductDetail, MapPreview,
  ScreenKtp, KtpProgress, KtpCameraFrame, KtpFakeCard, KtpFakeSelfie,
});


