/* global React, ReactDOM, gsap, ScrollTrigger, MotionPathPlugin */
/* eslint-disable */
const { useState, useEffect, useMemo, useRef, useCallback } = React;

/* ============================================================
   GSAP plugin registration
   ============================================================ */
if (typeof gsap !== "undefined") {
  gsap.registerPlugin(ScrollTrigger);
  if (typeof MotionPathPlugin !== "undefined") gsap.registerPlugin(MotionPathPlugin);
}

/* ============================================================
   Storage helpers
   ============================================================ */
const STORAGE_KEY = "mariany_rsvps_v1";
function loadRsvps() {
  try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); }
  catch { return []; }
}
function saveRsvp(r) {
  const all = loadRsvps();
  all.unshift({ ...r, id: Date.now(), createdAt: new Date().toISOString() });
  localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
}

/* ============================================================
   Tweaks defaults
   ============================================================ */
const TWEAK_DEFAULTS = {
  palette: "blush",
  showFlyingButterflies: true,
  showParticles: true,
  particleDensity: 28,
  videoLabel: "Mariany",
};

const PALETTES = {
  blush: {
    name: "Blush Garden",
    "--blush-50": "oklch(0.985 0.008 10)",
    "--blush-100": "oklch(0.965 0.018 12)",
    "--blush-200": "oklch(0.93 0.04 10)",
    "--blush-300": "oklch(0.88 0.07 10)",
    "--blush-400": "oklch(0.82 0.11 10)",
    "--candy-500": "oklch(0.74 0.16 12)",
    "--rose-600": "oklch(0.62 0.18 14)",
    "--rose-700": "oklch(0.48 0.16 16)",
    "--rose-900": "oklch(0.28 0.10 18)",
    "--lilac-200": "oklch(0.92 0.035 320)",
  },
  candy: {
    name: "Candy Bloom",
    "--blush-50": "oklch(0.98 0.012 350)",
    "--blush-100": "oklch(0.96 0.026 350)",
    "--blush-200": "oklch(0.92 0.05 350)",
    "--blush-300": "oklch(0.86 0.09 350)",
    "--blush-400": "oklch(0.78 0.14 350)",
    "--candy-500": "oklch(0.7 0.2 350)",
    "--rose-600": "oklch(0.58 0.22 0)",
    "--rose-700": "oklch(0.44 0.18 5)",
    "--rose-900": "oklch(0.26 0.12 8)",
    "--lilac-200": "oklch(0.9 0.05 310)",
  },
  pearl: {
    name: "Pearl Petal",
    "--blush-50": "oklch(0.99 0.004 20)",
    "--blush-100": "oklch(0.975 0.012 20)",
    "--blush-200": "oklch(0.95 0.025 20)",
    "--blush-300": "oklch(0.91 0.05 20)",
    "--blush-400": "oklch(0.86 0.08 18)",
    "--candy-500": "oklch(0.78 0.12 15)",
    "--rose-600": "oklch(0.66 0.14 18)",
    "--rose-700": "oklch(0.52 0.12 20)",
    "--rose-900": "oklch(0.32 0.08 22)",
    "--lilac-200": "oklch(0.94 0.025 320)",
  },
};

function applyPalette(key) {
  const p = PALETTES[key] || PALETTES.blush;
  const root = document.documentElement;
  Object.entries(p).forEach(([k, v]) => {
    if (k.startsWith("--")) root.style.setProperty(k, v);
  });
}

/* ============================================================
   GSAP reveal hook — replaces IntersectionObserver
   ============================================================ */
function useGsapReveal(active) {
  useEffect(() => {
    if (!active || typeof gsap === "undefined") return;

    // Immediately reveal elements in view
    const revealEls = document.querySelectorAll(".reveal:not(.in)");
    revealEls.forEach((el) => {
      ScrollTrigger.create({
        trigger: el,
        start: "top 88%",
        onEnter: () => {
          gsap.to(el, {
            opacity: 1,
            y: 0,
            duration: 1.1,
            ease: "power3.out",
            overwrite: "auto",
          });
          el.classList.add("in");
        },
        once: true,
      });

      // Reveal immediately if already in viewport
      const rect = el.getBoundingClientRect();
      if (rect.top < window.innerHeight * 0.95) {
        gsap.to(el, { opacity: 1, y: 0, duration: 1.1, ease: "power3.out", overwrite: "auto" });
        el.classList.add("in");
      }
    });
  }, [active]);
}

/* ============================================================
   GSAP scene entrance hook
   ============================================================ */
function useGsapScenes(active) {
  const [activeScene, setActiveScene] = useState("hero");

  useEffect(() => {
    if (!active || typeof gsap === "undefined") return;

    const scenes = document.querySelectorAll("section[data-scene]");
    if (!scenes.length) return;

    const triggers = [];

    scenes.forEach((scene) => {
      const inner = scene.querySelector(".scene-inner");
      if (!inner) return;

      // Entrance
      const enterTrigger = ScrollTrigger.create({
        trigger: scene,
        start: "top 65%",
        onEnter: () => {
          gsap.to(inner, {
            opacity: 1,
            y: 0,
            scale: 1,
            filter: "blur(0px)",
            duration: 1.4,
            ease: "power3.out",
          });
          scene.classList.add("in");
          scene.classList.remove("past");
          setActiveScene(scene.dataset.scene);

          // Stagger child reveals
          const children = scene.querySelectorAll(".reveal:not(.in)");
          gsap.to(children, {
            opacity: 1,
            y: 0,
            duration: 1.1,
            ease: "power3.out",
            stagger: 0.12,
            delay: 0.2,
            onStart() { children.forEach((c) => c.classList.add("in")); },
          });
        },
        once: false,
      });

      // Exit upward
      const exitTrigger = ScrollTrigger.create({
        trigger: scene,
        start: "bottom 20%",
        onLeave: () => {
          gsap.to(inner, {
            opacity: 0.15,
            y: -30,
            scale: 0.97,
            filter: "blur(6px)",
            duration: 0.8,
            ease: "power2.in",
          });
          scene.classList.add("past");
        },
        onEnterBack: () => {
          gsap.to(inner, {
            opacity: 1,
            y: 0,
            scale: 1,
            filter: "blur(0px)",
            duration: 1.0,
            ease: "power3.out",
          });
          scene.classList.remove("past");
          setActiveScene(scene.dataset.scene);
        },
      });

      triggers.push(enterTrigger, exitTrigger);
    });

    // Always show first scene
    const first = scenes[0];
    if (first) {
      const fi = first.querySelector(".scene-inner");
      if (fi) {
        gsap.set(fi, { opacity: 1, y: 0, scale: 1, filter: "blur(0px)" });
        first.classList.add("in");
        first.querySelectorAll(".reveal").forEach((el) => {
          gsap.to(el, { opacity: 1, y: 0, duration: 1.1, ease: "power3.out", stagger: 0.1 });
          el.classList.add("in");
        });
      }
    }

    return () => {
      triggers.forEach((t) => t.kill());
    };
  }, [active]);

  return activeScene;
}

