// primer-components.jsx — Nav, Hero (animated demo), DashboardMockup

const { useState, useEffect, useRef } = React;

// ── tiny icon set ──────────────────────────────────────────────────────────
const Ico = {
  pin: () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" /><circle cx="12" cy="10" r="3" /></svg>,
  arrow: () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14" /><path d="m13 5 7 7-7 7" /></svg>,
  up: () => <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 19V5" /><path d="m5 12 7-7 7 7" /></svg>,
  check: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>,
  plus: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M12 5v14M5 12h14" /></svg>,
  minus: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M5 12h14" /></svg>,
  loader: () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" className="p-spin" /></svg>,
  folder: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>,
  sliders: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg>,
  file: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>,
  mic: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>,
  hammer: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m15 12-8.373 8.373a1 1 0 1 1-3-3L12 9"/><path d="m18 15 4-4"/><path d="m21.5 11.5-1.914-1.914A2 2 0 0 1 19 8.172V7l-2.26-2.26a6 6 0 0 0-4.202-1.756L9 2.96l.92.82A6.18 6.18 0 0 1 12 8.4V10l2 2h1.172a2 2 0 0 1 1.414.586L18.5 14.5"/></svg>,
  building: () => <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="16" height="20" x="4" y="2" rx="2"/><path d="M9 22v-4h6v4M8 6h.01M16 6h.01M12 6h.01M12 10h.01M12 14h.01M16 10h.01M16 14h.01M8 10h.01M8 14h.01"/></svg>,
  ext: () => <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>,
  search: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>,
  x: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>,
  layers: () => <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><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="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65M22 12.65l-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/></svg>
};

// ── platform links (config.js → PrimerLinks) ───────────────────────────────
function platformLoginUrl() {
  return (window.PrimerLinks && window.PrimerLinks.login()) || "#";
}
function platformTrialUrl(medium) {
  return (window.PrimerLinks && window.PrimerLinks.trial(medium)) || "#";
}
function platformSearchUrl(address) {
  return (window.PrimerLinks && window.PrimerLinks.search(address)) || "#";
}
function goToPlatformSearch(address) {
  const url = platformSearchUrl(address);
  if (url !== "#") window.location.assign(url);
}

