/* ipma-viewer.jsx — IPMA Slideware Viewer + Book Reader overlays */

/* ─────────────────────────────────────── SLIDE DATA (20 slides) ── */
const SL = window.IPMA_SL; /* shared source of truth → js/ipma-slides.jsx */


/* ─────────────────────────────────────── BOOK DATA (15 pages) ── */
const BK = [
{ n: 1, type: "cover", title: "Project Management", sub: "Based on IPMA Individual Competence Baseline Version 4", pub: "Van Haren Publishing", isbn: "978-94-018-1092-0" },
{ n: 2, type: "colophon", lines: ["Title: Project Management — based on IPMA Individual Competence Baseline Version 4", "Author: Van Haren Publishing", "Edition: 1st edition · English", "ISBN: 978-94-018-1092-0", "Publisher: Van Haren Publishing, Amersfoort, the Netherlands", "© Van Haren Publishing. All rights reserved.", "No part of this publication may be reproduced without written permission from the publisher."] },
{ n: 3, type: "toc", title: "Contents", chapters: [{ n: "1", title: "Project Management and the ICB4", p: 9 }, { n: "2", title: "Project Orientation", p: 25 }, { n: "3", title: "Project Preparation", p: 41 }, { n: "4", title: "Project Definition", p: 67 }, { n: "5", title: "Project Delivery", p: 103 }, { n: "6", title: "People Competencies", p: 133 }, { n: "7", title: "Perspective Competencies", p: 175 }, { n: "A", title: "Sample Exam Questions", p: 213 }] },
{ n: 4, type: "chapter-start", ch: 1, title: "Project Management and the ICB4", intro: "This chapter introduces the concept of project management and explains the structure of the IPMA Individual Competence Baseline (ICB4), the global standard for individual competence in project, programme and portfolio management." },
{ n: 5, type: "body", heading: "1.1  The Importance of Project Management", paras: ["Managing projects is becoming increasingly important. In an environment characterised by rapid change, organisations increasingly choose to implement changes through projects rather than through operational processes. The demand for skilled project managers has never been greater.", "The IPMA defines a project as 'a unique, temporary, multi-disciplinary and organised endeavour to realise agreed deliverables within predefined requirements and constraints.' This definition captures several characteristics that distinguish projects from other work.", "Projects are unique — each one differs from all previous projects. Projects are temporary — they have a defined start and end, unlike operational work. Projects are multi-disciplinary — drawing on expertise from multiple domains. And projects are organised — they have defined structure, governance, and decision-making processes."] },
{ n: 6, type: "body", heading: "1.2  The ICB4 Framework", paras: ["The IPMA Individual Competence Baseline (ICB4) is the global standard for individual competence in project, programme and portfolio management. It was developed to provide a clear and comprehensive description of the competences required by project management professionals at all levels.", "The ICB4 organises competences into three domains: Perspective, People, and Practice. Together, these three domains form the Eye of Competence — IPMA's iconic symbol representing the complete view of project management competence.", "The Perspective domain encompasses five competence elements defining the contextual competences required to navigate projects across the broader organisational environment. The People domain contains ten elements defining personal and interpersonal competences. The Practice domain contains thirteen elements defining the technical aspects of managing projects."] },
{ n: 7, type: "body", heading: "1.3  IPMA Certification Levels", paras: ["IPMA offers four certification levels, designated D, C, B and A, reflecting increasing degrees of responsibility, complexity, and seniority in project management practice.", "Level D — Certified Project Management Associate: This level demonstrates fundamental knowledge of project management. The candidate can support a project manager on a limited-complexity project in all aspects of the ICB4 competence elements.", "Level C — Certified Project Manager: This level demonstrates that the individual can manage limited-complexity projects independently, applying the ICB4 competence elements in practice. Level B — Senior Project Manager: can manage complex projects. Level A — Projects Director: can manage a portfolio or programme of projects."] },
{ n: 8, type: "body", heading: "1.4  Competence and Learning", paras: ["Competence is more than knowledge alone. The ICB4 defines competence as the application of knowledge, skills, and abilities in a given context. To become a competent project manager, it is not sufficient to know the theory — one must be able to apply it in practice.", "The framework uses three mastery levels aligned with Bloom's taxonomy: Comprehension (c) — remembering and understanding concepts; Application (p) — being able to apply knowledge; Analysis (a) — being able to analyse complex situations.", "For the IPMA-D certification, the primary focus is on comprehension. For higher levels (C, B, A), deeper mastery is required: applying competence elements in project situations and making strategic decisions under complexity."] },
{ n: 9, type: "chapter-start", ch: 2, title: "Project Orientation", intro: "This chapter covers the competence to determine whether an initiative should be managed as a project and how to apply the fundamental principles of project management in practice." },
{ n: 10, type: "body", heading: "2.1  What is a Project?", paras: ["The ICB4 defines a project as 'a unique, temporary, multi-disciplinary and organised endeavour to realise agreed deliverables within predefined requirements and constraints.' Each element of this definition deserves examination.", "Unique means that every project is different — even if similar work has been done before. This uniqueness creates complexity and risk that must be managed carefully.", "Temporary means that every project has a defined beginning and end. This distinguishes projects from ongoing operational work and creates urgency that requires careful planning of resources, budgets and activities within a constrained timeframe."] },
{ n: 11, type: "body", heading: "2.2  The Work Forms Model", paras: ["Not all work is best organised as a project. The work forms model helps organisations choose the most appropriate management approach. The model distinguishes three main forms: improvisation, routine (process-based) work, and plan-based (project) work.", "Improvisation is appropriate for ad hoc, flexible work where the approach cannot be specified in advance. Routine work is appropriate for repetitive, well-understood activities where efficiency is the primary goal. Plan-based work is appropriate when the work is unique, complex, and requires coordination across multiple disciplines.", "Projects sit in the plan-based category. They provide a structured framework for managing scope, time, cost, quality, and stakeholder expectations in a unique and temporary context."] },
{ n: 12, type: "body", heading: "2.3  Why Initiate a Project?", paras: ["Projects are initiated to implement change. The formula E = Q × A, attributed to Quirke (1995), captures a fundamental truth: Effectiveness equals Quality multiplied by Acceptance.", "This formula has profound implications for project managers. A technically perfect solution (Q = 10) that no one accepts or uses (A = 0) has zero effectiveness. Conversely, a modest solution (Q = 5) that is widely embraced (A = 8) achieves significant effectiveness (E = 40).", "The lesson is clear: project managers must invest as much effort in gaining stakeholder acceptance as in producing technical quality. Stakeholder engagement and change management are central to project success."] },
{ n: 13, type: "body", heading: "2.4  The Project Lifecycle", paras: ["Every project passes through a series of phases from initiation to closure. The ICB4 describes a generic project lifecycle consisting of four main stages: project preparation, project definition, project execution, and project closure.", "During Project Preparation, the project is justified and its feasibility established. The project sponsor approves the investment and authorises the project. During Project Definition, the project manager develops the Project Management Plan covering scope, schedule, budget, quality, resources, risks, communication, and procurement.", "During Project Execution, the team delivers the work packages defined in the plan. Regular monitoring and control ensures that deviations are detected and corrected early. The stage closes with a successful handover of all deliverables."] },
{ n: 14, type: "body", heading: "2.5  Project Success Factors", paras: ["Research consistently identifies factors that distinguish successful projects from unsuccessful ones. The Standish Group's CHAOS Report found that in 2021, only 29% of IT projects were truly successful, 53% were challenged, and 18% were cancelled.", "The factors most strongly associated with project success include: active executive sponsorship; clear project objectives and scope; experienced project manager; regular stakeholder engagement; effective risk management; and realistic planning with adequate contingency.", "Notably, purely technical factors are rarely the primary cause of project failure. The data consistently shows that people, process, and governance issues account for most project failures."] },
{ n: 15, type: "chapter-start", ch: 3, title: "Project Preparation", intro: "The Project Preparation stage is where the project is conceived, justified, and initially organised. This chapter covers the five practice competence elements: Project Preparation Stage, Stakeholders, Project Organisation, Requirements & Objectives, and Risk & Opportunity." }];


/* ─────────────────────────────────── SLIDE CARD RENDERER ── */
const SlideCard = window.IPMASlideCard; /* shared renderer → js/ipma-slides.jsx */


