/* =========================================================================
   DR. BANANA CLUB — MEMBERSHIP APP KIT · DETAIL
   Detail screens (Event, Vault, Tonight), shared chrome (DetailHead),
   and the EVENTS / VAULT_ITEMS canonical data sets. Loaded after
   kit-screens.jsx; exposes globals at the bottom for kit-app.jsx.
   ========================================================================= */

/* -----  EVENTS  -----
   Canonical event records. List screen (EventsScreen) and detail screen
   (EventDetail) both read from this array. Index = event id.
*/
const EVENTS = [
  {
    date: 'FRI 02.05',
    time: '23:00',
    title: 'Drop 1.0 · Opening',
    artist: 'ALUSTRA · NOMAD · K.O.RE',
    tag: 'INNER CIRCLE ONLY',
    variant: 'accent',
    lead: 'Drop 1.0. The opening. Three acts, one room, one rule — door closes at 02:00 and does not reopen.',
    lineup: [
      { act: 'ALUSTRA', slot: 'HEADLINE · 23:00', kind: 'SET' },
      { act: 'NOMAD',   slot: '01:30',            kind: 'SET' },
      { act: 'K.O.RE',  slot: '03:00',            kind: 'CLOSE' },
    ],
    location: '28.ROOM ● SÃO PAULO',
    coords:   '−23.5505° / −46.6333°',
  },
  {
    date: 'SAT 10.05',
    time: '00:00',
    title: 'Berlin Import',
    artist: 'guest (name withheld)',
    tag: 'EARLY ACCESS',
    variant: 'light',
    lead: 'A guest from elsewhere. The booking is real; the name is not yet yours to know.',
    lineup: [
      { act: '████ ████████', slot: 'HEADLINE · 00:00', kind: 'SET' },
      { act: 'NOMAD',          slot: 'WARMUP · 22:00',  kind: 'WARMUP' },
    ],
    location: '28.ROOM ● SÃO PAULO',
    coords:   '−23.5505° / −46.6333°',
  },
  {
    date: 'FRI 23.05',
    time: '??:??',
    title: 'Black Room Session',
    artist: 'lineup disclosed at door',
    tag: 'SECRET',
    variant: 'secret',
    lead: 'The lineup is disclosed at the door. The door knows your face.',
    lineup: [
      { act: '██████ ████', slot: 'TBA · ??:??', kind: 'TBA' },
      { act: '██████ ████', slot: 'TBA · ??:??', kind: 'TBA' },
      { act: '██████ ████', slot: 'TBA · ??:??', kind: 'TBA' },
    ],
    location: 'disclosed at door',
    coords:   null,
  },
  {
    date: 'SAT 07.06',
    time: '22:00',
    title: 'Residency · Night 09',
    artist: 'SUB:ROM b2b NOMAD',
    tag: 'PUBLIC',
    variant: 'muted',
    lead: 'Night nine of the residency. Doors at 22:00, last entry 02:30.',
    lineup: [
      { act: 'SUB:ROM b2b NOMAD', slot: 'HEADLINE · 23:00', kind: 'B2B' },
      { act: 'K.O.RE',             slot: 'CLOSE · 04:00',    kind: 'CLOSE' },
    ],
    location: '28.ROOM ● SÃO PAULO',
    coords:   '−23.5505° / −46.6333°',
  },
];

