/* ===== Kuntur shared: icons + GSAP animation helpers ===== */
const { useRef, useEffect, useState, useLayoutEffect } = React;

/* ---------- Icons ---------- */
function Icon({ name, className }) {
  const p = { width: "1em", height: "1em", viewBox: "0 0 24 24", fill: "none", className,
    stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round" };
  const paths = {
    arrow: <g><path d="M5 12h14" /><path d="M13 6l6 6-6 6" /></g>,
    arrowUR: <g><path d="M7 17L17 7" /><path d="M8 7h9v9" /></g>,
    plus: <g><path d="M12 5v14" /><path d="M5 12h14" /></g>,
    menu: <g><path d="M3 7h18" /><path d="M3 13h13" /></g>,
    close: <g><path d="M6 6l12 12" /><path d="M18 6L6 18" /></g>
  };
  return <svg {...p}>{paths[name]}</svg>;
}

function Social({ name, className }) {
  const p = { width: "1em", height: "1em", viewBox: "0 0 24 24", fill: "currentColor", className };
  const g = {
    whatsapp: <path d="M17.47 14.38c-.28-.14-1.63-.8-1.88-.89-.25-.1-.44-.14-.62.14-.18.28-.7.89-.86 1.07-.16.18-.32.2-.6.07-.28-.14-1.19-.44-2.26-1.4-.84-.74-1.4-1.66-1.56-1.94-.16-.28-.02-.43.12-.57.13-.13.28-.32.42-.48.14-.16.18-.28.28-.46.09-.18.05-.34-.02-.48-.07-.14-.62-1.49-.85-2.04-.22-.54-.45-.46-.62-.47H8.6c-.18 0-.46.07-.7.34C7.66 8 7 8.68 7 10.04c0 1.36.99 2.68 1.13 2.86.14.18 1.95 2.98 4.73 4.18.66.28 1.18.45 1.58.58.66.21 1.27.18 1.74.11.53-.08 1.63-.67 1.86-1.31.23-.64.23-1.19.16-1.31-.07-.12-.25-.19-.53-.33zM12 2a10 10 0 0 1 10 10 10 10 0 0 1-10 10c-1.76 0-3.4-.46-4.84-1.26L2 22l1.3-4.87A9.95 9.95 0 0 1 2 12 10 10 0 0 1 12 2zm0 1.8a8.2 8.2 0 0 0-8.2 8.2c0 1.7.52 3.28 1.4 4.59L4.35 19.7l3.2-.84A8.16 8.16 0 0 0 12 20.2a8.2 8.2 0 0 0 0-16.4z" />,
    instagram: <path d="M12 2.2c3.2 0 3.6 0 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s0 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58 0-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.7 3.7 0 0 1-1.38-.9 3.7 3.7 0 0 1-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.21 15.58 2.2 15.2 2.2 12s0-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.21 8.8 2.2 12 2.2zm0 1.8c-3.15 0-3.5 0-4.74.07-.9.04-1.38.19-1.7.31-.43.17-.74.37-1.06.69-.32.32-.52.63-.69 1.06-.12.32-.27.8-.31 1.7C3.42 8.5 3.4 8.85 3.4 12s0 3.5.07 4.74c.04.9.19 1.38.31 1.7.17.43.37.74.69 1.06.32.32.63.52 1.06.69.32.12.8.27 1.7.31 1.24.07 1.59.07 4.74.07s3.5 0 4.74-.07c.9-.04 1.38-.19 1.7-.31.43-.17.74-.37 1.06-.69.32-.32.52-.63.69-1.06.12-.32.27-.8.31-1.7.07-1.24.07-1.59.07-4.74s0-3.5-.07-4.74c-.04-.9-.19-1.38-.31-1.7a2.86 2.86 0 0 0-.69-1.06 2.86 2.86 0 0 0-1.06-.69c-.32-.12-.8-.27-1.7-.31C15.5 4 15.15 4 12 4zm0 3.07a4.93 4.93 0 1 1 0 9.86 4.93 4.93 0 0 1 0-9.86zm0 1.8a3.13 3.13 0 1 0 0 6.26 3.13 3.13 0 0 0 0-6.26zm5.15-2.99a1.15 1.15 0 1 1 0 2.3 1.15 1.15 0 0 1 0-2.3z" />,
    tiktok: <path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.27 6.27 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.69a8.18 8.18 0 0 0 4.84 1.56V6.78a4.85 4.85 0 0 1-1.07-.09z" />,
    linkedin: <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14zM8.34 18.34V9.9H5.67v8.44h2.67zM7 8.67a1.55 1.55 0 1 0 0-3.1 1.55 1.55 0 0 0 0 3.1zm11.34 9.67v-4.63c0-2.47-1.32-3.62-3.08-3.62-1.42 0-2.06.78-2.41 1.33V9.9h-2.67c.04.75 0 8.44 0 8.44h2.67v-4.71c0-.24.02-.48.09-.65.19-.48.63-.97 1.36-.97.96 0 1.35.73 1.35 1.8v4.53h2.69z" />,
    facebook: <path d="M14 13.5h2.5l1-4H14v-2c0-1.03 0-2 2-2h1.5V2.14c-.33-.04-1.57-.14-2.88-.14C11.88 2 10 3.66 10 6.7v2.8H7v4h3V22h4v-8.5z" />,
    x: <path d="M17.53 3H20.5l-6.49 7.41L21.75 21h-5.97l-4.68-6.12L5.74 21H2.77l6.94-7.93L2.25 3h6.12l4.23 5.59L17.53 3zm-1.05 16.2h1.65L7.6 4.7H5.83l10.65 14.5z" />,
    gmail: <path d="M24 5.457v13.909c0 .904-.732 1.636-1.636 1.636h-3.819V11.73L12 16.64l-6.545-4.91v9.273H1.636A1.636 1.636 0 0 1 0 19.366V5.457c0-2.023 2.309-3.178 3.927-1.964L5.455 4.64 12 9.548l6.545-4.907 1.528-1.148C21.69 2.28 24 3.434 24 5.457z" />
  };
  return <svg {...p}>{g[name]}</svg>;
}

/* ---------- Pill button ---------- */
function Btn({ children, href = "#", solid, className = "", icon = "arrow" }) {
  return (
    <a href={href} className={"btn " + (solid ? "btn--solid " : "") + className}>
      <span>{children}</span>
      <span className="btn-ic"><Icon name={icon} /></span>
    </a>);

}

/* ---------- GSAP setup ---------- */
/* Run fn now if the document is visible, else defer until it becomes visible.
   Keeps content at its (visible) CSS default whenever the rAF ticker is paused
   (background tab, capture context) so nothing ever gets stuck hidden. */
function runWhenVisible(fn) {
  if (document.visibilityState === "visible") {fn();return () => {};}
  const onVis = () => {
    if (document.visibilityState === "visible") {
      document.removeEventListener("visibilitychange", onVis);
      fn();
    }
  };
  document.addEventListener("visibilitychange", onVis);
  return () => document.removeEventListener("visibilitychange", onVis);
}

function useGsapReady(cb, deps = []) {
  useLayoutEffect(() => {
    if (!window.gsap) return;
    gsap.registerPlugin(ScrollTrigger);
    let ctx;
    const stopVis = runWhenVisible(() => {
      ctx = gsap.context(() => cb());
      if (window.ScrollTrigger) ScrollTrigger.refresh();
    });
    return () => {stopVis();if (ctx) ctx.revert();};
  }, deps);
}

/* Reveal a group of [data-reveal] children with stagger on scroll */
function Reveal({ children, className = "", y = 40, stagger = 0.08, delay = 0, sel = "[data-reveal]", start = "top 85%", as: Tag = "div" }) {
  const ref = useRef(null);
  useGsapReady(() => {
    const el = ref.current;
    const items = el.querySelectorAll(sel);
    const targets = items.length ? items : [el];
    gsap.set(targets, { opacity: 0, y });
    gsap.to(targets, {
      opacity: 1, y: 0, duration: 1, ease: "power3.out", stagger, delay,
      scrollTrigger: { trigger: el, start }
    });
  }, []);
  return <Tag ref={ref} className={className}>{children}</Tag>;
}

/* Masked line text that slides up on scroll */
function RevealText({ children, className = "", as: Tag = "div", start = "top 88%", delay = 0 }) {
  const ref = useRef(null);
  useGsapReady(() => {
    const inner = ref.current.querySelector(".line-inner");
    gsap.set(inner, { yPercent: 110 });
    gsap.to(inner, { yPercent: 0, duration: 1.1, ease: "power4.out", delay,
      scrollTrigger: { trigger: ref.current, start } });
  }, []);
  return (
    <Tag ref={ref} className={"line-mask " + className}>
      <span className="line-inner" style={{ fontSize: "70px" }}>{children}</span>
    </Tag>);

}

/* Infinite marquee (GSAP). dir: 1 = left, -1 = right */
function Marquee({ children, speed = 60, dir = 1, className = "", gap = 0, pauseHover = false }) {
  const trackRef = useRef(null);
  const tweenRef = useRef(null);
  useGsapReady(() => {
    const track = trackRef.current;
    const first = track.children[0];
    const w = first.getBoundingClientRect().width + gap;
    gsap.set(track, { x: dir === 1 ? 0 : -w });
    tweenRef.current = gsap.to(track, {
      x: dir === 1 ? -w : 0,
      duration: w / speed, ease: "none", repeat: -1,
      modifiers: { x: gsap.utils.unitize((x) => dir === 1 ? parseFloat(x) % w : parseFloat(x) % w, "px") }
    });
  }, []);
  const onEnter = () => pauseHover && tweenRef.current && tweenRef.current.timeScale(0.25);
  const onLeave = () => pauseHover && tweenRef.current && tweenRef.current.timeScale(1);
  return (
    <div className={"marquee " + className} onMouseEnter={onEnter} onMouseLeave={onLeave}>
      <div className="marquee__track" ref={trackRef} style={{ gap: gap + "px" }}>
        <div className="marquee__group" style={{ display: "flex", alignItems: "center", gap: gap + "px", flex: "none" }}>{children}</div>
        <div className="marquee__group" style={{ display: "flex", alignItems: "center", gap: gap + "px", flex: "none" }} aria-hidden="true">{children}</div>
      </div>
    </div>);

}

/* Count-up number on scroll (preserves any prefix/suffix like $, +, %, M) */
function CountUp({ value, className }) {
  const ref = useRef(null);
  const str = String(value);
  const m = str.match(/^([^0-9]*)([0-9][0-9,.]*)(.*)$/);
  const pre = m ? m[1] : "",numStr = m ? m[2] : str,suf = m ? m[3] : "";
  useGsapReady(() => {
    if (!m) return;
    const obj = { v: 0 };
    const target = parseFloat(numStr.replace(/,/g, "")) || 0;
    const decimals = (numStr.split(".")[1] || "").length;
    gsap.fromTo(obj, { v: 0 }, {
      v: target, duration: 2, ease: "power2.out", immediateRender: false,
      scrollTrigger: { trigger: ref.current, start: "top 90%" },
      onUpdate: () => {if (ref.current) ref.current.textContent = pre + obj.v.toFixed(decimals) + suf;}
    });
  }, []);
  return <span ref={ref} className={className}>{value}</span>;
}

/* Dead-ticker fallback: if rAF never advances (background tab / capture context),
   force all reveal-animated content to its visible end-state. */
function installTickerWatchdog() {
  if (!window.gsap) return;
  const f0 = gsap.ticker.frame;
  setTimeout(() => {
    if (gsap.ticker.frame - f0 < 2) {
      try {ScrollTrigger.getAll().forEach((s) => s.kill(false));} catch (e) {}
      gsap.globalTimeline.getChildren().forEach((tw) => tw.kill());
      const sel = ".line-inner, .line-mask, [data-reveal], .hero__banner, .hero__card, .reveal-up, .svc-chip, .work-card__media, .work-card__media img, .work-card__bar, .about__img, .stat__num";
      gsap.set(sel, { clearProps: "all" });
      document.querySelectorAll(sel).forEach((el) => {
        el.style.opacity = "1";el.style.transform = "none";el.style.clipPath = "none";
      });
    }
  }, 1100);
}

Object.assign(window, {
  useRef, useEffect, useState, useLayoutEffect,
  Icon, Social, Btn, useGsapReady, Reveal, RevealText, Marquee, CountUp, installTickerWatchdog
});