/* ============================================================
   Topbar
   ============================================================ */
function Topbar({ route, go }) {
  const ref = useRef(null);

  useEffect(() => {
    if (!ref.current || typeof gsap === "undefined") return;
    gsap.fromTo(ref.current,
      { y: -60, opacity: 0 },
      { y: 0, opacity: 1, duration: 1.2, ease: "power3.out", delay: 0.3 }
    );
  }, []);

  return (
    <nav className="topbar" ref={ref} aria-label="Navegação">
      <span className="brand">MARIANY MEU PRIMEIRO ANINHO</span>
      <a className={route === "home"         ? "active" : ""} onClick={() => go("home")}>Convite</a>
      <a className={route === "presentes"    ? "active" : ""} onClick={() => go("presentes")}>Presentes</a>
      <a className={route === "confirmacoes" ? "active" : ""} onClick={() => go("confirmacoes")}>Admin</a>
    </nav>
  );
}

/* ============================================================
   Audio toggle
   ============================================================ */
function AudioToggle() {
  const [on, setOn] = useState(false);
  const audioRef = useRef(null);

  useEffect(() => {
    const audio = new Audio("/musica.mp3");
    audio.loop = true;
    audio.volume = 0.45;
    audioRef.current = audio;
    return () => { audio.pause(); audio.src = ""; };
  }, []);

  const toggle = () => {
    const audio = audioRef.current;
    if (!audio) return;
    if (!on) {
      audio.play().then(() => setOn(true)).catch(() => {});
    } else {
      audio.pause();
      setOn(false);
    }
  };

  return (
    <button className="audio-toggle" onClick={toggle}
      aria-label={on ? "Pausar música" : "Tocar música"}>
      {on ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <path d="M9 18V5l12-2v13" /><circle cx="6" cy="18" r="3" /><circle cx="18" cy="16" r="3" />
        </svg>
      ) : (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <path d="M9 18V5l12-2v13" /><circle cx="6" cy="18" r="3" /><circle cx="18" cy="16" r="3" />
          <line x1="2" y1="2" x2="22" y2="22" />
        </svg>
      )}
    </button>
  );
}

/* ============================================================
   Hero — 10-second lock + GSAP cinematic entrance
   ============================================================ */
const HERO_LOCK_SECONDS = 10;

function Hero({ tweaks, locked, secondsLeft }) {
  const stageRef = useRef(null);
  const progress = 1 - secondsLeft / HERO_LOCK_SECONDS;
  const R = 32;
  const C = 2 * Math.PI * R;
  const dashOffset = C * (1 - progress);

  // Cinematic entrance timeline
  useEffect(() => {
    if (!stageRef.current || typeof gsap === "undefined") return;
    const stage = stageRef.current;
    const tl = gsap.timeline({ delay: 0.5 });

    // Video wrap scales in from center
    tl.fromTo(stage.querySelector(".video-wrap"),
      { scale: 0.7, opacity: 0, y: 40 },
      { scale: 1, opacity: 1, y: 0, duration: 1.6, ease: "back.out(1.3)" }
    );

    // Left titles stagger in
    tl.fromTo(stage.querySelectorAll(".hero-side.left .hero-title, .hero-side.left .hero-lede, .hero-side.left .hero-meta"),
      { x: -40, opacity: 0 },
      { x: 0, opacity: 1, duration: 1.2, ease: "power3.out", stagger: 0.15 },
      "-=1.2"
    );

    // Right titles stagger in
    tl.fromTo(stage.querySelectorAll(".hero-side.right .hero-title, .hero-side.right .hero-lede, .hero-side.right .hero-meta"),
      { x: 40, opacity: 0 },
      { x: 0, opacity: 1, duration: 1.2, ease: "power3.out", stagger: 0.15 },
      "-=1.2"
    );
  }, []);

  // Subtle continuous parallax on video-wrap
  useEffect(() => {
    if (!stageRef.current || typeof gsap === "undefined") return;
    const vw = stageRef.current.querySelector(".video-wrap");
    if (!vw) return;
    const onMove = (e) => {
      const mx = (e.clientX / window.innerWidth - 0.5) * 14;
      const my = (e.clientY / window.innerHeight - 0.5) * 10;
      gsap.to(vw, { x: mx, y: my, duration: 1.4, ease: "power1.out", overwrite: "auto" });
    };
    window.addEventListener("mousemove", onMove);
    return () => window.removeEventListener("mousemove", onMove);
  }, []);

  return (
    <section className="hero scene scene-hero" data-screen-label="01 Hero" data-scene="hero">
      <div className="scene-inner" style={{ display: "contents" }}>
        <Particles count={tweaks.showParticles ? tweaks.particleDensity : 0} />
        <StaticButterflies items={[
          { top: "12%", left: "6%",  size: 95, variant: 1, delay: 0.2, rot: -8 },
          { top: "20%", right: "8%", size: 78, variant: 2, delay: 0.6, rot: 12 },
          { top: "62%", left: "4%",  size: 64, variant: 3, delay: 1.1, rot: 8 },
          { top: "70%", right: "5%", size: 88, variant: 4, delay: 0.4, rot: -10 },
        ]} />
        {tweaks.showFlyingButterflies && <FlyingButterflies count={2} />}

        <div className="hero-stage" ref={stageRef}>
          <div className="hero-side left">
            <h1 className="hero-title reveal in">
              Há 1 ano…<br />
              <em>o nosso mundo</em>
              <em style={{ fontSize: "1.1em" }}>floresceu ✿</em>
            </h1>
            <p className="hero-lede reveal in">
              Da forma mais linda que poderíamos imaginar.
              Hoje, entre flores e borboletas, celebramos o primeiro
              capítulo do nosso conto encantado.
            </p>
          </div>

          <div className="video-wrap reveal in" aria-label="Vídeo da aniversariante">
            <video
              src="/mariany.mp4"
              autoPlay
              muted
              loop
              playsInline
              style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }}
            />
          </div>

          <div className="hero-side right">
            <h1 className="hero-title reveal in" style={{ fontSize: "clamp(40px, 5.5vw, 76px)" }}>
              Mariany
              <em>nossa princesa</em>
            </h1>
            <p className="hero-lede reveal in">
              Está completando seu primeiro aninho e
              queremos viver esse momento mágico ao seu lado.
            </p>
            <div className="hero-meta reveal in">
              <span><span className="dot"></span>13 · 06 · 2026</span>
              <span><span className="dot"></span>16h00</span>
              <span><span className="dot"></span>Chácara 3 Irmãos</span>
            </div>
          </div>
        </div>
      </div>

      <div className={`countdown-ring${locked ? "" : " done"}`} aria-live="polite">
        <div className="countdown-pill">
          <svg className="ring-svg" viewBox="0 0 80 80" aria-hidden="true">
            <circle className="ring-bg" cx="40" cy="40" r={R} />
            <circle className="ring-fg" cx="40" cy="40" r={R}
              strokeDasharray={C} strokeDashoffset={dashOffset} />
          </svg>
          <div className="countdown-num">
            {secondsLeft > 0
              ? <><span className="n">{secondsLeft}</span><span className="s">seg</span></>
              : <span className="check">✿</span>
            }
          </div>
        </div>
        <div className="countdown-label">
          {locked ? "assista nossa princesa" : "agora desça suavemente"}
        </div>
      </div>

      <div className={`scroll-cue ${locked ? "locked" : "unlocked"}`}>
        <span>desça suavemente</span>
        <span className="line"></span>
      </div>
    </section>
  );
}

