const { useState, useEffect, useMemo, useCallback, useRef } = React;

/* ============ Path-based router (History API) ============ */
const STATIC_ROUTES = ["contact","about","process","partners","careers","terms","privacy","cookies","book"];
const parsePath = () => {
  const p = window.location.pathname;
  const search = window.location.search;
  if (p === "/" || p === "") return { name: "home" };
  const mp = p.match(/^\/product\/([\w-]+)/);
  if (mp) return { name: "product", id: mp[1] };
  const mc = p.match(/^\/category\/([\w-]+)/);
  if (mc) return { name: "category", id: mc[1] };
  if (/^\/custom\/?$/.test(p)) return { name: "custom" };
  if (/^\/checkout\/thank-you\/?$/.test(p)) return { name: "thankyou" };
  if (/^\/checkout\/?$/.test(p)) return { name: "checkout" };
  for (const r of STATIC_ROUTES) {
    if (new RegExp(`^/${r}/?$`).test(p)) return { name: r };
  }
  if (/^\/shop(\/|\?|$)/.test(p)) {
    const params = new URLSearchParams(search);
    let cat = params.get("cat") || "all";
    if (LEGACY_CATEGORY_REDIRECT[cat]) cat = LEGACY_CATEGORY_REDIRECT[cat];
    return {
      name: "shop",
      cat,
      sort: params.get("sort") || "featured",
      q: params.get("q") || "",
    };
  }
  return { name: "notfound", path: p };
};

/** Old category URLs → canonical slugs (Lifecycle / Campaigns / AI → HubSpot; Web → Development). */
const LEGACY_CATEGORY_REDIRECT = {
  lifecycle: "hubspot",
  campaigns: "hubspot",
  ai: "hubspot",
  web: "development",
};

const resolveCategoryPath = (path) => {
  const m = String(path).match(/^\/category\/([\w-]+)/);
  if (!m) return path;
  const nid = LEGACY_CATEGORY_REDIRECT[m[1]];
  return nid ? `/category/${nid}` : path;
};

let _setRoute = null;
const navigate = (path) => {
  const next = resolveCategoryPath(path);
  history.pushState(null, "", next);
  if (_setRoute) _setRoute(parsePath());
  window.scrollTo({ top: 0, behavior: "instant" });
};

const useRoute = () => {
  const [route, setRoute] = useState(() => {
    if (typeof window === "undefined") return { name: "home" };
    const p = window.location.pathname;
    const fixed = resolveCategoryPath(p);
    if (fixed !== p) history.replaceState(null, "", fixed);
    return parsePath();
  });
  useEffect(() => {
    _setRoute = setRoute;
    const p = window.location.pathname;
    const search = window.location.search || "";
    /* Normalize legacy /shop?cat= URLs in the address bar */
    if (p.startsWith("/shop")) {
      const params = new URLSearchParams(search);
      const raw = params.get("cat");
      if (raw && LEGACY_CATEGORY_REDIRECT[raw]) {
        params.set("cat", LEGACY_CATEGORY_REDIRECT[raw]);
        const qs = params.toString();
        history.replaceState(null, "", qs ? `/shop?${qs}` : "/shop");
        setRoute(parsePath());
      }
    }
    // Backward compat: redirect old #/ hash URLs to clean paths
    const hash = window.location.hash;
    if (hash && hash.startsWith("#/")) {
      history.replaceState(null, "", hash.slice(1));
      setRoute(parsePath());
    }
    const onPop = () => {
      const p = window.location.pathname;
      const fixed = resolveCategoryPath(p);
      if (fixed !== p) history.replaceState(null, "", fixed);
      setRoute(parsePath());
      window.scrollTo({ top: 0, behavior: "instant" });
    };
    window.addEventListener("popstate", onPop);
    return () => { window.removeEventListener("popstate", onPop); _setRoute = null; };
  }, []);
  return route;
};
/* ---------- SEO: per-route document title, meta description, canonical, OG, JSON-LD ---------- */
const SITE_URL  = "https://vestalhub.com";
const SITE_NAME = "Vestal Hub";
const HOME_TITLE = "Vestal Hub — We make HubSpot easy for you";
const HOME_DESC  = "We make HubSpot easy for you. HubSpot Gold Partner trusted by 100+ companies. Browse 25+ fixed-scope HubSpot, RevOps & AI services — from quick fixes to complex implementations — priced like software. SOW within 1 business day, no discovery call.";
const HOME_OG_IMAGE = `${SITE_URL}/assets/products/hubspot-onboarding-wide.png?v=2`;

const setMeta = (selector, attr, value) => {
  let el = document.head.querySelector(selector);
  if (!el) {
    el = document.createElement("meta");
    const m = selector.match(/\[(name|property)="([^"]+)"\]/);
    if (m) el.setAttribute(m[1], m[2]);
    document.head.appendChild(el);
  }
  el.setAttribute(attr, value);
};
const setLink = (rel, href) => {
  let el = document.head.querySelector(`link[rel="${rel}"]`);
  if (!el) {
    el = document.createElement("link");
    el.setAttribute("rel", rel);
    document.head.appendChild(el);
  }
  el.setAttribute("href", href);
};
const setJsonLd = (data) => {
  const el = document.getElementById("vh-route-jsonld");
  if (el) el.textContent = data ? JSON.stringify(data) : "{}";
};

const useDocumentMeta = (route) => {
  useEffect(() => {
    let title = HOME_TITLE;
    let desc  = HOME_DESC;
    let path  = "/";
    let image = HOME_OG_IMAGE;
    let jsonld = null;

    if (route.name === "product") {
      const p = (window.PRODUCTS || []).find(x => x.id === route.id);
      if (p) {
        title = `${p.name} — ${SITE_NAME}`;
        desc  = (p.desc || HOME_DESC).slice(0, 220);
        path  = `/product/${p.id}`;
        image = p.image
          ? (p.image.startsWith("http") ? p.image : `${SITE_URL}${p.image.startsWith("/") ? "" : "/"}${p.image}`)
          : HOME_OG_IMAGE;
        jsonld = {
          "@context": "https://schema.org",
          "@type": "Service",
          "name": p.name,
          "description": p.desc || desc,
          "image": image,
          "provider": { "@type": "Organization", "name": SITE_NAME, "url": SITE_URL },
          "serviceType": p.category || "HubSpot service",
          "url": `${SITE_URL}${path}`,
          "offers": {
            "@type": "Offer",
            "price": String(p.price || 0),
            "priceCurrency": "USD",
            "availability": "https://schema.org/InStock",
            "url": `${SITE_URL}${path}`
          }
        };
      }
    } else if (route.name === "category") {
      const meta = (window.CATEGORY_META || {})[route.id];
      const label = meta?.name || route.id;
      title = `${label} services — ${SITE_NAME}`;
      desc  = meta?.sub || `Browse fixed-scope ${label.toLowerCase()} services. Priced like software, shipped by senior operators.`;
      path  = `/category/${route.id}`;
    } else if (route.name === "shop") {
      title = route.q
        ? `Search "${route.q}" — ${SITE_NAME} shop`
        : `Browse all services — ${SITE_NAME} shop`;
      desc  = "25+ fixed-scope HubSpot, RevOps & AI plays. Pricing on every card. Add what you need to your cart and we email a SOW within one business day.";
      const qs = [];
      if (route.cat && route.cat !== "all") qs.push(`cat=${route.cat}`);
      if (route.q) qs.push(`q=${encodeURIComponent(route.q)}`);
      path  = `/shop${qs.length ? "?" + qs.join("&") : ""}`;
    } else if (route.name === "custom") {
      title = `Custom work — hours packs & monthly retainers — ${SITE_NAME}`;
      desc  = "Senior HubSpot & RevOps operators on-tap. Hours packs (5/15/40h tiers) or monthly retainers. For work that doesn't fit a fixed SOW.";
      path  = "/custom";
    } else if (route.name === "checkout") {
      title = `Checkout — SOW within 1 business day — ${SITE_NAME}`;
      desc  = "Send your brief and receive a Statement of Work within one business day. No charge until signed. No discovery call required.";
      path  = "/checkout";
    } else if (route.name === "thankyou") {
      title = `Brief received — ${SITE_NAME}`;
      desc  = "Your Statement of Work arrives within one business day.";
      path  = "/checkout/thank-you";
    } else if (route.name === "contact") {
      title = `Contact — talk to a senior operator — ${SITE_NAME}`;
      desc  = "Tell us what you're shipping. We reply in one business day with the right engagement model and a fixed price — no discovery call required.";
      path  = "/contact";
    } else if (route.name === "about") {
      title = `About — built by senior operators — ${SITE_NAME}`;
      desc  = "HubSpot Gold Partner. Trusted by 100+ companies across SaaS, agencies, services, finance, and nonprofits. Senior operators only — no juniors, no rotations.";
      path  = "/about";
    } else if (route.name === "process") {
      title = `Process — how we ship — ${SITE_NAME}`;
      desc  = "The 4-stage delivery model behind every Vestal Hub engagement. Browse, brief, sign, ship. No surprises.";
      path  = "/process";
    } else if (route.name === "partners") {
      title = `Partner program — ${SITE_NAME}`;
      desc  = "Refer or co-sell with Vestal Hub. For agencies, RevOps consultants, and HubSpot peers.";
      path  = "/partners";
    } else if (route.name === "careers") {
      title = `Careers — senior HubSpot & RevOps operators — ${SITE_NAME}`;
      desc  = "We hire senior operators who've already shipped this work. No utilization targets, no juniors-shadowing-seniors model.";
      path  = "/careers";
    } else if (route.name === "terms") {
      title = `Terms of service — ${SITE_NAME}`;
      desc  = "Vestal Hub terms of service.";
      path  = "/terms";
    } else if (route.name === "privacy") {
      title = `Privacy policy — ${SITE_NAME}`;
      desc  = "How Vestal Hub handles your data.";
      path  = "/privacy";
    } else if (route.name === "cookies") {
      title = `Cookies — ${SITE_NAME}`;
      desc  = "Vestal Hub cookies policy.";
      path  = "/cookies";
    } else if (route.name === "notfound") {
      title = `Page not found — ${SITE_NAME}`;
      desc  = "The page you were looking for doesn't exist. Browse our HubSpot & RevOps services instead.";
      path  = "/404";
    }

    const fullUrl = `${SITE_URL}${path}`;
    document.title = title;
    setMeta('meta[name="description"]', "content", desc);
    setLink("canonical", fullUrl);
    setMeta('meta[property="og:title"]',       "content", title);
    setMeta('meta[property="og:description"]', "content", desc);
    setMeta('meta[property="og:url"]',         "content", fullUrl);
    setMeta('meta[property="og:image"]',       "content", image);
    setMeta('meta[name="twitter:title"]',      "content", title);
    setMeta('meta[name="twitter:description"]',"content", desc);
    setMeta('meta[name="twitter:image"]',      "content", image);
    setJsonLd(jsonld);
  }, [route.name, route.id, route.cat, route.q, route.sort, route.path]);
};

const goToProduct  = (id) => { navigate(`/product/${id}`); };
const goToCategory = (id) => { navigate(`/category/${id}`); };
const goToShop     = (cat, q) => {
  const params = [];
  let c = cat;
  if (c && LEGACY_CATEGORY_REDIRECT[c]) c = LEGACY_CATEGORY_REDIRECT[c];
  if (c && c !== "all") params.push(`cat=${c}`);
  if (q) params.push(`q=${encodeURIComponent(q)}`);
  navigate(params.length ? `/shop?${params.join("&")}` : `/shop`);
};
const goToCustom   = () => { navigate(`/custom`); };
const goToContact  = () => { navigate(`/contact`); };
const goToCheckout = () => { navigate(`/checkout`); };
const goToThankYou = () => { navigate(`/checkout/thank-you`); };
const goToAbout    = () => { navigate(`/about`); };
const goToProcess  = () => { navigate(`/process`); };
const goToPartners = () => { navigate(`/partners`); };
const goToCareers  = () => { navigate(`/careers`); };
const goToTerms    = () => { navigate(`/terms`); };
const goToPrivacy  = () => { navigate(`/privacy`); };
const goToCookies  = () => { navigate(`/cookies`); };
const goHome       = () => { navigate("/"); };

/* Vestal Hub social + brand constants */
const SOCIAL = {
  linkedin: "https://www.linkedin.com/company/vestalhub/",
  email:    "hi@vestalhub.com",
};

const Icon = ({ name, size = 18 }) => {
  const I = {
    search: <path d="M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16zM21 21l-4.3-4.3" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    heart: <path d="M12 21s-7-4.5-9.5-9C1 8.5 3 5 6.5 5c2 0 3.5 1 5.5 3 2-2 3.5-3 5.5-3C21 5 23 8.5 21.5 12 19 16.5 12 21 12 21z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    user: <g stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-7 8-7s8 3 8 7"/></g>,
    bag: <path d="M6 7h12l-1 13H7L6 7zm3 0a3 3 0 0 1 6 0" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    check: <path d="M20 6L9 17l-5-5" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    shield: <path d="M12 3l8 3v6c0 4.5-3.5 8-8 9-4.5-1-8-4.5-8-9V6l8-3z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    truck: <g stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"><rect x="2" y="7" width="12" height="10" rx="1"/><path d="M14 10h4l3 3v4h-7z"/><circle cx="6" cy="18" r="2"/><circle cx="17" cy="18" r="2"/></g>,
    refresh: <path d="M3 12a9 9 0 0 1 15-6.7L21 8M21 3v5h-5M21 12a9 9 0 0 1-15 6.7L3 16M3 21v-5h5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    plus: <path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>,
    arrow: <path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    close: <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>,
    zap: <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    star: <path d="M12 2l3 7 7 1-5 5 1 7-6-4-6 4 1-7-5-5 7-1 3-7z" fill="currentColor"/>,
    ship: <g stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"><path d="M3 20h18M5 20l-2-7h18l-2 7M12 3v10M8 7l4-4 4 4"/></g>,
    chat: <path d="M21 12c0 5-4 8-9 8-1.5 0-3-.3-4-1l-5 1 1-4c-1-1.5-1-3-1-4 0-5 4-8 9-8s9 3 9 8z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    rocket: <path d="M4 20l4-4M8 20l-4-4M15 5l4 4c0 0 0 5-5 9l-4 2-6-6 2-4c4-5 9-5 9-5zM13 11l-2 2" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    layers: <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    code: <path d="M8 6l-6 6 6 6M16 6l6 6-6 6M14 4l-4 16" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
    mail: <g stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 7l10 7 10-7"/></g>,
    chart: <g stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" fill="none"><path d="M3 21h18M7 21V10M12 21V6M17 21v-8"/></g>,
    linkedin: <path d="M20.5 3h-17A.5.5 0 0 0 3 3.5v17a.5.5 0 0 0 .5.5h17a.5.5 0 0 0 .5-.5v-17a.5.5 0 0 0-.5-.5zM8.3 18.3H5.7V9.7h2.6v8.6zM7 8.6a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm11.3 9.7h-2.6v-4.2c0-1 0-2.3-1.4-2.3s-1.6 1.1-1.6 2.2v4.3h-2.6V9.7h2.5v1.2c.4-.7 1.2-1.4 2.5-1.4 2.7 0 3.2 1.8 3.2 4.1v4.7z" fill="currentColor"/>,
    sparkle: <path d="M12 2v6M12 16v6M2 12h6M16 12h6M5 5l4 4M15 15l4 4M19 5l-4 4M9 15l-4 4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/>,
    puzzle: <path d="M9 3a2 2 0 0 0-2 2v1H4a1 1 0 0 0-1 1v3h1a2 2 0 0 1 0 4H3v3a1 1 0 0 0 1 1h3v-1a2 2 0 0 1 4 0v1h3a1 1 0 0 0 1-1v-3h-1a2 2 0 0 1 0-4h1V7a1 1 0 0 0-1-1h-3V5a2 2 0 0 0-2-2z" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" fill="none"/>,
  };
  return <svg width={size} height={size} viewBox="0 0 24 24">{I[name]}</svg>;
};

const Stars = ({ r = 5 }) => (
  <div className="stars">{[1,2,3,4,5].map(i => <Icon key={i} name="star" size={12} />)}</div>
);

