/* Utility sheets: share, map/directions, media viewer, artist */
function ShareSheet({ ev, open, onClose }) {
  const { toast } = useApp();
  const opts = [['WhatsApp', '#25D366', <svg width="22" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M12 2a10 10 0 0 0-8.6 15.1L2 22l5-1.3A10 10 0 1 0 12 2Zm0 18.2a8.2 8.2 0 0 1-4.2-1.2l-.3-.2-3 .8.8-2.9-.2-.3A8.2 8.2 0 1 1 12 20.2Zm4.5-6.1c-.2-.1-1.5-.7-1.7-.8-.2-.1-.4-.1-.6.1l-.8 1c-.1.2-.3.2-.5.1a6.7 6.7 0 0 1-3.3-2.9c-.3-.4.2-.4.7-1.3.1-.2 0-.3 0-.4l-.8-1.8c-.2-.5-.4-.4-.6-.4h-.5a1 1 0 0 0-.7.3 3 3 0 0 0-.9 2.2 5.2 5.2 0 0 0 1.1 2.8 11.9 11.9 0 0 0 4.6 4c1.7.7 2.4.8 3.2.7a2.7 2.7 0 0 0 1.8-1.3c.2-.6.2-1.1.2-1.3l-.6-.3Z" /></svg>], ['Instagram', 'linear-gradient(45deg,#F58529,#DD2A7B,#8134AF)', <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="2"><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><circle cx="17.5" cy="6.5" r="1" fill="#fff" /></svg>], ['Messages', '#34C759', <Ico.mail size={20} style={{ color: '#fff' }} />], ['Copy link', 'var(--chip)', <Ico.copy size={20} style={{ color: 'var(--ink)' }} />], ['More', 'var(--chip)', <Ico.share size={20} style={{ color: 'var(--ink)' }} />]];
  return <Sheet open={open} onClose={onClose} title={ev && ev.id === 'app' ? 'Share DesiPass' : 'Share event'}>
    {ev && <div style={{ display: 'flex', gap: 12, alignItems: 'center', padding: 10, borderRadius: 14, border: '1px solid var(--line)', marginBottom: 16 }}><img src={ev.img} alt="" style={{ width: 44, height: 56, borderRadius: 8, objectFit: 'cover' }} /><div style={{ minWidth: 0 }}><div style={{ fontWeight: 700, fontSize: 13.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ev.nm}</div><div style={{ fontSize: 11.5, color: 'var(--mut)', marginTop: 2, fontFamily: 'var(--dp-font-mono)' }}>{ev.id === 'app' ? 'desipass.com' : 'desipass.com/e/' + ev.id}</div></div></div>}
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5,1fr)', gap: 8 }}>{opts.map(([l, bg, I]) => <button key={l} className="press" onClick={() => { onClose(); toast(l === 'Copy link' ? 'Link copied' : 'Shared via ' + l); }} style={{ display: 'grid', justifyItems: 'center', gap: 6 }}><span style={{ width: 52, height: 52, borderRadius: 16, background: bg, display: 'grid', placeItems: 'center' }}>{I}</span><span style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--mut)' }}>{l}</span></button>)}</div>
  </Sheet>;
}

function MapSheet({ ev, open, onClose }) {
  const { toast } = useApp();
  return <Sheet open={open} onClose={onClose} title="Getting there">
    {ev && <>
      <div style={{ position: 'relative', height: 180, borderRadius: 16, overflow: 'hidden', background: 'linear-gradient(135deg,#EDE7F2,#F7EFE6)' }}>
        <svg viewBox="0 0 360 180" width="100%" height="100%" preserveAspectRatio="none" style={{ position: 'absolute', inset: 0, opacity: .55 }} fill="none" stroke="#C9BFD4" strokeWidth="6" strokeLinecap="round"><path d="M-10 60 C 80 40, 140 90, 220 70 S 340 40, 380 60" /><path d="M-10 130 C 60 120, 120 150, 200 130 S 300 110, 380 140" /><path d="M90 -10 C 100 60, 80 120, 110 200" /><path d="M250 -10 C 240 50, 270 120, 240 200" /></svg>
        <div style={{ position: 'absolute', left: '50%', top: '46%', transform: 'translate(-50%,-100%)', display: 'grid', justifyItems: 'center' }}><span style={{ width: 40, height: 40, borderRadius: '50% 50% 50% 0', transform: 'rotate(-45deg)', background: 'var(--red)', boxShadow: '0 8px 18px rgba(229,69,88,.4)', display: 'grid', placeItems: 'center' }}><span style={{ width: 14, height: 14, borderRadius: '50%', background: '#fff' }}></span></span></div>
      </div>
      <div style={{ marginTop: 14 }}><div style={{ fontWeight: 700, fontSize: 15, lineHeight: 1.3 }}>{ev.ven}</div><div style={{ fontSize: 13, color: 'var(--mut)', marginTop: 3 }}>{ev.city}, {ev.country}</div></div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginTop: 14 }}>{['Apple Maps', 'Google Maps'].map(m => <Btn key={m} kind="ghost" small onClick={() => { onClose(); toast('Opening ' + m); }} style={{ width: '100%', height: 46 }} icon={<Ico.map size={16} />}>{m}</Btn>)}</div>
      <button onClick={() => toast('Address copied')} style={{ marginTop: 12, display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, fontWeight: 700, color: 'var(--red)' }}><Ico.copy size={15} />Copy address</button>
    </>}
  </Sheet>;
}

