/* ============================================================
   Manigod Kids Club — site core
   Icons, Photo, Reveal, Navbar, Footer, Modal, Shell, hooks.
   Exports to window (Babel scopes per file).
   ============================================================ */
const { useState, useEffect, useRef } = React;

const PAGES = [
  { label: "Accueil", href: "/" },
  { label: "Saisons", href: "/saisons/" },
  { label: "Tarifs", href: "/tarifs/" },
  { label: "Galerie", href: "/galerie/" },
  { label: "Contact", href: "/contact/" },
];
/* page label → en helper for aria/labels */
const _T = (s) => (window.t ? window.t(s) : s);

/* ---------- BOOKING (YoPlanning) ----------
   Deux liens définitifs : un par saison. La page neutre /reservation/
   laisse le parent choisir sa saison avant de partir vers YoPlanning. */
const BOOKING = {
  ete: "https://booking.yoplanning.pro/e168364c-330a-4e0a-9456-e3a39f96c63c/",
  hiver: "https://booking.yoplanning.pro/63b7a662-a876-4288-86ee-f543dca95cb1/",
  page: "/reservation/",
};
/* season connu → onglet YoPlanning ; sinon → page de choix de saison */
function goBook(season) {
  const s = season === "ete" || season === "hiver" ? season : null;
  if (s && BOOKING[s]) {
    window.open(BOOKING[s], "_blank", "noopener,noreferrer");
  } else {
    window.location.href = BOOKING.page;
  }
}

