/* MOXIE x Equals Amsterdam - Vibe Coding Session
   Thursday 28 May 2026, Equals Amsterdam.
   Built on Mission Relearn slide-deck-basics template. */

const { useEffect, useState } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "showLayoutLabels": false,
  "language": "NL",
  "accent": "coral"
}/*EDITMODE-END*/;

function useSlides(tweaks) {
  const lang = tweaks.language || "EN";
  const t = (en, nl) => (lang === "NL" ? nl : en);

  return [
    // 1. COVER
    { label: "01 Cover", section: "Cover",
      render: () => (
        <CoverHero
          eyebrow={t("MOXIE × EQUALS AMSTERDAM", "MOXIE × EQUALS AMSTERDAM")}
          title={t("Take back", "Neem het stuur")}
          titleAccent={t("the wheel.", "terug.")}
          subtitle={t("A hands-on AI session for women who want to feel autonomy.", "Een hands-on AI sessie voor vrouwen die autonomie willen voelen.")}
          presenter="Annet Kloprogge · Mission Relearn"
          date={t("Thursday 28 May 2026 · Equals Amsterdam", "Donderdag 28 mei 2026 · Equals Amsterdam")}
        />
      ),
    },

    // 2. FROM FEAR TO CONTROL
    { label: "02 From fear to control", section: "Why we are here",
      render: (i, n) => (
        <Headline
          dark
          idx={i} total={n}
          eyebrow={t("WHY WE ARE HERE", "WAAROM WE HIER ZIJN")}
          title={t("From fear", "Van angst")}
          titleAccent={t("to control.", "naar grip.")}
          footnote={t("AI talk can spike anxiety. This session does the opposite. You walk out knowing you can build.", "AI gesprekken kunnen nerveus maken. Deze sessie doet het tegenovergestelde. Je loopt naar buiten met de wetenschap dat je kunt bouwen.")}
        />
      ),
    },

    // 3. AUTONOMY
    { label: "03 Autonomy", section: "Why we are here",
      render: (i, n) => (
        <StatsThree
          idx={i} total={n}
          eyebrow={t("ONE WORD", "ÉÉN WOORD")}
          title={t("Autonomy.", "Autonomie.")}
          stats={[
            { num: "01", label: t("HOW YOU WORK", "HOE JE WERKT"), body: t("Choose your tools, your hours, your collaborators.", "Kies je tools, je uren, je samenwerkers.") },
            { num: "02", label: t("WHAT YOU BUILD", "WAT JE BOUWT"), body: t("Make the thing you wish existed. Today, not next quarter.", "Bouw het ding dat je wilt zien bestaan. Vandaag, niet volgend kwartaal.") },
            { num: "03", label: t("WHERE NEXT", "WAAR NU"), body: t("Decide where your career goes, on your terms.", "Bepaal zelf waar je carrière heen gaat, op jouw voorwaarden.") },
          ]}
        />
      ),
    },

    // 4. AI IS NOT ONE THING
    { label: "04 AI is fluid", section: "Reframe",
      render: (i, n) => (
        <LeadAndBody
          idx={i} total={n}
          eyebrow={t("FIRST, A REFRAME", "EERST EEN REFRAME")}
          title={t("AI is not one thing. It is fluid.", "AI is niet één ding. Het is vloeibaar.")}
          lead={t("There is no single definition.", "Er is geen enkele definitie.")}
          body={t("Even AI researchers have no exact definition. The field is constantly redefined: some topics are reclassified as non-AI, new ones emerge. Once you accept that, it stops being intimidating and starts being useful.", "Zelfs AI-onderzoekers hebben geen exacte definitie. Het veld wordt continu herdefinieerd: sommige onderwerpen worden niet meer als AI gezien, nieuwe komen erbij. Als je dat accepteert, stopt het intimiderend te zijn en wordt het bruikbaar.")}
        />
      ),
    },

    // 5. WHAT I BUILT IN 3 MONTHS
    { label: "05 What I built", section: "Build log",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("ALL BUILT WITH AI, ZERO TECHNICAL BACKGROUND", "ALLES MET AI, ZONDER TECHNISCHE ACHTERGROND")}
          title={t("What I built in three months.", "Wat ik bouwde in drie maanden.")}
          left={{ label: t("APPS & TOOLS", "APPS & TOOLS"), title: t("Six things people use", "Zes dingen die mensen gebruiken"),
            items: [
              t("SpeakUp, a Chrome extension + SaaS", "SpeakUp, een Chrome extensie + SaaS"),
              t("NextUp, a macOS app", "NextUp, een macOS app"),
              t("RelearnRest, a macOS app", "RelearnRest, een macOS app"),
              t("TinyTeacher, a learning tool", "TinyTeacher, een leertool"),
              t("A booking system for scheduling", "Een booking systeem voor planning"),
              t("A meeting prep tool, AI-powered", "Een meeting prep tool met AI"),
            ] }}
          right={{ label: t("SYSTEMS & OUTPUTS", "SYSTEMEN & OUTPUTS"), title: t("Four things behind the scenes", "Vier dingen achter de schermen"),
            items: [
              t("Second Brain, an AI knowledge system", "Second Brain, een AI kennissysteem"),
              t("Client proposals, automated", "Klant voorstellen, geautomatiseerd"),
              t("Event keynotes, presentation tools", "Event keynotes, presentatie tools"),
              t("AI boardroom advisor, decision support", "AI boardroom advisor, beslissingsondersteuning"),
            ] }}
        />
      ),
    },

    // 6. KEY MESSAGE
    { label: "06 Key message", section: "Build log",
      render: (i, n) => (
        <BigStatement
          idx={i} total={n}
          pre={t("Do not underestimate", "Onderschat niet")}
          accent={t("the start you can make today.", "de start die je vandaag kunt maken.")}
          post={t("Zero to a full AI-first consultancy with clients, in three months.", "Van nul naar een AI-first consultancy met klanten, in drie maanden.")}
          foot={t("You can do this too.", "Jij kunt dit ook.")}
        />
      ),
    },

    // 7. TODAY'S PROMISE
    { label: "07 Today's promise", section: "Outputs",
      render: (i, n) => (
        <ThreeCardGrid
          idx={i} total={n}
          eyebrow={t("WHAT YOU LEAVE WITH", "WAT JE MEENEEMT")}
          title={t("A working app you built yourself.", "Een werkende app die jij zelf bouwde.")}
          items={[
            { icon: "file-text", title: t("A PRD", "Een PRD"), body: t("A short brief that tells the AI exactly what to build, so it stops guessing.", "Een korte brief die de AI precies vertelt wat te bouwen, zodat hij stopt met gokken.") },
            { icon: "monitor", title: t("A first screen that runs", "Een eerste scherm dat werkt"), body: t("Not a mockup. A real, working page you can click through.", "Geen mockup. Een echte werkende pagina waar je doorheen klikt.") },
            { icon: "wallet", title: t("10 tips to spend less", "10 tips om minder uit te geven"), body: t("Tokens are the meter that runs every time you ask AI to do something. We keep it low.", "Tokens zijn de meter die loopt elke keer dat je AI iets vraagt. We houden hem laag.") },
          ]}
        />
      ),
    },

    // 8. 10 TIPS DIVIDER
    { label: "08 10 tips divider", section: "Divider",
      render: (i, n) => (
        <DividerHero
          num="01" idx={i} total={n}
          title={t("10 tips to build smart, not expensive.", "10 tips om slim te bouwen, niet duur.")}
          subtitle={t("Every prompt costs the platform money: they call it tokens. These tips keep your bill, and your patience, low.", "Elke prompt kost het platform geld: tokens. Deze tips houden je rekening, en je geduld, laag.")}
        />
      ),
    },

    // 9. TIPS 1-2 RESEARCH & INSIGHT
    { label: "09 Tips 1-2", section: "10 tips",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("RESEARCH & INSIGHT", "RESEARCH & INZICHT")}
          title={t("Tips 1 and 2.", "Tips 1 en 2.")}
          left={{ label: "01", title: "Google NotebookLM",
            items: [
              t("Upload anything, become an expert in 30 minutes", "Upload alles, word expert in 30 minuten"),
              t("Free, browser based, no setup", "Gratis, browser based, geen setup"),
            ] }}
          right={{ label: "02", title: t("Grok on X", "Grok op X"),
            items: [
              t("Real opinions from real people", "Echte meningen van echte mensen"),
              t("Free market validation", "Gratis marktvalidatie"),
            ] }}
        />
      ),
    },

    // 10. TIPS 3-4 PLAN BEFORE YOU SPEND
    { label: "10 Tips 3-4", section: "10 tips",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("PLAN BEFORE YOU SPEND", "PLAN VOOR JE UITGEEFT")}
          title={t("Tips 3 and 4.", "Tips 3 en 4.")}
          left={{ label: "03", title: t("Write a PRD first", "Schrijf eerst een PRD"),
            items: [
              t("Use ChatPRD, it is free", "Gebruik ChatPRD, gratis"),
              t("Do not open Lovable until you know what you are building", "Open Lovable pas als je weet wat je bouwt"),
            ] }}
          right={{ label: "04", title: t("Use a Prompt Engineer agent", "Gebruik een Prompt Engineer agent"),
            items: [
              t("In ChatGPT or any LLM", "In ChatGPT of een andere LLM"),
              t("Turns vague ideas into instructions a builder AI can follow", "Maakt van vage ideeën instructies die een bouwer-AI kan volgen"),
              t("No wasted credits", "Geen verspilde credits"),
            ] }}
        />
      ),
    },

    // 11. TIPS 5-6 MAKE IT LOOK LIKE YOU MEANT IT
    { label: "11 Tips 5-6", section: "10 tips",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("MAKE IT LOOK LIKE YOU MEANT IT", "ZORG DAT HET ZO BEDOELD LIJKT")}
          title={t("Tips 5 and 6.", "Tips 5 en 6.")}
          left={{ label: "05", title: t("Steal style", "Steel stijl"),
            items: [
              "Google Stitch, Dribbble, Pinterest",
              t("Share images, not adjectives", "Deel beelden, geen bijvoeglijke naamwoorden"),
              t("The pros do this too", "De pros doen dit ook"),
            ] }}
          right={{ label: "06", title: t("Use Google Fonts or FontPair", "Gebruik Google Fonts of FontPair"),
            items: [
              t("One real font choice", "Eén echte font keuze"),
              t("And your app stops looking AI-generated", "En je app ziet er niet meer AI-gegenereerd uit"),
            ] }}
        />
      ),
    },

    // 12. TIPS 7-8 BUILD SMALL LEARN FAST
    { label: "12 Tips 7-8", section: "10 tips",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("BUILD SMALL, LEARN FAST", "BOUW KLEIN, LEER SNEL")}
          title={t("Tips 7 and 8.", "Tips 7 en 8.")}
          left={{ label: "07", title: t("Start with one screen", "Begin met één scherm"),
            items: [
              t("Not the whole app", "Niet de hele app"),
              t("One thing that works", "Eén ding dat werkt"),
            ] }}
          right={{ label: "08", title: t("Ask AI to explain after every step", "Vraag AI om uitleg na elke stap"),
            items: [
              t("'What did you just do?'", "'Wat deed je net?'"),
              t("Now you are learning while you build", "Nu leer je terwijl je bouwt"),
            ] }}
        />
      ),
    },

    // 13. TIPS 9-10 SHIP BEFORE YOU ARE READY
    { label: "13 Tips 9-10", section: "10 tips",
      render: (i, n) => (
        <TwoColumn
          idx={i} total={n}
          eyebrow={t("SHIP BEFORE YOU ARE READY", "SHIP VOORDAT JE KLAAR BENT")}
          title={t("Tips 9 and 10.", "Tips 9 en 10.")}
          left={{ label: "09", title: t("Test with someone outside your head", "Test met iemand buiten je hoofd"),
            items: [
              t("Your mom, your kid, your neighbour", "Je moeder, je kind, je buur"),
              t("They see what you cannot", "Zij zien wat jij niet ziet"),
            ] }}
          right={{ label: "10", title: t("One-shot publish", "One-shot publish"),
            items: [
              t("Lovable + a clear PRD + a style reference", "Lovable + een heldere PRD + een stijl referentie"),
              t("Produces a shareable result in one prompt", "Levert een deelbaar resultaat in één prompt"),
              t("Send it to a friend before you go to bed", "Stuur het naar een vriendin voor je gaat slapen"),
            ] }}
        />
      ),
    },

    // 14. FAIL = FIRST ATTEMPT IN LEARNING
    { label: "14 FAIL", section: "Reframe",
      render: (i, n) => (
        <Headline
          dark
          idx={i} total={n}
          eyebrow={t("ONE MORE REFRAME", "NOG ÉÉN REFRAME")}
          title={t("FAIL stands for", "FAIL staat voor")}
          titleAccent={t("First Attempt In Learning.", "First Attempt In Learning.")}
          footnote={t("Every screen that does not work is one less between you and the one that does.", "Elk scherm dat niet werkt is er één minder tussen jou en het scherm dat wel werkt.")}
        />
      ),
    },

    // 15. WHAT COULD YOU BUILD IN 30 MINUTES
    { label: "15 What could you build", section: "Build time",
      render: (i, n) => (
        <Bullets
          idx={i} total={n}
          eyebrow={t("NEED AN IDEA?", "EEN IDEE NODIG?")}
          title={t("What could you build in 30 minutes?", "Wat zou jij in 30 minuten kunnen bouwen?")}
          items={[
            { head: t("A personal homepage", "Een persoonlijke homepage"), tail: t("Your story, your style, one shareable link", "Jouw verhaal, jouw stijl, één deelbare link") },
            { head: t("A birthday quiz for a friend", "Een verjaardagsquiz voor een vriendin"), tail: t("10 questions about them, scored at the end", "10 vragen over haar, met score op het eind") },
            { head: t("A habit tracker", "Een habit tracker"), tail: t("Tick a box, see your streak grow", "Vink een vakje aan, zie je streak groeien") },
            { head: t("A recipe roulette", "Een recept roulette"), tail: t("Spin the wheel, dinner sorted", "Draai aan het wiel, avondeten geregeld") },
            { head: t("A book or film journal", "Een boek of film journaal"), tail: t("What you read, what you thought, beautifully", "Wat je las, wat je dacht, mooi vormgegeven") },
            { head: t("A tiny tool for your work", "Een klein tool voor je werk"), tail: t("Anything repetitive you do every week", "Iets repetitiefs dat je elke week doet") },
          ]}
        />
      ),
    },

    // 16. SAFETY & ETHICS
    { label: "16 Safety and ethics", section: "Before you ship",
      render: (i, n) => (
        <ThreeCardGrid
          idx={i} total={n}
          eyebrow={t("BEFORE YOU SHIP", "VOOR JE PUBLICEERT")}
          title={t("Build responsibly.", "Bouw met verantwoordelijkheid.")}
          items={[
            { icon: "lock", title: t("Keep secrets secret", "Houd geheimen geheim"), body: t("API keys, database passwords, .env files. Never paste them into a public prompt or commit them to a repo. If it leaks, rotate it today.", "API keys, database wachtwoorden, .env bestanden. Plak ze nooit in een publieke prompt en commit ze niet. Als het lekt, vervang het vandaag.") },
            { icon: "shield-check", title: t("Mind the data", "Let op de data"), body: t("If your app collects names, emails, anything personal: GDPR applies. Ask before you collect. Delete on request. No silent tracking.", "Verzamel je namen, mails of iets persoonlijks: dan geldt de AVG. Vraag toestemming. Verwijder op verzoek. Geen stille tracking.") },
            { icon: "eye", title: t("Test before you share", "Test voor je deelt"), body: t("Click through every screen yourself. Credit images you borrowed. Add alt text. Your name is on it.", "Klik zelf elk scherm door. Geef credits aan beelden die je leende. Voeg alt-tekst toe. Jouw naam staat er onder.") },
          ]}
        />
      ),
    },

    // 17. START HERE (three steps + starter prompts)
    { label: "17 Start here", section: "Build time",
      render: (i, n) => {
        const steps = [
          t("Open your laptop.", "Open je laptop."),
          t("Pick a starter prompt below.", "Kies een starter prompt hieronder."),
          t("Paste it into ChatGPT or Claude. Ask for a PRD plus follow-up questions to sharpen the idea.", "Plak hem in ChatGPT of Claude. Vraag om een PRD plus vervolgvragen om je idee aan te scherpen."),
          t("Paste the PRD into lovable.dev. GO.", "Plak de PRD in lovable.dev. GO."),
        ];
        const prompts = [
          { label: t("Personal homepage", "Persoonlijke homepage"), body: "Build a one-page personal homepage. My name, one paragraph about what I do, three things I'm proud of, and a contact link. Modern minimal." },
          { label: t("Habit tracker", "Habit tracker"), body: "Build a simple habit tracker. One habit, checkbox per day, calendar view that shows my streak. Save in localStorage." },
          { label: t("Birthday quiz", "Verjaardagsquiz"), body: "Build a 10-question quiz about my friend [name]. One question per screen, score at the end. Playful design." },
          { label: t("Tiny work tool", "Tiny work tool"), body: "Build a tool that takes names + emails in a textarea and exports them as a CSV. One button, clear instructions." },
        ];
        return (
          <div className="slide bg-light" style={{ position: "relative" }}>
            <Frame>
              <div style={{ display: "flex", gap: 16, marginBottom: 24 }}>
                <div className="pill" style={{ fontSize: 22 }}>
                  <Icon name="hammer" size={20} color="var(--coral)" />
                  {t("BUILD TIME", "BOUW TIJD")}
                </div>
                <div className="pill" style={{ fontSize: 22 }}>
                  <Icon name="clock" size={20} color="var(--coral)" />
                  25 MIN
                </div>
              </div>
              <h2 className="slide-title" style={{ fontSize: TYPE_SCALE.title, maxWidth: 1500 }}>
                {t("Start", "Start")} <span className="gradient-text">{t("here.", "hier.")}</span>
              </h2>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1.25fr", gap: 72, marginTop: 56, flex: 1, alignItems: "start" }}>
                <ol style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 22 }}>
                  {steps.map((step, k) => (
                    <li key={k} style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 22, alignItems: "baseline" }}>
                      <span className="gradient-text" style={{ fontFamily: "var(--font-heading)", fontSize: 56, fontWeight: 700, lineHeight: 1, letterSpacing: "-0.02em", minWidth: 72 }}>
                        {String(k + 1).padStart(2, "0")}
                      </span>
                      <span style={{ fontSize: 32, lineHeight: 1.3 }}>{step}</span>
                    </li>
                  ))}
                </ol>
                <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
                  <div style={{ fontSize: 20, fontWeight: 600, letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--muted)", marginBottom: 4 }}>
                    {t("PICK A STARTER PROMPT", "KIES EEN STARTER PROMPT")}
                  </div>
                  {prompts.map((p, k) => (
                    <div key={k} style={{
                      background: "#fff", padding: "20px 24px", borderRadius: "var(--radius-lg)",
                      border: "1px solid var(--border)", boxShadow: "var(--shadow-sm)",
                    }}>
                      <div style={{ fontFamily: "var(--font-heading)", fontSize: 22, fontWeight: 700, color: "var(--coral)", marginBottom: 6 }}>
                        {p.label}
                      </div>
                      <div style={{ fontSize: 20, lineHeight: 1.4, color: "var(--ink)" }}>
                        {p.body}
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </Frame>
            <SlideChrome idx={i} total={n} />
            <LayoutLabel>Build time · Start here</LayoutLabel>
          </div>
        );
      },
    },

    // 18. QR · TAKE THE SLIDES HOME
    { label: "18 Slides + feedback", section: "Closing",
      render: (i, n) => (
        <div className="slide bg-light" style={{ position: "relative" }}>
          <Frame>
            <Eyebrow>{t("BEFORE YOU GO", "VOOR JE GAAT")}</Eyebrow>
            <h2 className="slide-title" style={{ fontSize: TYPE_SCALE.title, maxWidth: 1400 }}>
              {t("Scan, fill in,", "Scan, vul in,")} <span className="gradient-text">{t("get the slides.", "krijg de slides.")}</span>
            </h2>
            <div style={{ display: "grid", gridTemplateColumns: "1.1fr 1fr", gap: 80, marginTop: 64, flex: 1, alignItems: "center" }}>
              <div>
                <ol style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 28 }}>
                  {[
                    t("Scan the QR with your phone camera.", "Scan de QR met je telefooncamera."),
                    t("Two minutes of feedback. Optional testimonial.", "Twee minuten feedback. Testimonial mag, hoeft niet."),
                    t("Hit submit and the slides land in your inbox.", "Klik verzenden en de slides komen in je inbox."),
                  ].map((step, k) => (
                    <li key={k} style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 24, alignItems: "baseline" }}>
                      <span className="gradient-text" style={{ fontFamily: "var(--font-heading)", fontSize: 56, fontWeight: 700, lineHeight: 1, letterSpacing: "-0.02em", minWidth: 64 }}>
                        {String(k + 1).padStart(2, "0")}
                      </span>
                      <span style={{ fontSize: TYPE_SCALE.subtitle, lineHeight: 1.35 }}>{step}</span>
                    </li>
                  ))}
                </ol>
                <div style={{ marginTop: 48, fontSize: TYPE_SCALE.small, color: "var(--muted)", maxWidth: 560 }}>
                  {t("Cannot scan? Go to ", "Lukt scannen niet? Ga naar ")}
                  <span style={{ fontFamily: "var(--font-heading)", color: "var(--coral)", fontWeight: 600 }}>tinyurl.com/moxie-slides</span>
                </div>
              </div>
              <div style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
                <div style={{ background: "#fff", padding: 36, borderRadius: "var(--radius-2xl)", boxShadow: "var(--shadow-md)" }}>
                  <img src="assets/qr-feedback.png" alt="QR to MOXIE feedback form" style={{ width: 480, height: 480, display: "block" }} />
                  <div style={{ marginTop: 20, textAlign: "center", fontSize: 22, fontWeight: 600, letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--muted)" }}>
                    {t("Feedback + slides", "Feedback + slides")}
                  </div>
                </div>
              </div>
            </div>
          </Frame>
          <SlideChrome idx={i} total={n} />
          <LayoutLabel>QR · Feedback + slides</LayoutLabel>
        </div>
      ),
    },

    // 19. LET'S BUILD (closing)
    { label: "19 Let's build", section: "Closing",
      render: (i, n) => (
        <Closing
          idx={i} total={n}
          message={t("Let's build.", "Laten we bouwen.")}
          contact={[
            { icon: "globe", label: "Web", value: "missionrelearn.com" },
            { icon: "mail", label: "Mail", value: "annet@missionrelearn.com" },
            { icon: "linkedin", label: "LinkedIn", value: "/in/annetkloprogge" },
          ]}
        />
      ),
    },
  ];
}