/* ============================================================
   Garden (scene 2)
   ============================================================ */
function GardenSection({ tweaks }) {
  return (
    <section className="scene scene-garden garden" data-screen-label="02 Jardim" data-scene="garden">

      {/* ── Atmosphere: direct children of section (z-index 1) — never overlaps text ── */}
      {tweaks.showParticles && <Particles count={Math.round(tweaks.particleDensity * 0.6)} />}

      {/* Flowers — only extreme corners */}
      <Flowers items={[
        { top: "6%",    left: "0%",   size: 100, variant: 1, delay: 0.2 },
        { top: "8%",    right: "0%",  size: 84,  variant: 2, delay: 0.7 },
        { bottom: "4%", left: "1%",   size: 92,  variant: 3, delay: 0.5 },
        { bottom: "6%", right: "0%",  size: 78,  variant: 1, delay: 1.0 },
      ]} />

      {/* Butterflies — 10 spread along left + right edges only */}
      <StaticButterflies items={[
        // Left edge column
        { top: "8%",   left: "1%",  size: 88, variant: 1, delay: 0.2, rot: -8,  opacity: 0.88 },
        { top: "24%",  left: "2%",  size: 70, variant: 3, delay: 0.7, rot: 6,   opacity: 0.82 },
        { top: "42%",  left: "1%",  size: 62, variant: 5, delay: 1.1, rot: -5,  opacity: 0.78 },
        { top: "60%",  left: "2%",  size: 74, variant: 2, delay: 0.4, rot: 10,  opacity: 0.85 },
        { bottom: "8%",left: "1%",  size: 58, variant: 4, delay: 1.3, rot: -12, opacity: 0.75 },
        // Right edge column
        { top: "6%",   right: "1%", size: 82, variant: 2, delay: 0.5, rot: 12,  opacity: 0.88 },
        { top: "22%",  right: "2%", size: 66, variant: 4, delay: 0.9, rot: -7,  opacity: 0.82 },
        { top: "40%",  right: "1%", size: 78, variant: 1, delay: 0.3, rot: 5,   opacity: 0.80 },
        { top: "58%",  right: "2%", size: 60, variant: 5, delay: 1.5, rot: -10, opacity: 0.75 },
        { bottom: "6%",right: "1%", size: 72, variant: 3, delay: 0.8, rot: 8,   opacity: 0.85 },
      ]} />

      {tweaks.showFlyingButterflies && <FlyingButterflies count={3} />}

      {/* ── Text: inside scene-inner (z-index 2) — always above decorative layer ── */}
      <div className="scene-inner">
        <div className="block-inner">
          <div className="section-label reveal">Capítulo Um</div>
          <h2 className="section-title reveal" style={{ marginInline: "auto" }}>
            Entre flores encantadas e <em>brilho no ar</em>
          </h2>
          <p className="section-body reveal" style={{ marginInline: "auto" }}>
            Borboletas dançam ao vento e cada pétala carrega um pedacinho de fantasia.
            Preparamos uma celebração cheia de amor, magia e memórias inesquecíveis —
            como um jardim que floresce só uma vez por ano.
          </p>
          <div className="divider reveal" aria-hidden="true">
            <span className="line"></span>
            <span style={{ fontSize: 18 }}>✿</span>
            <span className="line"></span>
          </div>
        </div>
      </div>

      <div className="scene-divider" aria-hidden="true"></div>
    </section>
  );
}

/* ============================================================
   Emotional (scene 3)
   ============================================================ */