/* ---------- ICONS (line, brand convention: 24/24, ~2.1 stroke) ---------- */
const I = {
  arrow: <path d="M5 12h14M13 6l6 6-6 6"/>,
  arrowDown: <path d="M12 5v14M6 13l6 6 6-6"/>,
  plus: <path d="M12 5v14M5 12h14"/>,
  chevron: <path d="M6 9l6 6 6-6"/>,
  prev: <path d="M15 6l-6 6 6 6"/>,
  next: <path d="M9 6l6 6-6 6"/>,
  sun: <g><circle cx="12" cy="12" r="4.2"/><path d="M12 2v2.5M12 19.5V22M22 12h-2.5M4.5 12H2M19 5l-1.8 1.8M6.8 17.2 5 19M19 19l-1.8-1.8M6.8 6.8 5 5"/></g>,
  snow: <g><path d="M12 2v20M3.5 7l17 10M20.5 7l-17 10"/><path d="M12 6l-2.4-2M12 6l2.4-2M12 18l-2.4 2M12 18l2.4 2M5.6 9.5 5 6.7l-2.8.4M18.4 14.5l.6 2.8 2.8-.4M18.4 9.5l.6-2.8 2.8.4M5.6 14.5 5 17.3l-2.8-.4"/></g>,
  marker: <g><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="2.8"/></g>,
  phone: <path d="M15.5 14.4l-2 .9a12.4 12.4 0 0 1-5.8-5.8l.9-2-1.6-4H3.4A1.4 1.4 0 0 0 2 5c.3 9.4 7.6 16.7 17 17a1.4 1.4 0 0 0 1.4-1.6v-3.4z"/>,
  mail: <g><rect x="3" y="5" width="18" height="14" rx="3"/><path d="m4 7 8 6 8-6"/></g>,
  star: <path d="M12 2l2.9 6.3 6.9.7-5.1 4.6 1.4 6.8L12 17.8 5.9 20.4l1.4-6.8L2.2 9l6.9-.7z"/>,
  menu: <path d="M4 7h16M4 12h16M4 17h16"/>,
  close: <path d="M6 6l12 12M18 6 6 18"/>,
  check: <path d="M4 12.5 9 17.5 20 6.5"/>,
  clock: <g><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></g>,
  mountain: <path d="M3 19h18L14.5 7.5l-3 5L9 9l-6 10Z"/>,
  bike: <g><circle cx="6" cy="17" r="3.4"/><circle cx="18" cy="17" r="3.4"/><path d="M6 17l4-7h5l-2.5 7M9 6h3l1.5 4"/></g>,
  tent: <path d="M12 4 3 20h18L12 4ZM12 9v11"/>,
  compass: <g><circle cx="12" cy="12" r="9"/><path d="M15.5 8.5 13 13l-4.5 2.5L11 11l4.5-2.5Z"/></g>,
  target: <g><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4.6"/><circle cx="12" cy="12" r=".6" fill="currentColor" stroke="none"/></g>,
  users: <g><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0M16 6.2a3 3 0 0 1 0 5.6M17.5 20a5.3 5.3 0 0 0-3-4.8"/></g>,
  leaf: <path d="M5 19C5 11 11 5 19 5c0 8-6 14-14 14ZM9 15l6-6"/>,
  globe: <g><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.6 2.6 2.6 15.4 0 18M12 3c-2.6 2.6-2.6 15.4 0 18"/></g>,
  ski: <g><path d="M5 18.5 19 8M4 21l14.5-4.5M8 5.5a1.6 1.6 0 1 0 .01 0M9 9l4 2.5"/></g>,
  sled: <g><path d="M4 9h11a3 3 0 0 1 3 3v3H7M4 9v6M4 18h15M19 15v3"/></g>,
  igloo: <g><path d="M3 16a9 9 0 0 1 18 0v0H3ZM3 16v0M9 16v-3a3 3 0 0 1 6 0v3"/></g>,
  image: <g><rect x="3" y="4" width="18" height="16" rx="3"/><circle cx="8.5" cy="9.5" r="1.6"/><path d="m4 17 5-4 4 3 3-2.5 4 3.5"/></g>,
  calendar: <g><rect x="3.5" y="5" width="17" height="15" rx="3"/><path d="M3.5 9.5h17M8 3v4M16 3v4"/></g>,
  euro: <path d="M17 5.5a7 7 0 1 0 0 13M5 10h7M5 14h7"/>,
  utensils: <g><path d="M5 3v8a2 2 0 0 0 4 0V3M7 11v10M17 3c-1.6 0-2.5 2-2.5 5s.9 4 2.5 4M17 12v9"/></g>,
  sparkles: <path d="M12 4l1.6 4.4L18 10l-4.4 1.6L12 16l-1.6-4.4L6 10l4.4-1.6L12 4ZM18 15l.7 1.8L20.5 17.5l-1.8.7L18 20l-.7-1.8L15.5 17.5l1.8-.7L18 15Z"/>,
  binocular: <g><path d="M7 4h2l1 4M17 4h-2l-1 4"/><circle cx="6" cy="14" r="3.6"/><circle cx="18" cy="14" r="3.6"/><path d="M10 13h4"/></g>,
  paw: <g><circle cx="7" cy="9" r="1.7"/><circle cx="12" cy="7" r="1.7"/><circle cx="17" cy="9" r="1.7"/><path d="M12 12c-3 0-5 2.5-5 5a2.5 2.5 0 0 0 4 1.4 2.5 2.5 0 0 0 2 0A2.5 2.5 0 0 0 17 17c0-2.5-2-5-5-5Z"/></g>,
  route: <g><circle cx="6" cy="6" r="2.4"/><circle cx="18" cy="18" r="2.4"/><path d="M8.4 6H14a3.5 3.5 0 0 1 0 7H10a3.5 3.5 0 0 0 0 7h5.6"/></g>,
  shield: <path d="M12 3 5 6v5c0 4.5 3 7.5 7 9 4-1.5 7-4.5 7-9V6l-7-3ZM9 12l2 2 4-4"/>,
  heart: <path d="M12 20s-7-4.5-9.2-9.2C1.4 8 2.6 5 5.6 5 7.5 5 12 7 12 7s4.5-2 6.4-2c3 0 4.2 3 2.8 5.8C19 15.5 12 20 12 20Z"/>,
  moon: <path d="M20.5 14.8A8.5 8.5 0 1 1 9.2 3.5a6.8 6.8 0 0 0 11.3 11.3Z"/>,
  cup: <g><path d="M4 8h13v5.5a4.5 4.5 0 0 1-4.5 4.5H8.5A4.5 4.5 0 0 1 4 13.5V8Z"/><path d="M17 9.5h2.2a2.3 2.3 0 0 1 0 4.6H17"/><path d="M7.5 2.5v2.2M11 2.5v2.2"/></g>,
};
function Icon({ name, size = 22, fill = false, style }) {
  return (
    <svg viewBox="0 0 24 24" width={size} height={size}
      fill={fill ? "currentColor" : "none"}
      stroke={fill ? "none" : "currentColor"}
      strokeWidth="2.1" strokeLinecap="round" strokeLinejoin="round"
      style={{ display: "block", flex: "none", ...style }} aria-hidden="true">
      {I[name]}
    </svg>
  );
}