/* ---------------- TWEAKS PANEL ---------------- */
function Tweaks() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  return (
    <TweaksPanel>
      <TweakSection title="Template">
        <TweakRadio
          label="Language"
          value={tweaks.language}
          onChange={(v) => setTweak("language", v)}
          options={[{ value: "EN", label: "EN" }, { value: "NL", label: "NL" }]}
        />
        <TweakToggle
          label="Show layout labels"
          value={tweaks.showLayoutLabels}
          onChange={(v) => setTweak("showLayoutLabels", v)}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

/* Inject Fullscreen + Edit-mode buttons into deck-stage's overlay (auto-hides with rest of nav). */
function installEditModeButton() {
  // Wait for deck-stage and its shadow overlay
  const stage = document.querySelector("deck-stage");
  if (!stage || !stage.shadowRoot) {
    setTimeout(installEditModeButton, 100);
    return;
  }
  const overlay = stage.shadowRoot.querySelector(".overlay");
  if (!overlay) {
    setTimeout(installEditModeButton, 100);
    return;
  }
  if (overlay.querySelector(".mr-injected-edit")) return;

  // Fullscreen helpers
  function isFullscreen() {
    return !!(document.fullscreenElement || document.webkitFullscreenElement);
  }
  function toggleFs() {
    if (isFullscreen()) {
      const exit = document.exitFullscreen || document.webkitExitFullscreen;
      if (exit) exit.call(document);
    } else {
      const el = document.documentElement;
      const req = el.requestFullscreen || el.webkitRequestFullscreen;
      if (req) req.call(el);
    }
  }

  // Add divider + fullscreen + edit buttons to existing overlay toolbar
  const divider = document.createElement("span");
  divider.className = "divider";
  overlay.appendChild(divider);

  const fsBtn = document.createElement("button");
  fsBtn.className = "btn reset mr-injected-fs";
  fsBtn.type = "button";
  fsBtn.setAttribute("aria-label", "Fullscreen aan/uit (F)");
  fsBtn.setAttribute("title", "Fullscreen aan/uit (toets: F)");
  fsBtn.innerHTML = 'Fullscreen<span class="kbd">F</span>';
  fsBtn.addEventListener("click", toggleFs);
  overlay.appendChild(fsBtn);

  const editBtn = document.createElement("button");
  editBtn.className = "btn reset mr-injected-edit";
  editBtn.type = "button";
  editBtn.setAttribute("aria-label", "Edit mode aan/uit (E)");
  editBtn.setAttribute("title", "Edit mode aan/uit (toets: E)");
  editBtn.innerHTML = 'Edit<span class="kbd">E</span>';
  overlay.appendChild(editBtn);

  const exportBtn = document.createElement("button");
  exportBtn.className = "btn reset mr-injected-export";
  exportBtn.type = "button";
  exportBtn.setAttribute("aria-label", "Exporteer wijzigingen naar clipboard (X)");
  exportBtn.setAttribute("title", "Exporteer wijzigingen naar clipboard (toets: X)");
  exportBtn.innerHTML = 'Export<span class="kbd">X</span>';
  overlay.appendChild(exportBtn);

  async function exportEdits() {
    const edits = collectEdits();
    const text = formatEdits(edits);
    try {
      await navigator.clipboard.writeText(text);
      if (edits.length === 0) {
        showToast("Geen wijzigingen sinds edit-mode aanstond.");
      } else {
        const total = edits.reduce((n, e) => n + e.changes.length, 0);
        showToast(total + " wijziging" + (total === 1 ? "" : "en") + " op " + edits.length + " slide" + (edits.length === 1 ? "" : "s") + " gekopieerd naar clipboard.");
      }
    } catch (err) {
      showToast("Clipboard mislukt: " + err.message, true);
      console.log("[export]", text);
    }
  }
  exportBtn.addEventListener("click", exportEdits);

  // Custom styling for active edit-mode button (shadow DOM scoped)
  const styleTag = document.createElement("style");
  styleTag.textContent = `
    .mr-injected-edit[data-on="1"] {
      background: rgba(237,112,89,0.95);
      color: #fff;
    }
    .mr-injected-edit[data-on="1"] .kbd {
      background: rgba(255,255,255,0.22);
      color: #fff;
    }
    .mr-injected-edit[data-on="1"]:hover {
      background: rgba(237,112,89,1);
    }
  `;
  stage.shadowRoot.appendChild(styleTag);

  let editOn = false;
  const setMode = (on) => {
    editOn = on;
    document.body.classList.toggle("edit-mode", on);
    applyEditMode(on);
    editBtn.setAttribute("data-on", on ? "1" : "0");
    editBtn.innerHTML = (on ? "Klaar" : "Edit") + '<span class="kbd">E</span>';
  };
  editBtn.addEventListener("click", () => setMode(!editOn));

  // Keyboard shortcuts (skip when typing)
  document.addEventListener("keydown", (e) => {
    if (e.target && (e.target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName))) return;
    if (e.key === "e" || e.key === "E") {
      e.preventDefault();
      setMode(!editOn);
    } else if (e.key === "f" || e.key === "F") {
      e.preventDefault();
      toggleFs();
    } else if (e.key === "x" || e.key === "X") {
      e.preventDefault();
      exportEdits();
    }
  });
}

