// ---- shared components & icons ----
const { useState, useEffect, useRef, useCallback } = React;

// Simple stroke icon set (1.6 weight). Decorative, kept geometric.
function Icon({ name, ...p }) {
  const paths = {
    leaf: <><path d="M11 21c-5 0-8-3-8-8 0-6 5-11 18-11 0 13-5 19-10 19Z"/><path d="M11 21C11 14 14 9 20 5"/></>,
    calendar: <><rect x="3" y="4.5" width="18" height="17" rx="2.5"/><path d="M3 9.5h18M8 2.5v4M16 2.5v4"/><path d="M7.5 14h2M14.5 14h2M11 17.5h2"/></>,
    sun: <><circle cx="12" cy="12" r="4.2"/><path d="M12 2v2.5M12 19.5V22M2 12h2.5M19.5 12H22M4.9 4.9l1.8 1.8M17.3 17.3l1.8 1.8M19.1 4.9l-1.8 1.8M6.7 17.3l-1.8 1.8"/></>,
    hand: <><path d="M8 11V5.5a1.8 1.8 0 0 1 3.6 0V10M11.6 10V4a1.8 1.8 0 0 1 3.6 0v6M15.2 10.5V6.5a1.7 1.7 0 0 1 3.4 0V14c0 4-2.6 7-7 7-3 0-4.6-1.2-6.4-3.6L3 13.4c-.7-1 .3-2.4 1.6-2l3.4 1.6"/></>,
    pin: <><path d="M12 21s7-6.3 7-12a7 7 0 1 0-14 0c0 5.7 7 12 7 12Z"/><circle cx="12" cy="9" r="2.6"/></>,
    mail: <><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M4 7l8 6 8-6"/></>,
    phone: <><path d="M5 3.5h3.3l1.6 4.2-2.1 1.5a13 13 0 0 0 5.4 5.4l1.5-2.1 4.2 1.6V19a2 2 0 0 1-2 2A16.5 16.5 0 0 1 3 6a2 2 0 0 1 2-2.5Z"/></>,
    clock: <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></>,
    arrow: <><path d="M5 12h14M13 6l6 6-6 6"/></>,
    arrowdown: <><path d="M12 5v14M6 13l6 6 6-6"/></>,
    check: <><path d="M5 12.5l4.5 4.5L19 6.5"/></>,
    x: <><path d="M18.5 2h3.4l-7.4 8.5L23 22h-6.8l-5.3-7-6.1 7H1.4l8-9.1L1 2h7l4.8 6.4L18.5 2Z" fill="currentColor" stroke="none"/></>,
    instagram: <><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.2" cy="6.8" r="1.1" fill="currentColor" stroke="none"/></>,
    sprout: <><path d="M12 21v-8M12 13c0-3.3-2.7-6-6-6 0 3.3 2.7 6 6 6ZM12 13c0-3.9 3.1-7 7-7 0 3.9-3.1 7-7 7Z"/></>,
  };
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"
      strokeLinecap="round" strokeLinejoin="round" {...p}>
      {paths[name]}
    </svg>
  );
}

// Brand mark — a stylised custard-apple / leaf glyph
function Mark() {
  return <Icon name="sprout" />;
}

// Reveal-on-scroll wrapper. Scroll-position based (IntersectionObserver is
// unreliable in the preview iframe) and animated with the Web Animations API
// (CSS transitions can stick at the start value in this engine).
function Reveal({ children, delay = 0, as = "div", className = "", ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const reveal = () => {
      if (done || !el) return;
      done = true;
      el.classList.add("in"); // static visible state (no CSS transition involved)
      if (!reduce && el.animate) {
        // Decorative entrance. fill:backwards holds the hidden frame during the
        // delay; a timer finishes it so a frozen timeline can never pin it hidden.
        let a;
        try {
          a = el.animate(
            [
              { opacity: 0, transform: "translateY(24px)" },
              { opacity: 1, transform: "none" },
            ],
            { duration: 850, delay, easing: "cubic-bezier(.22,.61,.36,1)", fill: "backwards" }
          );
        } catch (e) { a = null; }
        if (a) setTimeout(() => { try { a.finish(); } catch (e) {} }, delay + 950);
      }
      window.removeEventListener("scroll", check);
      window.removeEventListener("resize", check);
    };
    const check = () => {
      if (done || !el) return;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * 0.9 && r.bottom > 0) reveal();
    };
    const t = setTimeout(check, 60);
    window.addEventListener("scroll", check, { passive: true });
    window.addEventListener("resize", check);
    return () => {
      clearTimeout(t);
      window.removeEventListener("scroll", check);
      window.removeEventListener("resize", check);
    };
  }, []);
  const Tag = as;
  return (
    <Tag ref={ref} className={`reveal ${seen ? "in" : ""} ${className}`} {...rest}>
      {children}
    </Tag>
  );
}

function Eyebrow({ children, center }) {
  return <span className={`eyebrow ${center ? "center" : ""}`}>{children}</span>;
}

// striped placeholder background for image-slots (author-side hint)
function slotImg(id, ph, attrs = {}) {
  return React.createElement("image-slot", {
    id, placeholder: ph, ...attrs,
  });
}

Object.assign(window, { Icon, Mark, Reveal, Eyebrow, slotImg });
