// Shared primitives: Modal, Logo, Eyebrow, Button, validators
const { useState, useEffect, useRef, useCallback, useMemo } = React;

const PALETTE = {
  navy: "#0A1929",
  navy800: "#0F2238",
  navy700: "#1B2B4D",
  rule: "#E4E2DA",
  rule2: "#D4D2C9",
  ruleInverse: "#1F3658",
  paper: "#FAF9F5",
  paper2: "#F5F5F0",
  white: "#FFFFFF",
  ink: "#2C2C2C",
  mute1: "#5A5A53",
  mute2: "#8B8B83",
  mute3: "#B8B6AC",
  amber: "#D98300",
  amberHover: "#B86F00",
  amber500: "#FFA000",
  amber100: "#FFF1D6",
  blue: "#005FCC",
  blue700: "#003F99",
  blue100: "#E6EEFF",
  green: "#1F7A3D",
  red: "#A8261C",
};

function Logo({ inverse = false, size = 22 }) {
  const fg = inverse ? PALETTE.paper : PALETTE.navy;
  const sub = inverse ? "rgba(250,249,245,.55)" : PALETTE.mute1;
  return (
    <a href="/" style={{ display: "flex", alignItems: "baseline", textDecoration: "none", color: fg, gap: 0 }} aria-label="VS·Trade Intelligence">
      <span style={{ fontFamily: "'Source Serif 4', serif", fontSize: size, fontWeight: 600, letterSpacing: "-.012em", color: fg }}>VS</span>
      <span style={{ width: 4, height: 4, background: PALETTE.amber500, borderRadius: 999, margin: "0 6px", alignSelf: "center", display: "inline-block" }}></span>
      <span style={{ fontFamily: "'Source Serif 4', serif", fontSize: size, fontWeight: 600, letterSpacing: "-.012em", color: fg }}>Trade</span>
      <span style={{ fontFamily: "Inter, sans-serif", fontSize: 10, fontWeight: 600, letterSpacing: ".14em", color: sub, marginLeft: 12 }}>INTELLIGENCE</span>
    </a>
  );
}

function Eyebrow({ children, color, style }) {
  return (
    <div style={{
      fontFamily: "Inter, sans-serif",
      fontSize: 11,
      fontWeight: 600,
      letterSpacing: ".14em",
      textTransform: "uppercase",
      color: color || PALETTE.mute1,
      lineHeight: 1,
      ...style,
    }}>{children}</div>
  );
}

function PrimaryButton({ children, onClick, type = "button", style, ariaLabel }) {
  return (
    <button
      type={type}
      onClick={onClick}
      aria-label={ariaLabel}
      className="vst-btn-primary"
      style={{
        background: PALETTE.amber,
        color: PALETTE.paper,
        border: 0,
        borderRadius: 4,
        padding: "12px 22px",
        fontFamily: "Inter, sans-serif",
        fontSize: 15,
        fontWeight: 600,
        cursor: "pointer",
        letterSpacing: ".005em",
        ...style,
      }}
    >{children}</button>
  );
}

function GhostButton({ children, onClick, inverse = false, style }) {
  return (
    <button
      onClick={onClick}
      className="vst-btn-ghost"
      style={{
        background: "transparent",
        color: inverse ? PALETTE.paper : PALETTE.navy,
        border: `1px solid ${inverse ? "rgba(250,249,245,.25)" : PALETTE.rule2}`,
        borderRadius: 4,
        padding: "11px 20px",
        fontFamily: "Inter, sans-serif",
        fontSize: 15,
        fontWeight: 600,
        cursor: "pointer",
        ...style,
      }}
    >{children}</button>
  );
}

function isValidEmail(s) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test((s || "").trim());
}

