// Small atomic components shared across sections
const { useState, useEffect, useMemo, useRef } = React;

// ─────────── Global a11y primitives ───────────
// Inject accessibility primitives once per page: skip link + focus-visible styles.
if (typeof document !== "undefined" && !document.getElementById("a11y-primitives")) {
  const style = document.createElement("style");
  style.id = "a11y-primitives";
  style.textContent = `
    /* Skip-to-content link — only visible on keyboard focus */
    .skip-to-content {
      position: absolute;
      top: -100px;
      left: 0;
      background: #004AAD;
      color: #fff;
      padding: 10px 18px;
      z-index: 10000;
      text-decoration: none;
      font-weight: 600;
      font-size: 14px;
      border-radius: 0 0 8px 0;
    }
    .skip-to-content:focus {
      top: 0;
    }
    /* Visible focus ring for keyboard users */
    *:focus { outline: none; }
    *:focus-visible {
      outline: 2px solid #004AAD;
      outline-offset: 2px;
      border-radius: 4px;
    }
    /* Respect reduced motion */
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
      }
    }
  `;
  document.head.appendChild(style);

  // Inject skip link into body (runs after React mounts, so prepend to body)
  const injectSkip = () => {
    if (document.getElementById("skip-to-content")) return;
    const a = document.createElement("a");
    a.id = "skip-to-content";
    a.className = "skip-to-content";
    a.href = "#main";
    a.textContent = "Skip to main content";
    document.body.insertBefore(a, document.body.firstChild);
  };
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", injectSkip);
  } else {
    injectSkip();
  }
}

// Tile-reveal observer — adds `.in-view` to any `.tile-reveal` element
// when it scrolls into view. Stagger comes from inline `--i`. Reduced-
// motion users get `.in-view` immediately so content is never hidden.
//
// In SPA mode, route changes mount fresh tile-reveal elements long after
// the initial timed scans have fired. A MutationObserver catches those
// dynamic insertions so newly-mounted page subtrees still reveal on scroll.
if (typeof document !== "undefined" && !window.__vmTileReveal) {
  window.__vmTileReveal = true;
  const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
  const reveal = (el) => el.classList.add("in-view");

  if (reduced) {
    const flushAll = () => document.querySelectorAll(".tile-reveal").forEach(reveal);
    if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", flushAll);
    else flushAll();
    setTimeout(flushAll, 100);
    setTimeout(flushAll, 800);
    // SPA route changes — flush newly-inserted tiles immediately.
    if ("MutationObserver" in window) {
      const mo = new MutationObserver(() => flushAll());
      const start = () => mo.observe(document.body, { childList: true, subtree: true });
      if (document.body) start();
      else document.addEventListener("DOMContentLoaded", start);
    }
  } else if ("IntersectionObserver" in window) {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { reveal(e.target); io.unobserve(e.target); }
      });
    }, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
    const scan = () => {
      document.querySelectorAll(".tile-reveal:not(.in-view)").forEach((el) => io.observe(el));
    };
    // Expose scan so router.jsx can re-trigger it on route change as a belt-and-suspenders.
    window.__vmTileScan = scan;
    if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", scan);
    else scan();
    // Catch React's first paints.
    setTimeout(scan, 100);
    setTimeout(scan, 800);
    setTimeout(scan, 2000);
    // Catch any tiles inserted later (SPA route changes, async data loads).
    if ("MutationObserver" in window) {
      const mo = new MutationObserver((muts) => {
        for (const m of muts) {
          for (const n of m.addedNodes) {
            if (n.nodeType !== 1) continue;
            if (n.classList?.contains("tile-reveal") || n.querySelector?.(".tile-reveal")) {
              scan();
              return;
            }
          }
        }
      });
      const start = () => mo.observe(document.body, { childList: true, subtree: true });
      if (document.body) start();
      else document.addEventListener("DOMContentLoaded", start);
    }
  }
}

// useSpotlight — wires a pointermove listener on the ref'd element that
// updates --mx and --my CSS custom properties. Pair with the spotlight
// gradient defined in technology.css. Skipped under reduced-motion.
function useSpotlight(ref){
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
    el.style.setProperty("--mx", "70%");
    el.style.setProperty("--my", "30%");
    el.classList.add("has-spotlight");
    let raf = 0;
    const onMove = (e) => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = 0;
        const r = el.getBoundingClientRect();
        const x = ((e.clientX - r.left) / r.width) * 100;
        const y = ((e.clientY - r.top) / r.height) * 100;
        el.style.setProperty("--mx", `${x}%`);
        el.style.setProperty("--my", `${y}%`);
      });
    };
    el.addEventListener("pointermove", onMove);
    return () => {
      el.removeEventListener("pointermove", onMove);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);
}

