// =========================================================================
// Motion primitives — TextReveal, Reveal, MagneticButton
// =========================================================================
const { useEffect, useRef, useState, useLayoutEffect } = React;

// Hook: returns true once the ref enters the viewport.
function useInView(options = { threshold: 0.2, rootMargin: "0px 0px -10% 0px" }) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    if (typeof IntersectionObserver === "undefined") { setInView(true); return; }
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) { setInView(true); io.disconnect(); }
    }, options);
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return [ref, inView];
}

// Hook: respects prefers-reduced-motion
function useReducedMotion() {
  const [reduced, setReduced] = useState(false);
  useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    setReduced(mq.matches);
    const onChange = () => setReduced(mq.matches);
    mq.addEventListener("change", onChange);
    return () => mq.removeEventListener("change", onChange);
  }, []);
  return reduced;
}

// <TextReveal> — renders an array of `lines` (strings or JSX nodes), each
// animating in with a translateY/clip-unmask. Stagger 60ms, duration 900ms,
// expo-out. Accepts either:
//   <TextReveal lines={["Line one", "Line two"]} />
//   <TextReveal lines={["Line one", <>Mixed <em>JSX</em></>]} />
function TextReveal({ lines, as = "h1", className = "", style = {}, stagger = 60, delay = 0 }) {
  const [ref, inView] = useInView();
  const reduced = useReducedMotion();
  const Tag = as;
  const items = Array.isArray(lines) ? lines : [lines];
  return (
    <Tag ref={ref} className={className} style={style}>
      {items.map((line, i) => (
        <span
          key={i}
          style={{
            display: "block",
            overflow: "hidden",
            paddingBottom: "0.08em",
            marginBottom: "-0.08em",
          }}
        >
          <span
            style={{
              display: "block",
              transform: inView || reduced ? "translateY(0)" : "translateY(110%)",
              opacity: reduced ? 1 : (inView ? 1 : 0),
              transition: reduced
                ? "opacity 120ms linear"
                : `transform 900ms cubic-bezier(0.16, 1, 0.3, 1) ${delay + i * stagger}ms, opacity 600ms ease-out ${delay + i * stagger}ms`,
              willChange: "transform",
            }}
          >{line}</span>
        </span>
      ))}
    </Tag>
  );
}

// <Reveal> — fades + translateY 40px on enter
function Reveal({ children, delay = 0, y = 40, className = "", style = {} }) {
  const [ref, inView] = useInView();
  const reduced = useReducedMotion();
  return (
    <div
      ref={ref}
      className={className}
      style={{
        ...style,
        transform: (inView || reduced) ? "translateY(0)" : `translateY(${y}px)`,
        opacity: (inView || reduced) ? 1 : 0,
        transition: reduced
          ? "opacity 120ms linear"
          : `transform 600ms cubic-bezier(0.16, 1, 0.3, 1) ${delay}ms, opacity 600ms cubic-bezier(0.16, 1, 0.3, 1) ${delay}ms`,
      }}
    >
      {children}
    </div>
  );
}

// <MagneticButton> — pulls toward the cursor up to 6px on hover
function MagneticButton({ children, strength = 0.25, max = 6, style = {}, className = "", as = "button", ...rest }) {
  const ref = useRef(null);
  const Tag = as;
  const reduced = useReducedMotion();

  function onMove(e) {
    if (reduced || !ref.current) return;
    const r = ref.current.getBoundingClientRect();
    const dx = e.clientX - (r.left + r.width / 2);
    const dy = e.clientY - (r.top + r.height / 2);
    const x = Math.max(-max, Math.min(max, dx * strength));
    const y = Math.max(-max, Math.min(max, dy * strength));
    ref.current.style.transform = `translate(${x}px, ${y}px)`;
  }
  function onLeave() {
    if (!ref.current) return;
    ref.current.style.transform = "translate(0,0)";
  }

  return (
    <Tag
      ref={ref}
      onMouseMove={onMove}
      onMouseLeave={onLeave}
      className={className}
      style={{
        transition: "transform 320ms cubic-bezier(0.16, 1, 0.3, 1), background 200ms, color 200ms, box-shadow 320ms",
        ...style,
      }}
      {...rest}
    >
      {children}
    </Tag>
  );
}

