// ============ FEATURES — WishTrak ============
// 1) Disc Condition rarity meter
// 2) Boombox music player (chiptune synthesized via WebAudio — no external assets)
// 3) Trailer Night mode (faux DVD menu + chapter playback)

const { useState: useStateF, useEffect: useEffectF, useRef: useRefF, useCallback: useCallbackF } = React;

// ─────────────────────────────────────────────────────────────
// 1) DISC CONDITION
// Derived from item age (createdAt) + how stuck the wish is (low pct = more scratched).
// Completed items are always MINT.
// ─────────────────────────────────────────────────────────────
function discCondition(item) {
  if (item.completed) return { id: "mint", label: "MINT", color: "#7af09a", pct: 100, scratches: 0, ageDays: 0 };
  const ageDays = Math.max(0, (Date.now() - (item.createdAt || Date.now())) / (1000 * 60 * 60 * 24));
  const p = (typeof pctOf === "function") ? pctOf(item) : 0;
  // "stuck score" — older + lower progress = more scratched
  // 100 at day 0; loses ~0.6/day; each % of progress adds 0.4 back
  const score = Math.max(0, Math.min(100, 100 - ageDays * 0.6 + p * 0.4));
  let cond;
  if      (score >= 80) cond = { id: "mint",       label: "MINT",       color: "#7af09a", scratches: 0 };
  else if (score >= 55) cond = { id: "likenew",    label: "LIKE NEW",   color: "#ffd84d", scratches: 1 };
  else if (score >= 30) cond = { id: "scratched",  label: "SCRATCHED",  color: "#ff9a4d", scratches: 3 };
  else                  cond = { id: "unplayable", label: "UNPLAYABLE", color: "#ff4d6d", scratches: 6 };
  return { ...cond, pct: Math.round(score), ageDays: Math.round(ageDays) };
}

// Small pill badge — placed on grid cards
function DiscBadge({ item, size = "sm" }) {
  const c = discCondition(item);
  return (
    <div className={`disc-badge dc-${c.id} dc-${size}`} title={`${c.label} · ${c.ageDays}d on shelf`}>
      <span className="dc-dot" style={{ background: c.color, boxShadow: `0 0 6px ${c.color}` }}></span>
      <span className="dc-label">{c.label}</span>
    </div>
  );
}