/* ---------- PHOTO (real src or branded placeholder) ---------- */
function Photo({ src, label, alt = "", radius, className = "", style, eager = false }) {
  const base = { position: "absolute", inset: 0, width: "100%", height: "100%" };
  if (src) {
    return <img src={src} alt={alt} loading={eager ? "eager" : "lazy"} className={className}
      style={{ ...base, objectFit: "cover", borderRadius: radius, ...style }} />;
  }
  return (
    <div className={"mkc-ph " + className} style={{ ...base, borderRadius: radius, ...style }} role="img" aria-label={label || alt}>
      <img className="mkc-ph__mark" src="/assets/logos/monogram-cream.svg" alt="" />
      {label && <span className="mkc-ph__label">{label}</span>}
    </div>
  );
}

/* ---------- Reveal-on-scroll — IntersectionObserver (no per-frame layout
   reads, so scrolling stays smooth). Elements below the fold stay hidden
   until you actually scroll them into view, so the animation always plays
   *during* the scroll, never pre-emptively. ---------- */
let _revealIO = null;
function _getRevealIO() {
  if (_revealIO || typeof IntersectionObserver === "undefined") return _revealIO;
  _revealIO = new IntersectionObserver((entries, obs) => {
    for (const e of entries) {
      if (e.isIntersecting) { e.target.classList.add("is-in"); obs.unobserve(e.target); }
    }
  }, { rootMargin: "0px 0px -12% 0px", threshold: 0 });
  return _revealIO;
}
function Reveal({ children, as = "div", delay = 0, className = "", style, ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = _getRevealIO();
    if (!io) { el.classList.add("is-in"); return; }
    io.observe(el);
    // Failsafe — only reveal on a timer if the element is ALREADY on screen
    // (e.g. above-the-fold content, or if the observer somehow never fires).
    // Off-screen elements are left to the observer so they animate on scroll.
    const t = setTimeout(() => {
      const r = el.getBoundingClientRect();
      if (r.top < (window.innerHeight || 0) && r.bottom > 0) {
        el.classList.add("is-in"); io.unobserve(el);
      }
    }, 1400);
    return () => { io.unobserve(el); clearTimeout(t); };
  }, []);
  const Tag = as;
  return (
    <Tag ref={ref} className={"mkc-reveal " + className}
      style={{ transitionDelay: delay + "ms", ...style }} {...rest}>
      {children}
    </Tag>
  );
}

/* ---------- SCROLL THREAD ("lacet") — a soft wavy line that runs the full
   height of the page and is "drawn" downward as you scroll, weaving between
   the sections. Palette-only (brand green), no gradient, pointer-events none;
   it naturally fades into the green sections. Static under reduced-motion. ---------- */
function _buildWave(w, h) {
  const cx = w * 0.5;
  // sweep wide so the line hugs the page edges / margins and only crosses the
  // central text column briefly on the diagonals (reads as "going around" copy)
  const ampFrac = w < 760 ? 0.30 : 0.42;
  const amp = Math.min(w * ampFrac, 560);
  const segs = Math.max(4, Math.round(h / 760));
  const step = h / segs;
  let d = `M ${cx.toFixed(1)} 0`;
  let dir = 1;
  for (let i = 0; i < segs; i++) {
    const y0 = i * step, y1 = (i + 1) * step;
    d += ` C ${(cx + dir * amp).toFixed(1)} ${(y0 + step * 0.30).toFixed(1)}, ${(cx + dir * amp).toFixed(1)} ${(y1 - step * 0.30).toFixed(1)}, ${cx.toFixed(1)} ${y1.toFixed(1)}`;
    dir *= -1;
  }
  return d;
}
/* Collect the page-coordinate vertical ranges that have a GREEN background,
   so the cream copy of the thread can be revealed only over those bands.
   Green = any .mkc-sec--ink / .mkc-pagehero--ink block, plus the whole page
   when the season switch has set data-saison="hiver" on .mkc-app. */