/* -----  VAULT ITEMS  -----
   Canonical vault records. VaultScreen reads .kind/.title/.meta/.year for
   the list; VaultDetail reads .duration/.tracks/.note (audio) or .pages
   (document). Audio kinds are SET / FRAGMENT / PLAYLIST. DOC is the
   document kind.
*/
const VAULT_ITEMS = [
  {
    kind: 'SET',
    title: 'Nightshift',
    meta: '120 min · ALUSTRA · 03.24',
    year: '2024',
    duration: '02:00:00',
    tracks: [
      { n: '01', title: 'Cold open',     dur: '08:14' },
      { n: '02', title: 'Tunnel',        dur: '12:42' },
      { n: '03', title: 'Hours',         dur: '18:30' },
      { n: '04', title: 'Inner circle',  dur: '21:08' },
      { n: '05', title: 'Last call',     dur: '14:55' },
      { n: '06', title: 'Outro',         dur: '44:31' },
    ],
    note: 'Recorded at 28.ROOM, 03.24 — first hour omitted.',
  },
  {
    kind: 'FRAGMENT',
    title: 'Ringer Loop (unreleased)',
    meta: 'NOMAD · 4:12',
    year: '2025',
    duration: '04:12',
    tracks: [
      { n: '01', title: 'Ringer Loop', dur: '04:12' },
    ],
    note: null,
  },
  {
    kind: 'SET',
    title: 'After Hours',
    meta: '6h · archival · K.O.RE',
    year: '2024',
    duration: '06:00:00',
    tracks: [
      { n: '01', title: 'Side A', dur: '01:30:00' },
      { n: '02', title: 'Side B', dur: '01:30:00' },
      { n: '03', title: 'Side C', dur: '01:30:00' },
      { n: '04', title: 'Side D', dur: '01:30:00' },
    ],
    note: 'Archival pull from the K.O.RE residency, summer 2024.',
  },
  {
    kind: 'PLAYLIST',
    title: 'Residency canon vol.1',
    meta: '38 tracks',
    year: '2025',
    duration: '04:48:30',
    tracks: [
      { n: '01', title: 'opening invocation', dur: '06:12' },
      { n: '02', title: 'second pass',        dur: '07:48' },
      { n: '03', title: 'cold spread',        dur: '08:30' },
      { n: '04', title: 'tunnel reprise',     dur: '09:14' },
      { n: '05', title: 'inner circle pt.2',  dur: '11:22' },
      { n: '06', title: 'last call (edit)',   dur: '08:01' },
      { n: '07', title: '— interlude —',      dur: '02:55' },
      { n: '08', title: 'after hours · A',    dur: '14:30' },
      { n: '09', title: 'after hours · B',    dur: '12:18' },
      { n: '10', title: 'closing invocation', dur: '07:40' },
    ],
    note: null,
  },
  {
    kind: 'DOC',
    title: 'Polyrhythm sketches',
    meta: 'PDF · 12 pages',
    year: '2026',
    pages: 12,
    note: null,
  },
  {
    kind: 'FRAGMENT',
    title: 'Basement tape · side A',
    meta: 'SUB:ROM · 22:00',
    year: '2025',
    duration: '22:00',
    tracks: [
      { n: '01', title: 'Basement tape · side A', dur: '22:00' },
    ],
    note: null,
  },
];

/* -----  DETAIL HEAD  -----
   Replaces TopMeta on detail screens. Mono row with text-button back
   affordance reading "← S/0{n}" (always 1 in this iteration).
*/
const DetailHead = ({ depth = 1, code = '023', dark, onBack }) => {
  const hairline = dark ? 'var(--db-d-hairline)' : 'var(--db-hairline)';
  const ink      = dark ? 'var(--db-d-ink)'      : 'var(--db-ink)';
  const silver   = dark ? 'var(--db-d-silver)'   : 'var(--db-silver)';
  return (
    <div
      style={{
        display: 'flex',
        gap: 12,
        alignItems: 'center',
        padding: '10px 0 8px',
        borderBottom: `1px solid ${hairline}`,
        fontFamily: 'var(--font-mono)',
        fontSize: 10,
        letterSpacing: '0.08em',
        textTransform: 'uppercase',
      }}
    >
      <button
        onClick={onBack}
        style={{
          background: 'transparent',
          border: 0,
          padding: 0,
          cursor: 'pointer',
          fontFamily: 'var(--font-mono)',
          fontSize: 10,
          letterSpacing: '0.1em',
          textTransform: 'uppercase',
          color: ink,
        }}
      >
        ← S/0{depth}
      </button>
      <span style={{ color: silver }}>DR.BANANA</span>
      <span style={{ color: silver }}>●</span>
      <span style={{ color: silver }}>28.ROOM</span>
      <span style={{ marginLeft: 'auto', color: silver }}>NO. {code}</span>
    </div>
  );
};