// SVG disc with deterministic scratches — shown on detail cover
function ScratchedDisc({ item }) {
  const c = discCondition(item);
  // Deterministic pseudo-random seeded by item.id so scratches don't shift on re-render
  const seed = (item.id || "x").split("").reduce((s, ch) => s + ch.charCodeAt(0), 0);
  const rand = (i) => { const x = Math.sin(seed * 9301 + i * 49297) * 233280; return x - Math.floor(x); };
  const scratches = [];
  for (let i = 0; i < c.scratches; i++) {
    const angle = rand(i) * Math.PI * 2;
    const r1 = 30 + rand(i + 17) * 28;
    const r2 = 30 + rand(i + 31) * 28;
    scratches.push({
      x1: 50 + Math.cos(angle) * r1,
      y1: 50 + Math.sin(angle) * r1,
      x2: 50 + Math.cos(angle + 0.4 + rand(i + 5) * 0.6) * r2,
      y2: 50 + Math.sin(angle + 0.4 + rand(i + 5) * 0.6) * r2,
      w: 0.4 + rand(i + 9) * 0.7,
    });
  }
  return (
    <div className="scratch-disc-wrap" title={`Disc condition: ${c.label}`}>
      <svg viewBox="0 0 100 100" className="scratch-disc">
        <defs>
          <radialGradient id={`dg-${seed}`} cx="50%" cy="50%" r="50%">
            <stop offset="0%"   stopColor="#000" />
            <stop offset="22%"  stopColor="#000" />
            <stop offset="23%"  stopColor="#aaa" />
            <stop offset="60%"  stopColor="#e8e8e8" />
            <stop offset="100%" stopColor="#888" />
          </radialGradient>
        </defs>
        <circle cx="50" cy="50" r="48" fill={`url(#dg-${seed})`} stroke="#000" strokeWidth="0.5" />
        <circle cx="50" cy="50" r="22" fill="#000" />
        <circle cx="50" cy="50" r="9"  fill="#222" stroke="#666" strokeWidth="0.4" />
        {[28, 34, 40, 46].map((r, i) => (
          <circle key={i} cx="50" cy="50" r={r} fill="none" stroke="rgba(255,216,77,0.18)" strokeWidth="0.3" />
        ))}
        {scratches.map((s, i) => (
          <line key={i} x1={s.x1} y1={s.y1} x2={s.x2} y2={s.y2}
            stroke="rgba(255,255,255,0.85)" strokeWidth={s.w} strokeLinecap="round" />
        ))}
      </svg>
      <div className="scratch-disc-cap" style={{ color: c.color, borderColor: c.color }}>{c.label}</div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 2) BOOMBOX — chiptune music player (WebAudio, zero external assets)
// ─────────────────────────────────────────────────────────────
const BOOMBOX_TRACKS = [
  {
    id: "menu", title: "Main Menu Loop", bpm: 96, key: "Am",
    bass: [[1,1,2],[1,1,2],[5,1,1],[1,1,2],[6,1,2],[6,1,2],[3,1,2],[5,1,2]],
    lead: [[1,0.5,4],[3,0.5,4],[5,1,4],[3,0.5,4],[5,0.5,4],[6,1,4],[5,0.5,4],[3,0.5,4],[1,1,4]],
    pad:  [[1,4,3],[6,4,3]],
    scale: [0,2,3,5,7,8,10,12], root: 220,
  },
  {
    id: "trailer", title: "Trailer Underscore", bpm: 72, key: "Cm",
    bass: [[1,2,2],[5,2,1],[6,2,2],[4,2,2]],
    lead: [[5,1,4],[3,1,4],[1,1,4],[5,1,3],[6,1,4],[5,1,4],[3,2,4]],
    pad:  [[1,4,3],[5,4,3],[6,4,3],[4,4,3]],
    scale: [0,2,3,5,7,8,10,12], root: 261.63,
  },
  {
    id: "credits", title: "Credits Roll", bpm: 110, key: "F",
    bass: [[1,1,2],[5,1,2],[6,1,2],[4,1,2],[1,1,2],[5,1,2],[3,1,2],[4,1,2]],
    lead: [[5,0.5,4],[6,0.5,4],[8,0.5,4],[6,0.5,4],[5,1,4],[3,0.5,4],[5,0.5,4],[6,1,4]],
    pad:  [[1,4,3],[4,4,3]],
    scale: [0,2,4,5,7,9,11,12], root: 174.61,
  },
  {
    id: "rewind", title: "Rewind Reverie", bpm: 84, key: "Em",
    bass: [[1,1.5,2],[6,0.5,2],[4,2,2],[5,1,1],[1,1,2],[3,2,2]],
    lead: [[1,0.5,4],[5,0.5,4],[3,0.5,4],[1,0.5,4],[6,1,4],[5,0.5,4],[3,0.5,4],[1,1,4]],
    pad:  [[1,4,3],[6,4,3]],
    scale: [0,2,3,5,7,8,10,12], root: 164.81,
  },
];

function makeMusicPlayer() {
  let ctx = null, masterGain = null, analyser = null, trackTimer = null, active = null;
  let _vol = 0.25;
  // Track every scheduled audio node so stop() can kill them immediately
  let _nodes = [];
  // Subscribers notified on every play/stop so external UIs can stay in sync
  let _subs = [];

  const ensure = () => {
    if (!ctx) {
      try { ctx = new (window.AudioContext || window.webkitAudioContext)(); }
      catch (_) { return false; }
      masterGain = ctx.createGain();
      masterGain.gain.value = 0; // stays silent until play() un-mutes
      analyser = ctx.createAnalyser();
      analyser.fftSize = 64;
      masterGain.connect(analyser);
      analyser.connect(ctx.destination);
    }
    if (ctx.state === "suspended") ctx.resume();
    return true;
  };

  const noteFreq = (root, scale, deg, oct) => {
    const semis = scale[(deg - 1) % scale.length];
    return root * Math.pow(2, semis / 12) * Math.pow(2, oct - 3);
  };

  const playTone = (freq, start, dur, type, vol) => {
    const o = ctx.createOscillator(), g = ctx.createGain();
    o.type = type;
    o.frequency.setValueAtTime(freq, start);
    g.gain.setValueAtTime(0, start);
    g.gain.linearRampToValueAtTime(vol, start + 0.015);
    g.gain.exponentialRampToValueAtTime(0.0001, start + dur);
    o.connect(g).connect(masterGain);
    o.start(start); o.stop(start + dur + 0.05);
    _nodes.push(o);
  };

  const playKick = (start) => {
    const o = ctx.createOscillator(), g = ctx.createGain();
    o.type = "sine";
    o.frequency.setValueAtTime(120, start);
    o.frequency.exponentialRampToValueAtTime(40, start + 0.12);
    g.gain.setValueAtTime(0.5, start);
    g.gain.exponentialRampToValueAtTime(0.0001, start + 0.18);
    o.connect(g).connect(masterGain);
    o.start(start); o.stop(start + 0.2);
    _nodes.push(o);
  };

  const playHat = (start) => {
    const len = 0.04;
    const buf = ctx.createBuffer(1, Math.ceil(ctx.sampleRate * len), ctx.sampleRate);
    const data = buf.getChannelData(0);
    for (let i = 0; i < data.length; i++) data[i] = (Math.random() * 2 - 1) * 0.3;
    const src = ctx.createBufferSource(), g = ctx.createGain();
    const hp = ctx.createBiquadFilter();
    hp.type = "highpass"; hp.frequency.value = 7000;
    src.buffer = buf;
    g.gain.setValueAtTime(0.12, start);
    g.gain.exponentialRampToValueAtTime(0.0001, start + len);
    src.connect(hp).connect(g).connect(masterGain);
    src.start(start); src.stop(start + len + 0.02);
    _nodes.push(src);
  };

  // Kill all tracked nodes immediately and clear the list
  const killNodes = () => {
    const now = ctx ? ctx.currentTime : 0;
    _nodes.forEach(n => { try { n.stop(now); } catch (_) {} });
    _nodes = [];
  };

  const scheduleLoop = (track) => {
    if (!ctx || !active) return;
    const beatLen = 60 / track.bpm;
    const sumBeats = (seq) => seq.reduce((s, n) => s + n[1], 0);
    const barBeats = Math.max(sumBeats(track.bass), sumBeats(track.lead), sumBeats(track.pad));
    const barSec = barBeats * beatLen;
    const startAt = ctx.currentTime + 0.05;

    // bass: square, lead: triangle, pad: sine + fifth
    let t = startAt;
    for (const [deg, dur, oct] of track.bass) {
      playTone(noteFreq(track.root, track.scale, deg, oct), t, dur * beatLen * 0.95, "square", 0.16);
      t += dur * beatLen;
    }
    t = startAt;
    for (const [deg, dur, oct] of track.lead) {
      playTone(noteFreq(track.root, track.scale, deg, oct), t, dur * beatLen * 0.95, "triangle", 0.11);
      t += dur * beatLen;
    }
    t = startAt;
    for (const [deg, dur, oct] of track.pad) {
      const f = noteFreq(track.root, track.scale, deg, oct);
      playTone(f,       t, dur * beatLen * 0.98, "sine", 0.05);
      playTone(f * 1.5, t, dur * beatLen * 0.98, "sine", 0.025);
      t += dur * beatLen;
    }
    // drums
    for (let b = 0; b < barBeats; b += 0.5) {
      const bt = startAt + b * beatLen;
      if (Math.abs(b % 2) < 0.01) playKick(bt);
      if (Math.abs((b - 0.5) % 1) < 0.01) playHat(bt);
    }

    trackTimer = setTimeout(() => scheduleLoop(track), barSec * 1000);
  };

  return {
    play(trackId) {
      if (!ensure()) return false;
      // Hard-stop any currently playing sounds before starting new ones
      this.stop();
      const track = BOOMBOX_TRACKS.find(t => t.id === trackId) || BOOMBOX_TRACKS[0];
      active = track;
      // Restore gain now that we're starting playback
      const now = ctx.currentTime;
      masterGain.gain.cancelScheduledValues(now);
      masterGain.gain.linearRampToValueAtTime(_vol, now + 0.06);
      scheduleLoop(track);
      _subs.forEach(fn => fn(active));
      return true;
    },
    stop() {
      if (trackTimer) { clearTimeout(trackTimer); trackTimer = null; }
      active = null;
      // Kill all in-flight oscillator/buffer nodes immediately
      killNodes();
      // Silence the master gain — stays silent until play() restores it
      if (masterGain && ctx) {
        const now = ctx.currentTime;
        masterGain.gain.cancelScheduledValues(now);
        masterGain.gain.setValueAtTime(masterGain.gain.value, now);
        masterGain.gain.linearRampToValueAtTime(0, now + 0.06);
      }
      _subs.forEach(fn => fn(null));
    },
    setVolume(v) {
      _vol = v;
      // Only apply live if something is playing; otherwise just store for next play()
      if (active && ensure() && masterGain) {
        masterGain.gain.cancelScheduledValues(ctx.currentTime);
        masterGain.gain.linearRampToValueAtTime(v, ctx.currentTime + 0.05);
      }
    },
    // Subscribe to play/stop events. Callback receives the active track or null.
    // Returns an unsubscribe function.
    subscribe(fn) {
      _subs.push(fn);
      return () => { _subs = _subs.filter(s => s !== fn); };
    },
    getActive()   { return active; },
    getAnalyser() { return analyser; },
  };
}

const MusicPlayer = makeMusicPlayer();

function Boombox() {
  const [open,     setOpen]     = useStateF(false);
  // Initialise from the singleton's live state so external callers (e.g. TrailerNight)
  // that start playback before the Boombox mounts are immediately reflected.
  const [playing,  setPlaying]  = useStateF(() => !!MusicPlayer.getActive());
  const [trackIdx, setTrackIdx] = useStateF(() => {
    const a = MusicPlayer.getActive();
    if (!a) return 0;
    const i = BOOMBOX_TRACKS.findIndex(t => t.id === a.id);
    return i >= 0 ? i : 0;
  });
  const [vol,      setVol]      = useStateF(0.25);
  const [tape,     setTape]     = useStateF(0);
  const eqRef  = useRefF(null);
  const rafRef = useRefF(null);
  const track  = BOOMBOX_TRACKS[trackIdx];

  // Keep UI in sync when something else (TrailerNight, cleanup) calls play/stop
  useEffectF(() => {
    return MusicPlayer.subscribe((activeTrack) => {
      if (activeTrack) {
        const i = BOOMBOX_TRACKS.findIndex(t => t.id === activeTrack.id);
        setTrackIdx(i >= 0 ? i : 0);
        setPlaying(true);
      } else {
        setPlaying(false);
      }
    });
  }, []);

  // Drive the player from React state — but skip if the player is already correct
  // to avoid infinite loops with the subscriber above.
  useEffectF(() => {
    const current = MusicPlayer.getActive();
    if (playing) {
      if (!current || current.id !== track.id) MusicPlayer.play(track.id);
    } else {
      if (current) MusicPlayer.stop();
    }
    return () => MusicPlayer.stop();
  }, [playing, trackIdx]);

  useEffectF(() => { MusicPlayer.setVolume(vol); }, [vol]);

  // Animate reels + EQ bars
  useEffectF(() => {
    let last = performance.now();
    const tick = (now) => {
      const dt = (now - last) / 1000;
      last = now;
      if (playing) setTape(t => (t + dt * 144) % 360);
      if (eqRef.current) {
        const bars = eqRef.current.children;
        const an   = MusicPlayer.getAnalyser();
        if (an) {
          const data = new Uint8Array(an.frequencyBinCount);
          an.getByteFrequencyData(data);
          for (let i = 0; i < bars.length; i++) {
            const v = (data[i * 2] || 0) / 255;
            bars[i].style.height = `${Math.max(8, v * 100)}%`;
          }
        } else {
          for (let i = 0; i < bars.length; i++) {
            bars[i].style.height = playing ? `${30 + Math.sin(now / 200 + i) * 20}%` : "8%";
          }
        }
      }
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [playing]);

  const togglePlay = () => setPlaying(p => !p);
  const next = () => setTrackIdx(i => (i + 1) % BOOMBOX_TRACKS.length);
  const prev = () => setTrackIdx(i => (i - 1 + BOOMBOX_TRACKS.length) % BOOMBOX_TRACKS.length);

  if (!open) {
    return (
      <button className="boombox-fab" onClick={() => setOpen(true)} title="Open music player">
        <span className="bb-fab-ico">♪</span>
        <span className="bb-fab-tx">{playing ? "PLAYING" : "MUSIC"}</span>
        {playing && <span className="bb-fab-pulse"></span>}
      </button>
    );
  }

  return (
    <div className="boombox" role="region" aria-label="Music player">
      <div className="bb-top">
        <div className="bb-brand">SONIC▮TRAK</div>
        <div className="bb-led" data-on={String(playing)}></div>
        <button className="bb-close" onClick={() => setOpen(false)} title="Minimize">─</button>
      </div>

      <div className="bb-cassette">
        <div className="bb-window">
          <div className="bb-tape">
            <div className="bb-reel" style={{ transform: `rotate(${tape}deg)` }}>
              <span></span><span></span><span></span>
            </div>
            <div className="bb-tape-strip"></div>
            <div className="bb-reel" style={{ transform: `rotate(${tape * 1.6}deg)` }}>
              <span></span><span></span><span></span>
            </div>
          </div>
          <div className="bb-cassette-label">
            <div className="bb-side">SIDE A</div>
            <div className="bb-tape-title">{track.title}</div>
            <div className="bb-tape-meta">{track.bpm} BPM · {track.key}</div>
          </div>
        </div>
      </div>

      <div className="bb-eq" ref={eqRef}>
        {Array.from({ length: 14 }).map((_, i) => <span key={i}></span>)}
      </div>

      <div className="bb-transport">
        <button className="bb-tbtn" onClick={prev} title="Previous">◀◀</button>
        <button className={`bb-tbtn bb-play ${playing ? "on" : ""}`} onClick={togglePlay} title={playing ? "Stop" : "Play"}>
          {playing ? "■" : "▶"}
        </button>
        <button className="bb-tbtn" onClick={next} title="Next">▶▶</button>
      </div>

      <div className="bb-tracklist">
        {BOOMBOX_TRACKS.map((t, i) => (
          <div key={t.id}
            className={`bb-track ${i === trackIdx ? "active" : ""}`}
            onClick={() => { setTrackIdx(i); if (!playing) setPlaying(true); }}>
            <span className="bb-tnum">{String(i + 1).padStart(2, "0")}</span>
            <span className="bb-ttitle">{t.title}</span>
            <span className="bb-tbpm">{t.bpm}</span>
          </div>
        ))}
      </div>

      <div className="bb-vol-row">
        <span className="bb-vol-l">VOL</span>
        <input type="range" min="0" max="1" step="0.01" value={vol}
          className="bb-vol"
          onChange={e => setVol(Number(e.target.value))} />
        <span className="bb-vol-v">{Math.round(vol * 100)}</span>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 3) TRAILER NIGHT
// ─────────────────────────────────────────────────────────────
function TrailerNightScreen({ items, onHome, onAdd, onStats, ownerMode }) {
  const { play } = useSound();
  const [selected, setSelected] = useStateF(() =>
    items.slice(0, Math.min(5, items.length)).map(i => i.id)
  );
  const [phase,   setPhase]   = useStateF("menu");    // menu | playing | end
  const [chapter, setChapter] = useStateF(0);
  const [mode,    setMode]    = useStateF("idle");     // idle | playall | scenes | features

  const selItems = selected.map(id => items.find(i => i.id === id)).filter(Boolean);
  const total    = selItems.length;

  // Start trailer music on mount
  useEffectF(() => {
    MusicPlayer.play("trailer");
    return () => MusicPlayer.stop();
  }, []);

  // Auto-advance chapters every ~5 s
  useEffectF(() => {
    if (phase !== "playing") return;
    const t = setTimeout(() => {
      if (chapter + 1 >= total) { setPhase("end"); }
      else { play("tick"); setChapter(c => c + 1); }
    }, 5200);
    return () => clearTimeout(t);
  }, [phase, chapter, total]);

  const toggle      = (id) => { play("tick"); setSelected(s => s.includes(id) ? s.filter(x => x !== id) : [...s, id]); };
  const playAll     = () => { if (!total) { play("bad"); return; } play("trophy"); setMode("playall"); setChapter(0); setPhase("playing"); };
  const sceneStart  = (i) => { play("trophy"); setMode("scenes"); setChapter(i); setPhase("playing"); };
  const showFeatures = () => { play("select"); setMode(m => m === "features" ? "idle" : "features"); };
  const backToMenu  = () => { play("back"); setPhase("menu"); setMode("idle"); };

  // ── PLAYBACK VIEW ──
  if (phase === "playing") {
    const item = selItems[chapter];
    if (!item) return null;
    const cat  = CATEGORIES[item.category];
    const p    = pctOf(item);
    const cond = discCondition(item);
    return (
      <div className="screen tn-playback">
        <div className="tn-letterbox top"></div>
        <div className="tn-letterbox bottom"></div>
        <div className="tn-stage">
          {item.cover
            ? <img src={item.cover} className="tn-bg-img" alt="" />
            : <div className="tn-bg-glyph" style={{ color: cond.color }}>{cat.glyph}</div>
          }
          <div className="tn-vignette"></div>
          <div className="tn-static"></div>
          <div className="tn-card">
            <div className="tn-chapter">CHAPTER {String(chapter + 1).padStart(2, "0")} / {String(total).padStart(2, "0")}</div>
            <div className="tn-cat">{cat.label} · {cond.label}</div>
            <h1 className="tn-title">{item.title}</h1>
            {item.desc && <div className="tn-desc">{item.desc}</div>}
            <div className="tn-bar"><div className="tn-fill" style={{ width: `${p}%` }}></div></div>
            <div className="tn-meta">{p}% · {item.completed ? "GRANTED" : "IN PROGRESS"}</div>
          </div>
          <div className="tn-rating">
            <div className="rt-tag">DREAM RATED</div>
            <div className="rt-letter">{cond.label.charAt(0)}</div>
            <div className="rt-tag">FOR ALL AUDIENCES</div>
          </div>
        </div>
        <div className="tn-controls">
          <button className="btn" onClick={() => { play("back"); chapter === 0 ? backToMenu() : setChapter(c => c - 1); }}>◀ Prev</button>
          <button className="btn" onClick={backToMenu}>■ Stop</button>
          <button className="btn primary" onClick={() => {
            if (chapter + 1 >= total) setPhase("end");
            else { play("tick"); setChapter(c => c + 1); }
          }}>Next ▶</button>
        </div>
      </div>
    );
  }

  // ── END / CREDITS ──
  if (phase === "end") {
    return (
      <div className="screen tn-end">
        <div className="tn-letterbox top"></div>
        <div className="tn-letterbox bottom"></div>
        <div className="tn-end-inner">
          <div className="tn-end-fin">FIN.</div>
          <div className="tn-end-sub">A WishTrak Production</div>
          <div className="tn-credits">
            {selItems.map((it, i) => (
              <div key={it.id} className="tn-cred-row">
                <span className="tn-cred-role">CHAPTER {String(i + 1).padStart(2, "0")}</span>
                <span className="tn-cred-name">{it.title}</span>
              </div>
            ))}
            <div className="tn-cred-row" style={{ marginTop: 24 }}>
              <span className="tn-cred-role">DIRECTED BY</span>
              <span className="tn-cred-name">YOU</span>
            </div>
            <div className="tn-cred-row">
              <span className="tn-cred-role">SOUNDTRACK</span>
              <span className="tn-cred-name">SONIC▮TRAK ENGINE</span>
            </div>
          </div>
          <div className="tn-controls" style={{ marginTop: 18 }}>
            <button className="btn" onClick={() => { play("back"); setPhase("menu"); }}>◀ DVD Menu</button>
            <button className="btn primary" onClick={() => { play("trophy"); setChapter(0); setPhase("playing"); }}>↻ Play Again</button>
          </div>
        </div>
      </div>
    );
  }

  // ── MAIN DVD MENU ──
  return (
    <div className="screen tn-menu">
      <ChromeBar onHome={onHome} onAdd={onAdd} onStats={onStats} ownerMode={ownerMode} />
      <div className="tn-menu-body">

        {/* LEFT — menu options */}
        <div className="tn-left">
          <div className="tn-fbi">
            ▮ FBI WARNING ▮ FEDERAL LAW PROTECTS DREAMS<br />
            UNAUTHORIZED PURSUIT IS A CIVIC DUTY
          </div>
          <div className="tn-tagline">▮ DVD VIDEO · DREAM EDITION</div>
          <h1 className="tn-bigtitle">Trailer<br />Night</h1>
          <div className="tn-pitch">Pick your wishes. We'll cut a trailer for the family.</div>

          <div className="tn-menu-options">
            {/* Play All */}
            <div className="tn-opt" onClick={playAll} onMouseEnter={() => play("hover")}>
              <span className="tn-opt-arrow">▶</span>
              <div className="tn-opt-mid">
                <div className="tn-opt-l">Play All</div>
                <div className="tn-opt-s">{total} chapter{total === 1 ? "" : "s"} · ~{Math.max(1, Math.round(total * 5 / 60 * 10) / 10)} min runtime</div>
              </div>
            </div>

            {/* Scene Selection */}
            <div className={`tn-opt ${mode === "scenes" ? "open" : ""}`}
              onClick={() => { play("select"); setMode(m => m === "scenes" ? "idle" : "scenes"); }}
              onMouseEnter={() => play("hover")}>
              <span className="tn-opt-arrow">▶</span>
              <div className="tn-opt-mid">
                <div className="tn-opt-l">Scene Selection</div>
                <div className="tn-opt-s">Jump to a chapter</div>
              </div>
            </div>
            {mode === "scenes" && (
              <div className="tn-scenes">
                {selItems.length === 0 && <div className="tn-scene-empty">Pick wishes on the right →</div>}
                {selItems.map((it, i) => {
                  const cat = CATEGORIES[it.category];
                  return (
                    <div key={it.id} className="tn-scene" onClick={() => sceneStart(i)} onMouseEnter={() => play("hover")}>
                      <div className="tn-scene-num">{String(i + 1).padStart(2, "0")}</div>
                      <div className="tn-scene-thumb">
                        {it.cover ? <img src={it.cover} alt="" /> : <span>{cat.glyph}</span>}
                      </div>
                      <div className="tn-scene-mid">
                        <div className="tn-scene-title">{it.title}</div>
                        <div className="tn-scene-meta">{cat.label} · {pctOf(it)}%</div>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}

            {/* Special Features */}
            <div className={`tn-opt ${mode === "features" ? "open" : ""}`}
              onClick={showFeatures}
              onMouseEnter={() => play("hover")}>
              <span className="tn-opt-arrow">▶</span>
              <div className="tn-opt-mid">
                <div className="tn-opt-l">Special Features</div>
                <div className="tn-opt-s">Disc rarity report · Director&apos;s notes</div>
              </div>
            </div>
            {mode === "features" && (
              <div className="tn-features">
                <div className="tn-feat-title">▮ Disc Condition Report</div>
                {["mint", "likenew", "scratched", "unplayable"].map(id => {
                  const list = items.filter(i => discCondition(i).id === id);
                  return (
                    <div key={id} className={`tn-feat-row dc-${id}`}>
                      <div className="tn-feat-bar"><span style={{ width: `${Math.min(100, list.length * 14)}%` }}></span></div>
                      <div className="tn-feat-name">{id === "likenew" ? "LIKE NEW" : id.toUpperCase()}</div>
                      <div className="tn-feat-count">{list.length}</div>
                    </div>
                  );
                })}
                <div className="tn-feat-note">▮ Older wishes with low progress accumulate scratches.</div>
              </div>
            )}
          </div>
        </div>

        {/* RIGHT — chapter picker */}
        <div className="tn-right">
          <div className="tn-pickhead">▮ CHOOSE CHAPTERS · {selected.length}/{items.length}</div>
          <div className="tn-pick-grid">
            {items.map(it => {
              const isOn = selected.includes(it.id);
              const cat  = CATEGORIES[it.category];
              const cond = discCondition(it);
              return (
                <div key={it.id}
                  className={`tn-pick ${isOn ? "on" : ""}`}
                  onClick={() => toggle(it.id)}
                  onMouseEnter={() => play("hover")}>
                  <div className="tn-pick-thumb">
                    {it.cover ? <img src={it.cover} alt="" /> : <span>{cat.glyph}</span>}
                    <span className="tn-pick-cond" style={{ background: cond.color, color: "#0a1845" }}>
                      {cond.label.charAt(0)}
                    </span>
                  </div>
                  <div className="tn-pick-mid">
                    <div className="tn-pick-title">{it.title}</div>
                    <div className="tn-pick-cat">{cat.label} · {pctOf(it)}%</div>
                  </div>
                  <div className="tn-pick-check">{isOn ? "✓" : ""}</div>
                </div>
              );
            })}
          </div>
        </div>

      </div>
    </div>
  );
}

// Export all to window so other scripts can access them
Object.assign(window, {
  discCondition, DiscBadge, ScratchedDisc,
  Boombox, MusicPlayer, BOOMBOX_TRACKS,
  TrailerNightScreen,
});
