/* ipma-slides.jsx — SINGLE SOURCE OF TRUTH for the IPMA-D course slideware.
   Loaded by the Learner LMS, the Trainer portal and the Educator dashboard so
   every environment renders the exact same 20 slides from the same data.

   Exports (on window):
     IPMA_SL          — the 20-slide data array
     IPMASlideCard    — self-contained slide renderer (no external CSS / Icon deps)
     IPMADeckOverlay  — a portal slide viewer (prev/next + thumbnail rail)

   This file deliberately depends on NOTHING but React, so it behaves identically
   in all three portals. Colours use the shared --vh-* / --display CSS variables
   that every portal defines; the dotted-hex background is injected here. */

/* ─────────────────────────────────────── SLIDE DATA (20 slides) ── */
const IPMA_SL = [
{ n: 1, type: "cover", title: "Training IPMA D", sub: "Individual Competence Baseline · Version 4", credit: "Van Haren Academy" },
{ n: 2, type: "bullets", head: "Introduction", label: "Agenda", lead: null, items: ["Introduce yourself", "Learning objectives for participants", "House rules: mobile, e-mail, breaks, lunch", "IPMA and IPMA accreditation levels", "Course objectives", "Training approach and schedule"] },
{ n: 3, type: "bullets", head: "IPMA NL", label: "About IPMA", lead: "The International Project Management Association (IPMA) is a federation of national PM associations in over 70 countries.", items: ["IPMA NL: more than 2,400 project manager members", "Develops and promotes PM competence worldwide", "ICB4 is the global standard for individual PM competence"] },
{ n: 4, type: "cols3", head: "IPMA Individual Competence Baseline", sub: "ICB4 — Three competence areas", cols: [{ n: "05", name: "Perspective", color: "#3bc1ce", desc: "Contextual competencies" }, { n: "10", name: "People", color: "#1281c4", desc: "Personal & interpersonal" }, { n: "13", name: "Practice", color: "#c0392b", desc: "Technical PM" }], footer: "Knowledge + Skills + Abilities → Competencies" },
{ n: 5, type: "levels", head: "IPMA Accreditation Levels", levels: [{ code: "D", col: "#e8a020", title: "PM Associate", desc: "Knowledge of all PM elements. Can support a PM on limited complex projects." }, { code: "C", col: "#7a5ad6", title: "Project Manager", desc: "Can manage limited complex projects independently." }, { code: "B", col: "#1281c4", title: "Senior PM", desc: "Can manage complex projects." }, { code: "A", col: "#c0392b", title: "Projects Director", desc: "Can manage a portfolio or programme." }] },
{ n: 6, type: "steps", head: "IPMA-D Certification Process", steps: [{ n: 1, label: "Prerequisites", desc: "No requirements. Experience in projects is an advantage." }, { n: 2, label: "Written Exam", desc: "3 hours, multiple choice covering all 28 ICB4 competence elements." }, { n: 3, label: "Pass Mark", desc: "Minimum 55% correct answers required to pass." }, { n: 4, label: "Certificate", desc: "Valid 5 years. Renewal through continuing education (CPD)." }] },
{ n: 7, type: "objectives", head: "Learning Objectives", intro: "Upon completion of this course, participants:", items: ["Have knowledge of all project management elements", "Can support a PM of a limited complex project", "Are prepared for the IPMA-D written examination", "Can apply ICB4 competence elements in practical situations"] },
{ n: 8, type: "schedule", head: "Training Schedule", days: [{ n: 1, title: "Introduction & Project Preparation", color: "#c0392b" }, { n: 2, title: "Project Definition & Delivery", color: "#1281c4" }, { n: 3, title: "People Competencies", color: "#7a5ad6" }, { n: 4, title: "Perspective Competencies", color: "#3bc1ce" }] },
{ n: 9, type: "section", area: "Practice Competence Elements", chapter: "Project Orientation & Project Preparation", day: "Day 1" },
{ n: 10, type: "toc", head: "Project Orientation and Project Preparation", ref: "Project Management by ICB4", items: ["03 · Project Orientation", "04.01 · Project Preparation Stage", "04.02 · Stakeholders", "04.03 · Project Organisation", "04.04 · Requirements and Objectives", "04.05 · Risk and Opportunity"] },
{ n: 11, type: "competence", num: "3.01", head: "Project Orientation", level: "C2", area: "Practice", def: "The competence to determine whether an initiative can best be carried out as a project and apply the principles of project management." },
{ n: 12, type: "comparison", head: "What is a Project?", left: { src: "ICB4", text: "A unique, temporary, multi-disciplinary and organised endeavour to realise agreed deliverables within predefined requirements and constraints." }, right: { src: "PRINCE2", text: "A temporary organisation that is created for the purpose of delivering one or more business products according to an agreed Business Case." }, footer: "Both emphasise: temporary · unique · organised · goal-oriented" },
{ n: 13, type: "formula", head: "Why Carry Out a Project?", headline: "Implement Changes!", formula: "E = Q × A", explain: "Effectiveness = Quality × Acceptance", note: "A perfect solution (Q=10) with zero acceptance (A=0) = zero effectiveness." },
{ n: 14, type: "stats", head: "Derailment of Projects", src: "Standish Group International, UK 2021 — IT Projects", stats: [{ v: "29%", l: "Successful", c: "var(--vh-teal)" }, { v: "53%", l: "Not successful", c: "var(--vh-orange)" }, { v: "18%", l: "Cancelled", c: "#c0392b" }], insight: "More than 70% of IT projects fail to deliver on time, on budget and in scope." },
{ n: 15, type: "bullets", head: "What is a Successful Project?", label: "Definition", lead: "A project is successful to the extent to which it satisfies the relevant stakeholders.", items: ["Delivered on time and within budget", "Meets the agreed specifications", "Achieves the intended business outcome", "Stakeholders consider it a success"], note: "Project management success ≠ project success." },
{ n: 16, type: "bullets", head: "When is the User Satisfied?", label: "User Perspective", items: ["The purpose of the project is desired", "The urgency is felt, constraints are clear", "They have control over their immediate environment", "Actively involved throughout the project", "Purpose and constraints are well understood"] },
{ n: 17, type: "stats", head: "Project Success — Reality Check", src: "Industry research", stats: [{ v: "✓ Spec", l: "Conform specifications", c: "var(--vh-blue-500)" }, { v: "✓ Budget", l: "Within budget", c: "var(--vh-teal)" }, { v: "3×", l: "Over budget", c: "var(--vh-orange)" }, { v: "4×", l: "Over schedule", c: "#c0392b" }], insight: "Meeting specifications is not enough if budget and time overrun." },
{ n: 18, type: "emphasis", head: "Project Success", headline: "USERS FIRST", body: "User involvement and acceptance are the strongest predictors of project success — ahead of technical quality, budget adherence, and schedule performance.", src: "Standish Group CHAOS Report" },
{ n: 19, type: "cols3", head: "Work Forms", sub: "Increasing predictability →", cols: [{ n: "Ad hoc", name: "Improvisation", color: "#7a5ad6", desc: "Flexible, demand-driven" }, { n: "Standard", name: "Process approach", color: "#1281c4", desc: "Specified, efficient, routine" }, { n: "Planned", name: "Plan-based work", color: "#c0392b", desc: "Predictable, result-oriented" }], footer: "Projects sit in the 'plan-based' work category" },
{ n: 20, type: "steps", head: "Project-based Work — The Phases", steps: [{ n: 1, label: "Agree the assignment", desc: "Project preparation stage — clarify objectives, scope, constraints, organisation." }, { n: 2, label: "Plan the assignment", desc: "Project definition stage — create the project management plan." }, { n: 3, label: "Execute the assignment", desc: "Project execution stage(s) — deliver the work packages." }, { n: 4, label: "Hand over & close", desc: "Project closure — transfer output, capture lessons learned." }] }];