// ── Interactive dot field (Higgs-style proximity) ──────────────────────────
// Replaces the static CSS .bg-dots pattern: dots ease larger/darker near the
// cursor and ease back down as it leaves. After the hero/dashboard, interaction
// is muted over the center content column (.p-dot-mute-zone) so text stays clear.
function InteractiveDotField() {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const ctx = canvas.getContext("2d", { alpha: true });
    if (!ctx) return;

    const SPACING = 20;
    const BASE_RADIUS = 1;
    const MAX_RADIUS = 5.2;
    const INFLUENCE = 140;
    const BASE_ALPHA = 0.07;
    const MAX_ALPHA = 1;
    const GROW_SPEED = 0.22;
    const SHRINK_SPEED = 0.08;
    const MOUSE_FOLLOW = 0.18;
    // How strong the effect stays inside the text column (0 = off, 1 = full)
    const MUTE_FLOOR = 0.08;
    const EDGE_FADE = 72;

    const pointer = { x: -9999, y: -9999, active: false };
    const mouse = { x: -9999, y: -9999 };
    // Sparse per-cell intensity keyed by "col,row" in document space
    const intensity = new Map();
    // Viewport-space mute rect for the content column below the dashboard
    const mute = { top: Infinity, bottom: -Infinity, left: 0, right: 0, ready: false };

    let width = 0;
    let height = 0;
    let dpr = 1;
    let rafId = 0;
    let running = false;

    function cellKey(col, row) {
      return `${col},${row}`;
    }

    function updateMuteBounds() {
      const zone = document.querySelector(".p-dot-mute-zone");
      if (!zone) {
        mute.ready = false;
        return;
      }
      const zoneRect = zone.getBoundingClientRect();
      const column = zone.querySelector(".p-container") || zone;
      const colRect = column.getBoundingClientRect();
      mute.top = zoneRect.top;
      mute.bottom = zoneRect.bottom;
      mute.left = colRect.left;
      mute.right = colRect.right;
      mute.ready = true;
    }

    // Soft mask: full strength outside the content column / above the mute zone;
    // near-zero inside the text column, with a short fade at the edges.
    function muteFactor(x, y) {
      if (!mute.ready) return 1;
      if (y < mute.top - EDGE_FADE || y > mute.bottom + EDGE_FADE) return 1;

      let vertical = 1;
      if (y < mute.top) {
        const t = (mute.top - y) / EDGE_FADE;
        vertical = MUTE_FLOOR + (1 - MUTE_FLOOR) * t;
      } else if (y > mute.bottom) {
        const t = (y - mute.bottom) / EDGE_FADE;
        vertical = MUTE_FLOOR + (1 - MUTE_FLOOR) * t;
      } else {
        vertical = MUTE_FLOOR;
      }

      let horizontal = MUTE_FLOOR;
      if (x < mute.left) {
        const t = Math.min(1, (mute.left - x) / EDGE_FADE);
        horizontal = MUTE_FLOOR + (1 - MUTE_FLOOR) * t;
      } else if (x > mute.right) {
        const t = Math.min(1, (x - mute.right) / EDGE_FADE);
        horizontal = MUTE_FLOOR + (1 - MUTE_FLOOR) * t;
      }

      // Inside the column use the quieter of the two axes; outside, restore
      // strength from whichever edge you're past.
      if (x >= mute.left && x <= mute.right && y >= mute.top && y <= mute.bottom) {
        return MUTE_FLOOR;
      }
      return Math.max(vertical, horizontal);
    }

    function resize() {
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      width = window.innerWidth;
      height = window.innerHeight;
      canvas.width = Math.floor(width * dpr);
      canvas.height = Math.floor(height * dpr);
      canvas.style.width = `${width}px`;
      canvas.style.height = `${height}px`;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      updateMuteBounds();
    }

    function targetAt(x, y) {
      if (!pointer.active) return 0;
      const dx = x - mouse.x;
      const dy = y - mouse.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist >= INFLUENCE) return 0;
      const u = 1 - dist / INFLUENCE;
      // Ease-in curve so growth ramps up near the cursor
      const raw = u * u * u * (u * (u * 6 - 15) + 10);
      return raw * muteFactor(x, y);
    }

    function tick() {
      rafId = 0;

      // Smooth mouse chase — trail feels alive as you move
      if (pointer.active) {
        mouse.x += (pointer.x - mouse.x) * MOUSE_FOLLOW;
        mouse.y += (pointer.y - mouse.y) * MOUSE_FOLLOW;
      }

      const scrollY = window.scrollY || 0;
      const startX = SPACING / 2;
      const startY = SPACING / 2 - (scrollY % SPACING);

      // Document-space origin of the first on-screen cell
      const originCol = 0;
      const originRow = Math.floor(scrollY / SPACING);

      ctx.clearRect(0, 0, width, height);

      let anyActive = pointer.active;
      const seen = new Set();

      let row = originRow;
      for (let y = startY; y < height + SPACING; y += SPACING, row++) {
        let col = originCol;
        for (let x = startX; x < width + SPACING; x += SPACING, col++) {
          const key = cellKey(col, row);
          seen.add(key);

          const target = targetAt(x, y);
          const current = intensity.get(key) || 0;
          const speed = target > current ? GROW_SPEED : SHRINK_SPEED;
          const next = current + (target - current) * speed;

          if (next > 0.002) {
            intensity.set(key, next);
            anyActive = true;
          } else {
            intensity.delete(key);
          }

          const t = next > 0.002 ? next : 0;
          const radius = BASE_RADIUS + (MAX_RADIUS - BASE_RADIUS) * t;
          const alpha = BASE_ALPHA + (MAX_ALPHA - BASE_ALPHA) * t;
          ctx.beginPath();
          ctx.arc(x, y, radius, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(0,0,0,${alpha})`;
          ctx.fill();
        }
      }

      // Drop off-screen cells so the map stays bounded
      for (const key of intensity.keys()) {
        if (!seen.has(key)) intensity.delete(key);
      }

      // Keep animating while chasing, growing, or shrinking
      const mouseSettled =
        !pointer.active ||
        (Math.abs(pointer.x - mouse.x) < 0.15 && Math.abs(pointer.y - mouse.y) < 0.15);

      if (anyActive || !mouseSettled || intensity.size > 0) {
        rafId = requestAnimationFrame(tick);
      } else {
        running = false;
      }
    }

    function startLoop() {
      if (running) return;
      running = true;
      rafId = requestAnimationFrame(tick);
    }

    function onMove(e) {
      pointer.x = e.clientX;
      pointer.y = e.clientY;
      pointer.active = true;
      if (mouse.x < -9000) {
        mouse.x = pointer.x;
        mouse.y = pointer.y;
      }
      startLoop();
    }

    function onLeave() {
      pointer.active = false;
      startLoop();
    }

    function onScroll() {
      updateMuteBounds();
      startLoop();
    }

    const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const finePointer = window.matchMedia("(pointer: fine)").matches;

    resize();
    // Paint the static base field once; interaction starts the continuous loop
    startLoop();

    function onResize() {
      resize();
      startLoop();
    }

    window.addEventListener("resize", onResize);
    window.addEventListener("scroll", onScroll, { passive: true });

    if (!reduceMotion && finePointer) {
      window.addEventListener("mousemove", onMove, { passive: true });
      document.documentElement.addEventListener("mouseleave", onLeave);
    }

    return () => {
      if (rafId) cancelAnimationFrame(rafId);
      running = false;
      window.removeEventListener("resize", onResize);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("mousemove", onMove);
      document.documentElement.removeEventListener("mouseleave", onLeave);
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className="p-dot-field"
      aria-hidden="true"
    />
  );
}

// ── Nav ────────────────────────────────────────────────────────────────────
const USE_CASE_LINKS = [
  ["Home builders", "home-builders"], ["Developers", "developers"],
  ["Acquisitions", "acquisitions"], ["Brokerages", "brokerages"],
  ["Lenders", "lenders"], ["Capital markets", "capital-markets"],
];

function Nav({ style: navStyle = "pill" }) {
  const flat = navStyle === "flat";
  const [hidden, setHidden] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  useEffect(() => {
    let lastY = window.scrollY;
    function onScroll() {
      const y = window.scrollY;
      setHidden(y > lastY && y > 80);
      lastY = y;
    }
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  // mobile menu: lock body scroll and close on Escape
  useEffect(() => {
    document.body.style.overflow = menuOpen ? "hidden" : "";
    if (!menuOpen) return;
    const onKey = (e) => e.key === "Escape" && setMenuOpen(false);
    window.addEventListener("keydown", onKey);
    return () => {
      document.body.style.overflow = "";
      window.removeEventListener("keydown", onKey);
    };
  }, [menuOpen]);
  return (
    <div className={`p-nav-wrap${flat ? " flat" : ""}${hidden && !menuOpen ? " p-nav-hidden" : ""}`}>
      <nav className={`p-nav${flat ? " flat" : ""}`}>
        <a href="Primer.html" className="p-logo">
          <img src="assets/primer-mark.png" className="p-logo-img" alt=""/>
          <span>Primer</span>
        </a>
        <div className="p-nav-links">
          {["Pricing", "Insights"].map((l) =>
          <a key={l} href={l === "Pricing" ? "Pricing.html" : "Insights.html"} className="p-nav-link">{l}</a>
          )}
          <div className="p-nav-item-dropdown">
            <a href="#" className="p-nav-link p-nav-link-caret">
              Use cases
              <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/></svg>
            </a>
            <div className="p-nav-dropdown">
              <div className="p-nav-dropdown-inner">
                {USE_CASE_LINKS.map(([u, slug]) =>
                <a key={u} href={`UseCase.html?slug=${slug}`} className="p-nav-dropdown-link">{u}</a>
                )}
              </div>
            </div>
          </div>
          <a href="Contact.html" className="p-nav-link" data-track="nav_contact_click">Contact</a>
        </div>
        <div className="p-nav-end">
          <a href={platformLoginUrl()} className="p-nav-login">Log in</a>
          <a href={platformTrialUrl("nav")} className="p-btn p-btn-dark" data-track="nav_trial_click">Start free trial</a>
          {/* hidden inline so pages without primer-responsive.css (print/design) never show it */}
          <button
            className="p-nav-toggle"
            style={{ display: "none" }}
            aria-label={menuOpen ? "Close menu" : "Open menu"}
            aria-expanded={menuOpen}
            onClick={() => setMenuOpen((o) => !o)}>
            {menuOpen ?
              <Ico.x/> :
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
            }
          </button>
          <span className="p-nav-divider" style={{ width: 1, height: 32, background: "var(--hairline)", margin: "0 6px" }}/>
          <a href="https://www.linkedin.com/company/primitive-ai/?viewAsMember=true" target="_blank" rel="noopener" className="p-social" title="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg></a>
          <a href="#" className="p-social" title="X"><svg width="17" height="17" viewBox="0 0 24 24" fill="currentColor"><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932 6.064-6.933zm-1.291 19.494h2.039L6.486 3.24H4.298l13.312 17.407z"/></svg></a>
          <a href="#" className="p-social" title="Instagram"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"/></svg></a>
        </div>
      </nav>
      {menuOpen &&
      <div className="p-nav-mobile">
        <a href="Pricing.html" className="p-nav-mobile-link" onClick={() => setMenuOpen(false)}>Pricing</a>
        <a href="Insights.html" className="p-nav-mobile-link" onClick={() => setMenuOpen(false)}>Insights</a>
        <a href="Contact.html" className="p-nav-mobile-link" data-track="nav_contact_click" onClick={() => setMenuOpen(false)}>Contact</a>
        <div className="p-nav-mobile-label">Use cases</div>
        {USE_CASE_LINKS.map(([u, slug]) =>
        <a key={u} href={`UseCase.html?slug=${slug}`} className="p-nav-mobile-sub" onClick={() => setMenuOpen(false)}>{u}</a>
        )}
        <div className="p-nav-mobile-actions">
          <a href={platformLoginUrl()} className="p-btn p-btn-ghost" style={{ flex: 1, justifyContent: "center" }}>Log in</a>
          <a href={platformTrialUrl("nav_mobile")} className="p-btn p-btn-dark" data-track="nav_trial_click" style={{ flex: 1, justifyContent: "center" }}>Start free trial</a>
        </div>
      </div>
      }
    </div>);

}

// ── Demo address input ─────────────────────────────────────────────────────
const SAMPLE_ADDR = "2401 Pacific Ave, Venice CA 90291";
const STREAM_ITEMS = [
"Parcel geometry · APN 4286-001-022 · 7,200 sf lot",
"Zoning resolved · LAR3 base + TOC Tier 3 overlay",
"Setbacks applied · Front 15 / Side 5 / Rear 15",
"Buildable envelope · 14,820 sf GBA across 4 stories",
"Density bonus · 22 units (TOC incentive applied)",
"Comps pulled · 14 comparable sales within 0.5 mi",
"Pro forma complete · NOI $1.42M · uIRR 18.4%"];


function Hero({ accent }) {
  const [state, setState] = useState("idle"); // idle | typing | running | done
  const [inputVal, setInputVal] = useState("");
  const [items, setItems] = useState([]);
  const inputRef = useRef(null);

  const [typeTarget, setTypeTarget] = useState("");

  function runDemo(addr) {
    setInputVal("");
    setItems([]);
    setTypeTarget(addr);
    setState("typing");
  }

  function resetDemo() {
    setState("idle");
    setInputVal("");
    setItems([]);
    setTypeTarget("");
  }

  // auto-type the address, then advance to running
  useEffect(() => {
    if (state !== "typing" || !typeTarget) return;
    let i = 0;
    let advance;
    const iv = setInterval(() => {
      i++;
      setInputVal(typeTarget.slice(0, i));
      if (i >= typeTarget.length) {
        clearInterval(iv);
        advance = setTimeout(() => setState("running"), 360);
      }
    }, 30);
    return () => { clearInterval(iv); clearTimeout(advance); };
  }, [state, typeTarget]);

  // stream analysis items when running, then mark done
  useEffect(() => {
    if (state !== "running") return;
    setItems([]);
    const ts = [];
    STREAM_ITEMS.forEach((item, i) => {
      ts.push(setTimeout(() => setItems((p) => [...p, item]), (i + 1) * 370));
    });
    ts.push(setTimeout(() => setState("done"), STREAM_ITEMS.length * 370 + 600));
    return () => ts.forEach(clearTimeout);
  }, [state]);

  const isIdle = state === "idle";
  const isTyping = state === "typing";
  const isRunning = state === "running";
  const isDone = state === "done";
  const showInput = isIdle || isTyping;

  return (
    <section className="p-hero">
      <div className="p-container" style={{ textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center" }}>

        {/* headline */}
        <h1 className="p-display p-hero-title" style={{ maxWidth: 1100, marginBottom: 44, fontSize: 68, letterSpacing: "-0.038em", lineHeight: 1.16 }}>
          Find out if your project is feasible<br />
          in&nbsp;<span style={{
            background: "var(--accent)",
            color: "var(--accent-ink)",
            padding: "6px 22px 12px",
            borderRadius: 18,
            display: "inline-block",
            lineHeight: "0.95"
          }}>under a minute.</span>
        </h1>



        {/* ── Input / Demo area ── */}
        <div className="p-input-card" style={{ width: "100%", maxWidth: 820 }}>
          {showInput &&
          <div className="p-input-row">
              <span className="p-input-icon"><Ico.pin /></span>
              <input
              ref={inputRef}
              className="p-input"
              placeholder="Enter a property address…"
              value={inputVal}
              readOnly={isTyping}
              onChange={(e) => setInputVal(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && !isTyping && inputVal.trim() && goToPlatformSearch(inputVal.trim())} />
            
              <button
              className="p-input-go"
              style={{ background: "var(--accent)", color: "var(--accent-ink)" }}
              onClick={() => !isTyping && inputVal.trim() && goToPlatformSearch(inputVal.trim())}
              aria-label="Run">
              
                <span style={{ transform: "rotate(30deg)", display: "flex" }}><Ico.hammer /></span>
              </button>
            </div>
          }

          {(isRunning || isDone) &&
          <div className="p-stream">
              <div className="p-stream-header">
                <span className="p-mono" style={{ color: "var(--muted)" }}>
                  {isDone ? "REPORT READY · 58.2s" : "ANALYZING…"}
                </span>
                <button className="p-reset" onClick={resetDemo}>✕ reset</button>
              </div>
              <div className="p-stream-items">
                {items.map((item, i) =>
              <div key={i} className="p-stream-item">
                    <span className="p-stream-check" style={{ color: isDone || i < items.length - 1 ? "var(--accent, #111)" : "var(--muted)" }}>
                      <Ico.check />
                    </span>
                    <span className="p-mono" style={{ color: "var(--ink-soft)" }}>{item}</span>
                  </div>
              )}
                {isRunning && items.length < STREAM_ITEMS.length &&
              <div className="p-stream-item p-stream-item--pulse">
                    <span className="p-stream-spin"><Ico.loader /></span>
                    <span className="p-mono" style={{ color: "var(--muted)" }}>Processing…</span>
                  </div>
              }
              </div>
              {isDone &&
            <div className="p-result">
                  <div className="p-result-badge">FEASIBILITY · <strong>PASS</strong></div>
                  <div className="p-result-stats">
                    {[["22", "units"], ["14,820 sf", "GBA"], ["18.4%", "uIRR"], ["58s", "run time"]].map(([v, l]) =>
                <div key={l} className="p-result-stat">
                        <span className="p-result-num">{v}</span>
                        <span className="p-mono" style={{ color: "var(--muted)" }}>{l}</span>
                      </div>
                )}
                  </div>
                  <a href="#report" className="p-result-cta">
                    View full report <Ico.arrow />
                  </a>
                </div>
            }
            </div>
          }

          {showInput &&
          <div className="p-input-meta">
              <span className="p-input-live">
                <span style={{ width: 6, height: 6, borderRadius: 999, background: "#22c55e", display: "inline-block" }}></span>
                Live parcel data
              </span>
              <span>3,142 counties</span>
              <span>Avg 58s</span>
            </div>
          }
        </div>

        {/* sample addresses */}
        {isIdle &&
        <div className="p-samples" style={{ flexDirection: "row", flexWrap: "wrap", justifyContent: "center", maxWidth: 820, marginLeft: "auto", marginRight: "auto" }}>
            {[
          ["2401 Pacific Ave, Venice CA", "22 units · 18.4% uIRR"],
          ["188 Greenpoint Ave, Brooklyn NY", "14 units · 16.1% uIRR"],
          ["4400 Westheimer Rd, Houston TX", "31 units · 21.2% uIRR"]].
          map(([addr, hint]) =>
          <button key={addr} className="p-sample" onClick={() => goToPlatformSearch(addr)}>
                <Ico.pin /> <strong>{addr}</strong> <span className="p-mono" style={{ color: "var(--muted)", fontSize: 11 }}>{hint}</span>
              </button>
          )}
          </div>
        }


      </div>
    </section>);

}

// ── Dashboard mockup — faithful recreation of the real Primer app ─────────
// Scoped slate/shadcn palette + NYC-blue accents (matches Precursor_Version_4).
const MK = {
  bg: "#FFFFFF", bg2: "#F8FAFC", fg: "#0F172A", muted: "#64748B",
  muted2: "#94A3B8", border: "#E2E8F0", blue: "#2563EB", blueBg: "#EFF4FF",
  sans: '"Geist", system-ui, sans-serif', mono: '"Geist Mono", monospace',
};
function DashboardMockup({ animate = true }) {
  return (
    <div className={`p-mockup${animate ? " p-mockup--tilt" : ""}`} id="report" style={{ fontFamily: MK.sans, color: MK.fg, background: MK.bg }}>
      {/* three-panel layout (no browser chrome — full-bleed app like the real product) */}
      <div className="p-mockup-body" style={{ display: "grid", gridTemplateColumns: "330px 1fr 372px", height: 620, fontSize: 13 }}>

        {/* ══ LEFT: Property Details ══ */}
        <aside style={{ background: MK.bg, borderRight: `1px solid ${MK.border}`, display: "flex", flexDirection: "column", overflow: "hidden" }}>
          {/* panel header */}
          <div style={{ padding: "11px 14px", borderBottom: `1px solid ${MK.border}`, display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0 }}>
            <span style={{ display: "flex", alignItems: "center", gap: 7, fontWeight: 600, fontSize: 14, color: MK.fg }}>
              <img src="assets/primer-mark.png" style={{ width: 16, height: 16 }} alt=""/> Property Details
            </span>
            <span style={{ color: MK.muted2, display: "flex" }}><Ico.x/></span>
          </div>
          {/* tabs */}
          <div style={{ display: "flex", borderBottom: `1px solid ${MK.border}`, flexShrink: 0 }}>
            {["Property Details", "Building Imagery"].map((t, i) => (
              <div key={t} style={{ padding: "10px 16px", fontSize: 13.5, fontWeight: 500, color: i === 0 ? MK.blue : MK.muted, borderBottom: i === 0 ? `2px solid ${MK.blue}` : "2px solid transparent", marginBottom: -1, display: "flex", alignItems: "center", gap: 5 }}>{t}</div>
            ))}
          </div>

          <div style={{ overflow: "hidden", flex: 1, padding: 14 }}>
            {/* street view */}
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
              <span style={{ fontSize: 11.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: MK.muted }}>Street View</span>
              <span style={{ fontSize: 11.5, color: MK.muted2 }}>131 WEST 118 STREET</span>
            </div>
            <div style={{ borderRadius: 10, overflow: "hidden", position: "relative", height: 134, border: `1px solid ${MK.border}` }}>
              <img src="assets/streetview-venice.png" alt="Street view" style={{ width: "100%", height: "100%", objectFit: "cover", objectPosition: "center", display: "block" }}/>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 2px 14px" }}>
              <span style={{ fontSize: 11.5, color: MK.muted, textDecoration: "underline", textUnderlineOffset: 3, display: "flex", alignItems: "center", gap: 4 }}>Open in Google Maps <Ico.ext/></span>
              <span style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: "0.04em", color: MK.muted2 }}>Imagery © Google</span>
            </div>

            {/* header card */}
            <div style={{ borderRadius: 18, border: `1px solid ${MK.border}`, background: MK.bg, boxShadow: "0 1px 2px rgba(15,23,42,0.04)", padding: "16px 16px 14px", marginBottom: 12 }}>
              <div style={{ fontWeight: 700, fontSize: 17, letterSpacing: "-0.01em" }}>131 WEST 118 STREET</div>
              <div style={{ fontSize: 12.5, color: MK.muted, marginTop: 4, lineHeight: 1.45 }}>Manhattan · Block 1903, Lot 16<br/>New York County, NY · FIPS 36-061</div>
              <div style={{ display: "inline-block", marginTop: 10, padding: "3px 11px", background: MK.blueBg, color: MK.blue, borderRadius: 999, fontSize: 12.5, fontWeight: 600 }}>R7-2</div>
            </div>

            {/* quick stats / detail rows */}
            <div style={{ borderRadius: 18, border: `1px solid ${MK.border}`, background: MK.bg, padding: "6px 16px 8px", marginBottom: 12 }}>
              {[["Owner", "BRIAN J O'CONNOR"], ["Land Use", "Multi-Family Walk-Up"], ["Lot Area", "2,018 sq ft"], ["Lot Frontage", "20 ft"], ["Lot Depth", "100.92 ft"]].map(([k, v], i, a) => (
                <div key={k} style={{ display: "flex", justifyContent: "space-between", gap: 12, padding: "8px 0", borderBottom: i < a.length - 1 ? `1px solid ${MK.bg2}` : "none" }}>
                  <span style={{ color: MK.muted, fontSize: 13.5 }}>{k}</span>
                  <span style={{ fontWeight: 600, fontSize: 13.5, textAlign: "right", filter: k === "Owner" ? "blur(4px)" : "none", userSelect: k === "Owner" ? "none" : "auto" }}>{v}</span>
                </div>
              ))}
            </div>

            {/* building structure */}
            <div style={{ borderRadius: 18, border: `1px solid ${MK.border}`, background: MK.bg, padding: "12px 16px 8px" }}>
              <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.06em", color: MK.muted, marginBottom: 6, display: "flex", alignItems: "center", gap: 6 }}>
                <Ico.building/> Building Structure
              </div>
              {[["Year Built", "1899"], ["Year Altered", "1987"], ["Number of Buildings", "1"]].map(([k, v], i, a) => (
                <div key={k} style={{ display: "flex", justifyContent: "space-between", padding: "8px 0", borderBottom: i < a.length - 1 ? `1px solid ${MK.bg2}` : "none" }}>
                  <span style={{ color: MK.muted, fontSize: 13.5 }}>{k}</span>
                  <span style={{ fontWeight: 600, fontSize: 13.5 }}>{v}</span>
                </div>
              ))}
            </div>
          </div>
        </aside>

        {/* ══ CENTER: Map ══ */}
        <div style={{ position: "relative", background: "#EAE7E0", overflow: "hidden" }}>
          <img src="assets/map-venice.png" alt="Property map" style={{ width: "100%", height: "100%", objectFit: "cover", objectPosition: "center", display: "block" }}/>
        </div>

        {/* ══ RIGHT: AI Chat panel ══ */}
        <aside style={{ background: MK.bg, borderLeft: `1px solid ${MK.border}`, display: "flex", flexDirection: "column" }}>
          {/* header: Saved + avatar */}
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: `1px solid ${MK.border}`, padding: "8px 14px", flexShrink: 0 }}>
            <span style={{ display: "flex", alignItems: "center", gap: 7, fontSize: 14, fontWeight: 500, color: MK.fg }}><Ico.folder/> Saved</span>
            <div style={{ width: 28, height: 28, borderRadius: 999, background: "linear-gradient(135deg,#F59E0B,#EF4444)", display: "grid", placeItems: "center", color: "#fff", fontSize: 11, fontWeight: 700 }}>JD</div>
          </div>

          {/* welcome empty-state */}
          <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "24px 24px", textAlign: "center" }}>
            <img src="assets/primer-mark.png" alt="" style={{ width: 124, height: 124, opacity: 0.18, marginBottom: 18 }}/>
            <div style={{ fontWeight: 600, fontSize: 24, letterSpacing: "-0.02em", marginBottom: 8 }}>Welcome to Primer</div>
            <div style={{ fontSize: 13, color: MK.muted, lineHeight: 1.55, maxWidth: 300 }}>Ask me anything about real estate. I can help with zoning, development analysis, and more.</div>
            <div style={{ display: "flex", gap: 7, marginTop: 18, flexWrap: "wrap", justifyContent: "center" }}>
              {["Zoning requirements", "Recent sales", "Development potential"].map(c => (
                <div key={c} style={{ padding: "6px 12px", border: `1px solid ${MK.border}`, borderRadius: 999, fontSize: 11.5, fontWeight: 500, color: MK.fg, background: MK.bg }}>{c}</div>
              ))}
            </div>
          </div>

          {/* input area */}
          <div style={{ padding: 16, flexShrink: 0 }}>
            {/* property context chip */}
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
              <span style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 10px", background: "rgba(15,23,42,0.07)", color: MK.fg, borderRadius: 999, fontSize: 11, fontWeight: 500 }}>
                <Ico.building/> 131 WEST 118 STREET
              </span>
              <span style={{ fontSize: 10.5, color: MK.muted }}>Questions will include property context</span>
            </div>
            {/* unified input box */}
            <div style={{ borderRadius: 16, border: `1px solid ${MK.border}`, background: MK.bg }}>
              <div style={{ padding: "14px 16px 4px", fontSize: 14, color: MK.muted2 }}>Ask anything about NYC real estate...</div>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "4px 8px 8px" }}>
                <div style={{ display: "flex", gap: 2 }}>
                  {[<Ico.plus/>, <Ico.sliders/>, <Ico.file/>].map((ic, i) => (
                    <span key={i} style={{ width: 30, height: 30, borderRadius: 999, display: "grid", placeItems: "center", color: MK.muted }}>{ic}</span>
                  ))}
                </div>
                <div style={{ display: "flex", gap: 2, alignItems: "center" }}>
                  <span style={{ width: 30, height: 30, borderRadius: 999, display: "grid", placeItems: "center", color: MK.muted2 }}><Ico.mic/></span>
                  <span style={{ width: 30, height: 30, borderRadius: 999, display: "grid", placeItems: "center", color: "#fff", background: MK.fg }}><span style={{ transform: "rotate(30deg)", display: "flex" }}><Ico.hammer/></span></span>
                </div>
              </div>
            </div>
            <div style={{ textAlign: "center", fontSize: 10.5, color: MK.muted2, marginTop: 8 }}>AI can make mistakes. Please verify important information.</div>
          </div>
        </aside>
      </div>
    </div>
  );
}

Object.assign(window, { Nav, Hero, DashboardMockup, Ico, InteractiveDotField });