/* ============================================================
   Guided Workshop v2 — main app
   Layout: top bar + progress strip + viewer canvas + sticky action bar
   Overlays: chapter outline (slide-from-left), Cmd+K, actions drawer,
             poll presenter, lightbox.
   ============================================================ */

const { ContentView, MediaView, EvidenceView, QuestionView, PollPresenter, Lightbox, v2Icons } = window.gwV2Views;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "progressPreset": "mid",
  "perspective": "completer",
  "sessionLive": true
}/*EDITMODE-END*/;

/* ---------- helpers ---------- */
const allItems = () => GW_CHAPTERS.flatMap(c => c.items.map(it => ({ chapter: c, item: it })));
const flatIndex = (id) => allItems().findIndex(p => p.item.id === id);
const findById = (id) => allItems().find(p => p.item.id === id);

function presetCompletion(preset) {
  const ids = allItems().map(p => p.item.id);
  const n = preset === "start" ? 1
          : preset === "early" ? Math.round(ids.length * 0.15)
          : preset === "mid"   ? Math.round(ids.length * 0.45)
          : preset === "late"  ? Math.round(ids.length * 0.85)
          : ids.length;
  return new Set(ids.slice(0, n));
}

function labelForItem(it) {
  if (it.type === "question") {
    const map = { radio: "Multiple choice", rating: "Rating", boolean: "Yes / No", text: "Short answer", textarea: "Long answer" };
    const sub = map[it.questionType] || "Question";
    return it.mode === "poll" ? `Poll · ${sub}` : sub;
  }
  if (it.type === "media") {
    if (it.mediaKind === "video") return "Video";
    return Array.isArray(it.images) && it.images.length > 1 ? "Image set" : "Image";
  }
  if (it.type === "content") return "Reading";
  if (it.type === "evidence") return "Evidence upload";
  return it.type;
}

function iconForItem(it) {
  const t = it.type;
  if (t === "content") return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 6h16M4 12h10M4 18h16"/></svg>;
  if (t === "media") return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.5"/><polyline points="21 16 16 11 5 21"/></svg>;
  if (t === "evidence") return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>;
  if (t === "question") {
    if (it.mode === "poll") return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>;
    return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>;
  }
  return null;
}

/* ============================================================
   TopBar — minimal sticky header
   ============================================================ */
function TopBar({ index, total, percent, onOutline, onCmdK, onActions, onAi, tx }) {
  return (
    <header className="v2-topbar">
      <div className="v2-topbar-left">
        <a className="v2-back" href="../kits/completer-modules.html" title="Back to modules">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
        </a>
        <button className="v2-outline-trigger" onClick={onOutline} title="Workshop outline (O)">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
        </button>
        <div className="v2-topbar-title">
          <span className="v2-topbar-eyebrow">Guided workshop</span>
          <h1>Asset Management</h1>
        </div>
      </div>

      <div className="v2-topbar-right">
        {tx && <window.TranscribeButton tx={tx} variant="v2" />}
        <div className="v2-topbar-stat">
          <span className="v2-topbar-stat-num">{index + 1}<span>/{total}</span></span>
          <span className="v2-topbar-stat-lbl">{percent}% complete</span>
        </div>
        <button className="v2-topbar-btn" onClick={onCmdK} title="Quick jump (⌘K)">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
          <span className="v2-kbd">⌘K</span>
        </button>
        <button className="v2-topbar-btn" onClick={onActions} title="Actions captured (A)">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
          <span>Actions · {GW_ACTIONS.length}</span>
        </button>
        <button className="v2-ai-btn" onClick={onAi} title="AI report">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4z"/><path d="M5 18l.5 1.4L7 20l-1.5.6L5 22l-.5-1.4L3 20l1.5-.6z"/><path d="M19 16l.5 1.4L21 18l-1.5.6L19 20l-.5-1.4L17 18l1.5-.6z"/></svg>
          <span>AI report</span>
        </button>
      </div>
    </header>
  );
}

/* ============================================================
   ProgressStrip — thin progress bar with chapter section markers
   ============================================================ */