/* -----  EVENT DETAIL  -----
   Push-style detail for a single event. variant='event' default; 'tonight'
   adds the acid-yellow PASS READY strip and switches the action button.
*/
const EventDetail = ({ id, dark, variant = 'event', onBack }) => {
  const e = (window.EVENTS || [])[id];
  const ink      = dark ? 'var(--db-d-ink)'       : 'var(--db-ink)';
  const ink2     = dark ? 'var(--db-d-ink-2)'     : 'var(--db-ink-2)';
  const graphite = dark ? 'var(--db-d-graphite)'  : 'var(--db-graphite)';
  const hairline = dark ? 'var(--db-d-hairline)'  : 'var(--db-hairline)';
  const surface  = dark ? 'var(--db-d-surface)'   : 'var(--db-cream)';
  if (!e) {
    return (
      <div
        style={{
          position: 'relative',
          width: '100%',
          minHeight: '100%',
          padding: '0 20px',
          boxSizing: 'border-box',
          color: ink,
          fontFamily: 'var(--font-sans)',
        }}
      >
        <DetailHead depth={1} dark={dark} onBack={onBack} />
        <div
          style={{
            padding: 24,
            fontFamily: 'var(--font-mono)',
            fontSize: 11,
            letterSpacing: '0.08em',
            textTransform: 'uppercase',
            color: graphite,
          }}
        >
          EVENT NOT FOUND · ID={String(id)}
        </div>
      </div>
    );
  }

  const isSecret = e.tag === 'SECRET';
  const baseAction =
    e.tag === 'SECRET'              ? 'WAITLIST' :
    e.tag === 'PUBLIC'              ? 'OPEN DOORS' :
                                       'RSVP';
  const actionLabel = variant === 'tonight' ? 'SHOW QR' : baseAction;

  const [confirmed, setConfirmed] = React.useState(false);
  const [showQr, setShowQr] = React.useState(false);
  React.useEffect(() => {
    if (!confirmed) return;
    const tid = setTimeout(() => setConfirmed(false), 2000);
    return () => clearTimeout(tid);
  }, [confirmed]);
  React.useEffect(() => {
    if (!showQr) return;
    const tid = setTimeout(() => setShowQr(false), 3000);
    return () => clearTimeout(tid);
  }, [showQr]);
  const onAction = () => {
    if (variant === 'tonight') return setShowQr(true);
    setConfirmed(true);
  };

  const monoLabel = {
    fontFamily: 'var(--font-mono)',
    fontSize: 10,
    letterSpacing: '0.08em',
    textTransform: 'uppercase',
    color: graphite,
  };
  const sectionKicker = { ...monoLabel, marginBottom: 8 };

  return (
    <div
      style={{
        position: 'relative',
        width: '100%',
        minHeight: '100%',
        padding: '0 20px',
        boxSizing: 'border-box',
        color: ink,
        fontFamily: 'var(--font-sans)',
      }}
    >
      <DetailHead depth={1} dark={dark} onBack={onBack} />

      {/* Editorial head: kicker + title + meta on the left, EventTag on the right */}
      <div
        style={{
          padding: '20px 0',
          borderBottom: `1px solid ${hairline}`,
          display: 'flex',
          gap: 16,
          alignItems: 'flex-end',
          justifyContent: 'space-between',
        }}
      >
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ ...monoLabel, marginBottom: 8 }}>
            § {variant === 'tonight' ? 'TONIGHT' : 'EVENT'}
          </div>
          <h2
            style={{
              margin: 0,
              fontFamily: 'var(--font-sans-narrow)',
              fontWeight: 700,
              fontSize: 32,
              lineHeight: 0.95,
              letterSpacing: '-0.02em',
              color: ink,
            }}
          >
            {e.title}
          </h2>
          <div style={{ ...monoLabel, marginTop: 10, color: graphite }}>
            {e.date} · {e.time}
          </div>
        </div>
        <div style={{ flexShrink: 0 }}>
          <EventTag variant={e.variant} label={e.tag} dark={dark} />
        </div>
      </div>

      {/* Lead paragraph — italic serif */}
      <div style={{ padding: '18px 0', borderBottom: `1px solid ${hairline}` }}>
        <p
          style={{
            margin: 0,
            fontFamily: 'var(--font-serif-italic)',
            fontStyle: 'italic',
            fontSize: 18,
            lineHeight: 1.55,
            color: ink,
          }}
        >
          {e.lead}
        </p>
      </div>

      {/* Lineup ledger */}
      <div style={{ padding: '18px 0', borderBottom: `1px solid ${hairline}` }}>
        <div style={sectionKicker}>§ LINEUP</div>
        {e.lineup.map((row, i) => (
          <div
            key={i}
            style={{
              display: 'grid',
              gridTemplateColumns: 'minmax(120px, 1fr) minmax(120px, 1fr) auto',
              gap: 12,
              alignItems: 'baseline',
              padding: '10px 0',
              borderTop: i === 0 ? 'none' : `1px dashed ${hairline}`,
            }}
          >
            <span style={{ ...monoLabel, color: ink }}>{row.act}</span>
            <span
              style={{
                fontFamily: 'var(--font-serif-italic)',
                fontStyle: 'italic',
                fontSize: 14,
                color: ink2,
              }}
            >
              {row.slot}
            </span>
            <span style={{ ...monoLabel, color: graphite }}>{row.kind}</span>
          </div>
        ))}
      </div>

      {/* Location block */}
      <div style={{ padding: '18px 0', borderBottom: `1px solid ${hairline}` }}>
        <div style={sectionKicker}>§ LOCATION</div>
        {isSecret ? (
          <div style={{ ...monoLabel, color: ink }}>disclosed at door</div>
        ) : (
          <>
            <div style={{ ...monoLabel, color: ink, fontSize: 11 }}>{e.location}</div>
            {e.coords && (
              <div style={{ ...monoLabel, color: graphite, marginTop: 4 }}>{e.coords}</div>
            )}
          </>
        )}
      </div>

      {/* Tonight-only PASS READY strip */}
      {variant === 'tonight' && (
        <div
          style={{
            margin: '18px 0 0',
            padding: '10px 12px',
            background: 'var(--db-acid)',
            color: 'var(--db-ink)',
            fontFamily: 'var(--font-mono)',
            fontSize: 11,
            letterSpacing: '0.1em',
            textTransform: 'uppercase',
            borderRadius: 2,
          }}
        >
          PASS READY · {e.time} · ENTRY OPEN
        </div>
      )}

      {/* Action row */}
      <div style={{ padding: '18px 0 28px' }}>
        <button
          type="button"
          onClick={onAction}
          style={{
            width: '100%',
            padding: '14px 16px',
            background: 'transparent',
            border: `1px solid ${ink}`,
            borderRadius: 2,
            cursor: 'pointer',
            fontFamily: 'var(--font-mono)',
            fontSize: 11,
            letterSpacing: '0.12em',
            textTransform: 'uppercase',
            color: ink,
          }}
        >
          {confirmed ? 'CONFIRMED ●' : actionLabel}
        </button>
      </div>

      {/* QR overlay (tonight + SHOW QR pressed) */}
      {showQr && (
        <div
          onClick={() => setShowQr(false)}
          style={{
            position: 'fixed',
            inset: 0,
            background: 'rgba(10,9,8,0.55)',
            zIndex: 100,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <div
            style={{
              width: 220,
              height: 220,
              background: surface,
              border: `1px solid ${ink}`,
              borderRadius: 2,
              display: 'grid',
              gridTemplateColumns: 'repeat(11, 1fr)',
              gridTemplateRows: 'repeat(11, 1fr)',
              padding: 14,
              gap: 2,
            }}
          >
            {Array.from({ length: 121 }).map((_, i) => (
              <span
                key={i}
                style={{
                  background: (i * 7 + 13) % 3 === 0 ? ink : 'transparent',
                }}
              />
            ))}
          </div>
        </div>
      )}
    </div>
  );
};