function EmotionalSection() {
  return (
    <section className="scene scene-emotional emotional" data-screen-label="03 Conto" data-scene="emotional">

      {/* ── Atmosphere: direct children of section ── */}
      <Flowers items={[
        { top: "5%",    left: "0%",   size: 80,  variant: 2, delay: 0.3, opacity: 0.75 },
        { top: "7%",    right: "0%",  size: 70,  variant: 3, delay: 0.6, opacity: 0.72 },
        { bottom: "5%", left: "0%",   size: 88,  variant: 1, delay: 0.9, opacity: 0.78 },
        { bottom: "7%", right: "0%",  size: 74,  variant: 2, delay: 0.4, opacity: 0.72 },
      ]} />

      <StaticButterflies items={[
        // Left edge — 5 butterflies cascading down
        { top: "7%",   left: "1%",  size: 90, variant: 3, delay: 0.4,  rot: -10, opacity: 0.90 },
        { top: "25%",  left: "2%",  size: 68, variant: 1, delay: 0.9,  rot: 7,   opacity: 0.82 },
        { top: "44%",  left: "1%",  size: 76, variant: 5, delay: 0.6,  rot: -5,  opacity: 0.80 },
        { top: "63%",  left: "2%",  size: 60, variant: 2, delay: 1.2,  rot: 12,  opacity: 0.75 },
        { bottom: "6%",left: "1%",  size: 82, variant: 4, delay: 0.3,  rot: -8,  opacity: 0.85 },
        // Right edge — 5 butterflies cascading down
        { top: "5%",   right: "1%", size: 84, variant: 4, delay: 0.7,  rot: 14,  opacity: 0.90 },
        { top: "23%",  right: "2%", size: 72, variant: 2, delay: 1.0,  rot: -6,  opacity: 0.82 },
        { top: "42%",  right: "1%", size: 64, variant: 3, delay: 0.5,  rot: 8,   opacity: 0.78 },
        { top: "61%",  right: "2%", size: 78, variant: 5, delay: 1.4,  rot: -12, opacity: 0.75 },
        { bottom: "5%",right: "1%", size: 70, variant: 1, delay: 0.8,  rot: 5,   opacity: 0.85 },
      ]} />

      <FlyingButterflies count={2} />

      {/* ── Text: inside scene-inner (z-index 2) ── */}
      <div className="scene-inner">
        <div className="block-inner">
          <div className="section-label reveal" style={{ display: "block", textAlign: "center" }}>
            Um capítulo encantado
          </div>
          <p className="quote reveal">
            Cada sorriso da nossa princesa transformou nossos dias
            em um verdadeiro conto encantado.
          </p>
          <p className="quote-byline reveal" style={{ marginTop: 32 }}>
            ✦ &nbsp; com amor, papai &amp; mamãe &nbsp; ✦
          </p>
          <p className="section-body reveal" style={{ marginInline: "auto", marginTop: 36, textAlign: "center" }}>
            Agora queremos celebrar esse capítulo tão especial ao lado das pessoas
            que amamos. <span style={{ color: "var(--candy-500)" }}>♡</span>
          </p>
        </div>
      </div>

      <div className="scene-divider" aria-hidden="true"></div>
    </section>
  );
}

/* ============================================================
   Event info (scene 4)
   ============================================================ */
function EventSection({ onRSVP }) {
  return (
    <section className="scene scene-event" data-screen-label="04 Evento" data-scene="event">
      <StaticButterflies items={[
        { top: "6%",   left: "1%",  size: 78, variant: 5, delay: 0.5, rot: -8,  opacity: 0.85 },
        { top: "30%",  left: "2%",  size: 60, variant: 2, delay: 1.0, rot: 6,   opacity: 0.78 },
        { bottom: "8%",left: "1%",  size: 70, variant: 4, delay: 0.3, rot: -10, opacity: 0.80 },
        { top: "6%",   right: "1%", size: 72, variant: 1, delay: 0.8, rot: 10,  opacity: 0.85 },
        { top: "32%",  right: "2%", size: 64, variant: 3, delay: 0.6, rot: -7,  opacity: 0.78 },
        { bottom: "7%",right: "1%", size: 68, variant: 5, delay: 1.2, rot: 8,   opacity: 0.80 },
      ]} />
      <div className="scene-inner">

        <div className="block-inner" style={{ textAlign: "center" }}>
          <div className="section-label reveal" style={{ display: "block" }}>Os detalhes</div>
          <h2 className="section-title reveal" style={{ marginInline: "auto" }}>
            Você está convidado para um <em>dia mágico</em>
          </h2>

          <div className="event-grid reveal">
            <div className="event-card">
              <div className="icon">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="3" y="5" width="18" height="16" rx="3" /><path d="M3 10h18M8 3v4M16 3v4" />
                </svg>
              </div>
              <div className="lbl">Data</div>
              <div className="val">13 de Junho</div>
              <div className="sub">Sábado, 2026</div>
            </div>
            <div className="event-card">
              <div className="icon">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" />
                </svg>
              </div>
              <div className="lbl">Horário</div>
              <div className="val">16:00</div>
              <div className="sub">Recepção a partir das 15h30</div>
            </div>
            <div className="event-card">
              <div className="icon">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M12 21s-7-6.5-7-12a7 7 0 0114 0c0 5.5-7 12-7 12z" /><circle cx="12" cy="9" r="2.4" />
                </svg>
              </div>
              <div className="lbl">Local</div>
              <div className="val">Chácara 3 Irmãos</div>
              <div className="sub">Barra do Farias</div>
            </div>
          </div>

          <div className="reveal" style={{ display: "flex", gap: 14, justifyContent: "center", flexWrap: "wrap", marginTop: 12 }}>
            <a className="btn btn-ghost" href="https://share.google/YKMBDjooUf9eno187" target="_blank" rel="noopener">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M12 21s-7-6.5-7-12a7 7 0 0114 0c0 5.5-7 12-7 12z" /><circle cx="12" cy="9" r="2.4" />
              </svg>
              Ver localização
            </a>
            <button className="btn btn-primary" onClick={onRSVP}>Confirmar Presença</button>
          </div>
        </div>
      </div>
      <div className="scene-divider" aria-hidden="true"></div>
    </section>
  );
}

/* ============================================================
   Final (scene 5)
   ============================================================ */
