/* ========================================================================
   LUMINA — Workspace: Composition (GarageBand Live Loops + Resolume + DJ mixer)
   Track icons LEFT · clip grid CENTER · scene triggers BOTTOM · DJ mixer
   ======================================================================== */
const { useState: useStateCmp, useEffect: useEffectCmp, useRef: useRefCmp, useMemo: useMemoCmp } = React;

/* Track config — each row is a "layer track" with a distinctive look */
const TRACK_DEFS = [
  { id: "beat",    name: "Beat Driver",   color: "#ff7a1a", icon: "drums",
    vizs: ["bars", "radial", "tunnel", "kaleido"] },
  { id: "atmos",   name: "Atmosphere",    color: "#4be6ff", icon: "synth",
    vizs: ["liquid", "terrain", "wave", "lissajous"] },
  { id: "particle",name: "Particle FX",   color: "#b785ff", icon: "particles",
    vizs: ["particles", "radial", "kaleido", "liquid"] },
  { id: "image",   name: "Image / Photo", color: "#7cff4f", icon: "image",
    vizs: ["imageFrame", "imageBurst", "photoStrip", "imageFrame"] },
  { id: "video",   name: "Video / Live",  color: "#ff4ea6", icon: "video",
    vizs: ["videoTD", "videoMosh", "videoTD", "videoMosh"] },
  { id: "text",    name: "Text / Title",  color: "#ffae3a", icon: "text",
    vizs: ["type", "type", "type", "type"] },
  { id: "3d",      name: "3D Scene",      color: "#ff3b3b", icon: "cube",
    vizs: ["tunnel", "radial", "kaleido", "particles"] },
];

const SCENE_NAMES = ["Intro", "Build", "Verse", "Pre-Drop", "Drop", "Break", "Chorus", "Outro"];

/* ===== Track icon (skeu instrument) ===== */
function TrackIcon({ kind, color }) {
  const c = color || "#ffae3a";
  return (
    <svg width="34" height="34" viewBox="0 0 40 40">
      <defs>
        <radialGradient id={`tg-${kind}`}>
          <stop offset="0%" stopColor={c} stopOpacity="0.7" />
          <stop offset="100%" stopColor="#0a0a0c" />
        </radialGradient>
      </defs>
      <rect x="2" y="2" width="36" height="36" rx="6" fill={`url(#tg-${kind})`}
        stroke="rgba(255,255,255,0.1)" strokeWidth="0.5" />
      <g fill="none" stroke={c} strokeWidth="1.6" strokeLinecap="round">
        {kind === "drums" && (<>
          <circle cx="13" cy="22" r="6" /><circle cx="27" cy="22" r="6" />
          <path d="M13 16 L13 12 M27 16 L27 12 M10 12 L16 10 M24 10 L30 12" />
        </>)}
        {kind === "synth" && (<>
          <rect x="8" y="14" width="24" height="14" rx="1.5" />
          <path d="M14 14 v14 M20 14 v14 M26 14 v14" />
          <circle cx="11" cy="11" r="1.5" fill={c} /><circle cx="17" cy="11" r="1.5" fill={c} />
          <circle cx="23" cy="11" r="1.5" fill={c} />
        </>)}
        {kind === "particles" && (<>
          <circle cx="10" cy="10" r="1.5" fill={c} /><circle cx="20" cy="14" r="2" fill={c} />
          <circle cx="28" cy="9" r="1" fill={c} /><circle cx="14" cy="22" r="1.8" fill={c} />
          <circle cx="26" cy="24" r="1.5" fill={c} /><circle cx="20" cy="30" r="1.2" fill={c} />
          <circle cx="8" cy="28" r="1" fill={c} /><circle cx="32" cy="18" r="1" fill={c} />
        </>)}
        {kind === "image" && (<>
          <rect x="7" y="9" width="26" height="22" rx="2" />
          <circle cx="14" cy="16" r="2" fill={c} />
          <path d="M7 27 L17 18 L33 30" />
        </>)}
        {kind === "video" && (<>
          <rect x="6" y="11" width="22" height="18" rx="1.5" />
          <path d="M28 16 L34 13 V27 L28 24 Z" />
        </>)}
        {kind === "text" && (<>
          <text x="20" y="27" textAnchor="middle" fontSize="18" fontWeight="800"
            fontFamily="Space Grotesk" fill={c} stroke="none">Aa</text>
        </>)}
        {kind === "cube" && (<>
          <path d="M20 6 L32 12 V26 L20 32 L8 26 V12 Z" />
          <path d="M20 6 V32 M8 12 L32 12 M20 19 L32 12 M20 19 L8 12" opacity="0.6" />
        </>)}
      </g>
    </svg>
  );
}