function _greenBands(startY, h) {
  const app = document.querySelector(".mkc-app");
  const top = startY, bot = startY + h;
  if (app && app.getAttribute("data-saison") === "hiver") {
    // The whole page is green EXCEPT sections explicitly flipped to cream
    // (the Avis block + the final-CTA section, marked data-thread-cream).
    // Subtract those bands so the GREEN base thread shows through the cream,
    // and the line keeps reading correctly all the way down to the footer.
    const cream = [];
    document.querySelectorAll("[data-thread-cream]").forEach((el) => {
      const r = el.getBoundingClientRect();
      const t = Math.round(r.top + window.scrollY), b = Math.round(r.bottom + window.scrollY);
      if (b > t) cream.push({ t, b });
    });
    cream.sort((a, b) => a.t - b.t);
    const bands = [];
    let cur = top;
    for (const c of cream) {
      const ct = Math.max(top, c.t), cb = Math.min(bot, c.b);
      if (cb <= cur) continue;
      if (ct > cur) bands.push({ t: cur, b: ct });
      cur = cb;
    }
    if (cur < bot) bands.push({ t: cur, b: bot });
    return bands;
  }
  const bands = [];
  document.querySelectorAll(".mkc-sec--ink, .mkc-pagehero--ink").forEach((el) => {
    const r = el.getBoundingClientRect();
    bands.push({ t: Math.round(r.top + window.scrollY), b: Math.round(r.bottom + window.scrollY) });
  });
  return bands;
}

function ScrollThread() {
  const baseRef = useRef(null);
  const overRef = useRef(null);
  const cid = useRef("mkcband" + Math.random().toString(36).slice(2, 8));
  const [g, setG] = useState({ w: 1200, h: 3000, startY: 0, d: "", bands: [] });
  useEffect(() => {
    const build = () => {
      const w = document.documentElement.clientWidth;
      const sh = document.documentElement.scrollHeight;
      // begin the thread just below the hero on the home page (under the season
      // cards); on every inner page it starts right under the floating navbar so
      // it reads as one continuous line from the top, never cut by a section.
      const fan = document.querySelector(".mkc-fan");
      const nav = document.querySelector(".mkc-nav");
      const ph = document.querySelector(".mkc-pagehero");
      let startY = Math.round(window.innerHeight * 0.6);
      if (fan) startY = Math.round(fan.getBoundingClientRect().bottom + window.scrollY);
      else if (nav) startY = Math.round(nav.getBoundingClientRect().bottom + 10); // fixed nav → page-Y under it
      else if (ph) startY = Math.round(ph.getBoundingClientRect().bottom + window.scrollY);
      const h = Math.max(240, sh - startY);
      setG({ w, h, startY, d: _buildWave(w, h), bands: _greenBands(startY, h) });
    };
    build();
    const t1 = setTimeout(build, 700);
    const t2 = setTimeout(build, 1800);
    window.addEventListener("resize", build);
    // recompute the green bands when the season switch flips data-saison
    const app = document.querySelector(".mkc-app");
    let mo = null;
    if (app && typeof MutationObserver !== "undefined") {
      mo = new MutationObserver(build);
      mo.observe(app, { attributes: true, attributeFilter: ["data-saison"] });
    }
    return () => {
      window.removeEventListener("resize", build);
      clearTimeout(t1); clearTimeout(t2); if (mo) mo.disconnect();
    };
  }, []);
  useEffect(() => {
    const paths = [baseRef.current, overRef.current].filter(Boolean);
    if (!paths.length || !g.d) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const lens = paths.map((p) => { const l = p.getTotalLength(); p.style.strokeDasharray = l; return l; });
    if (reduce) { paths.forEach((p) => { p.style.strokeDashoffset = 0; }); return; }
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const sh = document.documentElement.scrollHeight;
        const head = window.scrollY + window.innerHeight * 1.15;
        const span = Math.max(1, sh - g.startY);
        const prog = Math.min(1, Math.max(0.04, (head - g.startY) / span));
        paths.forEach((p, i) => { p.style.strokeDashoffset = lens[i] * (1 - prog); });
      });
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => { window.removeEventListener("scroll", onScroll); cancelAnimationFrame(raf); };
  }, [g.d, g.startY, g.bands]);

  // green bands → clip rects in the thread's local (viewBox) coordinate space
  const rects = (g.bands || []).map((bnd, i) => {
    const y = Math.max(0, bnd.t - g.startY);
    const y2 = Math.min(g.h, bnd.b - g.startY);
    if (y2 <= y) return null;
    return <rect key={i} x="0" y={y} width={g.w} height={y2 - y} />;
  }).filter(Boolean);

  const stroke = { fill: "none", vectorEffect: "non-scaling-stroke", strokeWidth: "2.4",
    strokeLinecap: "round", strokeLinejoin: "round" };
  return (
    <>
      {/* green thread — sits on the cream paper */}
      <div className="mkc-thread mkc-thread--base" aria-hidden="true" style={{ top: g.startY }}>
        <svg width="100%" height={g.h} viewBox={`0 0 ${g.w} ${g.h}`} preserveAspectRatio="none">
          <path ref={baseRef} d={g.d} stroke="currentColor" {...stroke} />
        </svg>
      </div>
      {/* cream thread — identical geometry, revealed only over the green bands */}
      <div className="mkc-thread mkc-thread--over" aria-hidden="true" style={{ top: g.startY }}>
        <svg width="100%" height={g.h} viewBox={`0 0 ${g.w} ${g.h}`} preserveAspectRatio="none">
          {rects.length > 0 && <defs><clipPath id={cid.current}>{rects}</clipPath></defs>}
          <path ref={overRef} d={g.d} stroke="currentColor"
            clipPath={rects.length > 0 ? `url(#${cid.current})` : undefined}
            style={rects.length === 0 ? { display: "none" } : undefined} {...stroke} />
        </svg>
      </div>
    </>
  );
}