// <CursorDot> — a soft 24px cursor follower that scales over interactive elements
function CursorDot() {
  const ref = useRef(null);
  const reduced = useReducedMotion();
  useEffect(() => {
    if (reduced) return;
    if (window.matchMedia("(pointer: coarse)").matches) return; // touch only — skip
    const dot = ref.current;
    if (!dot) return;
    let raf = 0;
    let tx = 0, ty = 0, x = 0, y = 0;
    const onMove = (e) => { tx = e.clientX; ty = e.clientY; };
    const tick = () => {
      x += (tx - x) * 0.18;
      y += (ty - y) * 0.18;
      dot.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`;
      raf = requestAnimationFrame(tick);
    };
    const onOver = (e) => {
      const t = e.target;
      if (t.closest && t.closest("a, button, [data-magnetic], input, textarea")) {
        dot.classList.add("is-hot");
      } else {
        dot.classList.remove("is-hot");
      }
    };
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseover", onOver);
    raf = requestAnimationFrame(tick);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseover", onOver);
      cancelAnimationFrame(raf);
    };
  }, [reduced]);
  if (reduced) return null;
  return (
    <div
      ref={ref}
      aria-hidden="true"
      style={{
        position: "fixed",
        top: 0, left: 0,
        width: 24, height: 24,
        borderRadius: "50%",
        // Use a theme-aware border so cursor stays visible in both dark & light modes.
        // mixBlendMode:"difference" was dropping the ring to near-white on light bg — removed.
        border: "1.5px solid var(--fg)",
        background: "transparent",
        pointerEvents: "none",
        zIndex: 9999,
        transition: "width 320ms cubic-bezier(0.16,1,0.3,1), height 320ms cubic-bezier(0.16,1,0.3,1), background 200ms, border-color 200ms",
      }}
      className="cursor-dot"
    />
  );
}

// Language + theme context — created here (first file loaded) so all subsequent files can use it.
const LangContext = React.createContext({ lang: "en", t: (k) => k, theme: "dark" });

// ── Inline Lucide-style icon primitives (no CDN dependency) ──────────────
function Icon({ name, size = 16, style = {} }) {
  const shapes = {
    briefcase: <>
      <rect x="2" y="7" width="20" height="14" rx="2" ry="2"/>
      <path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
    </>,
    sparkles: <>
      <path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.937A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/>
      <path d="M20 3v4"/><path d="M22 5h-4"/><path d="M4 17v2"/><path d="M5 18H3"/>
    </>,
    layers: <>
      <path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/>
      <path d="m6.08 9.5-3.5 1.6a1 1 0 0 0 0 1.81l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9a1 1 0 0 0 0-1.83l-3.5-1.59"/>
      <path d="m6.08 14.5-3.5 1.6a1 1 0 0 0 0 1.81l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9a1 1 0 0 0 0-1.83l-3.5-1.59"/>
    </>,
  };
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width={size} height={size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
      style={style}
    >
      {shapes[name]}
    </svg>
  );
}

function useIsMobile(bp = 768) {
  const [mobile, setMobile] = React.useState(() => window.innerWidth < bp);
  React.useEffect(() => {
    const fn = () => setMobile(window.innerWidth < bp);
    window.addEventListener("resize", fn, { passive: true });
    return () => window.removeEventListener("resize", fn);
  }, []);
  return mobile;
}

Object.assign(window, { TextReveal, Reveal, MagneticButton, CursorDot, useInView, useReducedMotion, LangContext, Icon, useIsMobile });