function MediaViewer({ data, onClose }) {
  const { topInset, bottomInset } = useApp();
  const [i, setI] = useState(data ? data.i : 0); const ref = useRef();
  useEffect(() => { if (ref.current && data) ref.current.scrollLeft = data.i * ref.current.clientWidth; }, [data]);
  if (!data) return null;
  return <div className="fade-in" style={{ position: 'absolute', inset: 0, zIndex: 60, background: '#0b0612', color: '#fff', display: 'flex', flexDirection: 'column' }}>
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: `${topInset + 6}px 12px 6px` }}><IconBtn icon={Ico.x} onClick={onClose} bg="rgba(255,255,255,.12)" color="#fff" label="Close" /><span style={{ fontSize: 13, fontWeight: 600, opacity: .8 }}>{i + 1} / {DP.MEDIA.length}</span><IconBtn icon={Ico.share} onClick={() => window.openShare && window.openShare(data.ev)} bg="rgba(255,255,255,.12)" color="#fff" label="Share" /></div>
    <div ref={ref} className="hs" onScroll={e => setI(Math.round(e.target.scrollLeft / e.target.clientWidth))} style={{ flex: 1, alignItems: 'center' }}>{DP.MEDIA.map((m, k) => <div key={k} style={{ flex: '0 0 100%', height: '100%', display: 'grid', placeItems: 'center', position: 'relative' }}><img src={m} alt="" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />{k === 1 && <span style={{ position: 'absolute', width: 64, height: 64, borderRadius: '50%', background: 'rgba(255,255,255,.92)', display: 'grid', placeItems: 'center', color: '#1D0D31' }}><Ico.play size={28} fill="currentColor" stroke={0} /></span>}</div>)}</div>
    <div style={{ padding: `10px 20px ${bottomInset + 14}px`, fontSize: 13, color: 'rgba(255,255,255,.7)' }}>{data.ev.nm} · last edition</div>
  </div>;
}

function ArtistSheet({ artist, open, onClose, onOpen }) {
  const { toast } = useApp(); const [fol, setFol] = useState(false);
  const shows = DP.EVENTS.filter(e => e.cat === 'Concerts').slice(0, 4);
  return <Sheet open={open} onClose={onClose} full pad={false}>
    {artist && <>
      <div style={{ position: 'relative', height: 220, margin: '0 0 0' }}><img src={artist.img} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /><div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent 30%, var(--sur) 100%)' }}></div><div style={{ position: 'absolute', left: 20, right: 20, bottom: 8, display: 'flex', alignItems: 'flex-end', gap: 12 }}><div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 26, letterSpacing: '-.025em', color: 'var(--ink)' }}>{artist.nm}</div><div style={{ fontSize: 13, color: 'var(--mut)' }}>{artist.sub}</div></div><Btn small kind={fol ? 'ghost' : 'primary'} onClick={() => { setFol(!fol); toast(fol ? 'Unfollowed' : `You'll hear about ${artist.nm.split(' ')[0]}'s new dates`); }} style={{ height: 36, fontSize: 13 }}>{fol ? 'Following' : 'Follow'}</Btn></div></div>
      <div style={{ padding: '16px 20px 20px' }}><div style={{ fontFamily: 'var(--dp-font-mono)', fontSize: 10, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--red)', fontWeight: 700, marginBottom: 10 }}>Tour dates</div><div style={{ display: 'grid', gap: 8 }}>{shows.map(e => <button key={e.id} className="press" onClick={() => { onClose(); onOpen(e); }} style={{ display: 'flex', gap: 12, alignItems: 'center', padding: '10px 12px', borderRadius: 14, border: '1px solid var(--line)', textAlign: 'left' }}><div style={{ width: 44, textAlign: 'center', fontFamily: 'var(--dp-font-mono)', color: 'var(--red)', fontWeight: 700, fontSize: 10, lineHeight: 1.2 }}>{e.day}<br /><span style={{ fontSize: 16, color: 'var(--ink)', fontFamily: 'var(--dp-font-display)' }}>{e.dateLbl.split(' ')[0]}</span><br />{e.dateLbl.split(' ')[1].toUpperCase()}</div><div style={{ flex: 1, minWidth: 0 }}><div style={{ fontWeight: 700, fontSize: 14, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.city}, {e.cc}</div><div style={{ fontSize: 12, color: 'var(--mut)' }}>{e.ven}</div></div><span style={{ fontWeight: 700, fontSize: 13, color: e.st === 'out' ? 'var(--mut2)' : 'var(--price)' }}>{e.st === 'out' ? 'Sold out' : DP.priceLbl(e)}</span></button>)}</div></div>
    </>}
  </Sheet>;
}