/* ─────────────────────────────────── SLIDE VIEWER ── */
function IPMASlideViewer({ onClose, toast, onKahoot, onWordCloud }) {
  const SCALE = 140 / 900;
  const [idx, setIdx] = useState(0);
  const [trainerSlide] = useState(7); // simulated trainer position (slide 8, 0-indexed)
  const [notes, setNotes] = useState({});
  const [qText, setQText] = useState("");
  const [questions, setQuestions] = useState([]);
  const [panel, setPanel] = useState("notes"); // notes | questions
  const [follow, setFollow] = useState(null);
  const [followStats, setFollowStats] = useState({ yes: 18, less: 4, no: 2 });
  const [elapsed, setElapsed] = useState(0);
  const [gameAnswers, setGameAnswers] = useState({});
  const [gameRevealed, setGameRevealed] = useState({});
  const SLIDE_GAMES = [
    { slide: 4,  type: "kahoot",   q: "What does IPMA stand for?",                              opts: ["International Project Management Association", "Institute for Project Management Analysis", "International Program Management Authority", "Integrated Project Management Approach"], ans: 0 },
    { slide: 9,  type: "kahoot",   q: "Which element is NOT part of the IPMA Competence Eye?",  opts: ["People", "Practice", "Perspective", "Portfolio"], ans: 3 },
    { slide: 14, type: "wordcloud", q: "In one word: what makes a great project leader?" },
  ];
  const GOPTS_COLORS = ["#e74c3c", "#3498db", "#f99d25", "#27ae60"];
  const GOPTS_LABELS = ["A", "B", "C", "D"];

  useEffect(() => {
    const t = setInterval(() => setElapsed((e) => e + 1), 1000);
    return () => clearInterval(t);
  }, []);

  const fmt = (s) => `${String(Math.floor(s / 3600)).padStart(2, "0")}:${String(Math.floor(s % 3600 / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;
  const slide = SL[idx];
  const totalFollowers = followStats.yes + followStats.less + followStats.no;
  const activeGame = SLIDE_GAMES.find(g => g.slide === idx) || null;
  const nextGame   = SLIDE_GAMES.find(g => g.slide > idx)  || null;

  useEffect(() => {
    if (SLIDE_GAMES.some(g => g.slide === idx)) setPanel("notes");
  }, [idx]);

  function sendFollow(v) {
    if (follow) return;
    setFollow(v);
    setFollowStats((s) => ({ ...s, [v]: s[v] + 1 }));
    toast(v === "yes" ? "Great — marked as understood ✓" : "Feedback sent to trainer", "check");
  }

  function sendQ() {
    if (!qText.trim()) return;
    setQuestions((q) => [...q, { text: qText.trim(), time: fmt(elapsed) }]);
    setQText("");toast("Question sent to trainer", "sparkle");
  }

  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 200, background: "#0d1521", display: "flex", flexDirection: "column", fontFamily: "var(--body)" }}>
      {/* top bar */}
      <div style={{ height: 52, flex: "none", display: "flex", alignItems: "center", gap: 14, padding: "0 16px", background: "#0a1220", borderBottom: "1px solid #1e2e4a" }}>
        <button onClick={onClose} className="btn btn-ghost" style={{ fontSize: 13, padding: "7px 12px", background: "rgba(255,255,255,.08)", color: "#adc5e8" }}><Icon name="chevL" size={15} />Exit viewer</button>
        <div style={{ flex: 1, fontSize: 14, fontWeight: 600, color: "#adc5e8", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>Training IPMA D · {slide.head || slide.title || slide.chapter || "Slide " + slide.n}</div>
        <button
          onClick={() => setIdx(trainerSlide)}
          title="Jump to trainer's current slide"
          style={{ display: "flex", alignItems: "center", gap: 7, padding: "6px 12px", borderRadius: 8, border: "1px solid rgba(249,157,37,.35)", background: idx === trainerSlide ? "rgba(249,157,37,.18)" : "rgba(249,157,37,.08)", color: idx === trainerSlide ? "#f99d25" : "#c98020", fontFamily: "var(--body)", fontSize: 13, fontWeight: 700, cursor: "pointer", whiteSpace: "nowrap", transition: "background .15s" }}>
          <span style={{ width: 7, height: 7, borderRadius: "50%", background: "#f99d25", boxShadow: "0 0 0 3px rgba(249,157,37,.3)", animation: "pulse 2s infinite", display: "inline-block", flexShrink: 0 }}/>
          Trainer · Slide {trainerSlide + 1}
        </button>
        <div style={{ fontSize: 13, color: "#6b88b0", fontWeight: 600 }}>Slide {idx + 1} / {SL.length}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 6, background: "rgba(255,255,255,.07)", borderRadius: 8, padding: "5px 12px" }}>
          <Icon name="clock" size={14} style={{ color: "var(--vh-teal)" }} />
          <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, color: "var(--vh-teal)" }}>{fmt(elapsed)}</span>
        </div>
      </div>

      {/* main area */}
      <div style={{ flex: 1, display: "flex", minHeight: 0 }}>
        {/* left: previous slides rail */}
        <div style={{ width: 148, flex: "none", background: "#0a1220", borderRight: "1px solid #1e2e4a", overflowY: "auto", padding: 8, display: "flex", flexDirection: "column", gap: 6 }} className="scroll">
          <div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: ".1em", textTransform: "uppercase", color: "#4a6080", padding: "4px 4px 6px" }}>Slides</div>
          {SL.map((s, i) =>
          <button key={i} onClick={() => setIdx(i)}
          style={{ padding: 0, cursor: "pointer", border: `2px solid ${i === idx ? "var(--vh-orange)" : "transparent"}`, borderRadius: 6, overflow: "hidden", position: "relative", opacity: i > idx ? .45 : 1, background: "none" }}>
              <div style={{ width: 132, height: 75, overflow: "hidden", position: "relative" }}>
                <div style={{ position: "absolute", top: 0, left: 0, width: 900, height: 506, transformOrigin: "top left", transform: `scale(${132 / 900})` }}>
                  <SlideCard s={s} />
                </div>
              </div>
              <div style={{ position: "absolute", bottom: 3, right: 5, fontSize: 9.5, fontWeight: 700, color: "rgba(255,255,255,.7)", background: "rgba(0,0,0,.5)", borderRadius: 3, padding: "1px 4px" }}>{i + 1}</div>
            </button>
          )}
        </div>

        {/* center: current slide */}
        <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "20px 16px", overflow: "hidden" }}>
          {/* game badge on slides 15 & 16 */}
        {/* game badge: word cloud on slides 1-2, kahoot on slides 15-16 */}
        {(idx === 0 || idx === 1) &&
          <div style={{ position: "absolute", bottom: 10, right: 10, zIndex: 5 }}>
            <button onClick={onWordCloud}
            style={{ display: "flex", alignItems: "center", gap: 7, padding: "7px 14px", borderRadius: 999, background: "#2d0a6e", border: "2px solid rgba(255,255,255,.4)", color: "#fff", cursor: "pointer", fontFamily: "var(--display)", fontWeight: 800, fontSize: 13, boxShadow: "0 4px 16px rgba(0,0,0,.5)", animation: "gamePulse 2s infinite" }}>
              <span style={{ fontSize: 16 }}>☁️</span>Word cloud game!
            </button>
          </div>
          }
        {(idx === 14 || idx === 15) &&
          <div style={{ position: "absolute", bottom: 10, right: 10, zIndex: 5 }}>
            <button onClick={onKahoot}
            style={{ display: "flex", alignItems: "center", gap: 7, padding: "7px 14px", borderRadius: 999, background: "#46178f", border: "2px solid rgba(255,255,255,.4)", color: "#fff", cursor: "pointer", fontFamily: "var(--display)", fontWeight: 800, fontSize: 13, boxShadow: "0 4px 16px rgba(0,0,0,.5)", animation: "gamePulse 2s infinite" }}>
              <span style={{ fontSize: 16 }}>🎮</span>Game available!
            </button>
          </div>
          }
        <div style={{ width: "100%", aspectRatio: "16/9", maxWidth: "calc((100vh - 180px) * 16/9)", boxShadow: "0 20px 60px rgba(0,0,0,.6)", borderRadius: 8, overflow: "hidden" }}>
            <SlideCard s={slide} />
          </div>
        </div>

        {/* right: notes + questions panel */}
        <div style={{ width: 272, flex: "none", background: "#0d1929", borderLeft: "1px solid #1e2e4a", display: "flex", flexDirection: "column" }}>
          {/* panel tabs */}
          <div style={{ display: "flex", borderBottom: "1px solid #1e2e4a", flex: "none" }}>
            {[["notes", "Notes"], ["questions", "Questions"]].map(([id, lbl]) =>
            <button key={id} onClick={() => setPanel(id)}
            style={{ flex: 1, padding: "11px 0", fontSize: 13, fontWeight: 600, color: panel === id ? "#fff" : "#5a7aaa", background: panel === id ? "rgba(255,255,255,.06)" : "none", borderBottom: panel === id ? "2px solid var(--vh-orange)" : "2px solid transparent", transition: "all .15s" }}>
                {lbl}
              </button>
            )}
          </div>

          {panel === "notes" &&
          <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
            {/* Notes — top ¾ */}
            <div style={{ flex: 3, display: "flex", flexDirection: "column", padding: 12, gap: 8, minHeight: 0 }}>
              <div style={{ fontSize: 11.5, color: "#4a6080", fontWeight: 600 }}>Slide {idx + 1} notes</div>
              <textarea value={notes[idx] || ""}
                onChange={(e) => setNotes((n) => ({ ...n, [idx]: e.target.value }))}
                placeholder="Type your notes here…"
                style={{ flex: 1, resize: "none", background: "rgba(255,255,255,.05)", border: "1px solid #1e2e4a", borderRadius: 8, color: "#c8d8f0", fontSize: 13, padding: 10, outline: "none", fontFamily: "var(--body)", lineHeight: 1.6 }} />
              <button className="btn" style={{ fontSize: 12, background: "rgba(255,255,255,.08)", color: "#adc5e8" }}
                onClick={() => toast("Notes saved for slide " + (idx + 1), "check")}><Icon name="check" size={13} />Save note</button>
            </div>
            {/* Game widget — bottom ¼ */}
            <div style={{ flex: 1, borderTop: "1px solid #1e2e4a", display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden", background: activeGame ? "rgba(249,157,37,.05)" : "rgba(0,0,0,.18)" }}>
              {activeGame ? (
                <div style={{ flex: 1, display: "flex", flexDirection: "column", padding: "10px 12px", gap: 7, overflow: "auto" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                    <span style={{ width: 7, height: 7, borderRadius: "50%", background: "#f99d25", boxShadow: "0 0 0 3px rgba(249,157,37,.28)", animation: "pulse 2s infinite", display: "inline-block", flexShrink: 0 }}/>
                    <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: ".1em", textTransform: "uppercase", color: "#f99d25" }}>{activeGame.type === "kahoot" ? "Kahoot!" : "Word Cloud"} · Slide {idx + 1}</span>
                  </div>
                  <div style={{ fontSize: 12.5, fontWeight: 600, color: "#c8d8f0", lineHeight: 1.4 }}>{activeGame.q}</div>
                  {activeGame.type === "kahoot" && (
                    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 5 }}>
                      {activeGame.opts.map((opt, oi) => {
                        const chosen = gameAnswers[idx] === oi;
                        const revealed = gameRevealed[idx];
                        const correct = oi === activeGame.ans;
                        const base = GOPTS_COLORS[oi];
                        let bg = chosen ? base + "cc" : base + "1a";
                        if (revealed) bg = correct ? "#27ae6088" : chosen ? "#e74c3c44" : base + "0d";
                        return (
                          <button key={oi} disabled={gameAnswers[idx] !== undefined}
                            onClick={() => setGameAnswers(a => ({ ...a, [idx]: oi }))}
                            style={{ padding: "7px 8px", borderRadius: 7, border: `1.5px solid ${base}55`, background: bg, color: chosen || (revealed && correct) ? "#fff" : base, fontFamily: "var(--body)", fontSize: 11, fontWeight: 700, cursor: gameAnswers[idx] !== undefined ? "default" : "pointer", transition: "all .15s", textAlign: "left", lineHeight: 1.3 }}>
                            <span style={{ opacity: .7, marginRight: 4 }}>{GOPTS_LABELS[oi]}</span>{opt}
                          </button>
                        );
                      })}
                    </div>
                  )}
                  {activeGame.type === "wordcloud" && (
                    <div style={{ display: "flex", gap: 5 }}>
                      <input placeholder="Your answer…" style={{ flex: 1, background: "rgba(255,255,255,.07)", border: "1px solid #1e2e4a", borderRadius: 7, color: "#c8d8f0", fontSize: 12.5, padding: "7px 9px", outline: "none", fontFamily: "var(--body)" }}/>
                      <button className="btn" style={{ fontSize: 12, background: "var(--vh-teal)", color: "#fff", padding: "7px 11px" }} onClick={() => toast("Answer submitted!", "check")}><Icon name="arrowR" size={13}/></button>
                    </div>
                  )}
                  {activeGame.type === "kahoot" && gameAnswers[idx] !== undefined && !gameRevealed[idx] && (
                    <button className="btn" style={{ fontSize: 11.5, background: "rgba(255,255,255,.08)", color: "#adc5e8", padding: "6px 10px" }}
                      onClick={() => setGameRevealed(r => ({ ...r, [idx]: true }))}>Reveal answer</button>
                  )}
                  {gameRevealed[idx] && (
                    <div style={{ fontSize: 12, fontWeight: 700, color: gameAnswers[idx] === activeGame.ans ? "#4ade80" : "#f87171", textAlign: "center", padding: "4px 0" }}>
                      {gameAnswers[idx] === activeGame.ans ? "✓ Correct!" : "✗ Incorrect — " + activeGame.opts[activeGame.ans]}
                    </div>
                  )}
                </div>
              ) : (
                <div style={{ flex: 1, display: "flex", flexDirection: "column", padding: "10px 12px", gap: 6, justifyContent: "center" }}>
                  {nextGame ? (
                    <>
                      <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                        <Icon name="dice" size={13} style={{ color: "#4a6080" }}/>
                        <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: ".1em", textTransform: "uppercase", color: "#4a6080" }}>Next {nextGame.type === "kahoot" ? "Kahoot" : "Word Cloud"}</span>
                      </div>
                      <div style={{ fontSize: 12, color: "#6b88b0" }}>Slide {nextGame.slide + 1} · {nextGame.slide - idx} slide{nextGame.slide - idx !== 1 ? "s" : ""} away</div>
                      <div style={{ height: 4, borderRadius: 999, background: "#1e2e4a", overflow: "hidden" }}>
                        <div style={{ height: "100%", borderRadius: 999, background: "linear-gradient(90deg,var(--vh-blue-500),var(--vh-teal))", width: Math.min(100, Math.round((idx / nextGame.slide) * 100)) + "%" }}/>
                      </div>
                    </>
                  ) : (
                    <div style={{ fontSize: 12, color: "#4a6080", textAlign: "center" }}>No more games in this session.</div>
                  )}
                </div>
              )}
            </div>
          </div>
          }

          {panel === "questions" &&
          <div style={{ flex: 1, display: "flex", flexDirection: "column", padding: 12, gap: 8, minHeight: 0 }}>
              <div style={{ flex: 1, overflowY: "auto", display: "flex", flexDirection: "column", gap: 8 }} className="scroll">
                {questions.length === 0 && <div style={{ fontSize: 13, color: "#4a6080", textAlign: "center", marginTop: 24 }}>No questions yet.<br />Ask your trainer below.</div>}
                {questions.map((q, i) =>
              <div key={i} style={{ background: "rgba(255,255,255,.06)", border: "1px solid #1e2e4a", borderRadius: 8, padding: "8px 10px" }}>
                    <div style={{ fontSize: 13, color: "#c8d8f0", lineHeight: 1.5 }}>{q.text}</div>
                    <div style={{ fontSize: 10.5, color: "#4a6080", marginTop: 4 }}>Sent at {q.time}</div>
                  </div>
              )}
              </div>
              <div style={{ display: "flex", gap: 6 }}>
                <input value={qText} onChange={(e) => setQText(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && sendQ()}
              placeholder="Ask the trainer…"
              style={{ flex: 1, background: "rgba(255,255,255,.06)", border: "1px solid #1e2e4a", borderRadius: 8, color: "#c8d8f0", fontSize: 13, padding: "8px 10px", outline: "none", fontFamily: "var(--body)" }} />
                <button onClick={sendQ} className="btn" style={{ fontSize: 12, background: "var(--vh-blue-500)", color: "#fff", padding: "8px 12px" }}><Icon name="arrowR" size={14} /></button>
              </div>
            </div>
          }
        </div>
      </div>

      {/* bottom bar */}
      <div style={{ height: 62, flex: "none", display: "flex", alignItems: "center", gap: 14, padding: "0 18px", background: "#0a1220", borderTop: "1px solid #1e2e4a", flexWrap: "wrap" }}>
        {/* nav */}
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <button onClick={() => setIdx((i) => Math.max(0, i - 1))} className="btn" style={{ fontSize: 13, padding: "8px 14px", background: "rgba(255,255,255,.08)", color: "#adc5e8", opacity: idx === 0 ? .35 : 1 }} disabled={idx === 0}><Icon name="chevL" size={15} />Prev</button>
          <div style={{ height: 5, width: 120, background: "rgba(255,255,255,.1)", borderRadius: 9, overflow: "hidden" }}><div style={{ height: "100%", width: (idx + 1) / SL.length * 100 + "%", background: "var(--vh-orange)", borderRadius: 9, transition: "width .3s" }} /></div>
          <button onClick={() => setIdx((i) => Math.min(SL.length - 1, i + 1))} className="btn" style={{ fontSize: 13, padding: "8px 14px", background: "rgba(255,255,255,.08)", color: "#adc5e8", opacity: idx === SL.length - 1 ? .35 : 1 }} disabled={idx === SL.length - 1}>Next<Icon name="chevD" size={15} style={{ transform: "rotate(-90deg)" }} /></button>
        </div>

        <div style={{ flex: 1 }} />

        {/* do you follow */}
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{ fontSize: 12.5, color: "#6b88b0", fontWeight: 600, whiteSpace: "nowrap" }}>Do you follow?</span>
          {[["yes", "✓ Yes", "var(--vh-teal)"], ["less", "~ Less", "var(--vh-orange)"], ["no", "✗ No", "#c0392b"]].map(([v, lbl, col]) =>
          <button key={v} onClick={() => sendFollow(v)}
          style={{ fontSize: 12.5, padding: "6px 14px", borderRadius: 8, border: `1px solid ${follow === v ? col : "rgba(255,255,255,.15)"}`, background: follow === v ? col + "22" : "rgba(255,255,255,.05)", color: follow === v ? col : "#8aa0c0", fontWeight: follow === v ? 700 : 500, cursor: "pointer", transition: "all .15s" }}>
              {lbl}
            </button>
          )}
          {follow &&
          <div style={{ display: "flex", gap: 3, alignItems: "center", marginLeft: 6 }}>
              {[["yes", "var(--vh-teal)"], ["less", "var(--vh-orange)"], ["no", "#c0392b"]].map(([v, col]) =>
            <div key={v} style={{ width: Math.round(followStats[v] / totalFollowers * 60), height: 14, background: col, borderRadius: 3, minWidth: 2, transition: "width .4s", title: `${followStats[v]}` }} />
            )}
              <span style={{ fontSize: 11, color: "#4a6080", marginLeft: 4 }}>{totalFollowers} responses</span>
            </div>
          }
        </div>
      </div>
    </div>);

}

/* ─────────────────────────────────── BOOK READER ── */
function BookPage({ p }) {
  const paper = { width: "100%", height: "100%", background: "#faf8f5", padding: "7% 9%", boxSizing: "border-box", fontFamily: "Georgia,'Times New Roman',serif", color: "#2c2c2c", overflowY: "auto", position: "relative" };

  if (p.type === "cover") return (
    <div style={{ ...paper, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", textAlign: "center", background: "#1d3d7c" }}>
      <div className="hexfield" style={{ opacity: .12 }} />
      <div style={{ position: "relative" }}>
        <div style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: 36, color: "#fff", lineHeight: 1.1, marginBottom: 12 }}>{p.title}</div>
        <div style={{ fontSize: 16, color: "rgba(255,255,255,.7)", marginBottom: 24, lineHeight: 1.5 }}>{p.sub}</div>
        <div style={{ width: 50, height: 2, background: "var(--vh-orange)", margin: "0 auto 20px" }} />
        <div style={{ fontSize: 13, color: "rgba(255,255,255,.5)", letterSpacing: ".12em", textTransform: "uppercase" }}>{p.pub}</div>
        <div style={{ fontSize: 12, color: "rgba(255,255,255,.35)", marginTop: 6 }}>{p.isbn}</div>
      </div>
    </div>);


  if (p.type === "chapter-start") return (
    <div style={{ ...paper, display: "flex", flexDirection: "column" }}>
      <div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "flex-end", paddingBottom: "10%" }}>
        <div style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: 60, color: "#e8e4de", lineHeight: 1, marginBottom: 16 }}>0{p.ch}</div>
        <div style={{ width: 50, height: 3, background: "#c0392b", marginBottom: 20 }} />
        <div style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: 30, color: "#1d3d7c", marginBottom: 16, lineHeight: 1.2 }}>{p.title}</div>
        <div style={{ fontSize: 16, color: "#555", lineHeight: 1.7, maxWidth: 520 }}>{p.intro}</div>
      </div>
    </div>);


  if (p.type === "colophon") return (
    <div style={{ ...paper }}>
      <div style={{ marginTop: "20%", display: "flex", flexDirection: "column", gap: 12 }}>
        {p.lines.map((l, i) => <div key={i} style={{ fontSize: 13.5, color: "#555", lineHeight: 1.6, borderBottom: i < p.lines.length - 1 ? "1px solid #e8e4de" : "none", paddingBottom: 8 }}>{l}</div>)}
      </div>
    </div>);


  if (p.type === "toc") return (
    <div style={{ ...paper }}>
      <div style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: 28, color: "#1d3d7c", marginBottom: 4 }}>{p.title}</div>
      <div style={{ width: 40, height: 3, background: "#c0392b", marginBottom: 24 }} />
      <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
        {p.chapters.map((ch, i) =>
        <div key={i} style={{ display: "flex", alignItems: "baseline", gap: 8, padding: "10px 0", borderBottom: "1px solid #ece8e2" }}>
            <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, color: "#c0392b", width: 28, flex: "none" }}>{ch.n}</span>
            <span style={{ flex: 1, fontSize: 16, color: "#1d3d7c" }}>{ch.title}</span>
            <span style={{ fontSize: 13, color: "#999" }}>{ch.p}</span>
          </div>
        )}
      </div>
    </div>);


  // body
  return (
    <div style={{ ...paper }}>
      {p.heading && <div style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 18, color: "#1d3d7c", marginBottom: 18, paddingBottom: 10, borderBottom: "1px solid #e4dfd8" }}>{p.heading}</div>}
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        {p.paras.map((para, i) => <p key={i} style={{ fontSize: 15, lineHeight: 1.85, color: "#2c2c2c", margin: 0, textAlign: "justify" }}>{para}</p>)}
      </div>
    </div>);

}

function IPMABookReader({ onClose }) {
  const [page, setPage] = useState(0);
  const p = BK[page];

  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 200, background: "#1a1a1a", display: "flex", flexDirection: "column", fontFamily: "var(--body)" }}>
      {/* top bar */}
      <div style={{ height: 52, flex: "none", display: "flex", alignItems: "center", gap: 14, padding: "0 20px", background: "#111", borderBottom: "1px solid #333" }}>
        <button onClick={onClose} className="btn btn-ghost" style={{ fontSize: 13, padding: "7px 12px", background: "rgba(255,255,255,.08)", color: "#aaa" }}><Icon name="chevL" size={15} />Close reader</button>
        <div style={{ flex: 1, fontSize: 14, fontWeight: 600, color: "#aaa", textAlign: "center" }}>Project Management by ICB4 — Sample</div>
        <div style={{ fontSize: 13, color: "#666", fontWeight: 600 }}>Page {page + 1} / {BK.length}</div>
      </div>

      {/* reading progress */}
      <div style={{ height: 3, background: "#222", flex: "none" }}>
        <div style={{ height: "100%", width: (page + 1) / BK.length * 100 + "%", background: "var(--vh-orange)", transition: "width .3s" }} />
      </div>

      {/* page area */}
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "24px 16px", overflow: "hidden", gap: 0 }}>
        {/* prev button */}
        <button onClick={() => setPage((i) => Math.max(0, i - 1))} disabled={page === 0}
        style={{ width: 44, height: 44, borderRadius: "50%", background: "rgba(255,255,255,.06)", border: "1px solid #333", color: "#aaa", cursor: page === 0 ? "default" : "pointer", display: "grid", placeItems: "center", flex: "none", opacity: page === 0 ? .3 : 1, marginRight: 16 }}>
          <Icon name="chevL" size={18} />
        </button>

        {/* page content */}
        <div style={{ height: "100%", aspectRatio: "0.707", maxWidth: 560, maxHeight: "calc(100vh - 120px)", boxShadow: "0 12px 48px rgba(0,0,0,.6)", borderRadius: 4, overflow: "hidden" }}>
          <BookPage p={p} />
        </div>

        {/* next button */}
        <button onClick={() => setPage((i) => Math.min(BK.length - 1, i + 1))} disabled={page === BK.length - 1}
        style={{ width: 44, height: 44, borderRadius: "50%", background: "rgba(255,255,255,.06)", border: "1px solid #333", color: "#aaa", cursor: page === BK.length - 1 ? "default" : "pointer", display: "grid", placeItems: "center", flex: "none", opacity: page === BK.length - 1 ? .3 : 1, marginLeft: 16 }}>
          <Icon name="chevD" size={18} style={{ transform: "rotate(-90deg)" }} />
        </button>
      </div>

      {/* bottom: page thumbnails strip */}
      <div style={{ height: 56, flex: "none", background: "#111", borderTop: "1px solid #333", display: "flex", alignItems: "center", gap: 6, padding: "0 16px", overflowX: "auto" }} className="scroll">
        {BK.map((pg, i) =>
        <button key={i} onClick={() => setPage(i)}
        style={{ flex: "none", width: 34, height: 44, borderRadius: 3, border: `2px solid ${i === page ? "var(--vh-orange)" : "transparent"}`, background: i === page ? "#2a2a2a" : "#1e1e1e", color: i === page ? "var(--vh-orange)" : "#555", fontSize: 11, fontWeight: 700, cursor: "pointer", display: "grid", placeItems: "center" }}>
            {i + 1}
          </button>
        )}
      </div>
    </div>);

}

/* ─────────────────────────────── KAHOOT-STYLE GAME ── */
const KAHOOT_QS = [
{ slide: 15, q: "A project is successful to the extent to which it satisfies…",
  opts: ["The project manager", "The relevant stakeholders", "The project sponsor", "The budget constraints"],
  ans: 1, points: 1000, explain: "Slide 15: 'A project is successful to the extent to which it satisfies the relevant stakeholders.'" },
{ slide: 15, q: "Which statement about project success is TRUE?",
  opts: ["PM success = project success", "Meeting specs is always enough", "PM success ≠ project success", "On-time delivery guarantees success"],
  ans: 2, points: 1000, explain: "Slide 15 note: 'Project management success is not the same as project success.' A project can be well-managed yet still fail to deliver value." },
{ slide: 16, q: "Which is a key condition for USER satisfaction? (Slide 16)",
  opts: ["The project manager is experienced", "The budget was saved", "The purpose of the project is desired", "The project finished early"],
  ans: 2, points: 1000, explain: "Slide 16: 'The purpose of the project is desired' — users must want the outcome, not just receive it." },
{ slide: 16, q: "Users feel satisfied when the urgency is felt AND constraints are…",
  opts: ["Flexible", "Ignored", "Minimal", "Clear"],
  ans: 3, points: 1000, explain: "Slide 16: 'The urgency is felt, and constraints are clear' — clarity on scope and timeline drives user confidence." }];


const KH_SHAPES = ["▲", "◆", "●", "■"];
const KH_COLS = ["#e21b3c", "#1368ce", "#d89e00", "#26890c"];
const KH_BOTS = ["Jonas B.", "Aisha K.", "Priya M.", "Lars V.", "Sophie W.", "Tomás R.", "Chen L.", "Fatima A."];


const WC_JOBS = [
{ title: "Project Manager", size: 38, count: 4 },
{ title: "Business Analyst", size: 28, count: 3 },
{ title: "Programme Manager", size: 26, count: 2 },
{ title: "IT Manager", size: 24, count: 2 },
{ title: "Scrum Master", size: 22, count: 2 },
{ title: "Product Owner", size: 22, count: 2 },
{ title: "Team Lead", size: 20, count: 1 },
{ title: "Change Manager", size: 20, count: 1 },
{ title: "Consultant", size: 20, count: 1 },
{ title: "Portfolio Manager", size: 18, count: 1 },
{ title: "Service Manager", size: 18, count: 1 },
{ title: "Operations Manager", size: 18, count: 1 },
{ title: "Delivery Manager", size: 16, count: 1 },
{ title: "Department Manager", size: 16, count: 1 },
{ title: "PMO Coordinator", size: 16, count: 1 }];


const WC_COLORS = ["#e8a020", "#3bc1ce", "#1368ce", "#e21b3c", "#26890c", "#a855f7", "#f472b6", "#34d399", "#60a5fa", "#fb923c"];

function IPMAKahootGame({ onClose }) {
  const QTIME = 20;
  const [phase, setPhase] = useState("intro");
  const [myJob, setMyJob] = useState(null);
  const [jobVotes, setJobVotes] = useState(Object.fromEntries(WC_JOBS.map((j) => [j.title, j.count])));
  const [qi, setQi] = useState(0);
  const [selected, setSelected] = useState(null);
  const [timer, setTimer] = useState(QTIME);
  const [scores, setScores] = useState({ You: 0, ...Object.fromEntries(KH_BOTS.map((b) => [b, 0])) });
  const [botAnswers, setBotAnswers] = useState({});
  const [joinCount, setJoinCount] = useState(1);
  const [previewSec, setPreviewSec] = useState(3);

  // lobby: fake join animation
  useEffect(() => {if (phase !== "lobby" || joinCount >= KH_BOTS.length + 1) return;const t = setTimeout(() => setJoinCount((c) => c + 1), 600);return () => clearTimeout(t);}, [phase, joinCount]);

  // slide preview countdown
  useEffect(() => {if (phase !== "preview") return;if (previewSec <= 0) {setPhase("question");setTimer(QTIME);return;}const t = setTimeout(() => setPreviewSec((s) => s - 1), 1000);return () => clearTimeout(t);}, [phase, previewSec]);

  // question timer
  useEffect(() => {if (phase !== "question") return;if (timer <= 0) {doReveal(null);return;}const t = setTimeout(() => setTimer((s) => s - 1), 1000);return () => clearTimeout(t);}, [phase, timer]);

  // bots answer
  useEffect(() => {
    if (phase !== "question") return;
    const q = KAHOOT_QS[qi];
    const ts = KH_BOTS.map((bot, i) => {
      const delay = 1500 + Math.random() * 10000;
      return setTimeout(() => {
        const correct = Math.random() < 0.65;
        const choice = correct ? q.ans : (q.ans + 1 + Math.floor(Math.random() * 3)) % 4;
        setBotAnswers((b) => ({ ...b, [bot]: { choice, ms: delay } }));
      }, delay);
    });
    return () => ts.forEach(clearTimeout);
  }, [phase, qi]);

  function doReveal(choice) {
    const q = KAHOOT_QS[qi];
    const isCorrect = choice === q.ans;
    const timeBonus = Math.round(timer / QTIME * q.points);
    const earned = isCorrect ? Math.max(100, timeBonus) : 0;
    setSelected(choice);
    setScores((s) => {
      const next = { ...s, You: s.You + earned };
      KH_BOTS.forEach((bot) => {
        const ba = botAnswers[bot];
        if (ba && ba.choice === q.ans) {
          const bb = Math.round((QTIME - ba.ms / 1000) / QTIME * q.points);
          next[bot] = s[bot] + Math.max(100, bb);
        }
      });
      return next;
    });
    setPhase("reveal");
  }

  function goNext() {
    setBotAnswers({});
    if (qi + 1 >= KAHOOT_QS.length) {setPhase("podium");return;}
    setQi((q) => q + 1);setSelected(null);setPreviewSec(3);setPhase("preview");
  }

  const lb = Object.entries(scores).sort((a, b) => b[1] - a[1]).slice(0, 6);
  const q = KAHOOT_QS[qi];
  const timerPct = timer / QTIME * 100;
  const answeredCount = Object.keys(botAnswers).length + (selected != null ? 1 : 0);

  function ModalWrap({ children }) {
    return (
      <div style={{ position: "fixed", inset: 0, zIndex: 300, background: "rgba(0,0,0,.6)", display: "flex", alignItems: "center", justifyContent: "center" }}>
        <div style={{ position: "relative", width: "80%", maxWidth: 900, height: "82vh", borderRadius: 18, overflow: "hidden", display: "flex", flexDirection: "column", boxShadow: "0 28px 80px rgba(0,0,0,.75)" }}>
          <button onClick={onClose} style={{ position: "absolute", top: 12, right: 14, zIndex: 20, width: 34, height: 34, borderRadius: "50%", background: "rgba(0,0,0,.4)", border: "2px solid rgba(255,255,255,.3)", color: "#fff", fontSize: 20, cursor: "pointer", display: "grid", placeItems: "center", lineHeight: 1, fontFamily: "sans-serif" }}>×</button>
          {children}
        </div>
      </div>);

  }

  /* INTRO — word cloud */
  if (phase === "intro") return <ModalWrap>
    <div style={{ width: "100%", height: "100%", background: "linear-gradient(160deg,#2d0a6e,#46178f)", display: "flex", flexDirection: "column", fontFamily: "var(--display)", overflowY: "auto" }}>
      {/* header */}
      <div style={{ padding: "22px 28px 0", textAlign: "center" }}>
        <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".18em", textTransform: "uppercase", color: "rgba(255,255,255,.5)", marginBottom: 8 }}>Van Haren Academy · IPMA-D · Warm-up</div>
        <div style={{ fontWeight: 900, fontSize: 32, color: "#fff", lineHeight: 1.1, marginBottom: 6 }}>What is your current role?</div>
        <div style={{ fontSize: 15, color: "rgba(255,255,255,.65)", marginBottom: 20 }}>Click your job title to add it to the word cloud</div>
      </div>

      {/* word cloud */}
      <div style={{ flex: 1, padding: "10px 32px", display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "center", gap: 10 }}>
        {WC_JOBS.map((job, i) => {
          const votes = jobVotes[job.title] || 0;
          const isMe = myJob === job.title;
          const scale = 1 + (votes - job.count) * 0.08;
          return (
            <button key={job.title}
            onClick={() => {
              if (myJob === job.title) {
                setMyJob(null);
                setJobVotes((v) => ({ ...v, [job.title]: Math.max(job.count, v[job.title] - 1) }));
              } else {
                if (myJob) setJobVotes((v) => ({ ...v, [myJob]: Math.max(0, v[myJob] - 1) }));
                setMyJob(job.title);
                setJobVotes((v) => ({ ...v, [job.title]: (v[job.title] || 0) + 1 }));
              }
            }}
            style={{
              fontSize: job.size, fontWeight: 900, lineHeight: 1.2,
              color: isMe ? "#231f20" : WC_COLORS[i % WC_COLORS.length],
              background: isMe ? WC_COLORS[i % WC_COLORS.length] : "transparent",
              border: "none", cursor: "pointer", borderRadius: 8, padding: "2px 6px",
              transform: "scale(" + scale + ")", transition: "all .25s",
              textShadow: isMe ? "none" : "0 2px 12px rgba(0,0,0,.4)",
              outline: isMe ? "3px solid #fff" : "none"
            }}>
              {job.title}
            </button>);

        })}
      </div>

      {/* my pick + continue */}
      <div style={{ padding: "12px 28px 22px", display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
        <div style={{ flex: 1, fontSize: 14, color: "rgba(255,255,255,.65)" }}>
          {myJob ? <span>Your role: <strong style={{ color: "#fff" }}>{myJob}</strong></span> : "Select your role above to continue"}
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button onClick={() => setPhase("lobby")} style={{ padding: "11px 28px", borderRadius: 10, background: "rgba(255,255,255,.12)", color: "#fff", fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, border: "none", cursor: "pointer" }}>Skip</button>
          <button onClick={() => setPhase("lobby")} disabled={!myJob}
          style={{ padding: "11px 28px", borderRadius: 10, background: myJob ? "#fff" : "rgba(255,255,255,.2)", color: myJob ? "#46178f" : "rgba(255,255,255,.4)", fontFamily: "var(--display)", fontWeight: 900, fontSize: 15, border: "none", cursor: myJob ? "pointer" : "default", transition: "all .2s" }}>
            Continue →
          </button>
        </div>
      </div>
    </div>
  </ModalWrap>;

  /* LOBBY */
  if (phase === "lobby") return <ModalWrap>
    <div style={{ width: "100%", height: "100%", background: "#46178f", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: "var(--display)", overflowY: "auto" }}>
      <div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none" }}>
        {[...Array(10)].map((_, i) => <div key={i} style={{ position: "absolute", width: 80 + i * 40, height: 80 + i * 40, borderRadius: "50%", border: "2px solid rgba(255,255,255,.06)", top: "50%", left: "50%", transform: "translate(-50%,-50%)" }} />)}
      </div>
      <div style={{ position: "relative", textAlign: "center", padding: "0 24px" }}>
        <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".18em", textTransform: "uppercase", color: "rgba(255,255,255,.55)", marginBottom: 12 }}>Van Haren Academy · IPMA-D</div>
        <div style={{ fontWeight: 900, fontSize: 44, color: "#fff", lineHeight: 1.1, marginBottom: 8 }}>Project Success</div>
        <div style={{ fontSize: 17, color: "rgba(255,255,255,.7)", marginBottom: 32 }}>Slides 15 &amp; 16 · {KAHOOT_QS.length} questions</div>
        <div style={{ display: "flex", gap: 8, justifyContent: "center", flexWrap: "wrap", marginBottom: 28, maxWidth: 420 }}>
          {KH_BOTS.slice(0, joinCount - 1).map((b) =>
          <div key={b} style={{ padding: "5px 13px", borderRadius: 999, background: "rgba(255,255,255,.12)", fontSize: 13, color: "#fff", fontFamily: "var(--body)" }}>{b}</div>
          )}
          <div style={{ padding: "5px 13px", borderRadius: 999, background: "var(--vh-orange)", fontSize: 13, color: "#231f20", fontWeight: 700, fontFamily: "var(--body)" }}>You</div>
        </div>
        <div style={{ fontSize: 14, color: "rgba(255,255,255,.55)", marginBottom: 28 }}>{joinCount} player{joinCount !== 1 ? "s" : ""} joined</div>
        <div style={{ display: "flex", gap: 12, justifyContent: "center" }}>
          <button onClick={() => {setPhase("preview");setPreviewSec(3);}} style={{ padding: "15px 38px", borderRadius: 12, background: "#fff", color: "#46178f", fontFamily: "var(--display)", fontWeight: 900, fontSize: 18, border: "none", cursor: "pointer", boxShadow: "0 4px 20px rgba(0,0,0,.3)" }}>Start game!</button>
          <button onClick={onClose} style={{ padding: "15px 22px", borderRadius: 12, background: "rgba(255,255,255,.12)", color: "#fff", fontFamily: "var(--display)", fontWeight: 700, fontSize: 16, border: "none", cursor: "pointer" }}>Exit</button>
        </div>
      </div>
    </div>
  </ModalWrap>;

  /* SLIDE PREVIEW */
  if (phase === "preview") return <ModalWrap>
    <div style={{ width: "100%", height: "100%", background: "#1a1a2e", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: "var(--display)" }}>
      <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".14em", textTransform: "uppercase", color: "rgba(255,255,255,.5)", marginBottom: 14 }}>Question {qi + 1} of {KAHOOT_QS.length} · Slide {q.slide}</div>
      <div style={{ width: "min(680px,88vw)", aspectRatio: "16/9", borderRadius: 12, overflow: "hidden", boxShadow: "0 16px 60px rgba(0,0,0,.7)", marginBottom: 24 }}>
        <SlideCard s={SL[q.slide - 1]} />
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
        <div style={{ width: 54, height: 54, borderRadius: "50%", background: "var(--vh-orange)", display: "grid", placeItems: "center", fontWeight: 900, fontSize: 26, color: "#231f20" }}>{previewSec}</div>
        <div style={{ fontSize: 15, color: "rgba(255,255,255,.65)" }}>Get ready…</div>
      </div>
    </div>
  </ModalWrap>;

  /* QUESTION */
  if (phase === "question") return <ModalWrap>
    <div style={{ width: "100%", height: "100%", background: "#46178f", display: "flex", flexDirection: "column", fontFamily: "var(--display)" }}>
      <div style={{ padding: "12px 20px", display: "flex", alignItems: "center", gap: 14 }}>
        <div style={{ flex: 1, fontSize: 12, color: "rgba(255,255,255,.55)", fontWeight: 700 }}>Q{qi + 1}/{KAHOOT_QS.length}</div>
        <div style={{ position: "relative", width: 52, height: 52, flex: "none" }}>
          <svg width="52" height="52" style={{ position: "absolute", top: 0, left: 0, transform: "rotate(-90deg)" }}>
            <circle cx="26" cy="26" r="22" fill="none" stroke="rgba(255,255,255,.2)" strokeWidth="4" />
            <circle cx="26" cy="26" r="22" fill="none" stroke={timer > 8 ? "#fff" : "#e21b3c"} strokeWidth="4"
            strokeDasharray={String(2 * Math.PI * 22)} strokeDashoffset={String(2 * Math.PI * 22 * (1 - timerPct / 100))}
            style={{ transition: "stroke-dashoffset 1s linear,stroke .3s" }} />
          </svg>
          <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", fontWeight: 900, fontSize: 17, color: timer > 8 ? "#fff" : "#e21b3c" }}>{timer}</div>
        </div>
        <div style={{ fontSize: 12, color: "rgba(255,255,255,.65)", fontWeight: 700 }}>{answeredCount}/{joinCount} answered</div>
      </div>
      <div style={{ flex: "none", padding: "8px 28px 18px", textAlign: "center" }}>
        <div style={{ background: "rgba(255,255,255,.1)", borderRadius: 14, padding: "18px 24px", display: "inline-block", maxWidth: 680, width: "100%", boxSizing: "border-box" }}>
          <div style={{ fontWeight: 900, fontSize: 22, color: "#fff", lineHeight: 1.35 }}>{q.q}</div>
        </div>
      </div>
      <div style={{ flex: 1, display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, padding: "0 18px 18px" }}>
        {q.opts.map((opt, oi) =>
        <button key={oi} onClick={() => doReveal(oi)}
        style={{ borderRadius: 12, background: KH_COLS[oi], border: "none", color: "#fff", cursor: "pointer", display: "flex", alignItems: "center", gap: 12, padding: "16px 20px", textAlign: "left", boxShadow: "0 4px 12px rgba(0,0,0,.3)" }}>
            <span style={{ width: 34, height: 34, borderRadius: 8, background: "rgba(0,0,0,.2)", display: "grid", placeItems: "center", fontSize: 17, flex: "none" }}>{KH_SHAPES[oi]}</span>
            <span style={{ fontWeight: 700, fontSize: 16, lineHeight: 1.3 }}>{opt}</span>
          </button>
        )}
      </div>
    </div>
  </ModalWrap>;

  /* REVEAL */
  if (phase === "reveal") {
    const isCorrect = selected === q.ans;
    return <ModalWrap>
      <div style={{ width: "100%", height: "100%", background: "#46178f", display: "flex", flexDirection: "column", alignItems: "center", fontFamily: "var(--display)", overflowY: "auto" }}>
        <div style={{ width: "100%", padding: "24px 24px 20px", textAlign: "center", background: isCorrect ? "#26890c" : "#e21b3c", boxShadow: "0 4px 24px rgba(0,0,0,.3)" }}>
          <div style={{ fontSize: 48, marginBottom: 6 }}>{isCorrect ? "🎉" : "😅"}</div>
          <div style={{ fontWeight: 900, fontSize: 28, color: "#fff" }}>{isCorrect ? "Correct!" : selected === null ? "Time's up!" : "Wrong!"}</div>
        </div>
        <div style={{ padding: "14px 20px", width: "100%", boxSizing: "border-box", maxWidth: 560 }}>
          <div style={{ borderRadius: 12, background: KH_COLS[q.ans], padding: "12px 18px", display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }}>
            <span style={{ fontSize: 18 }}>{KH_SHAPES[q.ans]}</span>
            <span style={{ fontWeight: 700, fontSize: 15, color: "#fff", flex: 1 }}>{q.opts[q.ans]}</span>
            <span style={{ fontSize: 20, color: "#fff" }}>✓</span>
          </div>
          <div style={{ fontSize: 13, color: "rgba(255,255,255,.8)", lineHeight: 1.6, background: "rgba(255,255,255,.08)", borderRadius: 10, padding: "10px 14px", marginBottom: 12 }}>{q.explain}</div>
          {isCorrect && <div style={{ textAlign: "center", fontSize: 16, fontWeight: 700, color: "var(--vh-orange)", marginBottom: 10 }}>+{Math.max(100, Math.round(timer / QTIME * q.points))} pts · Total: {scores.You.toLocaleString()}</div>}
        </div>
        <div style={{ width: "100%", maxWidth: 400, padding: "0 20px", flex: 1, overflowY: "auto" }}>
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".1em", textTransform: "uppercase", color: "rgba(255,255,255,.45)", marginBottom: 8 }}>Standings</div>
          {lb.map(([name, sc], i) =>
          <div key={name} style={{ display: "flex", alignItems: "center", gap: 10, padding: "7px 0", borderBottom: "1px solid rgba(255,255,255,.09)" }}>
              <span style={{ width: 22, fontWeight: 900, fontSize: 15, color: i === 0 ? "#f9c74f" : i === 1 ? "#c0c0c0" : i === 2 ? "#cd7f32" : "rgba(255,255,255,.4)" }}>{i + 1}</span>
              <span style={{ flex: 1, fontSize: 13, fontWeight: name === "You" ? 700 : 400, color: name === "You" ? "var(--vh-orange)" : "#fff" }}>{name}{name === "You" ? " · you" : ""}</span>
              <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, color: "#fff" }}>{sc.toLocaleString()}</span>
            </div>
          )}
        </div>
        <div style={{ padding: "14px 20px", width: "100%", boxSizing: "border-box", maxWidth: 400 }}>
          <button onClick={goNext} style={{ width: "100%", padding: "14px", borderRadius: 12, background: "#fff", color: "#46178f", fontFamily: "var(--display)", fontWeight: 900, fontSize: 17, border: "none", cursor: "pointer" }}>
            {qi + 1 < KAHOOT_QS.length ? "Next question →" : "See final results →"}
          </button>
        </div>
      </div>
    </ModalWrap>;
  }

  /* PODIUM */
  const top3 = lb.slice(0, 3);
  const podH = [180, 140, 110];
  const podC = ["#f9c74f", "#c0c0c0", "#cd7f32"];
  return <ModalWrap>
    <div style={{ width: "100%", height: "100%", background: "linear-gradient(160deg,#46178f,#1a0a3e)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: "var(--display)", overflowY: "auto" }}>
      <div style={{ fontSize: 12, letterSpacing: ".16em", textTransform: "uppercase", color: "rgba(255,255,255,.45)", marginBottom: 6 }}>Final Results</div>
      <div style={{ fontWeight: 900, fontSize: 34, color: "#fff", marginBottom: 28 }}>Leaderboard</div>
      <div style={{ display: "flex", alignItems: "flex-end", gap: 12, marginBottom: 28 }}>
        {[1, 0, 2].map((pos) => {
          const [name, sc] = top3[pos] || ["—", 0];
          return (
            <div key={pos} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }}>
              <div style={{ fontSize: pos === 0 ? 32 : 22 }}>{pos === 0 ? "🥇" : pos === 1 ? "🥈" : "🥉"}</div>
              <div className="avatar" style={{ width: 40, height: 40, borderRadius: 10, fontSize: 13, background: podC[pos], color: "#231f20", fontWeight: 900 }}>{name.slice(0, 2)}</div>
              <div style={{ fontSize: 12, fontWeight: 700, color: "#fff", maxWidth: 72, textAlign: "center", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{name}</div>
              <div style={{ fontWeight: 700, fontSize: 13, color: podC[pos] }}>{sc.toLocaleString()}</div>
              <div style={{ width: 72, borderRadius: "6px 6px 0 0", background: podC[pos], height: podH[pos], display: "grid", placeItems: "center", fontWeight: 900, fontSize: 20, color: "#231f20" }}>{pos === 0 ? 1 : pos === 1 ? 2 : 3}</div>
            </div>);

        })}
      </div>
      <div style={{ width: "100%", maxWidth: 340, marginBottom: 20 }}>
        {lb.slice(3).map(([name, sc], i) =>
        <div key={name} style={{ display: "flex", gap: 10, padding: "7px 14px", background: "rgba(255,255,255,.07)", borderRadius: 7, marginBottom: 5, alignItems: "center" }}>
            <span style={{ width: 22, fontWeight: 700, fontSize: 13, color: "rgba(255,255,255,.45)" }}>{i + 4}</span>
            <span style={{ flex: 1, fontSize: 13, color: name === "You" ? "var(--vh-orange)" : "#fff", fontWeight: name === "You" ? 700 : 400 }}>{name}{name === "You" ? " · you" : ""}</span>
            <span style={{ fontWeight: 700, color: "#fff", fontSize: 13 }}>{sc.toLocaleString()}</span>
          </div>
        )}
      </div>
      <button onClick={onClose} style={{ padding: "13px 34px", borderRadius: 12, background: "#fff", color: "#46178f", fontFamily: "var(--display)", fontWeight: 900, fontSize: 15, border: "none", cursor: "pointer" }}>
        Done
      </button>
    </div>
  </ModalWrap>;
}

/* inject gamePulse animation */
if (typeof document !== 'undefined' && !document.getElementById('kahoot-pulse-style')) {
  const s = document.createElement('style');
  s.id = 'kahoot-pulse-style';
  s.textContent = '@keyframes gamePulse { 0%,100%{box-shadow:0 4px 16px rgba(70,23,143,.6),0 0 0 0 rgba(70,23,143,.5)} 50%{box-shadow:0 4px 24px rgba(70,23,143,.9),0 0 0 8px rgba(70,23,143,0)} }';
  document.head.appendChild(s);
}


/* ─────────────────────────── WORD CLOUD GAME ── */
const WCG_JOBS = [
{ title: "Project Manager", size: 42, base: 5 }, { title: "Business Analyst", size: 30, base: 3 },
{ title: "Programme Manager", size: 28, base: 2 }, { title: "IT Manager", size: 26, base: 2 },
{ title: "Scrum Master", size: 24, base: 3 }, { title: "Product Owner", size: 22, base: 2 },
{ title: "Team Lead", size: 22, base: 2 }, { title: "Change Manager", size: 20, base: 1 },
{ title: "Consultant", size: 20, base: 2 }, { title: "Portfolio Manager", size: 18, base: 1 },
{ title: "Service Manager", size: 18, base: 1 }, { title: "Operations Manager", size: 17, base: 1 },
{ title: "Delivery Manager", size: 17, base: 1 }, { title: "PMO Coordinator", size: 16, base: 1 },
{ title: "Department Manager", size: 16, base: 1 }];

const WCG_CHALLENGES = [
"Stakeholder management", "Scope creep", "Time pressure", "Budget constraints",
"Team motivation", "Risk management", "Communication", "Change resistance",
"Resource availability", "Unclear requirements", "Executive support", "Remote teams"];

const WCG_COLS = ["#e8a020", "#3bc1ce", "#1368ce", "#e21b3c", "#26890c", "#a855f7", "#f472b6", "#34d399", "#60a5fa", "#fb923c", "#f87171", "#4ade80"];

function IPMAWordCloudGame({ onClose }) {
  const [phase, setPhase] = useState("welcome");
  const [myJob, setMyJob] = useState(null);
  const [myChallenge, setMyChallenge] = useState(null);
  const [jobVotes, setJobVotes] = useState(Object.fromEntries(WCG_JOBS.map((j) => [j.title, j.base])));
  const [chalVotes, setChalVotes] = useState(Object.fromEntries(WCG_CHALLENGES.map((c) => [c, Math.floor(Math.random() * 3) + 1])));
  const [animating, setAnimating] = useState(false);
  const [participants, setParticipants] = useState(8);

  // Simulate others joining
  useEffect(() => {
    if (phase !== "job") return;
    const t = setInterval(() => {
      setParticipants((p) => {if (p >= 17) return p;return p + 1;});
      // random bot votes
      const job = WCG_JOBS[Math.floor(Math.random() * WCG_JOBS.length)];
      setJobVotes((v) => ({ ...v, [job.title]: v[job.title] + 1 }));
    }, 1400);
    return () => clearInterval(t);
  }, [phase]);

  useEffect(() => {
    if (phase !== "challenge") return;
    const t = setInterval(() => {
      const ch = WCG_CHALLENGES[Math.floor(Math.random() * WCG_CHALLENGES.length)];
      setChalVotes((v) => ({ ...v, [ch]: v[ch] + 1 }));
    }, 900);
    return () => clearInterval(t);
  }, [phase]);

  function submitJob() {
    if (!myJob) return;
    setJobVotes((v) => ({ ...v, [myJob]: v[myJob] + 1 }));
    setAnimating(true);
    setTimeout(() => {setAnimating(false);setPhase("job-reveal");}, 1400);
  }
  function submitChallenge() {
    if (!myChallenge) return;
    setChalVotes((v) => ({ ...v, [myChallenge]: v[myChallenge] + 1 }));
    setPhase("challenge-reveal");
  }

  function Modal({ children, bg = "#46178f" }) {
    return (
      <div style={{ position: "fixed", inset: 0, zIndex: 300, background: "rgba(0,0,0,.6)", display: "flex", alignItems: "center", justifyContent: "center" }}>
        <div style={{ position: "relative", width: "80%", maxWidth: 900, height: "82vh", borderRadius: 18, overflow: "hidden", display: "flex", flexDirection: "column", boxShadow: "0 28px 80px rgba(0,0,0,.75)", background: bg }}>
          <button onClick={onClose} style={{ position: "absolute", top: 12, right: 14, zIndex: 20, width: 34, height: 34, borderRadius: "50%", background: "rgba(0,0,0,.4)", border: "2px solid rgba(255,255,255,.3)", color: "#fff", fontSize: 20, cursor: "pointer", display: "grid", placeItems: "center", fontFamily: "sans-serif" }}>×</button>
          {children}
        </div>
      </div>);

  }

  // ── WELCOME ──
  if (phase === "welcome") return (
    <Modal bg="linear-gradient(160deg,#2d0a6e,#46178f)">
      <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", textAlign: "center", padding: "0 10%", fontFamily: "var(--display)" }}>
        <div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none" }}>
          {[...Array(8)].map((_, i) => <div key={i} style={{ position: "absolute", width: 100 + i * 60, height: 100 + i * 60, borderRadius: "50%", border: "2px solid rgba(255,255,255,.06)", top: "50%", left: "50%", transform: "translate(-50%,-50%)" }} />)}
        </div>
        <div style={{ position: "relative" }}>
          <div style={{ fontSize: 54, marginBottom: 16 }}>☁️</div>
          <div style={{ fontWeight: 900, fontSize: 38, color: "#fff", lineHeight: 1.1, marginBottom: 10 }}>Who's in the room?</div>
          <div style={{ fontSize: 17, color: "rgba(255,255,255,.7)", marginBottom: 8, lineHeight: 1.5 }}>Two quick questions to warm up the group<br />Your answers build a live word cloud for everyone</div>
          <div style={{ display: "flex", gap: 24, justifyContent: "center", margin: "24px 0 32px" }}>
            {[["☁️", "Word clouds", "Your role + challenges"], ["🔴", "Live voting", "See results grow in real-time"], ["⚡", "2 minutes", "Quick warm-up activity"]].map(([ic, tt, sub]) =>
            <div key={tt} style={{ textAlign: "center" }}>
                <div style={{ fontSize: 28, marginBottom: 6 }}>{ic}</div>
                <div style={{ fontWeight: 700, fontSize: 14, color: "#fff" }}>{tt}</div>
                <div style={{ fontSize: 12, color: "rgba(255,255,255,.55)", marginTop: 2 }}>{sub}</div>
              </div>
            )}
          </div>
          <button onClick={() => setPhase("job")} style={{ padding: "15px 44px", borderRadius: 12, background: "#fff", color: "#46178f", fontFamily: "var(--display)", fontWeight: 900, fontSize: 18, border: "none", cursor: "pointer", boxShadow: "0 4px 20px rgba(0,0,0,.3)" }}>Let's go! →</button>
        </div>
      </div>
    </Modal>);


  // ── QUESTION 1: What is your role? ──
  if (phase === "job") return (
    <Modal bg="#1a1a2e">
      <div style={{ flex: 1, display: "flex", flexDirection: "column", fontFamily: "var(--display)", overflowY: "auto" }}>
        <div style={{ padding: "20px 28px 0", textAlign: "center", flex: "none" }}>
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".18em", textTransform: "uppercase", color: "rgba(255,255,255,.45)", marginBottom: 8 }}>Question 1 of 2 · {participants} participants</div>
          <div style={{ fontWeight: 900, fontSize: 28, color: "#fff", marginBottom: 4 }}>What is your current role?</div>
          <div style={{ fontSize: 14, color: "rgba(255,255,255,.55)", marginBottom: 16 }}>Click your job title — the word cloud updates live</div>
        </div>

        {/* live word cloud area */}
        <div style={{ flex: 1, padding: "8px 28px", display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "center", gap: 8, minHeight: 180 }}>
          {WCG_JOBS.map((job, i) => {
            const votes = jobVotes[job.title] || 0;
            const isMe = myJob === job.title;
            const dynSize = Math.min(48, job.size * (0.7 + votes * 0.07));
            return (
              <button key={job.title} onClick={() => {
                if (isMe) setMyJob(null);else
                setMyJob(job.title);
              }}
              style={{ fontSize: dynSize, fontWeight: 900, lineHeight: 1.1, color: isMe ? "#231f20" : WCG_COLS[i % WCG_COLS.length], background: isMe ? WCG_COLS[i % WCG_COLS.length] : "transparent", border: isMe ? "3px solid " + WCG_COLS[i % WCG_COLS.length] : "none", cursor: "pointer", borderRadius: 8, padding: "2px 8px", transition: "all .35s ease", textShadow: isMe ? "none" : "0 2px 10px rgba(0,0,0,.5)" }}>
                {job.title}
              </button>);

          })}
        </div>

        <div style={{ padding: "10px 28px 0", flex: "none" }}>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            <input
              value={myJob && !WCG_JOBS.find((j) => j.title === myJob) ? myJob : ""}
              onChange={(e) => {const v = e.target.value.trim();setMyJob(v || null);}}
              placeholder="Or type your own role…"
              style={{ flex: 1, padding: "9px 13px", borderRadius: 9, border: "1.5px solid rgba(255,255,255,.2)", background: "rgba(255,255,255,.07)", color: "#fff", fontSize: 13.5, fontFamily: "var(--body)", outline: "none" }} />
            
            {myJob && !WCG_JOBS.find((j) => j.title === myJob) &&
            <button onClick={() => setMyJob(null)} style={{ background: "none", border: "none", color: "rgba(255,255,255,.5)", fontSize: 20, cursor: "pointer", padding: "0 6px" }}>×</button>
            }
          </div>
        </div>

        <div style={{ padding: "12px 28px 20px", display: "flex", alignItems: "center", gap: 12, flex: "none", borderTop: "1px solid rgba(255,255,255,.1)", marginTop: 8 }}>
          <div style={{ flex: 1, fontSize: 13, color: "rgba(255,255,255,.55)" }}>
            {myJob ? <span style={{ color: "#fff" }}>Selected: <strong>{myJob}</strong></span> : "Select your role or type one above"}
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "rgba(255,255,255,.4)" }}>
            <div style={{ width: 8, height: 8, borderRadius: "50%", background: "#4ade80", boxShadow: "0 0 6px #4ade80" }} />
            {participants} participants
          </div>
          <button onClick={submitJob} disabled={!myJob || animating}
          style={{ padding: "11px 28px", borderRadius: 10, background: myJob && !animating ? "#fff" : "rgba(255,255,255,.15)", color: myJob && !animating ? "#46178f" : "rgba(255,255,255,.4)", fontFamily: "var(--display)", fontWeight: 900, fontSize: 15, border: "none", cursor: myJob ? "pointer" : "default", transition: "all .2s" }}>
            {animating ? "Submitting…" : "Submit →"}
          </button>
        </div>
      </div>
    </Modal>);


  // ── JOB REVEAL ──
  if (phase === "job-reveal") {
    const sorted = [...WCG_JOBS].sort((a, b) => (jobVotes[b.title] || 0) - (jobVotes[a.title] || 0));
    const maxV = jobVotes[sorted[0].title] || 1;
    return (
      <Modal bg="#1a1a2e">
        <div style={{ flex: 1, display: "flex", flexDirection: "column", fontFamily: "var(--display)", overflowY: "auto" }}>
          <div style={{ padding: "20px 28px 12px", textAlign: "center", flex: "none" }}>
            <div style={{ fontWeight: 900, fontSize: 26, color: "#fff", marginBottom: 4 }}>Roles in the room</div>
            <div style={{ fontSize: 14, color: "rgba(255,255,255,.55)", marginBottom: 4 }}>{participants} participants · project management professionals</div>
          </div>
          <div style={{ flex: 1, padding: "8px 32px", display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "center", gap: 10 }}>
            {sorted.map((job, i) => {
              const votes = jobVotes[job.title] || 0;
              if (votes === 0) return null;
              const dynSize = 14 + Math.round(votes / maxV * 32);
              const isMe = myJob === job.title;
              return (
                <div key={job.title} style={{ fontSize: dynSize, fontWeight: 900, color: isMe ? "var(--vh-orange)" : WCG_COLS[i % WCG_COLS.length], lineHeight: 1.2, textAlign: "center", transition: "all .5s", padding: "2px 6px", borderRadius: 6, background: isMe ? "rgba(248,157,32,.15)" : "transparent", outline: isMe ? "2px solid var(--vh-orange)" : "none" }}>
                  {job.title}
                  <sup style={{ fontSize: 11, color: "rgba(255,255,255,.5)", marginLeft: 3 }}>{votes}</sup>
                </div>);

            })}
          </div>
          <div style={{ padding: "14px 28px 20px", display: "flex", justifyContent: "center", flex: "none", borderTop: "1px solid rgba(255,255,255,.1)" }}>
            <button onClick={() => setPhase("challenge")} style={{ padding: "13px 36px", borderRadius: 11, background: "var(--vh-orange)", color: "#231f20", fontFamily: "var(--display)", fontWeight: 900, fontSize: 16, border: "none", cursor: "pointer" }}>
              Next question →
            </button>
          </div>
        </div>
      </Modal>);

  }

  // ── QUESTION 2: Biggest PM challenge ──
  if (phase === "challenge") return (
    <Modal bg="#0a1429">
      <div style={{ flex: 1, display: "flex", flexDirection: "column", fontFamily: "var(--display)", overflowY: "auto" }}>
        <div style={{ padding: "20px 28px 0", textAlign: "center", flex: "none" }}>
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".18em", textTransform: "uppercase", color: "rgba(255,255,255,.45)", marginBottom: 8 }}>Question 2 of 2</div>
          <div style={{ fontWeight: 900, fontSize: 26, color: "#fff", marginBottom: 4 }}>What is your biggest PM challenge?</div>
          <div style={{ fontSize: 14, color: "rgba(255,255,255,.55)", marginBottom: 16 }}>Pick the one you struggle with most</div>
        </div>
        <div style={{ flex: 1, padding: "8px 28px", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {WCG_CHALLENGES.map((ch, i) => {
            const votes = chalVotes[ch] || 0;
            const isMe = myChallenge === ch;
            return (
              <button key={ch} onClick={() => setMyChallenge(isMe ? null : ch)}
              style={{ padding: "12px 16px", borderRadius: 11, border: "2px solid " + (isMe ? WCG_COLS[i % WCG_COLS.length] : "rgba(255,255,255,.12)"), background: isMe ? "color-mix(in oklab," + WCG_COLS[i % WCG_COLS.length] + ",transparent 82%)" : "rgba(255,255,255,.04)", color: isMe ? "#fff" : "rgba(255,255,255,.75)", cursor: "pointer", textAlign: "left", display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, transition: "all .15s", fontFamily: "var(--display)" }}>
                <span style={{ fontWeight: 700, fontSize: 14 }}>{ch}</span>
                <span style={{ fontSize: 12, color: "rgba(255,255,255,.4)", fontWeight: 600, flex: "none" }}>{votes}</span>
              </button>);

          })}
        </div>
        <div style={{ padding: "10px 28px 0", flex: "none" }}>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            <input
              value={myChallenge && !WCG_CHALLENGES.includes(myChallenge) ? myChallenge : ""}
              onChange={(e) => {const v = e.target.value.trim();setMyChallenge(v || null);}}
              placeholder="Or describe your own challenge…"
              style={{ flex: 1, padding: "9px 13px", borderRadius: 9, border: "1.5px solid rgba(255,255,255,.2)", background: "rgba(255,255,255,.07)", color: "#fff", fontSize: 13.5, fontFamily: "var(--body)", outline: "none" }} />
            
            {myChallenge && !WCG_CHALLENGES.includes(myChallenge) &&
            <button onClick={() => setMyChallenge(null)} style={{ background: "none", border: "none", color: "rgba(255,255,255,.5)", fontSize: 20, cursor: "pointer", padding: "0 6px" }}>×</button>
            }
          </div>
        </div>

        <div style={{ padding: "12px 28px 20px", display: "flex", alignItems: "center", gap: 12, flex: "none", borderTop: "1px solid rgba(255,255,255,.1)", marginTop: 8 }}>
          <div style={{ flex: 1, fontSize: 13, color: "rgba(255,255,255,.55)" }}>
            {myChallenge ? <span style={{ color: "#fff" }}>Selected: <strong>{myChallenge}</strong></span> : "Select or type your biggest challenge"}
          </div>
          <button onClick={submitChallenge} disabled={!myChallenge}
          style={{ padding: "11px 28px", borderRadius: 10, background: myChallenge ? "var(--vh-orange)" : "rgba(255,255,255,.15)", color: myChallenge ? "#231f20" : "rgba(255,255,255,.4)", fontFamily: "var(--display)", fontWeight: 900, fontSize: 15, border: "none", cursor: myChallenge ? "pointer" : "default", transition: "all .2s" }}>
            Submit →
          </button>
        </div>
      </div>
    </Modal>);


  // ── CHALLENGE REVEAL ──
  const chalSorted = [...WCG_CHALLENGES].sort((a, b) => (chalVotes[b] || 0) - (chalVotes[a] || 0));
  const maxCV = chalVotes[chalSorted[0]] || 1;
  return (
    <Modal bg="#0a1429">
      <div style={{ flex: 1, display: "flex", flexDirection: "column", fontFamily: "var(--display)", overflowY: "auto" }}>
        <div style={{ padding: "20px 28px 12px", textAlign: "center", flex: "none" }}>
          <div style={{ fontWeight: 900, fontSize: 26, color: "#fff", marginBottom: 4 }}>Group challenges revealed</div>
          <div style={{ fontSize: 14, color: "rgba(255,255,255,.55)", marginBottom: 4 }}>These are the topics we'll pay extra attention to this week</div>
        </div>
        <div style={{ flex: 1, padding: "12px 32px" }}>
          {chalSorted.slice(0, 8).map((ch, i) => {
            const votes = chalVotes[ch] || 0;
            const pct = Math.round(votes / maxCV * 100);
            const isMe = myChallenge === ch;
            return (
              <div key={ch} style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }}>
                <span style={{ fontSize: 13, fontWeight: isMe ? 700 : 500, color: isMe ? "var(--vh-orange)" : "#fff", width: 170, flex: "none", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{ch}{isMe ? " ← you" : ""}</span>
                <div style={{ flex: 1, height: 10, borderRadius: 9, background: "rgba(255,255,255,.1)", overflow: "hidden" }}>
                  <div style={{ height: "100%", width: pct + "%", background: WCG_COLS[i % WCG_COLS.length], borderRadius: 9, transition: "width .7s ease" }} />
                </div>
                <span style={{ width: 28, textAlign: "right", fontSize: 13, color: "rgba(255,255,255,.55)", fontWeight: 600, flex: "none" }}>{votes}</span>
              </div>);

          })}
        </div>
        <div style={{ padding: "14px 28px 20px", display: "flex", justifyContent: "center", gap: 12, flex: "none", borderTop: "1px solid rgba(255,255,255,.1)" }}>
          <button onClick={onClose} style={{ padding: "13px 36px", borderRadius: 11, background: "#fff", color: "#0a1429", fontFamily: "var(--display)", fontWeight: 900, fontSize: 16, border: "none", cursor: "pointer" }}>
            ✓ Done — let's start!
          </button>
        </div>
      </div>
    </Modal>);

}

/* ─────────────────────────────────── IFRAME SLIDE FRAME ── */
function IPMASlideFrame({ onClose, toast, onKahoot, onWordCloud }) {
  const iframeRef = React.useRef(null);
  const [idx, setIdx]     = useState(0);
  const [notes, setNotes] = useState({});
  const [qText, setQText] = useState("");
  const [questions, setQuestions] = useState([]);
  const [panel, setPanel] = useState("notes");
  const [follow, setFollow] = useState(null);
  const [followStats, setFollowStats] = useState({ yes:18, less:4, no:2 });
  const [elapsed, setElapsed] = useState(0);
  const [trainerSlide, setTrainerSlide] = useState(2);
  const [following, setFollowing] = useState(false);
  const followingRef = React.useRef(false);

  const TOTAL = 9;
  const TITLES = ["Title","Word Cloud","Learning Objectives","What Is a Stakeholder?","Power / Interest Matrix","Engagement Strategies","Case Study","Knowledge Check","Key Takeaways"];
  const GAMES  = [{ slide:1, type:"wordcloud", q:"Group warm-up: what makes a great project manager?" }, { slide:7, type:"kahoot", q:"Which stakeholder group requires the most active management?" }];

  useEffect(() => {
    const t = setInterval(() => setElapsed(e => e + 1), 1000);
    return () => clearInterval(t);
  }, []);

  // Simulate trainer advancing through slides
  useEffect(() => {
    const ts = Math.min(TOTAL - 1, 2 + Math.floor(elapsed / 38));
    setTrainerSlide(ts);
    if (followingRef.current) goTo(ts);
  }, [elapsed]);

  function handleIframeLoad() {
    try {
      const ds = iframeRef.current.contentWindow.document.querySelector("deck-stage");
      if (ds) ds.addEventListener("slidechange", (e) => setIdx(e.detail.index));
    } catch(e) {}
  }

  function goTo(n) {
    try { iframeRef.current.contentWindow.document.querySelector("deck-stage").goTo(Math.max(0, Math.min(TOTAL-1, n))); } catch(e) {}
  }

  function fmt(s) { return `${String(Math.floor(s/3600)).padStart(2,"0")}:${String(Math.floor(s%3600/60)).padStart(2,"0")}:${String(s%60).padStart(2,"0")}`; }

  function sendFollow(v) {
    if (follow) return;
    setFollow(v);
    setFollowStats(s => ({...s,[v]:s[v]+1}));
    toast(v==="yes" ? "Great — marked as understood ✓" : "Feedback sent to trainer", "check");
  }

  function sendQ() {
    if (!qText.trim()) return;
    setQuestions(q => [...q,{text:qText.trim(),time:fmt(elapsed)}]);
    setQText("");
    toast("Question sent to trainer","check");
  }

  const activeGame = GAMES.find(g => g.slide === idx) || null;
  const nextGame   = GAMES.find(g => g.slide > idx)  || null;
  const totalFollow = followStats.yes + followStats.less + followStats.no;

  const barBtn = (label, v, col) => (
    <button key={v} onClick={() => sendFollow(v)}
      style={{ fontSize:12.5, padding:"7px 12px", borderRadius:8, border:"1.5px solid "+(follow===v?col:"#1e2e4a"),
        background:follow===v?col+"22":"rgba(255,255,255,.05)", color:follow===v?col:"#6b88b0",
        fontFamily:"var(--body)", fontWeight:700, cursor:follow?"default":"pointer", transition:"all .15s" }}>
      {label}
    </button>
  );

  return (
    <div style={{ position:"fixed", inset:0, zIndex:200, background:"#0d1521", display:"flex", flexDirection:"column", fontFamily:"var(--body)" }}>

      {/* ── TOP BAR ── */}
      <div style={{ height:52, flex:"none", background:"#0a1220", borderBottom:"1px solid #1e2e4a", display:"flex", alignItems:"center", gap:14, padding:"0 16px" }}>
        <button onClick={onClose} className="btn btn-ghost" style={{ fontSize:13, padding:"7px 12px", background:"rgba(255,255,255,.08)", color:"#adc5e8" }}>
          <Icon name="chevL" size={15}/>Exit viewer
        </button>
        <div style={{ flex:1, fontSize:14, fontWeight:600, color:"#adc5e8", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>
          IPMA-D® · {TITLES[idx] || "Slide "+(idx+1)}
        </div>
        <div style={{ fontSize:13, color:"#6b88b0", fontWeight:600 }}>Slide {idx+1} / {TOTAL}</div>
        {/* Trainer indicator */}
        <button onClick={() => goTo(trainerSlide)}
          title="Jump to trainer's current slide"
          style={{ display:"flex", alignItems:"center", gap:7, padding:"6px 13px", borderRadius:8,
            border:`1px solid ${idx===trainerSlide?"rgba(249,157,37,.5)":"rgba(249,157,37,.25)"}`,
            background:idx===trainerSlide?"rgba(249,157,37,.2)":"rgba(249,157,37,.07)",
            color:idx===trainerSlide?"#f99d25":"#c98020", fontFamily:"var(--body)",
            fontSize:13, fontWeight:700, cursor:"pointer", whiteSpace:"nowrap", transition:"all .15s" }}>
          <span style={{ width:7, height:7, borderRadius:"50%", background:"#f99d25",
            display:"inline-block", flexShrink:0,
            boxShadow:idx===trainerSlide?"0 0 0 3px rgba(249,157,37,.3)":"none" }}/>
          Trainer · {TITLES[trainerSlide] || "Slide "+(trainerSlide+1)}<Tip text="Click to jump to the slide the trainer is currently presenting"/>
        </button>
        <button
          onClick={() => { const nv=!following; setFollowing(nv); followingRef.current=nv; if(nv) goTo(trainerSlide); }}
          style={{ padding:"6px 12px", borderRadius:8,
            border:`1px solid ${following?"rgba(249,157,37,.5)":"rgba(255,255,255,.12)"}`,
            background:following?"rgba(249,157,37,.15)":"rgba(255,255,255,.05)",
            color:following?"#f99d25":"#5a7aaa", fontFamily:"var(--body)",
            fontSize:13, fontWeight:700, cursor:"pointer", whiteSpace:"nowrap", transition:"all .15s" }}>
          {following ? "● Following" : "Follow trainer"}<Tip text="Auto-sync your view with the trainer — your slides follow theirs in real time"/>
        </button>
        <div style={{ display:"flex", alignItems:"center", gap:6, background:"rgba(255,255,255,.07)", borderRadius:8, padding:"5px 12px" }}>
          <Icon name="clock" size={14} style={{ color:"var(--vh-teal)" }}/>
          <span style={{ fontFamily:"var(--display)", fontWeight:700, fontSize:14, color:"var(--vh-teal)" }}>{fmt(elapsed)}</span>
        </div>
      </div>

      {/* ── MAIN ── */}
      <div style={{ flex:1, display:"flex", minHeight:0 }}>

        {/* Iframe */}
        <div style={{ flex:1, minWidth:0, position:"relative" }}>
          <iframe ref={iframeRef} onLoad={handleIframeLoad} src="slides/IPMA-D Slides.html"
            style={{ width:"100%", height:"100%", border:"none", display:"block" }}
            allowFullScreen title="IPMA-D Slides"/>
          {idx === trainerSlide && (
            <div style={{ position:"absolute", inset:0, pointerEvents:"none", zIndex:5,
              border:"3px solid rgba(249,157,37,.6)",
              boxShadow:"inset 0 0 24px rgba(249,157,37,.08)" }}/>
          )}
        </div>

        {/* Right panel */}
        <div style={{ width:272, flex:"none", background:"#0d1929", borderLeft:"1px solid #1e2e4a", display:"flex", flexDirection:"column" }}>

          {/* Tabs */}
          <div style={{ display:"flex", borderBottom:"1px solid #1e2e4a", flex:"none" }}>
            {[["notes","Notes"],["questions","Questions"]].map(([id,lbl]) => (
              <button key={id} onClick={() => setPanel(id)}
                style={{ flex:1, padding:"11px 0", fontSize:13, fontWeight:600, border:"none", cursor:"pointer",
                  color:panel===id?"#fff":"#5a7aaa", background:panel===id?"rgba(255,255,255,.06)":"none",
                  borderBottom:panel===id?"2px solid var(--vh-orange)":"2px solid transparent", transition:"all .15s" }}>
                {lbl}
              </button>
            ))}
          </div>

          {panel === "notes" && (
            <div style={{ flex:1, display:"flex", flexDirection:"column", minHeight:0 }}>
              {/* Notes */}
              <div style={{ flex:3, display:"flex", flexDirection:"column", padding:12, gap:8, minHeight:0 }}>
                <div style={{ fontSize:11.5, color:"#4a6080", fontWeight:600 }}>Slide {idx+1} · {TITLES[idx]||""}</div>
                <textarea value={notes[idx]||""} onChange={e => setNotes(n => ({...n,[idx]:e.target.value}))}
                  placeholder="Type your notes here…"
                  style={{ flex:1, resize:"none", background:"rgba(255,255,255,.05)", border:"1px solid #1e2e4a",
                    borderRadius:8, color:"#c8d8f0", fontSize:13, padding:10, outline:"none",
                    fontFamily:"var(--body)", lineHeight:1.6 }}/>
                <button className="btn" style={{ fontSize:12, background:"rgba(255,255,255,.08)", color:"#adc5e8" }}
                  onClick={() => toast("Notes saved for slide "+(idx+1),"check")}>
                  <Icon name="check" size={13}/>Save note<Tip text="Your notes are saved per slide and persist during this session"/>
                </button>
              </div>
              {/* Game widget */}
              <div style={{ flex:1, borderTop:"1px solid #1e2e4a", padding:"10px 12px", display:"flex",
                flexDirection:"column", gap:7, minHeight:0, overflow:"hidden",
                background:activeGame?"rgba(249,157,37,.05)":"rgba(0,0,0,.15)" }}>
                {activeGame ? (<>
                  <div style={{ display:"flex", alignItems:"center", gap:7 }}>
                    <span style={{ width:7, height:7, borderRadius:"50%", background:"#f99d25", display:"inline-block", flexShrink:0 }}/>
                    <span style={{ fontSize:10.5, fontWeight:700, letterSpacing:".1em", textTransform:"uppercase", color:"#f99d25" }}>
                      {activeGame.type==="kahoot"?"Kahoot!":"Word Cloud"} · Now
                    </span>
                  </div>
                  <div style={{ fontSize:12.5, color:"#c8d8f0", lineHeight:1.4 }}>{activeGame.q}</div>
                  <button className="btn" style={{ fontSize:12.5, background:"#46178f", color:"#fff", padding:"7px 10px" }}
                    onClick={activeGame.type==="kahoot"?onKahoot:onWordCloud}>
                    <Icon name="play" size={13}/>Launch game
                  </button>
                </>) : nextGame ? (<>
                  <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:".1em", textTransform:"uppercase", color:"#4a6080", marginBottom:2 }}>
                    Next {nextGame.type==="kahoot"?"Kahoot":"Word Cloud"}
                  </div>
                  <div style={{ fontSize:12, color:"#6b88b0" }}>Slide {nextGame.slide+1} · {nextGame.slide-idx} slide{nextGame.slide-idx!==1?"s":""} away</div>
                  <div style={{ height:4, borderRadius:999, background:"#1e2e4a", overflow:"hidden" }}>
                    <div style={{ height:"100%", borderRadius:999, background:"linear-gradient(90deg,var(--vh-blue-500),var(--vh-teal))",
                      width:Math.min(100,Math.round((idx/nextGame.slide)*100))+"%", transition:"width .3s" }}/>
                  </div>
                </>) : (
                  <div style={{ fontSize:12, color:"#4a6080", textAlign:"center", paddingTop:8 }}>No more games in this session.</div>
                )}
              </div>
            </div>
          )}

          {panel === "questions" && (
            <div style={{ flex:1, display:"flex", flexDirection:"column", padding:12, gap:8, minHeight:0 }}>
              <div style={{ flex:1, overflowY:"auto", display:"flex", flexDirection:"column", gap:8 }} className="scroll">
                {questions.length===0 && (
                  <div style={{ fontSize:13, color:"#4a6080", textAlign:"center", marginTop:24, lineHeight:1.6 }}>
                    No questions yet.<br/>Ask your trainer below.
                  </div>
                )}
                {questions.map((q,i) => (
                  <div key={i} style={{ background:"rgba(255,255,255,.06)", border:"1px solid #1e2e4a", borderRadius:8, padding:"8px 10px" }}>
                    <div style={{ fontSize:13, color:"#c8d8f0", lineHeight:1.5 }}>{q.text}</div>
                    <div style={{ fontSize:10.5, color:"#4a6080", marginTop:4 }}>Sent at {q.time}</div>
                  </div>
                ))}
              </div>
              <div style={{ display:"flex", gap:6 }}>
                <input value={qText} onChange={e=>setQText(e.target.value)}
                  onKeyDown={e=>e.key==="Enter"&&sendQ()}
                  placeholder="Ask the trainer…"
                  style={{ flex:1, background:"rgba(255,255,255,.06)", border:"1px solid #1e2e4a",
                    borderRadius:8, color:"#c8d8f0", fontSize:13, padding:"8px 10px",
                    outline:"none", fontFamily:"var(--body)" }}/>
                <button onClick={sendQ} className="btn" style={{ fontSize:12, background:"var(--vh-blue-500)", color:"#fff", padding:"8px 12px" }}>
                  <Icon name="arrowR" size={14}/>
                </button>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* ── BOTTOM BAR ── */}
      <div style={{ height:62, flex:"none", background:"#0a1220", borderTop:"1px solid #1e2e4a", display:"flex", alignItems:"center", gap:12, padding:"0 18px" }}>
        {/* Nav */}
        <div style={{ display:"flex", alignItems:"center", gap:8 }}>
          <button onClick={() => goTo(idx-1)} disabled={idx===0}
            style={{ display:"flex", alignItems:"center", gap:6, fontSize:13, padding:"8px 14px", borderRadius:9,
              background:"rgba(255,255,255,.08)", color:"#adc5e8", border:"none", cursor:idx===0?"default":"pointer",
              opacity:idx===0?.35:1, fontFamily:"var(--body)", fontWeight:600 }}>
            <Icon name="chevL" size={15}/>Prev
          </button>
          <div style={{ position:"relative", height:5, width:120, background:"rgba(255,255,255,.1)", borderRadius:9 }}>
            <div style={{ position:"absolute", height:"100%", width:(idx+1)/TOTAL*100+"%", background:"rgba(59,193,206,.7)", borderRadius:9, transition:"width .3s" }}/>
            <div title={"Trainer: "+(TITLES[trainerSlide]||"Slide "+(trainerSlide+1))}
              style={{ position:"absolute", top:"50%", left:(trainerSlide+0.5)/TOTAL*100+"%",
                transform:"translate(-50%,-50%)", width:13, height:13, borderRadius:"50%",
                background:"#f99d25", border:"2.5px solid #0a1220",
                boxShadow:"0 0 0 2.5px rgba(249,157,37,.4)", transition:"left .6s ease", zIndex:2 }}/>
          </div>
          <button onClick={() => goTo(idx+1)} disabled={idx===TOTAL-1}
            style={{ display:"flex", alignItems:"center", gap:6, fontSize:13, padding:"8px 14px", borderRadius:9,
              background:"rgba(255,255,255,.08)", color:"#adc5e8", border:"none", cursor:idx===TOTAL-1?"default":"pointer",
              opacity:idx===TOTAL-1?.35:1, fontFamily:"var(--body)", fontWeight:600 }}>
            Next<Icon name="arrowR" size={15}/>
          </button>
        </div>

        <div style={{ flex:1 }}/>

        {/* Do you follow? */}
        <div style={{ display:"flex", alignItems:"center", gap:8 }}>
          <span style={{ fontSize:12.5, color:"#6b88b0", fontWeight:600, whiteSpace:"nowrap" }}>Do you follow?</span><Tip text="Let the trainer know if you can keep up — results are anonymous and shown live"/>
          {barBtn("✓ Yes","yes","var(--vh-teal)")}
          {barBtn("~ Less","less","var(--vh-orange)")}
          {barBtn("✗ No","no","#c0392b")}
          {/* Mini bar chart */}
          <div style={{ display:"flex", gap:4, alignItems:"flex-end", height:34, paddingBottom:2, marginLeft:4 }}>
            {[["yes","var(--vh-teal)"],["less","var(--vh-orange)"],["no","#c0392b"]].map(([k,col]) => {
              const pct = Math.round(followStats[k]/totalFollow*100);
              return (
                <div key={k} style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:2 }}>
                  <span style={{ fontSize:9.5, color:col, fontWeight:700 }}>{pct}%</span>
                  <div style={{ width:10, background:col, borderRadius:"3px 3px 0 0", height:Math.max(2,Math.round(pct/3.5))+"px", transition:"height .4s" }}/>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { IPMASlideViewer, IPMABookReader, IPMAKahootGame, IPMAWordCloudGame, IPMASlideFrame });