/* Short speaker-note per slide — surfaced in the Trainer live session. */
const IPMA_NOTES = {
  0:  "Welcome the group. Set the tone: 4 days, exam-focused but practical. Quick round of introductions.",
  1:  "Walk through the agenda. Agree house rules together — phones on silent, breaks every 90 min.",
  2:  "Position IPMA as the global federation. Stress ICB4 is competence-based, not just knowledge.",
  3:  "Introduce the Eye of Competence: Perspective (5), People (10), Practice (13). Ask which area they find hardest.",
  4:  "Clarify D vs C in practice — D supports, C runs limited-complex projects independently.",
  5:  "Walk the certification path. Reassure: no prerequisites for D, 55% pass mark.",
  6:  "Tie each objective back to their day job. Ask for one project they want to apply this to.",
  7:  "Preview the 4 days. Note Day 1 is the foundation everything else builds on.",
  8:  "Section divider — we now enter the Practice competence elements. Energy check before the deep dive.",
  9:  "Map the chapter to the book. Point learners to ICB4 reference numbers.",
  10: "Define Project Orientation. Ask: when is something a project vs business-as-usual?",
  11: "Compare ICB4 and PRINCE2 definitions. Draw out the shared words: temporary, unique, organised.",
  12: "Emphasise the formula E = Q × A here. Ask participants for examples from their own projects before advancing.",
  13: "Use the Standish numbers to provoke discussion — why do 70% of projects struggle?",
  14: "Success ≠ delivery. A project can be 'on time, on budget' and still fail the stakeholders.",
  15: "Shift to the user's view. What makes THEM feel a project succeeded?",
  16: "Reality check: specs alone aren't enough. Budget and schedule overruns are the norm.",
  17: "Land the key message: USERS FIRST. Acceptance beats technical perfection.",
  18: "Work forms model — projects are plan-based work. Contrast with improvisation and routine.",
  19: "Close the practice intro with the 4 phases. Preview tomorrow's project definition stage.",
};