// Counter — counts from 0 to value once when scrolled into view.
// Respects prefers-reduced-motion (renders the final value immediately).
// Uses requestAnimationFrame + easeOutQuart over `duration` ms.
function Counter({ value, suffix = "", duration = 1400, decimals = 0 }){
  const [n, setN] = useState(0);
  const ref = useRef(null);
  const fired = useRef(false);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
    if (reduced) { setN(value); fired.current = true; return; }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (!e.isIntersecting || fired.current) return;
        fired.current = true;
        const start = performance.now();
        const tick = (now) => {
          const t = Math.min(1, (now - start) / duration);
          const eased = 1 - Math.pow(1 - t, 4); // easeOutQuart
          setN(value * eased);
          if (t < 1) requestAnimationFrame(tick);
          else setN(value);
        };
        requestAnimationFrame(tick);
      });
    }, { threshold: 0.4 });

    io.observe(el);
    return () => io.disconnect();
  }, [value, duration]);

  const formatted = decimals > 0
    ? n.toFixed(decimals)
    : Math.round(n).toLocaleString();

  return (
    <span ref={ref} style={{fontVariantNumeric:"tabular-nums slashed-zero"}}>
      {formatted}{suffix && <span style={{opacity:.7}}>{suffix}</span>}
    </span>
  );
}

function DotMark({size=22, color="#3393F0"}){
  // Recreates the "V of dots" from the VivaMed logo mark — tiny molecular cluster
  const rows = [
    [1,0,0,0,0,0,1,0,0,0,0,0,1],
    [0,1,0,0,0,0,1,0,0,0,0,1,0],
    [0,0,1,0,0,0,1,0,0,0,1,0,0],
    [0,0,0,1,0,0,1,0,0,1,0,0,0],
    [0,0,0,0,1,0,1,0,1,0,0,0,0],
    [0,0,0,0,0,1,1,1,0,0,0,0,0],
    [0,0,0,0,0,0,1,0,0,0,0,0,0],
  ];
  const unit = size/14;
  return (
    <svg width={size} height={size*0.7} viewBox={`0 0 ${14*unit} ${7.5*unit}`} style={{display:"block"}}>
      {rows.map((row,y)=>row.map((v,x)=>v?(
        <circle key={`${x}-${y}`} cx={(x+0.5)*unit} cy={(y+0.5)*unit} r={unit*0.35} fill={color}
          opacity={0.35 + (y*0.1)} />
      ):null))}
    </svg>
  );
}

function Nav({active, darkOnTop = true}){
  const links = [
    {href:"/", label:"Home", key:"home"},
    {href:"/pipeline", label:"Pipeline", key:"pipeline"},
    {href:"/platform", label:"Platform", key:"platform"},
    {href:"/people", label:"People", key:"people"},
    {href:"/partnerships", label:"Partnerships", key:"partnerships"},
    {href:"/investors", label:"Investors", key:"investors"},
  ];
  const [scrolled, setScrolled] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  useEffect(()=>{
    const on = ()=> setScrolled(window.scrollY > 20);
    on(); window.addEventListener("scroll", on, {passive:true});
    return ()=> window.removeEventListener("scroll", on);
  },[]);
  useEffect(()=>{
    document.body.style.overflow = mobileOpen ? "hidden" : "";
    return ()=> { document.body.style.overflow = ""; };
  },[mobileOpen]);
  return (
    <div className={`nav-wrap${scrolled?" scrolled":""}${darkOnTop?" on-dark":""}`}>
      <nav className="nav">
        <a href="/" className="nav-brand">
          <img src="assets/vivamed-logo.png" alt="VivaMed"/>
        </a>
        <div className="nav-pill" role="navigation">
          {links.map(l=>(
            <a key={l.key} className={`nav-pill-link${active===l.key?" active":""}`} href={l.href}>
              <span>{l.label}</span>
            </a>
          ))}
        </div>
        <a className="nav-cta" href="mailto:info@vivamed.com">
          <span>Request access</span>
          <svg viewBox="0 0 16 16" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M3 8h10M9 4l4 4-4 4"/></svg>
        </a>
        <button
          className={`nav-hamburger${mobileOpen?" is-open":""}`}
          aria-label={mobileOpen ? "Close menu" : "Open menu"}
          aria-expanded={mobileOpen}
          aria-controls="nav-mobile-panel"
          onClick={()=>setMobileOpen(o=>!o)}
        >
          <span/><span/><span/>
        </button>
      </nav>
      {mobileOpen && (
        <div className="nav-mobile-sheet" onClick={(e)=>{ if(e.target===e.currentTarget) setMobileOpen(false);}}>
          <div className="nav-mobile-panel">
            {links.map(l=>(
              <a key={l.key} href={l.href} className={`nav-mobile-link${active===l.key?" active":""}`} onClick={()=>setMobileOpen(false)}>
                {l.label}
              </a>
            ))}
            <a className="nav-mobile-cta" href="mailto:info@vivamed.com" onClick={()=>setMobileOpen(false)}>
              Request access
              <svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M3 8h10M9 4l4 4-4 4"/></svg>
            </a>
          </div>
        </div>
      )}
    </div>
  );
}

function GeneChips({genes, large=false}){
  return (
    <div className="gene-chips">
      {genes.map(g=><span key={g} className={`gene-chip${large?" lg":""}`}>{g}</span>)}
    </div>
  );
}