/* Walk DOM, mark every element with direct text content as editable + snapshot originals. */
function applyEditMode(on) {
  const stage = document.querySelector("deck-stage");
  if (!stage) return;
  stage.querySelectorAll("section").forEach(section => {
    section.querySelectorAll("*").forEach(el => {
      // Skip non-text-bearing tags
      if (/^(SCRIPT|STYLE|SVG|PATH|RECT|CIRCLE|LINE|POLYLINE|POLYGON|G|USE|DEFS|IMG)$/i.test(el.tagName)) return;
      // An element is text-bearing if it has at least one direct text-node child with non-empty content
      const hasDirectText = Array.from(el.childNodes).some(
        n => n.nodeType === 3 && n.textContent.trim().length > 0
      );
      if (!hasDirectText) return;
      if (on) {
        el.setAttribute("contenteditable", "plaintext-only");
        el.classList.add("mr-edit");
        if (!("originalText" in el.dataset)) {
          el.dataset.originalText = el.textContent;
        }
      } else {
        el.removeAttribute("contenteditable");
        el.classList.remove("mr-edit");
        // Keep data-original-text so Export still works after toggling off.
      }
    });
  });
}

/* Collect every snapshotted element whose text differs from original (works even when edit-mode is off). */
function collectEdits() {
  const stage = document.querySelector("deck-stage");
  if (!stage) return [];
  const out = [];
  stage.querySelectorAll("section").forEach(section => {
    const label = section.getAttribute("data-label") || "(no label)";
    const changed = Array.from(section.querySelectorAll("[data-original-text]"))
      .filter(el => el.dataset.originalText !== el.textContent);
    // Drop ancestors when a descendant also reports a change (the descendant is more specific).
    const final = changed.filter(el => !changed.some(o => o !== el && el.contains(o)));
    const changes = final.map(el => ({ orig: el.dataset.originalText, curr: el.textContent }));
    if (changes.length) out.push({ label, changes });
  });
  return out;
}