const FREE_EMAIL_DOMAINS = new Set([
  // Free consumer providers
  "gmail.com", "googlemail.com",
  "yahoo.com", "yahoo.co.uk", "ymail.com", "rocketmail.com",
  "hotmail.com", "hotmail.co.uk", "outlook.com", "live.com", "msn.com",
  "aol.com",
  "icloud.com", "me.com", "mac.com",
  "proton.me", "protonmail.com",
  "mail.com", "gmx.com", "gmx.net",
  "yandex.com", "yandex.ru",
  "zoho.com",
  "fastmail.com", "fastmail.fm",
  "tutanota.com", "tuta.io",
  "hey.com", "hushmail.com",
  "qq.com", "163.com", "126.com", "sina.com",
  "naver.com", "rediffmail.com",
  "libero.it", "web.de", "t-online.de",
  "laposte.net", "orange.fr", "free.fr", "wanadoo.fr",
  "btinternet.com", "ntlworld.com",
  // Disposable / temp mail
  "mailinator.com", "guerrillamail.com", "10minutemail.com",
  "tempmail.com", "throwaway.email", "sharklasers.com",
  "yopmail.com", "maildrop.cc", "mintemail.com",
  "fakemailgenerator.com", "trashmail.com",
  "getairmail.com", "dispostable.com",
]);

function isWorkEmail(email) {
  const at = (email || "").toLowerCase().trim().lastIndexOf("@");
  if (at < 0) return false;
  const domain = (email || "").toLowerCase().trim().slice(at + 1);
  if (!domain) return false;
  return !FREE_EMAIL_DOMAINS.has(domain);
}

// UTM reader. Returns an object so GTM dataLayer pushes have one key per field.
function readUtmObject() {
  const out = {
    utm_source: null, utm_medium: null, utm_campaign: null,
    utm_term: null, utm_content: null,
    gclid: null, fbclid: null, li_fat_id: null,
  };
  try {
    const qs = new URLSearchParams(window.location.search);
    for (const k of Object.keys(out)) {
      const v = qs.get(k);
      if (v) out[k] = v.slice(0, 80);
    }
  } catch (_) {}
  return out;
}

// Serialize UTMs + referrer into the worker `utm_payload` field
// (utm_source=…|utm_campaign=…|gclid=…|ref=…). Kept separate from the
// user-facing `interest` field. Capped to the worker schema limit (600).
function serializeUtmPayload() {
  try {
    const obj = readUtmObject();
    const parts = [];
    for (const [k, v] of Object.entries(obj)) {
      if (v) parts.push(`${k}=${v}`);
    }
    const referrer = (document.referrer || "").slice(0, 120);
    if (referrer) parts.push(`ref=${referrer}`);
    return parts.join("|").slice(0, 580);
  } catch (_) {
    return "";
  }
}

// GTM dataLayer push for CaptureModal success. Runs only after the worker
// confirms 2xx, before showing the thank-you state. Never blocks UX on error.
function pushCaptureSuccess({ mode, context }) {
  const id = (context && context.id) || "";
  const productCode = (id.match(/R00[1-9]/) || [])[0] || null;
  let event = null, source = null, product = null;

  if (mode === "download") {
    event = "lm3_download";
    source = "home_lm3";
    product = "LM3";
  } else if (mode === "waitlist") {
    event = "waitlist_signup";
    product = productCode || (id || null);
    source = `home_waitlist_${(productCode || id || "unknown").toLowerCase().replace(/\s+/g, "_")}`;
  } else if (mode === "inquire") {
    if (id.startsWith("R003")) {
      event = "r003_inquiry";
      source = "home_r003_inquiry";
      product = "R003";
    } else {
      event = "product_inquiry";
      product = productCode || (id || null);
      source = `home_${(id || "inquiry").toLowerCase().replace(/\s+/g, "_")}_inquiry`;
    }
  } else {
    return;
  }

  try {
    const utm = readUtmObject();
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event, source, product,
      utm_source: utm.utm_source,
      utm_medium: utm.utm_medium,
      utm_campaign: utm.utm_campaign,
      utm_content: utm.utm_content,
      utm_term: utm.utm_term,
      gclid: utm.gclid,
      lang: "en",
    });
  } catch (_) { /* GTM optional; never block UX */ }
}

