/* ============================================================
   Shared components, icons & helpers
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- WhatsApp ---------- */
const WA_NUMBER = "5511995367813";
function waLink(message) {
  return `https://wa.me/${WA_NUMBER}?text=${encodeURIComponent(message)}`;
}
const WA_DEFAULT = "Olá Wanderson! Acabei de fazer a análise no site e gostaria de entender minhas possibilidades.";

/* ---------- Reveal on scroll ---------- */
function Reveal({ children, delay = 0, className = "", as = "div", style }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const reveal = () => setSeen(true);
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) { reveal(); io.disconnect(); }
        });
      },
      { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
    );
    io.observe(el);
    // Failsafe: if the element is in view but the observer never fired
    // (e.g. a paused/throttled render context), reveal it anyway so content
    // can never get stuck invisible. Below-the-fold items still wait for scroll.
    const t = setTimeout(() => {
      const r = el.getBoundingClientRect();
      if (r.top < (window.innerHeight || 800) && r.bottom > 0) reveal();
    }, 1400);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  const Tag = as;
  const dcls = delay ? ` d${delay}` : "";
  return (
    <Tag ref={ref} className={`reveal${dcls} ${seen ? "in" : ""} ${className}`} style={style}>
      {children}
    </Tag>
  );
}

/* ---------- Striped placeholder ---------- */
function Placeholder({ label, className = "", style, children, radius }) {
  return (
    <div className={`ph ${className}`} style={{ borderRadius: radius, ...style }}>
      {label && <span className="ph-label">{label}</span>}
      {children}
    </div>
  );
}

/* ---------- Count-up number ---------- */
function CountUp({ to, suffix = "", prefix = "", dur = 1600 }) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const t0 = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - t0) / dur);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(Math.round(eased * to));
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, dur]);
  return <span ref={ref}>{prefix}{val.toLocaleString("pt-BR")}{suffix}</span>;
}

/* ---------- Icons (thin, geometric line set) ---------- */
const ic = (paths, extra = {}) => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"
       strokeLinecap="round" strokeLinejoin="round" {...extra}>{paths}</svg>
);
const Icons = {
  heart: ic(<path d="M12 20s-7-4.6-9.2-9C1.3 7.7 3 4.8 6 4.8c1.9 0 3.1 1.1 4 2.4.9-1.3 2.1-2.4 4-2.4 3 0 4.7 2.9 3.2 6.2C19 15.4 12 20 12 20z" />),
  badge: ic(<><circle cx="12" cy="12" r="9" /><path d="M8.5 12.2l2.4 2.4 4.6-4.8" /></>),
  map: ic(<><path d="M9 3.5L3.5 6v14L9 17.5l6 2.5 5.5-2.5v-14L15 6 9 3.5z" /><path d="M9 3.5v14M15 6v14" /></>),
  key: ic(<><circle cx="8" cy="8" r="3.5" /><path d="M10.5 10.5L20 20M16 16l2-2M18 18l1.5-1.5" /></>),
  chat: ic(<path d="M4 5h16v11H9l-4 3.5V16H4z" />),
  pin: ic(<><path d="M12 21s7-5.5 7-11a7 7 0 10-14 0c0 5.5 7 11 7 11z" /><circle cx="12" cy="10" r="2.5" /></>),
  shield: ic(<><path d="M12 3l7 3v5c0 4.6-3 8.2-7 10-4-1.8-7-5.4-7-10V6l7-3z" /><path d="M9 12l2 2 4-4" /></>),
  user: ic(<><circle cx="12" cy="8" r="3.6" /><path d="M5 20c0-3.6 3.1-6 7-6s7 2.4 7 6" /></>),
  arrow: ic(<path d="M5 12h14M13 6l6 6-6 6" />),
  arrowDown: ic(<path d="M12 5v14M6 13l6 6 6-6" />),
  check: ic(<path d="M5 12.5l4.5 4.5L19 6.5" />),
  spark: ic(<path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5L18 18M18 6l-2.5 2.5M8.5 15.5L6 18" />),
  coins: ic(<><ellipse cx="9" cy="7" rx="5.5" ry="2.6" /><path d="M3.5 7v5c0 1.4 2.5 2.6 5.5 2.6" /><ellipse cx="15" cy="13" rx="5.5" ry="2.6" /><path d="M9.5 13v4c0 1.4 2.5 2.6 5.5 2.6s5.5-1.2 5.5-2.6v-4" /></>),
  doc: ic(<><path d="M7 3h7l5 5v13H7z" /><path d="M14 3v5h5M10 13h6M10 17h6" /></>),
  home: ic(<><path d="M4 11l8-6.5 8 6.5" /><path d="M6 10v9h12v-9" /><path d="M10 19v-5h4v5" /></>),
  whats: (<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2a10 10 0 00-8.6 15l-1.3 4.7 4.8-1.3A10 10 0 1012 2zm0 1.7a8.3 8.3 0 11-4.3 15.4l-.3-.2-2.8.8.8-2.7-.2-.3A8.3 8.3 0 0112 3.7zm-3 4c-.2 0-.5 0-.7.4-.3.4-.9 1-.9 2.3s.9 2.6 1 2.8c.2.2 1.8 2.9 4.5 3.9 2.2.9 2.7.7 3.2.7s1.5-.6 1.7-1.2c.2-.6.2-1.1.1-1.2-.1-.1-.3-.2-.6-.3-.3-.2-1.5-.8-1.8-.9-.2-.1-.4-.1-.6.1-.2.3-.6.9-.8 1-.1.2-.3.2-.5.1-.3-.2-1.1-.4-2.1-1.3-.8-.7-1.3-1.5-1.4-1.8-.2-.3 0-.4.1-.6l.4-.5c.2-.1.2-.3.3-.4.1-.2 0-.3 0-.5l-.8-2c-.2-.5-.4-.4-.6-.4z" /></svg>),
  star: (<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.5l2.8 6 6.6.6-5 4.4 1.5 6.5L12 16.9 6.1 20l1.5-6.5-5-4.4 6.6-.6z" /></svg>),
};

/* ---------- Star rating ---------- */
function Stars({ n = 5, size = 15 }) {
  return (
    <span style={{ display: "inline-flex", gap: 2, color: "var(--gold-400)" }}>
      {Array.from({ length: n }).map((_, i) => (
        <span key={i} style={{ width: size, height: size, display: "inline-block" }}>{Icons.star}</span>
      ))}
    </span>
  );
}

/* ---------- Section thread connector ---------- */
function Thread({ h = 90 }) {
  return <div className="thread" style={{ height: h }} aria-hidden="true" />;
}

/* ---------- Brand logo (real artwork — negative lockup for dark bg) ---------- */
function CruzLogo({ height = 46, marginBlock }) {
  return (
    <img
      className="cruz-logo-img"
      src="assets/cruz-logo.png?v=3"
      alt="Cruz Consultoria Imobiliária · CRECI 299734-F"
      style={{ height, marginBlock, transition: "height .45s var(--ease-out), margin-block .45s var(--ease-out)" }}
    />
  );
}

Object.assign(window, {
  WA_NUMBER, waLink, WA_DEFAULT,
  Reveal, Placeholder, CountUp, Icons, Stars, Thread,
  CruzLogo,
});