function WalletSheet({ open, onClose, ios, saved, ev, lines, fee, total, onDone }) {
  const [ph, setPh] = useState(0);
  useEffect(() => { if (!open) { setPh(0); return; } }, [open]);
  const go = () => { setPh(1); setTimeout(() => setPh(2), 1300); setTimeout(onDone, 1900); };
  useEffect(() => { if (open && ios && !saved) { const t = setTimeout(go, 700); return () => clearTimeout(t); } }, [open]);
  if (!ev) return null;
  const cur = (v) => DP.money(Math.round(v * 100) / 100, ev.cc);
  const Row = ({ l, v, b }) => <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, padding: '11px 0', borderBottom: b ? 0 : '1px solid var(--line)', fontSize: 14, fontWeight: b ? 700 : 500 }}><span style={{ color: b ? 'var(--ink)' : 'var(--mut)' }}>{l}</span><span style={{ textAlign: 'right' }}>{v}</span></div>;
  return <Sheet open={open} onClose={ph ? () => {} : onClose}>
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}><span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontWeight: 700, fontSize: 19 }}>{saved ? <><Ico.lock size={18} />Confirm payment</> : <>{ios ? <Brand.apple color="currentColor" /> : <Brand.google />}Pay</>}</span>{!ph && <button onClick={onClose} style={{ color: ios ? '#0a84ff' : 'var(--red)', fontWeight: 600, fontSize: 14 }}>Cancel</button>}</div>
    <Row l={saved ? 'Card' : ios ? 'Card' : 'Payment'} v={saved ? 'Visa •••• 4242' : ios ? 'Apple Card •••• 1234' : 'Mastercard •••• 8812'} />
    <Row l="Contact" v={DP.USER.email} />
    {lines.map(([l, v], i) => <Row key={i} l={l} v={v ? cur(v) : 'Free'} />)}
    {fee > 0 && <Row l={`Booking fee`} v={cur(fee)} />}
    <Row b l="Pay DesiPass" v={cur(total)} />
    <div style={{ display: 'grid', justifyItems: 'center', gap: 8, padding: '14px 0 4px' }}>
      {ph === 0 && (ios && !saved ? <div style={{ fontSize: 13, color: 'var(--mut)' }}>Double-click side button to pay</div> : <Btn onClick={go} style={{ height: 50, background: saved ? 'var(--red)' : '#000' }} icon={saved ? <Ico.lock size={16} /> : null}>{saved ? 'Pay with Face ID' : 'Continue'}</Btn>)}
      {ph >= 1 && <div className="pop" style={{ width: 56, height: 56, borderRadius: 16, border: `2.5px solid ${ph === 2 ? '#30d158' : '#0a84ff'}`, display: 'grid', placeItems: 'center', color: ph === 2 ? '#30d158' : '#0a84ff', transition: 'all .25s' }}>{ph === 2 ? <Ico.check size={28} stroke={2.6} /> : <Ico.user size={26} />}</div>}
      {ph >= 1 && <div style={{ fontSize: 13, color: 'var(--mut)', fontWeight: 600 }}>{ph === 2 ? 'Done' : ios ? 'Face ID' : 'Verifying'}</div>}
    </div>
  </Sheet>;
}