function ProgressStrip({ percent, index, total }) {
  /* Chapter dividers — positioned at the cumulative item count */
  const total_ = allItems().length;
  let cum = 0;
  const markers = GW_CHAPTERS.map((c) => {
    cum += c.items.length;
    return { id: c.id, pos: (cum / total_) * 100 };
  }).slice(0, -1); // skip the last (100% boundary)

  return (
    <div className="v2-progress-strip" aria-hidden="true">
      <div className="v2-progress-fill" style={{ width: `${percent}%` }} />
      {markers.map((m) => (
        <span key={m.id} className="v2-progress-marker" style={{ left: `${m.pos}%` }} />
      ))}
      <span className="v2-progress-cursor" style={{ left: `${(index / Math.max(1, total - 1)) * 100}%` }} />
    </div>
  );
}

/* ============================================================
   Viewer — the hero canvas. Chooses layout by item type.
   ============================================================ */
function Viewer({ pair, completion, answers, setAnswer, pollLive, onReopenPoll, onPresentResults, sup }) {
  if (!pair) return null;
  const { item, chapter } = pair;
  const complete = completion.has(item.id);

  /* Each type gets its own outer layout. Title chrome (eyebrow + h1)
     is shared but hidden for media-noTitle. */
  const showTitleChrome = item.type !== "media" || item.showTitle;

  return (
    <section className="v2-viewer" data-screen-label={`${chapter.num}.${item.num} ${item.title}`}>
      {sup && sup.sessionLive && (
        <window.SupporterDock sup={sup} itemId={item.id} position="tr" />
      )}
      {sup && <window.SupporterAskCreator sup={sup} />}
      {sup && sup.sessionLive && <window.SupporterGuidanceCard sup={sup} itemId={item.id} />}
      {sup && sup.sessionLive && <window.SupporterHighlightStrip sup={sup} itemId={item.id} />}
      {sup && sup.sessionLive && <window.SupporterTakeoverPulse sup={sup} itemId={item.id} />}
      {showTitleChrome && (
        <header className="v2-viewer-header">
          <div className="v2-viewer-eyebrow">
            <span className="v2-chapter-tag">Chapter {chapter.num} · {chapter.title}</span>
            <span className="v2-type-tag">
              <span className="v2-type-icon">{iconForItem(item)}</span>
              {labelForItem(item)}
            </span>
            {item.required && <span className="v2-required-tag">Required</span>}
            {complete && <span className="v2-complete-tag">{v2Icons.check} Completed</span>}
          </div>
          <div className="v2-viewer-titlerow">
            <span className="v2-viewer-num">{item.num}</span>
            <h1 className="v2-viewer-title">{item.title}</h1>
          </div>
        </header>
      )}

      <div className="v2-viewer-body">
        {item.type === "content"  && <ContentView  item={item} />}
        {item.type === "media"    && <MediaView    item={item} />}
        {item.type === "evidence" && <EvidenceView item={item} />}
        {item.type === "question" && (
          <QuestionView
            item={item}
            answer={answers[item.id]}
            onAnswer={(a) => setAnswer(item.id, a)}
            pollLive={pollLive}
            complete={complete}
            onReopenPoll={onReopenPoll}
            onPresentResults={onPresentResults}
          />
        )}
        {sup && <window.SupporterStuckButton sup={sup} itemId={item.id} thresholdSec={30} />}
      </div>
      {sup && sup.sessionLive && sup.openPanel === "comments" && (
        <window.SupporterCommentPanel sup={sup} itemId={item.id} onClose={() => sup.setOpenPanel(null)} />
      )}
    </section>
  );
}

/* ============================================================
   ActionBar — sticky bottom: prev / contextual / complete / next
   ============================================================ */