function SectionHead({eyebrow, title, lede, children, align}){
  return (
    <div className="section-head" style={align==="center"?{margin:"0 auto 64px",textAlign:"center"}:undefined}>
      <div className="section-eyebrow" style={align==="center"?{justifyContent:"center"}:undefined}>
        <span className="line"/>{eyebrow}
      </div>
      <h2 className="section-title">{title}</h2>
      {lede && <p className="section-lede" style={align==="center"?{margin:"0 auto"}:undefined}>{lede}</p>}
      {children}
    </div>
  );
}

// ─────────── Canonical site footer (used on every page) ───────────
function SiteFooter(){
  return (
    <footer className="site-footer">
      <div className="site-footer-inner">
        <div className="site-footer-col">
          <img src="assets/vivamed-logo-300.png" alt="VivaMed BioPharma" style={{height:36,filter:"brightness(0) invert(1)",opacity:.95,marginBottom:14}}/>
          <p className="site-footer-blurb">
            Developing tomorrow's therapies, today, through precision drug discovery and repurposing.
          </p>
        </div>
        <div className="site-footer-col">
          <h4>Company</h4>
          <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/platform">Platform</a></li>
            <li><a href="/pipeline">Pipeline</a></li>
            <li><a href="/partnerships">Partnerships</a></li>
            <li><a href="/people">People</a></li>
          </ul>
        </div>
        <div className="site-footer-col">
          <h4>People</h4>
          <ul>
            <li><a href="/people">Leadership</a></li>
            <li><a href="/advisors">Advisors</a></li>
          </ul>
        </div>
        <div className="site-footer-col">
          <h4>Legal</h4>
          <ul>
            <li><a href="/privacy-policy">Privacy Policy</a></li>
            <li><a href="/terms-of-use">Terms of Use</a></li>
          </ul>
        </div>
        <div className="site-footer-col">
          <h4>Contact</h4>
          <ul>
            <li><a href="mailto:info@vivamed.com">info@vivamed.com</a></li>
            <li><a href="/contact">Contact page</a></li>
          </ul>
          <p className="site-footer-offices">Phoenix · New York · Basel · Bogotá · Riyadh</p>
        </div>
      </div>
      <div className="site-footer-legal">
        <p className="site-footer-disclaimer">
          VivaMed.com is for general informational purposes only and is not medical, legal, tax, or investment advice. Please do not submit patient-identifiable or other sensitive health information through this website.
        </p>
        <p className="site-footer-copy">© 2026 VivaMed BioPharma, Inc. · All rights reserved.</p>
      </div>
      <style>{`
        .site-footer {
          background: #061526;
          color: #9DB1C5;
          padding: 80px 0 40px;
        }
        .site-footer-inner {
          max-width: 1280px;
          margin: 0 auto;
          padding: 0 32px;
          display: grid;
          grid-template-columns: 2fr 1fr 1fr 1fr 1.4fr;
          gap: 48px;
        }
        @media (max-width: 900px) {
          .site-footer-inner { grid-template-columns: 1fr 1fr; gap: 32px; }
        }
        .site-footer-col h4 {
          color: #E6EDF5;
          font-size: 13px;
          letter-spacing: .08em;
          text-transform: uppercase;
          margin: 0 0 16px;
          font-weight: 600;
        }
        .site-footer-col ul {
          list-style: none;
          padding: 0;
          margin: 0;
        }
        .site-footer-col li {
          margin-bottom: 10px;
          font-size: 14px;
        }
        .site-footer-col a {
          color: #9DB1C5;
          text-decoration: none;
          transition: color 180ms ease;
        }
        .site-footer-col a:hover {
          color: #3393F0;
        }
        .site-footer-blurb {
          font-size: 13.5px;
          line-height: 1.6;
          margin: 0;
          max-width: 300px;
        }
        .site-footer-offices {
          font-size: 12.5px;
          margin: 16px 0 0;
          color: #6B8AAB;
        }
        .site-footer-legal {
          max-width: 1280px;
          margin: 56px auto 0;
          padding: 32px 32px 0;
          border-top: 1px solid rgba(255,255,255,.08);
        }
        .site-footer-disclaimer {
          font-size: 11.5px;
          line-height: 1.6;
          color: #6B8AAB;
          margin: 0 0 16px;
          max-width: 900px;
        }
        .site-footer-copy {
          font-size: 12px;
          color: #6B8AAB;
          margin: 0;
        }
      `}</style>
    </footer>
  );
}

// ─────────── Back-to-top button (persistent across routes) ───────────
function BackToTop(){
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    // Show as soon as the user starts scrolling — small threshold so it
    // appears within the first scroll gesture, not at the bottom.
    const onScroll = () => setVisible(window.scrollY > 80);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  const onClick = () => {
    const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
    window.scrollTo({ top: 0, behavior: reduced ? "auto" : "smooth" });
  };
  return (
    <button
      type="button"
      className={`back-to-top${visible ? " visible" : ""}`}
      aria-label="Back to top"
      onClick={onClick}
    >
      <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="M3 10l5-5 5 5"/>
      </svg>
    </button>
  );
}

Object.assign(window, { DotMark, Nav, GeneChips, SectionHead, SiteFooter, BackToTop });