/* ===== Clip thumbnail (SVG, GarageBand-style abstract waveform) ===== */
function ClipThumb({ kind, active, seed = 0 }) {
  // generate a deterministic mini-wave or circle thumb
  const c = active ? "#fff" : "rgba(255,255,255,0.85)";
  if (kind === "image" || kind === "video") {
    return (
      <svg viewBox="0 0 40 40" width="100%" height="100%">
        <rect x="6" y="9" width="28" height="22" rx="2" fill="none" stroke={c} strokeWidth="1.4" />
        <circle cx="14" cy="17" r="2" fill={c} />
        <path d="M6 27 L17 18 L34 30" stroke={c} strokeWidth="1.4" fill="none" />
      </svg>
    );
  }
  if (kind === "text") {
    return (
      <svg viewBox="0 0 40 40" width="100%" height="100%">
        <text x="20" y="26" textAnchor="middle" fontSize="14" fontWeight="800"
          fontFamily="Space Grotesk" fill={c}>Aa</text>
      </svg>
    );
  }
  if (kind === "cube") {
    return (
      <svg viewBox="0 0 40 40" width="100%" height="100%">
        <path d="M20 8 L31 13 V26 L20 31 L9 26 V13 Z" fill="none" stroke={c} strokeWidth="1.3" />
        <path d="M20 8 V31 M9 13 L31 13 M9 13 L20 19 L31 13" stroke={c} strokeWidth="1" fill="none" opacity="0.6" />
      </svg>
    );
  }
  if (kind === "synth" || kind === "drums") {
    // concentric circle / radial bars
    const N = 28;
    const r = 14;
    const cx = 20, cy = 20;
    let path = "";
    for (let i = 0; i < N; i++) {
      const ang = (i / N) * Math.PI * 2;
      const v = 0.55 + Math.sin(i * 1.7 + seed * 0.6) * 0.3 + Math.sin(i * 0.5 + seed) * 0.15;
      const r1 = r * 0.65, r2 = r * (0.65 + 0.35 * v);
      path += `M${cx + Math.cos(ang) * r1} ${cy + Math.sin(ang) * r1} L${cx + Math.cos(ang) * r2} ${cy + Math.sin(ang) * r2} `;
    }
    return (
      <svg viewBox="0 0 40 40" width="100%" height="100%">
        <circle cx={cx} cy={cy} r={r * 0.55} fill="none" stroke={c} strokeWidth="0.7" opacity="0.6" />
        <path d={path} stroke={c} strokeWidth="1.2" strokeLinecap="round" />
      </svg>
    );
  }
  // default: waveform
  const N = 22;
  const pts = [];
  for (let i = 0; i < N; i++) {
    const x = 4 + (i / (N - 1)) * 32;
    const v = 0.4 + Math.sin(i * 0.8 + seed) * 0.5 + Math.sin(i * 1.6 + seed * 1.2) * 0.15;
    const y = 20 + (i % 2 ? -v : v) * 12;
    pts.push(`${x},${y}`);
  }
  return (
    <svg viewBox="0 0 40 40" width="100%" height="100%">
      <polyline points={pts.join(" ")} fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" />
    </svg>
  );
}

/* ===== DJ Channel Strip ===== */
function ChannelStrip({ idx, color, name, fader, setFader, eq, setEq, gain, setGain, muted, setMuted, cued, setCued }) {
  return (
    <div style={{
      display: "flex", flexDirection: "column", gap: 6, alignItems: "center",
      padding: "10px 8px", borderRadius: 10,
      background: "linear-gradient(180deg, var(--panel-hi), var(--panel))",
      boxShadow: "var(--nshadow-out-sm)",
      borderTop: `2px solid ${color}`,
      minWidth: 64,
    }}>
      <div style={{
        fontFamily: "var(--font-mono)", fontSize: 9, color: color,
        textShadow: `0 0 6px ${color}`, textAlign: "center",
        whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", width: "100%",
        fontWeight: 700, letterSpacing: "0.1em",
      }}>{name}</div>

      <Knob size="sm" value={gain} onChange={setGain} min={-12} max={12} step={0.1}
        label="GAIN" unit="dB" />
      <Knob size="sm" value={eq.hi} onChange={v => setEq({...eq, hi: v})}
        min={-12} max={12} step={0.1} label="HI" unit="" bipolar />
      <Knob size="sm" value={eq.mid} onChange={v => setEq({...eq, mid: v})}
        min={-12} max={12} step={0.1} label="MID" unit="" bipolar />
      <Knob size="sm" value={eq.lo} onChange={v => setEq({...eq, lo: v})}
        min={-12} max={12} step={0.1} label="LO" unit="" bipolar />

      <Fader value={fader} onChange={setFader} min={0} max={1} height={90} label="" />

      <div style={{ display: "flex", gap: 4, width: "100%" }}>
        <button className={`nbtn compact ${cued ? "glow pressed" : ""}`}
          onClick={() => setCued(c => !c)}
          style={{ flex: 1, padding: "3px 0", fontSize: 8 }}>CUE</button>
        <button className={`nbtn compact ${muted ? "danger pressed" : ""}`}
          onClick={() => setMuted(m => !m)}
          style={{ flex: 1, padding: "3px 0", fontSize: 8 }}>MUTE</button>
      </div>

      {/* VU */}
      <div style={{ width: 18 }}><VU level={fader * 0.95} segments={10} /></div>
    </div>
  );
}