/* ============ Header ============ */
const Header = ({ count, onCart }) => {
  const [q, setQ] = useState("");
  const [open, setOpen] = useState(false);
  const [active, setActive] = useState(0);
  const inputRef = useRef(null);
  const wrapRef  = useRef(null);

  // ⌘K / Ctrl+K to focus, Escape to clear+close
  useEffect(() => {
    const onKey = (e) => {
      const k = (e.key || "").toLowerCase();
      if ((e.metaKey || e.ctrlKey) && k === "k") {
        e.preventDefault();
        inputRef.current?.focus();
        inputRef.current?.select();
        setOpen(true);
      }
    };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, []);

  // close on outside click
  useEffect(() => {
    const onClick = (e) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
    };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, []);

  // close on route change
  useEffect(() => {
    const onHash = () => { setOpen(false); setQ(""); };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  const matches = useMemo(() => {
    const s = q.trim().toLowerCase();
    if (!s) return [];
    const tokens = s.split(/\s+/).filter(Boolean);
    const scored = [];
    for (const p of (typeof PRODUCTS !== "undefined" ? PRODUCTS : [])) {
      if (p.hidden) continue;
      const name = (p.name || "").toLowerCase();
      const desc = (p.desc || "").toLowerCase();
      const catN = (p.category || p.cat || "").toLowerCase();
      const scope = Array.isArray(p.scope) ? p.scope.join(" ").toLowerCase() : "";
      const hay = `${name} ${desc} ${catN} ${scope}`;
      if (!tokens.every(t => hay.includes(t))) continue;
      let score = 0;
      if (name.startsWith(s)) score -= 100;
      else if (name.includes(s)) score -= 50;
      else if (catN.includes(s)) score -= 20;
      score += hay.indexOf(s);
      if (p.featured) score -= 5;
      scored.push({ p, score });
    }
    return scored.sort((a, b) => a.score - b.score).slice(0, 6).map(x => x.p);
  }, [q]);

  useEffect(() => { setActive(0); }, [q]);

  const submit = () => {
    const term = q.trim();
    if (!term) return;
    setOpen(false);
    inputRef.current?.blur();
    goToShop(null, term);
  };

  const pick = (p) => {
    setOpen(false);
    setQ("");
    goToProduct(p.id);
  };

  return (
  <>
    <div className="announce">
      ✦ Add services to cart · get your SOW and pay after approval · <a href="/shop" onClick={(e) => { e.preventDefault(); goToShop(); }} style={{textDecoration:"underline"}}>start here →</a>
    </div>
    <header className="hdr">
      <div className="wrap">
        <div className="hdr-inner">
          <a href="#" onClick={(e) => { e.preventDefault(); goHome(); }} className="logo" aria-label="Vestal Hub">
            <img src="Vestal-hub.png" alt="Vestal Hub" className="logo-img" />
          </a>
          <div className={`search${open && q.trim() ? " is-open" : ""}`} ref={wrapRef}>
            <Icon name="search" size={16} />
            <input
              ref={inputRef}
              placeholder="Search services, e.g. onboarding, audit, nurture…"
              value={q}
              onChange={(e) => { setQ(e.target.value); setOpen(true); }}
              onFocus={() => { if (q.trim()) setOpen(true); }}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault();
                  if (open && matches[active]) pick(matches[active]);
                  else submit();
                } else if (e.key === "Escape") {
                  if (q) { setQ(""); setOpen(false); }
                  else inputRef.current?.blur();
                } else if (e.key === "ArrowDown") {
                  e.preventDefault();
                  if (matches.length) { setOpen(true); setActive(a => Math.min(a + 1, matches.length - 1)); }
                } else if (e.key === "ArrowUp") {
                  e.preventDefault();
                  setActive(a => Math.max(a - 1, 0));
                }
              }}
              aria-label="Search the service catalog"
              aria-autocomplete="list"
              aria-expanded={open && !!q.trim()}
            />
            {q ? (
              <button
                type="button"
                className="search-clear"
                aria-label="Clear search"
                onMouseDown={(e) => e.preventDefault()}
                onClick={() => { setQ(""); setOpen(false); inputRef.current?.focus(); }}>
                <Icon name="close" size={14}/>
              </button>
            ) : (
            <kbd>⌘K</kbd>
            )}
            {open && q.trim() && (
              <div className="search-pop" role="listbox">
                {matches.length === 0 ? (
                  <div className="search-empty">
                    <div>No services match "<b>{q.trim()}</b>".</div>
                    <button type="button" className="search-empty-cta" onClick={submit}>
                      Search the full catalog → 
                    </button>
                  </div>
                ) : (
                  <>
                    <div className="search-pop-head">
                      // {matches.length} {matches.length === 1 ? "MATCH" : "MATCHES"}
                    </div>
                    {matches.map((p, i) => (
                      <button
                        key={p.id}
                        type="button"
                        className={`search-pop-row${i === active ? " on" : ""}`}
                        role="option"
                        aria-selected={i === active}
                        onMouseEnter={() => setActive(i)}
                        onMouseDown={(e) => e.preventDefault()}
                        onClick={() => pick(p)}>
                        <span className="r-thumb">
                          {p.image ? <img src={p.image} alt="" loading="lazy"/> : <Icon name="layers" size={18}/>}
                        </span>
                        <span className="r-body">
                          <span className="r-cat">{(p.category || p.cat || "").toUpperCase()}</span>
                          <span className="r-name">{p.name}</span>
                        </span>
                        <span className="r-price">${(p.price || 0).toLocaleString()}{p.cat === "custom" && p.id === "x-retainer" ? "/mo" : ""}</span>
                      </button>
                    ))}
                    <button type="button" className="search-pop-foot" onMouseDown={(e) => e.preventDefault()} onClick={submit}>
                      See all results for "<b>{q.trim()}</b>" <Icon name="arrow" size={12}/>
                    </button>
                  </>
                )}
              </div>
            )}
          </div>
          <div className="hdr-actions">
            <a href="/book" onClick={(e) => { e.preventDefault(); navigate("/book"); }} className="btn btn-primary hdr-book">Book a call</a>
            <button className="icon-btn" aria-label="Cart" onClick={onCart}>
              <Icon name="bag" />
              {count > 0 && <span className="b">{count}</span>}
            </button>
          </div>
        </div>
        <nav className="hdr-nav">
          <a href="/shop"      onClick={(e) => { e.preventDefault(); goToShop(); }}>All services</a>
          <a href="/category/hubspot"     onClick={(e) => { e.preventDefault(); goToCategory("hubspot"); }}>HubSpot</a>
          <a href="/category/development" onClick={(e) => { e.preventDefault(); goToCategory("development"); }}>Development</a>
          <a href="/category/addons" onClick={(e) => { e.preventDefault(); goToCategory("addons"); }}>Add-ons</a>
          <a href="/custom"          onClick={(e) => { e.preventDefault(); goToCustom(); }} style={{color:"var(--brand)"}}>Custom work</a>
          <div style={{flex:1}}/>
          <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Contact</a>
        </nav>
      </div>
      <div className="trust-row">
        <div className="t"><Icon name="check" size={14}/> SOW in 24 hours</div>
        <div className="t"><Icon name="check" size={14}/> Fixed price · no surprises</div>
        <div className="t"><Icon name="check" size={14}/> Built by senior operators</div>
      </div>
    </header>
  </>
);
};

/* ============ Hero — simplified, centered ============ */
const Hero = () => (
  <section className="hero">
    <div className="wrap">
      <div className="hero-grid">
        <h1>We make HubSpot <span className="hl">easy for you.</span></h1>
        <p className="hero-lead">
          From quick fixes to complex implementations, we handle HubSpot so your team stays focused.
        </p>
        <div className="hero-ctas">
          <a href="/shop" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToShop(); }}>Shop all services <Icon name="arrow" size={14}/></a>
          <a href="/process" className="btn btn-ghost" onClick={(e) => { e.preventDefault(); goToProcess(); }}>How it works</a>
        </div>
        <div className="hero-cred" role="complementary" aria-label="Partner status and customer trust">
          <div className="hero-cred-cell">
            <img
              src="assets/trust/hubspot-gold-partner.png"
              alt="HubSpot Solutions Partner — Gold"
              className="hero-cred-badge"
              width="120" height="120" loading="lazy"
            />
            <span className="hero-cred-copy">
              <b>HubSpot</b>
              <span>Gold Solutions Partner</span>
            </span>
          </div>
          <span className="hero-cred-divider" aria-hidden="true"/>
          <div className="hero-cred-cell">
            <span className="hero-cred-avatars" aria-hidden="true">
              <img src="assets/trust/avatar-copilotkit.webp"  alt="" width="32" height="32" loading="lazy"/>
              <img src="assets/trust/avatar-mavenagi.webp"    alt="" width="32" height="32" loading="lazy"/>
              <img src="assets/trust/avatar-catio.webp"       alt="" width="32" height="32" loading="lazy"/>
              <img src="assets/trust/avatar-kindsight.webp"   alt="" width="32" height="32" loading="lazy"/>
              <img src="assets/trust/avatar-talentcaddy.jpeg" alt="" width="32" height="32" loading="lazy"/>
            </span>
            <span className="hero-cred-copy">
              <span className="hero-cred-stars" aria-label="5 out of 5 stars">★★★★★</span>
              <span>Trusted by <b>100+ companies</b></span>
            </span>
          </div>
        </div>
      </div>
    </div>
  </section>
);

/* ============ Category Tiles ============ */
const Categories = () => {
  const cats = [
    { id: "hubspot",     n: "HubSpot",           i: "layers" },
    { id: "development", n: "Development",       i: "code" },
    { id: "addons",      n: "Add-ons",           i: "plus" },
    { id: "custom",      n: "Custom & Retainer", i: "refresh", href: "custom" },
  ];
  return (
    <section className="cat-section">
      <div className="wrap">
        <div className="section-head">
          <div>
            <h2>Shop <em>by category</em></h2>
            <div className="sub">{PRODUCTS.filter(p => !p.hidden).length} PROVEN PLAYS · BUILT FOR ANY INDUSTRY</div>
          </div>
          <a href="/shop" className="link" onClick={(e) => { e.preventDefault(); goToShop(); }}>View all <Icon name="arrow" size={12}/></a>
        </div>
        <div className="cat-tiles">
          {cats.map((c, i) => {
            const cnt = PRODUCTS.filter(p => p.cat === c.id && !p.hidden).length;
            return (
              <button key={c.id}
                      className="cat-tile cat-tile-link"
                      onClick={() => c.href === "custom" ? goToCustom() : goToCategory(c.id)}
                      aria-label={`Browse ${c.n} services`}>
              <div className="idx">[0{i+1}]</div>
              <div className="ic"><Icon name={c.i} size={20}/></div>
              <div>
                <div className="n">{c.n}</div>
                  <div className="c">{cnt} {cnt === 1 ? "SERVICE" : "SERVICES"}</div>
              </div>
                <span className="cat-tile-arrow"><Icon name="arrow" size={14}/></span>
              </button>
            );
          })}
        </div>
      </div>
    </section>
  );
};

/* ============ Products ============ */
const Product = ({ p, onAdd, wish, onWish }) => {
  const open = (e) => {
    if (e.defaultPrevented) return;
    goToProduct(p.id);
  };
  const stop = (e) => { e.preventDefault(); e.stopPropagation(); };
  return (
    <article className="product is-link" onClick={open} role="link" tabIndex={0}
             onKeyDown={(e) => { if (e.key === "Enter") open(e); }}>
      <div className="p-vis">
        {p.badge && (
          <div className="p-badges">
            <span className={`p-badge ${p.badge}`}>{p.badge === "new" ? "NEW" : "POPULAR"}</span>
          </div>
        )}
        <button className={`p-wish ${wish ? "on" : ""}`}
                onClick={(e)=>{stop(e); onWish(p.id);}}>
          <Icon name="heart" size={16}/>
        </button>
        {p.image ? (
          <img className="p-img" src={p.image} alt={p.name} loading="lazy"/>
        ) : (
        <div className="p-glyph">
          <span className="num">{p.num}</span>
          <span className="cat">{p.category}</span>
        </div>
        )}
        <div className="p-quick" onClick={(e) => { stop(e); onAdd(p); }}>
          <Icon name="bag" size={14}/> Quick add
        </div>
      </div>
      <div className="p-body">
        <span className="p-cat">{p.category}</span>
        <h3 className="p-name">{p.name}</h3>
        <p className="p-desc">{p.desc}</p>
        <div className="p-meta">
          <span className="m"><Icon name="truck" size={12}/> {p.duration}</span>
          <span className="m"><Icon name="shield" size={12}/> SOW in 24h</span>
        </div>
        <div className="p-foot">
          <div className="p-price">
            ${p.price.toLocaleString()}
            <span className="unit">{p.duration === "monthly" ? "/mo" : ""}</span>
          </div>
          <button className="p-add" onClick={(e) => { stop(e); onAdd(p); }} aria-label="Add to cart">
            <Icon name="plus" size={16}/>
          </button>
        </div>
      </div>
    </article>
  );
};

/* Homepage Shop — featured HubSpot services + Custom Dashboard Build + Monthly Retainer (8 cards) */
const Shop = ({ onAdd }) => {
  const [wish, setWish] = useState({});
  const featured = useMemo(() => {
    const base = PRODUCTS.filter(p => p.cat === "hubspot" && p.featured && !p.hidden);
    const extraIds = ["a-dash", "x-retainer"];
    const extras = extraIds
      .map(id => PRODUCTS.find(p => p.id === id && !p.hidden))
      .filter(Boolean);
    const seen = new Set();
    return [...base, ...extras].filter(p => {
      if (seen.has(p.id)) return false;
      seen.add(p.id);
      return true;
    });
  }, []);
  const toggleWish = (id) => setWish(w => ({...w, [id]: !w[id]}));
  return (
    <section id="shop" className="shop-section">
      <div className="wrap">
        <div className="section-head">
          <div>
            <h2>How can we <em>help you</em> today?</h2>
            <p className="shop-section-lead" style={{margin:"10px auto 0", maxWidth:"60ch", color:"var(--muted)", fontSize:"var(--fs-xl)", lineHeight:1.45}}>
              Choose between the following solutions or <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} style={{color:"var(--brand)", textDecoration:"underline"}}>contact us</a> for a custom quote.
            </p>
            <div className="sub">HAND-PICKED · SENIOR-LED · FIXED SCOPE</div>
          </div>
        </div>
        <div className="products">
          {featured.map(p => <Product key={p.id} p={p} onAdd={onAdd} wish={wish[p.id]} onWish={toggleWish}/>)}
        </div>
        <div className="shop-cta-row">
          <p>Looking for a small fix, a block of senior hours, or a monthly retainer? We also ship CRM migrations, attribution dashboards, and full marketing-site refreshes. Browse the full catalog and filter by category.</p>
          <a href="/shop" className="btn btn-secondary" onClick={(e) => { e.preventDefault(); goToShop(); }}>
            Browse all services <Icon name="arrow" size={12}/>
          </a>
        </div>
      </div>
    </section>
  );
};

/* Full catalog page with category filter + sort */
const ShopPage = ({ onAdd, initialCat = "all", initialSort = "featured", initialQ = "" }) => {
  const [active, setActive] = useState(initialCat);
  const [sort, setSort]     = useState(initialSort);
  const [q, setQ]           = useState(initialQ);
  const [wish, setWish]     = useState({});
  const toggleWish = (id) => setWish(w => ({...w, [id]: !w[id]}));

  useEffect(() => { setActive(initialCat); }, [initialCat]);
  useEffect(() => { setSort(initialSort); }, [initialSort]);
  useEffect(() => { setQ(initialQ); }, [initialQ]);

  const cats = useMemo(() => ([
    { id: "all",       name: "All",            count: PRODUCTS.filter(p => !p.hidden).length },
    ...["hubspot","development","addons","custom"].map(id => {
      const meta = CATEGORY_META[id];
      return { id, name: meta?.name || id, count: PRODUCTS.filter(p => p.cat === id && !p.hidden).length };
    }),
  ]), []);

  const list = useMemo(() => {
    let l = active === "all" ? PRODUCTS.filter(p => !p.hidden) : PRODUCTS.filter(p => p.cat === active && !p.hidden);
    const s = (q || "").trim().toLowerCase();
    if (s) {
      const tokens = s.split(/\s+/).filter(Boolean);
      l = l.filter(p => {
        const hay = `${p.name || ""} ${p.desc || ""} ${p.category || ""} ${p.cat || ""} ${Array.isArray(p.scope) ? p.scope.join(" ") : ""}`.toLowerCase();
        return tokens.every(t => hay.includes(t));
      });
    }
    if (sort === "price-asc")  l.sort((a,b) => a.price - b.price);
    if (sort === "price-desc") l.sort((a,b) => b.price - a.price);
    if (sort === "duration")   l.sort((a,b) => (parseInt(a.duration) || 999) - (parseInt(b.duration) || 999));
    if (sort === "featured")   l.sort((a,b) => (b.featured ? 1 : 0) - (a.featured ? 1 : 0));
    return l;
  }, [active, sort, q]);

  return (
    <>
      <section className="shop-page-hero">
        <div className="wrap">
          <nav className="cat-crumbs">
            <a href="#" onClick={(e)=>{e.preventDefault();goHome();}}>Home</a>
            <span className="sep">/</span>
            <span className="here">All services</span>
          </nav>
          <span className="shop-page-eye">FULL CATALOG · {PRODUCTS.filter(p => !p.hidden).length} PROVEN PLAYS</span>
          <h1>{q ? <>Search results for <em>"{q}"</em></> : "Every HubSpot service we ship."}</h1>
          <p className="shop-page-sub">
            {q
              ? <>Found <b>{list.length}</b> {list.length === 1 ? "service" : "services"} matching your search. Sharpen the filter, or <a href="/shop" onClick={(e) => { e.preventDefault(); setQ(""); window.history.replaceState(null, "", "/shop"); }}>clear and browse all {PRODUCTS.length} →</a></>
              : "Fixed scope. Senior-led. SOW in 24 hours, no sales calls. Filter by category or sort by what matters most to you."}
          </p>
        </div>
      </section>

      <section id="shop" className="shop-section shop-page-section">
        <div className="wrap">
        <div className="shop-bar">
            <div className="count">
              Showing <b>{list.length}</b> of <b>{PRODUCTS.filter(p => !p.hidden).length}</b> services
              {q && (
                <span className="shop-q-pill">
                  <Icon name="search" size={11}/> "{q}"
                  <button type="button" className="shop-q-clear" aria-label="Clear search" onClick={() => { setQ(""); window.history.replaceState(null, "", active === "all" ? "/shop" : `/shop?cat=${active}`); }}>
                    <Icon name="close" size={11}/>
                  </button>
                </span>
              )}
            </div>
          <div className="chips">
              {cats.map(c => (
              <button key={c.id} className={`chip ${active === c.id ? "on" : ""}`} onClick={() => setActive(c.id)}>
                {c.name}<span className="n">{c.count}</span>
              </button>
            ))}
          </div>
            <label className="sort-wrap">
              <span className="sort-lab">Sort</span>
              <select className="sort-select" value={sort} onChange={(e) => setSort(e.target.value)}>
                <option value="featured">Featured</option>
                <option value="price-asc">Price · low → high</option>
                <option value="price-desc">Price · high → low</option>
                <option value="duration">Time to live</option>
              </select>
            </label>
        </div>

          {list.length === 0 ? (
            <div className="shop-empty">
              {q ? (
                <>
                  <p>No services match <b>"{q}"</b>{active !== "all" ? <> in <b>{cats.find(c => c.id === active)?.name}</b></> : null}.</p>
                  <div style={{display:"flex",gap:10,flexWrap:"wrap",justifyContent:"center"}}>
                    <button className="btn btn-secondary" onClick={() => { setQ(""); window.history.replaceState(null, "", active === "all" ? "/shop" : `/shop?cat=${active}`); }}>Clear search</button>
                    {active !== "all" && (
                      <button className="btn btn-ghost" onClick={() => { setActive("all"); }}>Search all categories</button>
                    )}
                    <a href="/contact" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToContact(); }}>Talk about custom work <Icon name="arrow" size={12}/></a>
                  </div>
                </>
              ) : (
                <>
                  <p>No services in this category yet.</p>
                  <button className="btn btn-secondary" onClick={() => setActive("all")}>Show all services</button>
                </>
              )}
            </div>
          ) : (
        <div className="products">
          {list.map(p => <Product key={p.id} p={p} onAdd={onAdd} wish={wish[p.id]} onWish={toggleWish}/>)}
            </div>
          )}

          <div className="shop-page-foot">
            <div className="shop-page-foot-row">
              <div>
                <h3>Don't see exactly what you need?</h3>
                <p>Tell us what you're shipping and we'll scope it. Most custom SOWs go out within 48 hours.</p>
              </div>
              <a href="/contact" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToContact(); }}>
                Talk about custom work <Icon name="arrow" size={12}/>
              </a>
            </div>
        </div>
      </div>
    </section>
    </>
  );
};

/* ============ Product detail page ============ */
const tierPriceFor = (p, t) => (t.price != null ? t.price : Math.round(p.price * (t.mult ?? 1)));
const pickInitialTier = (tiers) => tiers.find(t => t.badge) || tiers[Math.min(1, tiers.length - 1)] || tiers[0];