/* -----  VAULT DETAIL  -----
   Two layouts:
     audio: SET / FRAGMENT / PLAYLIST — tape-deck timestamp + tracklist.
     document: DOC — page preview + page nav. (Added in Task 13.)
*/

/* Convert a "MM:SS" or "HH:MM:SS" string to total seconds. */
const parseDur = (s) => {
  const parts = String(s).split(':').map(Number);
  if (parts.some(isNaN)) return 0;
  return parts.reduce((acc, n) => acc * 60 + n, 0);
};

/* Convert total seconds back to "HH:MM:SS" or "MM:SS" matching duration shape. */
const formatDur = (secs, shape) => {
  const useHours = String(shape).split(':').length === 3;
  const h = Math.floor(secs / 3600);
  const m = Math.floor((secs % 3600) / 60);
  const s = secs % 60;
  const pad = (n) => String(n).padStart(2, '0');
  return useHours ? `${pad(h)}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`;
};

/* -----  VAULT DOCUMENT DETAIL  -----
   Document variant of VaultDetail. Renders a faux page preview with crop
   marks and a clamped page-nav. Visual only.
*/
const VaultDocDetail = ({ item, dark, onBack }) => {
  const ink      = dark ? 'var(--db-d-ink)'       : 'var(--db-ink)';
  const graphite = dark ? 'var(--db-d-graphite)'  : 'var(--db-graphite)';
  const hairline = dark ? 'var(--db-d-hairline)'  : 'var(--db-hairline)';
  const surface  = dark ? 'var(--db-d-surface)'   : 'var(--db-cream)';

  const [page, setPage] = React.useState(1);
  const monoLabel = {
    fontFamily: 'var(--font-mono)',
    fontSize: 10,
    letterSpacing: '0.08em',
    textTransform: 'uppercase',
    color: graphite,
  };
  const sectionKicker = { ...monoLabel, marginBottom: 8 };

  const cropMark = (corner) => {
    const base = { position: 'absolute', width: 12, height: 12, borderColor: graphite, borderStyle: 'dashed', borderWidth: 0 };
    if (corner === 'tl') return { ...base, top: 8, left: 8, borderTopWidth: 1, borderLeftWidth: 1 };
    if (corner === 'tr') return { ...base, top: 8, right: 8, borderTopWidth: 1, borderRightWidth: 1 };
    if (corner === 'bl') return { ...base, bottom: 8, left: 8, borderBottomWidth: 1, borderLeftWidth: 1 };
    if (corner === 'br') return { ...base, bottom: 8, right: 8, borderBottomWidth: 1, borderRightWidth: 1 };
    return base;
  };

  return (
    <div
      style={{
        position: 'relative',
        width: '100%',
        minHeight: '100%',
        padding: '0 20px',
        boxSizing: 'border-box',
        color: ink,
        fontFamily: 'var(--font-sans)',
      }}
    >
      <DetailHead depth={1} dark={dark} onBack={onBack} />

      {/* Editorial head */}
      <div style={{ padding: '20px 0', borderBottom: `1px solid ${hairline}` }}>
        <div style={sectionKicker}>§ DOC</div>
        <h2
          style={{
            margin: 0,
            fontFamily: 'var(--font-sans-narrow)',
            fontWeight: 700,
            fontSize: 30,
            lineHeight: 0.95,
            letterSpacing: '-0.02em',
            color: ink,
          }}
        >
          {item.title}
        </h2>
        <div style={{ ...monoLabel, marginTop: 10 }}>{item.meta}</div>
      </div>

      {/* Page preview */}
      <div style={{ padding: '20px 0' }}>
        <div
          style={{
            position: 'relative',
            background: surface,
            border: `1px solid ${hairline}`,
            height: 360,
            padding: '32px 28px',
          }}
        >
          <span style={cropMark('tl')} />
          <span style={cropMark('tr')} />
          <span style={cropMark('bl')} />
          <span style={cropMark('br')} />
          <div style={{ ...monoLabel, color: ink, fontSize: 9, marginBottom: 24 }}>
            {item.title.toUpperCase()} — PAGE {String(page).padStart(2, '0')}
          </div>
          {Array.from({ length: 6 }).map((_, i) => (
            <div
              key={i}
              style={{
                height: 1,
                background: graphite,
                opacity: 0.45,
                margin: '18px 0',
                width: i === 5 ? '40%' : '100%',
              }}
            />
          ))}
        </div>
      </div>

      {/* Page nav */}
      <div
        style={{
          padding: '8px 0 18px',
          borderBottom: `1px solid ${hairline}`,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 18,
        }}
      >
        <button
          type="button"
          onClick={() => setPage((p) => Math.max(1, p - 1))}
          disabled={page <= 1}
          style={{
            background: 'transparent',
            border: 0,
            padding: 0,
            cursor: page <= 1 ? 'default' : 'pointer',
            fontFamily: 'var(--font-mono)',
            fontSize: 10,
            letterSpacing: '0.1em',
            textTransform: 'uppercase',
            color: page <= 1 ? graphite : ink,
            opacity: page <= 1 ? 0.4 : 1,
          }}
        >
          ← PAGE
        </button>
        <span style={{ ...monoLabel, color: ink }}>
          {String(page).padStart(2, '0')} / {String(item.pages).padStart(2, '0')}
        </span>
        <button
          type="button"
          onClick={() => setPage((p) => Math.min(item.pages, p + 1))}
          disabled={page >= item.pages}
          style={{
            background: 'transparent',
            border: 0,
            padding: 0,
            cursor: page >= item.pages ? 'default' : 'pointer',
            fontFamily: 'var(--font-mono)',
            fontSize: 10,
            letterSpacing: '0.1em',
            textTransform: 'uppercase',
            color: page >= item.pages ? graphite : ink,
            opacity: page >= item.pages ? 0.4 : 1,
          }}
        >
          PAGE →
        </button>
      </div>

      {/* Action row */}
      <div style={{ padding: '18px 0 28px' }}>
        <button
          type="button"
          style={{
            width: '100%',
            padding: '14px 16px',
            background: 'transparent',
            border: `1px solid ${ink}`,
            borderRadius: 2,
            cursor: 'pointer',
            fontFamily: 'var(--font-mono)',
            fontSize: 11,
            letterSpacing: '0.12em',
            textTransform: 'uppercase',
            color: ink,
          }}
        >
          DOWNLOAD PDF
        </button>
      </div>
    </div>
  );
};