/* ---------- NAVBAR ---------- */
function Navbar({ active = "Accueil", glass = false, onBook }) {
  const [open, setOpen] = useState(false);
  const logo = glass ? "logo-typo-cream.svg" : "logo-typo-green.svg";
  // lock body scroll while the mobile menu is open + close on Escape; both
  // cleaned up so nothing stays blocked after the menu closes/unmounts
  useEffect(() => {
    if (!open) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => { document.body.style.overflow = prev; window.removeEventListener("keydown", onKey); };
  }, [open]);
  return (
    <div className="mkc-navwrap">
      <nav className={"mkc-nav" + (glass ? " mkc-nav--glass" : "")} aria-label={_T("Navigation principale")}>
        <a href="/" aria-label={_T("Accueil — Manigod Kids Club")}>
          <img className="mkc-nav__logo" src={"/assets/logos/" + logo} alt="Manigod Kids Club" />
        </a>
        <div className="mkc-nav__links mkc-nav__desktop">
          {PAGES.map((p) => (
            <a key={p.label} href={p.href}
              className={"mkc-navlink" + (p.label === active ? " is-active" : "")}
              aria-current={p.label === active ? "page" : undefined}>{_T(p.label)}</a>
          ))}
        </div>
        <div className="mkc-nav__desktop mkc-nav__langwrap"><LangSwitch glass={glass} /></div>
        <button className={"mkc-btn mkc-btn--sm mkc-nav__cta" + (glass ? " mkc-btn--on-ink" : "")}
          onClick={onBook}>{_T("Réserver")}</button>
        <button className="mkc-nav__burger" onClick={() => setOpen(true)} aria-label={_T("Ouvrir le menu")}>
          <Icon name="menu" size={22} />
        </button>
      </nav>

      {open && (
        <div className="mkc-mobnav" onClick={() => setOpen(false)}>
          <div className="mkc-mobnav__sheet" onClick={(e) => e.stopPropagation()}>
            <div className="mkc-mobnav__head">
              <img src="/assets/logos/logo-typo-green.svg" alt="" style={{ height: 30 }} />
              <button className="mkc-iconbtn" onClick={() => setOpen(false)} aria-label={_T("Fermer")}>
                <Icon name="close" size={22} />
              </button>
            </div>
            {PAGES.map((p) => (
              <a key={p.label} href={p.href}
                className={"mkc-mobnav__link" + (p.label === active ? " is-active" : "")}>
                {_T(p.label)}<Icon name="arrow" size={20} />
              </a>
            ))}
            <div className="mkc-mobnav__lang">
              <span className="mkc-eyebrow">{_T("Langue")}</span>
              <LangSwitch block />
            </div>
            <button className="mkc-btn mkc-btn--block" style={{ marginTop: 8 }}
              onClick={() => { setOpen(false); onBook && onBook(); }}>{_T("Réserver")}</button>
          </div>
        </div>
      )}
    </div>
  );
}