/* ─────────────────────────────── inline icons (self-contained) ── */
function IpmaIcon({ name, size = 18, color = "currentColor", stroke = 2 }) {
  const paths = {
    graduation: ["M3 9l9-5 9 5-9 5z", "M7 11v5c0 1 2.2 2.5 5 2.5s5-1.5 5-2.5v-5", "M21 9v5"],
    check: ["M5 13l4 4L19 7"],
  }[name] || [];
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" style={{ display: "block" }}>
      {paths.map((d, i) => <path key={i} d={d} />)}
    </svg>);
}

/* Inject the dotted-hex background once, scoped to .ipma-hexfield. */
(function injectIpmaCss() {
  if (typeof document === "undefined" || document.getElementById("ipma-slides-css")) return;
  const st = document.createElement("style");
  st.id = "ipma-slides-css";
  st.textContent =
    ".ipma-hexfield{position:absolute;inset:0;opacity:.5;pointer-events:none;" +
    "background-image:radial-gradient(rgba(148,191,230,.45) 1.1px,transparent 1.2px);" +
    "background-size:18px 18px;-webkit-mask-image:linear-gradient(120deg,transparent,#000 60%);" +
    "mask-image:linear-gradient(120deg,transparent,#000 60%)}";
  document.head.appendChild(st);
})();