const VaultDetail = ({ id, dark, onBack }) => {
  const item = (window.VAULT_ITEMS || [])[id];
  const ink      = dark ? 'var(--db-d-ink)'       : 'var(--db-ink)';
  const ink2     = dark ? 'var(--db-d-ink-2)'     : 'var(--db-ink-2)';
  const graphite = dark ? 'var(--db-d-graphite)'  : 'var(--db-graphite)';
  const silver   = dark ? 'var(--db-d-silver)'    : 'var(--db-silver)';
  const hairline = dark ? 'var(--db-d-hairline)'  : 'var(--db-hairline)';
  const surface  = dark ? 'var(--db-d-surface)'   : 'var(--db-cream)';

  if (!item) return null;
  if (item.kind === 'DOC') {
    return <VaultDocDetail item={item} dark={dark} onBack={onBack} />;
  }

  /* Audio state */
  const totalSecs = parseDur(item.duration);
  const cumulative = React.useMemo(() => {
    let acc = 0;
    return item.tracks.map((t) => {
      const s = parseDur(t.dur);
      acc += s;
      return acc; /* end time of each track */
    });
  }, [item]);

  const [playhead, setPlayhead] = React.useState(0);
  const [playing, setPlaying]   = React.useState(false);
  React.useEffect(() => {
    if (!playing) return;
    const tid = setInterval(() => {
      setPlayhead((p) => {
        const next = p + 1;
        if (next >= totalSecs) {
          setPlaying(false);
          return 0;
        }
        return next;
      });
    }, 1000);
    return () => clearInterval(tid);
  }, [playing, totalSecs]);

  const rawIdx = cumulative.findIndex((end) => playhead < end);
  const activeIdx = rawIdx === -1 ? cumulative.length - 1 : rawIdx;
  const monoLabel = {
    fontFamily: 'var(--font-mono)',
    fontSize: 10,
    letterSpacing: '0.08em',
    textTransform: 'uppercase',
    color: graphite,
  };
  const sectionKicker = { ...monoLabel, marginBottom: 8 };

  return (
    <div
      style={{
        position: 'relative',
        width: '100%',
        minHeight: '100%',
        padding: '0 20px',
        boxSizing: 'border-box',
        color: ink,
        fontFamily: 'var(--font-sans)',
      }}
    >
      <DetailHead depth={1} dark={dark} onBack={onBack} />

      {/* Editorial head */}
      <div style={{ padding: '20px 0', borderBottom: `1px solid ${hairline}` }}>
        <div style={{ ...monoLabel, marginBottom: 8 }}>§ {item.kind}</div>
        <h2
          style={{
            margin: 0,
            fontFamily: 'var(--font-sans-narrow)',
            fontWeight: 700,
            fontSize: 30,
            lineHeight: 0.95,
            letterSpacing: '-0.02em',
            color: ink,
          }}
        >
          {item.title}
        </h2>
        <div style={{ ...monoLabel, marginTop: 10 }}>{item.meta}</div>
      </div>

      {/* Tape-deck block */}
      <div
        style={{
          padding: '24px 0',
          borderBottom: `1px solid ${hairline}`,
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          gap: 16,
        }}
      >
        <div
          style={{
            fontFamily: 'var(--font-mono)',
            fontSize: 28,
            fontWeight: 500,
            letterSpacing: '0.04em',
          }}
        >
          <span style={{ color: ink }}>{formatDur(playhead, item.duration)}</span>
          <span style={{ color: silver }}>{' / '}</span>
          <span style={{ color: silver }}>{item.duration}</span>
        </div>
        <button
          type="button"
          onClick={() => setPlaying((p) => !p)}
          style={{
            padding: '12px 24px',
            minWidth: 120,
            background: 'transparent',
            border: `1px solid ${ink}`,
            borderRadius: 2,
            cursor: 'pointer',
            fontFamily: 'var(--font-mono)',
            fontSize: 10,
            letterSpacing: '0.12em',
            textTransform: 'uppercase',
            color: ink,
          }}
        >
          {playing ? '❚❚ PAUSE' : '▶ PLAY'}
        </button>
      </div>

      {/* Tracklist */}
      <div style={{ padding: '18px 0', borderBottom: `1px solid ${hairline}` }}>
        <div style={sectionKicker}>§ TRACKS</div>
        {item.tracks.map((tr, i) => {
          const isActive = playing && i === activeIdx;
          return (
            <div
              key={tr.n}
              style={{
                display: 'grid',
                gridTemplateColumns: '40px 1fr auto',
                gap: 12,
                alignItems: 'baseline',
                padding: '10px 0 10px 8px',
                borderTop: i === 0 ? 'none' : `1px dashed ${hairline}`,
                borderLeft: isActive ? '2px solid var(--db-acid)' : '2px solid transparent',
              }}
            >
              <span style={{ ...monoLabel, color: ink }}>{tr.n}</span>
              <span
                style={{
                  fontFamily: 'var(--font-serif-italic)',
                  fontStyle: 'italic',
                  fontSize: 15,
                  color: ink2,
                }}
              >
                {tr.title}
              </span>
              <span style={{ ...monoLabel, color: graphite }}>{tr.dur}</span>
            </div>
          );
        })}
      </div>

      {/* Notes block (optional) */}
      {item.note && (
        <div style={{ padding: '18px 0 28px' }}>
          <p
            style={{
              margin: 0,
              fontFamily: 'var(--font-serif-italic)',
              fontStyle: 'italic',
              fontSize: 14,
              lineHeight: 1.55,
              color: graphite,
            }}
          >
            {item.note}
          </p>
        </div>
      )}
      {!item.note && <div style={{ height: 28 }} />}
    </div>
  );
};

/* -----  DETAIL ROUTER  -----
   Dispatches to the appropriate detail component based on detail.kind.
*/
const DetailRouter = ({ detail, dark, onBack }) => {
  if (!detail) return null;
  if (detail.kind === 'event')   return <EventDetail id={detail.id} variant="event" dark={dark} onBack={onBack} />;
  if (detail.kind === 'tonight') return <EventDetail id={0} variant="tonight" dark={dark} onBack={onBack} />;
  if (detail.kind === 'vault')   return <VaultDetail id={detail.id} dark={dark} onBack={onBack} />;
  return null;
};

Object.assign(window, {
  EVENTS,
  VAULT_ITEMS,
  DetailHead,
  DetailRouter,
  EventDetail,
  VaultDetail,
});
