/* Coco Beauty Salon — app root + interactions */
(function () {
  function App() {
    const [menu, setMenu] = React.useState(false);
    React.useEffect(() => {
      document.body.classList.toggle("no-scroll", menu);
    }, [menu]);
    // (re)build icons after every render so re-rendered subtrees keep their glyphs
    React.useEffect(() => { if (window.lucide) window.lucide.createIcons(); });
    return (
      React.createElement(React.Fragment, null,
        React.createElement(Nav, { onMenu: () => setMenu(true) }),
        React.createElement(Drawer, { open: menu, onClose: () => setMenu(false) }),
        React.createElement("main", null,
          React.createElement(Hero),
          React.createElement(TrustBar),
          React.createElement(Services),
          React.createElement(Signature),
          React.createElement(Cinematic),
          React.createElement(Gallery),
          React.createElement(Prices),
          React.createElement(Reviews),
          React.createElement(Booking),
          React.createElement(FAQ),
          React.createElement(Contact)
        ),
        React.createElement(FooterSection)
      )
    );
  }

  const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const touch = window.matchMedia && window.matchMedia("(hover: none)").matches;

  /* ---------- entrance overlay (kept up until content is actually ready) ---------- */
  const intro = document.getElementById("intro");
  const START = Date.now();
  const MIN = reduce ? 200 : 2050;
  let mounted = false, done = false;

  function revealAll() {
    document.querySelectorAll(".reveal").forEach((el) => el.classList.add("in"));
  }
  function doHide() {
    if (done) return; done = true;
    if (intro) intro.classList.add("hide");
    document.documentElement.classList.remove("intro-active");
    document.body.classList.remove("intro-active", "no-scroll");
    setTimeout(() => { if (intro) intro.style.display = "none"; }, 1200);
  }
  // fade out only once React has mounted AND the minimum cinematic time has passed
  function attemptHide() {
    if (done) return;
    if (!mounted) return;
    const el = Date.now() - START;
    if (el >= MIN) doHide();
    else setTimeout(attemptHide, MIN - el + 20);
  }
  document.documentElement.classList.add("intro-active");
  document.body.classList.add("intro-active");
  if (intro) intro.addEventListener("click", doHide);          // tap to skip
  window.addEventListener("load", attemptHide);
  setTimeout(attemptHide, MIN + 40);
  setTimeout(doHide, 7000);                                    // hard fallback — never stuck

  /* ---------- mount (with retry: babel scripts may still be arriving) ---------- */
  let tries = 0, rendered = false;
  function render() {
    if (rendered) return; rendered = true;
    try {
      ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App));
      mounted = true;
      attemptHide();
      requestAnimationFrame(() => requestAnimationFrame(() => {
        try { initInteractions(); } catch (e) { console.error(e); revealAll(); }
      }));
    } catch (e) {
      console.error(e);
      rendered = false;
      if (tries++ < 60) { setTimeout(mount, 120); }
      else {
        // last resort — never leave a blank page: show a minimal branded view
        const root = document.getElementById("root");
        if (root && !root.children.length) {
          root.innerHTML = '<div style="min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:40px;background:var(--color-canvas);color:var(--color-ink);font-family:var(--font-display)">'
            + '<div style="font-size:34px;font-weight:300;letter-spacing:.04em">Coco Beauty Salon</div>'
            + '<div style="width:80px;height:1px;background:var(--color-primary-focus);margin:20px 0"></div>'
            + '<div style="font-size:13px;letter-spacing:.3em;text-transform:uppercase;color:var(--color-ink-muted-48)">Houston, Texas</div>'
            + '<div style="margin-top:22px;font-size:15px;color:#6a5142">10209 Veterans Memorial Drive &middot; Please refresh to load the full site.</div>'
            + '</div>';
        }
        revealAll(); doHide();
      }
    }
  }
  function mount() {
    const ready = window.React && window.ReactDOM && typeof window.Nav === "function";
    if (!ready) {
      if (tries++ < 60) { setTimeout(mount, 100); return; }
    }
    // Let the intro paint its opening animation (wordmark fade) before we do the
    // heavy DOM mount — the overlay is opaque, so mounting behind it is invisible.
    // This keeps the desktop entrance animation smooth (no main-thread contention).
    if (reduce) { render(); }
    else { setTimeout(render, 720); }
  }

  /* ---------- interactions ---------- */
  function initInteractions() {
    /* scroll reveal */
    const els = document.querySelectorAll(".reveal");
    if (reduce || !("IntersectionObserver" in window)) {
      els.forEach((el) => el.classList.add("in"));
    } else {
      const io = new IntersectionObserver((entries) => {
        entries.forEach((en) => { if (en.isIntersecting) { en.target.classList.add("in"); io.unobserve(en.target); } });
      }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
      els.forEach((el) => io.observe(el));
    }

    /* count-up on the price preview numbers */
    const nums = document.querySelectorAll(".pv[data-count]");
    const animateCount = (elm) => {
      const target = parseFloat(elm.getAttribute("data-count")) || 0;
      const dur = 1200, t0 = performance.now();
      const step = (t) => {
        const p = Math.min(1, (t - t0) / dur);
        const eased = 1 - Math.pow(1 - p, 3);
        elm.textContent = "$" + Math.round(eased * target);
        if (p < 1) requestAnimationFrame(step); else elm.textContent = "$" + target;
      };
      requestAnimationFrame(step);
    };
    if (nums.length) {
      if (reduce || !("IntersectionObserver" in window)) {
        nums.forEach((n) => { n.textContent = "$" + (parseFloat(n.getAttribute("data-count")) || 0); });
      } else {
        const co = new IntersectionObserver((ents) => {
          ents.forEach((en) => { if (en.isIntersecting) { animateCount(en.target); co.unobserve(en.target); } });
        }, { threshold: 0.5 });
        nums.forEach((n) => co.observe(n));
      }
    }

    /* lazy-load the map iframe when contact nears the viewport (keeps initial load fast) */
    const mapFrame = document.querySelector(".map-wrap iframe[data-src]");
    if (mapFrame) {
      const load = () => { if (!mapFrame.src) mapFrame.src = mapFrame.getAttribute("data-src"); };
      if ("IntersectionObserver" in window) {
        const mo = new IntersectionObserver((ents) => {
          ents.forEach((en) => { if (en.isIntersecting) { load(); mo.disconnect(); } });
        }, { rootMargin: "400px" });
        mo.observe(mapFrame);
      } else { load(); }
    }

    /* parallax on cinematic panels */
    if (!reduce) {
      const panels = Array.from(document.querySelectorAll("[data-parallax]"));
      let ticking = false;
      const update = () => {
        panels.forEach((p) => {
          const bg = p.querySelector(".cine-bg");
          if (!bg) return;
          const r = p.getBoundingClientRect();
          if (r.bottom < 0 || r.top > window.innerHeight) return;
          const prog = (r.top + r.height / 2 - window.innerHeight / 2) / window.innerHeight;
          bg.style.transform = "translateY(" + (prog * -60).toFixed(1) + "px)";
        });
        ticking = false;
      };
      window.addEventListener("scroll", () => { if (!ticking) { ticking = true; requestAnimationFrame(update); } }, { passive: true });
      update();
    }

    /* custom cursor (desktop / fine pointer only) */
    if (!touch && window.matchMedia("(pointer: fine)").matches) {
      const ring = document.getElementById("cursor");
      const dot = document.getElementById("cursor-dot");
      if (ring && dot) {
        document.body.classList.add("cursor-on");
        let rx = -100, ry = -100, x = -100, y = -100, shown = false, scale = 1, ts = 1;
        window.addEventListener("mousemove", (e) => {
          x = e.clientX; y = e.clientY;
          dot.style.transform = "translate(" + x + "px," + y + "px) translate(-50%,-50%)";
          if (!shown) { shown = true; ring.classList.add("ready"); dot.classList.add("ready"); }
        }, { passive: true });
        const loop = () => {
          rx += (x - rx) * 0.2; ry += (y - ry) * 0.2; scale += (ts - scale) * 0.25;
          ring.style.transform = "translate(" + rx.toFixed(2) + "px," + ry.toFixed(2) + "px) translate(-50%,-50%) scale(" + scale.toFixed(3) + ")";
          requestAnimationFrame(loop);
        };
        loop();
        const grow = () => ring.classList.add("grow");
        const shrink = () => ring.classList.remove("grow");
        window.addEventListener("mousedown", () => { ts = 0.8; }, { passive: true });
        window.addEventListener("mouseup", () => { ts = 1; }, { passive: true });
        document.addEventListener("mouseover", (e) => {
          if (e.target.closest("a,button,.svc-card,.gal-item,.faq-q,input,select,textarea")) grow(); else shrink();
        });
        window.addEventListener("mouseout", (e) => { if (!e.relatedTarget) { ring.classList.remove("ready"); dot.classList.remove("ready"); shown = false; } });
      }
    }
  }

  /* ---------- go ---------- */
  mount();
})();
