/* Event detail - mirrors web event-detail.html order: title → date/location → Reserve your spot → Who's going → About → Photos → FAQ → Organiser */
const LONG = { Concerts: 'Door times, when set, are shown under the date. Standing and seated tickets available. Children under 6 enter free on a parent\'s lap. Full lineup and timings are announced one week before the event.', default: 'Doors open 30 minutes before start. Bring your ticket QR in the app and a valid ID. Full programme and timings are announced closer to the date.' };
LONG['Club nights'] = LONG['Club nights'] || LONG.Parties; LONG.Meetups = LONG.Meetups || LONG.Social;
function tiersFor(ev) {
  if (ev.testPasses) return [{ k: 'free', nm: 'Community Pass', p: 0, note: 'Free entry. The organiser reviews each request.', appr: 1, max: 2 }, { k: 'paid', nm: 'Supporter Pass', p: ev.price, note: 'Supports the meetup. Snacks & drinks included.', appr: 1, max: 2 }];
  if (ev.approval) { const b = ev.price || 0; return b ? [{ k: 'creator', nm: 'Creator Pass', p: b, note: 'For active content creators and influencers. Snacks & drinks included.', appr: 1, max: 2 }, { k: 'builder', nm: 'Community Builder Pass', p: b, note: 'For community builders, organisers and founders. Snacks & drinks included.', appr: 1, max: 2 }, { k: 'net', nm: 'Networking Pass', p: Math.round(b * .6), note: 'Open to anyone who wants to meet the room. Snacks & drinks included.', max: 4 }, { k: 'sup', nm: 'Supporter Pass', p: Math.round(b * 1.6), note: 'Priority seating and a thank-you in the closing note.', max: 4 }] : [{ k: 'founder', nm: 'Founder Pass', p: 0, note: 'For founders building in the Desi community.', appr: 1, max: 1 }, { k: 'guest', nm: 'Guest Pass', p: 0, note: 'Open to anyone curious to meet the room.', max: 2 }]; }
  if (!ev.price && !ev.pmax) return [{ k: 'rsvp', nm: 'General · RSVP', p: 0, note: 'Free entry' }];
  if (ev.pmax && !ev.price) return [{ k: 'kids', nm: 'Kids under 12', p: 0, note: 'Free with an adult' }, { k: 'ga', nm: 'General', p: Math.round(ev.pmax * .4), note: 'Standing', urg: 'fast' }, { k: 'vip', nm: 'VIP Table', p: ev.pmax, note: 'Reserved table for 4 · welcome drinks', left: 3 }];
  if (ev.longTiers) return [{ k: 'early', nm: 'Early Bird · Front Row Seated Experience with Complimentary Chai & Snacks', p: ev.price, note: 'Includes a reserved seat in the first three rows, a welcome chai, an assorted snack platter served during the interval, and a printed programme signed by the artists. Entry from 18:30 through the artists\' door on Schönhauser Allee.', left: 6, urg: 'few' },
    { k: 'ga', nm: 'General Admission · Unreserved Seating', p: ev.price + 10, note: 'Open seating from row four onwards. First come, first served.' },
    { k: 'patron', nm: 'Patron Circle', p: ev.price * 3, note: 'Private meet & greet after the show, listed as a patron in the programme.', ends: '20 Oct' }];
  const base = ev.price || 0;
  if (ev.group) return [{ k: 'ga', nm: 'General Admission', p: base, note: 'Main deck, standing. Welcome drink on boarding.', urg: 'fast' }, { k: 'vip', nm: 'VIP - Open Bar', p: Math.round(base * 2.7), note: 'Open bar for 4 hours, reserved upper-deck seating.', urg: 'few', left: 7 }, { k: 'grp', nm: 'Group Table', p: 100, note: 'Reserved table on the upper deck for 4 people. Add extra seats for friends joining.', group: 4, extra: 22 }, { k: 'grpx', nm: 'Extra seats', p: 22, hidden: true }];
  return [{ k: 'ga', nm: 'General', p: base, note: 'Standing', left: ev.st === 'few' ? 9 : 0, urg: ev.st === 'few' ? 'few' : ev.st === 'fast' ? 'fast' : '' }, { k: 'vip', nm: 'VIP', p: Math.round(base * 2.2), note: 'Front section · lounge access' }];
}
/* Same title rule as the web (title-split.js): see that file for the rule. Returns [black, red, black-after]. */
const titleParts = (() => {
  var JOIN = /^(ft\.?|feat\.?|featuring|with|x|·|–|—|-|:)$/i;
  var TAIL = /^(\d{2,4}|vol\.?|edition|ed\.|#\d+|\d+(st|nd|rd|th)?)$/i;
  var SMALL = /^(in|of|the|and|&|to|at|for|a|an|on|by)$/i;
  function split(full) {
    var w = String(full || '').replace(/\s+/g, ' ').trim().split(' ').filter(Boolean);
    if (w.length < 2) return [w.join(' '), '', ''];
    var len = w.join(' ').length, s = -1, e = w.length;
    for (var i = w.length - 2; i >= 0; i--) {
      if (JOIN.test(w[i]) || /:$/.test(w[i])) { if (w.length - 1 - i <= 3) s = i + 1; break; }
    }
    if (s < 0) {
      while (e > 1 && w.length - e < 2 && TAIL.test(w[e - 1])) e--;
      if (e < 2) e = w.length;
      s = Math.max(1, e - 2);
      while (s > 1 && SMALL.test(w[s]) && e - s < 3) s--;
      if (SMALL.test(w[s])) s++;
      if (s >= e) return [w.join(' '), '', ''];
    }
    var red = w.slice(s, e).join(' ');
    if (red.length > len * 0.45 && e - s > 1) s = e - 1;
    return [w.slice(0, s).join(' '), w.slice(s, e).join(' '), w.slice(e).join(' ')];
  }
  return (ev) => split(ev.nm);
})();
const titleSize = (n) => (n.length <= 30 ? 28 : n.length <= 55 ? 24 : 22);
const fmtDate = (d) => d.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' });
const doorsOf = (t) => t.replace(/^(\d+)/, m => String(+m - 1).padStart(2, '0'));
/* booking fee rate is set in the CMS (DP.CONFIG.bookingFeePercent); never shown to the buyer, only the amount */
const FEE_PCT = (window.DP && DP.CONFIG && typeof DP.CONFIG.bookingFeePercent === 'number') ? DP.CONFIG.bookingFeePercent : 5; const feeFor = (ev) => ev.feeInc ? 0 : FEE_PCT / 100; const feeOf = (p, ev) => Math.round(p * feeFor(ev) * 100) / 100;
const KI = (f, s = 16, style) => <img src={DP.A + 'icons/' + f} alt="" style={{ width: s, height: s, objectFit: 'contain', ...style }} />;

const HOSTS = [{ initials: 'DB', name: 'Desi Berlin Events', color: 'linear-gradient(135deg,#1D0D31,#3D1B5E)' }, { initials: 'BC', name: 'Bollywood Cruises', color: 'linear-gradient(135deg,#A1304A,#5C1830)' }];
const STAT_META = { fast: ['Filling fast!', 'fast.svg', 'var(--warn-bg)', 'var(--warn-fg)'], few: ['Only few left!', 'fire.svg', 'var(--warn-bg)', 'var(--warn-fg)'], out: ['Sold out!', '', 'var(--out-bg)', 'var(--out-fg)'], wait: ['Waiting list open', 'clock.svg', 'var(--purple-soft)', 'var(--purple)'], appr: ['Approval required', 'clock.svg', 'var(--purple-soft)', 'var(--purple)'], open: ['Open to all', '', 'rgba(18,158,106,.12)', 'var(--green)'] };
const Stat = ({ k, size = 'sm' }) => { const m = STAT_META[k]; if (!m) return null; const lg = size === 'lg'; return <span style={{ display: 'inline-flex', alignItems: 'center', gap: lg ? 6 : 5, height: lg ? 30 : 24, padding: lg ? '0 12px' : '0 9px', borderRadius: 6, background: m[2], color: m[3], fontSize: lg ? 13 : 11.5, fontWeight: 600, whiteSpace: 'nowrap', flex: 'none', boxShadow: k === 'out' ? 'none' : 'var(--stat-shadow)' }}>{m[1] && <img src={DP.A + 'icons/' + m[1]} alt="" style={{ height: lg ? 16 : 13, width: 'auto' }} />}{m[0]}</span>; };
const Lbl = ({ children, style }) => <div style={{ fontFamily: 'var(--dp-font-mono)', fontSize: 10, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--mut2)', fontWeight: 600, ...style }}>{children}</div>;
const H3 = ({ children }) => <h3 style={{ margin: '4px 0 12px', fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 20, letterSpacing: '-.02em', color: 'var(--ink)', lineHeight: 1.2 }}>{children}</h3>;
function Av({ g, size = 30, i }) { return <span style={{ width: size, height: size, borderRadius: '50%', background: g[1], color: '#fff', fontSize: size * .4, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', border: '2px solid var(--bg)', marginLeft: i ? -10 : 0, fontFamily: 'var(--dp-font-display)' }}>{g[0][0]}</span>; }
function Stepper({ v, set, max = 8 }) { const b = (on) => ({ width: 30, height: 30, borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', border: '1px solid var(--line)', background: 'var(--sur)', color: on ? 'var(--ink)' : 'var(--mut2)', fontSize: 17, fontWeight: 500 }); return <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}><button className="press" onClick={() => set(Math.max(0, v - 1))} style={b(v > 0)}>−</button><span style={{ minWidth: 14, textAlign: 'center', fontWeight: 700, fontSize: 14 }}>{v}</span><button className="press" onClick={() => set(Math.min(max, v + 1))} style={b(v < max)}>+</button></div>; }

function GuestListSheet({ ev, open, onClose, booked, onBook }) {
  if (!ev) return null;
  const locked = !booked;
  return <Sheet open={open} onClose={onClose} title="Who's going">
    {locked ? <div style={{ textAlign: 'center', padding: '8px 0 10px' }}><div style={{ display: 'inline-flex', marginBottom: 14 }}>{DP.GUESTS.slice(0, 5).map((x, i) => <Av key={i} g={x} i={i} size={40} />)}</div><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 20, letterSpacing: '-.02em' }}>Book to view guest list</div><p style={{ color: 'var(--mut)', fontSize: 14, margin: '8px 0 20px', lineHeight: 1.5 }}>The full guest list is only visible to ticket holders. Book a ticket to see who else is coming.</p><Btn onClick={() => { onClose(); onBook(); }} icon={<Ico.lock size={16} />}>Book to view guest list</Btn></div>
      : <div>{DP.GUESTS.map((x, i) => <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0', borderBottom: '1px solid var(--line)' }}><Av g={x} size={38} /><div style={{ flex: 1, fontWeight: 700, fontSize: 14 }}>{x[0]}</div></div>)}<div style={{ textAlign: 'center', padding: '14px 0 4px', fontSize: 13, color: 'var(--mut2)' }}>and {(ev.going - 8).toLocaleString('en-GB')} more</div></div>}
  </Sheet>;
}

function EventDetail({ z, ev, onBack, onOpen, onBook, onPaid, closing, booked, pending, declined, onWithdraw, waiting, onWaitlist, onSheet }) {
  const { topInset, bottomInset, city, toast, hero, device, express, sim } = useApp();
  const [loadErr, setLoadErr] = useState(sim === 'evfail');
  const [optin, setOptin] = useState(false); const [orgSheet, setOrgSheet] = useState(''); const [wallet, setWallet] = useState(false); const [terms, setTerms] = useState('');
  const [addr, setAddr] = useState(false); const [follow, setFollow] = useState(false); const [faqOpen, setFaqOpen] = useState(0); const [guests, setGuests] = useState(false);
  const [sc, setSc] = useState(0);
  const tiers = tiersFor(ev);
  const [qty, setQty] = useState({});
  const n = Object.values(qty).reduce((a, b) => a + b, 0);
  const fee = feeFor(ev); const sub = tiers.reduce((s, t) => s + (qty[t.k] || 0) * t.p, 0); const feeTot = Math.round(sub * fee * 100) / 100;
  const free = !ev.price && !ev.pmax, isWait = !!ev.waitlist, isAppr = !!ev.approval;
  const needs = tiers.some(t => qty[t.k] && t.appr); const unit = isAppr ? 'pass' : 'ticket';
  const [withdraw, setWithdraw] = useState(false);
  const cur = (v) => DP.money(v, ev.cc);
  const longVen = ev.ven.length > 34;
  const solid = hero === 'inset' || sc > 300;
  const glass = { background: 'rgba(0,0,0,.35)', color: '#fff', backdropFilter: 'blur(8px)' };
  const regRef = useRef(); const scrRef = useRef();
  const toReg = () => { const el = regRef.current, s = scrRef.current; if (el && s) s.scrollTo({ top: el.offsetTop - topInset - 70, behavior: 'smooth' }); };
  const canBook = isWait || isAppr || n > 0;
  const xp = !booked && !pending && !isWait && !needs && !ev.seated && !ev.questions && n > 0 && sub > 0;
  const ios = device !== 'android', saved = express === 'card';
  const primary = () => { if (booked) return onSheet('ticket', ev); if (isWait) { if (!waiting) onWaitlist(true); return; } if (pending) return; if (!n) return toReg(); onBook(ev, qty); };
  const ctaTxt = booked ? 'View ticket' : isWait ? (waiting ? 'On the waiting list' : 'Join Waiting List') : pending ? 'Request pending' : isAppr && n > 0 ? `${needs ? 'Request' : 'Book'} ${n} pass${n > 1 ? 'es' : ''}${sub > 0 ? ' · ' + cur(sub + feeTot) : ''}` : isAppr ? 'Select a pass' : n > 0 ? `Book now · ${cur(sub + feeTot)}` : free ? 'Reserve free spot' : 'Select tickets';
  if (loadErr) return <div className={'push' + (closing ? ' out' : '')} style={{ position: 'absolute', inset: 0, zIndex: z || 30, background: 'var(--paper)' }}><TopBar onBack={onBack} /><ErrorState title="Couldn't load this event" body="Check your connection and try again." onRetry={() => setLoadErr(false)} /></div>;
  return (
    <div className={'push' + (closing ? ' out' : '')} style={{ position: 'absolute', inset: 0, zIndex: z || 30, background: 'var(--paper)' }}>
      <div ref={scrRef} className="scr" onScroll={e => setSc(e.target.scrollTop)} style={{ paddingBottom: bottomInset + 92, background: 'var(--paper)' }}>
        <div style={{ position: 'sticky', top: 0, zIndex: 8, height: 0 }}>
          <div style={{ position: 'absolute', left: 0, right: 0, top: 0, height: topInset + 58, background: 'var(--paper)', opacity: hero === 'inset' ? Math.min(1, sc / 40) : Math.min(1, Math.max(0, (sc - 260) / 80)), borderBottom: '1px solid var(--line)', transition: 'opacity .15s' }}></div>
          <div style={{ position: 'absolute', left: 12, right: 12, top: topInset + 8, display: 'flex', alignItems: 'center', gap: 8 }}>
            <IconBtn icon={Ico.back} onClick={onBack} style={solid ? { background: 'var(--chip)' } : glass} color={solid ? 'var(--ink)' : '#fff'} label="Back" />
            <div style={{ flex: 1, fontWeight: 700, fontSize: 15, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', opacity: solid ? 1 : 0, transition: 'opacity .2s' }}>{ev.nm}</div>
            <IconBtn icon={Ico.share} onClick={() => onSheet('share', ev)} style={solid ? { background: 'var(--chip)' } : glass} color={solid ? 'var(--ink)' : '#fff'} label="Share" />
            <HeartBtn ev={ev} size={40} glass={!solid} />
          </div>
        </div>
        {/* poster: full image, no fade - title sits below on solid ground like desktop */}
        {hero === 'inset' ? <div style={{ padding: `${topInset + 60}px 20px 0`, display: 'flex', justifyContent: 'center' }}>
          <div style={{ position: 'relative', width: '64%', borderRadius: 16, overflow: 'hidden', boxShadow: '0 22px 44px -22px rgba(29,13,49,.45)', background: 'var(--chip)' }}>
            <img src={ev.img} alt="" style={{ width: '100%', aspectRatio: '4 / 5', height: 'auto', display: 'block', objectFit: 'cover' }} />
            {ev.tag && <span style={{ position: 'absolute', left: 10, top: 10, fontFamily: 'var(--dp-font-mono)', fontWeight: 700, fontSize: 8.5, letterSpacing: '.1em', textTransform: 'uppercase', padding: '5px 9px', borderRadius: 6, background: ev.tag === 'New' ? '#7B5CFF' : '#E54558', color: '#fff' }}>{ev.tag}</span>}
          </div>
        </div> : <div style={{ position: 'relative', overflow: 'hidden', background: 'var(--paper)', padding: `${topInset + 58}px 0 84px`, display: 'flex', justifyContent: 'center' }}>
          <img src={ev.img} alt="" aria-hidden="true" style={{ position: 'absolute', inset: -40, width: 'calc(100% + 80px)', height: 'calc(100% + 80px)', objectFit: 'cover', filter: 'blur(32px) saturate(1.15)', opacity: .8, WebkitMaskImage: 'linear-gradient(180deg,#000 35%,transparent 80%)', maskImage: 'linear-gradient(180deg,#000 35%,transparent 80%)' }} />
          <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(20,10,34,.32) 0%, rgba(20,10,34,.08) 38%, color-mix(in srgb, var(--paper) 55%, transparent) 66%, color-mix(in srgb, var(--paper) 92%, transparent) 80%, var(--paper) 90%, var(--paper) 100%)' }}></div>
          <div style={{ position: 'relative', width: '72%', borderRadius: 14, overflow: 'hidden', boxShadow: '0 1px 0 rgba(255,255,255,.15) inset, 0 10px 24px -12px rgba(20,10,34,.35)', transform: `scale(${Math.max(.94, 1 - sc / 2500)})`, transformOrigin: '50% 0' }}>
            <img src={ev.img} alt="" style={{ width: '100%', aspectRatio: '4 / 5', height: 'auto', display: 'block', objectFit: 'cover', background: '#1D0D31' }} />
            {ev.tag && <span style={{ position: 'absolute', left: 10, top: 10, fontFamily: 'var(--dp-font-mono)', fontWeight: 700, fontSize: 8.5, letterSpacing: '.1em', textTransform: 'uppercase', padding: '5px 9px', borderRadius: 6, background: ev.tag === 'New' ? '#7B5CFF' : '#E54558', color: '#fff' }}>{ev.tag}</span>}
          </div>
        </div>}
        <div style={{ position: 'relative', zIndex: 2, padding: hero === 'inset' ? '20px 20px 0' : '0 20px', marginTop: hero === 'inset' ? 0 : -46 }}>
          <h1 style={{ margin: 0, fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: titleSize(ev.nm), display: '-webkit-box', WebkitBoxOrient: 'vertical', WebkitLineClamp: 3, overflow: 'hidden', lineHeight: 1.15, letterSpacing: '-.015em', color: 'var(--ink)', textWrap: 'pretty' }}>{(() => { const [a, b, c] = titleParts(ev); return <>{a}{b && <> <em style={{ fontStyle: 'italic', fontWeight: 500, color: 'var(--red)' }}>{b}</em></>}{c && ' ' + c}</>; })()}</h1>
          {/* date · location strip (kit icons) */}
          <div style={{ display: 'grid', gap: 14, marginTop: 18, paddingBottom: 18, borderBottom: '1px solid var(--line)' }}>
            <div aria-label="Date" role="group" style={{ display: 'flex', gap: 11, alignItems: 'center' }}>{KI('calendar.svg', 20)}<div style={{ flex: 1, minWidth: 0 }}><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 15 }}>{fmtDate(ev.date).replace(/\s\d{4}$/, '')} · {ev.time}</div>{(() => { const t = window.dpTimes ? dpTimes(ev.nm, false, ev.time) : {}; const s = [t.doors && 'Doors ' + t.doors, t.end && 'Ends ' + t.end].filter(Boolean).join(' · '); return s && <div style={{ fontSize: 12.5, fontWeight: 500, color: 'var(--mut2)', marginTop: 2 }}>{s}</div>; })()}</div></div>
            <div role="button" aria-label="Location" className="press" onClick={() => longVen ? setAddr(!addr) : onSheet('map', ev)} style={{ display: 'flex', gap: 11, alignItems: 'center', textAlign: 'left', cursor: 'pointer' }}>{KI('location.svg', 20)}<div style={{ flex: 1, minWidth: 0 }}><div style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 15, lineHeight: 1.25, display: addr ? 'block' : '-webkit-box', WebkitLineClamp: 1, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{ev.ven && ev.ven !== ev.city ? ev.ven : 'To be announced'}</div><div style={{ fontSize: 12.5, fontWeight: 500, color: 'var(--mut2)', marginTop: 2 }}>{ev.city}, {ev.country}</div></div><button onClick={(e) => { e.stopPropagation(); onSheet('map', ev); }} style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--red)', whiteSpace: 'nowrap' }}>Map</button></div>
          </div>
          {/* Reserve your spot */}
          <div ref={regRef} style={{ marginTop: 22, background: 'var(--sur)', border: '1px solid var(--line)', borderRadius: 18, overflow: 'hidden', boxShadow: '0 8px 28px -14px rgba(15,10,30,.14)' }}>
            <div style={{ padding: '12px 16px', background: 'var(--sur2)', borderBottom: '1px solid var(--line)', fontFamily: 'var(--dp-font-mono)', fontSize: 11, letterSpacing: '.12em', textTransform: 'uppercase', fontWeight: 700, color: 'var(--ink)' }}>{booked ? 'You\'re going' : pending ? 'Request sent' : isWait ? 'Waiting list' : 'Reserve your spot'}</div>
            <div style={{ padding: 16 }}>
            {booked && <div style={{ display: 'flex', gap: 10, alignItems: 'center', padding: '12px 14px', borderRadius: 12, background: 'rgba(18,158,106,.12)', color: 'var(--green)', fontSize: 13, fontWeight: 600 }}>{KI('ticket.svg', 16)}Your ticket is in Bookings.</div>}
            {!booked && isWait && (waiting ? <div className="fade-in" style={{ display: 'grid', gap: 4, padding: '13px 15px', borderRadius: 13, background: 'var(--purple-soft)', color: 'var(--purple)', fontSize: 13.5, lineHeight: 1.45 }}><b>You're on the waiting list</b><span>We'll email you if a spot opens.</span><button onClick={() => onWaitlist(false)} style={{ justifySelf: 'start', marginTop: 4, fontSize: 13, fontWeight: 600, color: 'var(--purple)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Leave waiting list</button></div> : <div style={{ display: 'grid', gap: 8, justifyItems: 'start' }}><Stat k="out" /><p style={{ margin: 0, fontSize: 13.5, color: 'var(--mut)', lineHeight: 1.55 }}>Every ticket is gone. Join the waiting list and we'll email you if a spot opens.</p></div>)}
            {pending && <div className="fade-in" style={{ display: 'grid', gap: 10 }}><div style={{ display: 'flex', gap: 10, alignItems: 'flex-start', fontSize: 13.5, color: 'var(--mut)', lineHeight: 1.5 }}><span style={{ width: 24, height: 24, flex: 'none', borderRadius: '50%', background: 'rgba(18,158,106,.12)', color: 'var(--green)', display: 'grid', placeItems: 'center' }}><Ico.check size={14} stroke={2.4} /></span><span><b style={{ color: 'var(--ink)' }}>{(pending.cats || 1) > 1 ? tierSummary(pending, 'pass') : pending.tier}</b> requested. Pending organiser approval. We'll email you.</span></div>{!withdraw ? <button onClick={() => setWithdraw(true)} style={{ justifySelf: 'start', fontSize: 13, fontWeight: 600, color: 'var(--mut)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Withdraw request</button> : <div className="fade-in" style={{ padding: 12, borderRadius: 12, border: '1px solid var(--line)' }}><p style={{ margin: 0, fontSize: 13, color: 'var(--mut)', lineHeight: 1.5 }}>{pending.total > 0 ? 'Withdraw this request? Your card is released and the spot goes back to the organiser. You can request again while spots last.' : 'Withdraw this request? The spot goes back to the organiser. You can request again while spots last.'}</p><div style={{ display: 'flex', gap: 8, marginTop: 10 }}><Btn small kind="ghost" onClick={() => setWithdraw(false)} style={{ flex: 1, height: 40 }}>Keep request</Btn><Btn small onClick={() => { setWithdraw(false); onWithdraw(pending); }} style={{ flex: 1, height: 40 }}>Withdraw</Btn></div></div>}</div>}
            {!booked && !pending && !isWait && <div style={{ display: 'grid', gap: 10 }}>{declined && <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start', padding: '12px 14px', borderRadius: 12, background: 'var(--out-bg)', color: 'var(--out-fg)', fontSize: 13, lineHeight: 1.5 }}><Ico.info size={17} style={{ flex: 'none', marginTop: 1 }} /><span>Your request wasn't accepted this time.{declined.total > 0 ? ' The hold on your card was released.' : ''}</span></div>}{tiers.filter(t => !t.hidden).map(t => { const q = qty[t.k] || 0, out = t.left === 0 && t.urg === 'out', lock = !!declined && t.appr && !ev.reapply; return <div key={t.k} style={{ border: `1.5px solid ${q ? 'var(--ink)' : 'var(--line)'}`, borderRadius: 13, padding: '13px 14px', opacity: lock ? .55 : 1, background: q ? 'var(--red-soft)' : 'var(--sur)', boxShadow: q ? '0 0 0 3px rgba(229,69,88,.08)' : 'none', transition: 'all .15s' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, paddingBottom: 12, borderBottom: '1px solid var(--line)' }}><div style={{ flex: 1, minWidth: 0, display: 'grid', gap: 6, justifyItems: 'start' }}><b style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 15, lineHeight: 1.3, textWrap: 'pretty', overflowWrap: 'anywhere' }}>{t.nm}</b>{isAppr ? <Stat k={t.appr ? 'appr' : 'open'} /> : t.urg && <Stat k={t.urg} />}</div><div style={{ flex: 'none', paddingTop: 1 }}>{lock ? <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--mut2)', whiteSpace: 'nowrap' }}>Not available for you</span> : <Stepper v={q} set={v => setQty(t.group && !v ? { ...qty, [t.k]: 0, grpx: 0 } : { ...qty, [t.k]: v })} max={t.max || t.left || 8} />}</div></div>
              <div style={{ paddingTop: 12 }}><span style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 19, letterSpacing: '-.02em', color: t.p ? 'var(--price)' : 'var(--green)' }}>{t.p ? cur(t.p) : 'Free'}</span>{t.p > 0 && fee > 0 && <span style={{ fontSize: 12.5, color: 'var(--mut)', marginLeft: 6 }}>+ {cur(feeOf(t.p, ev))} fee</span>}<div style={{ marginTop: 8, fontSize: 13, color: 'var(--mut)', lineHeight: 1.55, overflowWrap: 'anywhere' }}>{t.note}</div>{t.left > 0 && <div style={{ marginTop: 8, fontSize: 12, fontWeight: 700, color: 'var(--warn-fg)' }}>{t.left} tickets left at this price</div>}{t.ends && <div style={{ marginTop: 8, fontSize: 12, color: 'var(--mut2)' }}>Sales end {t.ends}</div>}{t.group && <div style={{ marginTop: 12, paddingTop: 12, borderTop: '1px dashed var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, opacity: q ? 1 : .45, pointerEvents: q ? 'auto' : 'none', transition: 'opacity .2s' }}><div><div style={{ fontSize: 13, fontWeight: 700 }}>Extra seats</div><div style={{ fontSize: 12, color: 'var(--mut)', marginTop: 1 }}>{cur(t.extra)}{fee ? ' + ' + cur(fee) + ' fee' : ''} each · {q ? (q * t.group + (qty.grpx || 0)) + ' people at your table' : 'Add a table first'}</div></div><Stepper v={qty.grpx || 0} set={v => setQty({ ...qty, grpx: v })} max={4 * Math.max(1, q)} /></div>}</div>
            </div>; })}
              {n > 0 && <div className="fade-in" style={{ padding: '12px 14px', borderRadius: 12, border: '1px solid var(--line)', fontSize: 13 }}><Lbl style={{ marginBottom: 8 }}>{needs ? 'Your request' : 'Your order'}</Lbl>{tiers.filter(t => qty[t.k]).map(t => <div key={t.k} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 10, color: 'var(--mut)', padding: '3px 0' }}><span style={{ flex: 1, minWidth: 0, lineHeight: 1.4, overflowWrap: 'anywhere' }}>{t.group ? `${qty[t.k]} × ${t.nm} (${qty[t.k] * t.group} pax)` : t.k === 'grpx' ? `${qty[t.k]} × extra seat${qty[t.k] > 1 ? 's' : ''}` : `${qty[t.k]} × ${t.nm}`}</span><span style={{ flex: 'none', whiteSpace: 'nowrap' }}>{t.p ? cur(qty[t.k] * t.p) : 'Free'}</span></div>)}{feeTot > 0 && <div style={{ display: 'flex', justifyContent: 'space-between', color: 'var(--mut)', padding: '3px 0' }}><span>Booking fee</span><span>{cur(feeTot)}</span></div>}<div style={{ display: 'flex', justifyContent: 'space-between', fontWeight: 700, fontSize: 15, paddingTop: 8, marginTop: 6, borderTop: '1px solid var(--line)' }}><span>Total</span><span>{cur(sub + feeTot)}</span></div>{isAppr && <div style={{ marginTop: 8, fontSize: 12, color: 'var(--mut)' }}>{needs ? (sub > 0 ? 'Charged only once the organiser approves.' : 'The organiser confirms each request.') : "No approval needed. You're booking straight away."}</div>}</div>}
              {xp && <div className="fade-in"><OptIn on={optin} set={setOptin} /></div>}
            </div>}
            </div>
          </div>
          {/* Who's going */}
          {ev.guests && <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)' }}><Lbl>Who's going</Lbl><button className="press" onClick={() => setGuests(true)} style={{ display: 'flex', alignItems: 'center', gap: 11, marginTop: 10, textAlign: 'left' }}><span style={{ display: 'inline-flex' }}>{DP.GUESTS.slice(0, 4).map((x, i) => <Av key={i} g={x} i={i} size={32} />)}</span><span style={{ fontSize: 14, color: 'var(--ink)', textDecoration: 'underline', textUnderlineOffset: 3, textDecorationColor: 'var(--line)' }}>{booked ? <><b>{DP.GUESTS[0][0]}, {DP.GUESTS[1][0]}</b> and {ev.going.toLocaleString('en-GB')} others are going</> : <><b>{DP.GUESTS[0][0]}, {DP.GUESTS[1][0]}</b> and others are going</>}</span></button></div>}
          {/* About - full, no clamp */}
          <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)' }}><Lbl>About</Lbl><H3>{ev.nm.split(' · ')[0].split(':')[0]} comes to {ev.city}.</H3><p style={{ margin: 0, fontSize: 14, lineHeight: 1.6, color: 'var(--mut)' }}>{LONG[ev.cat] || LONG.default}</p><p style={{ margin: '12px 0 0', fontSize: 14, lineHeight: 1.6, color: 'var(--mut)' }}>Hosted with the local Desi community; expect a warm, loud and welcoming crowd.</p></div>
        </div>
        {ev.media && <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)', margin: '28px 20px 0' }}><Lbl>Photos & videos</Lbl><H3>Get a feel for it</H3>
          <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr', gridTemplateRows: '120px 120px', gap: 6, borderRadius: 14, overflow: 'hidden' }}>{DP.MEDIA.slice(0, 3).map((m, i) => <button key={i} className="press" onClick={() => onSheet('media', { i, ev })} style={{ position: 'relative', gridRow: i === 0 ? '1 / 3' : 'auto', overflow: 'hidden', background: 'var(--chip)' }}><img src={m} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />{i === 1 && <span style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', background: 'rgba(0,0,0,.25)' }}><span style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(255,255,255,.9)', display: 'grid', placeItems: 'center', color: '#1D0D31' }}><Ico.play size={18} fill="currentColor" stroke={0} /></span></span>}{i === 2 && <span style={{ position: 'absolute', right: 8, bottom: 8, fontSize: 11, fontWeight: 700, padding: '4px 8px', borderRadius: 6, background: 'rgba(0,0,0,.55)', color: '#fff' }}>+{DP.MEDIA.length - 3} more</span>}</button>)}</div></div>}
        <div style={{ padding: '0 20px' }}>
          {ev.faq && <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)' }}><Lbl>FAQ</Lbl><H3>Common questions</H3><div style={{ borderTop: '1px solid var(--line)' }}>{DP.FAQ.filter(f => isWait || !f.q.includes('waiting')).map((f, i) => <div key={i} style={{ borderBottom: '1px solid var(--line)' }}><button onClick={() => setFaqOpen(faqOpen === i ? -1 : i)} style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', textAlign: 'left', padding: '13px 0', fontWeight: 600, fontSize: 14 }}><span style={{ flex: 1 }}>{f.q}</span><Ico.down size={16} style={{ color: 'var(--mut2)', transform: faqOpen === i ? 'rotate(180deg)' : 'none', transition: 'transform .25s' }} /></button><div style={{ display: 'grid', gridTemplateRows: faqOpen === i ? '1fr' : '0fr', transition: 'grid-template-rows .3s cubic-bezier(.2,.8,.2,1)' }}><div style={{ overflow: 'hidden' }}><p style={{ margin: '0 0 14px', fontSize: 13.5, lineHeight: 1.5, color: 'var(--mut)' }}>{f.a}</p></div></div></div>)}</div></div>}
          <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)' }}><Lbl style={{ color: 'var(--red)' }}>Organiser</Lbl><div style={{ display: 'grid', gap: 10, marginTop: 12 }}>{HOSTS.slice(0, 1).map(h => <div key={h.name} style={{ display: 'flex', alignItems: 'center', gap: 11 }}><span style={{ width: 40, height: 40, borderRadius: 11, background: h.color, color: '#fff', display: 'grid', placeItems: 'center', fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, flex: 'none', overflow: 'hidden' }}>{h.img ? <img src={h.img} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : h.initials}</span><b style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, letterSpacing: '-.01em' }}>{h.name}</b></div>)}</div>{HOSTS.length > 1 && <><Lbl style={{ color: 'var(--red)', marginTop: 20 }}>{HOSTS.length > 2 ? 'Co-organisers' : 'Co-organiser'}</Lbl><div style={{ display: 'grid', gap: 10, marginTop: 12 }}>{HOSTS.slice(1).map(h => <div key={h.name} style={{ display: 'flex', alignItems: 'center', gap: 11 }}><span style={{ width: 40, height: 40, borderRadius: 11, background: h.color, color: '#fff', display: 'grid', placeItems: 'center', fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, flex: 'none', overflow: 'hidden' }}>{h.img ? <img src={h.img} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : h.initials}</span><b style={{ fontFamily: 'var(--dp-font-display)', fontWeight: 700, fontSize: 14, letterSpacing: '-.01em' }}>{h.name}</b></div>)}</div></>}
            <div style={{ display: 'grid', gap: 0, marginTop: 14, paddingTop: 6, borderTop: '1px solid var(--line)' }}>{[['Message organiser', 'msg', <path d="M4 4h16v12H5.17L4 17.17z" />], ['Report event', 'report', <path d="M12 9v4M12 17h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />]].map(([l, k, p]) => <button key={k} onClick={() => setOrgSheet(k)} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, minHeight: 32, fontSize: 13.5, fontWeight: 500, color: 'var(--mut)', textAlign: 'left' }}><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">{p}</svg>{l}</button>)}</div></div>
        </div>
      </div>
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 9, padding: `10px 16px ${bottomInset + 10}px`, background: 'var(--tabbg)', backdropFilter: 'blur(18px)', borderTop: '1px solid var(--line)', boxShadow: '0 -8px 24px -12px rgba(29,13,49,.18)' }}>
        {xp ? <div className="fade-in" style={{ display: 'grid', gap: 8 }}>
          <div style={{ fontSize: 11, color: 'var(--mut)', textAlign: 'center', lineHeight: 1.45 }}>By paying you agree to the <a onClick={() => setTerms('event')} style={{ color: 'var(--ink)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Event Terms</a>, <a onClick={() => setTerms('terms')} style={{ color: 'var(--ink)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Terms</a> &amp; <a onClick={() => setTerms('privacy')} style={{ color: 'var(--ink)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Privacy</a>.</div>
          {saved ? <Btn onClick={() => setWallet(true)} style={{ height: 52, fontSize: 15.5 }} icon={<Ico.lock size={16} />}>{`Pay ${cur(sub + feeTot)} · Visa •• 4242`}</Btn>
            : <button className="press" onClick={() => setWallet(true)} style={{ height: 52, borderRadius: 12, background: '#000', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, fontSize: 16, fontWeight: 600, border: ios ? 0 : '1px solid #3c4043' }}>{ios ? <Brand.apple /> : <Brand.google />}Pay<span style={{ opacity: .55, margin: '0 4px' }}>·</span>{cur(sub + feeTot)}</button>}
          <button onClick={() => onBook(ev, qty)} style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--mut)', textDecoration: 'underline', textUnderlineOffset: 2 }}>Other ways to pay or add a promo code</button>
        </div> : <Btn onClick={primary} kind={booked || (isWait && waiting) ? 'ghost' : 'primary'} style={{ height: 52, fontSize: 15.5, ...(!booked && !isWait && (pending || n === 0) ? { background: '#EDE3D2', color: 'var(--mut)' } : {}) }} icon={booked ? <Ico.qr size={18} /> : isWait ? (waiting ? <Ico.check size={18} /> : <Ico.clock size={18} />) : <Ico.check size={18} />}>{ctaTxt}</Btn>}
      </div>
      <WalletSheet open={wallet} onClose={() => setWallet(false)} ios={ios} saved={saved} ev={ev} lines={tiers.filter(t => qty[t.k]).map(t => [`${qty[t.k]} × ${t.nm}`, t.p * qty[t.k]])} fee={feeTot} total={sub + feeTot} onDone={() => { setWallet(false); onPaid({ ev, qty, tiers, total: sub + feeTot, pm: saved ? 'Visa •• 4242' : ios ? 'Apple Pay' : 'Google Pay', n, status: 'confirmed', optin }); }} />
      <MessageOrganiser open={orgSheet === 'msg'} onClose={() => setOrgSheet('')} ev={ev} />
      <ReportEvent open={orgSheet === 'report'} onClose={() => setOrgSheet('')} />
      <TermsSheet open={!!terms} tab={terms} setTab={setTerms} onClose={() => setTerms('')} />
      <GuestListSheet ev={ev} open={guests} onClose={() => setGuests(false)} booked={booked} onBook={() => n ? onBook(ev, qty) : toReg()} />
    </div>
  );
}

function Success({ booking, onTicket, onHome }) {
  const { topInset, bottomInset } = useApp();
  const ev = booking.ev; const [ph, setPh] = useState(0);
  useEffect(() => { const t = [setTimeout(() => setPh(1), 900), setTimeout(() => setPh(2), 1700), setTimeout(() => setPh(3), 2500)]; return () => t.forEach(clearTimeout); }, []);
  const C = 2 * Math.PI * 46;
  return <div style={{ position: 'absolute', inset: 0, zIndex: 35, overflow: 'hidden', background: 'radial-gradient(90% 60% at 50% 30%, #2E1A45 0%, #1D0D31 55%, #0E0618 100%)', color: '#fff', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: `${topInset + 10}px 24px ${bottomInset + 20}px`, animation: 'dpFade .3s ease both' }}>
    <div style={{ position: 'absolute', left: '50%', top: '38%', width: 420, height: 420, margin: '-210px 0 0 -210px', borderRadius: '50%', background: ph >= 1 ? 'radial-gradient(circle, rgba(62,213,152,.3), transparent 62%)' : 'radial-gradient(circle, rgba(229,69,88,.3), transparent 62%)', transition: 'background .6s', animation: 'dpHaze 2.4s ease-in-out infinite' }}></div>
    {/* ring → check → confetti */}
    <div style={{ position: 'relative', width: 108, height: 108, flex: 'none', transform: ph >= 2 ? 'scale(.78) translateY(-8px)' : 'none', transition: 'transform .6s cubic-bezier(.2,.8,.2,1)' }}>
      <svg width="108" height="108" viewBox="0 0 108 108" style={{ position: 'absolute', inset: 0, transform: 'rotate(-90deg)' }}><circle cx="54" cy="54" r="46" fill="none" stroke="rgba(255,255,255,.12)" strokeWidth="5" /><circle cx="54" cy="54" r="46" fill="none" stroke={ph >= 1 ? '#3ED598' : '#E54558'} strokeWidth="5" strokeLinecap="round" strokeDasharray={C} style={{ strokeDashoffset: C, animation: 'dpRingFill .85s cubic-bezier(.4,0,.2,1) .05s forwards', transition: 'stroke .3s' }} /></svg>
      <div style={{ position: 'absolute', inset: 12, borderRadius: '50%', background: ph >= 1 ? '#3ED598' : 'rgba(255,255,255,.06)', display: 'grid', placeItems: 'center', transition: 'background .35s', boxShadow: ph >= 1 ? '0 0 50px rgba(62,213,152,.5)' : 'none' }}>{ph >= 1 && <svg className="tick" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="#0E0618" strokeWidth="2.8" strokeLinecap="round" strokeLinejoin="round"><path d="m5 12.5 4.5 4.5L19 7" /></svg>}</div>
      {ph >= 1 && <span className="burst" style={{ inset: -40 }}><b style={{ borderColor: '#3ED598' }}></b>{[...Array(20)].map((_, i) => { const r = i / 20 * Math.PI * 2, d = 110 + (i % 3) * 30; return <i key={i} style={{ width: i % 2 ? 8 : 5, height: i % 2 ? 5 : 8, borderRadius: 2, margin: -3, background: ['#E54558', '#3ED598', '#B9A6FF', '#FFD166', '#fff'][i % 5], '--dx': Math.cos(r) * d + 'px', '--dy': Math.sin(r) * d + 'px', animationDuration: '1.1s' }}></i>; })}</span>}
    </div>
    <h1 key={ph >= 1 ? 'a' : 'b'} className="rise" style={{ margin: '14px 0 0', fontFamily: 'var(--dp-font-display)', fontWeight: 600, fontSize: 30, letterSpacing: '-.025em', color: '#fff', textAlign: 'center' }}>{ph >= 1 ? <>You're <em style={{ fontStyle: 'italic', fontWeight: 500, color: '#FF8E9B' }}>going!</em></> : 'Confirming payment…'}</h1>
    {/* ticket rises */}
    <div style={{ width: '100%', maxWidth: 300, marginTop: 22, opacity: ph >= 2 ? 1 : 0, transform: ph >= 2 ? 'none' : 'translateY(60px) rotateX(30deg) scale(.92)', transition: 'all .7s cubic-bezier(.2,.8,.2,1)', perspective: 800 }}>
      <div style={{ borderRadius: 18, background: '#fff', color: '#1D0D31', overflow: 'hidden', boxShadow: '0 30px 60px -24px rgba(0,0,0,.7)' }}>
        <div style={{ display: 'flex', gap: 12, alignItems: 'center', padding: 14, borderBottom: '2px dashed #EEE8F2' }}><img src={ev.img} alt="" style={{ width: 48, height: 60, borderRadius: 9, objectFit: 'cover' }} /><div style={{ minWidth: 0 }}><div style={{ fontFamily: 'var(--dp-font-mono)', fontSize: 9, color: '#E54558', fontWeight: 700, letterSpacing: '.08em' }}>{ev.day} · {ev.dateLbl.toUpperCase()} · {ev.time}</div><div style={{ fontWeight: 700, fontSize: 14, lineHeight: 1.2, marginTop: 3, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{ev.nm}</div><div style={{ fontSize: 11.5, color: '#6B6478', marginTop: 3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{tierSummary(booking)}</div></div></div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14 }}><div style={{ position: 'relative', width: 72, height: 72, flex: 'none' }}><QRPattern seed={(booking.code || 'x').length * 7 + 3} size={72} /><span style={{ position: 'absolute', left: 0, right: 0, height: 2, background: '#E54558', boxShadow: '0 0 8px #E54558', animation: ph >= 2 ? 'scTicket 1.4s ease-in-out .3s 2' : 'none', opacity: 0 }}></span></div><div style={{ fontSize: 12, color: '#6B6478', lineHeight: 1.45 }}>Ticket ready. Show this QR at the door. Also sent to {DP.USER.email}.</div></div>
      </div>
    </div>
    <div style={{ width: '100%', maxWidth: 300, marginTop: 24, display: 'grid', gap: 10, opacity: ph >= 3 ? 1 : 0, transform: ph >= 3 ? 'none' : 'translateY(16px)', transition: 'all .5s cubic-bezier(.2,.8,.2,1)', pointerEvents: ph >= 3 ? 'auto' : 'none' }}><Btn onClick={onTicket} icon={<Ico.qr size={18} />}>View ticket</Btn><Btn kind="ghost" onClick={onHome} style={{ background: 'rgba(255,255,255,.1)', color: '#fff' }}>Back to home</Btn></div>
  </div>;
}

Object.assign(window, { titleParts, HOSTS, feeOf, FEE_PCT, STAT_META, EventDetail, Success, tiersFor, fmtDate, doorsOf, feeFor, Av, Stat, Lbl, KI, Stepper });