function FinalSection({ onRSVP }) {
  return (
    <section className="scene scene-final final" data-screen-label="05 Final" data-scene="final">
      <FlyingButterflies count={5} />
      <Particles count={36} />
      <Flowers items={[
        { top: "5%",    left: "0%",  size: 96, variant: 1, delay: 0.2 },
        { top: "5%",    right: "0%", size: 80, variant: 2, delay: 0.6 },
        { bottom: "4%", left: "0%",  size: 88, variant: 3, delay: 0.9 },
        { bottom: "5%", right: "0%", size: 82, variant: 1, delay: 0.4 },
      ]} />
      <StaticButterflies items={[
        { top: "8%",   left: "1%",  size: 90, variant: 1, delay: 0.3,  rot: -8,  opacity: 0.90 },
        { top: "28%",  left: "2%",  size: 72, variant: 3, delay: 0.8,  rot: 6,   opacity: 0.82 },
        { top: "52%",  left: "1%",  size: 66, variant: 5, delay: 1.2,  rot: -10, opacity: 0.78 },
        { bottom: "8%",left: "1%",  size: 80, variant: 2, delay: 0.5,  rot: 9,   opacity: 0.85 },
        { top: "6%",   right: "1%", size: 86, variant: 4, delay: 0.6,  rot: 12,  opacity: 0.90 },
        { top: "26%",  right: "2%", size: 70, variant: 2, delay: 1.0,  rot: -7,  opacity: 0.82 },
        { top: "50%",  right: "1%", size: 74, variant: 1, delay: 0.4,  rot: 5,   opacity: 0.78 },
        { bottom: "7%",right: "1%", size: 78, variant: 3, delay: 0.9,  rot: -11, opacity: 0.85 },
      ]} />
      <div className="scene-inner">
        <div className="block-inner">
          <p className="quote reveal" style={{
            fontFamily: "var(--serif-display)",
            fontSize: "clamp(28px, 3.6vw, 48px)",
            fontStyle: "italic",
            lineHeight: 1.25,
            color: "var(--rose-700)",
            maxWidth: "22ch",
            margin: "0 auto",
          }}>
            Seu carinho faz parte da nossa história…
          </p>
          <p className="signature reveal">Esperamos por você ✿</p>
          <p className="section-body reveal" style={{ margin: "20px auto 36px", textAlign: "center", maxWidth: 520 }}>
            Para viver esse dia mágico ao nosso lado.
          </p>
          <div className="reveal" style={{ textAlign: "center" }}>
            <button className="btn btn-primary btn-large" onClick={onRSVP}>
              Confirmar Presença ✿
            </button>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   RSVP Modal
   ============================================================ */
function RSVPModal({ open, onClose }) {
  const [name, setName] = useState("");
  const [phone, setPhone] = useState("");
  const [count, setCount] = useState(0);
  const [companions, setCompanions] = useState([]);
  const [sent, setSent] = useState(false);

  useEffect(() => {
    if (open) {
      setName(""); setPhone(""); setCount(0); setCompanions([]); setSent(false);
      document.body.style.overflow = "hidden";
    } else {
      document.body.style.overflow = "";
    }
    return () => { document.body.style.overflow = ""; };
  }, [open]);

  useEffect(() => {
    setCompanions((prev) => {
      const next = [...prev];
      while (next.length < count) next.push("");
      next.length = count;
      return next;
    });
  }, [count]);

  if (!open) return null;

  const submit = (e) => {
    e.preventDefault();
    if (!name.trim() || !phone.trim()) return;
    saveRsvp({ name: name.trim(), phone: phone.trim(), count, companions: companions.map((c) => c.trim()).filter(Boolean), pix: 0 });
    setSent(true);
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true">
        <button className="modal-close" onClick={onClose} aria-label="Fechar">×</button>

        {!sent ? (
          <form onSubmit={submit}>
            <h3>Confirmar presença</h3>
            <p className="modal-sub">Será uma alegria ter você conosco ✿</p>
            <div className="field">
              <label>Nome completo</label>
              <input type="text" value={name} onChange={(e) => setName(e.target.value)}
                placeholder="Como devemos te chamar?" required />
            </div>
            <div className="field">
              <label>WhatsApp</label>
              <input type="tel" value={phone} onChange={(e) => setPhone(e.target.value)}
                placeholder="(00) 00000-0000" required />
            </div>
            <div className="field">
              <label>Quantidade de acompanhantes</label>
              <select value={count} onChange={(e) => setCount(parseInt(e.target.value, 10))}>
                <option value={0}>Vou sozinho(a)</option>
                {Array.from({ length: 10 }, (_, i) => i + 1).map((n) => (
                  <option key={n} value={n}>{n} acompanhante{n > 1 ? "s" : ""}</option>
                ))}
              </select>
            </div>
            {count > 0 && (
              <div className="companions">
                <div className="clbl">Nome dos acompanhantes</div>
                {companions.map((c, i) => (
                  <input key={i} type="text" value={c}
                    onChange={(e) => { const arr = [...companions]; arr[i] = e.target.value; setCompanions(arr); }}
                    placeholder={`Acompanhante ${i + 1}`} />
                ))}
              </div>
            )}
            <button type="submit" className="btn btn-primary form-submit">Enviar confirmação ✿</button>
          </form>
        ) : (
          <div className="success-card">
            <div className="icon">🦋</div>
            <h4>Presença confirmada!</h4>
            <p>Sua presença é o nosso maior presente.<br />Te esperamos no jardim encantado em <strong>13 · 06 · 2026</strong>.</p>
            <button className="btn btn-ghost" onClick={onClose} style={{ marginTop: 24 }}>Fechar</button>
          </div>
        )}
      </div>
    </div>
  );
}

/* ============================================================
   Presentes page
   ============================================================ */
function PresentesPage({ tweaks }) {
  const [amount, setAmount] = useState(100);
  const [copied, setCopied] = useState(false);
  const pixKey = "08576056402";

  const copy = () => {
    try { navigator.clipboard?.writeText(pixKey); } catch {}
    setCopied(true);
    setTimeout(() => setCopied(false), 1900);
  };

  return (
    <div className="route-fade">
      {copied && <div className="toast">Chave PIX copiada ✿</div>}
      {tweaks.showParticles && <Particles count={tweaks.particleDensity} />}
      {tweaks.showFlyingButterflies && <FlyingButterflies count={2} />}

      <section className="block" style={{ paddingTop: 140 }} data-screen-label="06 Presentes">
        <StaticButterflies items={[
          { top: "12%", left: "6%",   size: 80, variant: 1 },
          { top: "20%", right: "8%",  size: 72, variant: 2, delay: 0.4 },
          { bottom: "12%", left: "10%", size: 64, variant: 3, delay: 0.8 },
        ]} />
        <div className="block-inner" style={{ textAlign: "center" }}>
          <div className="section-label reveal in" style={{ display: "block" }}>Lista de presentes</div>
          <h2 className="section-title reveal in" style={{ marginInline: "auto" }}>
            O maior presente é <em>compartilhar</em> esse momento com você ♡
          </h2>
          <p className="section-body reveal in" style={{ marginInline: "auto" }}>
            Mas, para quem desejar presentear nossa princesa, deixamos algumas
            sugestões com muito carinho — escolha o que tocar o seu coração.
          </p>

          <div className="gift-grid reveal in">
            <div className="gift-card">
              <div className="num">01</div>
              <h4>Roupinhas</h4>
              <p>Vestidos, conjuntos e peças tamanho <strong>2 a 3 anos</strong> para acompanhar nossa borboleta.</p>
            </div>
            <div className="gift-card">
              <div className="num">02</div>
              <h4>Sapatinhos &amp; sandálias</h4>
              <p>Para pisar leve no jardim — também tamanho <strong>2 a 3 anos</strong>.</p>
            </div>
            <div className="gift-card">
              <div className="num">03</div>
              <h4>Brinquedos interativos</h4>
              <p>Que estimulem o desenvolvimento infantil — descoberta, cores e sons.</p>
            </div>
          </div>

          <div className="pix-card reveal in" style={{ marginTop: 80 }}>
            <h3>… ou presenteie via PIX ✿</h3>
            <p className="pix-sub">Para quem preferir, também disponibilizamos esta opção delicada.</p>

            <div className="pix-amount">
              <span className="currency">R$</span>
              <span className="value">{amount}</span>
              <span className="currency">,00</span>
            </div>

            <div className="amount-controls">
              <button className="amount-btn minus" onClick={() => setAmount((a) => Math.max(100, a - 10))} disabled={amount <= 100}>−10</button>
              <button className="amount-btn minus" onClick={() => setAmount((a) => Math.max(100, a - 50))} disabled={amount <= 100}>−50</button>
              <button className="amount-btn" onClick={() => setAmount((a) => Math.min(9999, a + 50))}>+50</button>
              <button className="amount-btn" onClick={() => setAmount((a) => Math.min(9999, a + 100))}>+100</button>
              <button className="amount-btn" onClick={() => setAmount((a) => Math.min(9999, a + 200))}>+200</button>
            </div>

            <div className="pix-qr" aria-label="QR Code PIX">
              <QRPlaceholder amount={amount} />
            </div>

            <div className="pix-key-row">
              <input readOnly value={pixKey} />
              <button className="btn btn-primary" onClick={copy} style={{ padding: "12px 22px", fontSize: 11 }}>Copiar</button>
            </div>
            <div className="pix-min">Valor mínimo · R$ 100,00</div>
          </div>
        </div>
      </section>
    </div>
  );
}

/* ============================================================
   PIX EMV payload builder (Banco Central do Brasil spec)
   ============================================================ */
function buildPixPayload(key, merchantName, city, amount) {
  // Format: ID (2) + Length (2) + Value
  const f = (id, val) => {
    const v = String(val);
    return id + String(v.length).padStart(2, "0") + v;
  };

  const merchantInfo = f("26",
    f("00", "br.gov.bcb.pix") +
    f("01", key)
  );

  const additional = f("62", f("05", "***"));

  let payload = [
    f("00", "01"),                                       // Payload format indicator
    merchantInfo,                                        // Merchant account info (PIX)
    f("52", "0000"),                                     // Merchant category code
    f("53", "986"),                                      // Currency BRL
    amount > 0 ? f("54", amount.toFixed(2)) : "",        // Transaction amount
    f("58", "BR"),                                       // Country code
    f("59", merchantName.slice(0, 25)),                  // Merchant name
    f("60", city.slice(0, 15)),                          // Merchant city
    additional,                                          // Reference label
    "6304",                                              // CRC placeholder
  ].join("");

  // CRC-16/CCITT-FALSE (polynomial 0x1021, init 0xFFFF)
  let crc = 0xFFFF;
  for (let i = 0; i < payload.length; i++) {
    crc ^= payload.charCodeAt(i) << 8;
    for (let j = 0; j < 8; j++) {
      crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
      crc &= 0xFFFF;
    }
  }

  return payload + crc.toString(16).toUpperCase().padStart(4, "0");
}

/* ============================================================
   QR Code real — usa qrcodejs + payload PIX válido
   ============================================================ */
function QRPlaceholder({ amount }) {
  const containerRef = useRef(null);

  const pixPayload = useMemo(
    () => buildPixPayload("08576056402", "Mariany Aniversario", "Brasil", amount),
    [amount]
  );

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    el.innerHTML = "";

    if (typeof QRCode !== "undefined") {
      new QRCode(el, {
        text: pixPayload,
        width: 172,
        height: 172,
        colorDark: "#48162a",
        colorLight: "#ffffff",
        correctLevel: QRCode.CorrectLevel.M,
      });
      // qrcodejs inserts a table + img; make both fill the container
      el.querySelectorAll("img, canvas, table").forEach((n) => {
        n.style.cssText = "width:100%;height:100%;display:block;";
      });
    } else {
      el.innerHTML = `<p style="font-size:11px;color:#c87890;padding:8px;text-align:center">QR Code indisponível — copie a chave acima</p>`;
    }
  }, [pixPayload]);

  return (
    <div
      ref={containerRef}
      style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}
    />
  );
}