function ActionBar({ pair, prev, next, complete, onPrev, onNext, onComplete, onOpenPoll, onPresent, onReopenPoll, pollLive }) {
  if (!pair) return null;
  const { item } = pair;
  const isPoll = item.type === "question" && item.mode === "poll";
  const pollState = !isPoll ? null : pollLive ? "live" : complete ? "closed" : "never";

  return (
    <footer className="v2-actionbar">
      <button className="v2-actionbar-step" onClick={onPrev} disabled={!prev} title={prev ? `Previous · ${prev.item.num} ${prev.item.title}` : null}>
        <span className="v2-actionbar-step-arrow">{v2Icons.arrowL}</span>
        <span className="v2-actionbar-step-text">
          {prev ? (
            <>
              <span className="v2-actionbar-step-lbl">Previous</span>
              <span className="v2-actionbar-step-name">{prev.item.num} {prev.item.title}</span>
            </>
          ) : <span className="v2-actionbar-step-lbl">Start</span>}
        </span>
      </button>

      <div className="v2-actionbar-center">
        {isPoll && pollState === "never" && (
          <button className="v2-btn v2-btn-tonal" onClick={onOpenPoll}>
            {v2Icons.play}<span>Open poll</span>
          </button>
        )}
        {isPoll && pollState === "live" && (
          <>
            <button className="v2-btn v2-btn-tonal is-on" onClick={onPresent}>
              <span className="v2-live-dot" />
              <span>Poll live · {item.session?.responded || 0}</span>
              {v2Icons.expand}
            </button>
          </>
        )}
        {isPoll && pollState === "closed" && (
          <button className="v2-btn v2-btn-secondary" onClick={onReopenPoll}>
            {v2Icons.refresh}<span>Reopen poll</span>
          </button>
        )}
        {complete ? (
          <button className="v2-btn v2-btn-completed" onClick={onComplete} title="Mark as not complete">
            <span className="v2-btn-check">{v2Icons.check}</span><span>Completed</span>
          </button>
        ) : (
          <button
            className="v2-btn v2-btn-primary"
            onClick={onComplete}
            disabled={isPoll && pollState === "never"}
            title={isPoll && pollState === "never" ? "Open the poll first" : null}
          >
            {v2Icons.check}<span>{isPoll && pollState === "live" ? "Close poll & complete" : "Mark complete"}</span>
          </button>
        )}
      </div>

      <button className="v2-actionbar-step is-right" onClick={onNext} disabled={!next} title={next ? `Next · ${next.item.num} ${next.item.title}` : null}>
        <span className="v2-actionbar-step-text v2-actionbar-step-text-right">
          {next ? (
            <>
              <span className="v2-actionbar-step-lbl">Next</span>
              <span className="v2-actionbar-step-name">{next.item.num} {next.item.title}</span>
            </>
          ) : <span className="v2-actionbar-step-lbl">Finish</span>}
        </span>
        <span className="v2-actionbar-step-arrow">{v2Icons.arrowR}</span>
      </button>
    </footer>
  );
}

/* ============================================================
   ChapterOutline — slide-over from left, shows full chapter tree
   ============================================================ */
function ChapterOutline({ open, onClose, activeId, completion, onPick }) {
  return (
    <div className={`v2-outline-overlay ${open ? "is-open" : ""}`} onClick={onClose}>
      <aside className="v2-outline" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="Workshop outline">
        <header className="v2-outline-head">
          <div>
            <div className="v2-outline-eyebrow">Outline</div>
            <h2>Asset Management</h2>
          </div>
          <button className="v2-icon-btn" onClick={onClose} aria-label="Close">{v2Icons.x}</button>
        </header>
        <div className="v2-outline-body">
          {GW_CHAPTERS.map((c) => {
            const cDone = c.items.filter(it => completion.has(it.id)).length;
            return (
              <section key={c.id} className="v2-outline-chapter">
                <div className="v2-outline-chapter-head">
                  <span className="v2-outline-chapter-num">{c.num}</span>
                  <span className="v2-outline-chapter-title">{c.title}</span>
                  <span className="v2-outline-chapter-meta">{cDone}/{c.items.length}</span>
                </div>
                <ul className="v2-outline-items">
                  {c.items.map((it) => {
                    const isActive = it.id === activeId;
                    const isDone = completion.has(it.id);
                    return (
                      <li key={it.id}>
                        <button className={`v2-outline-item ${isActive ? "is-active" : ""} ${isDone ? "is-done" : ""}`} onClick={() => { onPick(it.id); onClose(); }}>
                          <span className="v2-outline-item-status">
                            {isDone ? v2Icons.check : <span className="v2-outline-item-dot" />}
                          </span>
                          <span className="v2-outline-item-icon">{iconForItem(it)}</span>
                          <span className="v2-outline-item-text">
                            <span className="v2-outline-item-title">{it.num} {it.title}</span>
                            <span className="v2-outline-item-type">{labelForItem(it)}</span>
                          </span>
                        </button>
                      </li>
                    );
                  })}
                </ul>
              </section>
            );
          })}
        </div>
      </aside>
    </div>
  );
}

/* ============================================================
   CmdK — quick-jump command palette
   ============================================================ */