const TERMS_DOCS = {
  event: ['Event Terms', [['Entry', 'Photo ID and a valid QR ticket required.'], ['Refunds', 'Non-refundable and non-transferable once issued. Full refund if the organiser cancels.'], ['Media', 'Photography and filming take place at this event.'], ['Conduct', 'Entry may be refused for unsafe behaviour, with no refund.']]],
  terms: ['Terms', [['Who sells', 'DesiPass sells tickets on behalf of the organiser, who is responsible for the event.'], ['Booking fee', 'Covers payment processing, ticket delivery and support. Refunded if the event is cancelled.']]],
  privacy: ['Privacy', [['Organiser', 'Your name and email are shared with the organiser of this event to manage entry.'], ['Payments', 'Handled by Stripe. DesiPass never stores card details.']]]
};
function TermsSheet({ open, tab, setTab, onClose }) {
  const k = tab || 'event';
  return <Sheet open={open} onClose={onClose} title={TERMS_DOCS[k][0]}>
    <div style={{ display: 'flex', gap: 6, marginBottom: 14 }}>{Object.keys(TERMS_DOCS).map(x => <button key={x} onClick={() => setTab(x)} style={{ height: 32, padding: '0 12px', borderRadius: 9999, fontSize: 12.5, fontWeight: 600, border: `1px solid ${x === k ? 'var(--red)' : 'var(--line)'}`, background: x === k ? 'var(--red-soft)' : 'transparent', color: x === k ? 'var(--red)' : 'var(--ink)' }}>{TERMS_DOCS[x][0]}</button>)}</div>
    <div key={k} className="fade-in" style={{ display: 'grid', gap: 10, fontSize: 13.5, lineHeight: 1.6, color: 'var(--mut)' }}>{TERMS_DOCS[k][1].map(([h, p]) => <p key={h} style={{ margin: 0 }}><b style={{ color: 'var(--ink)' }}>{h}.</b> {p}</p>)}</div>
  </Sheet>;
}

