/* Nutshell shell prototype — GENERATION QUEUE (shared across the 3 options)
   window.SHELL_QUEUE = { QueueProvider, useQueue, ShellChrome, QueueCompose,
                          JobIcon, StateDot, JobMeta, MiniBar, Ring, CONCURRENCY,
                          stateLabel, etaText } */
(function () {
  const { Icon } = window.NSIcons;
  const C = window.SHELL_CORE;
  const O = window.SHELL_OVERLAYS;
  const useEngine = C.useEngine;
  const { DiagramCanvas, ZoomPanel, Transport, IBtn, Pill, Avatar } = C;
  const { ChatBody, NuggetsBody, SourceBody, LibraryBody, OverlayHost, Scrim } = O;
  const D = window.SHELL;

  const CONCURRENCY = 2;            // heavy jobs that may run at once
  const TYPE_ICON = { youtube: "youtube", graph: "graph", text: "text" };

  // ---------------------------------------------------------------- engine
  const QueueCtx = React.createContext(null);
  const useQueue = () => React.useContext(QueueCtx);

  let _id = 100;
  const seed = () => ([
    { id: 1, title: "How Kafka works — explained",  type: "youtube", mode: "visual", state: "processing", progress: 62, step: 3 },
    { id: 2, title: "Checkout state machine",        type: "graph",   mode: "visual", state: "processing", progress: 24, step: 1 },
    { id: 3, title: "Q4 OKRs — planning notes",      type: "text",    mode: "audio",  state: "queued",     progress: 0,  step: 0 },
    { id: 4, title: "Vector databases explained",    type: "youtube", mode: "visual", state: "queued",     progress: 0,  step: 0 },
    { id: 5, title: "Auth service request flow",     type: "graph",   mode: "visual", state: "failed",     progress: 46, step: 2, error: "Engine timed out at “Render diagram”" },
  ]);

  function QueueProvider({ children }) {
    const e = useEngine();
    const [jobs, setJobs] = React.useState(seed);

    // promote queued → processing while a slot is free
    const promote = (list) => {
      const out = list.map((j) => ({ ...j }));
      let running = out.filter((j) => j.state === "processing").length;
      for (const j of out) {
        if (running >= CONCURRENCY) break;
        if (j.state === "queued") { j.state = "processing"; running++; }
      }
      return out;
    };

    // real-time-ish simulation
    React.useEffect(() => {
      const t = setInterval(() => {
        setJobs((prev) => {
          let next = prev.map((j) => {
            if (j.state !== "processing") return j;
            const np = Math.min(100, j.progress + 2 + Math.random() * 3);
            const step = Math.min(D.genSteps.length - 1, Math.floor((np / 100) * D.genSteps.length));
            if (np >= 100) return { ...j, progress: 100, step: D.genSteps.length - 1, state: "done", completedAt: Date.now() };
            return { ...j, progress: np, step };
          });
          return promote(next);
        });
      }, 650);
      return () => clearInterval(t);
    }, []);

    const enqueue = ({ title, type, mode }) => {
      const job = { id: ++_id, title: title || "New walkthrough", type: type || "text", mode: mode || "visual", state: "queued", progress: 0, step: 0, justAdded: true };
      setJobs((prev) => promote([...prev, job]));
      setTimeout(() => setJobs((prev) => prev.map((j) => j.id === job.id ? { ...j, justAdded: false } : j)), 1600);
      return job.id;
    };
    const cancel  = (id) => setJobs((prev) => promote(prev.filter((j) => j.id !== id)));
    const retry   = (id) => setJobs((prev) => promote(prev.map((j) => j.id === id ? { ...j, state: "queued", progress: 0, step: 0, error: null } : j)));
    const dismiss = (id) => setJobs((prev) => prev.filter((j) => j.id !== id));
    const clearFinished = () => setJobs((prev) => prev.filter((j) => j.state === "processing" || j.state === "queued"));

    const processing = jobs.filter((j) => j.state === "processing");
    const queued     = jobs.filter((j) => j.state === "queued");
    const done       = jobs.filter((j) => j.state === "done");
    const failed     = jobs.filter((j) => j.state === "failed");
    const active     = processing.length + queued.length;
    const overallPct = processing.length
      ? Math.round(processing.reduce((a, j) => a + j.progress, 0) / processing.length)
      : 0;

    const value = {
      jobs, processing, queued, done, failed, active, overallPct,
      enqueue, cancel, retry, dismiss, clearFinished, CONCURRENCY,
    };
    return React.createElement(QueueCtx.Provider, { value }, children);
  }

  // ---------------------------------------------------------------- helpers
  const stateLabel = (j) => ({
    processing: D.genSteps[j.step] ? D.genSteps[j.step].label : "Working",
    queued: "Waiting in line",
    done: "Ready",
    failed: j.error || "Failed",
  }[j.state]);

  const etaText = (j) => {
    if (j.state === "processing") { const s = Math.max(1, Math.round((100 - j.progress) / 100 * 38)); return "~" + s + "s left"; }
    if (j.state === "queued") return "Up next";
    if (j.state === "done") return "Done";
    return "";
  };

  // ---------------------------------------------------------------- atoms
  function JobIcon({ type, size = 15 }) { return <Icon name={TYPE_ICON[type] || "text"} size={size} />; }

  function StateDot({ state }) {
    return <span className={"q-sdot q-sdot--" + state} aria-hidden="true">
      {state === "done"   && <Icon name="check" size={10} />}
      {state === "failed" && <Icon name="x" size={10} />}
      {state === "queued" && <Icon name="clock" size={10} />}
      {state === "processing" && <span className="q-spin" />}
    </span>;
  }

  function MiniBar({ pct, state }) {
    return <div className={"q-bar q-bar--" + state}><i style={{ width: (state === "queued" ? 0 : pct) + "%" }} /></div>;
  }

  // circular progress ring (SVG)
  function Ring({ pct, size = 38, stroke = 4, state = "processing", children }) {
    const r = (size - stroke) / 2, c = 2 * Math.PI * r;
    const off = c * (1 - (state === "queued" ? 0 : pct) / 100);
    const col = state === "failed" ? "var(--danger)" : state === "done" ? "var(--success)" : "var(--accent)";
    return (
      <span className="q-ring" style={{ width: size, height: size }}>
        <svg width={size} height={size}>
          <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--separator)" strokeWidth={stroke} />
          <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={col} strokeWidth={stroke} strokeLinecap="round"
            strokeDasharray={c} strokeDashoffset={off} transform={`rotate(-90 ${size / 2} ${size / 2})`}
            style={{ transition: "stroke-dashoffset .5s ease, stroke .3s" }} />
        </svg>
        <span className="q-ring-in">{children}</span>
      </span>
    );
  }

  // ---------------------------------------------------------------- compose → enqueue
  // Used by all options in place of the blocking ComposeBody. Generate ENQUEUES
  // and closes immediately — the queue surface takes over from here.
  const detect = (t) => /-->|graph |sequencediagram/i.test(t) ? "graph" : /(youtu\.be|youtube\.com)/i.test(t) ? "youtube" : "text";
  const TYPE_NAME = { youtube: "YouTube", graph: "Mermaid", text: "Text" };
  function QueueCompose() {
    const e = useEngine(), q = useQueue();
    const [src, setSrc] = React.useState("https://youtu.be/agent-memory-deep-dive");
    const [title, setTitle] = React.useState("Designing agent memory");
    const [speed, setSpeed] = React.useState(1);
    const [level, setLevel] = React.useState(1);
    const [dd, setDd] = React.useState(null);
    const SPEED = ["Fast", "Normal", "Smart"], LEVEL = ["Easy", "Normal", "Technical"];
    const SPEED_D = ["Quick draft, lowest cost", "Balanced quality", "Deepest reasoning"];
    const LEVEL_D = ["Plain language", "General audience", "Full depth & jargon"];
    const AUDIENCE = ["Plain", "Exec", "Deep"];  // segmented audience control
    const type = detect(src);
    const ytLocked = type === "youtube" && !e.ytEnabled;  // YouTube Import is a Pro plugin

    const submit = (mode) => {
      q.enqueue({ title: title.trim() || "New walkthrough", type, mode });
      e.closeOverlay();
      const slotFree = q.processing.length < q.CONCURRENCY;
      e.flash(slotFree ? "Added — generating now" : "Added to the queue · " + (q.queued.length + 1) + " waiting");
    };

    return (
      <Scrim onClose={e.closeOverlay} blur center>
        <div className="modal modal--compose" onPointerDown={(ev) => ev.stopPropagation()}>
          <O.ModalHead title="New walkthrough" sub="Paste a source — it joins your generation queue" onClose={e.closeOverlay} icon="plus" />
          <div className="compose-block">
            <span className="compose-cap">Name</span>
            <input className="field-lg" value={title} onChange={(ev) => setTitle(ev.target.value)} placeholder="Name this walkthrough" />
          </div>
          <span className="compose-cap">Source</span>
          <div className="src-area">
            <textarea value={src} onChange={(ev) => setSrc(ev.target.value)} placeholder="Paste a Mermaid diagram, a YouTube link, or notes…" />
            <span className={"detect-badge" + (ytLocked ? " detect-badge--locked" : "")}>
              {ytLocked ? <React.Fragment><Icon name="lock" size={10} />YouTube · Pro</React.Fragment> : "Detected: " + TYPE_NAME[type]}
            </span>
          </div>
          <div className="compose-fields">
            {[["Intelligence", SPEED, SPEED_D, speed, setSpeed], ["Audience", AUDIENCE, LEVEL_D, level, setLevel]].map(([lbl, OPTS, DESC, val, set]) => (
              <div key={lbl} className="audfield">
                <span className="lbl">{lbl}</span>
                <div className="audseg" role="group" aria-label={lbl}>
                  {OPTS.map((t, i) => (
                    <button key={t} type="button" className={i === val ? "on" : ""} onClick={() => set(i)} data-tip={DESC[i]}>
                      {t}
                    </button>
                  ))}
                </div>
              </div>
            ))}
          </div>
          {ytLocked ? (
            <div className="q-foot-note q-foot-note--lock"><Icon name="lock" size={12} />YouTube Import is a Pro plugin — unlock it to turn videos into walkthroughs.</div>
          ) : q.processing.length >= q.CONCURRENCY && (
            <div className="q-foot-note"><Icon name="clock" size={12} />{q.processing.length} jobs running — yours waits its turn, then starts automatically.</div>
          )}
          <div className="modal-foot">
            <span className="modal-status" />
            {ytLocked ? (
              <Pill variant="pri" icon="lock" onClick={() => e.openOverlay("paywall")}>Unlock YouTube Import · {D.youtube.price}</Pill>
            ) : (
              <React.Fragment>
                <Pill variant="sec" icon="wave" onClick={() => submit("audio")}>Audio only</Pill>
                <Pill variant="pri" icon="activity" onClick={() => submit("visual")}>Visual walkthrough</Pill>
              </React.Fragment>
            )}
          </div>
        </div>
      </Scrim>
    );
  }

  // ---------------------------------------------------------------- audio "now playing" stage
  // Shown in place of the diagram when an audio-only walkthrough is playing.
  function AudioStage() {
    const e = useEngine();
    const ch = e.D.chapters[e.ci];
    const s = e.D.transcript[e.curSentence];
    return (
      <div className="aud-stage">
        <div className="aud-center">
          <Avatar speaking={e.playing} size={116} />
          <div className="aud-kicker"><Icon name="wave" size={12} />Audio narration</div>
          <div className="aud-title">{e.D.meta.title}</div>
          <div className="aud-chap">{e.ci + 1}/{e.D.chapters.length} · {ch.title}</div>
          {e.captionsOn && <p className="aud-cap">{s ? s.text : ""}</p>}
          {!e.playing && <div className="aud-hint">Press play — there’s no diagram for this one, just narration.</div>}
        </div>
      </div>
    );
  }

  // ---------------------------------------------------------------- Library-as-queue (Option C)
  // The shipped integration: jobs live inside the Library as an "In progress"
  // section that resolves into finished walkthroughs, plus a global hairline +
  // a live badge by the Library chip.
  function QCJobRow({ j }) {
    const q = useQueue();
    const e = useEngine();
    const open = () => { e.closeOverlay(); e.setPlaybackMode(j.mode || "visual"); e.flash((j.mode === "audio" ? "Playing audio narration — “" : "Opened “") + j.title + "”"); e.gotoChapter(0); q.dismiss(j.id); };
    return (
      <div className={"qc-jrow qc-jrow--" + j.state + (j.justAdded ? " q-row--added" : "")}>
        <span className="qc-jrow-ic"><JobIcon type={j.type} size={15} /></span>
        <div className="qc-jrow-main">
          <div className="qc-jrow-top">
            <span className="qc-jrow-t">{j.title}</span>
            <span className={"q-badge q-badge--" + j.state}>
              {j.state === "processing" && <React.Fragment>Working · {Math.round(j.progress)}%</React.Fragment>}
              {j.state === "queued" && "Queued"}
              {j.state === "done" && "Ready"}
              {j.state === "failed" && "Failed"}
            </span>
          </div>
          {(j.state === "processing" || j.state === "queued") && <MiniBar pct={j.progress} state={j.state} />}
          <div className="qc-jrow-sub">
            {j.state === "failed"
              ? <span style={{ color: "var(--danger)" }}>{j.error}</span>
              : <span>{stateLabel(j)} · {etaText(j)}</span>}
          </div>
        </div>
        <div className="q-row-act">
          {j.state === "done"   && <button className="q-act q-act--go" onClick={open}>Open</button>}
          {j.state === "failed" && <button className="q-act q-act--retry" onClick={() => q.retry(j.id)}><Icon name="refresh" size={13} />Retry</button>}
          {(j.state === "processing" || j.state === "queued") && <button className="q-act q-act--danger" onClick={() => q.cancel(j.id)} title="Cancel"><Icon name="x" size={15} /></button>}
          {j.state === "failed" && <button className="q-act" onClick={() => q.dismiss(j.id)} title="Dismiss"><Icon name="x" size={14} /></button>}
        </div>
      </div>
    );
  }

  function QueueLibrary() {
    const e = useEngine();
    const q = useQueue();
    const [tab, setTab] = React.useState("all");      // all | progress
    const [libItems, setLibItems] = React.useState(D.library);
    const [selecting, setSelecting] = React.useState(false);
    const [sel, setSel] = React.useState(() => new Set());
    const [srcMenu, setSrcMenu] = React.useState(null);   // index of the row whose source popup is open
    const inProgress = [...q.processing, ...q.queued, ...q.failed];
    const [query, setQuery] = React.useState("");
    const ql = query.trim().toLowerCase();
    const match = (t) => !ql || t.toLowerCase().includes(ql);
    const visProgress = inProgress.filter((j) => match(j.title));
    const visSaved = libItems.map((r, i) => ({ r, i })).filter(({ r }) => match(r.title));
    const showProgress = tab === "all" || tab === "progress";
    const showSaved = tab === "all";
    const allSel = visSaved.length > 0 && visSaved.every(({ i }) => sel.has(i));
    const toggleSel = (i) => setSel((s) => { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });
    const exitSelect = () => { setSelecting(false); setSel(new Set()); };
    const delSelected = () => { const n = sel.size; setLibItems((items) => items.filter((_, i) => !sel.has(i))); exitSelect(); e.flash(n + (n === 1 ? " walkthrough deleted" : " walkthroughs deleted")); };

    // finished jobs flow straight into Your walkthroughs (tagged New), no separate section
    const doneKey = q.done.map((j) => j.id).join(",");
    React.useEffect(() => {
      if (q.done.length === 0) return;
      setLibItems((items) => {
        const fresh = q.done
          .filter((j) => !items.some((it) => it._jid === j.id))
          .map((j) => ({ title: j.title, type: j.type, dur: "", mode: j.mode, state: "active", isNew: true, _jid: j.id }));
        return fresh.length ? [...fresh, ...items] : items;
      });
      q.done.forEach((j) => q.dismiss(j.id));
      // eslint-disable-next-line
    }, [doneKey]);
    return (
      <Scrim onClose={e.closeOverlay} blur>
        <div className="spotlight spotlight--lib glassT qc-lib" onPointerDown={(ev) => ev.stopPropagation()}>
          <O.ModalHead title="Library" sub="Generating now and everything you’ve made" icon="collection" onClose={e.closeOverlay} />
          <div className="qc-tabs">
            <button className={tab === "all" ? "on" : ""} onClick={() => setTab("all")}>All</button>
            <button className={tab === "progress" ? "on" : ""} onClick={() => setTab("progress")}>
              In progress {inProgress.length > 0 && <span className="qc-tab-n">{inProgress.length}</span>}
            </button>
            <span className="qc-tabs-sp" />
            <Pill variant="pri" icon="plus" onClick={() => e.openOverlay("qcompose")}>New</Pill>
          </div>

          <div className="field qc-search">
            <Icon name="search" size={15} />
            <input placeholder="Search walkthroughs…" value={query} onChange={(ev) => setQuery(ev.target.value)} autoFocus />
            {query
              ? <button className="ib" onClick={() => setQuery("")} aria-label="Clear search"><Icon name="x" size={13} /></button>
              : <kbd>⌘L</kbd>}
          </div>

          <div className="qc-scroll">
            {showProgress && visProgress.length > 0 && (
              <React.Fragment>
                <div className="q-sec"><span>In progress</span><span className="q-sec-count">{visProgress.length}</span><span className="q-sec-line" />
                  {q.failed.length + q.done.length > 0 && <button className="qc-clear" onClick={q.clearFinished}>Clear finished</button>}
                </div>
                {visProgress.map((j) => <QCJobRow key={j.id} j={j} />)}
              </React.Fragment>
            )}

            {showSaved && (
              <React.Fragment>
                <div className="q-sec" style={{ marginTop: inProgress.length ? "16px" : 0 }}><span>Your walkthroughs</span><span className="q-sec-line" />
                  {!selecting && libItems.length > 0 && <button className="qc-sel" onClick={() => setSelecting(true)}>Select</button>}
                  {selecting && (
                    <span className="qc-selbar">
                      <button className="qc-sel" onClick={() => setSel(allSel ? new Set() : new Set(visSaved.map(({ i }) => i)))}>{allSel ? "Clear" : "All"}</button>
                      <button className="qc-sel qc-sel--danger" disabled={sel.size === 0} onClick={delSelected}><Icon name="trash" size={12} />Delete{sel.size ? " (" + sel.size + ")" : ""}</button>
                      <button className="qc-sel" onClick={exitSelect}>Done</button>
                    </span>
                  )}
                </div>
                {libItems.length === 0 && <div className="q-empty"><Icon name="collection" size={24} /><b>No saved walkthroughs</b><span>Generate one with New — it lands here when it’s ready.</span></div>}
                {libItems.length > 0 && visSaved.length === 0 && <div className="q-empty"><Icon name="search" size={24} /><b>No matches</b><span>Nothing here matches “{query}”.</span></div>}
                {visSaved.map(({ r, i }, pos) => {
                  const up = visSaved.length > 3 && pos >= visSaved.length - 2;
                  return (
                  <div key={i} className={"qc-srow" + (r.current && !selecting ? " qc-srow--cur" : "") + (selecting && sel.has(i) ? " qc-srow--sel" : "") + (srcMenu === i ? " qc-srow--menu" : "")}
                    onClick={selecting ? () => toggleSel(i) : () => { e.closeOverlay(); e.setPlaybackMode(r.mode || "visual"); e.gotoChapter(0); }}>
                    {selecting && <span className={"qc-check" + (sel.has(i) ? " on" : "")} aria-hidden="true" />}
                    <Icon name={TYPE_ICON[r.type]} size={16} />
                    <span className="qc-srow-t">{r.title}</span>
                    {r.isNew && <span className="q-badge q-badge--done">New</span>}
                    {r.mode === "audio" && <span className="qc-aud" title="Audio only — narration, no diagram"><Icon name="wave" size={12} /></span>}
                    {r.dur && <span className="lrow-dur">{r.dur}</span>}
                    {!selecting && (
                      <span className="qc-srow-actions" onClick={(ev) => ev.stopPropagation()}>
                        <IBtn icon="play" size={13} label={r.mode === "audio" ? "Play audio" : "Play walkthrough"} onClick={() => { e.closeOverlay(); e.setPlaybackMode(r.mode || "visual"); e.gotoChapter(0); e.setPlaying(true); e.flash(r.mode === "audio" ? "Playing audio narration" : "Playing walkthrough"); }} />
                        <span className="qc-srcwrap">
                          <IBtn icon="clipboard" size={13} label="Original source" active={srcMenu === i} onClick={() => setSrcMenu(srcMenu === i ? null : i)} />
                          {srcMenu === i && (
                            <React.Fragment>
                              <div className="qc-srcpop-catch" onClick={(ev) => { ev.stopPropagation(); setSrcMenu(null); }} />
                              <div className={"qc-srcpop glassT" + (up ? " qc-srcpop--up" : "")}>
                                <div className="qc-srcpop-head">
                                  <span className="qc-srcpop-ic"><Icon name="clipboard" size={15} /></span>
                                  <div className="qc-srcpop-meta"><b>Original source</b><span>{D.source.origin}</span></div>
                                </div>
                                <button className="menu-row" onClick={() => { setSrcMenu(null); e.openOverlay("sourceFull"); }}><Icon name="expand" size={15} /><span>View source</span></button>
                                <button className="menu-row" onClick={() => { setSrcMenu(null); e.flash("Source copied"); }}><Icon name="link" size={15} /><span>Copy</span></button>
                                <button className="menu-row" onClick={() => { setSrcMenu(null); e.flash("Source downloaded"); }}><Icon name="arrowUp" size={15} /><span>Download</span></button>
                              </div>
                            </React.Fragment>
                          )}
                        </span>
                        <IBtn icon="bookmark" size={13} label="Save" onClick={() => e.flash("Saved to favorites")} />
                        <IBtn icon="trash" size={13} label="Delete" onClick={() => { setLibItems((items) => items.filter((_, k) => k !== i)); e.flash("Walkthrough deleted"); }} />
                      </span>
                    )}
                  </div>
                  );
                })}
              </React.Fragment>
            )}

            {tab === "progress" && visProgress.length === 0 && (
              <div className="q-empty"><Icon name={ql ? "search" : "check"} size={26} /><b>{ql ? "No matches" : "Nothing generating"}</b><span>{ql ? "No in-progress jobs match “" + query + "”." : "Everything’s finished. New walkthroughs appear here while they cook."}</span></div>
            )}
          </div>
        </div>
      </Scrim>
    );
  }

  function Hairline() {
    const q = useQueue();
    if (q.processing.length === 0) return null;
    return <div className="qc-hair"><i style={{ width: q.overallPct + "%" }} /></div>;
  }
  function LibBadge() {
    const e = useEngine();
    const q = useQueue();
    if (q.active === 0 && q.failed.length === 0) return null;
    return (
      <button className={"qc-badge" + (q.failed.length ? " qc-badge--warn" : "")} onClick={() => e.openOverlay("library")} title="Open Library — generation in progress">
        {q.processing.length > 0
          ? <Ring size={17} stroke={2.5} pct={q.overallPct} />
          : <Icon name={q.failed.length ? "refresh" : "clock"} size={13} />}
        <span>{q.active || q.failed.length}</span>
      </button>
    );
  }

  // ---------------------------------------------------------------- shared shell chrome
  const Traffic = () => <div className="traffic"><i className="r" /><i className="y" /><i className="g" /></div>;
  function Pop({ where, onClose, children }) {
    return (
      <React.Fragment>
        <div className="pop-catch" onPointerDown={onClose} />
        <div className={"pop-anchor pop-anchor--" + where}>{children}</div>
      </React.Fragment>
    );
  }
  const moreItems = (e) => ([
    { ic: "youtube", label: "Original source…", go: () => e.openOverlay("source") },
    { ic: "settings", label: "Settings…", kbd: "⌘,", go: () => e.openOverlay("settings") },
    { sep: true },
    { ic: e.theme === "dark" ? "info" : "dot", label: e.theme === "dark" ? "Switch to Light" : "Switch to Dark", go: e.toggleTheme },
  ]);
  function Menu({ items, onClose, where }) {
    return (
      <Pop where={where} onClose={onClose}>
        <div className="menu glassT">
          {items.map((it, i) => it.sep
            ? <div key={i} className="menu-sep" />
            : <button key={i} className="menu-row" onClick={() => { onClose(); it.go(); }}>
                <Icon name={it.ic} size={15} /><span>{it.label}</span>{it.kbd && <kbd>{it.kbd}</kbd>}
              </button>)}
        </div>
      </Pop>
    );
  }
  function Toast() { const e = useEngine(); if (!e.toast) return null; return <div className="toast glassT"><Icon name="check" size={14} />{e.toast}</div>; }

  /* ShellChrome — the common Concept1 portable shell.
     props:
       brandSlot   : node rendered in the brand pill, after "New"
       onNew       : New-button handler (defaults to qcompose overlay)
       libraryNode : custom library modal (defaults to centered LibraryBody)
       children    : queue surface(s) rendered on top of the canvas         */
  function ShellChrome({ brandSlot, onNew, libraryNode, children }) {
    const e = useEngine();
    const [pop, setPop] = React.useState(null);
    const [actOpen, setActOpen] = React.useState(false);
    const [actPinned, setActPinned] = React.useState(false);
    const actExpanded = actOpen || actPinned;
    const newHandler = onNew || (() => e.openOverlay("qcompose"));
    const actions = (
      <React.Fragment>
        <IBtn icon="sparkles" label="Gold nuggets" active={pop === "nuggets"} onClick={() => setPop(pop === "nuggets" ? null : "nuggets")} />
        <IBtn icon="chat" label="Ask" active={e.chatOpen} onClick={e.toggleChat} />
        <IBtn icon="wand" label="Change audience" onClick={() => e.openOverlay("audience")} />
        <IBtn icon="share" label="Share" onClick={() => e.flash("Link copied")} />
        <IBtn icon="settings" label="More" active={pop === "menu"} onClick={() => setPop(pop === "menu" ? null : "menu")} />
      </React.Fragment>
    );
    return (
      <div className="c1">
        {e.playbackMode === "audio" ? <AudioStage /> : <DiagramCanvas />}

        <div className="c1-topleft">
          <div className="c1-brand glass">
            <Traffic />
            <button className="c1-libword" onClick={() => e.openOverlay("library")} title="Open Library">
              <Icon name="collection" size={14} /><span>Library</span>
            </button>
            <Pill variant="pri" icon="plus" onClick={newHandler}>New</Pill>
            {brandSlot}
          </div>
          {e.playbackMode !== "audio" && <ZoomPanel collapsible />}
        </div>

        <div className="c1-actions glass"
          onMouseEnter={() => setActOpen(true)}
          onMouseLeave={() => { if (!pop) setActOpen(false); }}>
          {actExpanded ? (
            <React.Fragment>
              <button className={"ib" + (actPinned ? " ib--on" : "")} onClick={() => setActPinned((p) => !p)} title={actPinned ? "Unpin" : "Pin controls open"} aria-pressed={actPinned}><Icon name="chevronRight" size={16} /></button>
              {actions}
            </React.Fragment>
          ) : (
            <IBtn icon="chevronLeft" label="Show controls" onClick={() => setActPinned(true)} />
          )}
        </div>

        {pop === "nuggets" && <Pop where="tr" onClose={() => setPop(null)}><NuggetsBody onClose={() => setPop(null)} /></Pop>}
        {pop === "menu" && <Menu where="tr" items={moreItems(e)} onClose={() => setPop(null)} />}

        <div className="c1-bottom"><Transport caption collapsible /></div>

        {e.chatOpen && (
          <div className="c1-drawer">
            <div className="glassT drawer-card"><ChatBody variant="drawer" unifiedHead onClose={() => e.setChatOpen(false)} /></div>
          </div>
        )}

        {/* queue surface(s) for this option */}
        {children}

        {/* library */}
        {e.overlay === "library" && (libraryNode || (
          <Scrim onClose={e.closeOverlay} blur>
            <div className="spotlight spotlight--lib glassT" onPointerDown={(ev) => ev.stopPropagation()}><LibraryBody centered onClose={e.closeOverlay} /></div>
          </Scrim>
        ))}
        {e.overlay === "source" && <Scrim onClose={e.closeOverlay} blur center><div onPointerDown={(ev) => ev.stopPropagation()}><SourceBody onClose={e.closeOverlay} openFull={() => e.openOverlay("sourceFull")} /></div></Scrim>}
        {e.overlay === "qcompose" && <QueueCompose />}
        <OverlayHost />
        <Toast />
      </div>
    );
  }

  window.SHELL_QUEUE = {
    QueueProvider, useQueue, ShellChrome, QueueCompose,
    QueueLibrary, QCJobRow, Hairline, LibBadge, AudioStage,
    JobIcon, StateDot, MiniBar, Ring, Toast,
    CONCURRENCY, stateLabel, etaText, TYPE_ICON,
  };
})();