/* ---------- FOOTER ---------- */
function Footer() {
  return (
    <footer className="mkc-footer">
      <div className="mkc-container mkc-footer__grid">
        <div className="mkc-footer__brand">
          <a href="/"><img src="/assets/logos/logo-full-cream.svg" alt="Manigod Kids Club" /></a>
          <p>{_T("Le premier club bilingue des Aravis")}<br />{_T("Manigod, Haute-Savoie.")}</p>
          <div className="mkc-footer__partners">
            <span className="mkc-eyebrow mkc-eyebrow--paper">{_T("En collaboration avec")}</span>
            <div className="mkc-footer__plogos">
              <a className="mkc-plogo" href={window.ESF_URL || "https://www.esfmanigod.com/"} target="_blank" rel="noreferrer" aria-label={_T("ESF Manigod — site officiel (nouvel onglet)")}><img src="/assets/logos/partner-esf.svg" alt="ESF" /></a>
              <span className="mkc-plogo"><img src="/assets/logos/partner-manigod.svg" alt="Commune de Manigod" /></span>
              <span className="mkc-plogo"><img src="/assets/logos/partner-laregion.svg" alt="La Région Auvergne-Rhône-Alpes" /></span>
              <span className="mkc-plogo"><img src="/assets/logos/partner-reseau-initiative.svg" alt="Réseau Initiative Grand Annecy" /></span>
              <span className="mkc-plogo"><img src="/assets/logos/partner-labellemontagne.png" alt="Labellemontagne" /></span>
            </div>
          </div>
        </div>
        <nav className="mkc-footer__col">
          <span className="mkc-eyebrow mkc-eyebrow--paper">{_T("Le club")}</span>
          <a href="/">{_T("Accueil")}</a>
          <a href="/saisons/">{_T("Saisons")}</a>
          <a href="/tarifs/">{_T("Tarifs")}</a>
          <a href="/galerie/">{_T("Galerie")}</a>
        </nav>
        <nav className="mkc-footer__col">
          <span className="mkc-eyebrow mkc-eyebrow--paper">{_T("Infos")}</span>
          <a href="/contact/">{_T("Contact")}</a>
          <a href="/">{_T("FAQ")}</a>
          <a href="/conditions/">{_T("Conditions & règlement")}</a>
        </nav>
        <div className="mkc-footer__col">
          <span className="mkc-eyebrow mkc-eyebrow--paper">{_T("Contact")}</span>
          <a href="tel:+33613944509">+33 6 13 94 45 09</a>
          <a href="mailto:contact@manigodkidsclub.com">contact@manigodkidsclub.com</a>
          <a href="/contact/">{_T("7082 Route du Col de la Croix Fry,")}<br />{_T("74230 Manigod")}</a>
        </div>
      </div>
      <div className="mkc-container mkc-footer__base">
        <span>{_T("© 2026 Manigod Kids Club")}</span>
        <a href="/conditions/" className="mkc-footer__baselink">{_T("Conditions générales & règlement intérieur")}</a>
        <span>{_T("Été & Hiver · Aravis · Haute-Savoie")}</span>
      </div>
    </footer>
  );
}

/* ---------- MODAL ---------- */
function Modal({ kind, onClose }) {
  const copy = kind === "book"
    ? { t: _T("La réservation en ligne arrive très bientôt"), b: _T("Le module de réservation est en cours de préparation et sera disponible très prochainement. En attendant, contactez-nous directement — nous serons ravis de réserver la semaine de vos enfants."), cta: _T("Fermer"), ic: "clock" }
    : { t: _T("Message envoyé"), b: _T("Maquette — votre message serait transmis à l'équipe du Manigod Kids Club (contact@manigodkidsclub.com), qui vous recontacterait rapidement."), cta: _T("Parfait"), ic: "check" };
  useEffect(() => {
    const k = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", k); return () => window.removeEventListener("keydown", k);
  }, []);
  return (
    <div className="mkc-modal" onClick={onClose} role="dialog" aria-modal="true">
      <div className="mkc-modal__box" onClick={(e) => e.stopPropagation()}>
        <div className="mkc-modal__ic"><Icon name={copy.ic} size={30} /></div>
        <h3 style={{ fontSize: "1.6rem", fontWeight: 600, margin: "0 0 10px" }}>{copy.t}</h3>
        <p style={{ color: "var(--mkc-ink-soft)", lineHeight: 1.55 }}>{copy.b}</p>
        {kind === "book" &&
          <div className="mkc-modal__actions" style={{ display: "flex", gap: 10, flexWrap: "wrap", justifyContent: "center", marginTop: 18 }}>
            <a className="mkc-btn mkc-btn--sm" href="tel:+33613944509">{_T("Appeler")}</a>
            <a className="mkc-btn mkc-btn--sm mkc-btn--secondary" href="mailto:contact@manigodkidsclub.com">{_T("Nous écrire")}</a>
          </div>}
        <button className="mkc-btn mkc-btn--block" style={{ marginTop: kind === "book" ? 12 : 22 }} onClick={onClose}>{copy.cta}</button>
      </div>
    </div>
  );
}