function RequestSending({ booking, onDone }) {
  const [ph, setPh] = useState(0);
  useEffect(() => { const t = [setTimeout(() => setPh(1), 1200), setTimeout(() => setPh(2), 2500), setTimeout(onDone, 4000)]; return () => t.forEach(clearTimeout); }, []);
  const ev = booking.ev;
  const all = String(booking.tier || 'Pass').split(' + '); const passes = all.slice(0, 3); const more = all.length - 3;
  const T = [['Preparing your request', 'Checking your passes and details'], ['Sending to the organiser', 'Securing your spot in the queue'], ['Request sent', "Pending organiser approval. We'll email you."]][ph];
  return <div style={{ position: 'absolute', inset: 0, zIndex: 70, overflow: 'hidden', background: 'radial-gradient(90% 60% at 50% 38%, #3B2150 0%, #1D0D31 55%, #0E0618 100%)', color: '#fff', animation: 'dpFade .35s ease both' }}>
    <div style={{ position: 'absolute', left: '50%', top: '36%', width: 420, height: 420, margin: '-210px 0 0 -210px', borderRadius: '50%', background: ph === 2 ? 'radial-gradient(circle, rgba(255,181,71,.26), transparent 62%)' : 'radial-gradient(circle, rgba(229,69,88,.32), rgba(123,92,255,.16) 45%, transparent 66%)', animation: 'dpHaze 2.4s ease-in-out infinite', transition: 'background .6s' }}></div>
    {/* stage */}
    <div style={{ position: 'absolute', left: 0, right: 0, top: '36%', height: 0 }}>
      {/* phase 0: pass cards fan in, scan shimmer */}
      {passes.map((p, i) => { const off = i - (passes.length - 1) / 2; return <div key={i} style={{ position: 'absolute', left: '50%', top: 0, width: 200, marginLeft: -100, marginTop: -54, transition: 'transform .7s cubic-bezier(.6,0,.3,1), opacity .5s', transform: ph === 0 ? `translateX(${off * 26}px) rotate(${off * 7}deg) translateY(${Math.abs(off) * 6}px)` : 'translateY(0) scale(.25) rotate(0deg)', opacity: ph === 0 ? 1 : 0, zIndex: 3 - Math.abs(off) }}>
        <div style={{ animation: `dpCardIn .45s cubic-bezier(.2,.8,.2,1) ${i * .08}s both` }}>
          <div style={{ position: 'relative', display: 'flex', gap: 10, alignItems: 'center', padding: 10, height: 108, borderRadius: 16, background: '#fff', color: '#1D0D31', boxShadow: '0 24px 40px -18px rgba(0,0,0,.6)', overflow: 'hidden' }}>
            <img src={ev.img} alt="" style={{ width: 62, height: 86, borderRadius: 10, objectFit: 'cover', flex: 'none' }} />
            <div style={{ minWidth: 0, flex: 1 }}><div style={{ fontFamily: 'var(--dp-font-mono)', fontSize: 8.5, letterSpacing: '.12em', color: '#E54558', fontWeight: 700 }}>PASS REQUEST</div><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, lineHeight: 1.2, marginTop: 4, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{p}</div><div style={{ fontSize: 11, color: '#6B6478', marginTop: 4 }}>{ev.dateLbl} · {ev.city}</div></div>
            <span style={{ position: 'absolute', right: -9, top: '50%', marginTop: -9, width: 18, height: 18, borderRadius: '50%', background: '#2a1640' }}></span>
            <span style={{ position: 'absolute', inset: 0, background: 'linear-gradient(105deg, transparent 35%, rgba(229,69,88,.22) 48%, rgba(123,92,255,.22) 52%, transparent 65%)', animation: 'dpScan 1.3s ease-in-out .5s infinite' }}></span>
          </div>
        </div>
      </div>; })}
      {/* phase 1: spinning ring + orbits */}
      <div style={{ position: 'absolute', left: '50%', top: 0, width: 132, height: 132, margin: '-66px 0 0 -66px', opacity: ph >= 1 ? 1 : 0, transform: ph >= 1 ? 'scale(1)' : 'scale(.4)', transition: 'opacity .5s .15s, transform .6s cubic-bezier(.34,1.56,.64,1) .15s' }}>
        <div style={{ position: 'absolute', inset: 0, borderRadius: '50%', background: ph === 2 ? '#FFB547' : 'conic-gradient(from 0deg, transparent 0 15%, #E54558 45%, #7B5CFF 80%, transparent 100%)', WebkitMask: 'radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px))', mask: 'radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px))', animation: ph === 2 ? 'none' : 'dpSpin 1s linear infinite', transition: 'background .4s' }}></div>
        {ph === 1 && [0, 1, 2].map(i => <div key={i} style={{ position: 'absolute', inset: -14 - i * 12, animation: `dpSpin ${1.6 + i * .7}s linear infinite ${i % 2 ? 'reverse' : ''}` }}><span style={{ position: 'absolute', left: '50%', top: 0, width: 7 - i, height: 7 - i, marginLeft: -3, borderRadius: '50%', background: ['#FFB6C0', '#fff', '#B9A6FF'][i], boxShadow: '0 0 12px currentColor' }}></span></div>)}
        <div style={{ position: 'absolute', inset: 14, borderRadius: '50%', background: ph === 2 ? 'rgba(255,181,71,.16)' : 'rgba(255,255,255,.06)', display: 'grid', placeItems: 'center', transition: 'background .45s', boxShadow: ph === 2 ? '0 0 50px rgba(255,181,71,.35)' : 'none' }}>
          {ph === 1 && <div style={{ display: 'flex', gap: 5 }}>{[0, 1, 2].map(i => <span key={i} style={{ width: 8, height: 8, borderRadius: '50%', background: '#fff', animation: `dpDot 1s ease-in-out ${i * .15}s infinite` }}></span>)}</div>}
          {ph === 2 && <svg className="pop" width="46" height="46" viewBox="0 0 24 24" fill="none" stroke="#FFB547" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={{ animation: 'dpPop .45s cubic-bezier(.34,1.56,.64,1) both, rqTurn 1.6s ease-in-out .5s infinite' }}><path d="M6 2h12M6 22h12" /><path d="M7 2v3a5 5 0 0 0 2.5 4.3L12 11l2.5-1.7A5 5 0 0 0 17 5V2" /><path d="M7 22v-3a5 5 0 0 1 2.5-4.3L12 13l2.5 1.7A5 5 0 0 1 17 19v3" /><path d="M10 19.5h4" /></svg>}
        </div>
        
      </div>
    </div>
    {/* copy + progress */}
    <div style={{ position: 'absolute', left: 24, right: 24, top: 'calc(36% + 120px)', textAlign: 'center' }}>
      <div className="rise" style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 24, letterSpacing: '-.02em' }}>Requesting your spot</div>
      <div className="rise" style={{ fontSize: 14, color: 'rgba(255,255,255,.7)', marginTop: 8, lineHeight: 1.5, animationDelay: '.08s' }}>Pending organiser approval. We'll email you.</div>
    </div>
  </div>;
}