function CmdK({ open, onClose, onPick }) {
  const [query, setQuery] = useState("");
  const inputRef = useRef(null);
  useEffect(() => {
    if (open) {
      setQuery("");
      setTimeout(() => inputRef.current?.focus(), 30);
    }
  }, [open]);
  if (!open) return null;
  const items = allItems();
  const q = query.toLowerCase();
  const filtered = !q ? items : items.filter(p => {
    const it = p.item;
    return (it.title || "").toLowerCase().includes(q)
        || (it.num   || "").toLowerCase().includes(q)
        || (p.chapter.title || "").toLowerCase().includes(q);
  });

  return (
    <div className="v2-cmdk-overlay" onClick={onClose}>
      <div className="v2-cmdk" onClick={(e) => e.stopPropagation()}>
        <div className="v2-cmdk-input-wrap">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
          <input ref={inputRef} className="v2-cmdk-input" placeholder="Jump to an item, chapter, or action…" value={query} onChange={(e) => setQuery(e.target.value)} />
          <kbd className="v2-kbd">esc</kbd>
        </div>
        <div className="v2-cmdk-list">
          {filtered.slice(0, 12).map((p) => (
            <button key={p.item.id} className="v2-cmdk-row" onClick={() => { onPick(p.item.id); onClose(); }}>
              <span className="v2-cmdk-icon">{iconForItem(p.item)}</span>
              <span className="v2-cmdk-text">
                <span className="v2-cmdk-title">{p.item.num} {p.item.title}</span>
                <span className="v2-cmdk-meta">Chapter {p.chapter.num} · {p.chapter.title} · {labelForItem(p.item)}</span>
              </span>
              <span className="v2-cmdk-go">{v2Icons.arrowR}</span>
            </button>
          ))}
          {filtered.length === 0 && <div className="v2-cmdk-empty">No matches</div>}
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   ActionsDrawer — slide-over from right with action list
   ============================================================ */
function ActionsDrawer({ open, onClose }) {
  const priorityLabel = { high: "High", med: "Medium", low: "Low" };
  const priorityCls   = { high: "is-high", med: "is-med", low: "is-low" };
  const statusLabel   = { "in-progress": "In progress", open: "Open", done: "Done" };
  return (
    <div className={`v2-drawer-overlay ${open ? "is-open" : ""}`} onClick={onClose}>
      <aside className="v2-drawer" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="Actions">
        <header className="v2-drawer-head">
          <div>
            <div className="v2-drawer-eyebrow">Captured</div>
            <h2>Actions <span className="v2-drawer-count">{GW_ACTIONS.length}</span></h2>
          </div>
          <button className="v2-icon-btn" onClick={onClose} aria-label="Close">{v2Icons.x}</button>
        </header>
        <div className="v2-drawer-body">
          <button className="v2-btn v2-btn-secondary v2-add-action">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M12 5v14M5 12h14"/></svg>
            <span>Add action</span>
          </button>
          {GW_ACTIONS.map(a => (
            <article key={a.id} className="v2-action-card">
              <div className="v2-action-top">
                <h3>{a.title}</h3>
                <span className={`v2-pill v2-pill-priority ${priorityCls[a.priority]}`}>{priorityLabel[a.priority]}</span>
              </div>
              <p>{a.desc}</p>
              <div className="v2-action-meta">
                <span className="v2-action-owner">
                  <img src={a.owner.avatar} alt=""/>
                  <span>{a.owner.name}</span>
                </span>
                <span className="v2-action-due">Due {a.due}</span>
                <span className={`v2-pill v2-pill-status is-${a.status}`}>{statusLabel[a.status]}</span>
              </div>
              {a.linkedItem && (
                <div className="v2-action-linked">
                  <span>Linked to</span> <b>{a.linkedItem}</b>
                </div>
              )}
            </article>
          ))}
        </div>
      </aside>
    </div>
  );
}

/* ============================================================
   App — root
   ============================================================ */
function App() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  /* Supporter — co-pilot session state */
  const sup = window.useSupporter(t.perspective);
  useEffect(() => { if (sup.perspective !== t.perspective) sup.setPerspective(t.perspective); /* eslint-disable-next-line */ }, [t.perspective]);
  useEffect(() => { sup.setSessionLive(t.sessionLive); /* eslint-disable-next-line */ }, [t.sessionLive]);

  /* Transcribe — session recording + AI summary */
  const tx = window.useTranscribe({ moduleName: "Asset Management" });

  /* URL-param entry point: ?as=supporter | ?as=completer overrides initial perspective. */
  useEffect(() => {
    const as = new URLSearchParams(location.search).get("as");
    if ((as === "supporter" || as === "completer") && t.perspective !== as) setTweak("perspective", as);
    // eslint-disable-next-line
  }, []);

  const items = allItems();
  const total = items.length;

  /* Active item — start at the first not-yet-complete item */
  const [activeId, setActiveId] = useState(() => items[0].item.id);
  const pair = findById(activeId);
  const idx  = flatIndex(activeId);
  const prev = idx > 0           ? items[idx - 1] : null;
  const next = idx < total - 1   ? items[idx + 1] : null;

  const [completion, setCompletion] = useState(() => presetCompletion(t.progressPreset));
  useEffect(() => { setCompletion(presetCompletion(t.progressPreset)); }, [t.progressPreset]);

  /* On mount, jump to the first incomplete item */
  useEffect(() => {
    const firstIncomplete = items.find(p => !completion.has(p.item.id));
    if (firstIncomplete) setActiveId(firstIncomplete.item.id);
    // eslint-disable-next-line
  }, []);

  /* When preset changes, reset to first incomplete */
  useEffect(() => {
    const firstIncomplete = items.find(p => !completion.has(p.item.id));
    if (firstIncomplete) setActiveId(firstIncomplete.item.id);
    // eslint-disable-next-line
  }, [t.progressPreset]);

  const [answers, setAnswers] = useState({});
  const setAnswer = useCallback((id, a) => setAnswers(p => ({ ...p, [id]: a })), []);

  const [pollsLive, setPollsLive] = useState({});
  const isPollLive = (id) => !!pollsLive[id];
  const openPoll   = useCallback((id) => setPollsLive(p => ({ ...p, [id]: true })),  []);
  const closePoll  = useCallback((id) => setPollsLive(p => ({ ...p, [id]: false })), []);

  const [presenterFor, setPresenterFor] = useState(null);

  const toggleComplete = useCallback((id) => {
    setCompletion(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else {
        next.add(id);
        if (pollsLive[id]) {
          setPollsLive(p => ({ ...p, [id]: false }));
          if (presenterFor === id) setPresenterFor(null);
        }
      }
      return next;
    });
  }, [pollsLive, presenterFor]);

  const reopenPoll = useCallback((id) => {
    setPollsLive(p => ({ ...p, [id]: true }));
    setCompletion(prev => { const next = new Set(prev); next.delete(id); return next; });
  }, []);

  const enterPresenter = useCallback(() => {
    if (!pair || pair.item.type !== "question" || pair.item.mode !== "poll") return;
    if (!isPollLive(pair.item.id)) openPoll(pair.item.id);
    setPresenterFor(pair.item.id);
  }, [pair, pollsLive, openPoll]);

  /* Overlays */
  const [outlineOpen, setOutlineOpen] = useState(false);
  const [cmdkOpen, setCmdkOpen]       = useState(false);
  const [actionsOpen, setActionsOpen] = useState(false);
  const [aiOpen, setAiOpen]           = useState(false);

  /* Keyboard shortcuts */
  useEffect(() => {
    const onKey = (e) => {
      const isModK = (e.key === "k" || e.key === "K") && (e.metaKey || e.ctrlKey);
      if (isModK) { e.preventDefault(); setCmdkOpen(true); return; }
      if (presenterFor) {
        if (e.key === "Escape") setPresenterFor(null);
        return;
      }
      if (cmdkOpen || outlineOpen || actionsOpen) {
        if (e.key === "Escape") { setCmdkOpen(false); setOutlineOpen(false); setActionsOpen(false); }
        return;
      }
      const tag = e.target?.tagName;
      if (tag === "INPUT" || tag === "TEXTAREA") return;
      if (e.key === "ArrowRight" && next) setActiveId(next.item.id);
      if (e.key === "ArrowLeft"  && prev) setActiveId(prev.item.id);
      if (e.key === "c" || e.key === "C") toggleComplete(activeId);
      if (e.key === "o" || e.key === "O") setOutlineOpen(true);
      if (e.key === "a" || e.key === "A") setActionsOpen(true);
      if (e.key === "p" || e.key === "P") {
        if (pair?.item.type === "question" && pair.item.mode === "poll") {
          if (isPollLive(pair.item.id)) enterPresenter();
          else openPoll(pair.item.id);
        }
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [next, prev, activeId, pair, cmdkOpen, outlineOpen, actionsOpen, presenterFor, toggleComplete, enterPresenter, openPoll, pollsLive]);

  const done = completion.size;
  const percent = Math.round((done / total) * 100);

  const tweaks = (
    <window.TweaksPanel>
      <window.TweakSection label="Progress state">
        <window.TweakRadio
          options={[
            { value: "start", label: "Just started" },
            { value: "mid",   label: "Mid-flight"   },
            { value: "late",  label: "Almost done"  },
          ]}
          value={t.progressPreset}
          onChange={(v) => setTweak("progressPreset", v)}
        />
      </window.TweakSection>
      <window.TweakSection label="Perspective">
        <window.TweakRadio
          options={[
            { value: "completer", label: "Completer" },
            { value: "supporter", label: "Creator (supporter)" },
          ]}
          value={t.perspective}
          onChange={(v) => setTweak("perspective", v)}
        />
      </window.TweakSection>
      <window.TweakSection label="Live session">
        <window.TweakToggle
          label="Session active"
          value={t.sessionLive}
          onChange={(v) => setTweak("sessionLive", v)}
        />
      </window.TweakSection>
    </window.TweaksPanel>
  );

  return (
    <>
      <TopBar
        index={idx} total={total} percent={percent}
        onOutline={() => setOutlineOpen(true)}
        onCmdK={() => setCmdkOpen(true)}
        onActions={() => setActionsOpen(true)}
        onAi={() => setAiOpen(true)}
        tx={tx}
      />
      <ProgressStrip percent={percent} index={idx} total={total} />

      {sup.sessionLive && <window.SupporterSessionBanner sup={sup} moduleName="Asset Management" />}

      <div className="v2-canvas">
        <Viewer
          pair={pair}
          completion={completion}
          answers={answers}
          setAnswer={setAnswer}
          pollLive={pair ? isPollLive(pair.item.id) : false}
          onReopenPoll={() => pair && reopenPoll(pair.item.id)}
          onPresentResults={() => pair && setPresenterFor(pair.item.id)}
          sup={sup}
        />
      </div>

      {sup.sessionLive && pair && (
        <window.SupporterCoPilotBar sup={sup} itemId={pair.item.id} itemLabel={`${pair.item.num} ${pair.item.title}`} />
      )}

      <ActionBar
        pair={pair}
        prev={prev} next={next}
        complete={pair ? completion.has(pair.item.id) : false}
        pollLive={pair ? isPollLive(pair.item.id) : false}
        onPrev={() => prev && setActiveId(prev.item.id)}
        onNext={() => next && setActiveId(next.item.id)}
        onComplete={() => pair && toggleComplete(pair.item.id)}
        onOpenPoll={() => { if (pair) { openPoll(pair.item.id); setPresenterFor(pair.item.id); } }}
        onPresent={() => enterPresenter()}
        onReopenPoll={() => pair && reopenPoll(pair.item.id)}
      />

      <ChapterOutline
        open={outlineOpen} onClose={() => setOutlineOpen(false)}
        activeId={activeId} completion={completion}
        onPick={setActiveId}
      />

      <CmdK open={cmdkOpen} onClose={() => setCmdkOpen(false)} onPick={setActiveId} />

      <ActionsDrawer open={actionsOpen} onClose={() => setActionsOpen(false)} />

      {presenterFor && pair?.item.id === presenterFor && (
        <PollPresenter
          item={pair.item}
          complete={completion.has(pair.item.id)}
          onClose={() => setPresenterFor(null)}
          onMarkComplete={() => { toggleComplete(pair.item.id); setPresenterFor(null); }}
        />
      )}

      <Lightbox />
      <window.TranscribeDrawer tx={tx} variant="v2" />
      <window.TranscribeSummaryModal tx={tx} variant="v2" />
      {aiOpen && (
        <div className="v2-ai-overlay" onClick={() => setAiOpen(false)}>
          <div className="v2-ai-shell" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="AI report">
            <header className="v2-ai-head">
              <div className="v2-ai-head-text">
                <span className="v2-ai-head-eyebrow">✨ Workshop intelligence</span>
                <h2>AI report · Asset Management</h2>
              </div>
              <button className="v2-ai-close" type="button" aria-label="Close" onClick={() => setAiOpen(false)}>
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
              </button>
            </header>
            <div className="v2-ai-body">
              <window.AiReportTab />
            </div>
          </div>
        </div>
      )}
      {tweaks}
    </>
  );
}

ReactDOM.createRoot(document.getElementById("app-root")).render(<App />);