/* ─────────────────────────────────────── SLIDE CARD RENDERER ── */
function IPMASlideCard({ s }) {
  const navy = "#0e1a35";const white = "#fff";
  const base = { width: "100%", height: "100%", position: "relative", overflow: "hidden", fontFamily: "var(--display)", boxSizing: "border-box" };

  if (s.type === "cover") return (
    <div style={{ ...base, background: "linear-gradient(140deg,#1d3d7c,#0a1429)", display: "flex", alignItems: "center", justifyContent: "center", textAlign: "center" }}>
      <div className="ipma-hexfield" style={{ opacity: .14 }} />
      <div style={{ position: "relative", padding: "0 12%" }}>
        <div style={{ width: 74, height: 81, margin: "0 auto 18px", clipPath: "polygon(50% 0,93% 25%,93% 75%,50% 100%,7% 75%,7% 25%)", background: "var(--vh-orange)", display: "grid", placeItems: "center" }}><IpmaIcon name="graduation" size={38} color="#231f20" /></div>
        <div style={{ fontWeight: 800, fontSize: 38, color: white, lineHeight: 1.1 }}>{s.title}</div>
        {s.sub && <div style={{ fontSize: 17, color: "rgba(255,255,255,.75)", marginTop: 10 }}>{s.sub}</div>}
        {s.credit && <div style={{ fontSize: 13, color: "rgba(255,255,255,.4)", marginTop: 14, textTransform: "uppercase", letterSpacing: ".1em" }}>{s.credit}</div>}
      </div>
    </div>);


  if (s.type === "section") return (
    <div style={{ ...base, background: "linear-gradient(135deg,#c0392b,#8b1a1a)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", textAlign: "center", padding: "0 10%" }}>
      <div className="ipma-hexfield" style={{ opacity: .14 }} />
      <div style={{ position: "relative" }}>
        <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".2em", textTransform: "uppercase", color: "rgba(255,255,255,.6)", marginBottom: 12 }}>{s.day}</div>
        <div style={{ fontWeight: 700, fontSize: 14, color: "rgba(255,255,255,.7)", textTransform: "uppercase", letterSpacing: ".12em", marginBottom: 8 }}>{s.area}</div>
        <div style={{ fontWeight: 800, fontSize: 36, color: white, lineHeight: 1.15 }}>{s.chapter}</div>
      </div>
    </div>);


  if (s.type === "formula" || s.type === "emphasis") return (
    <div style={{ ...base, background: "linear-gradient(140deg,#1d3d7c,#0a1429)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", textAlign: "center", padding: "0 8%" }}>
      <div className="ipma-hexfield" style={{ opacity: .12 }} />
      <div style={{ position: "relative" }}>
        <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".18em", color: "rgba(255,255,255,.5)", textTransform: "uppercase", marginBottom: 16 }}>{s.head}</div>
        {s.headline && <div style={{ fontWeight: 800, fontSize: s.type === "emphasis" ? 52 : 28, color: white, marginBottom: s.type === "emphasis" ? 20 : 8, lineHeight: 1.1 }}>{s.headline}</div>}
        {s.formula && <div style={{ fontFamily: "Georgia,serif", fontWeight: 700, fontSize: 54, color: "var(--vh-orange)", margin: "8px 0" }}>{s.formula}</div>}
        {s.explain && <div style={{ fontSize: 18, color: "rgba(255,255,255,.7)", marginBottom: 16 }}>{s.explain}</div>}
        {(s.note || s.body) && <div style={{ fontSize: 15, color: "rgba(255,255,255,.65)", lineHeight: 1.6, maxWidth: 600 }}>{s.note || s.body}</div>}
        {s.src && <div style={{ fontSize: 12, color: "rgba(255,255,255,.4)", marginTop: 14, fontStyle: "italic" }}>{s.src}</div>}
      </div>
    </div>);


  if (s.type === "stats") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ borderLeft: "4px solid #c0392b", paddingLeft: 14, marginBottom: "auto" }}>
        <div style={{ fontWeight: 800, fontSize: 26, color: navy }}>{s.head}</div>
        {s.src && <div style={{ fontSize: 12, color: "#888", marginTop: 4 }}>{s.src}</div>}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: `repeat(${s.stats.length},1fr)`, gap: 16, flex: 1, alignItems: "center" }}>
        {s.stats.map((st, i) =>
        <div key={i} style={{ textAlign: "center", padding: "16px 8px", borderRadius: 12, background: "#f8f9fb", border: "1px solid #e8ecf4" }}>
            <div style={{ fontWeight: 800, fontSize: 40, color: st.c, lineHeight: 1 }}>{st.v}</div>
            <div style={{ fontSize: 13, color: "#555", marginTop: 8, fontWeight: 600 }}>{st.l}</div>
          </div>
        )}
      </div>
      {s.insight && <div style={{ fontSize: 13.5, color: "#555", marginTop: 12, padding: "10px 14px", borderRadius: 8, background: "#f0f4ff", lineHeight: 1.5 }}>{s.insight}</div>}
    </div>);


  if (s.type === "cols3") return (
    <div style={{ ...base, background: s.cols[0].color ? "#0e1a35" : white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div className="ipma-hexfield" style={{ opacity: .1 }} />
      <div style={{ position: "relative", flex: 1, display: "flex", flexDirection: "column" }}>
        <div style={{ fontWeight: 800, fontSize: 26, color: white, marginBottom: 4 }}>{s.head}</div>
        {s.sub && <div style={{ fontSize: 14, color: "rgba(255,255,255,.6)", marginBottom: 20 }}>{s.sub}</div>}
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 14, flex: 1 }}>
          {s.cols.map((c, i) =>
          <div key={i} style={{ borderRadius: 12, background: "rgba(255,255,255,.07)", border: `1px solid ${c.color}44`, padding: "20px 16px", display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 10 }}>
              <div style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: 36, color: c.color }}>{c.n}</div>
              <div style={{ fontWeight: 700, fontSize: 16, color: white }}>{c.name}</div>
              <div style={{ fontSize: 13, color: "rgba(255,255,255,.6)" }}>{c.desc}</div>
            </div>
          )}
        </div>
        {s.footer && <div style={{ fontSize: 13, color: "rgba(255,255,255,.5)", marginTop: 12, textAlign: "center" }}>{s.footer}</div>}
      </div>
    </div>);


  if (s.type === "comparison") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ fontWeight: 800, fontSize: 26, color: navy, marginBottom: 18 }}>{s.head}</div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18, flex: 1 }}>
        {[s.left, s.right].map((side, i) =>
        <div key={i} style={{ borderRadius: 12, background: i === 0 ? "#fff5e6" : "#e8f0fe", border: `2px solid ${i === 0 ? "var(--vh-orange)" : "var(--vh-blue-500)"}`, padding: "20px 18px" }}>
            <div style={{ fontWeight: 800, fontSize: 15, color: i === 0 ? "var(--vh-orange)" : "var(--vh-blue-500)", marginBottom: 10, textTransform: "uppercase", letterSpacing: ".06em" }}>{side.src}</div>
            <div style={{ fontSize: 15, color: "#1c2740", lineHeight: 1.6 }}>{side.text}</div>
          </div>
        )}
      </div>
      {s.footer && <div style={{ fontSize: 13, color: "#888", marginTop: 12, textAlign: "center", fontStyle: "italic" }}>{s.footer}</div>}
    </div>);


  if (s.type === "levels") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ fontWeight: 800, fontSize: 26, color: navy, marginBottom: 16 }}>{s.head}</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 10, flex: 1 }}>
        {s.levels.map((lv, i) =>
        <div key={i} style={{ display: "flex", alignItems: "center", gap: 14, padding: "12px 16px", borderRadius: 11, background: "#f8f9fb", border: "1px solid #e4e9f2" }}>
            <div style={{ width: 44, height: 44, borderRadius: 10, flex: "none", background: lv.col, display: "grid", placeItems: "center", fontWeight: 900, fontSize: 22, color: "#fff" }}>{lv.code}</div>
            <div>
              <div style={{ fontWeight: 700, fontSize: 15, color: navy }}>{lv.title}</div>
              <div style={{ fontSize: 13, color: "#666", marginTop: 3 }}>{lv.desc}</div>
            </div>
          </div>
        )}
      </div>
    </div>);


  if (s.type === "steps") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ fontWeight: 800, fontSize: 24, color: navy, marginBottom: 16 }}>{s.head}</div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, flex: 1 }}>
        {s.steps.map((st, i) =>
        <div key={i} style={{ borderRadius: 11, background: "#f8f9fb", border: "1px solid #e4e9f2", padding: "14px 16px", display: "flex", gap: 12 }}>
            <div style={{ width: 30, height: 30, borderRadius: "50%", flex: "none", background: "#c0392b", color: "#fff", fontWeight: 800, fontSize: 15, display: "grid", placeItems: "center" }}>{st.n}</div>
            <div><div style={{ fontWeight: 700, fontSize: 14, color: navy, marginBottom: 4 }}>{st.label}</div><div style={{ fontSize: 12.5, color: "#555", lineHeight: 1.5 }}>{st.desc}</div></div>
          </div>
        )}
      </div>
    </div>);


  if (s.type === "schedule") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ fontWeight: 800, fontSize: 26, color: navy, marginBottom: 16 }}>{s.head}</div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, flex: 1 }}>
        {s.days.map((d) =>
        <div key={d.n} style={{ borderRadius: 12, background: d.color, padding: "18px 20px", position: "relative", overflow: "hidden" }}>
            <div className="ipma-hexfield" style={{ opacity: .18 }} />
            <div style={{ position: "relative" }}>
              <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".16em", color: "rgba(255,255,255,.7)", textTransform: "uppercase", marginBottom: 6 }}>Day {d.n}</div>
              <div style={{ fontWeight: 700, fontSize: 17, color: "#fff", lineHeight: 1.3 }}>{d.title}</div>
            </div>
          </div>
        )}
      </div>
    </div>);


  if (s.type === "objectives") return (
    <div style={{ ...base, background: "linear-gradient(140deg,#1d3d7c,#0a1429)", display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div className="ipma-hexfield" style={{ opacity: .12 }} />
      <div style={{ position: "relative", flex: 1, display: "flex", flexDirection: "column" }}>
        <div style={{ fontWeight: 800, fontSize: 26, color: white, marginBottom: 8 }}>{s.head}</div>
        {s.intro && <div style={{ fontSize: 14, color: "rgba(255,255,255,.65)", marginBottom: 16, fontStyle: "italic" }}>{s.intro}</div>}
        <div style={{ display: "flex", flexDirection: "column", gap: 10, flex: 1 }}>
          {s.items.map((it, i) =>
          <div key={i} style={{ display: "flex", gap: 12, alignItems: "flex-start", padding: "10px 14px", borderRadius: 10, background: "rgba(255,255,255,.07)" }}>
              <div style={{ width: 24, height: 24, borderRadius: "50%", flex: "none", background: "var(--vh-teal)", display: "grid", placeItems: "center", marginTop: 1 }}><IpmaIcon name="check" size={13} color="#fff" /></div>
              <span style={{ fontSize: 15, color: white, lineHeight: 1.4 }}>{it}</span>
            </div>
          )}
        </div>
      </div>
    </div>);


  if (s.type === "competence") return (
    <div style={{ ...base, background: "linear-gradient(140deg,#1d3d7c,#0a1429)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "5% 8%", textAlign: "center" }}>
      <div className="ipma-hexfield" style={{ opacity: .12 }} />
      <div style={{ position: "relative" }}>
        <div style={{ fontSize: 13, color: "rgba(255,255,255,.5)", letterSpacing: ".14em", textTransform: "uppercase", marginBottom: 6 }}>Competence Element {s.num} · {s.area} · Level {s.level}</div>
        <div style={{ fontWeight: 800, fontSize: 34, color: white, marginBottom: 20 }}>{s.head}</div>
        <div style={{ fontSize: 18, color: "rgba(255,255,255,.8)", lineHeight: 1.65, maxWidth: 560, fontStyle: "italic" }}>"{s.def}"</div>
      </div>
    </div>);


  if (s.type === "toc") return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      <div style={{ fontWeight: 800, fontSize: 22, color: navy, marginBottom: 4 }}>{s.head}</div>
      {s.ref && <div style={{ fontSize: 12, color: "#888", marginBottom: 16 }}>Reference: {s.ref}</div>}
      <div style={{ display: "flex", flexDirection: "column", gap: 8, flex: 1 }}>
        {s.items.map((it, i) =>
        <div key={i} style={{ display: "flex", gap: 12, alignItems: "center", padding: "8px 12px", borderRadius: 8, background: "#f8f9fb", border: "1px solid #e4e9f2" }}>
            <div style={{ width: 6, height: 6, borderRadius: "50%", background: "#c0392b", flex: "none" }} />
            <span style={{ fontSize: 15, color: navy, fontWeight: 500 }}>{it}</span>
          </div>
        )}
      </div>
    </div>);


  // default: bullets
  return (
    <div style={{ ...base, background: white, display: "flex", flexDirection: "column", padding: "5% 6%" }}>
      {s.label && <div style={{ display: "inline-block", fontSize: 11, fontWeight: 700, letterSpacing: ".14em", color: "#fff", background: "#c0392b", padding: "3px 10px", borderRadius: 4, marginBottom: 10, width: "fit-content", textTransform: "uppercase" }}>{s.label}</div>}
      <div style={{ fontWeight: 800, fontSize: 26, color: navy, marginBottom: s.lead ? 10 : 16 }}>{s.head}</div>
      {s.lead && <div style={{ fontSize: 15, color: "#333", lineHeight: 1.6, marginBottom: 14, padding: "10px 14px", borderLeft: "3px solid #c0392b", background: "#fef9f4" }}>{s.lead}</div>}
      <div style={{ display: "flex", flexDirection: "column", gap: 8, flex: 1 }}>
        {s.items && s.items.map((it, i) =>
        <div key={i} style={{ display: "flex", gap: 12, alignItems: "flex-start", fontSize: 15, color: "#333", lineHeight: 1.5 }}>
            <span style={{ color: "#c0392b", fontWeight: 700, flex: "none", marginTop: 2 }}>›</span><span>{it}</span>
          </div>
        )}
      </div>
      {s.note && <div style={{ fontSize: 12.5, color: "#888", marginTop: 12, fontStyle: "italic", borderTop: "1px solid #eee", paddingTop: 10 }}>{s.note}</div>}
    </div>);
}

/* ─────────────────── auto-fit wrapper: renders the slide at a fixed
   1280×720 design size and scales it to fit any container (letterboxed),
   so the px-based slide always keeps correct proportions regardless of the
   box it lives in. Used by the Trainer live stage and the Educator overlay. */
function ScaledSlide({ s, radius = 8, shadow = true }) {
  const baseW = 1280, baseH = 720;
  const ref = React.useRef(null);
  const [d, setD] = React.useState(null);
  React.useLayoutEffect(() => {
    const el = ref.current; if (!el) return;
    const update = () => {
      const r = el.getBoundingClientRect();
      if (r.width && r.height) { const sc = Math.min(r.width / baseW, r.height / baseH); setD({ sc: sc, w: baseW * sc, h: baseH * sc }); }
    };
    update();
    const ro = new ResizeObserver(update); ro.observe(el);
    return () => ro.disconnect();
  }, []);
  return (
    <div ref={ref} style={{ width: "100%", height: "100%", position: "relative", overflow: "hidden" }}>
      {d &&
      <div style={{ position: "absolute", top: "50%", left: "50%", width: d.w, height: d.h, marginLeft: -d.w / 2, marginTop: -d.h / 2, borderRadius: radius, overflow: "hidden", background: "#fff", boxShadow: shadow ? "0 18px 50px rgba(0,0,0,.5)" : "none" }}>
        <div style={{ width: baseW, height: baseH, transform: `scale(${d.sc})`, transformOrigin: "top left" }}>
          <IPMASlideCard s={s} />
        </div>
      </div>}
    </div>);
}

/* ─────────────────────── shared portal viewer (Educator / generic) ── */
function IPMADeckOverlay({ onClose, title = "IPMA-D® Certification — Official Slideware", startIdx = 0 }) {
  const TOTAL = IPMA_SL.length;
  const [idx, setIdx] = React.useState(startIdx);
  const go = (n) => setIdx(Math.max(0, Math.min(TOTAL - 1, n)));
  React.useEffect(() => {
    function k(e) { if (e.key === "ArrowRight") go(idx + 1); else if (e.key === "ArrowLeft") go(idx - 1); else if (e.key === "Escape") onClose && onClose(); }
    window.addEventListener("keydown", k); return () => window.removeEventListener("keydown", k);
  }, [idx]);

  return ReactDOM.createPortal(
    <div style={{ position: "fixed", inset: 0, zIndex: 1400, background: "#06101e", display: "flex", flexDirection: "column", fontFamily: "var(--body)" }}>
      <div style={{ height: 54, flex: "none", display: "flex", alignItems: "center", gap: 14, padding: "0 20px", borderBottom: "1px solid #14233c" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: 11.5, fontWeight: 700, letterSpacing: ".08em", textTransform: "uppercase", color: "#f99d25" }}>● Official slideware · synced</span>
        <span style={{ fontSize: 15, fontWeight: 600, color: "#adc5e8", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{title}</span>
        <span style={{ fontSize: 13, fontWeight: 600, color: "#6b88b0" }}>Slide {idx + 1} / {TOTAL}</span>
        <button onClick={onClose} style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 13, padding: "7px 13px", borderRadius: 8, background: "rgba(255,255,255,.1)", color: "#fff", border: "none", cursor: "pointer", fontFamily: "var(--body)", fontWeight: 600 }}>✕ Close</button>
      </div>

      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 16, padding: "20px 16px", minHeight: 0 }}>
        <button onClick={() => go(idx - 1)} disabled={idx === 0} style={{ flex: "none", width: 50, height: 50, borderRadius: "50%", border: "none", background: "rgba(255,255,255,.1)", color: "#fff", cursor: idx === 0 ? "default" : "pointer", opacity: idx === 0 ? .3 : 1, fontSize: 22 }}>‹</button>
        <div style={{ width: "min(92vw, calc((100vh - 210px) * 1.7778))", height: "calc(100vh - 210px)", maxHeight: "calc(100vw / 1.7778)" }}>
          <ScaledSlide s={IPMA_SL[idx]} />
        </div>
        <button onClick={() => go(idx + 1)} disabled={idx === TOTAL - 1} style={{ flex: "none", width: 50, height: 50, borderRadius: "50%", border: "none", background: "rgba(255,255,255,.1)", color: "#fff", cursor: idx === TOTAL - 1 ? "default" : "pointer", opacity: idx === TOTAL - 1 ? .3 : 1, fontSize: 22 }}>›</button>
      </div>

      <div style={{ flex: "none", height: 76, display: "flex", gap: 8, padding: "0 20px 16px", overflowX: "auto", justifyContent: TOTAL < 14 ? "center" : "flex-start" }} className="scroll">
        {IPMA_SL.map((sl, i) =>
        <div key={i} onClick={() => go(i)} style={{ flex: "none", height: 56, aspectRatio: "16 / 9", borderRadius: 5, overflow: "hidden", cursor: "pointer", border: i === idx ? "2.5px solid #f99d25" : "2.5px solid transparent", opacity: i === idx ? 1 : .5, position: "relative" }}>
          <div style={{ position: "absolute", inset: 0, transform: "scale(0.105)", transformOrigin: "top left", width: "952%", height: "952%" }}><IPMASlideCard s={sl} /></div>
        </div>
        )}
      </div>
    </div>, document.body);
}

Object.assign(window, { IPMA_SL, IPMA_NOTES, IpmaIcon, IPMASlideCard, ScaledSlide, IPMADeckOverlay });