/* ===== Main composition workspace ===== */
function CompositionDeck({ vizId, setVizId, params, onParam, audio }) {
  // tracks = rows
  const tracks = TRACK_DEFS;
  const cols = SCENE_NAMES.length;

  // active clip per track (null = nothing playing on this track)
  const [active, setActive] = useStateCmp(() => tracks.map(() => null));
  const [hovered, setHovered] = useStateCmp(null);

  // currently playing scene column (the "vertical trigger")
  const [playingScene, setPlayingScene] = useStateCmp(null);
  const [autopilot, setAutopilot] = useStateCmp(false);
  const [autopilotBars, setAutopilotBars] = useStateCmp(4);
  const [snapMode, setSnapMode] = useStateCmp(true);
  const [pendingScene, setPendingScene] = useStateCmp(null);
  const [pendingCell, setPendingCell] = useStateCmp(null);
  const autopilotRef = useRefCmp(0);

  // per-track mute / solo
  const [tState, setTState] = useStateCmp(() => tracks.map(() => ({ muted: false, solo: false, opacity: 0.9, blend: "normal" })));
  const updT = (i, patch) => {
    setTState(s => s.map((t, k) => k === i ? { ...t, ...patch } : t));
    // propagate live changes to the track's compositor layer if it's playing
    const S = window.LuminaStack;
    if (S && active[i] != null) {
      const L = S.layers[i];
      if (L) {
        const p = {};
        if ("opacity" in patch) p.opacity = patch.opacity;
        if ("blend" in patch) p.blend = patch.blend;
        if ("muted" in patch) p.enabled = !patch.muted;
        if ("solo" in patch) p.solo = patch.solo;
        if (Object.keys(p).length) S.update(L.id, p);
      }
    }
  };

  // map each track row → a dedicated compositor layer (Resolume layers × columns)
  const trackLayer = (r) => {
    const S = window.LuminaStack;
    if (!S) return null;
    while (S.layers.length <= r) S.add();
    return S.layers[r];
  };

  // BPM tap
  const [bpm, setBpm] = useStateCmp(128);
  const tapsRef = useRefCmp([]);
  const onTap = () => {
    const now = performance.now();
    tapsRef.current.push(now);
    while (tapsRef.current.length > 6) tapsRef.current.shift();
    if (tapsRef.current.length >= 2) {
      const d = [];
      for (let i = 1; i < tapsRef.current.length; i++) d.push(tapsRef.current[i] - tapsRef.current[i-1]);
      const avg = d.reduce((a,b)=>a+b,0) / d.length;
      setBpm(Math.round(60000 / avg));
    }
  };

  // grid: row=track, col=scene
  // clip configuration deterministic
  const grid = useMemoCmp(() =>
    tracks.map((t, r) => Array.from({ length: cols }, (_, c) => ({
      vizId: t.vizs[c % t.vizs.length],
      seed: r * 7 + c * 3,
    })))
  , []);

  // Autopilot: auto-advance scene every N bars
  useEffectCmp(() => {
    if (!autopilot || !window.LuminaClock) return;
    const C = window.LuminaClock;
    autopilotRef.current = C.bar;
    const id = setInterval(() => {
      const bars = C.bar - autopilotRef.current;
      if (bars >= autopilotBars) {
        autopilotRef.current = C.bar;
        const next = playingScene == null ? 0 : (playingScene + 1) % cols;
        triggerScene(next);
      }
    }, 100);
    return () => clearInterval(id);
  }, [autopilot, autopilotBars, playingScene]);

  const triggerCell = (r, c) => {
    const fire = () => {
      const S = window.LuminaStack;
      // toggle off if re-triggering the playing clip
      if (active[r] === c) {
        const L = trackLayer(r);
        if (L && S) S.update(L.id, { enabled: false });
        setActive(a => a.map((v, i) => i === r ? null : v));
        setPendingCell(null);
        return;
      }
      setActive(a => a.map((v, i) => i === r ? c : v));
      const L = trackLayer(r);
      if (L && S) S.update(L.id, {
        source: grid[r][c].vizId, enabled: !tState[r].muted,
        opacity: tState[r].opacity, blend: tState[r].blend, solo: tState[r].solo,
      });
      if (r === 0) setVizId(grid[r][c].vizId);
      setPendingCell(null);
    };
    if (snapMode && window.LuminaClock && window.LuminaClock.snap !== "off") {
      setPendingCell({ r, c });
      window.LuminaClock.onSnap(fire);
    } else fire();
  };
  const triggerScene = (c) => {
    const fire = () => {
      const S = window.LuminaStack;
      setActive(a => a.map(() => c));
      tracks.forEach((t, r) => {
        const L = trackLayer(r);
        if (L && S) S.update(L.id, {
          source: grid[r][c].vizId, enabled: !tState[r].muted,
          opacity: tState[r].opacity, blend: tState[r].blend, solo: tState[r].solo,
        });
      });
      setVizId(grid[0][c].vizId);
      setPlayingScene(c);
      setPendingScene(null);
    };
    if (snapMode && window.LuminaClock && window.LuminaClock.snap !== "off") {
      setPendingScene(c);
      window.LuminaClock.onSnap(fire);
    } else fire();
  };
  // ── MIDI mapping: expose triggers + register every cell/scene as a learnable
  //    MIDI target so a hardware controller (APC40 / Launchpad …) drives clips ──
  const [midiMap, setMidiMap] = useStateCmp(false);   // "MIDI map" arm mode
  const [, forceMidi] = useStateCmp(0);
  const trigCellRef = useRefCmp(triggerCell);
  const trigSceneRef = useRefCmp(triggerScene);
  trigCellRef.current = triggerCell;
  trigSceneRef.current = triggerScene;
  useEffectCmp(() => {
    window.__triggerComposScene = (c) => trigSceneRef.current(c);
    window.__triggerComposCell = (r, c) => trigCellRef.current(r, c);
    // Register stable MIDI targets for all cells + scenes
    const M = window.MidiTargets;
    if (M) {
      for (let r = 0; r < tracks.length; r++)
        for (let c = 0; c < cols; c++)
          M[`cell-${r}-${c}`] = { onTrigger: () => trigCellRef.current(r, c) };
      for (let c = 0; c < cols; c++)
        M[`scene-${c}`] = { onTrigger: () => trigSceneRef.current(c) };
      M["blackout"] = { onTrigger: () => { const S = window.LuminaStack; if (S) S.setMasterBlackout(b => !b); } };
      M["stopall"] = { onTrigger: () => stopAll() };
      M["master-dim"] = { onValue: (v) => { const S = window.LuminaStack; if (S) S.setMasterOpacity(v); } };
    }
    const off = window.LuminaMidi?.on?.(() => forceMidi(x => x + 1));
    return () => { delete window.__triggerComposScene; delete window.__triggerComposCell; off?.(); };
  }, [cols, tracks.length]);
  const cellBound = (r, c) => !!window.LuminaMidi?.findBinding?.(`cell-${r}-${c}`);
  const sceneBound = (c) => !!window.LuminaMidi?.findBinding?.(`scene-${c}`);
  const armLearn = (id) => {
    if (!window.LuminaMidi) return;
    window.LuminaMidi.startLearn({ id, kind: "trigger" });
    forceMidi(x => x + 1);
  };

  const stopAll = () => {
    const S = window.LuminaStack;
    tracks.forEach((t, r) => { const L = trackLayer(r); if (L && S) S.update(L.id, { enabled: false }); });
    setActive(a => a.map(() => null));
    setPlayingScene(null);
  };

  // ── KEYBOARD LAUNCH SURFACE (Resolume-style hands-free triggering) ──
  // Digit row  → launch whole SCENE columns 1..10
  // Letter grid→ launch individual cells (3 rows = tracks 0,1,2 · 8 cols)
  // Space      → blackout / stop all     ·  B → master blackout toggle
  const [kbd, setKbd] = useStateCmp(() => {
    try { return localStorage.getItem("lumina_kbd_launch") !== "0"; } catch (e) { return true; }
  });
  const CELL_KEY_ROWS = ["qwertyui", "asdfghjk", "zxcvbnm,"];
  const keyForCell = (r, c) => {
    if (r < CELL_KEY_ROWS.length && c < 8) return CELL_KEY_ROWS[r][c];
    return null;
  };
  const sceneKeyFor = (c) => (c < 10 ? String((c + 1) % 10) : null);
  useEffectCmp(() => {
    try { localStorage.setItem("lumina_kbd_launch", kbd ? "1" : "0"); } catch (e) {}
    if (!kbd) return;
    const onKey = (e) => {
      // ignore when typing in a field or using a modifier (those are app shortcuts)
      const tag = (e.target.tagName || "").toLowerCase();
      if (tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable) return;
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      const k = e.key.toLowerCase();
      if (e.key === " ") { e.preventDefault(); stopAll(); flashKey("␣"); return; }
      if (k === "b") { const S = window.LuminaStack; if (S && S.setMasterBlackout) S.setMasterBlackout(b => !b); flashKey("B"); return; }
      // digit → scene column
      if (/^[0-9]$/.test(k)) {
        const col = (parseInt(k, 10) + 9) % 10; // '1'→0 ... '0'→9
        if (col < cols) { triggerScene(col); flashKey(k); e.preventDefault(); }
        return;
      }
      // letter grid → individual cell
      for (let r = 0; r < CELL_KEY_ROWS.length; r++) {
        const ci = CELL_KEY_ROWS[r].indexOf(k);
        if (ci >= 0 && r < tracks.length && ci < cols) {
          triggerCell(r, ci); flashKey(k); e.preventDefault(); return;
        }
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [kbd, snapMode, cols, grid, tState]);
  const [keyFlash, setKeyFlash] = useStateCmp(null);
  const flashKey = (k) => { setKeyFlash(k); setTimeout(() => setKeyFlash(f => f === k ? null : f), 220); };

  // crossfader
  const [xfade, setXfade] = useStateCmp(0.5);
  const [deck, setDeck] = useStateCmp("A");
  const [mixerOpen, setMixerOpen] = useStateCmp(() => {
    try { return localStorage.getItem("lumina_mixer_open") !== "0"; } catch (e) { return true; }
  });
  useEffectCmp(() => {
    try { localStorage.setItem("lumina_mixer_open", mixerOpen ? "1" : "0"); } catch (e) {}
  }, [mixerOpen]);

  // master output blackout state (mirrors LuminaStack for button feedback)
  const [masterBO, setMasterBO] = useStateCmp(false);
  useEffectCmp(() => {
    const S = window.LuminaStack;
    if (!S) return;
    setMasterBO(!!S.masterBlackout);
    return S.on(s => setMasterBO(!!s.masterBlackout));
  }, []);
  const flashOutput = () => {
    if (window.Strobo) window.Strobo.fire("#ffffff");
  };
  const [strobeOn, setStrobeOn] = useStateCmp(false);

  // mixer state
  const [strip, setStrip] = useStateCmp(() => tracks.map((t, i) => ({
    fader: i === 0 ? 1 : 0.6, gain: 0,
    eq: { hi: 0, mid: 0, lo: 0 },
    muted: false, cued: false,
  })));
  const updS = (i, patch) => setStrip(s => s.map((v, k) => k === i ? { ...v, ...patch } : v));

  return (
    <div className="panel stage-bezel" style={{ padding: 0, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <Screws />

      {/* Top toolbar (GarageBand-style) */}
      <div className="stage-toolbar" style={{ borderBottom: "1px solid rgba(255,255,255,0.04)" }}>
        <div className="stage-tabs">
          <div className="stage-tab active">Live Loops</div>
        </div>
        <div style={{ flex: 1 }} />
        <Lcd tone="amber" style={{ fontSize: 11, padding: "4px 10px", minWidth: 100 }}>
          ♩ <b>{bpm}</b> <span style={{ opacity: 0.4, marginLeft: 4 }}>BPM</span>
        </Lcd>
        <button className="nbtn compact glow pressed" onClick={onTap}>TAP</button>
        <select style={{
          background: "linear-gradient(180deg,#0a0a0c,#16161a)",
          border: "none", borderRadius: 6, padding: "4px 8px",
          color: "var(--led-amber)", fontFamily: "var(--font-mono)", fontSize: 10,
          boxShadow: "var(--nshadow-in-sm)", textShadow: "0 0 4px var(--led-amber-glow)",
          outline: "none",
        }}>
          <option>1 Bar</option><option>1/2</option><option>1/4</option><option>Free</option>
        </select>
        <button className={`nbtn compact ${snapMode ? "glow pressed" : ""}`}
          onClick={() => setSnapMode(s => !s)}
          title="Beat snap: clips fire on next downbeat">
          ⏱ Snap
        </button>
        <button className={`nbtn compact ${autopilot ? "glow pressed" : ""}`}
          onClick={() => setAutopilot(a => !a)}
          title="Auto-advance scenes">
          ✈ Auto
        </button>
        <select value={autopilotBars} onChange={e => setAutopilotBars(Number(e.target.value))}
          style={{ background: "linear-gradient(180deg,#0a0a0c,#16161a)",
            border: "none", borderRadius: 4, padding: "4px 6px",
            color: "var(--accent)", textShadow: "0 0 3px var(--accent-glow)",
            fontFamily: "var(--font-mono)", fontSize: 9, outline: "none",
            boxShadow: "var(--nshadow-in-sm)" }}>
          {[1, 2, 4, 8, 16, 32].map(n => <option key={n} value={n}>{n} bar</option>)}
        </select>
        <button className={`nbtn compact ${kbd ? "glow pressed" : ""}`}
          onClick={() => setKbd(k => !k)}
          title="Keyboard launch: digits fire scenes · QWERTY grid fires clips · Space = blackout">
          ⌨ Keys
        </button>
        <button className="nbtn compact" onClick={stopAll}>■ STOP</button>
      </div>

      {/* Bar timeline header (numbered) */}
      <div style={{
        display: "grid",
        gridTemplateColumns: `120px repeat(${cols}, 1fr)`,
        gap: 4,
        padding: "6px 10px 4px 10px",
        background: "linear-gradient(180deg, #0a0a0c, #14141a)",
        borderBottom: "1px solid rgba(255,255,255,0.03)",
        position: "relative",
      }}>
        <div />
        {Array.from({ length: cols }, (_, i) => (
          <div key={i} style={{
            display: "flex", alignItems: "flex-end", justifyContent: "space-between",
            paddingBottom: 2, position: "relative",
          }}>
            <div style={{
              fontFamily: "var(--font-mono)", fontSize: 9,
              color: playingScene === i ? "var(--led-amber)" : "var(--ink-faint)",
              textShadow: playingScene === i ? "0 0 5px var(--led-amber-glow)" : "none",
              fontWeight: 600, letterSpacing: "0.1em",
            }}>
              {i * 4 + 1}
              {i === 0 && <sub style={{ color: "var(--accent)", marginLeft: 2, fontSize: 8 }}>A</sub>}
              {i === 4 && <sub style={{ color: "var(--led-cyan)", marginLeft: 2, fontSize: 8 }}>B</sub>}
            </div>
            <div style={{
              width: 1, height: 8, background: "rgba(255,255,255,0.1)",
            }} />
            {kbd && sceneKeyFor(i) && (
              <div style={{
                position: "absolute", top: -2, right: 0,
                fontFamily: "var(--font-mono)", fontSize: 8, fontWeight: 700,
                color: keyFlash === sceneKeyFor(i) ? "#0a0a0c" : "var(--led-cyan)",
                background: keyFlash === sceneKeyFor(i) ? "var(--led-cyan)" : "rgba(0,0,0,0.5)",
                border: "1px solid var(--led-cyan)", borderRadius: 3,
                padding: "0 3px", lineHeight: "12px",
                textShadow: keyFlash === sceneKeyFor(i) ? "none" : "0 0 4px var(--led-cyan)",
                boxShadow: keyFlash === sceneKeyFor(i) ? "0 0 8px var(--led-cyan)" : "none",
              }}>{sceneKeyFor(i)}</div>
            )}
          </div>
        ))}
      </div>

      {/* MAIN GRID — tracks left, clips center. minHeight keeps the clip
          grid usable even with the mixer expanded */}
      <div style={{
        flex: 1,
        display: "grid",
        gridTemplateColumns: `120px 1fr 220px`,
        gap: 0,
        minHeight: 220,
        overflow: "hidden",
      }}>
        {/* Left: track icons column */}
        <div style={{
          background: "linear-gradient(180deg, #0a0a0c, #14141a)",
          display: "flex", flexDirection: "column",
          borderRight: "1px solid rgba(255,255,255,0.04)",
          overflowY: "auto",
        }}>
          {tracks.map((t, r) => (
            <div key={t.id}
              style={{
                flex: 1,
                display: "flex", alignItems: "center", gap: 8,
                padding: "0 8px",
                borderBottom: "1px solid rgba(255,255,255,0.03)",
                minHeight: 64,
                background: r === 0 ? "linear-gradient(90deg, rgba(255,122,26,0.08), transparent)" : "transparent",
              }}>
              <TrackIcon kind={t.icon} color={t.color} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{
                  fontFamily: "var(--font-display)", fontSize: 10,
                  fontWeight: 700, color: "var(--ink)",
                  whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
                  letterSpacing: "0.04em",
                }}>{t.name}</div>
                <div style={{ display: "flex", gap: 3, marginTop: 4 }}>
                  <button className={`nbtn compact ${tState[r].muted ? "danger pressed" : ""}`}
                    style={{ padding: "2px 5px", fontSize: 8 }}
                    onClick={() => updT(r, { muted: !tState[r].muted })}>M</button>
                  <button className={`nbtn compact ${tState[r].solo ? "glow pressed" : ""}`}
                    style={{ padding: "2px 5px", fontSize: 8 }}
                    onClick={() => updT(r, { solo: !tState[r].solo })}>S</button>
                  <button className="nbtn compact" style={{ padding: "2px 5px", fontSize: 8 }}>R</button>
                </div>
              </div>
            </div>
          ))}
        </div>

        {/* CENTER GRID */}
        <div style={{
          display: "grid",
          gridTemplateRows: `repeat(${tracks.length}, 1fr)`,
          minHeight: 0,
          overflow: "auto",
          background: "#0a0a0c",
        }}>
          {tracks.map((t, r) => (
            <div key={t.id} style={{
              display: "grid",
              gridTemplateColumns: `repeat(${cols}, 1fr)`,
              gap: 3, padding: 3,
              borderBottom: "1px solid rgba(255,255,255,0.03)",
              minHeight: 64,
            }}>
              {grid[r].map((clip, c) => {
                const isActive = active[r] === c;
                const isScene = playingScene === c;
                const isPending = (pendingScene === c) || (pendingCell?.r === r && pendingCell?.c === c);
                return (
                  <button key={c}
                    onClick={() => triggerCell(r, c)}
                    onMouseEnter={() => setHovered({ r, c })}
                    onMouseLeave={() => setHovered(null)}
                    style={{
                      position: "relative",
                      border: "none",
                      borderRadius: 5,
                      padding: 0, overflow: "hidden",
                      cursor: "pointer",
                      background: isActive
                        ? `linear-gradient(180deg, ${t.color}, hsl(from ${t.color} h s calc(l - 25)))`
                        : "linear-gradient(180deg, #2a3a5a, #18253c)",
                      color: isActive ? "#0a0a0c" : "rgba(180,210,255,0.95)",
                      boxShadow: isActive
                        ? `inset 0 0 0 1px rgba(255,255,255,0.4),
                           inset 0 -3px 0 rgba(0,0,0,0.3),
                           0 0 18px ${t.color}80,
                           0 1px 0 rgba(0,0,0,0.5)`
                        : `inset 0 1px 0 rgba(255,255,255,0.08),
                           inset 0 -1px 0 rgba(0,0,0,0.5),
                           0 1px 0 rgba(0,0,0,0.6)`,
                      transition: "all 80ms ease",
                      transform: isActive ? "scale(0.97)" : "scale(1)",
                      outline: hovered && hovered.r === r && hovered.c === c
                        ? "2px solid rgba(255,255,255,0.5)" : "none",
                    }}>
                    <div style={{
                      position: "absolute", inset: 6,
                      display: "flex", alignItems: "center", justifyContent: "center",
                      pointerEvents: "none",
                    }}>
                      <ClipThumb kind={t.icon} active={isActive} seed={clip.seed} />
                    </div>
                    {kbd && keyForCell(r, c) && (
                      <div style={{
                        position: "absolute", top: 3, left: 4,
                        fontFamily: "var(--font-mono)", fontSize: 8, fontWeight: 700,
                        textTransform: "uppercase",
                        color: keyFlash === keyForCell(r, c) ? "#0a0a0c" : "rgba(255,255,255,0.85)",
                        background: keyFlash === keyForCell(r, c) ? "#fff" : "rgba(0,0,0,0.5)",
                        border: "1px solid rgba(255,255,255,0.35)", borderRadius: 3,
                        padding: "0 3px", lineHeight: "12px", pointerEvents: "none",
                        boxShadow: keyFlash === keyForCell(r, c) ? "0 0 8px #fff" : "none",
                      }}>{keyForCell(r, c)}</div>
                    )}
                    {isActive && (
                      <>
                        {/* playhead bar */}
                        <div style={{
                          position: "absolute", bottom: 2, left: 4, right: 4, height: 2,
                          background: "rgba(0,0,0,0.4)", borderRadius: 1,
                        }}>
                          <div style={{
                            height: "100%", width: `${50 + Math.sin(Date.now() / 200) * 40}%`,
                            background: "#fff", borderRadius: 1,
                            boxShadow: "0 0 6px #fff",
                          }} />
                        </div>
                        <div style={{
                          position: "absolute", top: 3, right: 4,
                          width: 6, height: 6, borderRadius: "50%",
                          background: "#fff", boxShadow: "0 0 8px #fff",
                        }} />
                      </>
                    )}
                    {isScene && !isActive && (
                      <div style={{
                        position: "absolute", inset: 0,
                        border: "1.5px solid rgba(255,255,255,0.4)",
                        borderRadius: 5, pointerEvents: "none",
                      }} />
                    )}
                    {isPending && !isActive && (
                      <div style={{
                        position: "absolute", inset: 0,
                        border: "2px dashed var(--led-amber)",
                        borderRadius: 5, pointerEvents: "none",
                        animation: "pulse 0.6s infinite",
                      }} />
                    )}
                  </button>
                );
              })}
            </div>
          ))}
        </div>

        {/* RIGHT: Scene Outliner */}
        <SceneOutliner
          tracks={tracks} active={active} grid={grid} tState={tState}
          playingScene={playingScene} bpm={bpm}
          stripState={strip}
        />
      </div>

      {/* SCENE TRIGGERS (bottom row, GarageBand-style) */}
      <div style={{
        display: "grid",
        gridTemplateColumns: `120px repeat(${cols}, 1fr) 220px`,
        gap: 3, padding: "6px 10px 6px 10px",
        background: "linear-gradient(180deg, #14141a, #0a0a0c)",
        borderTop: "1px solid rgba(255,255,255,0.06)",
      }}>
        <div style={{
          display: "flex", alignItems: "center", justifyContent: "flex-end",
          paddingRight: 8, gap: 6,
        }}>
          <span className="cap">SCENES</span>
          <Led on color="cyan" />
        </div>
        {SCENE_NAMES.map((name, c) => {
          const isOn = playingScene === c;
          return (
            <button key={c}
              onClick={() => triggerScene(c)}
              style={{
                border: "none",
                background: isOn
                  ? "linear-gradient(180deg, #ffb850, #c87016)"
                  : "linear-gradient(180deg, #2a2a30, #1a1a1e)",
                color: isOn ? "#1a0a02" : "var(--ink-2)",
                padding: "8px 4px",
                borderRadius: 6,
                fontFamily: "var(--font-display)",
                fontSize: 10, fontWeight: 700,
                letterSpacing: "0.06em",
                cursor: "pointer",
                boxShadow: isOn
                  ? "inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -2px 0 rgba(0,0,0,0.3), 0 0 14px rgba(255,184,80,0.6)"
                  : "var(--nshadow-out-sm)",
                display: "flex", flexDirection: "column", alignItems: "center", gap: 2,
                transition: "all 80ms",
              }}>
              <svg width="14" height="10" viewBox="0 0 14 10" fill={isOn ? "#1a0a02" : "var(--ink-dim)"}>
                <path d="M7 1 L13 9 L1 9 Z" />
              </svg>
              {name}
            </button>
          );
        })}
        <div style={{ display: "flex", alignItems: "center", gap: 6, paddingLeft: 12 }}>
          <Led on color="amber" />
          <span className="cap">{playingScene !== null ? SCENE_NAMES[playingScene] : "—"}</span>
        </div>
      </div>

      {/* DJ MIXER — collapsible + scrollable so the clip grid ALWAYS has room */}
      <div onClick={() => setMixerOpen(o => !o)}
        title={mixerOpen ? "Comprimi il mixer (più spazio alla griglia clip)" : "Espandi il mixer"}
        style={{
          display: "flex", alignItems: "center", gap: 8,
          padding: "5px 14px",
          background: "linear-gradient(180deg, #1a1a20, #121216)",
          borderTop: "2px solid rgba(0,0,0,0.6)",
          cursor: "pointer", userSelect: "none", flexShrink: 0,
        }}>
        <Led on={mixerOpen} color="amber" size={7} />
        <span className="cap">VJ · DJ Mixer</span>
        <div style={{ flex: 1 }} />
        <span className="cap" style={{ color: "var(--accent)" }}>
          {mixerOpen ? "▾ comprimi" : "▴ espandi"}
        </span>
      </div>
      {mixerOpen && (
      <div style={{
        display: "grid",
        gridTemplateColumns: `120px 1fr 220px`,
        gap: 0,
        background: "linear-gradient(180deg, #14141a, #0a0a0c)",
        boxShadow: "inset 0 4px 8px rgba(0,0,0,0.4)",
        padding: "12px 0",
        maxHeight: "44%",
        overflowY: "auto",
        flexShrink: 0,
      }}>
        {/* left badge */}
        <div style={{
          display: "flex", alignItems: "center", justifyContent: "center",
          flexDirection: "column", gap: 4,
          borderRight: "1px solid rgba(255,255,255,0.04)",
        }}>
          <div className="brand-mark" style={{ width: 30, height: 30, fontSize: 13 }}>M</div>
          <div className="cap" style={{ fontSize: 8 }}>VJ · DJ MIXER</div>
        </div>

        {/* channel strips */}
        <div style={{
          display: "grid", gridTemplateColumns: `repeat(${tracks.length}, 1fr) 0.7fr`,
          gap: 6, padding: "0 12px",
        }}>
          {tracks.map((t, i) => (
            <ChannelStrip key={t.id} idx={i} color={t.color} name={t.name.split(" ")[0]}
              fader={strip[i].fader} setFader={v => updS(i, { fader: v })}
              eq={strip[i].eq} setEq={v => updS(i, { eq: v })}
              gain={strip[i].gain} setGain={v => updS(i, { gain: v })}
              muted={strip[i].muted} setMuted={v => updS(i, { muted: typeof v === "function" ? v(strip[i].muted) : v })}
              cued={strip[i].cued} setCued={v => updS(i, { cued: typeof v === "function" ? v(strip[i].cued) : v })}
            />
          ))}
          {/* MASTER strip */}
          <div style={{
            display: "flex", flexDirection: "column", gap: 6, alignItems: "center",
            padding: "10px 8px", borderRadius: 10,
            background: "linear-gradient(180deg, #3a2a14, #1a120a)",
            boxShadow: "var(--nshadow-out-sm), inset 0 0 0 1px rgba(255,184,80,0.2)",
            borderTop: "2px solid var(--accent)",
            minWidth: 64,
          }}>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 10, fontWeight: 700,
              color: "var(--accent)", textShadow: "0 0 6px var(--accent-glow)",
              letterSpacing: "0.16em" }}>MASTER</div>
            <Knob size="sm" value={0} onChange={()=>{}} min={-20} max={6} step={0.1} label="GAIN" unit="dB" />
            <div style={{ flex: 1 }} />
            <Fader value={0.85} onChange={()=>{}} min={0} max={1} height={130} label="" />
            <div style={{ display: "flex", gap: 4, width: "100%" }}>
              <button className="nbtn compact" style={{ flex: 1, padding: "3px 0", fontSize: 8 }}>BOOTH</button>
            </div>
            <div style={{ width: 18 }}><VU level={audio?.energy || 0} segments={10} /></div>
          </div>
        </div>

        {/* Crossfader area */}
        <div style={{
          padding: "10px 14px",
          borderLeft: "1px solid rgba(255,255,255,0.04)",
          display: "flex", flexDirection: "column", gap: 8, justifyContent: "center",
        }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <button className={`nbtn compact ${deck === "A" ? "glow pressed" : ""}`}
              onClick={() => setDeck("A")} style={{ minWidth: 32 }}>A</button>
            <span className="cap">CROSSFADER</span>
            <button className={`nbtn compact ${deck === "B" ? "cyan pressed glow" : ""}`}
              onClick={() => setDeck("B")} style={{ minWidth: 32 }}>B</button>
          </div>
          <HSlider value={xfade} onChange={setXfade} min={0} max={1} />
          <div style={{ display: "flex", justifyContent: "space-between" }}>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--led-amber)" }}>
              {Math.round((1 - xfade) * 100)}%
            </span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--led-cyan)" }}>
              {Math.round(xfade * 100)}%
            </span>
          </div>
          <div style={{
            display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 4, marginTop: 4,
          }}>
            {[
              { n: "Flash", c: "red", on: false, fn: flashOutput },
              { n: "Strobe", c: "amber", on: strobeOn, fn: () => { if (window.Strobo) { window.Strobo.enabled = !window.Strobo.enabled; setStrobeOn(window.Strobo.enabled); } } },
              { n: "Black", c: "green", on: masterBO, fn: () => { const S = window.LuminaStack; if (S) S.setMasterBlackout(b => !b); } },
              { n: "Snap", c: "cyan", on: snapMode, fn: () => setSnapMode(s => !s) },
            ].map((b, i) => (
              <button key={b.n} className={`nbtn compact ${b.on ? "danger pressed glow" : ""}`}
                onClick={b.fn}
                style={{ padding: "5px 0", fontSize: 8,
                  background: b.on ? undefined : `linear-gradient(180deg, hsl(${i*60},45%,30%), hsl(${i*60},45%,18%))` }}>
                <Led on={b.on || i < 1} color={b.c} size={6} />
                {b.n.toUpperCase()}
              </button>
            ))}
          </div>
        </div>
      </div>
      )}
    </div>
  );
}

/* ===== Scene Outliner (right side panel inside composition) ===== */
function SceneOutliner({ tracks, active, grid, tState, playingScene, bpm, stripState }) {
  const sceneName = playingScene !== null ? SCENE_NAMES[playingScene] : "— no scene —";
  return (
    <div style={{
      background: "linear-gradient(180deg, #1a1a1e, #14141a)",
      borderLeft: "1px solid rgba(255,255,255,0.04)",
      padding: "10px 8px",
      display: "flex", flexDirection: "column", gap: 8,
      overflowY: "auto",
    }}>
      <div style={{
        display: "flex", alignItems: "center", gap: 6,
        padding: "6px 8px",
        background: "linear-gradient(180deg, var(--panel-hi), var(--panel))",
        borderRadius: 6, boxShadow: "var(--nshadow-out-sm)",
      }}>
        <span style={{ width: 6, height: 6, borderRadius: "50%",
          background: "var(--led-amber)", boxShadow: "0 0 6px var(--led-amber-glow)" }} />
        <span className="cap" style={{ flex: 1 }}>Scene Outliner</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--led-amber)",
          textShadow: "0 0 4px var(--led-amber-glow)" }}>{bpm} BPM</span>
      </div>

      <div style={{
        padding: "6px 8px",
        background: "linear-gradient(180deg, #0a0a0c, #14141a)",
        borderRadius: 6, boxShadow: "var(--nshadow-in-sm)",
      }}>
        <div className="cap" style={{ fontSize: 8 }}>ACTIVE SCENE</div>
        <div style={{
          fontFamily: "var(--font-display)", fontSize: 14, fontWeight: 700,
          color: playingScene !== null ? "var(--accent)" : "var(--ink-faint)",
          textShadow: playingScene !== null ? "0 0 6px var(--accent-glow)" : "none",
          letterSpacing: "0.04em", marginTop: 2,
        }}>{sceneName}</div>
        <div style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--ink-faint)", marginTop: 4 }}>
          {active.filter(a => a !== null).length} / {tracks.length} layers playing
        </div>
      </div>

      {/* Per-track */}
      {tracks.map((t, r) => {
        const a = active[r];
        const playing = a !== null && !tState[r].muted;
        const viz = a !== null && window.VISUALIZERS.find(v => v.id === grid[r][a].vizId);
        return (
          <div key={t.id} style={{
            padding: 6,
            background: playing
              ? `linear-gradient(180deg, ${t.color}22, ${t.color}05)`
              : "linear-gradient(180deg, #1a1a1e, #14141a)",
            borderLeft: `3px solid ${playing ? t.color : "#2a2a30"}`,
            borderRadius: 4,
            display: "flex", flexDirection: "column", gap: 3,
          }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
              <Led on={playing} color={"amber"} size={6} />
              <span style={{
                fontFamily: "var(--font-display)", fontSize: 10, fontWeight: 700,
                color: playing ? t.color : "var(--ink-dim)",
                flex: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
              }}>{t.name}</span>
              <span style={{
                fontFamily: "var(--font-mono)", fontSize: 8, color: "var(--ink-faint)",
              }}>{Math.round(stripState[r].fader * 100)}%</span>
            </div>
            {a !== null && (
              <div style={{
                fontFamily: "var(--font-mono)", fontSize: 8.5,
                color: "var(--ink-faint)", paddingLeft: 12,
              }}>
                └ {viz?.name || "—"}{tState[r].muted ? " · MUTED" : ""}
              </div>
            )}
          </div>
        );
      })}

      {/* Counts row */}
      <div style={{
        marginTop: "auto", paddingTop: 8, borderTop: "1px solid rgba(255,255,255,0.04)",
        display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6,
      }}>
        <div style={{ padding: 6, background: "linear-gradient(180deg, #1a1a1e, #14141a)", borderRadius: 4 }}>
          <div className="cap" style={{ fontSize: 8 }}>Behaviors</div>
          <div style={{ color: "var(--accent)", fontFamily: "var(--font-mono)", fontSize: 14,
            fontWeight: 700, textShadow: "0 0 4px var(--accent-glow)" }}>
            {window.Prog?.behaviors?.length || 0}
          </div>
        </div>
        <div style={{ padding: 6, background: "linear-gradient(180deg, #1a1a1e, #14141a)", borderRadius: 4 }}>
          <div className="cap" style={{ fontSize: 8 }}>FX</div>
          <div style={{ color: "var(--led-cyan)", fontFamily: "var(--font-mono)", fontSize: 14,
            fontWeight: 700, textShadow: "0 0 4px var(--led-cyan-glow)" }}>
            {window.Prog?.fxChain?.length || 0}
          </div>
        </div>
      </div>
    </div>
  );
}

window.CompositionDeck = CompositionDeck;