/* ---------- SHELL — wraps a page: nav + chrome + footer + modals + tweaks ----------
   Usage: <Shell active="Accueil" heroGlass>{({ book }) => <>…sections…</>}</Shell>  */
function Shell({ active, heroGlass = false, children }) {
  const [modal, setModal] = useState(null);
  const [scrolled, setScrolled] = useState(false);
  const [t, setTweak] = useTweaks(window.TWEAK_DEFAULTS || {});

  useEffect(() => {
    if (!heroGlass) return;
    const onScroll = () => setScrolled(window.scrollY > window.innerHeight * 0.6);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, [heroGlass]);

  const book = (season) => goBook(season);
  const sent = () => setModal("sent");
  const glass = heroGlass && !scrolled;

  const appAttrs = {
    "data-herocards": t.heroCards || "fan",
    "data-round": t.round || "standard",
  };
  const appStyle = {
    "--fan-rot": (t.fanRot != null ? t.fanRot : 6) + "deg",
    "--veil-mul": t.veil != null ? t.veil : 1,
    "--mkc-r-lg": RND[t.round || "standard"].lg,
    "--mkc-r-xl": RND[t.round || "standard"].xl,
    "--mkc-r-2xl": RND[t.round || "standard"].xxl,
  };
  const displayWeight = t.displayWeight || 600;

  return (
    <div className="mkc mkc-app" {...appAttrs} style={appStyle}>
      <style>{`.mkc-app .mkc-hero__title,.mkc-app .mkc-finalcta h2,.mkc-app .mkc-showcase__hero h3,.mkc-app .mkc-pagehero h1,.mkc-app .mkc-agegroup__head h3,.mkc-app .mkc-tarif .price{font-weight:${displayWeight};}`}</style>
      <Navbar active={active} glass={glass} onBook={book} />
      {typeof children === "function" ? children({ book, sent }) : children}
      <Footer />
      {modal && <Modal kind={modal} onClose={() => setModal(null)} />}
      <SiteTweaks t={t} setTweak={setTweak} />
    </div>
  );
}

const RND = {
  soft: { lg: "20px", xl: "26px", xxl: "34px" },
  standard: { lg: "32px", xl: "40px", xxl: "56px" },
  extra: { lg: "40px", xl: "52px", xxl: "72px" },
};

/* ---------- CALL BUTTON ----------
   Touch devices place the call (tel:). On desktop, where a raw tel: link
   triggers an unstyled OS/browser "call" vignette, we instead copy the number
   and show a clean brand toast — no parasitic popup, same visual button. */
function CallButton({ className = "", label, tel = "+33613944509", display = "+33 6 13 94 45 09" }) {
  const [toast, setToast] = useState(false);
  const timer = useRef(0);
  const lbl = label || _T("Nous appeler");
  const onClick = () => {
    const touch = window.matchMedia("(hover: none) and (pointer: coarse)").matches;
    if (touch) { window.location.href = "tel:" + tel; return; }
    try { navigator.clipboard && navigator.clipboard.writeText(display); } catch (e) {}
    setToast(true);
    window.clearTimeout(timer.current);
    timer.current = window.setTimeout(() => setToast(false), 2600);
  };
  return (
    <span className="mkc-callwrap">
      <button type="button" className={"mkc-btn " + className} onClick={onClick}
        aria-label={lbl + " — " + display}>
        <Icon name="phone" size={18} /> {lbl}
      </button>
      <span className={"mkc-calltoast" + (toast ? " is-on" : "")} role="status" aria-live="polite">
        {_T("Numéro copié")}&nbsp;: {display}
      </span>
    </span>);

}

Object.assign(window, { Icon, Photo, Reveal, ScrollThread, Navbar, Footer, Modal, Shell, PAGES, RND, CallButton, BOOKING, goBook });