const ProductPage = ({ id, onAdd }) => {
  const product = useMemo(() => PRODUCTS.find(p => p.id === id), [id]);
  const tiers   = useMemo(() => (product?.simple ? [] : (product?.tiers || [])), [product]);
  const simple  = !!product?.simple;
  const [tier, setTier]     = useState(() => (tiers.length ? pickInitialTier(tiers) : null));
  const [extras, setExtras] = useState({});
  const [qty, setQty]       = useState(1);
  const [tab, setTab]       = useState("overview");

  useEffect(() => {
    setTier(tiers.length ? pickInitialTier(tiers) : null);
    setExtras({});
    setQty(1);
  }, [id]);

  if (!product) {
    return (
      <section className="pdp pdp-empty">
        <div className="wrap">
          <h1>Service not found</h1>
          <p>That SKU isn't in the shop. <a href="/shop" onClick={(e)=>{e.preventDefault();goToShop();}}>Browse the catalog →</a></p>
        </div>
      </section>
    );
  }

  const p          = product;
  const activeTier = tier;
  const deliv      = p.pillars || DELIVERABLES[p.cat] || DELIVERABLES.hubspot;
  const productAddons = p.addonsOverride || ADDONS;
  const outcome    = (() => {
    const reviewId = OUTCOMES[p.id];
    const r = reviewId && REVIEWS.find(rev => rev.id === reviewId);
    if (!r) return null;
    return {
      metric:  r.metric || r.badge || "Verified client",
      quote:   (r.text || "").replace(/<\/?[a-z][^>]*>/gi, ""),
      who:     `${r.name} · ${r.role}, ${r.company}`,
      company: r.company,
    };
  })();
  const pairs      = PRODUCTS.filter(x => x.cat === p.cat && x.id !== p.id && !x.hidden).slice(0, 2);
  const isMonthly  = p.duration === "monthly";
  const priceUnit  = isMonthly ? "/mo" : "";
  const tierPrice  = simple || !tier ? p.price : tierPriceFor(p, tier);
  const extraTotal = Object.keys(extras).filter(k => extras[k]).reduce((s, k) => s + ((p.addonsOverride || ADDONS).find(a => a.id === k)?.price || 0), 0);
  const total      = (tierPrice + extraTotal) * qty;
  const cheapest   = useMemo(() => (tiers.length ? Math.min(...tiers.map(t => tierPriceFor(p, t))) : p.price), [p, tiers]);
  const showFromStrike = !simple && tier && tierPrice > cheapest;

  const tog = (k) => setExtras(e => ({...e, [k]: !e[k]}));

  const addCurrent = () => {
    const tierLabel = simple || !tier ? "" : ` · ${tier.name}`;
    const item = {
      ...p,
      _uid: `${p.id}-${(tier?.id || "base")}-${Date.now()}`,
      name: `${p.name}${tierLabel}`,
      price: tierPrice * qty,
      tier: tier?.id,
    };
    onAdd(item);
    Object.keys(extras).filter(k => extras[k]).forEach(k => {
      const a = ADDONS.find(x => x.id === k);
      if (!a) return;
      onAdd({
        id: `addon-${a.id}`,
        _uid: `${a.id}-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,
        num: "+",
        name: `Add-on · ${a.name}`,
        category: "Add-on",
        duration: a.sub,
        price: a.price,
      });
    });
  };

  return (
    <section className="pdp">
      <div className="wrap">
        <nav className="pdp-crumbs">
          <a href="/shop" onClick={(e)=>{e.preventDefault();goToShop();}}>Shop</a>
          <span>/</span>
          <a href={`/category/${p.cat}`} onClick={(e)=>{e.preventDefault();goToCategory(p.cat);}}>{p.category}</a>
          <span>/</span>
          <b>{p.name}</b>
        </nav>

        <div className="pdp-grid">
          {/* ============ LEFT — gallery / proof ============ */}
          <div className="pdp-gallery">
            {/* Main visual */}
            <div className="pdp-hero-card">
              {p.badge && (
                <div className="p-badges pdp-hero-badges">
                  <span className={`p-badge ${p.badge}`}>{p.badge === "new" ? "NEW" : "POPULAR"}</span>
                </div>
              )}
              <div className="pdp-hero-meta">
                <span className="pdp-hero-num">{p.num}</span>
                <span className="pdp-hero-cat">{p.category}</span>
              </div>
              {p.image ? (
                <img className="pdp-hero-img" src={p.image} alt={p.name} loading="eager"/>
              ) : (
                <div className="pdp-hero-glyph">
                  <span className="num">{p.num}</span>
                  <span className="cat">{p.category}</span>
                </div>
              )}
              <div className="pdp-hero-foot">
                <span><Icon name="check" size={12}/> Senior-led</span>
                <span><Icon name="shield" size={12}/> Fixed price</span>
                <span><Icon name="zap" size={12}/> Live in {activeTier?.duration || p.duration}</span>
              </div>
            </div>

            {/* secondary image hidden for now
            {p.imageWide && (
              <div className="pdp-secondary-img">
                <img src={p.imageWide} alt={`${p.name} — detailed overview`} loading="lazy"/>
              </div>
            )}
            */}

            {/* What you get */}
            <div className="pdp-block">
              <div className="pdp-block-head">
                <span className="pdp-block-eye">CORE PILLARS</span>
                <h3>{p.pillars ? "What's included" : "What you get"}</h3>
              </div>
              <div className="pdp-deliv">
                {deliv.map(d => (
                  <div className="pdp-deliv-i" key={d.t}>
                    <div className="ic"><Icon name={d.i} size={18}/></div>
                    <div className="meta">
                      <div className="t">{d.t}</div>
                      <p>{d.d}</p>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Detailed scope — per-service bullets, per-tier when available */}
            {(() => {
              const activeScope = activeTier?.scope || activeTier?.bullets || p.scope;
              const scopeTitle = p.scopeLabel
                ? (activeTier ? p.scopeLabel.replace(/Pro/, activeTier.name) : p.scopeLabel)
                : (activeTier ? `What's in the box · ${activeTier.name}` : "What's in the box");
              if (!activeScope?.length) return null;
              return (
                <div className="pdp-block">
                  <div className="pdp-block-head">
                    <span className="pdp-block-eye">DETAILED SCOPE</span>
                    <h3>{scopeTitle}</h3>
                  </div>
                  <ul className="pdp-scope">
                    {activeScope.map((s, i) => (
                      <li key={i}>
                        <span className="pdp-scope-ic" aria-hidden="true">
                          <Icon name="check" size={12}/>
                        </span>
                        <span>{s}</span>
                      </li>
                    ))}
                  </ul>
                  <div className="pdp-scope-foot">
                    {p.scopeNote || <>Quantities above are upper limits — final scope is confirmed in your SOW. Need something not listed? <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Talk about custom scope →</a></>}
                  </div>
                  {activeTier?.excluded && (
                    <div className="pdp-tier-excluded">
                      <div className="pdp-tier-excluded-label">Does not include:</div>
                      <ul className="pdp-scope pdp-scope-excluded">
                        {activeTier.excluded.map((s, i) => (
                          <li key={i}>
                            <span className="pdp-scope-ic pdp-scope-ic-x" aria-hidden="true">✕</span>
                            <span>{s}</span>
                          </li>
                        ))}
                      </ul>
                    </div>
                  )}
                </div>
              );
            })()}

            {/* Not included by default — tier-aware intro when available */}
            {(() => {
              const ni = activeTier?.notIncluded || p.notIncluded;
              if (!ni) return null;
              const introText = activeTier
                ? ni.intro.replace(/^This package/, `This ${activeTier.name} package`)
                : ni.intro;
              return (
                <div className="pdp-block">
                  <div className="pdp-block-head">
                    <span className="pdp-block-eye">EXCLUSIONS</span>
                    <h3>Not included by default</h3>
                  </div>
                  <p className="pdp-scope-foot" style={{marginBottom:12}}>{introText}</p>
                  <ul className="pdp-scope pdp-scope-excluded">
                    {ni.items.map((s, i) => (
                      <li key={i}>
                        <span className="pdp-scope-ic pdp-scope-ic-x" aria-hidden="true">✕</span>
                        <span>{s}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              );
            })()}

            {/* Is this the right fit? — tier-aware override when present */}
            {(() => {
              const fit = activeTier?.bestFit || p.bestFit;
              if (!fit) return null;
              return (
                <div className="pdp-block">
                  <div className="pdp-block-head">
                    <span className="pdp-block-eye">FIT CHECK</span>
                    <h3>Is this the right fit?</h3>
                  </div>
                  <div className="pdp-fit-grid">
                    <div className="pdp-fit-col pdp-fit-good">
                      <div className="pdp-fit-label"><Icon name="check" size={14}/> Best fit</div>
                      <ul>
                        {fit.good.map((s, i) => <li key={i}>{s}</li>)}
                      </ul>
                    </div>
                    <div className="pdp-fit-col pdp-fit-bad">
                      <div className="pdp-fit-label"><Icon name="close" size={14}/> Not the best fit</div>
                      <ul>
                        {fit.bad.map((s, i) => <li key={i}>{s}</li>)}
                      </ul>
                    </div>
                  </div>
                  <p className="pdp-fit-note">Not the right fit? <a href="/shop" onClick={(e) => { e.preventDefault(); goToShop(); }}>Browse all services</a> or <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>request custom scope</a>.</p>
                </div>
              );
            })()}

            {/* Outcome card (lifestyle equivalent) */}
            {outcome && (
              <div className="pdp-outcome">
                <span className="pdp-outcome-eye">IN THEIR WORDS · {outcome.company.toUpperCase()}</span>
                <div className="pdp-outcome-row">
                  <div className="pdp-outcome-metric">{outcome.metric}</div>
                  <div className="pdp-outcome-body">
                    <p>"{outcome.quote}"</p>
                    <small>— {outcome.who}</small>
                  </div>
                </div>
              </div>
            )}

            {/* Service highlights */}
            <div className="pdp-highlights">
              <div className="pdp-block-head">
                <span className="pdp-block-eye">SERVICE SPECS</span>
                <h3>Highlights</h3>
              </div>
              {(() => {
                const sp = activeTier?.specs;
                if (sp) return (
                  <div className="pdp-hi-grid">
                    <div className="pdp-hi"><div className="ic"><Icon name="rocket" size={16}/></div><div><b>{sp.timeline}</b><span>Time to live</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="layers" size={16}/></div><div><b>{sp.deliverables}</b><span>Fixed scope</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="user" size={16}/></div><div><b>{sp.team}</b><span>Operator</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="chat" size={16}/></div><div><b>{sp.support}</b><span>During build</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="mail" size={16}/></div><div><b>SOW</b><span>{sp.sow}</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="refresh" size={16}/></div><div><b>{sp.updates}</b><span>Status</span></div></div>
                    {sp.extra && <div className="pdp-hi"><div className="ic"><Icon name="zap" size={16}/></div><div><b>{sp.extra}</b><span>Included</span></div></div>}
                  </div>
                );
                return (
                  <div className="pdp-hi-grid">
                    <div className="pdp-hi"><div className="ic"><Icon name="rocket" size={16}/></div><div><b>{p.duration}</b><span>Time to live</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="layers" size={16}/></div><div><b>{deliv.length} deliverables</b><span>Fixed scope</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="user" size={16}/></div><div><b>1 senior</b><span>Operator owner</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="chat" size={16}/></div><div><b>Slack</b><span>Async support</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="mail" size={16}/></div><div><b>SOW</b><span>in 24 hours</span></div></div>
                    <div className="pdp-hi"><div className="ic"><Icon name="refresh" size={16}/></div><div><b>Weekly</b><span>Progress updates</span></div></div>
                  </div>
                );
              })()}
            </div>

            {/* Tabs */}
            <div className="pdp-tabs">
              <div className="pdp-tabs-bar">
                {[["overview","Overview"],["process","Process"],["faq","FAQ"]].map(([k,l]) => (
                  <button key={k} className={`pdp-tab ${tab===k?"on":""}`} onClick={()=>setTab(k)}>{l}</button>
                ))}
              </div>
              <div className="pdp-tabs-body">
                {tab === "overview" && (
                  <div>
                    {activeTier && activeTier.desc && (
                      <p style={{borderLeft:"3px solid var(--brand)",paddingLeft:12,marginBottom:14}}>
                        <b>{activeTier.name} scope:</b> {activeTier.desc}
                      </p>
                    )}
                    {(() => {
                      const ov = activeTier?.overview || p.overview;
                      if (ov) return ov.split("\n\n").map((para, i) => <p key={i}>{para}</p>);
                      return (
                        <>
                          <p>{p.desc}</p>
                          {simple ? (
                            <p>You get a fixed-scope add-on, not a hand-rolled SOW. We start the moment the SOW is signed and hand off in <b>{activeTier?.duration || p.duration}</b> with QA, a Loom walkthrough, and a 7-day Slack window for questions.</p>
                          ) : isMonthly ? (
                            <p>You get a senior operator embedded with your team on the <b>{tier.name}</b> plan — month-to-month, cancel any time. Slack-first, weekly working session, and a sprint board you prioritize.</p>
                          ) : (
                            <p>You get a fixed-scope engagement, not a hand-rolled SOW. <b>{tier.name}</b> {tiers === TIERS ? "tier" : "package"} ships {tier.bullets[1]?.toLowerCase().replace(/^\+ /, "") || "the published scope"} on a {activeTier?.duration || p.duration} timeline. We've shipped this play to dozens of teams — same formula, calibrated to your stack.</p>
                          )}
                        </>
                      );
                    })()}
                  </div>
                )}
                {tab === "process" && (
                  <ol className="pdp-steps">
                    {p.processSteps ? p.processSteps.map((s, i) => (
                      <li key={i}><b>Step {i+1} — {s.title}.</b> {s.body}</li>
                    )) : (
                      <>
                        <li><b>Day 0 — checkout.</b> Reserve a spot. Zero charge.</li>
                        <li><b>Day 1 — SOW.</b> A scoped Statement of Work in your inbox within 24 hours.</li>
                        <li><b>Day 7 — kickoff.</b> Senior operator assigned, Slack channel opened.</li>
                        <li><b>Week 2 → handoff.</b> Weekly progress, no surprises. Ship on the date we promised.</li>
                      </>
                    )}
                  </ol>
                )}
                {tab === "faq" && (
                  <div className="pdp-faq">
                    {(p.productFaq || FAQ.slice(0,3)).map((f,i) => (
                      <details key={i} open={i===0}>
                        <summary>{f.q}</summary>
                        <p>{f.a}</p>
                      </details>
                    ))}
                  </div>
                )}
              </div>
            </div>
          </div>

          {/* ============ RIGHT — buy column ============ */}
          <aside className="pdp-side">
            <span className="pdp-eye">{p.category} · SKU {p.num}</span>
            <h1 className="pdp-title">{p.name}</h1>
            <p className="pdp-tagline">{p.tagline || p.desc}</p>
            {p.supporting && <p className="pdp-supporting">{p.supporting}</p>}

            <div className="pdp-price-row">
              <div className="pdp-price">
                ${tierPrice.toLocaleString()}{priceUnit}
                <span className="u">{p.priceLabel || (isMonthly ? "USD · monthly · cancel anytime" : "USD · fixed · one-time")}</span>
              </div>
              {showFromStrike && (
                <span className="pdp-price-from">from <s>${cheapest.toLocaleString()}{priceUnit}</s></span>
              )}
            </div>

            {/* Tier selector — the "Color: Timber" equivalent */}
            {!simple && tier && (
              <div className="pdp-tier">
                <div className="pdp-l">{isMonthly ? "Plan" : "Engagement tier"}: <b>{tier.name}</b> <span className="muted">— {tier.tag}</span></div>
                <div className="pdp-tier-row">
                  {tiers.map(t => {
                    const tp = tierPriceFor(p, t);
                    const label = tp >= 1000 ? `$${(tp/1000).toFixed(tp >= 10000 ? 0 : 1)}k${priceUnit}` : `$${tp}${priceUnit}`;
                    return (
                      <button key={t.id}
                              className={`pdp-tier-btn ${tier.id === t.id ? "on" : ""}`}
                              onClick={() => setTier(t)}>
                        {t.badge && <span className="pdp-tier-badge">★</span>}
                        <span className="t">{t.name}</span>
                        <span className="p">{label}</span>
                      </button>
                    );
                  })}
                </div>
                <ul className="pdp-tier-bullets">
                  {tier.bullets.map((b, i) => (
                    <li key={i}><Icon name="check" size={12}/> {b}</li>
                  ))}
                </ul>
                {tier.desc && <p className="pdp-tier-desc">{tier.desc}</p>}
              </div>
            )}

            {!tier && (
              <div className="pdp-tier pdp-tier-simple">
                <div className="pdp-l">{simple ? "Fixed-scope add-on" : "Fixed-scope engagement"} <span className="muted">— ships in {p.duration}</span></div>
                <ul className="pdp-tier-bullets">
                  <li><Icon name="check" size={12}/> Senior operator on day one</li>
                  <li><Icon name="check" size={12}/> 1-page SOW, fixed price</li>
                  <li><Icon name="check" size={12}/> 7-day Slack window after handoff</li>
                </ul>
              </div>
            )}

            {/* Popular upgrades — the screenshot pattern */}
            <div className="pdp-addons">
              <div className="pdp-addons-head">
                <Icon name="zap" size={14}/>
                <span>Popular upgrades</span>
              </div>
              {productAddons.map(a => (
                <label key={a.id} className={`pdp-addon ${extras[a.id] ? "on" : ""}`}>
                  <input type="checkbox" checked={!!extras[a.id]} onChange={() => tog(a.id)}/>
                  <span className="pdp-addon-chk"><Icon name="check" size={12}/></span>
                  <div className="pdp-addon-meta">
                    <div className="n">{a.name}</div>
                    <div className="d">{a.sub}</div>
                  </div>
                  <div className="pdp-addon-p">+${a.price.toLocaleString()}</div>
                </label>
              ))}
            </div>

            {isMonthly && (
              <div className="pdp-stock pdp-stock-retainer">
                <div className="pdp-stock-l">Month-to-month · cancel any time with 30 days' notice</div>
              </div>
            )}

            {/* Qty + Add */}
            <div className="pdp-cta-row">
              <div className="pdp-qty">
                <button onClick={() => setQty(q => Math.max(1, q-1))} aria-label="Decrease">−</button>
                <span>{qty}</span>
                <button onClick={() => setQty(q => q+1)} aria-label="Increase">+</button>
              </div>
              <button className="btn btn-primary pdp-add" onClick={addCurrent}>
                Add to cart · ${total.toLocaleString()}{priceUnit}
              </button>
            </div>
            <button className="btn pdp-buy" onClick={addCurrent}>
              {p.ctaPrimary || (isMonthly ? "Start retainer →" : simple ? "Add to cart →" : "Reserve cohort spot →")}
            </button>
            {p.ctaSecondary ? (
              <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="pdp-payopts">{p.ctaSecondary} →</a>
            ) : (
              <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="pdp-payopts">Or contact us about custom scope →</a>
            )}
            {p.ctaNote && <p className="pdp-cta-note">{p.ctaNote}</p>}
            {p.riskNote && <p className="pdp-risk-note">{p.riskNote}</p>}

            {/* Status box */}
            <div className="pdp-pickup">
              <div className="pdp-pickup-ic"><Icon name="check" size={14}/></div>
              <div className="pdp-pickup-meta">
                <b>Senior operator assigned within 24 hours</b>
                <span>SOW signed within 48h · zero charge until you sign</span>
              </div>
              <a href="/process" onClick={(e)=>{e.preventDefault(); goToProcess();}} className="pdp-pickup-link">How it works →</a>
            </div>

            <div className="pdp-share">
              <span>Share:</span>
              <button aria-label="Email"><Icon name="mail" size={14}/></button>
              <button aria-label="Twitter">𝕏</button>
              <button aria-label="LinkedIn">in</button>
              <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="pdp-help"><Icon name="chat" size={14}/> Need help?</a>
            </div>

            {/* Pairs well with */}
            {pairs.length > 0 && (
              <div className="pdp-pairs">
                <div className="pdp-pairs-head">Pairs well with</div>
                {pairs.map(x => (
                  <div className="pdp-pair" key={x.id} onClick={() => goToProduct(x.id)} role="link" tabIndex={0}>
                    <div className="vis"><span>{x.num}</span></div>
                    <div className="meta">
                      <div className="n">{x.name}</div>
                      <div className="p">${x.price.toLocaleString()}</div>
                    </div>
                    <button className="add" onClick={(e) => { e.stopPropagation(); onAdd(x); }}>
                      <Icon name="plus" size={12}/> Add
                    </button>
                  </div>
                ))}
              </div>
            )}

            {/* Trust badges */}
            <div className="pdp-trust">
              <div className="i"><Icon name="check"  size={14}/> Fixed price · no surprises</div>
              <div className="i"><Icon name="shield" size={14}/> SOW within 24 hours, free</div>
              <div className="i"><Icon name="zap"    size={14}/> 8+ year senior operator</div>
              <div className="i"><Icon name="refresh"size={14}/> No payment until you sign the SOW</div>
            </div>
          </aside>
        </div>
      </div>
    </section>
  );
};

/* ============ Category page ============ */
const CategoryPage = ({ id, onAdd }) => {
  const meta     = CATEGORY_META[id];
  const [sort, setSort]     = useState("featured");
  const [wish, setWish]     = useState({});
  const toggleWish = (pid) => setWish(w => ({...w, [pid]: !w[pid]}));

  if (!meta) {
    return (
      <section className="pdp pdp-empty">
        <div className="wrap">
          <h1>Category not found</h1>
          <p>That category doesn't exist. <a href="/shop" onClick={(e)=>{e.preventDefault();goToShop();}}>Browse all services →</a></p>
        </div>
      </section>
    );
  }

  const products = useMemo(() => {
    const list = PRODUCTS.filter(p => p.cat === id && !p.hidden);
    if (sort === "price-asc")  return [...list].sort((a, b) => a.price - b.price);
    if (sort === "price-desc") return [...list].sort((a, b) => b.price - a.price);
    if (sort === "fastest")    return [...list].sort((a, b) => parseInt(a.duration) - parseInt(b.duration));
    return [...list].sort((a, b) => (b.badge === "pop" ? 1 : 0) - (a.badge === "pop" ? 1 : 0));
  }, [id, sort]);

  const reviews   = REVIEWS.filter(r => r.slot !== "micro").slice(0, 2);
  const faqItems  = (meta.faqIds || []).map(i => FAQ[i]).filter(Boolean);
  const otherCats = Object.values(CATEGORY_META).filter(c => c.id !== id);

  return (
    <>
      {/* ===== Hero ===== */}
      <section className="cat-hero" style={{"--cat-color": meta.color}}>
        <div className="wrap">
          <nav className="pdp-crumbs cat-crumbs">
            <a href="/shop" onClick={(e)=>{e.preventDefault();goToShop();}}>Shop</a>
            <span>/</span>
            <b>{meta.name}</b>
          </nav>

          <div className="cat-hero-grid">
            <div className="cat-hero-main">
              <span className="cat-eye">{meta.eyebrow}</span>
              <h1 className="cat-h1">{meta.hero}</h1>
              <p className="cat-sub">{meta.sub}</p>
              <div className="cat-hero-meta">
                <span className="m"><Icon name="layers" size={13}/> <b>{products.length}</b> proven {products.length === 1 ? "play" : "plays"}</span>
                <span className="m"><Icon name="zap"    size={13}/> Live in 2&ndash;6 weeks</span>
                <span className="m"><Icon name="shield" size={13}/> Fixed price · senior-led</span>
                <span className="m"><Icon name="check"  size={13}/> SOW in 24h, free</span>
              </div>
            </div>
            <div className={`cat-hero-card${meta.image ? " cat-hero-card-img" : ""}`}>
              {meta.image ? (
                <img src={meta.image} alt={`${meta.name} services overview`} className="cat-hero-img" loading="eager" />
              ) : (
                <div className="cat-card-glyph"><Icon name={meta.icon} size={56}/></div>
              )}
              <div className="cat-card-foot">
                <span>CATEGORY</span>
                <b>{meta.name}</b>
              </div>
            </div>
          </div>

          <div className="cat-fit">
            <span className="cat-fit-eye">FIT</span>
            <p>{meta.fitFor}</p>
          </div>
        </div>
      </section>

      {/* ===== Benefits strip ===== */}
      <section className="cat-benefits">
        <div className="wrap">
          <div className="cat-ben-grid">
            {meta.benefits.map((b, i) => (
              <div className="cat-ben" key={b.t}>
                <div className="cat-ben-num">0{i+1}</div>
                <div className="cat-ben-ic"><Icon name={b.i} size={20}/></div>
                <h3>{b.t}</h3>
                <p>{b.d}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* ===== Product grid ===== */}
      <section className="cat-grid-section">
        <div className="wrap">
          <div className="cat-grid-bar">
            <div className="count">
              Showing <b>all {products.length}</b> {products.length === 1 ? "service" : "services"} in <b>{meta.name}</b>
            </div>
            <div className="cat-jumps">
              {Object.values(CATEGORY_META).map(c => (
                <button key={c.id}
                        className={`chip ${c.id === id ? "on" : ""}`}
                        onClick={() => goToCategory(c.id)}>
                  {c.name}
                </button>
              ))}
              <button className="chip" onClick={() => goToShop()}>
                All ({PRODUCTS.length})
              </button>
            </div>
            <select className="cat-sort" value={sort} onChange={(e) => setSort(e.target.value)} aria-label="Sort">
              <option value="featured">Sort: Featured</option>
              <option value="price-asc">Price · low → high</option>
              <option value="price-desc">Price · high → low</option>
              <option value="fastest">Fastest delivery</option>
            </select>
          </div>

          <div className="products cat-products">
            {products.map(p => (
              <Product key={p.id} p={p} onAdd={onAdd} wish={wish[p.id]} onWish={toggleWish}/>
            ))}
          </div>
        </div>
      </section>

      {/* ===== Reviews mini ===== */}
      {reviews.length > 0 && (
        <section className="cat-reviews">
          <div className="wrap">
            <span className="cat-section-eye">SOCIAL PROOF · TEAMS WHO SHIPPED THIS</span>
            <h2>What changed after launch.</h2>
            <div className="cat-reviews-grid">
              {reviews.map(r => (
                <article className="cat-review" key={r.id}>
                  <Stars/>
                  <p dangerouslySetInnerHTML={{__html:`"${r.text}"`}}/>
                  <div className="cr-author">
                    <img src={r.avatar} alt={r.name} loading="lazy"/>
                    <div>
                      <b>{r.name}</b>
                      <span>{r.role} · <em>{r.company}</em></span>
                    </div>
                    {r.logo && <img className="cr-logo" src={r.logo} alt={r.company} loading="lazy"/>}
                  </div>
                </article>
              ))}
            </div>
          </div>
        </section>
      )}

      {/* ===== FAQ specific ===== */}
      {faqItems.length > 0 && (
        <section className="cat-faq">
          <div className="wrap">
            <div className="cat-faq-grid">
              <div>
                <span className="cat-section-eye">COMMON QUESTIONS · {meta.name.toUpperCase()}</span>
                <h2>Before you check out.</h2>
                <p>Need something not in the shop? <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Tell us what you're shipping</a> and we'll scope a custom SOW within 48 hours.</p>
              </div>
              <div className="cat-faq-list">
                {faqItems.map((f, i) => (
                  <details key={i} open={i === 0}>
                    <summary>
                      <span>{f.q}</span>
                      <span className="plus"><Icon name="plus" size={14}/></span>
                    </summary>
                    <p>{f.a}</p>
                  </details>
                ))}
              </div>
            </div>
          </div>
        </section>
      )}

      {/* ===== Cross-category ===== */}
      <section className="cat-related">
        <div className="wrap">
          <div className="cat-related-head">
            <h3>Browse other categories</h3>
            <a href="/shop" onClick={(e)=>{e.preventDefault();goToShop();}} className="link">All services <Icon name="arrow" size={12}/></a>
          </div>
          <div className="cat-related-grid">
            {otherCats.map(c => (
              <button key={c.id} className="cat-related-tile" onClick={() => goToCategory(c.id)}>
                <div className="ic"><Icon name={c.icon} size={20}/></div>
                <div>
                  <div className="n">{c.name}</div>
                  <div className="c">{PRODUCTS.filter(p => p.cat === c.id && !p.hidden).length} services</div>
                </div>
                <Icon name="arrow" size={14}/>
              </button>
            ))}
          </div>
        </div>
      </section>

      {/* Reuse the existing CTA band */}
      <Cta />
    </>
  );
};

/* ============ Features strip ============ */
const Features = () => {
  const f = [
    {
      i: "user",
      n: "01 / PROVEN EXPERIENCE",
      t: "Trusted by",
      e: "100+ companies.",
      d: "We've shipped HubSpot systems across SaaS, agencies, services, e-commerce, finance, and nonprofits — so you're not paying for someone's first attempt.",
      k: "Proven across industries",
    },
    {
      i: "shield",
      n: "02 / FIXED SCOPE",
      t: "Buy the playbook,",
      e: "not the hours.",
      d: "Each service comes with clear deliverables, fixed pricing, and a defined scope — so you know what you're getting before work starts.",
      k: "No open-ended retainers",
    },
    {
      i: "zap",
      n: "03 / SENIOR OPERATORS",
      t: "Senior, all the",
      e: "way down.",
      d: "Your engagement is owned end-to-end by an experienced HubSpot and revenue-ops operator. No junior teams, no handoffs.",
      k: "Built by senior operators",
    },
  ];
  return (
    <section className="features">
      <div className="wrap">
        <div className="feat-grid">
          {f.map(x => (
            <div className="feat" key={x.n}>
              <div className="ic"><Icon name={x.i} size={26}/></div>
              <div className="n">{x.n}</div>
              <h3>{x.t}<br/><em>{x.e}</em></h3>
              <p>{x.d}</p>
              <div className="feat-divider" aria-hidden="true"/>
              <div className="feat-foot">
                <span className="feat-foot-ic" aria-hidden="true"><Icon name="check" size={12}/></span>
                <span>{x.k}</span>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

/* ============ How it works (buying steps) ============ */
const HowItWorks = () => {
  const pills = [
    "SOW in 24 hours",
    "Fixed price · no surprises",
    "Built by senior operators",
  ];
  const steps = [
    { i: "search", n: "01", t: "Browse services", d: "Pick a package or pre-built bundle based on the HubSpot work you need." },
    { i: "bag",    n: "02", t: "Build your cart", d: "Stack services, compare pricing, and apply bundle discounts automatically." },
    { i: "mail",   n: "03", t: "Approve the SOW", d: "We send a clear Statement of Work with deliverables, timeline, and fixed pricing within 24 hours." },
    { i: "rocket", n: "04", t: "Kickoff & ship",  d: "Once signed, your senior operator starts the work and sends weekly progress updates." },
  ];
  return (
    <section className="how-section" id="how">
      <div className="wrap">
        <div className="how-pills">
          {pills.map(p => (
            <span className="how-pill" key={p}>
              <Icon name="check" size={12}/>
              {p}
            </span>
          ))}
        </div>

        <div className="how-head">
          <h2>A <em>simple process</em> to get started</h2>
          <p>Choose a fixed-price HubSpot service, approve the SOW, and start with a senior operator. <span className="how-head-accent">No payment required</span> until the scope is signed.</p>
        </div>

        <div className="how-grid">
          {steps.map((s, idx) => (
            <div className="how-step" key={s.t}>
              <div className="hs-num">{s.n}</div>
              <div className="hs-ic"><Icon name={s.i} size={22}/></div>
              <h3>{s.t}</h3>
              <div className="hs-divider" aria-hidden="true"/>
              <p>{s.d}</p>
              {idx < steps.length - 1 && <div className="hs-arrow"><Icon name="arrow" size={14}/></div>}
            </div>
          ))}
        </div>

        <div className="how-paths">
          <div className="how-path how-path-shop">
            <div className="hp-ic"><Icon name="bag" size={22}/></div>
            <div className="hp-body">
              <h3>Buying a defined package?</h3>
              <p>Browse services, add them to cart, and receive your SOW in 24 hours.</p>
              <a href="/shop" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToShop(); }}>
                Browse services <Icon name="arrow" size={12}/>
              </a>
            </div>
          </div>
          <div className="how-paths-or" aria-hidden="true"><span>OR</span></div>
          <div className="how-path how-path-custom">
            <div className="hp-ic hp-ic-custom"><Icon name="puzzle" size={22}/></div>
            <div className="hp-body">
              <h3>Need a custom build?</h3>
              <p>Tell us what you're trying to ship. We'll scope a custom fixed-price engagement within 48 hours.</p>
              <a href="/contact" className="btn btn-custom" onClick={(e) => { e.preventDefault(); goToContact(); }}>
                Talk about custom work <Icon name="arrow" size={12}/>
              </a>
            </div>
          </div>
        </div>

        <p className="how-foot">
          <Icon name="shield" size={14}/>
          <span>No payment required until the scope is approved and the SOW is signed.</span>
        </p>
      </div>
    </section>
  );
};

/* ============ Bundles ============ */
const Bundles = ({ onAdd }) => {
  const fmt = (n) => `$${n.toLocaleString("en-US")}`;
  return (
  <section className="bundles-section" id="bundles">
    <div className="wrap">
      <div className="section-head">
        <div>
          <h2>Save <em>with a bundle</em></h2>
            <div className="sub">FOUR JOURNEYS · BUILT FROM REAL CATALOG SERVICES · 15–25% OFF</div>
        </div>
          <a href="/contact" className="link" onClick={(e) => { e.preventDefault(); goToContact(); }}>Need a custom mix? <Icon name="arrow" size={12}/></a>
      </div>
      <div className="bundles">
          {BUNDLES.map((b, i) => {
            const itemsTotal = b.items.reduce((s, it) => s + it.price, 0);
            const regular = b.regular || itemsTotal;
            const savings = Math.max(0, regular - b.price);
            const pct = regular > 0 ? Math.round((savings / regular) * 100) : 0;
            return (
              <div key={b.id} className={`bundle ${b.featured ? "featured" : ""}`}
                   style={{ "--bundle-color": b.color }}>
            {b.featured && <span className="b-tag"><span className="d"/> MOST POPULAR</span>}
                <div className="b-head">
                  <span className="b-glyph" aria-hidden="true">
                    <Icon name={b.icon || "prism"} size={18}/>
                  </span>
                  <div className="b-head-text">
                    <span className="b-eye">{b.eyebrow}</span>
              <h3 className="b-name">{b.name} <em>bundle</em></h3>
                  </div>
                </div>
              <p className="b-sub">{b.sub}</p>

                <div className="b-price-block">
                  <div className="b-price-row">
                    <span className="b-price">{fmt(b.price)}</span>
                    <span className="b-regular" aria-label={`Regularly ${fmt(regular)}`}>{fmt(regular)}</span>
            </div>
                  <div className="b-meta-row">
                    <span className="b-savings">Save {fmt(savings)} · {pct}% off</span>
                    <span className="b-fixed">Fixed · one-time</span>
            </div>
                </div>

                <div className="b-best">
                  <span className="b-best-l">Best for</span>
                  <span className="b-best-t">{b.bestFor}</span>
                </div>

            <ul className="b-list">
              {b.items.map((it, idx) => (
                    <li key={idx}>
                      <Icon name="check" size={14}/>
                      <span className="b-li-name">{it.name}</span>
                      <span className="b-li-price">{fmt(it.price)}</span>
                    </li>
                  ))}
                  {b.bonus && b.bonus.map((bn, idx) => (
                    <li key={`bn-${idx}`} className="b-li-bonus">
                      <Icon name="plus" size={14}/>
                      <span className="b-li-name">{bn}</span>
                      <span className="b-li-price">Included</span>
                    </li>
              ))}
            </ul>

            <button className={`btn ${b.featured ? "btn-primary" : "btn-secondary"}`}
                  onClick={() => onAdd({
                    id:`bundle-${b.id}`, num:"B"+(i+1),
                    name:`${b.name} Bundle`, desc:b.sub,
                    price:b.price, duration:"bundle",
                    category:"Bundle", glyph:b.icon || "prism"
                  })}>
                  Add {b.name.toLowerCase()} bundle <Icon name="arrow" size={12}/>
            </button>
          </div>
            );
          })}
      </div>
    </div>
  </section>
);
};

/* ============ Reviews ============ */
const Reviews = () => {
  const stacked = REVIEWS.filter(r => r.slot === "stack");
  const micro   = REVIEWS.filter(r => r.slot === "micro");
  return (
    <section className="reviews-section">
      <div className="wrap">
        <div className="reviews-head">
          <h2>Why teams <em>choose</em> Vestal Hub.</h2>
          <div className="rate">
            <Stars/>
            <b>5 / 5</b>
            <span className="rv-dot">·</span>
            <span>Trusted by 100+ companies</span>
          </div>
        </div>

        <div className="reviews-grid">
          {stacked.map((x, i) => (
            <article className="review review-small" key={x.id || i}>
              <div className="rv-head">
                <Stars/>
                <span className="rv-pill">{x.metric || x.badge}</span>
              </div>
              <p className="t" dangerouslySetInnerHTML={{__html:`"${x.text}"`}}/>
              <div className="w">
                <img className="av av-img" src={x.avatar} alt={x.name} loading="lazy"/>
                <div className="n">
                  <b>{x.name}</b>
                  <span>{x.role} · <em>{x.company}</em></span>
                </div>
                {x.logo && <img className="rv-co-logo" src={x.logo} alt={x.company} loading="lazy"/>}
              </div>
            </article>
          ))}
        </div>

        <div className="reviews-micro">
          {micro.map((x, i) => (
            <div className="rv-mini" key={x.id || i}>
              <Stars/>
              <p dangerouslySetInnerHTML={{__html:`"${x.text}"`}}/>
              <small><b>{x.name}</b>{x.role ? ` · ${x.role}` : ""} · {x.company}</small>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

/* ============ Logos ============ */
const Logos = () => (
  <section className="logo-bar">
    <div className="wrap">
      <div className="t">Driving revenue for high-tech companies</div>
      <div className="row">
        {LOGOS.map(l => (
          <div className="lg" key={l.name} title={l.name}>
            <img src={l.src} alt={l.name} loading="lazy"/>
          </div>
        ))}
      </div>
    </div>
  </section>
);

/* ============ Stats — second social proof band ============ */
const Stats = () => {
  const stats = [
    { n: "100+",  l: "Companies served" },
    { n: "5/5", l: "Average rating" },
    { n: "$24M+", l: "Pipeline shipped for clients" },
    { n: "28d",   l: "Average time to live" },
    { n: "100%",  l: "Fixed-price engagements" },
  ];
  return (
    <section className="stats-section">
      <div className="wrap">
        <div className="stats-inner">
          <div className="stats-head">
            <h2>Operators ship <em>real numbers</em>.</h2>
            <p>Not vanity metrics. Pipeline, ARR, and shipped systems — measured in dollars and weeks, not slides.</p>
          </div>
          <div className="stats-grid">
            {stats.map(s => (
              <div className="stat" key={s.l}>
                <div className="n">{s.n}</div>
                <div className="l">{s.l}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
};

/* ============ FAQ ============ */
const Faq = () => (
  <section className="faq-section">
    <div className="wrap">
      <div className="faq-grid">
        <div>
          <h2>Common <em>questions</em></h2>
          <p>Shopping for services is different. Here's what most teams want to know <em>before they check out</em>. Need something not in the shop? <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Tell us what you're shipping</a>.</p>
        </div>
        <div className="faq-list">
          {FAQ.map((f, i) => (
            <details className="faq-item" key={i} open={i === 0}>
              <summary>
                <span>{f.q}</span>
                <span className="plus"><Icon name="plus" size={14}/></span>
              </summary>
              <p className="ans">{f.a}</p>
            </details>
          ))}
        </div>
      </div>
    </div>
  </section>
);

/* ============ CTA ============ */
const Cta = () => (
  <section className="cta-band" id="cta">
    <div className="wrap">
      <div className="cta-inner">
        <h2>Ready to compound your <em>revenue?</em></h2>
        <p>Pick a service or send a custom brief. SOW in your inbox within 24 hours — <em>no sales calls, no decks.</em></p>
        <div className="btns">
          <a href="/shop" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToShop(); }}>Shop services <Icon name="arrow" size={14}/></a>
          <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="btn btn-ghost">Talk about custom work</a>
        </div>
      </div>
    </div>
  </section>
);

/* ============ Custom Work page ============ */
const CustomPage = ({ onAdd }) => {
  const hours    = useMemo(() => PRODUCTS.find(p => p.id === "x-hours"),    []);
  const retainer = useMemo(() => PRODUCTS.find(p => p.id === "x-retainer"), []);
  const fmtPrice = (n) => n >= 1000 ? `$${(n/1000).toFixed(n >= 10000 ? 0 : 1)}k` : `$${n}`;

  const useCases = [
    { i: "code",    n: "Custom integrations",        d: "API work between HubSpot and your data warehouse, billing system, product analytics, or a tool that doesn't have a native connector." },
    { i: "chart",   n: "Bespoke reporting",          d: "Custom dashboards, BI exports, blended attribution models, and the report your CFO has been asking for since Q2." },
    { i: "refresh", n: "Multi-portal migrations",    d: "Merging two HubSpot portals after an acquisition, splitting one portal into two BUs, or migrating from another CRM with custom logic." },
    { i: "rocket",  n: "Launch crunch coverage",     d: "An extra senior pair of hands for 2–6 weeks around a launch, fundraise, or board meeting — without hiring full-time." },
    { i: "user",    n: "RevOps as a service",        d: "Fractional ops leadership: weekly priorities, sprint planning, hiring help, vendor evaluation — embedded with your team." },
    { i: "shield",  n: "Audits + remediation",       d: "Security review, GDPR / SOC 2 prep on the HubSpot side, deliverability rehab, or unwinding a previous agency mess." },
  ];

  const steps = [
    { n: "01", t: "Tell us what you're shipping",
      d: "Send a short brief — what you need, when, and any constraints. No sales call required, but we're happy to hop on one." },
    { n: "02", t: "SOW or proposal in 48h",
      d: "If it fits an Hours Package or Retainer, we send a 1-page SOW. If it's a true custom build, you get a fixed-price proposal with milestones." },
    { n: "03", t: "Senior on day one",
      d: "Same operator owns the engagement end-to-end — no juniors, no account managers, no handoffs. Slack channel up within 24h of signing." },
    { n: "04", t: "Weekly cadence + burndown",
      d: "Async-first via Slack, plus one live working session per week. You get a written burndown report so you always know where hours stand." },
  ];

  const customFaq = [
    { q: "When should I buy hours vs sign a retainer?",
      a: "Buy an Hours Package when you have a project with a clear end — a launch, a migration, a quarter of optimization. You pay once, burn the hours within 90 days, no monthly commitment. Sign a Retainer when you want an operator to own the long tail of HubSpot / RevOps work week after week — standing session, dedicated Slack, sprint planning. The trade is rate vs flexibility: Hours run $135–$175/hr, Retainer drops to $110–$140/hr in exchange for the ongoing commitment." },
    { q: "What's actually a 'custom' engagement vs a service in the catalog?",
      a: "If 80% of what you need is already in the catalog, buy that and add an Hours block on top. If your scope is genuinely bespoke — a custom integration, a multi-system migration, fractional RevOps leadership — it's custom work, and we'll write a fixed-price proposal." },
    { q: "Can I roll over unused hours?",
      a: "Hours Packages are valid for 90 days. You can roll over up to 25% of unused hours into a follow-on block. Retainer hours don't roll over month to month — they're sized to your monthly burn rate so you're not over-buying." },
    { q: "Do you sign NDAs and DPAs?",
      a: "Yes. Standard mutual NDA and DPA templates are ready to sign. SOC 2 questionnaires welcomed — we run our practice on the same controls we help our clients implement." },
    { q: "What if my scope changes mid-engagement?",
      a: "We re-baseline the SOW or burndown together. No surprise change orders. If a project balloons past the original block, we'll tell you in week two — not week eight." },
    { q: "Can you work with our existing agency or in-house team?",
      a: "All the time. We're happy to be the senior pair of hands inside your team or a specialist your agency loops in for HubSpot / RevOps work specifically." },
  ];

  const renderModel = (p, eyebrow) => (
    <div className="cwp-model">
      <span className="cwp-model-eye">{eyebrow}</span>
      <div className="cwp-model-head">
        <div>
          <h3>{p.name}</h3>
          <p>{p.desc}</p>
        </div>
        <div className="cwp-model-from">
          <span className="l">From</span>
          <span className="p">{fmtPrice(Math.min(...p.tiers.map(t => t.price)))}{p.duration === "monthly" ? <small>/mo</small> : null}</span>
        </div>
      </div>
      <div className="cwp-tiers">
        {p.tiers.map(t => (
          <button key={t.id}
                  className={`cwp-tier ${t.badge ? "on" : ""}`}
                  onClick={() => goToProduct(p.id)}>
            {t.badge && <span className="cwp-tier-badge">★ Popular</span>}
            <div className="cwp-tier-head">
              <span className="cwp-tier-n">{t.name}</span>
              <span className="cwp-tier-tag">{t.tag}</span>
            </div>
            <div className="cwp-tier-p">
              {fmtPrice(t.price)}{p.duration === "monthly" ? <small>/mo</small> : null}
            </div>
            <ul>
              {t.bullets.slice(0, 3).map((b, i) => (
                <li key={i}><Icon name="check" size={11}/> {b}</li>
              ))}
              {t.bullets.length > 3 && <li className="more">+ {t.bullets.length - 3} more</li>}
            </ul>
          </button>
        ))}
      </div>
      <div className="cwp-model-foot">
        <button className="btn btn-primary" onClick={() => goToProduct(p.id)}>
          {p.duration === "monthly" ? "View retainer plans" : "View hours packages"} <Icon name="arrow" size={14}/>
        </button>
        <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="btn btn-ghost">Contact us about scope</a>
      </div>
    </div>
  );

  return (
    <>
      {/* ===== Hero ===== */}
      <section className="cat-hero cwp-hero" style={{"--cat-color": "#7C5CFC"}}>
        <div className="wrap">
          <nav className="pdp-crumbs cat-crumbs">
            <a href="/shop" onClick={(e) => { e.preventDefault(); goToShop(); }}>Shop</a>
            <span>/</span>
            <b>Custom work</b>
          </nav>

          <div className="cat-hero-grid">
            <div className="cat-hero-main">
              <span className="cat-eye">CUSTOM WORK · WHEN THE CATALOG ISN'T ENOUGH</span>
              <h1 className="cat-h1">When you need a senior on tap, <em>not a SKU.</em></h1>
              <p className="cat-sub">
                Two-thirds of our work fits a fixed service in the shop. For the other third — custom integrations, multi-portal migrations, fractional RevOps leadership, launch crunch coverage — pick the engagement model that matches your scope, and start with a senior operator on day one.
              </p>
              <div className="cat-hero-meta">
                <span className="m"><Icon name="zap"    size={13}/> Kickoff in <b>5 days</b></span>
                <span className="m"><Icon name="user"   size={13}/> One senior operator, end-to-end</span>
                <span className="m"><Icon name="shield" size={13}/> Fixed price · no surprise change orders</span>
                <span className="m"><Icon name="check"  size={13}/> Cancel any time · no annual lock-in</span>
              </div>
              <div className="hero-ctas" style={{marginTop:18}}>
                <a href="#cwp-models" className="btn btn-primary"
                   onClick={(e) => { e.preventDefault(); document.getElementById("cwp-models")?.scrollIntoView({behavior:"smooth"}); }}>
                  See engagement models <Icon name="arrow" size={14}/>
                </a>
                <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} className="btn btn-ghost">Send us a brief</a>
              </div>
            </div>
            <div className="cat-hero-card">
              <div className="cat-card-glyph"><Icon name="refresh" size={56}/></div>
              <div className="cat-card-foot">
                <span>ENGAGEMENT</span>
                <b>Custom &amp; Retainer</b>
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* ===== Engagement models ===== */}
      <section className="cwp-models" id="cwp-models">
        <div className="wrap">
          <div className="section-head">
            <div>
              <h2>Two ways to <em>engage.</em></h2>
              <div className="sub">PICK THE ONE THAT MATCHES YOUR SCOPE</div>
            </div>
          </div>
          <div className="cwp-models-grid">
            {hours    && renderModel(hours,    "01 · ONE-OFF SCOPE")}
            {retainer && renderModel(retainer, "02 · ONGOING SUPPORT")}
          </div>
          <div className="cwp-compare">
            <div className="cwp-compare-row cwp-compare-h">
              <div></div>
              <div>Hours Package</div>
              <div>Monthly Retainer</div>
            </div>
            <div className="cwp-compare-row">
              <div>Best for</div>
              <div>A defined project with a clear end date</div>
              <div>Ongoing ops you want a senior to own week after week</div>
            </div>
            <div className="cwp-compare-row">
              <div>Commitment</div>
              <div>One-time payment · no monthly bill</div>
              <div>Month-to-month · cancel with 30 days' notice</div>
            </div>
            <div className="cwp-compare-row">
              <div>Cadence</div>
              <div>Async + working sessions you schedule when you need them</div>
              <div>Standing weekly session + dedicated Slack from day one</div>
            </div>
            <div className="cwp-compare-row">
              <div>Planning</div>
              <div>SOW + burndown against your block</div>
              <div>Sprint board · prioritized with you every 2 weeks</div>
            </div>
            <div className="cwp-compare-row">
              <div>Hours expiry</div>
              <div>90-day window · roll over up to 25% unused</div>
              <div>Sized to your monthly burn · no rollover</div>
            </div>
            <div className="cwp-compare-row">
              <div>Hourly rate</div>
              <div><b>$135–$175 / hr</b> (depending on block size)</div>
              <div><b>$110–$140 / hr</b> (lower in exchange for commitment)</div>
            </div>
            <div className="cwp-compare-row">
              <div>Starts at</div>
              <div>$1,750 · 10h block</div>
              <div>$1,400 / month · Lite</div>
            </div>
          </div>
        </div>
      </section>

      {/* ===== Use cases ===== */}
      <section className="cwp-uses">
        <div className="wrap">
          <div className="section-head">
            <div>
              <h2>What teams <em>use it for.</em></h2>
              <div className="sub">REAL ENGAGEMENTS · LAST 12 MONTHS</div>
            </div>
          </div>
          <div className="cwp-uses-grid">
            {useCases.map((u, i) => (
              <div className="cwp-use" key={u.n}>
                <div className="cwp-use-num">0{i+1}</div>
                <div className="cwp-use-ic"><Icon name={u.i} size={20}/></div>
                <h3>{u.n}</h3>
                <p>{u.d}</p>
              </div>
            ))}
          </div>
          <p className="cwp-uses-foot">
            Don't see your scope? <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Send us a 3-line brief</a> and we'll tell you within 24h whether it fits an Hours Package, a Retainer, or a fully custom proposal.
          </p>
        </div>
      </section>

      {/* ===== Process ===== */}
      <section className="cwp-process">
        <div className="wrap">
          <div className="section-head">
            <div>
              <h2>How <em>custom engagements</em> work.</h2>
              <div className="sub">FOUR STEPS · NO SALES THEATRE</div>
            </div>
          </div>
          <div className="cwp-steps">
            {steps.map((s) => (
              <div className="cwp-step" key={s.n}>
                <div className="cwp-step-n">{s.n}</div>
                <h3>{s.t}</h3>
                <p>{s.d}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* ===== Reviews ===== */}
      <section className="cat-reviews">
        <div className="wrap">
          <span className="cat-section-eye">FROM TEAMS WHO WORK WITH US BEYOND THE CATALOG</span>
          <h2>What an embedded senior changes.</h2>
          <div className="cat-reviews-grid">
            <article className="cat-review">
              <Stars/>
              <p>"Working with Vestal Hub has been game changing. Their <b>speed to value is incredible</b>. The engagement model — Slack-first plus a weekly working session — supports both ad-hoc tactical changes and larger project implementations."</p>
              <div className="cr-author">
                <img src="https://vestalhub.com/hubfs/mavenagi_testimonial.webp" alt="Erin Parker" loading="lazy"/>
                <div>
                  <b>Erin Parker</b>
                  <span>Head of Revenue Operations · <em>Maven AGI</em></span>
                </div>
                <img className="cr-logo" src="https://vestalhub.com/hubfs/mavenagi.webp" alt="Maven AGI" loading="lazy"/>
              </div>
            </article>
            <article className="cat-review">
              <Stars/>
              <p>"We bought a 25-hour block to get past a launch crunch. <b>Used it in 3 weeks, no drama.</b> Then rolled the rest into a Lite retainer so we always have a senior on hand for the long tail of HubSpot work."</p>
              <div className="cr-author">
                <img src="https://vestalhub.com/hubfs/copilotkit_testimonial.webp" alt="Travis Murdock" loading="lazy"/>
                <div>
                  <b>Travis Murdock</b>
                  <span>Head of GTM · <em>CopilotKit</em></span>
                </div>
                <img className="cr-logo" src="https://vestalhub.com/hubfs/copilotkit.svg" alt="CopilotKit" loading="lazy"/>
              </div>
            </article>
          </div>
        </div>
      </section>

      {/* ===== FAQ ===== */}
      <section className="cat-faq">
        <div className="wrap">
          <div className="cat-faq-grid">
            <div>
              <span className="cat-section-eye">COMMON QUESTIONS · CUSTOM WORK</span>
              <h2>Before you brief us.</h2>
              <p>Most teams have the same five questions. If yours isn't here, <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>contact us</a> — we reply within one business day.</p>
            </div>
            <div className="cat-faq-list">
              {customFaq.map((f, i) => (
                <details key={i} open={i === 0}>
                  <summary>
                    <span>{f.q}</span>
                    <span className="plus"><Icon name="plus" size={14}/></span>
                  </summary>
                  <p>{f.a}</p>
                </details>
              ))}
            </div>
          </div>
        </div>
      </section>

      {/* ===== CTA band ===== */}
      <section className="cta-band" id="cta">
        <div className="wrap">
          <div className="cta-inner">
            <h2>Tell us what you're <em>shipping.</em></h2>
            <p>Three lines is enough: what you need, when you need it, any constraints. We'll reply within one business day with the right engagement model and a fixed price — no discovery call required.</p>
            <div className="btns">
              <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}
                 className="btn btn-primary">Send us a brief <Icon name="arrow" size={14}/></a>
              <a href="/shop" className="btn btn-ghost"
                 onClick={(e) => { e.preventDefault(); goToShop(); }}>Browse fixed-scope services</a>
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

/* ============================================================
   STATIC PAGES — Contact, About, Process, Partners, Careers,
   Terms, Privacy, Cookies. All share the .page-* shell.
============================================================ */

const PageHero = ({ eyebrow, title, lead, accent = "var(--brand)" }) => (
  <section className="page-hero" style={{ "--page-accent": accent }}>
    <div className="wrap">
      <span className="page-eye">{eyebrow}</span>
      <h1>{title}</h1>
      {lead && <p className="page-lead">{lead}</p>}
    </div>
  </section>
);

/* ============ Contact ============ */
/* ============ Booking page (HubSpot meetings embed) ============ */
const BookingPage = () => {
  const containerRef = useRef(null);
  useEffect(() => {
    if (!containerRef.current) return;
    const div = document.createElement("div");
    div.className = "meetings-iframe-container";
    div.setAttribute("data-src", "https://grow.vestalhub.com/meetings/vestalhub/hubspot-call?embed=true");
    containerRef.current.appendChild(div);
    const script = document.createElement("script");
    script.src = "https://static.hsappstatic.net/MeetingsEmbed/ex/MeetingsEmbedCode.js";
    script.async = true;
    containerRef.current.appendChild(script);
    return () => {
      if (containerRef.current) containerRef.current.innerHTML = "";
    };
  }, []);
  return (
    <section className="book-page">
      <div className="wrap">
        <div className="book-head">
          <span className="pdp-block-eye">BOOK A CALL</span>
          <h1>Talk to a senior operator</h1>
          <p>Whether you need a quick fix, a full onboarding, better reporting, cleaner CRM data, or a custom HubSpot build, we'll review your request and recommend the fastest path to get it done right.</p>
        </div>
        <div className="book-embed" ref={containerRef}/>
      </div>
    </section>
  );
};

const ContactPage = () => {
  const [form, setForm] = useState({ name:"", email:"", company:"", topic:"engagement", msg:"" });
  const [submitting, setSubmitting] = useState(false);
  const [sent, setSent] = useState(false);
  const [error, setError] = useState(null);
  const submit = async (e) => {
    e.preventDefault();
    setError(null);
    setSubmitting(true);
    try {
      const res = await fetch("/api/contact", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          name: form.name,
          email: form.email,
          company: form.company,
          topic: form.topic,
          message: form.msg,
        }),
      });
      // Read body once as text so we can show real diagnostics if it isn't JSON.
      const raw = await res.text();
      let json = {};
      try { json = raw ? JSON.parse(raw) : {}; } catch { /* non-JSON */ }
      if (!res.ok || !json.ok) {
        const detail = json.error || (raw && !json.error ? raw.slice(0, 140) : null);
        throw new Error(
          detail
            ? `${detail} (status ${res.status})`
            : `Submission failed (status ${res.status}). Please email hi@vestalhub.com directly.`
        );
      }
      setSent(true);
      setForm({ name:"", email:"", company:"", topic:"engagement", msg:"" });
    } catch (err) {
      // Network failures (offline, DNS, CORS) come through here with a generic message;
      // surface that to the user instead of swallowing it.
      const msg = err?.message || "Network error. Please check your connection or email hi@vestalhub.com directly.";
      console.error("[contact:submit] failed:", err);
      setError(msg);
    } finally {
      setSubmitting(false);
    }
  };
  return (
    <>
      <PageHero
        eyebrow="CONTACT · ONE BUSINESS DAY RESPONSE"
        title={<>Talk to a senior <em>operator.</em></>}
        lead="Tell us what you're shipping. We reply in one business day with the right engagement model and a fixed price — no discovery call required."
        accent="#3B69FF"
      />
      <section className="page-body">
        <div className="wrap contact-grid">
          <div className="contact-form-card">
            <span className="page-section-eye">SEND A BRIEF</span>
            <h2>Three lines is enough.</h2>
            <p className="contact-form-lead">What you need, when you need it, any constraints. We turn it into a SOW within one business day.</p>
            <form onSubmit={submit} className="contact-form">
              <label>
                <span>Your name *</span>
                <input type="text" required value={form.name} onChange={e => setForm({...form, name:e.target.value})} placeholder="Jane Doe"/>
              </label>
              <label>
                <span>Work email *</span>
                <input type="email" required value={form.email} onChange={e => setForm({...form, email:e.target.value})} placeholder="jane@acme.com"/>
              </label>
              <label>
                <span>Company</span>
                <input type="text" value={form.company} onChange={e => setForm({...form, company:e.target.value})} placeholder="Acme Inc."/>
              </label>
              <label>
                <span>What's this about?</span>
                <select value={form.topic} onChange={e => setForm({...form, topic:e.target.value})}>
                  <option value="engagement">A new engagement / project</option>
                  <option value="custom">Custom work / hours / retainer</option>
                  <option value="partner">Partner program</option>
                  <option value="careers">Careers</option>
                  <option value="press">Press / partnerships</option>
                  <option value="other">Something else</option>
                </select>
              </label>
              <label>
                <span>Brief *</span>
                <textarea required rows={6} value={form.msg} onChange={e => setForm({...form, msg:e.target.value})} placeholder="What you need: …&#10;When: …&#10;Constraints: …"></textarea>
              </label>
              <button className="btn btn-primary" type="submit" disabled={submitting}>
                {submitting ? "Sending…" : <>Send brief <Icon name="arrow" size={14}/></>}
              </button>
              {sent && (
                <div className="contact-form-sent">
                  <b>Got it.</b> A senior operator will reply within one business day at the email you provided.
                </div>
              )}
              {error && <div className="checkout-err">{error}</div>}
            </form>
          </div>

          <aside className="contact-side">
            <div className="contact-card">
              <span className="page-section-eye">EMAIL US DIRECTLY</span>
              <a className="contact-email" href={`mailto:${SOCIAL.email}`}>{SOCIAL.email}</a>
              <p>One inbox, monitored by senior operators. We reply within one business day, weekends and holidays excluded.</p>
            </div>
            <div className="contact-card">
              <span className="page-section-eye">CONNECT</span>
              <ul className="contact-list">
                <li>
                  <Icon name="linkedin" size={18}/>
                  <div>
                    <b>LinkedIn</b>
                    <a href={SOCIAL.linkedin} target="_blank" rel="noopener noreferrer">linkedin.com/company/vestalhub</a>
                  </div>
                </li>
                <li>
                  <Icon name="shield" size={18}/>
                  <div>
                    <b>HubSpot Solutions Partner</b>
                    <span>Gold tier · Trusted by 100+ companies across SaaS, agencies, services, finance, and nonprofits.</span>
                  </div>
                </li>
                <li>
                  <Icon name="rocket" size={18}/>
                  <div>
                    <b>Cohort calendar</b>
                    <span>New engagements start every two weeks. Rush delivery available (+$1,200 · ~25% faster).</span>
                  </div>
                </li>
              </ul>
            </div>
            <div className="contact-card contact-card-alt">
              <span className="page-section-eye">QUICK PATHS</span>
              <a href="/shop" className="contact-quick" onClick={(e) => { e.preventDefault(); goToShop(); }}>
                <span><b>Browse fixed-scope services</b><em>25 published SKUs · pricing on every card</em></span>
                <Icon name="arrow" size={16}/>
              </a>
              <a href="/custom" className="contact-quick" onClick={(e) => { e.preventDefault(); goToCustom(); }}>
                <span><b>Hours pack or monthly retainer</b><em>For work that doesn't fit a fixed SOW</em></span>
                <Icon name="arrow" size={16}/>
              </a>
              <a href="/partners" className="contact-quick" onClick={(e) => { e.preventDefault(); goToPartners(); }}>
                <span><b>Partner program</b><em>For agencies, RevOps consultants, and HubSpot peers</em></span>
                <Icon name="arrow" size={16}/>
              </a>
            </div>
          </aside>
        </div>
      </section>
    </>
  );
};

/* ============ About ============ */
const AboutPage = () => {
  const principles = [
    { i:"shield",  t:"Senior, all the way down",
      d:"Every engagement is owned end-to-end by an operator with 8+ years in HubSpot and revenue ops. No juniors learning on your portal." },
    { i:"layers",  t:"Buy the playbook, not the hours",
      d:"Each service is a fixed-scope system: same scope, same deliverables, same outcomes. Predictable in, predictable out." },
    { i:"rocket",  t:"Ship in weeks, not quarters",
      d:"Standardized config means we skip the months-long discovery. Most engagements are live in 14–28 days." },
    { i:"chart",   t:"Measured in dollars, not slides",
      d:"Every project ends with a dashboard that ties our work to pipeline, ARR, or hours saved. If we can't measure it, we don't ship it." },
  ];
  return (
    <>
      <PageHero
        eyebrow="ABOUT · WHO YOU'RE BUYING FROM"
        title={<>Senior HubSpot operators, <em>priced like software.</em></>}
        lead={<>Vestal Hub is a <a href="https://ecosystem.hubspot.com/marketplace/solutions/vestalhub" target="_blank" rel="noopener noreferrer" style={{textDecoration:"underline"}}>HubSpot Solutions Partner (Gold tier)</a>. We've helped 100+ companies across SaaS, agencies, services, finance, real estate, e-commerce, and nonprofits stand up HubSpot and revenue systems. We turned every recurring engagement into a fixed-price SKU so buying senior help is as easy as buying software.</>}
        accent="#3B69FF"
      />
      <section className="page-body">
        <div className="wrap">
          <div className="about-stats">
            <div className="about-stat"><b>100+</b><span>Companies served</span></div>
            <div className="about-stat"><b>5 / 5</b><span>Average client rating</span></div>
          </div>

          <div className="page-section">
            <span className="page-section-eye">HOW WE GOT HERE</span>
            <h2>Why <em>value based</em> beats hourly.</h2>
            <p className="page-prose">
              The traditional consulting model trades hours for money — which means consultants get paid more when projects take longer, and clients pay more when they ask better questions. That's a misaligned incentive on both sides.
            </p>
            <p className="page-prose">
              We turned the dozen engagements we ship every month into <b>fixed-scope services with published prices</b>. Same shape, same deliverables, same outcomes. You always know what you're buying. We always know what we're shipping. Pricing is the same whether you're a five-person seed startup or a 500-person Series C.
            </p>
            <p className="page-prose">
              For everything that doesn't fit a SKU — strategic ops work, ongoing optimization, weird integrations — we have <a href="/custom" onClick={(e) => { e.preventDefault(); goToCustom(); }}>hours packages and monthly retainers</a> with the same senior operators.
            </p>
          </div>

          <div className="page-section">
            <span className="page-section-eye">WHAT WE BELIEVE</span>
            <h2>Four principles, applied to every engagement.</h2>
            <div className="about-principles">
              {principles.map((p, i) => (
                <article key={i} className="about-principle">
                  <span className="about-principle-ic"><Icon name={p.i} size={20}/></span>
                  <h3>{p.t}</h3>
                  <p>{p.d}</p>
                </article>
              ))}
            </div>
          </div>

          <div className="page-section page-cta-block">
            <h2>Have a brief? <em>Send it.</em></h2>
            <p>One business day, fixed price, no sales call.</p>
            <div className="page-cta-row">
              <a href="/contact" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToContact(); }}>Get in touch <Icon name="arrow" size={14}/></a>
              <a href="/shop" className="btn btn-secondary" onClick={(e) => { e.preventDefault(); goToShop(); }}>Browse the catalog</a>
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

/* ============ Process ============ */
const ProcessPage = () => {
  const steps = [
    { n:"01", t:"Pick services or send a brief",
      d:"Browse the catalog and add fixed-scope SKUs to your cart, or email us a 3-line brief if your work doesn't fit. Bundles and add-ons stack at checkout. Zero pressure to talk to sales." },
    { n:"02", t:"SOW in 24 hours",
      d:"For fixed-scope services from the catalog, you receive a signed-ready Statement of Work with exact deliverables, milestones, dates, and price within 24 hours. No surprises, no change orders. You don't pay until you sign — checkout is really a reservation.",
      note:"Custom briefs may take longer. If your work doesn't fit a published SKU, the SOW can take more than 24 hours depending on complexity, and may require an additional discovery call to scope it properly." },
    { n:"03", t:"Sign and kick off in 7–14 days",
      d:"A senior operator (8+ years HubSpot / RevOps) is assigned within 24h of signing. We schedule a 30-minute kickoff to confirm goals, share access, and lock the timeline." },
    { n:"04", t:"Weekly progress, fixed cadence",
      d:"Every Monday: a written update on what shipped, what's next, what we need from you. Slack channel for the duration. No status meetings unless you want one." },
    { n:"05", t:"QA + handoff",
      d:"Every workflow QA'd before handoff, every dashboard wired to live data, training delivered live and on Loom. You leave the engagement with documentation your team can actually use." },
    { n:"06", t:"30-day post-launch window",
      d:"After handoff, we stay on Slack for a 30-day window for tweaks, edge cases, and questions. No retainer required." },
  ];
  return (
    <>
      <PageHero
        eyebrow="PROCESS · HOW BUYING ACTUALLY WORKS"
        title={<>Six steps from <em>brief to live.</em></>}
        lead="Same process for every engagement — whether you're buying a $700 add-on or a $25k Scale bundle. Predictable in, predictable out."
        accent="#7C5CFC"
      />
      <section className="page-body">
        <div className="wrap">
          <div className="process-steps">
            {steps.map((s) => (
              <article key={s.n} className="process-step">
                <span className="process-step-num">{s.n}</span>
                <div className="process-step-body">
                  <h3>{s.t}</h3>
                  <p>{s.d}</p>
                  {s.note && (
                    <p className="process-step-note">
                      <Icon name="shield" size={12}/> {s.note}
                    </p>
                  )}
                </div>
              </article>
            ))}
          </div>

          <div className="page-section page-cta-block">
            <h2>Ready to brief us? <em>Three lines is enough.</em></h2>
            <p>What you need, when you need it, any constraints.</p>
            <div className="page-cta-row">
              <a href="/contact" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToContact(); }}>Send a brief <Icon name="arrow" size={14}/></a>
              <a href="/shop" className="btn btn-secondary" onClick={(e) => { e.preventDefault(); goToShop(); }}>Browse fixed-scope services</a>
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

/* ============ Partner program ============ */
const PartnersPage = () => {
  const tracks = [
    { t:"Referral partner",
      who:"Agencies, fractional CMOs, RevOps consultants who don't deliver HubSpot work themselves but talk to teams who need it.",
      payout:"10% of first-year revenue",
      ship:[
        "Email us a warm intro · we close, deliver, and pay quarterly",
        "No co-selling required · we run our own sales cycle",
        "Quarterly partner newsletter with new SKUs and case studies",
      ],
    },
    { t:"Tech / app partner",
      who:"Software companies in the HubSpot ecosystem (data, enrichment, attribution, sales tools) who want a delivery arm for joint customers.",
      payout:"Co-marketing · joint case studies",
      ship:[
        "Implementation playbooks for your app on HubSpot",
        "Co-authored case studies · joint webinars",
        "Reciprocal listing on partner pages",
      ],
    },
  ];
  return (
    <>
      <PageHero
        eyebrow="PARTNER PROGRAM · 2 TRACKS · ZERO MINIMUMS"
        title={<>Partner with senior <em>HubSpot operators.</em></>}
        lead="Two ways to work with us as a peer. Refer warm intros or co-build with us as a tech partner. No minimums, no exclusivity, fixed payouts."
        accent="#0E8A4F"
      />
      <section className="page-body">
        <div className="wrap">
          <div className="partner-tracks">
            {tracks.map((t, i) => (
              <article key={i} className="partner-track">
                <span className="partner-track-num">{`0${i+1}`}</span>
                <h3>{t.t}</h3>
                <div className="partner-payout">
                  <span className="partner-payout-l">Payout</span>
                  <span className="partner-payout-t">{t.payout}</span>
                </div>
                <p className="partner-track-who"><b>Who it's for:</b> {t.who}</p>
                <ul>
                  {t.ship.map((s, j) => (
                    <li key={j}><Icon name="check" size={14}/> {s}</li>
                  ))}
                </ul>
              </article>
            ))}
          </div>

          <div className="page-section page-cta-block">
            <h2>Sound interesting? <em>Let's talk.</em></h2>
            <p>One business day reply. We'll send a one-page partner agreement after a quick alignment call.</p>
            <div className="page-cta-row">
              <a href={`mailto:${SOCIAL.email}?subject=Partner%20program&body=Track%20I'm%20interested%20in%3A%20%0AWhat%20I%20do%3A%20%0AHow%20I'd%20like%20to%20work%20together%3A%20%0A`} className="btn btn-primary">
                Email partnerships <Icon name="arrow" size={14}/>
              </a>
              <a href="/contact" className="btn btn-secondary" onClick={(e) => { e.preventDefault(); goToContact(); }}>Send a brief</a>
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

/* ============ Careers ============ */
const CareersPage = () => {
  const roles = [
    { t:"Senior HubSpot Operator", loc:"Remote · Americas", type:"Full-time",
      d:"Own end-to-end delivery on 4–6 fixed-scope engagements per quarter. Sales, marketing, or service hub focus. 8+ years in HubSpot and revenue operations." },
    { t:"Lifecycle & Lead Scoring Lead", loc:"Remote · Americas", type:"Full-time",
      d:"Build lifecycle stages, scoring models, and attribution dashboards across the catalog. Strong product analytics + HubSpot reporting depth required." },
    { t:"HubSpot CMS Developer", loc:"Remote · global", type:"Full-time / contract",
      d:"Ship landing-page systems and marketing-site refreshes on HubSpot CMS. HubL, modular sections, Core Web Vitals. Bonus for design-system experience." },
    { t:"RevOps Apprentice", loc:"Remote · Americas", type:"Full-time · paid",
      d:"6-month structured apprenticeship pairing with senior operators on real client work. For ops-curious folks transitioning from sales, marketing, or CS." },
  ];
  const benefits = [
    "Async-first, deep-work culture · no daily standups",
    "Senior comp, profit share, and a real cohort to learn from",
    "Health, dental, vision (US) · stipend equivalent globally",
    "$2,000 / yr learning budget · annual team offsite",
    "4-day workweeks every other Friday",
    "No timesheets, no utilization targets · we measure shipped outcomes",
  ];
  return (
    <>
      <PageHero
        eyebrow="CAREERS · SENIOR OPERATORS ONLY"
        title={<>Join a team that ships <em>real outcomes.</em></>}
        lead="We hire senior operators who've already shipped this work somewhere else. No juniors, no rotating account managers, no utilization targets. Get paid to do your best work for clients who can tell the difference."
        accent="#FF7A29"
      />
      <section className="page-body">
        <div className="wrap">
          <div className="page-section">
            <span className="page-section-eye">OPEN ROLES</span>
            <h2>Currently <em>hiring.</em></h2>
            <div className="careers-roles">
              {roles.map((r, i) => (
                <article key={i} className="careers-role">
                  <div className="careers-role-head">
                    <h3>{r.t}</h3>
                    <span className="careers-role-meta">{r.loc} · {r.type}</span>
                  </div>
                  <p>{r.d}</p>
                  <a href={`mailto:${SOCIAL.email}?subject=Application%3A%20${encodeURIComponent(r.t)}&body=Hi%20Vestal%20Hub%2C%0A%0AI'd%20like%20to%20apply%20for%20${encodeURIComponent(r.t)}.%0A%0AAttached%3A%20resume%20%2F%20LinkedIn%0AThree%20projects%20I'm%20proud%20of%3A%20%0A`} className="careers-role-cta">
                    Apply by email <Icon name="arrow" size={12}/>
                  </a>
                </article>
              ))}
            </div>
          </div>

          <div className="page-section">
            <span className="page-section-eye">HOW WE WORK</span>
            <h2>What you get for <em>showing up.</em></h2>
            <ul className="careers-benefits">
              {benefits.map((b, i) => (
                <li key={i}><Icon name="check" size={14}/> {b}</li>
              ))}
            </ul>
          </div>

          <div className="page-section page-cta-block">
            <h2>Don't see your role? <em>We're still listening.</em></h2>
            <p>If you've shipped HubSpot or RevOps work for the last decade and want to do it without timesheets, send a note.</p>
            <div className="page-cta-row">
              <a href="/contact" className="btn btn-primary" onClick={(e) => { e.preventDefault(); goToContact(); }}>
                Contact us <Icon name="arrow" size={14}/>
              </a>
              <a href="/about" className="btn btn-secondary" onClick={(e) => { e.preventDefault(); goToAbout(); }}>About us</a>
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

/* ============ Legal: Terms / Privacy / Cookies ============ */
const LegalPage = ({ kind }) => {
  const today = new Date();
  const updated = today.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });

  const docs = {
    terms: {
      eyebrow: "LEGAL · TERMS OF SERVICE",
      title: <>Terms of <em>service.</em></>,
      lead: "These terms govern any engagement you purchase from Vestal Hub LLC, a Florida company based in Miami. By signing a Statement of Work or paying an invoice, you agree to them.",
      sections: [
        { h: "1. About these terms", body: [
          "Vestal Hub LLC is a Florida limited liability company based in Miami, Florida (\"Vestal Hub\", \"we\", \"us\"). These terms govern any engagement, subscription, or purchase you make from us via this website, a Statement of Work (\"SOW\"), or an invoice.",
          "By signing an SOW, paying an invoice, or accepting a service we deliver, you (\"Client\", \"you\") agree to these terms. If your organization has a master services agreement we've countersigned, that agreement controls; otherwise, these terms apply.",
        ]},
        { h: "2. Engagements & scope changes", body: [
          "Every Vestal Hub engagement is governed by a written SOW. The SOW defines deliverables, timeline, price, acceptance criteria, and any client responsibilities. The SOW supersedes any conflicting language in marketing materials, email threads, or this catalog.",
          "Fixed-scope SKUs ship the deliverables published on their product page, subject to the upper limits stated there. Work outside the SOW (new requirements, expanded limits, additional surface area) is added via a written change order — a short addendum signed by both parties — or a new SOW. We don't accept uncontrolled change orders mid-engagement.",
          "Where a deliverable depends on third-party tools (HubSpot plans, integrations, ad platforms, LLM providers), the SOW assumes you maintain active subscriptions to those tools for the duration of the engagement.",
        ]},
        { h: "3. Payment", body: [
          "Payment is due on signature of the SOW unless otherwise stated, in USD. We accept ACH, wire transfer, and major credit cards via Stripe. Engagements over $10,000 may be split 50/50 between kickoff and acceptance.",
          "Hours packs are billed in full at purchase and valid for 90 days from the purchase date. Monthly retainers are billed on the 1st of each calendar month, prorated for the first month, and require 30 days' written notice to cancel — see Section 9.",
          "Invoices not paid within 30 days of issue accrue interest at 1.5% per month, or the maximum rate permitted by Florida law, whichever is lower. We may pause work on past-due engagements after 15 days' written notice.",
        ]},
        { h: "4. Client responsibilities", body: [
          "Your timely responses keep our timelines honest. We expect: HubSpot Super Admin access (or a scoped equivalent) within 3 business days of SOW signature; decisions on key trade-offs within 3 business days of being asked; content, brand assets, and approvals as the SOW requires.",
          "If we're blocked on a client decision, access, or asset for more than 10 business days, the timeline pauses without affecting price. Engagements paused longer than 30 days may be re-scoped at our discretion to reflect any material changes since signature.",
          "You are responsible for the accuracy of data you provide and for any third-party tool fees (HubSpot, Zapier, OpenAI, ad platforms, etc.) used during the engagement.",
        ]},
        { h: "5. Acceptance", body: [
          "Each deliverable has a 5-business-day acceptance window from delivery. If you don't request changes within the window, the deliverable is deemed accepted. If you do, we'll address them and re-deliver within 5 business days. Repeated cycles of substantively new requirements are treated as a scope change under Section 2.",
          "Post-launch support windows (typically 30 days, where included) cover bug fixes, configuration tweaks, and minor tuning — not new scope.",
        ]},
        { h: "6. Intellectual property", body: [
          "On full payment of an SOW, you own all custom deliverables created specifically for you under that SOW: HubSpot configurations, custom code, copy, design files, and documentation. We assign to you all rights necessary to use, modify, and operate those deliverables.",
          "Vestal Hub retains ownership of our pre-existing IP — frameworks, templates, internal tools, generic code patterns, and methodologies developed independent of your engagement. We grant you a perpetual, royalty-free, worldwide license to use those elements as incorporated into your deliverables.",
        ]},
        { h: "7. Confidentiality", body: [
          "We treat all client data, configurations, business information, and access credentials as confidential. We sign mutual NDAs on request at no cost. Confidential information is used only to perform the engagement and protected for 3 years after engagement end (perpetually for trade secrets).",
          "We may reference engagements in case studies, on this website, and in proposals only with your prior written consent. You may withdraw that consent at any time, and we'll remove the reference within 30 days.",
        ]},
        { h: "8. Warranty & liability", body: [
          "Services are provided \"as-is\" with the warranty that they will perform substantially as described in the SOW. We disclaim all other warranties, express or implied, including merchantability and fitness for a particular purpose.",
          "Our total aggregate liability for any engagement is capped at the fees you paid for that engagement in the 12 months preceding the claim. Neither party is liable for indirect, incidental, consequential, special, or revenue-related damages — even if foreseeable. These limits do not apply to fraud, willful misconduct, or indemnification obligations.",
        ]},
        { h: "9. Cancellation & termination", body: [
          "You may cancel an engagement at any time by sending written notice to " + SOCIAL.email + ". As a general rule, fees for work already performed are non-refundable. What you owe at cancellation depends on the engagement type:",
          "Fixed-scope SKUs paid up-front: Fees are non-refundable. On cancellation, we stop further work immediately and hand off every completed deliverable plus any works-in-progress (drafts, partial configurations, written documentation) in their current state. You don't owe anything beyond the SOW price already paid.",
          "Fixed-scope SKUs with split payments (e.g. 50/50): Amounts already invoiced are non-refundable. You also owe the proportion of the total SOW fee corresponding to work delivered or in active production at the cancellation date, less amounts already paid. Unbilled future milestones beyond that point are not owed.",
          "Hours packs: Non-refundable. Unused hours may be transferred to another SOW signed within 90 days of the original purchase date.",
          "Monthly retainers: You owe the current month's fee. Cancellation takes effect at the end of the calendar month following 30 days' written notice. Hours unused in the current month do not roll over after termination, and prepaid months are not refunded.",
          "We don't charge cancellation penalties beyond the rules above. Either party may terminate immediately for the other's uncured material breach (after 15 days' written notice to cure), insolvency, or violation of confidentiality.",
        ]},
        { h: "10. Non-solicitation", body: [
          "During the engagement and for 12 months after it ends, neither party will directly solicit for employment the other's employees or contractors who worked on the engagement, without the other party's prior written consent. General job postings and unsolicited applications to them are not considered solicitation.",
        ]},
        { h: "11. Independent contractor", body: [
          "Vestal Hub is an independent contractor. Nothing in these terms or any SOW creates an employment, partnership, joint venture, or agency relationship between the parties. Neither party may bind the other.",
        ]},
        { h: "12. Force majeure", body: [
          "Neither party is liable for delays or failures caused by events outside its reasonable control, including natural disasters, pandemics, government action, internet or hosting-provider outages, and acts of third parties. The affected party will notify the other promptly and resume performance as soon as practicable.",
        ]},
        { h: "13. Governing law & disputes", body: [
          "These terms are governed by the laws of the State of Florida, USA, without regard to conflict-of-laws principles. The parties first agree to attempt good-faith resolution of any dispute by direct discussion for 30 days.",
          "If that fails, disputes will be resolved by binding arbitration administered by the American Arbitration Association under its Commercial Arbitration Rules, seated in Miami-Dade County, Florida. Either party may seek injunctive or equitable relief in a court of competent jurisdiction in Miami-Dade County, Florida.",
        ]},
        { h: "14. Miscellaneous", body: [
          "Notices: Written notices may be sent by email to " + SOCIAL.email + " (for Vestal Hub) and to the email address on the SOW (for Client). Notice is effective the next business day.",
          "Entire agreement: An executed SOW plus these terms is the entire agreement between the parties on its subject matter, superseding prior discussions. Amendments require a signed writing from both parties.",
          "Severability & waiver: If any provision is held unenforceable, the remainder stay in effect. Waivers must be in writing and apply only to the specific instance.",
          "Assignment: Neither party may assign these terms without the other's written consent, except to a successor in a merger, acquisition, or sale of substantially all assets.",
        ]},
      ],
    },
    privacy: {
      eyebrow: "LEGAL · PRIVACY POLICY",
      title: <>Privacy <em>policy.</em></>,
      lead: "We collect the minimum we need to deliver engagements, reply to inquiries, and operate this website. We don't sell your data.",
      sections: [
        { h: "What we collect", body: [
          "From this website: pages visited, basic device/browser info, and form submissions (name, email, company, message). We use first-party analytics with IP truncation by default.",
          "From engagements: the access credentials, account configurations, and data you grant us in HubSpot or related tools, only to the extent needed to perform the SOW.",
          "From your inbox: email correspondence with us, retained per our records-retention schedule.",
        ]},
        { h: "What we use it for", body: [
          "Replying to your inquiries (one business day SLA).",
          "Delivering the engagement you signed an SOW for.",
          "Sending operational updates (status emails, invoices, SOW change notices).",
          "Improving the website and our published catalog.",
        ]},
        { h: "What we don't do", body: [
          "We don't sell or rent your personal information to third parties.",
          "We don't run ad-tech retargeting on this site.",
          "We don't enrich your contact data with third-party brokers.",
        ]},
        { h: "Sub-processors", body: [
          "We use HubSpot (CRM and forms), Google Workspace (email, docs), Stripe (payment processing), Vercel (website hosting), and a small number of analytics tools. The full list is available on request.",
        ]},
        { h: "Your rights", body: [
          "You may request access to, correction of, or deletion of your personal information at any time by emailing " + SOCIAL.email + ". We respond within 30 days.",
          "If you're in the EU, UK, California, or any jurisdiction with similar rights, those rights apply to you regardless of your residency.",
        ]},
        { h: "Retention", body: [
          "We retain client engagement data for 24 months after engagement end, then delete or anonymize it unless legal obligations require longer retention. Inquiry emails are retained for 12 months.",
        ]},
        { h: "Contact", body: [
          "Questions? Email " + SOCIAL.email + " with the subject line \"Privacy\". We'll route it to the right person.",
        ]},
      ],
    },
    cookies: {
      eyebrow: "LEGAL · COOKIES NOTICE",
      title: <>Cookies <em>notice.</em></>,
      lead: "We use a small number of first-party cookies to keep this website working and to understand how it's used in aggregate. No advertising trackers.",
      sections: [
        { h: "Strictly necessary", body: [
          "Used to keep this website functional. Examples: storing your cart contents between page loads, remembering you've dismissed a banner, securing form submissions. These can't be disabled without breaking the site.",
        ]},
        { h: "Analytics", body: [
          "We use first-party, IP-truncated analytics to understand which services and pages teams find useful. We don't track you across the rest of the web. You can opt out by sending Do Not Track in your browser — we honor it.",
        ]},
        { h: "What we don't use", body: [
          "We don't use Facebook Pixel, Google Ads remarketing, LinkedIn Insight Tag, or any third-party advertising trackers on this site.",
        ]},
        { h: "Managing cookies", body: [
          "You can clear or block cookies from your browser settings at any time. Doing so may break parts of this site (notably the cart). On a fresh visit, blocked cookies will be re-attempted on each page load.",
        ]},
        { h: "Updates", body: [
          "We update this notice when we add or remove tools. The \"Last updated\" date below always reflects the current version. Material changes are summarized at the top of the notice for 30 days.",
        ]},
      ],
    },
  };

  const doc = docs[kind];
  return (
    <>
      <PageHero eyebrow={doc.eyebrow} title={doc.title} lead={doc.lead} accent="#3B69FF" />
      <section className="page-body">
        <div className="wrap legal-grid">
          <aside className="legal-toc">
            <span className="page-section-eye">ON THIS PAGE</span>
            <ul>
              {doc.sections.map((s, i) => (
                <li key={i}><a href={`#sec-${i}`}>{s.h}</a></li>
              ))}
            </ul>
            <div className="legal-meta">
              <span>Last updated</span>
              <b>{updated}</b>
            </div>
            <div className="legal-meta">
              <span>Questions?</span>
              <a href={`mailto:${SOCIAL.email}?subject=Legal%20question`}>{SOCIAL.email}</a>
            </div>
          </aside>
          <article className="legal-body">
            {doc.sections.map((s, i) => (
              <section key={i} id={`sec-${i}`} className="legal-section">
                <h2>{s.h}</h2>
                {s.body.map((p, j) => <p key={j}>{p}</p>)}
              </section>
            ))}
            <p className="legal-foot">
              By using this website or signing a Statement of Work with Vestal Hub, you acknowledge you've read and accepted this notice.
              For anything else, email <a href={`mailto:${SOCIAL.email}`}>{SOCIAL.email}</a>.
            </p>
          </article>
        </div>
      </section>
    </>
  );
};

/* ============ Footer ============ */
const Footer = () => {
  return (
    <footer className="footer">
      <div className="wrap">
        <div className="ft-grid">
          <div>
            <a href="#" onClick={(e) => { e.preventDefault(); goHome(); }} className="logo" aria-label="Vestal Hub"><img src="Vestal-hub.png" alt="Vestal Hub" className="logo-img logo-img-footer" /></a>
            <p>HubSpot &amp; RevOps services for teams of any size. Trusted by 100+ companies, <em>shipped by senior operators</em>, priced like software.</p>
            <div className="ft-social">
              <a href={SOCIAL.linkedin} target="_blank" rel="noopener noreferrer" aria-label="Vestal Hub on LinkedIn">
                <Icon name="linkedin" size={16}/>
              </a>
              <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }} aria-label="Contact us">
                <Icon name="mail" size={16}/>
              </a>
            </div>
            <div className="ft-badge">
              <span className="ft-badge-dot" aria-hidden="true"/>
              <div className="ft-badge-text">
                <b>HubSpot Solutions Partner</b>
                <span>Gold tier · Trusted by 100+ companies</span>
              </div>
            </div>
          </div>
          <div>
            <h4>Shop</h4>
            <a href="/shop"               onClick={(e) => { e.preventDefault(); goToShop(); }}>All services</a>
            <a href="/category/hubspot"     onClick={(e) => { e.preventDefault(); goToCategory("hubspot"); }}>HubSpot</a>
            <a href="/category/development" onClick={(e) => { e.preventDefault(); goToCategory("development"); }}>Development</a>
            <a href="/category/addons"    onClick={(e) => { e.preventDefault(); goToCategory("addons"); }}>Add-ons</a>
            <a href="/custom"             onClick={(e) => { e.preventDefault(); goToCustom(); }}>Custom &amp; Retainer</a>
          </div>
          <div>
            <h4>Studio</h4>
            <a href="/about"    onClick={(e) => { e.preventDefault(); goToAbout(); }}>About</a>
            <a href="/process"  onClick={(e) => { e.preventDefault(); goToProcess(); }}>Process</a>
            <a href="/partners" onClick={(e) => { e.preventDefault(); goToPartners(); }}>Partner program</a>
            <a href="/careers"  onClick={(e) => { e.preventDefault(); goToCareers(); }}>Careers</a>
          </div>
          <div>
            <h4>Support</h4>
            <a href="/contact"  onClick={(e) => { e.preventDefault(); goToContact(); }}>Contact</a>
            <a href={`mailto:${SOCIAL.email}?subject=Help`}>Email us</a>
            <a href="/process"  onClick={(e) => { e.preventDefault(); goToProcess(); }}>How it works</a>
            <a href="#"          onClick={(e) => { e.preventDefault(); goHome(); setTimeout(() => document.querySelector(".faq-section")?.scrollIntoView({behavior:"smooth"}), 50); }}>FAQ</a>
          </div>
          <div>
            <h4>Legal</h4>
            <a href="/terms"   onClick={(e) => { e.preventDefault(); goToTerms(); }}>Terms</a>
            <a href="/privacy" onClick={(e) => { e.preventDefault(); goToPrivacy(); }}>Privacy</a>
            <a href="/cookies" onClick={(e) => { e.preventDefault(); goToCookies(); }}>Cookies</a>
          </div>
        </div>
        <div className="ft-bot">
          <div>© 2026 Vestal Hub</div>
          <div className="ft-pay">
            <span className="c">VISA</span>
            <span className="c">MC</span>
            <span className="c">AMEX</span>
            <span className="c">ACH</span>
            <span className="c">WIRE</span>
          </div>
        </div>
      </div>
    </footer>
  );
};

/* ============ Checkout ============
 *
 * Two-column layout: form on the left, sticky order summary on the right.
 * Cart is read-only on this page — buyers can't edit line items here, only
 * fill in their info and submit. Successful submission POSTs to /api/checkout
 * which emails both sides + creates a HubSpot Contact + Deal, then we save a
 * cart snapshot to sessionStorage and route to the thank-you page.
 */
const COUNTRIES = [
  "United States","Canada","United Kingdom","Ireland","Germany","France","Spain",
  "Portugal","Netherlands","Sweden","Denmark","Norway","Finland","Switzerland",
  "Australia","New Zealand","Singapore","Japan","Brazil","Mexico","Argentina",
  "Chile","Colombia","Other"
];
const TEAM_SIZES = [
  "Just me","2–10","11–50","51–200","201–500","500+"
];
const KICKOFF_WINDOWS = [
  "This week (rush)","Next 2 weeks","Next month","Flexible / TBD"
];

const CheckoutPage = ({ items, addons, onCleared }) => {
  const totals = cartMath(items, addons);
  const addonList = Object.keys(addons || {})
    .filter(k => addons[k])
    .map(k => ADDONS.find(a => a.id === k))
    .filter(Boolean);

  const [buyer, setBuyer] = useState({ name: "", email: "", role: "" });
  const [company, setCompany] = useState({
    legalName: "", website: "", country: "United States", size: "11–50",
  });
  const [engagement, setEngagement] = useState({
    kickoff: "Next 2 weeks", channel: "Slack", brief: "",
  });
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState(null);

  // Empty cart → bounce them back to the shop. (We don't want a "submit"
  // action with a $0 cart that creates phantom HubSpot deals.)
  if (!items || items.length === 0) {
    return (
      <>
        <PageHero
          eyebrow="CHECKOUT"
          title={<>Your cart is <em>empty.</em></>}
          lead="Add a fixed-scope service to your cart, then come back here to send a brief and receive your SOW within one business day."
          accent="#3B69FF"
        />
        <section className="page-body">
          <div className="wrap" style={{textAlign:"center", padding: "20px 0 40px"}}>
            <a className="btn btn-primary" href="/shop"
               onClick={(e) => { e.preventDefault(); goToShop(); }}>
               Browse services <Icon name="arrow" size={14}/>
            </a>
          </div>
        </section>
      </>
    );
  }

  const submit = async (e) => {
    e.preventDefault();
    setError(null);
    setSubmitting(true);

    const payload = {
      buyer,
      company,
      engagement,
      cart: {
        items: items.map(it => ({
          id: it.id, name: it.name, category: it.category,
          duration: it.duration, price: it.price,
        })),
        addons: addonList.map(a => ({ id: a.id, name: a.name, price: a.price })),
      },
      totals,
    };

    try {
      const res = await fetch("/api/checkout", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      // Read once as text so we can show real diagnostics on a non-JSON 5xx body.
      const raw = await res.text();
      let json = {};
      try { json = raw ? JSON.parse(raw) : {}; } catch { /* non-JSON */ }
      if (!res.ok || !json.ok) {
        const detail = json.error || (raw && !json.error ? raw.slice(0, 140) : null);
        throw new Error(
          detail
            ? `${detail} (status ${res.status})`
            : `Submission failed (status ${res.status}). Please email hi@vestalhub.com directly.`
        );
      }

      // Snapshot for the thank-you page (the cart will be cleared right after).
      try {
        sessionStorage.setItem("vh:lastOrder", JSON.stringify({
          items: payload.cart.items,
          addons: payload.cart.addons,
          totals,
          buyer,
          calendarUrl: json.calendarUrl,
          at: Date.now(),
        }));
      } catch {}

      onCleared && onCleared();
      goToThankYou();
    } catch (err) {
      // Network failures (offline, DNS, CORS) reach this branch with the bare
      // "Failed to fetch" message — surface it instead of swallowing it.
      const msg = err?.message || "Network error. Please check your connection or email hi@vestalhub.com directly.";
      console.error("[checkout:submit] failed:", err);
      setError(msg);
      setSubmitting(false);
    }
  };

  return (
    <>
      <PageHero
        eyebrow="CHECKOUT · SOW WITHIN 1 BUSINESS DAY"
        title={<>Send your brief. <em>SOW arrives tomorrow.</em></>}
        lead="No charge until you sign. No discovery call required. A senior operator drafts your Statement of Work directly from this brief."
        accent="#3B69FF"
      />
      <section className="page-body">
        <div className="wrap checkout-grid">
          <form className="checkout-form" onSubmit={submit}>
            <div className="checkout-block">
              <span className="page-section-eye">01 · YOU</span>
              <div className="checkout-row">
                <label>
                  <span>Full name *</span>
                  <input type="text" required value={buyer.name}
                         onChange={e => setBuyer({...buyer, name: e.target.value})}
                         placeholder="Jane Doe"/>
                </label>
                <label>
                  <span>Work email *</span>
                  <input type="email" required value={buyer.email}
                         onChange={e => setBuyer({...buyer, email: e.target.value})}
                         placeholder="jane@acme.com"/>
                </label>
              </div>
              <label>
                <span>Your role</span>
                <input type="text" value={buyer.role}
                       onChange={e => setBuyer({...buyer, role: e.target.value})}
                       placeholder="Head of RevOps"/>
              </label>
            </div>

            <div className="checkout-block">
              <span className="page-section-eye">02 · COMPANY</span>
              <div className="checkout-row">
                <label>
                  <span>Legal company name *</span>
                  <input type="text" required value={company.legalName}
                         onChange={e => setCompany({...company, legalName: e.target.value})}
                         placeholder="Acme Inc."/>
                </label>
                <label>
                  <span>Website</span>
                  <input type="url" value={company.website}
                         onChange={e => setCompany({...company, website: e.target.value})}
                         placeholder="https://acme.com"/>
                </label>
              </div>
              <div className="checkout-row">
                <label>
                  <span>Country</span>
                  <select value={company.country}
                          onChange={e => setCompany({...company, country: e.target.value})}>
                    {COUNTRIES.map(c => <option key={c} value={c}>{c}</option>)}
                  </select>
                </label>
                <label>
                  <span>Team size</span>
                  <select value={company.size}
                          onChange={e => setCompany({...company, size: e.target.value})}>
                    {TEAM_SIZES.map(s => <option key={s} value={s}>{s}</option>)}
                  </select>
                </label>
              </div>
            </div>

            <div className="checkout-block">
              <span className="page-section-eye">03 · ENGAGEMENT</span>
              <div className="checkout-row">
                <label>
                  <span>Preferred kickoff</span>
                  <select value={engagement.kickoff}
                          onChange={e => setEngagement({...engagement, kickoff: e.target.value})}>
                    {KICKOFF_WINDOWS.map(k => <option key={k} value={k}>{k}</option>)}
                  </select>
                </label>
                <label>
                  <span>Primary channel</span>
                  <select value={engagement.channel}
                          onChange={e => setEngagement({...engagement, channel: e.target.value})}>
                    <option value="Slack">Slack (we open a shared channel)</option>
                    <option value="Email">Email only</option>
                    <option value="Teams">Microsoft Teams</option>
                  </select>
                </label>
              </div>
              <label>
                <span>Anything we should know? <em className="opt">(optional, but useful)</em></span>
                <textarea rows={5} value={engagement.brief}
                          onChange={e => setEngagement({...engagement, brief: e.target.value})}
                          placeholder="Current HubSpot tier, integrated tools, hard deadlines, anything that could affect scope. The more specific, the tighter the SOW."/>
              </label>
            </div>

            {error && <div className="checkout-err">{error}</div>}

            <button type="submit" className="btn btn-primary checkout-submit" disabled={submitting}>
              {submitting ? "Sending brief…" : <>Send brief — SOW arrives within 1 business day <Icon name="arrow" size={14}/></>}
            </button>

            <div className="checkout-trust">
              <span><Icon name="shield" size={12}/> Fixed price</span>
              <span><Icon name="check"  size={12}/> No charge until SOW signed</span>
              <span><Icon name="zap"    size={12}/> Senior operator only</span>
            </div>
          </form>

          <aside className="checkout-summary">
            <span className="page-section-eye">YOUR ORDER</span>
            <div className="checkout-summary-card">
              {items.map(it => (
                <div className="cs-line" key={it._uid || it.id}>
                  <div className="cs-line-name">
                    <b>{it.name}</b>
                    <span>{it.category}{it.duration ? " · " + it.duration : ""}</span>
                  </div>
                  <div className="cs-line-p">
                    ${it.price.toLocaleString()}{it.duration === "monthly" ? <em>/mo</em> : null}
                  </div>
                </div>
              ))}
              {addonList.map(a => (
                <div className="cs-line cs-addon" key={a.id}>
                  <div className="cs-line-name">
                    <b>+ {a.name}</b>
                    <span>Add-on</span>
                  </div>
                  <div className="cs-line-p">+${a.price.toLocaleString()}</div>
                </div>
              ))}
              <div className="cs-totals">
                <div className="r"><span>Subtotal</span><span>${totals.subtotal.toLocaleString()}</span></div>
                {totals.addons > 0   && <div className="r"><span>Add-ons</span><span>+${totals.addons.toLocaleString()}</span></div>}
                {totals.discount > 0 && <div className="r save"><span>Multi-service discount</span><span>−${totals.discount.toLocaleString()}</span></div>}
                <div className="r t"><span>Total</span><span>${totals.total.toLocaleString()}</span></div>
              </div>
            </div>

            <div className="checkout-help">
              <b>Need to change something?</b>
              <p>Edit your cart from any page using the bag icon, or <a href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>email a custom brief</a> if your work doesn't fit a published SKU.</p>
            </div>
          </aside>
        </div>
      </section>
    </>
  );
};

/* ============ Thank you ============ */
const ThankYouPage = () => {
  const [snapshot, setSnapshot] = useState(null);
  useEffect(() => {
    try {
      const raw = sessionStorage.getItem("vh:lastOrder");
      if (raw) setSnapshot(JSON.parse(raw));
    } catch {}
  }, []);

  const calendarUrl =
    snapshot?.calendarUrl ||
    "https://grow.vestalhub.com/meetings/vestalhub/hubspot-call";

  return (
    <>
      <PageHero
        eyebrow="BRIEF RECEIVED"
        title={<>Your SOW arrives <em>within one business day.</em></>}
        lead={snapshot?.buyer?.email
          ? `We'll email it to ${snapshot.buyer.email}. Nothing has been charged. Signing the SOW kicks off the engagement.`
          : "We'll email it to you shortly. Nothing has been charged. Signing the SOW kicks off the engagement."}
        accent="#3B69FF"
      />
      <section className="page-body">
        <div className="wrap thankyou-grid">
          <div className="thankyou-main">
            <div className="thankyou-card">
              <span className="page-section-eye">WHAT HAPPENS NEXT</span>
              <ol className="thankyou-steps">
                <li>
                  <span className="ts-n">01</span>
                  <div>
                    <b>We draft your SOW</b>
                    <p>A senior operator pulls scope, deliverables, and timeline from the catalog and tailors them to your brief. No templates copy-pasted at you.</p>
                  </div>
                </li>
                <li>
                  <span className="ts-n">02</span>
                  <div>
                    <b>You receive it for signature</b>
                    <p>Usually by end of next business day. Reply with edits or sign as-is — there's no obligation either way.</p>
                  </div>
                </li>
                <li>
                  <span className="ts-n">03</span>
                  <div>
                    <b>Kickoff within 24h of signing</b>
                    <p>Slack channel opened, calendar invites sent, work begins. First milestone usually lands within a week.</p>
                  </div>
                </li>
              </ol>
            </div>

            <div className="thankyou-card thankyou-cal">
              <div>
                <span className="page-section-eye">OPTIONAL · 20 MIN</span>
                <h3>Want to talk before the SOW arrives?</h3>
                <p>Some teams want to compare options or sanity-check scope before signing. Grab time with a senior operator — no sales script.</p>
              </div>
              <a className="btn btn-primary" href={calendarUrl} target="_blank" rel="noopener noreferrer">
                Book 20 min <Icon name="arrow" size={14}/>
              </a>
            </div>
          </div>

          <aside className="thankyou-side">
            {snapshot ? (
              <div className="thankyou-card">
                <span className="page-section-eye">YOUR ORDER</span>
                <div className="thankyou-recap">
                  {snapshot.items.map(it => (
                    <div className="cs-line" key={it.id + (it.name || "")}>
                      <div className="cs-line-name">
                        <b>{it.name}</b>
                        <span>{it.category}{it.duration ? " · " + it.duration : ""}</span>
                      </div>
                      <div className="cs-line-p">${it.price.toLocaleString()}{it.duration === "monthly" ? <em>/mo</em> : null}</div>
                    </div>
                  ))}
                  {(snapshot.addons || []).map(a => (
                    <div className="cs-line cs-addon" key={a.id}>
                      <div className="cs-line-name"><b>+ {a.name}</b><span>Add-on</span></div>
                      <div className="cs-line-p">+${a.price.toLocaleString()}</div>
                    </div>
                  ))}
                  <div className="cs-totals">
                    {snapshot.totals.discount > 0 && (
                      <div className="r save"><span>Multi-service discount</span><span>−${snapshot.totals.discount.toLocaleString()}</span></div>
                    )}
                    <div className="r t"><span>Total</span><span>${snapshot.totals.total.toLocaleString()}</span></div>
                  </div>
                </div>
                <p className="thankyou-fwd">Forward this to a stakeholder if you need approval — the SOW will arrive at <b>{snapshot.buyer?.email}</b>.</p>
              </div>
            ) : (
              <div className="thankyou-card">
                <span className="page-section-eye">WE'RE ON IT</span>
                <p>If you don't see a confirmation email within a few minutes, check spam or email <a href="mailto:hi@vestalhub.com">hi@vestalhub.com</a> directly.</p>
              </div>
            )}

            <div className="thankyou-card thankyou-card-alt">
              <span className="page-section-eye">WHILE YOU WAIT</span>
              <a href="/process" onClick={(e) => { e.preventDefault(); goToProcess(); }} className="contact-quick">
                <span><b>How we work</b><em>The 4-stage delivery model behind every SOW</em></span>
                <Icon name="arrow" size={16}/>
              </a>
              <a href="/about" onClick={(e) => { e.preventDefault(); goToAbout(); }} className="contact-quick">
                <span><b>Who you'll work with</b><em>Senior operators only — no juniors, no rotations</em></span>
                <Icon name="arrow" size={16}/>
              </a>
            </div>
          </aside>
        </div>
      </section>
    </>
  );
};

/* ============ Not found (404) ============ */
const NotFoundPage = ({ path }) => (
  <>
    <PageHero
      eyebrow="404 · PAGE NOT FOUND"
      title={<>This page <em>doesn't exist.</em></>}
      lead={path
        ? `Nothing lives at ${path}. It may have moved, or the link may be wrong.`
        : "It may have moved, or the link may be wrong."}
      accent="#3B69FF"
    />
    <section className="page-body">
      <div className="wrap" style={{maxWidth: 720, textAlign: "center", padding: "8px 0 40px"}}>
        <p style={{color: "var(--muted)", fontSize: "var(--fs-xl)", lineHeight: 1.55, marginBottom: 28}}>
          Try one of these instead — or email <a href="mailto:hi@vestalhub.com" style={{color: "var(--brand)", textDecoration: "none"}}>hi@vestalhub.com</a> if you can't find what you're looking for.
        </p>
        <div style={{display: "flex", flexWrap: "wrap", gap: 12, justifyContent: "center", marginBottom: 32}}>
          <a className="btn btn-primary"  href="/shop"    onClick={(e) => { e.preventDefault(); goToShop();    }}>Browse all services <Icon name="arrow" size={14}/></a>
          <a className="btn btn-secondary" href="/contact" onClick={(e) => { e.preventDefault(); goToContact(); }}>Contact us</a>
          <a className="btn btn-secondary" href="/"        onClick={(e) => { e.preventDefault(); goHome();      }}>Back to home</a>
        </div>
      </div>
    </section>
  </>
);

/* ============ Cart math (shared between drawer + checkout) ============ */
const cartMath = (items, addons) => {
  const sub = items.reduce((s, i) => s + i.price, 0);
  const add = Object.keys(addons || {})
    .filter(k => addons[k])
    .reduce((s, k) => s + (ADDONS.find(x => x.id === k)?.price || 0), 0);
  const bundleSaving = items.length >= 3 ? Math.round(sub * 0.1) : 0;
  const total = sub + add - bundleSaving;
  return { subtotal: sub, addons: add, discount: bundleSaving, total };
};

/* ============ Cart drawer ============ */
const Cart = ({ open, items, addons, onClose, onRem, onTog, onCheckout }) => {
  const { subtotal: sub, addons: add, discount: bundleSaving, total } = cartMath(items, addons);
  return (
    <>
      <div className={`scrim ${open ? "on" : ""}`} onClick={onClose}/>
      <aside className={`drawer ${open ? "on" : ""}`}>
        <div className="dr-head">
          <h3>Your cart <span style={{color:"var(--muted)", fontWeight:400, fontSize:"var(--fs-base)"}}>({items.length})</span></h3>
          <button className="icon-btn" onClick={onClose}><Icon name="close"/></button>
        </div>
        <div className="dr-body">
          {items.length === 0 ? (
            <div className="empty">
              <div className="ic"><Icon name="bag" size={24}/></div>
              <div className="big">Your cart is empty</div>
              <p>Browse services to start building your order</p>
            </div>
          ) : (<>
            {items.map(it => (
              <div className="ci" key={it._uid}>
                <div className="ci-vis">{it.num}</div>
                <div>
                  <h4>{it.name}</h4>
                  <div className="s">{it.category} · {it.duration}</div>
                  <div className="r">
                    <div className="p">${it.price.toLocaleString()}{it.duration === "monthly" ? "/mo" : ""}</div>
                    <button className="rm" onClick={() => onRem(it._uid)}>Remove</button>
                  </div>
                </div>
              </div>
            ))}
            <div className="addons">
              <h5>Add to your order</h5>
              {ADDONS.map(a => (
                <div key={a.id} className={`addon ${addons[a.id] ? "on" : ""}`} onClick={() => onTog(a.id)}>
                  <div className="addon-chk"><Icon name="check" size={12}/></div>
                  <div className="addon-n">{a.name}<div className="d">{a.sub}</div></div>
                  <div className="addon-p">+${a.price}</div>
                </div>
              ))}
            </div>
          </>)}
        </div>
        {items.length > 0 && (
          <div className="dr-foot">
            <div className="tot">
              <div className="r"><span>Subtotal</span><span>${sub.toLocaleString()}</span></div>
              {add > 0 && <div className="r"><span>Add-ons</span><span>+${add.toLocaleString()}</span></div>}
              {bundleSaving > 0 && <div className="r save"><span>Multi-service discount</span><span>−${bundleSaving.toLocaleString()}</span></div>}
              <div className="r t"><span>Total</span><span>${total.toLocaleString()}</span></div>
            </div>
            <button
              className="btn btn-primary checkout"
              onClick={() => { onCheckout && onCheckout(); }}
            >Checkout → SOW in 24h <Icon name="arrow" size={14}/></button>
            <div className="trust-mini">
              <span className="i"><Icon name="shield" size={12}/> Fixed price</span>
              <span className="i"><Icon name="check" size={12}/> No charge until SOW signed</span>
            </div>
          </div>
        )}
      </aside>
    </>
  );
};

/* ============ Tweaks ============ */
const Tweaks = ({ visible, state, onChange }) => {
  if (!visible) return null;
  const accents = [
    { id: "orange",  c: "#FF3B00" },
    { id: "blue",    c: "#0042FF" },
    { id: "ink",     c: "#0A0A0A" },
    { id: "green",   c: "#0E8A4F" },
    { id: "purple",  c: "#7C3AED" },
  ];
  const heroes = [{id:"serif",n:"Italic serif"},{id:"solid",n:"Solid block"},{id:"plain",n:"Plain"}];
  return (
    <div className="tweaks on">
      <h4>Tweaks</h4>
      <div>
        <div className="tw-l">Accent color</div>
        <div className="tw-chips">
          {accents.map(b => (
            <button key={b.id} className={`tw-chip ${state.accent === b.id ? "on" : ""}`} onClick={() => onChange({accent:b.id})}>
              <span style={{display:"inline-block", width:9, height:9, background:b.c, borderRadius:2, marginRight:6, verticalAlign:"middle"}}/>
              {b.id}
            </button>
          ))}
        </div>
      </div>
      <div>
        <div className="tw-l">Hero headline</div>
        <div className="tw-chips">
          {heroes.map(r => (
            <button key={r.id} className={`tw-chip ${state.hero === r.id ? "on" : ""}`} onClick={() => onChange({hero:r.id})}>{r.n}</button>
          ))}
        </div>
      </div>
    </div>
  );
};

/* ============ App ============ */
const App = () => {
  const [cart, setCart]     = useState([]);
  const [open, setOpen]     = useState(false);
  const [addons, setAddons] = useState({});
  const [state, setState]   = useState(window.__TWEAKS_V4__ || {accent:"vestal", hero:"gradient"});
  const [editOn, setEditOn] = useState(false);

  useEffect(() => {
    const ssrEl = document.getElementById("ssr-product");
    if (ssrEl) ssrEl.remove();
  }, []);

  useEffect(() => {
    const root = document.documentElement;
    const m = {
      vestal: ["#3B69FF", "#5C84FF", "rgba(59,105,255,0.14)"],
      blue:   ["#3B69FF", "#5C84FF", "rgba(59,105,255,0.14)"],
      cyan:   ["#22D3EE", "#67E8F9", "rgba(34,211,238,0.14)"],
      orange: ["#FF7A29", "#FF9A5C", "rgba(255,122,41,0.14)"],
      purple: ["#7C5CFC", "#9C82FF", "rgba(124,92,252,0.14)"],
      green:  ["#22C55E", "#4ADE80", "rgba(34,197,94,0.14)"],
      pink:   ["#F472B6", "#F9A8D4", "rgba(244,114,182,0.14)"],
      ink:    ["#F4F6FB", "#FFFFFF", "rgba(255,255,255,0.10)"],
    };
    const [b, bi, bs] = m[state.accent] || m.vestal;
    root.style.setProperty("--brand", b);
    root.style.setProperty("--brand-ink", bi);
    root.style.setProperty("--brand-soft", bs);
    document.querySelectorAll(".hero h1 .hl").forEach(el => {
      el.style.cssText = "";
    });
  }, [state]);

  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === "__activate_edit_mode")   setEditOn(true);
      if (d.type === "__deactivate_edit_mode") setEditOn(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  const update = (patch) => {
    const next = {...state, ...patch};
    setState(next);
    window.parent.postMessage({ type: "__edit_mode_set_keys", edits: patch }, "*");
  };

  const add = (p) => { setCart(c => [...c, {...p, _uid: p._uid || `${p.id}-${Date.now()}`}]); setOpen(true); };
  const rem = (uid) => setCart(c => c.filter(i => i._uid !== uid));
  const tog = (id)  => setAddons(a => ({...a, [id]: !a[id]}));

  const route = useRoute();
  useDocumentMeta(route);

  return (
    <div data-screen-label="Vestal Hub">
      <Header count={cart.length} onCart={() => setOpen(true)}/>
      {route.name === "product" ? (
        <ProductPage id={route.id} onAdd={add} />
      ) : route.name === "category" ? (
        <CategoryPage id={route.id} onAdd={add} />
      ) : route.name === "shop" ? (
        <ShopPage key={route.q || ""} onAdd={add} initialCat={route.cat} initialSort={route.sort} initialQ={route.q} />
      ) : route.name === "custom" ? (
        <CustomPage onAdd={add} />
      ) : route.name === "checkout" ? (
        <CheckoutPage
          items={cart}
          addons={addons}
          onCleared={() => { setCart([]); setAddons({}); setOpen(false); }}
        />
      ) : route.name === "thankyou" ? (
        <ThankYouPage />
      ) : route.name === "contact" ? (
        <ContactPage />
      ) : route.name === "book" ? (
        <BookingPage />
      ) : route.name === "about" ? (
        <AboutPage />
      ) : route.name === "process" ? (
        <ProcessPage />
      ) : route.name === "partners" ? (
        <PartnersPage />
      ) : route.name === "careers" ? (
        <CareersPage />
      ) : route.name === "terms" ? (
        <LegalPage kind="terms" />
      ) : route.name === "privacy" ? (
        <LegalPage kind="privacy" />
      ) : route.name === "cookies" ? (
        <LegalPage kind="cookies" />
      ) : route.name === "notfound" ? (
        <NotFoundPage path={route.path} />
      ) : (
        <>
      <Hero />
      <Logos />
      <Shop onAdd={add} />
      <HowItWorks />
      <Features />
      <Reviews />
      {/* <Bundles onAdd={add} /> */}
      <Stats />
      <Faq />
      <Cta />
        </>
      )}
      <Footer />
      <Cart
        open={open}
        items={cart}
        addons={addons}
        onClose={() => setOpen(false)}
        onRem={rem}
        onTog={tog}
        onCheckout={() => { setOpen(false); goToCheckout(); }}
      />
      <Tweaks visible={editOn} state={state} onChange={update}/>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