// Universal modal — handles download (LM3), waitlist, inquire flows
function CaptureModal({ open, onClose, mode, context }) {
  // mode: 'download' | 'waitlist' | 'inquire'
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [firm, setFirm] = useState("");
  const [role, setRole] = useState("");
  const [interest, setInterest] = useState("");
  const [message, setMessage] = useState("");
  const [submitted, setSubmitted] = useState(false);
  const [touched, setTouched] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const closeBtnRef = useRef(null);

  useEffect(() => {
    if (open) {
      setSubmitted(false);
      setTouched(false);
      setLoading(false);
      setError(null);
      // focus close on open
      setTimeout(() => closeBtnRef.current && closeBtnRef.current.focus(), 50);
      const onKey = (e) => { if (e.key === "Escape") onClose(); };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }
  }, [open, onClose]);

  // All hooks must run unconditionally before any early return.
  const allRequiredFilled = useMemo(() => {
    const emailOk = isValidEmail(email);
    if (mode === "download") return emailOk;
    if (mode === "waitlist") {
      return emailOk && name.trim() && firm.trim() && role && interest.trim();
    }
    if (mode === "inquire") {
      return emailOk && name.trim() && firm.trim() && role && message.trim();
    }
    return emailOk;
  }, [mode, email, name, firm, role, interest, message]);

  if (!open) return null;

  const titleByMode = {
    download: "Download LM3 Public Snapshot",
    waitlist: `Join the waitlist · ${context?.id || ""}`,
    inquire: `Inquire about ${context?.title || "this report"}`,
  };
  const subByMode = {
    download: "18 pages · LFPDPPP 2025 compliant · IMMEX verified (snapshot March 2026). Delivered to your inbox immediately, no follow-up sales sequence.",
    waitlist: context?.note || "We'll email you when this report enters production. No marketing list — only release notifications and methodology updates.",
    inquire: context?.note || "A founder-led reply within one business day. We'll confirm scope, coverage, and SLA before any commitment.",
  };
  const ctaByMode = {
    download: "Email me the PDF",
    waitlist: "Add me to the waitlist",
    inquire: "Send inquiry",
  };

  const valid = isValidEmail(email);

  async function handleSubmit(e) {
    e.preventDefault();
    setTouched(true);
    setError(null);

    if (!isValidEmail(email)) {
      setError("Please enter a valid email address.");
      return;
    }
    if (!isWorkEmail(email)) {
      setError("Please use your work email. Free email providers (gmail, yahoo, etc.) are not accepted.");
      return;
    }
    if (!allRequiredFilled) {
      setError("Please complete all required fields.");
      return;
    }

    setLoading(true);

    const sourceLabel =
      mode === "download" ? "modal_download_lm3" :
      mode === "waitlist" ? `modal_waitlist_${context?.id || "unknown"}` :
      "modal_inquire";

    try {
      const response = await fetch(
        "https://leads.vstrade.co/subscribe",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            email: email.toLowerCase().trim(),
            source: sourceLabel,
            name: name?.trim() || undefined,
            firm: firm?.trim() || undefined,
            role: role || undefined,
            interest: interest?.trim() || undefined,
            message: message?.trim() || undefined,
            utm_payload: serializeUtmPayload() || undefined,
            context_id: context?.id || undefined,
          }),
        }
      );

      let data = {};
      try { data = await response.json(); } catch (_) {}

      if (response.status === 201 || (response.status === 200 && data.already_subscribed)) {
        pushCaptureSuccess({ mode, context });
        setSubmitted(true);
      } else if (response.status === 200) {
        pushCaptureSuccess({ mode, context });
        setSubmitted(true);
      } else if (response.status === 400) {
        setError(data.error || "Invalid input. Please check and try again.");
      } else if (response.status === 429) {
        setError("Too many requests. Please try again in a minute.");
      } else {
        setError("Something went wrong. Please try again.");
      }
    } catch (err) {
      setError("Network error. Please check your connection and try again.");
    } finally {
      setLoading(false);
    }
  }

  return (
    <div
      role="dialog"
      aria-modal="true"
      aria-labelledby="vst-modal-title"
      style={{
        position: "fixed", inset: 0, zIndex: 100,
        background: "rgba(10,25,41,.62)", backdropFilter: "blur(2px)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 24, animation: "vst-fade-in 180ms cubic-bezier(.2,0,.2,1)",
      }}
      onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
    >
      <div style={{
        background: PALETTE.paper, color: PALETTE.navy,
        borderRadius: 6, maxWidth: 520, width: "100%",
        boxShadow: "0 4px 16px rgba(10,25,41,.10), 0 1px 0 rgba(10,25,41,.04)",
        border: `1px solid ${PALETTE.rule}`,
        animation: "vst-pop-in 220ms cubic-bezier(.2,0,.2,1)",
        maxHeight: "calc(100vh - 48px)", overflowY: "auto",
      }}>
        {/* Header */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", padding: "22px 24px 0" }}>
          <div>
            <div style={{ fontFamily: "JetBrains Mono, monospace", fontSize: 11, color: PALETTE.mute2, letterSpacing: ".04em" }}>
              {mode === "download" ? "LM3 · PUBLIC SNAPSHOT" : mode === "waitlist" ? "WAITLIST" : "INQUIRY"}
            </div>
          </div>
          <button
            ref={closeBtnRef}
            onClick={onClose}
            aria-label="Close"
            style={{ background: "transparent", border: 0, padding: 4, cursor: "pointer", color: PALETTE.mute1, lineHeight: 0 }}
          >
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6L6 18M6 6l12 12"/></svg>
          </button>
        </div>

        <div style={{ padding: "10px 24px 8px" }}>
          <h3 id="vst-modal-title" style={{
            fontFamily: "'Source Serif 4', serif", fontSize: 24, fontWeight: 600,
            lineHeight: 1.25, letterSpacing: "-.012em", color: PALETTE.navy, margin: "0 0 8px",
          }}>{titleByMode[mode]}</h3>
          <p style={{ fontFamily: "Inter, sans-serif", fontSize: 14, lineHeight: 1.6, color: PALETTE.mute1, margin: 0 }}>
            {subByMode[mode]}
          </p>
        </div>

        {!submitted ? (
          <form onSubmit={handleSubmit} style={{ padding: "16px 24px 24px" }}>
            <FormField label="Work email" required>
              <input
                type="email"
                value={email}
                onChange={(e) => { setEmail(e.target.value); if (error) setError(null); }}
                onBlur={() => setTouched(true)}
                placeholder="analyst@firm.com"
                autoFocus
                disabled={loading}
                style={{ ...fieldInput(!!error || (touched && !valid)), opacity: loading ? 0.7 : 1 }}
              />
              {error && (
                <div style={{
                  fontFamily: "Inter, sans-serif", fontSize: 12, color: PALETTE.red,
                  marginTop: 8, lineHeight: 1.5, wordBreak: "break-word",
                }}>
                  {error}
                </div>
              )}
            </FormField>

            {mode !== "download" && (
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FormField label="Name" required>
                  <input
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    placeholder="J. Smith"
                    required
                    disabled={loading}
                    style={{ ...fieldInput(touched && !name.trim()), opacity: loading ? 0.7 : 1 }}
                  />
                </FormField>
                <FormField label="Firm" required>
                  <input
                    value={firm}
                    onChange={(e) => setFirm(e.target.value)}
                    placeholder="Lazard, McKinsey…"
                    required
                    disabled={loading}
                    style={{ ...fieldInput(touched && !firm.trim()), opacity: loading ? 0.7 : 1 }}
                  />
                </FormField>
              </div>
            )}

            {mode !== "download" && (
              <FormField label="Role" required>
                <select
                  value={role}
                  onChange={(e) => setRole(e.target.value)}
                  required
                  disabled={loading}
                  style={{ ...fieldInput(touched && !role), opacity: loading ? 0.7 : 1 }}
                >
                  <option value="">Select…</option>
                  <option>Strategy partner — boutique consultancy</option>
                  <option>PE/VC analyst</option>
                  <option>Corporate strategy lead</option>
                  <option>Director of research</option>
                  <option>Other</option>
                </select>
              </FormField>
            )}

            {mode === "waitlist" && (
              <FormField label="Specific interest" required>
                <input
                  value={interest}
                  onChange={(e) => setInterest(e.target.value)}
                  placeholder="e.g. accelerator-level breakdown, Q4 cross-border flows…"
                  required
                  disabled={loading}
                  style={{ ...fieldInput(touched && !interest.trim()), opacity: loading ? 0.7 : 1 }}
                />
              </FormField>
            )}

            {mode === "inquire" && (
              <FormField label="What scope are you considering?" required>
                <textarea
                  value={message}
                  onChange={(e) => setMessage(e.target.value)}
                  placeholder="Coverage period, named entities of interest, deadline…"
                  rows={3}
                  required
                  disabled={loading}
                  style={{ ...fieldInput(touched && !message.trim()), resize: "vertical", fontFamily: "Inter, sans-serif", opacity: loading ? 0.7 : 1 }}
                />
              </FormField>
            )}

            {touched && !allRequiredFilled && !error && (
              <div style={{
                marginTop: 12, fontFamily: "Inter, sans-serif",
                fontSize: 12, color: PALETTE.red, lineHeight: 1.5,
              }}>
                Please complete all required fields.
              </div>
            )}

            <div style={{ display: "flex", gap: 12, alignItems: "center", marginTop: 18 }}>
              <PrimaryButton type="submit" style={{ flex: "0 0 auto", opacity: loading ? 0.7 : 1, cursor: loading ? "default" : "pointer" }}>
                {loading ? "Sending…" : <>{ctaByMode[mode]} <span className="vst-link-arrow">→</span></>}
              </PrimaryButton>
              <button type="button" onClick={onClose} disabled={loading} style={{
                background: "transparent", border: 0, padding: "10px 4px", cursor: loading ? "default" : "pointer",
                fontFamily: "Inter, sans-serif", fontSize: 14, fontWeight: 500, color: PALETTE.mute1,
                opacity: loading ? 0.5 : 1,
              }}>Cancel</button>
            </div>

            <div style={{ marginTop: 16, paddingTop: 14, borderTop: `1px solid ${PALETTE.rule}` }}>
              <div style={{ display: "flex", alignItems: "flex-start", gap: 8, fontFamily: "Inter, sans-serif", fontSize: 11.5, color: PALETTE.mute1, lineHeight: 1.55 }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, marginTop: 1 }}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
                <span>We use your email for the requested deliverable and release notifications only. No third-party sharing. <a href="/privacy" target="_blank" rel="noopener" style={{ color: PALETTE.blue }}>Privacy →</a></span>
              </div>
            </div>
          </form>
        ) : (
          <div style={{ padding: "24px 24px 28px" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14 }}>
              <span style={{
                width: 36, height: 36, background: PALETTE.green, color: PALETTE.paper, borderRadius: 999,
                display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
              }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
              </span>
              <div style={{ fontFamily: "'Source Serif 4', serif", fontSize: 22, fontWeight: 600, color: PALETTE.navy, letterSpacing: "-.012em" }}>
                {mode === "download" ? "Check your inbox." : mode === "waitlist" ? "You're on the list." : "Inquiry received."}
              </div>
            </div>
            <p style={{ fontFamily: "Inter, sans-serif", fontSize: 14, lineHeight: 1.65, color: PALETTE.mute1, margin: "0 0 18px" }}>
              {context?.successMessage ? (
                renderWithEmail(context.successMessage, email)
              ) : mode === "download" ? (
                <>The LM3 Public Snapshot has been sent to <span style={{ fontFamily: "JetBrains Mono, monospace", color: PALETTE.navy }}>{email}</span>. If it doesn't arrive within 5 minutes, check spam or write to <a href="mailto:hello@vstrade.co" style={{ color: PALETTE.blue }}>hello@vstrade.co</a>.</>
              ) : mode === "waitlist" ? (
                <>We'll notify <span style={{ fontFamily: "JetBrains Mono, monospace", color: PALETTE.navy }}>{email}</span> when {context?.id} ships. In the meantime, the LM3 Public Snapshot is the closest preview of our methodology.</>
              ) : (
                <>Thanks — we'll be in touch within one business day from <a href="mailto:hello@vstrade.co" style={{ color: PALETTE.blue }}>hello@vstrade.co</a>. Replies are written by Sebastian, the founder; expect specifics on coverage and SLA, not a sales sequence.</>
              )}
            </p>
            <button onClick={onClose} style={{
              background: PALETTE.navy, color: PALETTE.paper, border: 0, borderRadius: 4,
              padding: "10px 20px", fontFamily: "Inter, sans-serif", fontSize: 14, fontWeight: 600, cursor: "pointer",
            }}>Close</button>
          </div>
        )}
      </div>
    </div>
  );
}