/* ============================================================
   Admin confirmações
   ============================================================ */
function ConfirmacoesPage() {
  const [auth, setAuth]   = useState(() => sessionStorage.getItem("admin_ok") === "1");
  const [pw, setPw]       = useState("");
  const [err, setErr]     = useState("");
  const [filter, setFilter] = useState("all");
  const [rows, setRows]   = useState(() => loadRsvps());

  useEffect(() => {
    const id = setInterval(() => setRows(loadRsvps()), 1500);
    return () => clearInterval(id);
  }, []);

  if (!auth) {
    const tryLogin = (e) => {
      e.preventDefault();
      if (pw === "mariany1106") {
        sessionStorage.setItem("admin_ok", "1");
        setAuth(true); setErr("");
      } else {
        setErr("Senha incorreta — tente novamente.");
      }
    };
    return (
      <div className="route-fade">
        <div className="login-card">
          <h2>Acesso reservado</h2>
          <p>Apenas a família tem acesso a esta área ✿</p>
          <form onSubmit={tryLogin}>
            <div className="field">
              <label>Senha</label>
              <input type="password" value={pw} onChange={(e) => setPw(e.target.value)}
                placeholder="••••••••" autoFocus />
            </div>
            <button className="btn btn-primary form-submit" type="submit">Entrar</button>
            {err && <div className="err">{err}</div>}
          </form>
        </div>
      </div>
    );
  }

  const totalGuests = rows.reduce((s, r) => s + 1 + (r.count || 0), 0);
  const totalPix    = rows.reduce((s, r) => s + (r.pix || 0), 0);
  const filtered    = filter === "alone" ? rows.filter((r) => (r.count || 0) === 0)
                    : filter === "group" ? rows.filter((r) => (r.count || 0) > 0)
                    : rows;

  const logout = () => { sessionStorage.removeItem("admin_ok"); setAuth(false); };

  const seedDemo = () => {
    if (rows.length > 0) return;
    const demo = [
      { name: "Vovó Cláudia",  phone: "(11) 98742-0011", count: 2, companions: ["Vovô Antônio","Tia Bruna"], pix: 200 },
      { name: "Tia Larissa",   phone: "(11) 99123-4501", count: 1, companions: ["Lucas Mendes"], pix: 0 },
      { name: "Madrinha Aline",phone: "(21) 98810-2233", count: 3, companions: ["Padrinho Felipe","Júlia (5)","Bento (2)"], pix: 300 },
      { name: "Patrícia Sales", phone: "(11) 99988-1100", count: 0, companions: [], pix: 100 },
    ];
    const all = demo.map((r, i) => ({ ...r, id: Date.now() + i, createdAt: new Date(Date.now() - i * 3600e3).toISOString() }));
    localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
    setRows(all);
  };

  return (
    <div className="route-fade">
      <StaticButterflies items={[
        { top: "10%", left: "3%",  size: 60, variant: 2, opacity: 0.5 },
        { top: "16%", right: "4%", size: 56, variant: 4, opacity: 0.5 },
      ]} />
      <div className="dashboard">
        <div className="dash-header">
          <div>
            <h2>Confirmações</h2>
            <p>Painel privado · convidados da Mariany ✿</p>
          </div>
          <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
            {rows.length === 0 && <button className="logout-btn" onClick={seedDemo}>Carregar exemplo</button>}
            <button className="logout-btn" onClick={logout}>Sair</button>
          </div>
        </div>

        <div className="stats">
          <div className="stat"><div className="lbl">Confirmações</div><div className="val">{rows.length}</div><div className="sub">famílias</div></div>
          <div className="stat"><div className="lbl">Convidados</div><div className="val">{totalGuests}</div><div className="sub">pessoas ao todo</div></div>
          <div className="stat"><div className="lbl">Acompanhantes</div><div className="val">{rows.reduce((s, r) => s + (r.count || 0), 0)}</div><div className="sub">além dos titulares</div></div>
          <div className="stat"><div className="lbl">PIX recebido</div><div className="val">R${totalPix}</div><div className="sub">em presentes</div></div>
        </div>

        <div className="table-wrap">
          <div className="table-head">
            <h3>Lista de convidados</h3>
            <div className="filter">
              <button className={"chip" + (filter === "all"   ? " on" : "")} onClick={() => setFilter("all")}>Todos</button>
              <button className={"chip" + (filter === "alone" ? " on" : "")} onClick={() => setFilter("alone")}>Sozinhos</button>
              <button className={"chip" + (filter === "group" ? " on" : "")} onClick={() => setFilter("group")}>Em grupo</button>
            </div>
          </div>
          {filtered.length === 0 ? (
            <div className="empty">
              <p style={{ fontFamily: "var(--serif-display)", fontSize: 22, color: "var(--rose-700)", marginBottom: 6 }}>Nenhuma confirmação ainda</p>
              <p style={{ fontFamily: "var(--serif)", fontSize: 15 }}>As respostas aparecerão aqui assim que chegarem ✿</p>
            </div>
          ) : (
            <table className="tbl">
              <thead>
                <tr>
                  <th style={{ width: "22%" }}>Nome</th>
                  <th style={{ width: "16%" }}>WhatsApp</th>
                  <th style={{ width: "8%" }}>Qtd.</th>
                  <th style={{ width: "26%" }}>Acompanhantes</th>
                  <th style={{ width: "12%" }}>PIX</th>
                  <th style={{ width: "16%" }}>Data</th>
                </tr>
              </thead>
              <tbody>
                {filtered.map((r) => (
                  <tr key={r.id}>
                    <td className="name">{r.name}</td>
                    <td>{r.phone}</td>
                    <td>{r.count || 0}</td>
                    <td className="companions-cell">
                      {(r.companions || []).length === 0
                        ? <span style={{ opacity: 0.5, background: "transparent" }}>—</span>
                        : (r.companions || []).map((c, i) => <span key={i}>{c}</span>)
                      }
                    </td>
                    <td className="pix-val">{r.pix ? `R$${r.pix}` : "—"}</td>
                    <td>{new Date(r.createdAt).toLocaleString("pt-BR", { dateStyle: "short", timeStyle: "short" })}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>

        <p style={{ textAlign: "center", marginTop: 28, fontFamily: "var(--sans)", fontSize: 10, letterSpacing: "0.3em", textTransform: "uppercase", color: "var(--ink-mute)" }}>
          Dados armazenados localmente neste navegador
        </p>
      </div>
    </div>
  );
}

/* ============================================================
   Scene rail nav
   ============================================================ */
function SceneRail({ activeScene, hidden, locked }) {
  const scenes = [
    { id: "hero",      label: "Início" },
    { id: "garden",    label: "Jardim" },
    { id: "emotional", label: "Conto" },
    { id: "event",     label: "Evento" },
    { id: "final",     label: "Convite" },
  ];
  const go = (id) => {
    if (locked) return;
    const el = document.querySelector(`section[data-scene="${id}"]`);
    if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
  };
  return (
    <div className={`scene-rail ${hidden ? "hidden" : ""}`} aria-label="Capítulos">
      {scenes.map((s) => (
        <span key={s.id}
          className={`dot ${activeScene === s.id ? "active" : ""}`}
          data-label={s.label}
          onClick={() => go(s.id)}
          role="button"
          aria-label={s.label}></span>
      ))}
    </div>
  );
}

/* ============================================================
   Hero lock hook
   ============================================================ */
function useHeroLock(active) {
  const [secondsLeft, setSecondsLeft] = useState(HERO_LOCK_SECONDS);
  const locked = secondsLeft > 0;

  useEffect(() => {
    if (!active || secondsLeft <= 0) return;
    const t = setTimeout(() => setSecondsLeft((s) => Math.max(0, s - 1)), 1000);
    return () => clearTimeout(t);
  }, [secondsLeft, active]);

  useEffect(() => {
    if (!active || !locked) {
      document.documentElement.style.overflow = "";
      document.body.style.overflow = "";
      return;
    }
    document.documentElement.style.overflow = "hidden";
    document.body.style.overflow = "hidden";
    window.scrollTo({ top: 0, behavior: "auto" });

    const prevent = (e) => e.preventDefault();
    const onKey = (e) => {
      const keys = ["ArrowDown", "ArrowUp", "PageDown", "PageUp", "Home", "End", " ", "Spacebar"];
      if (keys.includes(e.key)) e.preventDefault();
    };
    window.addEventListener("wheel", prevent, { passive: false });
    window.addEventListener("touchmove", prevent, { passive: false });
    window.addEventListener("keydown", onKey);
    return () => {
      window.removeEventListener("wheel", prevent);
      window.removeEventListener("touchmove", prevent);
      window.removeEventListener("keydown", onKey);
      document.documentElement.style.overflow = "";
      document.body.style.overflow = "";
    };
  }, [active, locked]);

  const reset = useCallback(() => setSecondsLeft(HERO_LOCK_SECONDS), []);
  return { secondsLeft, locked, reset };
}

/* ============================================================
   App root
   ============================================================ */
function App() {
  const initialRoute = (() => {
    const h = (window.location.hash || "").replace("#", "").replace("/", "");
    return h === "presentes" || h === "confirmacoes" ? h : "home";
  })();

  const [route, setRoute] = useState(initialRoute);
  const [modal, setModal] = useState(false);
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  useEffect(() => { applyPalette(tweaks.palette); }, [tweaks.palette]);

  useEffect(() => {
    const onHash = () => {
      const h = (window.location.hash || "").replace("#", "").replace("/", "");
      setRoute(h === "presentes" || h === "confirmacoes" ? h : "home");
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  const go = (r) => {
    window.location.hash = r === "home" ? "" : "/" + r;
    setRoute(r);
    window.scrollTo({ top: 0, behavior: "smooth" });
    // Refresh ScrollTrigger after route change
    setTimeout(() => { if (typeof ScrollTrigger !== "undefined") ScrollTrigger.refresh(); }, 80);
  };

  const { secondsLeft, locked, reset } = useHeroLock(route === "home");
  useEffect(() => { if (route === "home") reset(); }, [route]);

  useEffect(() => {
    const root = document.documentElement;
    if (route === "home" && !locked) {
      root.classList.add("cinematic");
      root.classList.remove("no-snap");
    } else {
      root.classList.remove("cinematic");
      root.classList[locked ? "add" : "remove"]("no-snap");
    }
  }, [route, locked]);

  // GSAP scene entrance (replaces IntersectionObserver)
  const activeScene = useGsapScenes(route === "home");

  // GSAP reveal for non-scene pages
  useGsapReveal(route !== "home");

  // Re-run ScrollTrigger after unlock
  useEffect(() => {
    if (!locked && typeof ScrollTrigger !== "undefined") {
      setTimeout(() => ScrollTrigger.refresh(), 100);
    }
  }, [locked]);

  return (
    <div className="app">
      <Topbar route={route} go={go} />
      <AudioToggle />
      {route === "home" && <SceneRail activeScene={activeScene} hidden={locked} locked={locked} />}

      {route === "home" && (
        <div className="route-fade" key="home">
          <Hero tweaks={tweaks} locked={locked} secondsLeft={secondsLeft} />
          <GardenSection tweaks={tweaks} />
          <EmotionalSection />
          <EventSection onRSVP={() => setModal(true)} />
          <FinalSection onRSVP={() => setModal(true)} />
          <footer className="footer">
            <span>Com <span className="heart">♡</span> da família Mariany · 13 · 06 · 2026</span>
          </footer>
        </div>
      )}

      {route === "presentes"    && <PresentesPage tweaks={tweaks} />}
      {route === "confirmacoes" && <ConfirmacoesPage />}

      <RSVPModal open={modal} onClose={() => setModal(false)} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Atmosfera">
          <TweakToggle label="Borboletas voando" value={tweaks.showFlyingButterflies} onChange={(v) => setTweak("showFlyingButterflies", v)} />
          <TweakToggle label="Partículas"        value={tweaks.showParticles}          onChange={(v) => setTweak("showParticles", v)} />
          <TweakSlider label="Densidade" value={tweaks.particleDensity} min={6} max={70} step={2} onChange={(v) => setTweak("particleDensity", v)} />
        </TweakSection>
        <TweakSection label="Conteúdo">
          <TweakText label="Nome no vídeo" value={tweaks.videoLabel} onChange={(v) => setTweak("videoLabel", v)} />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

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