function MessageOrganiser({ open, onClose, ev }) {
  const [topic, setTopic] = useState(''); const [msg, setMsg] = useState(''); const [sent, setSent] = useState(false);
  useEffect(() => { if (open) { setTopic(''); setMsg(''); setSent(false); } }, [open]);
  const topics = ['Tickets', 'Refunds', 'Event info', 'Accessibility', 'Other'];
  const ok = msg.trim().length > 0;
  return <Sheet open={open} onClose={onClose} title={sent ? '' : 'Message organiser'} full>
    {sent ? <div className="fade-in" style={{ textAlign: 'center', padding: '20px 0 8px' }}><div className="pop" style={{ width: 72, height: 72, margin: '0 auto 16px', borderRadius: '50%', background: 'rgba(18,158,106,.12)', color: 'var(--green)', display: 'grid', placeItems: 'center' }}><Ico.mail size={32} /></div><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 21, letterSpacing: '-.02em' }}>Message sent</div><p style={{ margin: '8px 0 20px', fontSize: 14, color: 'var(--mut)', lineHeight: 1.5 }}>The organiser will reply to {DP.USER.email}.</p><Btn onClick={onClose}>Done</Btn></div> : <>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, paddingBottom: 14, borderBottom: '1px solid var(--line)' }}><span style={{ width: 40, height: 40, borderRadius: 11, background: HOSTS[0].color, color: '#fff', display: 'grid', placeItems: 'center', fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, flex: 'none' }}>{HOSTS[0].initials}</span><div style={{ minWidth: 0 }}><div style={{ fontWeight: 700, fontSize: 14.5 }}>{HOSTS.map(h => h.name).join(' & ')}</div><div style={{ fontSize: 12.5, color: 'var(--mut)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>About: {ev && ev.nm}</div></div></div>
      <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--mut)', margin: '16px 2px 8px' }}>Topic</div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>{topics.map(t => { const on = topic === t; return <button key={t} className="press" onClick={() => setTopic(on ? '' : t)} style={{ height: 36, padding: '0 14px', borderRadius: 9999, fontSize: 13, fontWeight: 600, border: `1.5px solid ${on ? 'var(--red)' : 'var(--line)'}`, background: on ? 'var(--red-soft)' : 'transparent', color: on ? 'var(--red)' : 'var(--ink)' }}>{t}</button>; })}</div>
      <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--mut)', margin: '16px 2px 8px' }}>Message</div>
      <div style={{ borderRadius: 14, border: '1.5px solid var(--line)', background: 'var(--sur)', padding: '12px 14px' }}><textarea value={msg} onChange={e => setMsg(e.target.value.slice(0, 500))} rows={5} placeholder="Write your question for the organiser" style={{ width: '100%', border: 0, outline: 0, resize: 'none', background: 'transparent', fontSize: 15, lineHeight: 1.5, color: 'var(--ink)', fontFamily: 'inherit' }}></textarea><div style={{ textAlign: 'right', fontSize: 11.5, color: 'var(--mut2)' }}>{msg.length}/500</div></div>
      <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--mut)', margin: '16px 2px 8px' }}>Reply to</div><div style={{ display: 'flex', alignItems: 'center', height: 44, borderRadius: 14, border: '1px solid var(--line)', background: 'var(--sur2)', padding: '0 14px' }}><input type="email" value={DP.USER.email} disabled aria-label="Reply email" style={{ width: '100%', border: 0, outline: 0, background: 'transparent', fontSize: 14, color: 'var(--mut)', WebkitTextFillColor: 'var(--mut)', fontFamily: 'inherit', cursor: 'not-allowed', padding: 0 }} /></div><div style={{ fontSize: 12, color: 'var(--mut2)', margin: '8px 2px 0' }}>The organiser replies to this email.</div>
      <Btn onClick={() => ok && setSent(true)} style={{ marginTop: 16, opacity: ok ? 1 : .5 }} icon={<Ico.mail size={17} />}>Send message</Btn>
    </>}
  </Sheet>;
}