// Render a success-message string with {email} replaced by a styled span.
function renderWithEmail(template, email) {
  const parts = String(template).split("{email}");
  return parts.flatMap((part, i) =>
    i < parts.length - 1
      ? [
          part,
          <span key={`em-${i}`} style={{ fontFamily: "JetBrains Mono, monospace", color: PALETTE.navy }}>{email}</span>,
        ]
      : [part]
  );
}

function FormField({ label, required, children }) {
  return (
    <label style={{ display: "block", marginBottom: 12 }}>
      <div style={{
        fontFamily: "Inter, sans-serif", fontSize: 11, fontWeight: 600,
        letterSpacing: ".14em", color: PALETTE.mute1, textTransform: "uppercase",
        marginBottom: 6,
      }}>
        {label}{required ? <span style={{ color: PALETTE.red, marginLeft: 4 }}>*</span> : null}
      </div>
      {children}
    </label>
  );
}

function fieldInput(error) {
  return {
    width: "100%",
    border: `1px solid ${error ? PALETTE.red : PALETTE.rule2}`,
    borderRadius: 4,
    padding: "10px 12px",
    fontFamily: "Inter, sans-serif",
    fontSize: 14,
    color: PALETTE.navy,
    background: PALETTE.white,
    outline: "none",
    transition: "border-color 120ms",
  };
}