function formatEdits(edits) {
  if (!edits.length) return "Geen wijzigingen sinds edit-mode aanstond.";
  const lines = ["# MOXIE deck — exported edits", "# Datum: " + new Date().toISOString().slice(0, 16).replace("T", " "), ""];
  edits.forEach(({ label, changes }) => {
    lines.push("## " + label);
    changes.forEach(({ orig, curr }) => {
      lines.push("OUD: " + JSON.stringify(orig));
      lines.push("NIEUW: " + JSON.stringify(curr));
      lines.push("");
    });
  });
  return lines.join("\n");
}

function showToast(message, isError = false) {
  let toast = document.getElementById("mr-toast");
  if (toast) toast.remove();
  toast = document.createElement("div");
  toast.id = "mr-toast";
  toast.textContent = message;
  Object.assign(toast.style, {
    position: "fixed",
    top: "60px",
    left: "50%",
    transform: "translateX(-50%)",
    padding: "12px 22px",
    background: isError ? "#dc2626" : "#1D2237",
    color: "#fff",
    fontFamily: "var(--font-body)",
    fontSize: "14px",
    fontWeight: "600",
    borderRadius: "9999px",
    boxShadow: "0 8px 28px rgba(0,0,0,0.25)",
    zIndex: "2147483647",
    pointerEvents: "none",
    maxWidth: "80vw",
    textAlign: "center",
  });
  document.body.appendChild(toast);
  setTimeout(() => { toast.style.opacity = "0"; toast.style.transition = "opacity 300ms"; }, 2400);
  setTimeout(() => toast.remove(), 2800);
}

/* ---------------- MAIN APP ---------------- */
function App() {
  const [tweaks] = useTweaks(TWEAK_DEFAULTS);
  const slides = useSlides(tweaks);

  useEffect(() => {
    const stage = document.querySelector("deck-stage");
    if (!stage) return;
    stage.innerHTML = "";
    const total = slides.length;
    slides.forEach((slide, i) => {
      const sec = document.createElement("section");
      sec.setAttribute("data-label", slide.label);
      stage.appendChild(sec);
      const root = ReactDOM.createRoot(sec);
      root.render(slide.render(i + 1, total));
    });
    setTimeout(() => {
      if (window.lucide) window.lucide.createIcons();
      // Re-apply edit-mode after re-render if it is currently on
      applyEditMode(document.body.classList.contains("edit-mode"));
      installEditModeButton();
    }, 80);
  }, [tweaks.language, tweaks.accent]);

  useEffect(() => {
    document.body.classList.toggle("hide-labels", !tweaks.showLayoutLabels);
  }, [tweaks.showLayoutLabels]);

  return <Tweaks />;
}

const tweaksRoot = document.createElement("div");
document.body.appendChild(tweaksRoot);
ReactDOM.createRoot(tweaksRoot).render(<App />);