function ReportEvent({ open, onClose }) {
  const [why, setWhy] = useState(''); const [txt, setTxt] = useState(''); const [done, setDone] = useState(false);
  useEffect(() => { if (open) { setWhy(''); setTxt(''); setDone(false); } }, [open]);
  const reasons = ['Misleading or scam', 'Wrong date, venue or price', 'Event cancelled', 'Inappropriate content', 'Spam', 'Something else'];
  return <Sheet open={open} onClose={onClose} title={done ? '' : 'Report event'} full>
    {done ? <div className="fade-in" style={{ textAlign: 'center', padding: '20px 0 8px' }}><div className="pop" style={{ width: 72, height: 72, margin: '0 auto 16px', borderRadius: '50%', background: 'var(--purple-soft)', color: 'var(--purple)', display: 'grid', placeItems: 'center' }}><Ico.check size={32} stroke={2.4} /></div><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 21, letterSpacing: '-.02em' }}>Thanks for letting us know</div><p style={{ margin: '8px 0 20px', fontSize: 14, color: 'var(--mut)', lineHeight: 1.5 }}>Our team reviews every report.</p><Btn onClick={onClose}>Done</Btn></div> : <>
      <div style={{ fontSize: 13.5, color: 'var(--mut)', margin: '0 0 8px' }}>What's wrong with this event?</div>
      <div>{reasons.map((r, i) => { const on = why === r; return <button key={r} className="press" onClick={() => setWhy(r)} style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', minHeight: 50, textAlign: 'left', borderBottom: i < reasons.length - 1 ? '1px solid var(--line)' : 0 }}><span style={{ width: 20, height: 20, flex: 'none', borderRadius: '50%', border: `1.5px solid ${on ? 'var(--red)' : '#C4BDCC'}`, display: 'grid', placeItems: 'center' }}>{on && <span className="pop" style={{ width: 10, height: 10, borderRadius: '50%', background: 'var(--red)' }}></span>}</span><span style={{ fontSize: 15, fontWeight: 500 }}>{r}</span></button>; })}</div>
      {why && <div className="fade-in" style={{ marginTop: 14 }}><div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--mut)', margin: '0 2px 8px', display: 'flex', gap: 6, alignItems: 'center' }}>Details<span style={{ fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 4, background: 'var(--chip)', color: 'var(--mut2)' }}>Optional</span></div><div style={{ borderRadius: 14, border: '1.5px solid var(--line)', background: 'var(--sur)', padding: '12px 14px' }}><textarea value={txt} onChange={e => setTxt(e.target.value.slice(0, 500))} rows={3} placeholder="Tell us more" style={{ width: '100%', border: 0, outline: 0, resize: 'none', background: 'transparent', fontSize: 15, lineHeight: 1.5, color: 'var(--ink)', fontFamily: 'inherit' }}></textarea></div></div>}
      <Btn onClick={() => why && setDone(true)} style={{ marginTop: 16, opacity: why ? 1 : .5 }}>Submit report</Btn>
    </>}
  </Sheet>;
}

const ST_ICONS = {
  card: <><rect x="3" y="5" width="18" height="14" rx="3" /><path d="M3 10h18M7 15h4" /><path d="m16 13 4 4M20 13l-4 4" /></>,
  bank: <><path d="M3 10h18L12 4 3 10Z" /><path d="M5 10v8M10 10v8M14 10v8M19 10v8M3 20h18" /></>,
  sold: <><path d="M3 9a2 2 0 0 0 2-2V6h14v1a2 2 0 0 0 2 2v6a2 2 0 0 0-2 2v1H5v-1a2 2 0 0 0-2-2Z" /><path d="m9 9 6 6M15 9l-6 6" /></>,
  timer: <><circle cx="12" cy="13" r="8" /><path d="M12 9v4l2.5 1.5M9 2h6" /></>,
  user: <><circle cx="12" cy="8" r="4" /><path d="M4 21a8 8 0 0 1 16 0" /><path d="M19 3v3M19 9h.01" /></>,
  wifi: <><path d="M2 8.8a15 15 0 0 1 20 0M5 12.5a10 10 0 0 1 14 0M8.5 16a5 5 0 0 1 7 0M12 19.5h.01" /><path d="M3 3l18 18" /></>,
  alert: <><circle cx="12" cy="12" r="9" /><path d="M12 7v6M12 16.5h.01" /></>,
  pin: <><path d="M12 22s7-6.5 7-12a7 7 0 1 0-14 0c0 5.5 7 12 7 12Z" /><path d="M3 3l18 18" /></>
};
function StateIcon({ k, tone = 'red', spin }) {
  const c = { red: ['var(--red-soft)', 'var(--red)'], amber: ['var(--warn-bg)', 'var(--warn-fg)'], purple: ['var(--purple-soft)', 'var(--purple)'] }[tone];
  return <div className="pop" style={{ position: 'relative', width: 72, height: 72, margin: '0 auto 16px', borderRadius: '50%', background: c[0], color: c[1], display: 'grid', placeItems: 'center' }}>{spin && <span style={{ position: 'absolute', inset: -4, borderRadius: '50%', border: '2.5px solid transparent', borderTopColor: c[1], animation: 'dpSpin .9s linear infinite' }}></span>}<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">{ST_ICONS[k]}</svg></div>;
}
function StateSheet({ open, onClose, icon, tone, spin, title, body, primary, onPrimary, secondary, onSecondary }) {
  return <Sheet open={open} onClose={onClose}>
    <div style={{ textAlign: 'center', padding: '12px 0 4px' }}><StateIcon k={icon} tone={tone} spin={spin} /><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 21, letterSpacing: '-.02em' }}>{title}</div><p style={{ margin: '8px auto 20px', fontSize: 14, color: 'var(--mut)', lineHeight: 1.5, maxWidth: 300 }}>{body}</p></div>
    {primary && <Btn onClick={onPrimary}>{primary}</Btn>}{secondary && <Btn kind="ghost" onClick={onSecondary} style={{ marginTop: 8 }}>{secondary}</Btn>}
  </Sheet>;
}
function ErrorState({ title, body, onRetry, icon = 'alert' }) {
  return <div className="fade-in" style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', padding: 32, textAlign: 'center' }}><div><StateIcon k={icon} tone="purple" /><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 21, letterSpacing: '-.02em', color: 'var(--ink)' }}>{title}</div><p style={{ margin: '8px auto 20px', fontSize: 14, color: 'var(--mut)', lineHeight: 1.5, maxWidth: 280 }}>{body}</p>{onRetry && <Btn small onClick={onRetry} style={{ padding: '0 24px' }}>Try again</Btn>}</div></div>;
}
function OfflineBanner() {
  const { bottomInset } = useApp();
  return <div className="rise" style={{ position: 'absolute', left: 12, right: 12, bottom: bottomInset + 84, zIndex: 90, pointerEvents: 'none', display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', borderRadius: 14, background: '#1D0D31', color: '#fff', fontSize: 13, fontWeight: 600, boxShadow: '0 12px 30px -12px rgba(0,0,0,.5)' }}><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">{ST_ICONS.wifi}</svg><span style={{ flex: 1 }}>You're offline. Your tickets still work.</span></div>;
}


/* Refunds info: same content as the web refunds.html. Opened with an event (ticket) → button messages that organiser.
   Opened without one (Help & support) → button goes to Bookings so the user picks the booking first. */
function RefundSheet({ open, onClose, ev, onMessage, onBookings }) {
  const Q = [['Where do I find the policy?', 'On the event page under Reserve your spot, on your ticket, and in your booking email.'], ['How do I ask for a refund?', 'Message the organiser and pick Refunds as the topic. Add your booking reference.'], ['When will I get my money back?', "That depends on the organiser's policy. Once issued, it goes back to the payment method you used. Your bank may take a few extra days."], ['What if the event is cancelled?', 'You get a full refund of the ticket price and the booking fee, automatically.'], ['What if the date or venue changes?', "Your ticket stays valid. If you can't make it, message the organiser. They decide."], ['Is the booking fee refunded?', "Only when the event is cancelled. Otherwise the organiser's policy decides."]];
  const T = [['No refunds', 'Some organisers still allow a transfer.'], ['Up to 7 days before', 'Ask up to 7 days before the start.'], ['Up to 30 days before', 'Ask up to 30 days before the start.']];
  return <Sheet open={open} onClose={onClose} title="Refunds">
    <div style={{ fontSize: 14, color: 'var(--mut)', lineHeight: 1.55 }}>Every event has its own refund policy. The organiser sets it, and DesiPass follows it.</div>
    {ev && <div style={{ display: 'flex', gap: 12, alignItems: 'center', marginTop: 14, padding: 12, borderRadius: 14, border: '1px solid var(--line)', background: 'var(--sur)' }}><img src={ev.img} alt="" style={{ width: 48, height: 48, borderRadius: 10, objectFit: 'cover' }} /><div style={{ minWidth: 0 }}><div style={{ fontWeight: 700, fontSize: 14, lineHeight: 1.25 }}>{ev.nm}</div><div style={{ fontSize: 12.5, color: 'var(--mut)', marginTop: 3 }}>{ev.refund || "Policy set by the organiser. Message them to check."}</div></div></div>}
    <div style={{ display: 'grid', gap: 8, marginTop: 14 }}>{T.map(([a, b]) => <div key={a} style={{ padding: '10px 12px', borderRadius: 12, border: '1px solid var(--line)' }}><div style={{ fontWeight: 700, fontSize: 13.5 }}>{a}</div><div style={{ fontSize: 12.5, color: 'var(--mut)', marginTop: 2 }}>{b}</div></div>)}</div>
    <div style={{ marginTop: 8 }}>{Q.map(([q, a]) => <div key={q} style={{ padding: '12px 0', borderBottom: '1px solid var(--line)' }}><div style={{ fontWeight: 600, fontSize: 14 }}>{q}</div><div style={{ fontSize: 13, color: 'var(--mut)', lineHeight: 1.55, marginTop: 4 }}>{a}</div></div>)}</div>
    <Btn onClick={() => ev ? onMessage(ev) : onBookings()} style={{ width: '100%', marginTop: 16 }}>{ev ? 'Message the organiser' : 'Go to my bookings'}</Btn>
    {!ev && <div style={{ fontSize: 12.5, color: 'var(--mut)', textAlign: 'center', marginTop: 8 }}>Open the booking, then tap Refund policy.</div>}
  </Sheet>;
}

Object.assign(window, { RefundSheet,  ST_ICONS, StateSheet, StateIcon, ErrorState, OfflineBanner, MessageOrganiser, ReportEvent, RequestSending, WalletSheet, TermsSheet, ShareSheet, MapSheet, MediaViewer, ArtistSheet });