// Hairline subtle chart-line background SVG for hero
function HeroChartPattern() {
  return (
    <svg
      aria-hidden="true"
      width="100%" height="100%"
      viewBox="0 0 1440 700"
      preserveAspectRatio="xMidYMid slice"
      style={{ position: "absolute", inset: 0, opacity: 0.5 }}
    >
      <defs>
        <pattern id="vst-grid" width="80" height="80" patternUnits="userSpaceOnUse">
          <path d="M 80 0 L 0 0 0 80" fill="none" stroke="#1F3658" strokeWidth="0.6"/>
        </pattern>
        <pattern id="vst-grid-fine" width="20" height="20" patternUnits="userSpaceOnUse">
          <path d="M 20 0 L 0 0 0 20" fill="none" stroke="#15294A" strokeWidth="0.4"/>
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#vst-grid-fine)"/>
      <rect width="100%" height="100%" fill="url(#vst-grid)"/>

      {/* axis labels */}
      <g fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#3A557F" letterSpacing="0.04em">
        <text x="40" y="80">$400B</text>
        <text x="40" y="240">$300B</text>
        <text x="40" y="400">$200B</text>
        <text x="40" y="560">$100B</text>
        <text x="180" y="640">2024 Q1</text>
        <text x="430" y="640">2024 Q3</text>
        <text x="680" y="640">2025 Q1</text>
        <text x="930" y="640">2025 Q3</text>
        <text x="1180" y="640">2026 Q1</text>
      </g>

      {/* growth area */}
      <path
        d="M 120 540 L 280 510 L 440 470 L 600 410 L 760 320 L 920 230 L 1080 180 L 1240 140 L 1360 110 L 1360 600 L 120 600 Z"
        fill="#0B5FFF" fillOpacity="0.06"
      />
      {/* main line */}
      <path
        d="M 120 540 L 280 510 L 440 470 L 600 410 L 760 320 L 920 230 L 1080 180 L 1240 140 L 1360 110"
        fill="none" stroke="#0B5FFF" strokeWidth="1.6" strokeOpacity="0.85"
      />
      {/* secondary line (declared) */}
      <path
        d="M 120 560 L 280 540 L 440 510 L 600 470 L 760 400 L 920 320 L 1080 280 L 1240 250 L 1360 230"
        fill="none" stroke="#FFA000" strokeWidth="1.2" strokeDasharray="3 3" strokeOpacity="0.7"
      />
      {/* data points */}
      <g fill="#0B5FFF">
        <circle cx="280" cy="510" r="2"/>
        <circle cx="440" cy="470" r="2"/>
        <circle cx="600" cy="410" r="2"/>
        <circle cx="760" cy="320" r="2"/>
        <circle cx="920" cy="230" r="2"/>
        <circle cx="1080" cy="180" r="2"/>
        <circle cx="1240" cy="140" r="2.5" stroke="#FFA000" strokeWidth="1.5" fill="#0A1929"/>
      </g>
      {/* annotation */}
      <g fontFamily="Inter, sans-serif" fontSize="10" fill="#FFA000" fontWeight="600">
        <line x1="1240" y1="140" x2="1240" y2="100" stroke="#FFA000" strokeWidth="0.8" strokeDasharray="2 2"/>
        <text x="1248" y="96" letterSpacing="0.04em">+64.9% YoY</text>
      </g>
    </svg>
  );
}

// expose
Object.assign(window, {
  PALETTE, Logo, Eyebrow, PrimaryButton, GhostButton,
  CaptureModal, FormField, fieldInput, isValidEmail, isWorkEmail,
  FREE_EMAIL_DOMAINS, HeroChartPattern,
  readUtmObject, serializeUtmPayload, pushCaptureSuccess,
});
