// SPECTR site bundle (auto-generated; sources in src/)
const { useState, useEffect } = React;

/* data */
// Packet stream rows — IT-heavy mix with OT/IoT/Wi-Fi cameos and anomalies sprinkled in.
const PACKETS = [
{ n: 1042, t: "14:32:01.284", proto: "HTTPS", domain: "it", src: "10.0.4.22", dst: "104.18.32.7", len: 517, desc: "TLSv1.3 · ja3 t13d1516h2_acb858a92679_3fdcc2ef9d8a" },
{ n: 1043, t: "14:32:01.291", proto: "DNS", domain: "it", src: "10.0.4.22", dst: "1.1.1.1", len: 74, desc: "Standard query A sentry.io" },
{ n: 1044, t: "14:32:01.298", proto: "TLS", domain: "it", src: "10.0.4.22", dst: "142.250.80.46", len: 1420, desc: "ClientHello · h2 alpn · sni=clients.google.com" },
{
  n: 1045, t: "14:32:01.305", proto: "HTTP", domain: "it",
  src: "10.0.4.91", dst: "203.0.113.44", len: 612,
  desc: "POST /upload?id=u8821 · Content-Type: application/octet-stream",
  anomaly: "crit", rule: "IT-EX-12",
  ai: {
    title: "Plaintext exfiltration to unrecognized host",
    body: "Host <em>10.0.4.91</em> POSTed 612B of <em>application/octet-stream</em> over cleartext HTTP to <em>203.0.113.44</em> — an IP never seen in the 14-day egress baseline. Destination ASN is a low-reputation hosting block. No User-Agent. No Referer.",
    rec: "Block 203.0.113.44 at the egress firewall. Quarantine 10.0.4.91 and pull its outbound HTTP history for the past 72 hours."
  }
},
{ n: 1046, t: "14:32:01.312", proto: "LDAP", domain: "it", src: "10.0.4.22", dst: "10.0.2.5", len: 286, desc: "bindRequest · simple · cn=svc-mon,ou=svc,dc=corp" },
{ n: 1047, t: "14:32:01.319", proto: "MQTT", domain: "iot", src: "10.0.8.41", dst: "10.0.2.10", len: 128, desc: "Publish · sensors/bay-4/temp · QoS 1" },
{
  n: 1048, t: "14:32:01.326", proto: "KRB5", domain: "it",
  src: "10.0.4.137", dst: "10.0.2.5", len: 1188,
  desc: "TGS-REQ · 23 SPNs in 18s · etype=23 (RC4-HMAC)",
  anomaly: "crit", rule: "IT-ID-KRB",
  ai: {
    title: "Kerberoasting — high-rate TGS for service SPNs",
    body: "Host <em>10.0.4.137</em> requested 23 service tickets in 18 seconds, all targeting MSSQL/backup SPNs and all encrypted with <em>RC4-HMAC</em>. Modern domains negotiate AES; RC4 requests are the textbook offline-crackable Kerberoasting signature.",
    rec: "Pull the source host. Force a password rotation on every SPN in the request burst. Disable RC4-HMAC in the realm policy if not already."
  }
},
{ n: 1049, t: "14:32:01.333", proto: "HTTP", domain: "it", src: "10.0.4.22", dst: "10.0.2.40", len: 340, desc: "GET /api/v2/health · 200 OK" },
{ n: 1050, t: "14:32:01.341", proto: "MODBUS", domain: "ot",
  src: "192.168.1.50", dst: "10.0.10.14", len: 78,
  desc: "FC16 Write Multiple · regs 40032..40033",
  anomaly: "crit", rule: "OT-W-03",
  ai: {
    title: "Unauthorized Modbus FC16 write to PLC",
    body: "Function code <em>16 (write multiple registers)</em> issued from <em>192.168.1.50</em> to PLC <em>10.0.10.14</em>. Source host is not in the authorized HMI subnet (10.0.9.0/24) and has never written to this PLC in the 14-day baseline. Target registers 40032–40033 control the <em>bay-4 setpoint</em>.",
    rec: "Isolate 192.168.1.50 and inspect preceding auth flows. No legitimate operational reason for a write from this VLAN."
  }
},
{
  n: 1051, t: "14:32:01.348", proto: "SMB", domain: "it",
  src: "10.0.4.188", dst: "10.0.4.22", len: 180,
  desc: "Negotiate Protocol Request · dialects include SMB1",
  anomaly: "warn", rule: "IT-LM-11",
  ai: {
    title: "SMBv1 negotiation attempt — EternalBlue surface",
    body: "Host <em>10.0.4.188</em> initiated an SMB negotiate with <em>SMB1</em> in the dialect list. SMBv1 is the attack vector for EternalBlue/WannaCry and has no legitimate use in a 2026 environment.",
    rec: "Disable SMBv1 on 10.0.4.188 via Group Policy. Review the host's patch level and EDR status."
  }
},
{
  n: 1052, t: "14:32:01.355", proto: "DNS", domain: "it",
  src: "10.0.4.91", dst: "8.8.8.8", len: 144,
  desc: "Query TXT · aHR0cHM6Ly9jMi5leGFtcGxl.atk.example",
  anomaly: "crit", rule: "IT-EX-07",
  ai: {
    title: "DNS tunneling pattern",
    body: "Base64-shaped label (<em>aHR0cHM6Ly9jMi5leGFtcGxl</em>) in TXT query to <em>atk.example</em>. Query entropy 5.42 bits/char, length 144B — consistent with command-and-control over DNS.",
    rec: "Block atk.example at resolver. Pull full DNS history for 10.0.4.91 and quarantine."
  }
},
{ n: 1053, t: "14:32:01.362", proto: "RDP", domain: "it", src: "10.0.4.22", dst: "10.0.2.88", len: 412, desc: "Connection Request · cookie=mstshash=jwong" },
{ n: 1054, t: "14:32:01.370", proto: "OPC-UA", domain: "ot", src: "10.0.9.51", dst: "10.0.10.21", len: 210, desc: "Read Request · 3 attributes" },
{ n: 1055, t: "14:32:01.377", proto: "DOT11", domain: "wifi", src: "aa:bb:cc:11", dst: "ff:ff:ff:ff", len: 62, desc: "Beacon · ssid=corp-iot · ch 6 · -42 dBm" },
{ n: 1056, t: "14:32:01.384", proto: "DNP3", domain: "ot", src: "10.0.10.14", dst: "10.0.9.7", len: 92, desc: "Unsolicited response · class 1 · obj 30 var 5" }];

const DOMAINS = [
{
  key: "it", label: "IT", name: "Enterprise traffic",
  desc: "29 protocols deep-parsed. JA3/JA3S passive + JARM active TLS fingerprinting, identity extraction from NTLMSSP, LDAP bind DN, and Kerberos SPN. Optional SSLKEYLOGFILE TLS decryption.",
  count: "29 protocols",
  protos: ["HTTP/2", "TLS 1.3", "DNS", "SMB", "Kerberos", "LDAP", "RDP", "SSH", "FTP", "NTP", "Syslog", "SIP/RTP", "gRPC", "WebSocket", "RADIUS", "LLMNR/NBNS"]
},
{
  key: "iot", label: "IoT", name: "Device protocols",
  desc: "Lightweight protocols your asset inventory misses. MQTT topic-level awareness, CoAP observation, AMQP, and automatic device behavioral baselining.",
  count: "3 parsed",
  protos: ["MQTT", "CoAP", "AMQP"]
},
{
  key: "ot", label: "OT / ICS", name: "Industrial control",
  desc: "Function-code level parsing for 9 OT protocols. Write detection, setpoint tracking, Purdue-zone classification, ICS-CERT advisory correlation, and process-historian comparison.",
  count: "9 protocols",
  protos: ["Modbus TCP/RTU", "DNP3", "OPC-UA", "EtherNet/IP", "BACnet", "S7comm", "IEC 60870-5-104", "PROFINET"]
},
{
  key: "wifi", label: "Wireless", name: "802.11 visibility",
  desc: "Passive Radiotap + Dot11 parsing. Beacon, probe, auth/assoc/deauth, control + data frames. Linux monitor-mode automated; macOS/Windows guided. Optional SSLKEYLOGFILE TLS decryption on captured frames.",
  count: "4 wireless rules",
  protos: ["Beacon/Probe", "Auth/Assoc", "Deauth", "Control", "Data", "Radiotap"]
}];

const ANOMALIES = [
{ sev: "crit", rule: "OT-W-03", title: "Unauthorized Modbus write", body: '<span class="k">pkt</span> #1046 · <span class="k">src</span> 192.168.1.50 → <span class="k">dst</span> 10.0.10.14 · <span class="hl">FC16 write to 40032–40033 from host outside authorized HMI subnet</span>' },
{ sev: "crit", rule: "IT-EX-07", title: "DNS tunneling — C2 signal", body: '<span class="k">pkt</span> #1053 · TXT query to atk.example · <span class="hl">base64-shaped label, entropy 5.42 bits/char</span>' },
{ sev: "crit", rule: "WIFI-D-01", title: "802.11 deauthentication flood", body: '<span class="k">pkt</span> #1052 · BSSID aa:bb:cc:11 · <span class="hl">47 deauth/s for 4.2s — rogue-AP roaming attack</span>' },
{ sev: "crit", rule: "IT-ID-KRB", title: "Kerberoasting — high-rate TGS for SPNs", body: '<span class="k">pkt</span> #4102 · 23 TGS-REQ for MSSQL/backup SPNs from single host in 18s · <span class="hl">RC4-HMAC encryption requested</span>' },
{ sev: "warn", rule: "IT-LM-11", title: "SMBv1 negotiation", body: '<span class="k">pkt</span> #1050 · 10.0.4.188 → 10.0.4.22 · SMB1 in dialect list — EternalBlue attack surface' },
{ sev: "warn", rule: "WIFI-T-02", title: "Evil-twin candidate AP", body: '<span class="k">pkt</span> #2890 · SSID corp-guest broadcast from new BSSID outside known OUI range · <span class="hl">RSSI consistent with same physical area</span>' },
{ sev: "warn", rule: "OT-ICSA", title: "ICS-CERT advisory match · Siemens S7-1500", body: '<span class="k">pkt</span> #5201 · S7comm session to 10.0.10.21 · firmware banner matches <span class="hl">ICSA-25-038-01</span>' },
{ sev: "info", rule: "AI-LM", title: "Lateral movement: IT host → OT controller", body: '<span class="k">pkt</span> #2318 · 10.0.4.22 (laptop subnet, L4) initiated OPC-UA session to 10.0.10.21 (L2) · no baseline precedent in 14d' }];

const TAGLINES = {
  see_everything: { pre: "See everything.", main: "Understand", tail: "instantly.", sub: "Crafted to capture every packet. Engineered to explain it in your language. One install — IT, IoT, OT, and the air between them." },
  full_spectrum: { pre: "Full-spectrum", main: "packet", tail: "intelligence.", sub: "Designed for forty protocols. Tuned for the boundaries where they meet. Local by default. Quiet until something speaks." },
  wireshark_ai: { pre: "Wireshark", main: "with an", tail: "AI analyst.", sub: "Wireshark shows you everything. SPECTR tells you what matters." }
};

/* icons */
const Icon = {
  capture: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <rect x="3" y="5" width="18" height="14" rx="2" />
      <path d="M3 10h18M8 14h3M13 14h3" />
    </svg>,

  detect: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4L7 17M17 7l1.4-1.4" />
      <circle cx="12" cy="12" r="4" />
    </svg>,

  brain: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M9 6a3 3 0 1 0-3 3v6a3 3 0 1 0 3 3V6z" />
      <path d="M15 6a3 3 0 1 1 3 3v6a3 3 0 1 1-3 3V6z" />
    </svg>,

  lock: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <rect x="4" y="11" width="16" height="10" rx="2" />
      <path d="M8 11V7a4 4 0 0 1 8 0v4" />
    </svg>,

  shield: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6l8-3z" />
    </svg>,

  offline: (p) =>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M4 12a8 8 0 0 1 16 0M8 12a4 4 0 0 1 8 0" />
      <line x1="3" y1="21" x2="21" y2="3" />
    </svg>,

  github: (p) =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" {...p}>
      <path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.38 7.86 10.9.58.1.79-.25.79-.56v-2c-3.2.7-3.87-1.37-3.87-1.37-.52-1.32-1.28-1.67-1.28-1.67-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.55-.29-5.24-1.28-5.24-5.68 0-1.26.45-2.29 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18.92-.26 1.9-.38 2.88-.39.98 0 1.96.13 2.88.39 2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.11 3.05.74.8 1.18 1.83 1.18 3.09 0 4.41-2.69 5.39-5.25 5.67.42.36.77 1.06.77 2.14v3.17c0 .31.2.67.8.56C20.21 21.37 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5z" />
    </svg>,

  arrow: (p) =>
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M2 6h8M6.5 2.5L10 6l-3.5 3.5" />
    </svg>

};

/* Chrome */


/* ── Logo ──────────────────────────────────────────────────── */
function Logo() {
  return (
    <a className="logo" href="index.html" aria-label="SPECTR home">
      <span className="logo__word">
        <span>SPECT</span>
        <span className="logo__r">R</span>
      </span>
      <span className="logo__bars" aria-hidden="true">
        <span style={{ background: "var(--accent-blue)" }} />
        <span style={{ background: "var(--accent-yellow)" }} />
        <span style={{ background: "var(--accent-red)" }} />
      </span>
    </a>);

}

/* ── Header ──────────────────────────────────────────────── */
function Header() {
  return (
    <header className="site-header" id="top">
      <div className="container site-header__inner">
        <Logo />
        <nav className="nav" aria-label="Primary">
          <a href="#coverage">Coverage</a>
          <a href="#intelligence">Intelligence</a>
          <a href="#netintel">Net Intel</a>
          <a href="#throughput">Throughput</a>
          <a href="#compliance">Compliance</a>
          <a href="#enterprise">Enterprise</a>
          <a href="#pricing">Pricing</a>
        </nav>
        <div className="nav-cta">
          <a className="btn btn--primary btn--sm" href="#signup">Contact sales</a>
        </div>
      </div>
    </header>);

}

/* ── Footer ───────────────────────────────────────────────── */
function Footer() {
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer__grid">
          <div className="footer__col">
            <Logo />
            <p style={{ marginTop: 16, color: "var(--text-muted)", maxWidth: 280, fontSize: 13, lineHeight: 1.55 }}>AI packet intelligence for IT, IoT, and OT networks. Runs locally, sees everything, explains what matters.</p>
          </div>
          <div className="footer__col">
            <h4>Product</h4>
            <a href="#coverage">Protocol coverage</a>
            <a href="#anomalies">Anomaly engine</a>
            <a href="#intelligence">AI intelligence</a>
            <a href="#netintel">Network Intelligence</a>
            <a href="#throughput">Throughput &amp; perfSONAR</a>
            <a href="#compliance">Compliance</a>
            <a href="#enterprise">Enterprise</a>
            <a href="#pricing">Pricing</a>
          </div>
          <div className="footer__col">
            <h4>Developers</h4>
            <a href="#">Documentation</a>
            <a href="#">API reference</a>
            <a href="#">Rule DSL</a>
            <a href="#">Changelog</a>
          </div>
          <div className="footer__col">
            <h4>Company</h4>
            <a href="about.html">About Rex Labs LLC</a>
            <a href="#">Security</a>
            <a href="#">Contact</a>
            <a href="mailto:spectr@rex-labs.tech">spectr@rex-labs.tech</a>
          </div>
        </div>
        <div className="footer__bottom">
          <span>© 2026 Rex Labs LLC · SPECTR 0.6.0 · Net Intel 1.7.0 (perfSONAR · iPerf3 · SNMP)</span>
          <span style={{ color: "var(--text-muted)" }}>rex-labs.tech · spectr@rex-labs.tech</span>
        </div>
      </div>
    </footer>);

}

/* ── Tweaks panel — only used on home ──────────────────────── */
function TweaksPanel({ open, tagline, onTagline, heroVariant, onHero }) {
  if (!open) return null;
  return (
    <div className="tweaks" role="dialog" aria-label="Tweaks">
      <div className="tweaks__head"><span>Tweaks</span><span style={{ opacity: 0.6, fontSize: 9 }}>live · persisted</span></div>
      <div className="tweaks__body">
        <div className="tweaks__grp">
          <label>Tagline</label>
          <div className="tweaks__opts">
            {[
            ["see_everything", "See everything. Understand instantly.", "On-brand, benefit-first"],
            ["full_spectrum", "Full-spectrum packet intelligence.", "Category-defining"],
            ["wireshark_ai", "Wireshark with an AI analyst.", "Comparative, pragmatic"]].
            map(([k, label, note]) =>
            <button key={k} className={`tweaks__opt ${tagline === k ? "is-active" : ""}`} onClick={() => onTagline(k)}>
                <span className="dot" />
                <span>
                  <div style={{ color: "var(--text-primary)", fontWeight: 600 }}>{label}</div>
                  <div style={{ color: "var(--text-muted)", fontSize: 11, marginTop: 2 }}>{note}</div>
                </span>
              </button>
            )}
          </div>
        </div>
        <div className="tweaks__grp">
          <label>Hero layout</label>
          <div className="tweaks__opts">
            {[
            ["centered", "Centered", "Headline-forward, demo below"],
            ["split", "Split", "Copy left, stream right"]].
            map(([k, label, note]) =>
            <button key={k} className={`tweaks__opt ${heroVariant === k ? "is-active" : ""}`} onClick={() => onHero(k)}>
                <span className="dot" />
                <span>
                  <div style={{ color: "var(--text-primary)", fontWeight: 600 }}>{label}</div>
                  <div style={{ color: "var(--text-muted)", fontSize: 11, marginTop: 2 }}>{note}</div>
                </span>
              </button>
            )}
          </div>
        </div>
      </div>
    </div>);

}

/* ── Edit-mode hook for tweaks panel ──────────────────────── */
function useEditMode() {
  const [open, setOpen] = useState(false);
  useEffect(() => {
    function onMsg(e) {
      const d = e.data || {};
      if (d.type === "__activate_edit_mode") setOpen(true);
      if (d.type === "__deactivate_edit_mode") setOpen(false);
    }
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);
  return [open, setOpen];
}
function persist(key, value) {
  window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [key]: value } }, "*");
}

/* Hero */



function PacketStream() {
  return (
    <div className="pshot" role="figure" aria-label="SPECTR live capture — actual product UI">
      <div className="pshot__chrome">
        <div className="pshot__chrome-dots">
          <span /><span /><span />
        </div>
        <div className="pshot__chrome-title">SPECTR · live capture · en0</div>
        <div className="pshot__chrome-meta">
          <span className="pshot__rec">REC</span>
          <span>1,770 pkts · 38 alerts</span>
        </div>
      </div>
      <img
        className="pshot__img"
        src="assets/spectr-live-capture.png"
        alt="SPECTR live packet capture interface showing TLS, ARP, and UDP traffic with the AI Analyst panel surfacing lateral-movement and custom-rule findings on the right."
        loading="eager"
        decoding="async"
        width="1237"
        height="955" />
      
    </div>);

}
function Hero({ tagline, variant }) {
  const t = TAGLINES[tagline] || TAGLINES.see_everything;
  const copy =
  <>
      <div className="kicker hero__kicker">
        <span className="kicker__dot" />
        <span>SPECTR 0.6.0 · NET INTEL 1.7.0 · MACOS · WINDOWS · LINUX</span>
      </div>
      <h1>
        <span className="dim">{t.pre}</span><br />
        {t.main} <span className="blue">{t.tail}</span>
      </h1>
      <p className="hero__sub">{t.sub}</p>
      <div className="hero__meta">
        <span><span className="tick">✓</span> 47 protocols · IT + IoT + OT + Wi-Fi</span>
        <span><span className="tick">✓</span> 34 anomaly rules · zero-latency</span>
        <span><span className="tick">✓</span> Local AI · air-gap compatible</span>
        <span><span className="tick">✓</span> Active throughput + perfSONAR drift correlation</span>
      </div>
    </>;

  if (variant === "split") {
    return (
      <section className="hero hero--split">
        <div className="container">
          <div className="hero__split-grid">
            <div>{copy}</div>
            <div><PacketStream /></div>
          </div>
        </div>
      </section>);

  }
  return (
    <section className="hero">
      <div className="container">
        {copy}
        <PacketStream />
      </div>
    </section>);

}
function ProductCaption() {
  return (
    <section className="section section--tight" id="product" style={{ borderTop: 0, paddingTop: 40 }}>
      <div className="container section__head section__head--center">
        <div className="section__eyebrow">Live capture</div>
        <h2 className="section__title">Crafted for microsecond detection. Composed for plain-English clarity.</h2>
        <p className="section__sub">
          The product, today. Live packet capture with the AI Analyst surfacing lateral movement, custom rules, and threats — in plain English, with the packets to back it up.
        </p>
      </div>
    </section>);

}

/* ProductSections */
function HowItWorks() {
  return (
    <section className="section" id="how">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">The flow</div>
          <h2 className="section__title">Install. Capture. Ask.</h2>
          <p className="section__sub">Three commands. No agents. No cloud. Yours, end to end.</p>
        </div>
        <div className="steps">
          <div className="step">
            <div className="step__num">01 / CAPTURE</div>
            <div className="step__icon"><Icon.capture /></div>
            <h3 className="step__title">Point it at an interface or a PCAP.</h3>
            <p className="step__body">Reads live from tshark on macOS and Windows, or opens any PCAP/PCAPNG. Drag-and-drop supported. First-run setup checks dependencies and exits with a specific error if something's missing.</p>
            <div className="step__code"><span className="c"># live capture</span><br /><span className="k">sudo</span> spectr <span className="s">--iface en0</span></div>
          </div>
          <div className="step">
            <div className="step__num">02 / DETECT</div>
            <div className="step__icon"><Icon.detect /></div>
            <h3 className="step__title">Rules fire on every frame. Zero latency.</h3>
            <p className="step__body">Deep-parses 30+ protocols and evaluates a rule set across IT, IoT, and OT — unauthorized writes, lateral movement, DNS tunneling, SMBv1 negotiation, cross-domain flows, and more.</p>
            <div className="step__code"><span className="c"># tune per-environment</span><br />spectr rules <span className="k">enable</span> <span className="s">OT-W-*</span></div>
          </div>
          <div className="step">
            <div className="step__num">03 / ASK</div>
            <div className="step__icon"><Icon.brain /></div>
            <h3 className="step__title">Plain-English diagnosis with packet citations.</h3>
            <p className="step__body">Ask the analyst <em>why is this PLC getting writes from an unknown IP?</em> — get a specific answer referencing packet IDs, IPs, function codes, and a recommended action. Runs against Claude or a local Ollama model.</p>
            <div className="step__code"><span className="c"># local inference</span><br /><span className="k">export</span> INFERENCE_URL=<span className="s">http://localhost:11434/v1</span></div>
          </div>
        </div>
      </div>
    </section>);

}
function Coverage() {
  return (
    <section className="section" id="coverage">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Coverage</div>
          <h2 className="section__title">Every domain. One capture.</h2>
          <p className="section__sub">Designed for environments that never sit still. IT, IoT, OT, and Wi-Fi — parsed in a single stream. The traffic that crosses domains is usually the traffic worth watching.</p>
        </div>
        <div className="fgrid" style={{ gridTemplateColumns: "repeat(4, 1fr)" }}>
          {DOMAINS.map((d) =>
          <div key={d.key} className={`fgrid__card fgrid__card--${d.key}`}>
              <div className="fgrid__label"><span>{d.label}</span><span className="count">{d.count}</span></div>
              <h3 className="fgrid__title">{d.name}</h3>
              <p className="fgrid__desc">{d.desc}</p>
              <div className="fgrid__protos">{d.protos.map((p) => <span key={p}>{p}</span>)}</div>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function AnomalyShowcase() {
  return (
    <section className="section" id="anomalies">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Detection</div>
          <h2 className="section__title">Specific findings. Not alert noise.</h2>
          <p className="section__sub">Crafted to cite the packet, the rule, the evidence. Every detection is inspectable. Every threshold is yours to tune.</p>
        </div>
        <div className="anoms">
          {ANOMALIES.map((a, i) =>
          <div key={i} className={`anom anom--${a.sev}`}>
              <div className="anom__sev">{a.sev}</div>
              <div>
                <div className="anom__title">{a.title}</div>
                <div className="anom__body" dangerouslySetInnerHTML={{ __html: a.body }} />
              </div>
              <div className="anom__rule">{a.rule}</div>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function NetworkGraphFeature() {
  const HUB = { x: 440, y: 270, label: "192.168.1.162", r: 22 };
  const primary = [
  { x: 200, y: 150, label: "224.0.0.251", dom: "iot", alert: true },
  { x: 680, y: 130, label: "239.255.255.250", dom: "iot", alert: true },
  { x: 160, y: 310, label: "192.168.1.188", dom: "it", alert: true },
  { x: 285, y: 215, label: "192.168.1.144", dom: "it" },
  { x: 320, y: 360, label: "192.168.1.106", dom: "it" },
  { x: 380, y: 180, label: "162.125.21.2", dom: "it" },
  { x: 565, y: 200, label: "142.251.179.94", dom: "it" },
  { x: 600, y: 270, label: "35.186.224.24", dom: "it" },
  { x: 760, y: 290, label: "17.253.12.93", dom: "it", warn: true },
  { x: 520, y: 410, label: "104.17.132.16", dom: "it" },
  { x: 360, y: 440, label: "74.125.139.180", dom: "it" },
  { x: 250, y: 420, label: "52.110.2.139", dom: "it" }];

  const secondary = [
  [0, 130, 90], [0, 245, 75],
  [1, 750, 70], [1, 620, 60],
  [3, 215, 240], [5, 415, 105],
  [6, 540, 130], [7, 660, 215],
  [8, 830, 240], [8, 830, 330],
  [9, 595, 460], [10, 380, 490], [11, 175, 460]];

  return (
    <div className="ngraph">
      <div className="ngraph__copy">
        <div className="section__eyebrow" style={{ color: "var(--accent-purple)" }}>Featured · the Network Graph</div>
        <h3 className="ngraph__h">Unveil the blast radius — before you have to explain it.</h3>
        <p className="ngraph__sub">
          The Network Graph reconstructs every IP conversation in your capture as a live force-directed graph. A flagged host isn't a single line in a log — it's a hub with <strong>primary</strong> connections (who it talked to directly) and <strong>secondary</strong> connections (who those hosts talked to in turn). One click on an alert tells you exactly how far the problem reaches.
        </p>
        <ul className="ngraph__list">
          <li>
            <span className="ngraph__dot ngraph__dot--alert" />
            <div>
              <strong>Alerts on the graph, not just the list.</strong>
              Hosts tied to active anomalies render in red so the affected sub-graph is visible at a glance.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--primary" />
            <div>
              <strong>Primary vs. secondary relationships.</strong>
              Direct neighbors are first-class edges; their downstream peers fan out as a second ring — the actual reachability footprint.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--metric" />
            <div>
              <strong>Blast radius is a number.</strong>
              We count the unique hosts reachable from a flagged node through observed traffic — the same metric an IR team would compute by hand, but live.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--filter" />
            <div>
              <strong>Filter by domain, alert, or substring.</strong>
              IT / IoT / OT pills, custom-alert overlay, IP-contains search. The same graph, scoped to the question you're asking.
            </div>
          </li>
        </ul>
        <div className="ngraph__stats">
          <div><span className="ngraph__stat-k">Matched</span><span className="ngraph__stat-v">5</span></div>
          <div><span className="ngraph__stat-k">Blast radius</span><span className="ngraph__stat-v ngraph__stat-v--accent">55</span></div>
          <div><span className="ngraph__stat-k">Edges</span><span className="ngraph__stat-v">69</span></div>
          <div><span className="ngraph__stat-k">Packets</span><span className="ngraph__stat-v">2,139</span></div>
        </div>
      </div>

      <div className="ngraph__viz" aria-hidden="true">
        <div className="ngraph__viz-head">
          <span className="ngraph__tab ngraph__tab--active">Network Graph</span>
          <span className="ngraph__tab">Ping</span>
          <span className="ngraph__tab">Traceroute</span>
          <span className="ngraph__tab">Diagnose</span>
        </div>
        <div className="ngraph__viz-filters">
          <span className="ngraph__pill ngraph__pill--it">IT</span>
          <span className="ngraph__pill ngraph__pill--iot ngraph__pill--on">IoT</span>
          <span className="ngraph__pill ngraph__pill--ot">OT</span>
          <span className="ngraph__pill ngraph__pill--alerts">Custom alerts (1)</span>
        </div>
        <svg className="ngraph__svg" viewBox="0 0 880 520" preserveAspectRatio="xMidYMid meet">
          <defs>
            <radialGradient id="hubGlow" cx="50%" cy="50%" r="50%">
              <stop offset="0%" stopColor="rgba(239,68,68,0.5)" />
              <stop offset="100%" stopColor="rgba(239,68,68,0)" />
            </radialGradient>
          </defs>

          {secondary.map(([pi, sx, sy], i) => {
            const p = primary[pi];
            return (
              <line key={`se-${i}`} x1={p.x} y1={p.y} x2={sx} y2={sy}
              className="ngraph__edge ngraph__edge--secondary" />);

          })}

          {primary.map((p, i) =>
          <line key={`pe-${i}`} x1={HUB.x} y1={HUB.y} x2={p.x} y2={p.y}
          className={
          "ngraph__edge ngraph__edge--primary" + (
          p.alert ? " ngraph__edge--alert" : "") + (
          p.warn ? " ngraph__edge--warn" : "")
          } />
          )}

          {secondary.map(([, sx, sy], i) =>
          <circle key={`sn-${i}`} cx={sx} cy={sy} r="4.5"
          className="ngraph__node ngraph__node--secondary" />
          )}

          {primary.map((p, i) =>
          <g key={`pn-${i}`}>
              <circle cx={p.x} cy={p.y} r={p.alert ? 9 : 7}
            className={"ngraph__node" + (p.alert ? " ngraph__node--alert" : " ngraph__node--primary")} />
              <text x={p.x} y={p.y - (p.alert ? 14 : 12)}
            className={"ngraph__label" + (p.alert ? " ngraph__label--alert" : "")}
            textAnchor="middle">
                {p.label}
              </text>
            </g>
          )}

          <circle cx={HUB.x} cy={HUB.y} r="60" fill="url(#hubGlow)" />
          <circle cx={HUB.x} cy={HUB.y} r={HUB.r} className="ngraph__node ngraph__node--hub" />
          <text x={HUB.x} y={HUB.y + HUB.r + 18} className="ngraph__label ngraph__label--hub" textAnchor="middle">
            {HUB.label}
          </text>

          <circle cx={HUB.x} cy={HUB.y} r="120" className="ngraph__ring" />
          <g transform={`translate(${HUB.x + 130}, ${HUB.y - 110})`}>
            <line x1="0" y1="0" x2="40" y2="-30" className="ngraph__leader" />
            <g transform="translate(40, -52)">
              <rect x="0" y="0" width="148" height="44" rx="6" className="ngraph__callout" />
              <text x="12" y="18" className="ngraph__callout-k">BLAST RADIUS</text>
              <text x="12" y="36" className="ngraph__callout-v">55 reachable hosts</text>
            </g>
          </g>
        </svg>
      </div>
    </div>);

}

function DeepAnalysisFeature() {
  return (
    <div className="danalysis">
      <div className="danalysis__copy">
        <div className="section__eyebrow" style={{ color: "var(--accent-purple)" }}>Featured · deep analysis</div>
        <h3 className="ngraph__h">Ask once. Unveil everything — citation by citation.</h3>
        <p className="ngraph__sub">
          Point SPECTR at a capture and ask it what's going on. The analyst reads the full session — flows, protocols, payload metadata — and returns a structured finding with the exact packet IDs, the risk, and a recommended action. No alert-list scrolling, no rule-ID decoding. <strong>Plain-English answers, packet-level evidence.</strong>
        </p>
        <ul className="ngraph__list">
          <li>
            <span className="ngraph__dot ngraph__dot--alert" />
            <div>
              <strong>Concrete findings, never "suspicious activity."</strong>
              Every finding names the protocol, the endpoints, the offending packets, and why it matters.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--primary" />
            <div>
              <strong>Tiered recommendations.</strong>
              Immediate / short-term / policy — the same framing your IR runbook already uses.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--filter" />
            <div>
              <strong>Positive observations, not just red flags.</strong>
              When the traffic is clean, the analyst says so — explicitly — and tells you what it ruled out.
            </div>
          </li>
          <li>
            <span className="ngraph__dot ngraph__dot--metric" />
            <div>
              <strong>Runs locally.</strong>
              Same output against a local Ollama / LM Studio model. Your packets never leave the host.
            </div>
          </li>
        </ul>
      </div>

      <div className="danalysis__panel" aria-hidden="true">
        <div className="danalysis__head">
          <div className="danalysis__head-l">
            <span className="danalysis__dot" />
            <span className="danalysis__title">SPECTR AI</span>
          </div>
          <span className="danalysis__badge">claude · local</span>
        </div>
        <div className="danalysis__meta">
          <span>Capture <span className="danalysis__meta-v">web-egress.pcap</span></span>
          <span>9,412 pkts · 47.3 MB</span>
        </div>
        <div className="danalysis__prompt">
          <span className="danalysis__prompt-k">User</span>
          <span>Anything I should be worried about in this capture?</span>
        </div>
        <div className="danalysis__body">
          <p>Based on my analysis of this capture, I can identify <strong>one notable security concern</strong>:</p>

          <div className="danalysis__h danalysis__h--warn">
            <span className="danalysis__h-tag">[WARNING]</span>
            Unencrypted HTTP/WebSocket Communication
          </div>

          <div className="danalysis__sec">
            <div className="danalysis__sec-k">What I observed</div>
            <ul>
              <li>All traffic between <code>10.0.52.164</code> and external server <code>204.152.184.134</code> is occurring over <strong>port 80 (HTTP)</strong> rather than HTTPS</li>
              <li>The session includes WebSocket communication (packets <code>#9334</code>, <code>#9337</code>, <code>#9338</code>, <code>#9347</code>) which is also unencrypted</li>
              <li>Active web application session that concluded with a WebSocket close frame (<code>#9347</code>)</li>
            </ul>
          </div>

          <div className="danalysis__sec">
            <div className="danalysis__sec-k danalysis__sec-k--risk">Security Risk</div>
            <ul>
              <li>All data transmitted in this session is <strong>visible to any network observer</strong></li>
              <li>If this application handles sensitive data, credentials, or business information, it's completely exposed</li>
              <li>WebSocket traffic often carries real-time application data — session tokens, business logic, personal info</li>
            </ul>
          </div>

          <div className="danalysis__sec">
            <div className="danalysis__sec-k danalysis__sec-k--rec">Recommendation</div>
            <ul>
              <li><strong>Immediate:</strong> Verify what application is communicating with <code>204.152.184.134</code> and assess data sensitivity</li>
              <li><strong>Short-term:</strong> Migrate to HTTPS (port 443) and secure WebSockets (WSS)</li>
              <li><strong>Policy:</strong> Implement firewall rules to block outbound HTTP traffic and enforce HTTPS-only for web applications</li>
            </ul>
          </div>

          <div className="danalysis__h danalysis__h--ok">Positive Security Observations</div>
          <ul className="danalysis__ok-list">
            <li><span className="danalysis__ok">✓</span> <strong>No active threats detected.</strong> No port scans, malware indicators, or attack patterns observed.</li>
            <li><span className="danalysis__ok">✓</span> <strong>Clean traffic pattern.</strong> Normal TCP connection establishment, data exchange, and teardown.</li>
            <li><span className="danalysis__ok">✓</span> <strong>No anomalies flagged.</strong> SPECTR's anomaly engine found no suspicious behavior.</li>
          </ul>

          <div className="danalysis__sec">
            <div className="danalysis__sec-k">Overall Assessment</div>
            <p>Appears to be legitimate application traffic, but the use of unencrypted transport is a meaningful security gap worth closing before it carries production data.</p>
          </div>
        </div>
        <div className="danalysis__input">
          <span>Ask SPECTR about this capture…</span>
          <span className="danalysis__send">Send</span>
        </div>
      </div>
    </div>);

}

function AIIntelligence() {
  const caps = [
  { t: "Plain-English investigation", b: "Ask the analyst anything about a packet, a flow, or the last hour. Every answer names the IPs, cites the packet numbers, and ends with a recommended next move." },
  { t: "Natural-language packet search", b: "Skip the BPF. ‘Failed auth from the past hour.’ ‘Anything talking to a new external IP.’ The model writes the filter and applies it." },
  { t: "PCAP comparison", b: "Two captures, one diff. New devices, new protocols, behavioral drift — surfaced as a structured before/after report." },
  { t: "Per-device behavioral baseline", b: "Each device's normal — protocols, peers, rate envelopes — learned from observed traffic. Deviations show up where you're looking." },
  { t: "MITRE ATT&CK mapping", b: "Every finding carries a MITRE technique ID — Enterprise for IT, ICS for OT. Your SOC tooling already speaks this language." },
  { t: "JA3 / JA3S + JARM fingerprinting", b: "Every TLS handshake fingerprinted on the way in. Optional active JARM probes for C2 surface — admin-only, audit-logged, internal targets refused by default." },
  { t: "ICS-CERT / CISA correlation", b: "OT devices in the capture matched against a local CISA advisory database. Hits appear inline. No internet required." },
  { t: "Auto-summary on import", b: "Every PCAP that lands in the library — local, remote, or hand-carried — gets an AI summary in the background. Read the headline. Decide if it's worth a full investigation." }];

  return (
    <section className="section" id="intelligence">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">The analyst</div>
          <h2 className="section__title">Designed to understand your network. Trained to explain it.</h2>
          <p className="section__sub">Orchestrated from behavioral truth, not statistical guesses. Every finding traces back to packets. Every model runs where you do.</p>
        </div>

        <NetworkGraphFeature />

        <DeepAnalysisFeature />

        <div className="fgrid" style={{ gridTemplateColumns: "repeat(4, 1fr)" }}>
          {caps.map((c) =>
          <div key={c.t} className="fgrid__card" style={{ "--fc": "var(--accent-purple)" }}>
              <h3 className="fgrid__title" style={{ fontSize: 16 }}>{c.t}</h3>
              <p className="fgrid__desc" style={{ marginBottom: 0 }}>{c.b}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function Compare() {
  const rows = [
  ["Live capture + PCAP", "tick", "tick", "partial", "tick"],
  ["IT protocols (HTTP, TLS, DNS, SMB)", "tick", "tick", "tick", "partial"],
  ["IoT protocols (MQTT, CoAP)", "tick", "partial", "cross", "cross"],
  ["OT protocols (Modbus, DNP3, OPC-UA)", "tick", "partial", "cross", "tick"],
  ["Rule-based anomaly detection", "tick", "cross", "tick", "tick"],
  ["Plain-English AI diagnosis", "tick", "cross", "partial", "cross"],
  ["Runs air-gapped / local inference", "tick", "tick", "cross", "partial"],
  ["Single-command install", "tick", "tick", "cross", "cross"]];

  const headers = ["", "SPECTR", "Wireshark", "SIEM", "OT-specific"];
  const cell = (v) => {
    if (v === "tick") return <span className="tick">●</span>;
    if (v === "cross") return <span className="cross">—</span>;
    if (v === "partial") return <span className="partial">partial</span>;
    return v;
  };
  return (
    <section className="section" id="compare">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Against the field</div>
          <h2 className="section__title">Wireshark is powerful. A SIEM is generic. OT tools are siloed.</h2>
          <p className="section__sub">Crafted at the intersection. Packet-level depth. Real-time clarity. Every domain. One install.</p>
        </div>
        <div className="compare">
          <div className="compare__row compare__head">
            {headers.map((h, i) => <div key={i} className={i === 1 ? "spectr-col" : ""}>{h}</div>)}
          </div>
          {rows.map((r, i) =>
          <div key={i} className="compare__row">
              <div className="cell-crit">{r[0]}</div>
              <div className="spectr-col">{cell(r[1])}</div>
              <div>{cell(r[2])}</div>
              <div>{cell(r[3])}</div>
              <div>{cell(r[4])}</div>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function Privacy() {
  return (
    <section className="section" id="privacy">
      <div className="container">
        <div className="privacy">
          <div>
            <div className="section__eyebrow">Privacy by design</div>
            <h2 className="section__title">Your packets stay on your network.</h2>
            <p className="section__sub" style={{ marginBottom: 32 }}>Most packet analysis tools ship your capture to their cloud. SPECTR doesn't. The default inference path is a local model — Ollama, LM Studio, or SGLang — running on the same machine.</p>
            <div className="privacy__points">
              <div className="privacy__pt">
                <div className="privacy__pt-icon"><Icon.offline /></div>
                <div>
                  <div className="privacy__pt-title">Air-gap compatible</div>
                  <div className="privacy__pt-body">Zero outbound requests when configured with a local backend. Suitable for isolated OT networks and classified environments.</div>
                </div>
              </div>
              <div className="privacy__pt">
                <div className="privacy__pt-icon"><Icon.lock /></div>
                <div>
                  <div className="privacy__pt-title">Payload redaction before prompt</div>
                  <div className="privacy__pt-body">Optional privacy layer strips credentials, tokens, and payload contents from the AI context window. Headers and metadata only.</div>
                </div>
              </div>
              <div className="privacy__pt">
                <div className="privacy__pt-icon"><Icon.shield /></div>
                <div>
                  <div className="privacy__pt-title">Pluggable backend</div>
                  <div className="privacy__pt-body">Swap between Anthropic API, OpenAI, Gemini, and local models by changing one env var. No vendor lock.</div>
                </div>
              </div>
            </div>
          </div>
          <div className="privacy__diagram" aria-hidden="true">
            <div style={{ color: "var(--text-muted)", letterSpacing: 1.5, fontSize: 10, textTransform: "uppercase", marginBottom: 16 }}>$ cat ~/Library/Application Support/SPECTR/.env</div>
            <div style={{ display: "grid", gap: 6, color: "var(--text-secondary)" }}>
              <div><span style={{ color: "var(--text-muted)" }}># local inference (default)</span></div>
              <div>INFERENCE_URL=<span style={{ color: "var(--accent-green)" }}>http://localhost:11434/v1</span></div>
              <div>LOCAL_MODEL=<span style={{ color: "var(--accent-green)" }}>mistral-nemo</span></div>
              <div>&nbsp;</div>
              <div><span style={{ color: "var(--text-muted)" }}># or cloud, your key</span></div>
              <div><span style={{ color: "var(--text-muted)" }}># ANTHROPIC_API_KEY=sk-ant-...</span></div>
              <div>&nbsp;</div>
              <div><span style={{ color: "var(--text-muted)" }}># privacy</span></div>
              <div>REDACT_PAYLOADS=<span style={{ color: "var(--accent-blue)" }}>true</span></div>
              <div>SEND_TELEMETRY=<span style={{ color: "var(--accent-red)" }}>false</span></div>
            </div>
            <div style={{ marginTop: 20, paddingTop: 14, borderTop: "1px solid var(--border)", fontSize: 10, color: "var(--text-muted)", letterSpacing: 1, textTransform: "uppercase" }}>Network egress: <span style={{ color: "var(--accent-green)" }}>0 B</span></div>
          </div>
        </div>
      </div>
    </section>);

}

/* BizSections */
function Compliance() {
  const fw = [
  { k: "IEC 62443", d: "Zone/conduit analysis from captured traffic. Gap detection against IEC 62443 security requirements." },
  { k: "NERC CIP", d: "Electronic Security Perimeter and CIP-007 monitoring evidence, generated from observed flows." },
  { k: "NIST CSF 2.0", d: "Identify / Protect / Detect category mapping with finding citations." },
  { k: "NIS2", d: "EU directive — incident reporting artifacts, asset coverage, detection evidence." }];

  return (
    <section className="section" id="compliance">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Compliance</div>
          <h2 className="section__title">Four frameworks. One capture. No spreadsheets.</h2>
          <p className="section__sub">Orchestrated across IEC 62443, NERC CIP, NIST CSF 2.0, and NIS2. Delivered on your cadence. Audit-ready, every time.</p>
        </div>
        <div className="fgrid" style={{ gridTemplateColumns: "repeat(4, 1fr)" }}>
          {fw.map((f) =>
          <div key={f.k} className="fgrid__card" style={{ "--fc": "var(--accent-cyan)" }}>
              <div className="fgrid__label"><span>{f.k}</span></div>
              <p className="fgrid__desc" style={{ marginBottom: 0 }}>{f.d}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function NetIntel() {
  const caps = [
  { t: "5-vendor automation", b: "Cisco IOS / NX-OS, Arista EOS, Juniper JunOS, Fortinet. Forbidden-command regex + safe-command allowlist. AES-GCM credential vault — now covers SSH + SNMP v3 secrets." },
  { t: "5 transports · Pattern C hybrid", b: "SSH (Netmiko) · NETCONF (ncclient) · Serial console (pyserial) · RESTCONF (urllib) · SNMP v2c + v3 USM (HMAC-SHA1/256 + AES-128/256). New per-device state_transport decouples config and state channels — SSH for diff/drift, SNMP for high-resolution counters." },
  { t: "9 standard MIBs covered", b: "IF-MIB (HC 64-bit counters) · IP-MIB (ARP) · BRIDGE-MIB + Q-BRIDGE-MIB (MAC) · IP-FORWARD-MIB (routes) · LLDP-MIB (BFS picks up SNMP-only devices) · Q-BRIDGE-MIB (VLAN) · RSTP-MIB (STP) · ENTITY-MIB (SBOM). No vendor MIBs required." },
  { t: "Auto-discovery + vendor fingerprint", b: "CDP/LLDP recursive crawl with Purdue-zone guard. New SNMP fingerprint endpoint pulls sysDescr / sysName / sysObjectID and classifies Cisco / Juniper / Arista / Fortinet / HP / Dell / Mikrotik from the enterprise-OID prefix." },
  { t: "Config risk engine", b: "10 deterministic rules (SNMPv1, telnet, type-7, AAA gaps, ACL hygiene…) + optional LLM per-vendor analysis. Diff-aware findings auto-resolve when fixed. Encrypted-at-rest config snapshots (AES-GCM, reuses vault key)." },
  { t: "Agentic troubleshoot", b: "7 protocol playbooks: BGP, OSPF, STP, VLAN, IP, OT, DHCP. 4 tools, 8-iter cap. Native tool-use across Anthropic / OpenAI / Gemini; structured-JSON fallback for local models." },
  { t: "State discovery", b: "ARP / MAC / routes / BGP / OSPF / interface counters / VLAN / STP. Fleet-wide locators (“where is this MAC?”, “what's down?”) with longest-prefix-match routing." },
  { t: "CVE + SBOM", b: "Local NVD SQLite mirror (air-gap default). CycloneDX 1.4 + SPDX 2.3. SNMP-only devices now emit SBOM via ENTITY-MIB. Grey-market serial detection. Boot-image drift via source-scoped finding diff." },
  { t: "Topology + lifecycle", b: "Vendored Cytoscape map (3 layouts) with VLAN filter + STP overlay + 👑 root-bridge crown. Live flow overlays. Maintenance windows with pre/post safety snapshots. NERC CIP-010 PDF (deterministic SHA256 report-ID)." },
  { t: "JSONL transcript logger", b: "Per-session request/response transcript across SSH / NETCONF / serial / RESTCONF. Atomic 0o600 file create, tenant-prefixed filenames, configurable retention (default 24h sweep), per-session size cap." },
  { t: "Enterprise Devices grid", b: "Server-side filter / search / pagination. Bulk operations (200-device cap, no implicit cascade). Live /ws/netintel/devices WebSocket with online / stale / offline badges and row-pulse on events." },
  { t: "1,522 tests · air-gap verified", b: "Net Intel sub-suite passing. SNMP secrets never appear in audit / response / error / log fixtures. Same Ed25519-signed JWT licensing as core; license modal shows live node usage and renewal prompts." }];

  return (
    <section className="section" id="netintel">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Network Intelligence · separately licensed · Net Intel 1.7.0</div>
          <h2 className="section__title">Designed to read the network. Engineered to change it.</h2>
          <p className="section__sub">Net Intel adds active infrastructure discovery to SPECTR <strong>Five transports</strong> (SSH · NETCONF · Serial · RESTCONF · SNMP v2c/v3) across five vendors, the new <strong>Pattern C hybrid</strong> (SSH for configs + SNMP for state), nine standard MIBs covered with zero vendor-MIB dependencies, deterministic risk rules, agentic troubleshooting, CVE correlation, and SBOM — same air-gap, multi-tenant, license-gated posture as core SPECTR.</p>
        </div>
        <div className="fgrid" style={{ gridTemplateColumns: "repeat(4, 1fr)" }}>
          {caps.map((c) =>
          <div key={c.t} className="fgrid__card" style={{ "--fc": "var(--accent-cyan)" }}>
              <h3 className="fgrid__title" style={{ fontSize: 16 }}>{c.t}</h3>
              <p className="fgrid__desc" style={{ marginBottom: 0 }}>{c.b}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function Throughput() {
  const phases = [
  {
    stage: "iPerf3",
    ver: "v0.5.3",
    bg: "var(--accent-blue)",
    tier: "Core SPECTR · Tools panel",
    t: "Active throughput testing",
    b: "New Throughput subtab next to Ping and Traceroute. TCP/UDP, reverse mode (download), 1–60s duration. Live canvas-rendered line chart of throughput-over-time. Color-coded summary cards: avg Mbps, retransmits, jitter, loss. Streaming text log for per-second forensic detail. Bundled iperf3 binary for macOS (Apple Silicon + Intel) and Windows; system $PATH fallback on Linux / Docker.",
    meta: "WebSocket-streamed · 71 tests · SPECTR_IPERF3_PATH override"
  },
  {
    stage: "B0",
    ver: "v0.5.4",
    bg: "var(--accent-green)",
    tier: "Net Intel · SNMP fallback",
    t: "SNMP utilisation overlay",
    b: "Tier-0 fallback that needs no perfSONAR deployment. Green/amber/red colour band on every topology edge, computed from SNMP IF-MIB octet counter deltas (HC 64-bit preferred). Hover tooltip shows in/out percentages + absolute bps. Threshold bands at <50% / <80% / ≥80%; edges with insufficient data stay neutral.",
    meta: "?include=utilisation · +37 tests"
  },
  {
    stage: "B1",
    ver: "v0.5.5",
    bg: "var(--accent-cyan)",
    tier: "Net Intel · perfSONAR clients",
    t: "pScheduler + esmond REST clients",
    b: "Stdlib-only urllib clients for perfSONAR's two REST APIs. Default OFF — quadruple env gate: ENABLED + PSCHEDULER_URL + ESMOND_URL + TRUSTED_HOSTS allowlist. Defense-in-depth PII redaction strips operator contact metadata from every response. URL allowlist re-checked at task-URL boundary. Optional bearer auth via API_KEY.",
    meta: "Air-gap default · +73 tests"
  },
  {
    stage: "B2",
    ver: "v0.5.6",
    bg: "var(--accent-cyan)",
    tier: "Net Intel · perfSONAR overlay",
    t: "Measured throughput on the topology map",
    b: "Second \"perfSONAR\" toggle in the topology toolbar. Edges between registered testpoints paint by measured throughput / latency / loss from esmond's archive. Layers on top of B0: edges without perfSONAR data fall back to SNMP colour, so the operator always sees something. Hover shows \"perfSONAR: 942 Mbps · 1.23 ms · 0.01% loss\".",
    meta: "?include=perfsonar · +24 tests"
  },
  {
    stage: "B3",
    ver: "v0.5.7",
    bg: "var(--accent-purple)",
    tier: "Net Intel · AI tools",
    t: "Historical questions to the analyst",
    b: "Agentic engine catalogue extends from 4 to 6 tools: query_perfsonar_latency and query_perfsonar_throughput. Ask \"what was latency between site A and B last Tuesday?\" or \"did congestion start after the config push?\" — the model picks the right tool, the right window, and answers in concrete numbers. Aggregate stats include count, avg, p50/p95/p99, max, min.",
    meta: "Up to 168h window · +39 tests"
  },
  {
    stage: "B4",
    ver: "v0.5.8",
    bg: "var(--accent-red)",
    tier: "Net Intel · drift correlation",
    t: "Strategic differentiator",
    b: "When Net Intel detects config drift, the correlator automatically: reads pre-drift throughput + latency from esmond, schedules a fresh perfSONAR test on each affected path via pScheduler, polls until the run completes, re-reads esmond for post-drift, persists the before/after delta to the finding. The findings modal renders \"throughput: 1000.0 Mbps → 750.0 Mbps (Δ -25.0%)\" with green/red/muted colour coding past a 5% noise floor.",
    meta: "+24 tests · 1,742 Net Intel total"
  }];

  return (
    <section className="section" id="throughput" style={{ background: "linear-gradient(180deg, transparent 0%, rgba(6,182,212,0.025) 100%)" }}>
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Throughput visibility · iPerf3 + perfSONAR</div>
          <h2 className="section__title">"Ping says good. The app feels bad." Now you can prove which.</h2>
          <p className="section__sub">Six features compose into a complete throughput-investigation workflow — from a one-shot iperf3 test in the Tools panel, to passive SNMP utilisation on the topology map, to perfSONAR-measured edges, AI-driven historical queries, and the differentiator: automatic before/after correlation when Net Intel detects config drift.</p>
        </div>

        <div className="tput-callout">
          <div className="tput-callout__badge">⚡ The differentiator</div>
          <div className="tput-callout__body">
            <strong>Config drift triggers a perfSONAR test. The delta is attached to the finding.</strong> When Net Intel sees a running-config change, the drift correlator auto-schedules a fresh throughput + latency measurement on every affected adjacency, then writes <code>throughput: 1000 → 750 Mbps (Δ -25%)</code> directly onto the drift finding. No other commercial network-monitoring tool does this. Air-gap safe; default off; opt-in via four env vars.
          </div>
        </div>

        <div className="tput-grid">
          {phases.map((p, i) =>
          <div key={i} className="tput-card">
              <div className="tput-card__head">
                <span className="tput-card__stage" style={{ background: p.bg }}>{p.stage}</span>
                <span className="tput-card__ver">{p.ver}</span>
              </div>
              <div className="tput-card__tier">{p.tier}</div>
              <div className="tput-card__title">{p.t}</div>
              <p className="tput-card__body">{p.b}</p>
              <div className="tput-card__meta">{p.meta}</div>
            </div>
          )}
        </div>

        <div className="tput-workflow">
          <div className="tput-workflow__title">An incident walks through every layer of the stack</div>
          <ol className="tput-workflow__steps">
            <li><strong>SNMP utilisation overlay</strong> paints the site-A → site-B edge amber. <span className="tput-workflow__cite">(B0 · passive)</span></li>
            <li><strong>perfSONAR overlay</strong> confirms it's not a counter-flap — same edge paints red on measured throughput. <span className="tput-workflow__cite">(B2 · active)</span></li>
            <li>Operator asks the AI: <em>"what was throughput last Tuesday?"</em> Model calls <code>query_perfsonar_throughput</code> and answers. <span className="tput-workflow__cite">(B3 · historical)</span></li>
            <li>Drift correlator already attached <code>throughput: 1000 → 750 Mbps (Δ -25%)</code> to the change-window finding. <span className="tput-workflow__cite">(B4 · automatic)</span></li>
            <li>After the rollback, Tools → Throughput → one-shot iperf3 confirms the fix is live. <span className="tput-workflow__cite">(iPerf3 · verify)</span></li>
          </ol>
        </div>
      </div>
    </section>);

}
function Enterprise() {
  const items = [
  { t: "RBAC + audit log", b: "4 roles (superadmin / admin / analyst / viewer), JWT-gated REST + WebSocket, full audit trail. Opt-in — single-user mode stays simple." },
  { t: "Multi-tenancy", b: "Tenant-scoped users, rules, schedules, and agents. Superadmin role for cross-tenant visibility. Built for MSSPs and multi-site teams." },
  { t: "PCAP-over-IP remote agents", b: "Single-file standalone agent streams packets to a central server over an authenticated TCP channel. SHA256-hashed, tenant-scoped tokens." },
  { t: "Custom rule builder", b: "9 fields × 16 operators. Build, test, and ship anomaly rules from the UI — no Python required. Live hit-counter via WebSocket; per-rule recent-matches view." },
  { t: "Unified remote agent", b: "One spectr-agent binary. stream subcommand for live PCAP-over-IP; capture for time-boxed field collection with one-shot upload tokens. --save-only for air-gapped sites." },
  { t: "Docker Compose self-host", b: "Multi-stage Dockerfile (non-root, tini PID 1, /data volume, EXPOSE 8765) + compose.yml with /api/auth/config healthcheck. Optional nginx TLS-termination block. SQLite + WAL backend; Litestream-ready." },
  { t: "AI chat history", b: "Server-side persistence, tenant + user scoped, date-bucketed drawer. Resume any conversation. 90-day retention by default; opt-out via env." },
  { t: "Hardened CORS + WS reconnect", b: "v0.4.7 audit closes the wildcard-CORS-with-credentials CSRF amplifier; WebSocket reconnect honours close codes (4401 auth / 4402 license / 4403 forbidden) and the 5-retry give-up. Capture state broadcasts authoritative running / last_error after every start/stop." },
  { t: "Encrypted config snapshots", b: "AES-GCM at rest, reuses the credential vault key. Lazy decrypt with per-instance cache. SHA256 of plaintext keeps drift dedup unchanged. Superadmin migration endpoint for legacy rows. Vault-status banner re-arms on key rotation." }];

  return (
    <section className="section" id="enterprise">
      <div className="container">
        <div className="section__head">
          <div className="section__eyebrow">Enterprise</div>
          <h2 className="section__title">Crafted for a single operator. Scaled for a practice.</h2>
          <p className="section__sub">Auth, RBAC, multi-tenancy, and remote capture — all optional, all backward-compatible with the single-operator default.</p>
        </div>
        <div className="steps fgrid" style={{ gridTemplateColumns: "repeat(3, 1fr)" }}>
          {items.map((i) =>
          <div key={i.t} className="step">
              <h3 className="step__title" style={{ fontSize: 17 }}>{i.t}</h3>
              <p className="step__body">{i.b}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}
function Pricing() {
  return (
    <section className="section" id="pricing">
      <div className="container">
        <div className="section__head section__head--center">
          <div className="section__eyebrow">Pricing</div>
          <h2 className="section__title">A foundation you own. An upgrade when you need it.</h2>
          <p className="section__sub">Packet Intelligence is licensed per analyst seat, per year. Network Intelligence — the active layer for the gear under your team's care — is licensed per managed node, per year, and available to any Packet Intelligence customer.</p>
          <p className="section__sub" style={{ marginTop: 12 }}>Both run in a single install. One stack. One license file.</p>
        </div>
        <div className="pricing">
          <div className="tier">
            <div className="tier__head">
              <div className="tier__name">Packet Intelligence</div>
              <div className="tier__flag" style={{ background: "rgba(109, 213, 140, 0.12)", borderColor: "rgba(109, 213, 140, 0.4)", color: "var(--accent-green, #6dd58c)" }}>Contact sales</div>
            </div>
            <div className="tier__price"><span className="amt amt--label">TBD</span><span className="per">/ year · per seat</span></div>
            <div className="tier__tag">Capture. Understand. Answer. The whole product, one install.</div>
            <ul className="tier__feats">
              <li><strong>Live capture & the PCAP library.</strong> Open anything libpcap-aware. Re-analyze, compare, and export without re-running a session.</li>
              <li><strong>47 protocol parsers.</strong> 29 IT · 9 OT/ICS · 3 IoT · plus the basics. OT is always routed first.</li>
              <li><strong>The AI analyst — local by default.</strong> Claude, Ollama, LM Studio, or SGLang. Cloud is an explicit choice, never the default.</li>
              <li><strong>34 anomaly rules + a custom rule builder.</strong> MITRE ATT&CK mapped — Enterprise and ICS. Every finding cites the packet.</li>
              <li><strong>JA3 / JA3S · JARM · ICS-CERT correlation.</strong> TLS fingerprints and CISA advisories on the way in. Internet not required.</li>
              <li><strong>Behavioral baselines + Purdue zone mapping.</strong> What's normal per device, and what crossed a boundary it shouldn't.</li>
              <li><strong>Four compliance frameworks.</strong> IEC 62443, NERC CIP, NIST CSF, NIS2 — plus an executive summary, on your cadence.</li>
              <li><strong>Network Graph, sequence diagrams, draw.io export.</strong> Blast radius in one click. Reports your team can ship.</li>
              <li><strong>Distributed capture.</strong> Streaming agents, one-shot field tokens, or fully air-gap PCAPs — all into the same library.</li>
              <li><strong>Network tools, built in.</strong> Ping, traceroute, and bundled iPerf3. Throughput problems, proven.</li>
              <li><strong>Multi-tenancy, RBAC, audit log.</strong> Off for solo operators. Ready the day you scale.</li>
              <li><strong>macOS · Linux · Windows · Docker.</strong> Air-gap supported. 14-day trial, no card.</li>
            </ul>
            <a className="btn btn--primary tier__cta" href="#signup">Contact sales <Icon.arrow /></a>
          </div>
          <div className="tier tier--pro">
            <div className="tier__head">
              <div className="tier__name">Network Intelligence</div>
              <div className="tier__flag">Per node</div>
            </div>
            <div className="tier__price"><span className="amt amt--label">TBD</span><span className="per">/ year · per managed node</span></div>
            <div className="tier__tag">Active config / state / drift. SSH · NETCONF · Serial · RESTCONF · SNMP. Runs in the same install.</div>
            <ul className="tier__feats">
              <li><strong>5 vendors:</strong> Cisco IOS / NX-OS, Arista EOS, Juniper JunOS, Fortinet</li>
              <li><strong>5 transports:</strong> SSH · NETCONF · Serial · RESTCONF · SNMP v2c/v3</li>
              <li><strong>Pattern C hybrid</strong> — SSH for configs + SNMP for state</li>
              <li>Auto-discovery (CDP/LLDP) + SNMP vendor fingerprint endpoint</li>
              <li><strong>perfSONAR integration</strong> — utilisation overlay, measured overlay, AI tools</li>
              <li><strong>Drift correlation</strong> — auto pre/post throughput delta on config drift</li>
              <li><strong>Config risk engine</strong> — 10 deterministic rules + LLM per-vendor</li>
              <li><strong>Agentic troubleshoot</strong> — 7 playbooks + 6 tools (incl. perfSONAR)</li>
              <li><strong>CVE + SBOM</strong> (CycloneDX 1.4 / SPDX 2.3) · NERC CIP-010 PDF</li>
              <li>Topology (VLAN · STP · 👑 root-bridge · utilisation · perfSONAR)</li>
              <li>JSONL transcript · encrypted snapshots · maintenance windows · 1,742 tests</li>
            </ul>
            <a className="btn btn--primary tier__cta" href="#signup">Contact sales <Icon.arrow /></a>
          </div>
        </div>
      </div>
    </section>);

}
function Signup() {
  const [state, setState] = useState({ email: "", role: "", env: "", note: "", submitted: false, error: "", busy: false });

  // Pick the API endpoint based on host. Override at runtime by setting
  // window.__SPECTR_API__ = "https://api.example.com" before bundle.jsx loads.
  const API_BASE = typeof window !== "undefined" && window.__SPECTR_API__ || (
  typeof window !== "undefined" && /(^|\.)rex-labs\.tech$/.test(window.location.hostname) ?
  "https://api.rex-labs.tech" :
  "");

  async function submit(e) {
    e.preventDefault();
    if (!state.email || !state.email.includes("@")) {
      setState((s) => ({ ...s, error: "Enter a valid email address." }));
      return;
    }
    setState((s) => ({ ...s, busy: true, error: "" }));

    // Always stash locally as a fallback so we never lose a lead.
    try {
      const list = JSON.parse(localStorage.getItem("spectr_signups") || "[]");
      list.push({ email: state.email, role: state.role, env: state.env, note: state.note, ts: Date.now() });
      localStorage.setItem("spectr_signups", JSON.stringify(list));
    } catch (_) {}

    // POST to the signup API. If the API isn't reachable we still show success
    // (the lead is in localStorage and the form is honest about reaching out).
    try {
      if (API_BASE) {
        const res = await fetch(API_BASE + "/api/signup", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            email: state.email,
            role: state.role,
            env: state.env,
            note: state.note,
            source: window.location.hostname,
            website: "" // honeypot
          })
        });
        if (!res.ok) {
          const j = await res.json().catch(() => ({}));
          setState((s) => ({ ...s, busy: false, error: j.error || "Could not send. Please try again or email spectr@rex-labs.tech." }));
          return;
        }
      }
    } catch (err) {
      setState((s) => ({ ...s, busy: false, error: "Network error. Please try again or email spectr@rex-labs.tech." }));
      return;
    }

    setState((s) => ({ ...s, submitted: true, busy: false, error: "" }));
  }

  return (
    <section className="section signup" id="signup">
      <div className="container">
        <div className="signup__grid">
          <div className="signup__copy">
            <div className="section__eyebrow">Early access</div>
            <h2 className="section__title">Join early.</h2>
            <div className="signup__offer">
              <div className="signup__offer-badge">Early adopter</div>
              <div className="signup__offer-body">
                <strong>Second year free</strong> for everyone who joins the list before GA. One year paid, one year on us — same product, same support, same license.
              </div>
            </div>
            <p className="section__sub">SPECTR 0.6.0 + Net Intel 1.7.0 are in late beta. Join the early-access list and we'll reach out with pricing, a demo, and a license for your environment. We don't blast — typically one email when there's something specific to share.</p>
            <ul className="signup__bullets">
              <li><span className="tick">✓</span> Pricing and per-seat / per-node terms</li>
              <li><span className="tick">✓</span> Live demo against your traffic profile</li>
              <li><span className="tick">✓</span> Air-gap deployment guidance</li>
              <li><span className="tick">✓</span> Or just early-access updates — your call</li>
            </ul>
          </div>

          <form className="signup__form" onSubmit={submit} noValidate>
            {state.submitted ?
            <div className="signup__ok">
                <div className="signup__ok-icon">✓</div>
                <div>
                  <div className="signup__ok-title">You're on the list.</div>
                  <div className="signup__ok-body">We'll reach out at <strong>{state.email}</strong>. Reply directly to that first email if you want to schedule a demo sooner.</div>
                </div>
                <button type="button" className="btn btn--ghost btn--sm" onClick={() => setState({ email: "", role: "", env: "", note: "", submitted: false, error: "" })}>Add another</button>
              </div> :

            <>
                <div className="signup__field signup__field--full">
                  <label htmlFor="su-email">Work email <span className="req">*</span></label>
                  <input id="su-email" type="email" autoComplete="email" required placeholder="you@company.com"
                value={state.email} onChange={(e) => setState((s) => ({ ...s, email: e.target.value, error: "" }))} />
                </div>

                <div className="signup__field">
                  <label htmlFor="su-role">Role</label>
                  <select id="su-role" value={state.role} onChange={(e) => setState((s) => ({ ...s, role: e.target.value }))}>
                    <option value="">Select…</option>
                    <option>Security engineer / analyst</option>
                    <option>Network / OT engineer</option>
                    <option>SOC manager / CISO</option>
                    <option>MSSP / consultant</option>
                    <option>Other</option>
                  </select>
                </div>

                <div className="signup__field">
                  <label htmlFor="su-env">Environment</label>
                  <select id="su-env" value={state.env} onChange={(e) => setState((s) => ({ ...s, env: e.target.value }))}>
                    <option value="">Select…</option>
                    <option>Enterprise IT</option>
                    <option>OT / ICS / SCADA</option>
                    <option>Mixed IT + OT</option>
                    <option>IoT / consumer</option>
                    <option>MSSP / multi-tenant</option>
                  </select>
                </div>

                <div className="signup__field signup__field--full">
                  <label htmlFor="su-note">Anything specific? <span className="opt">(optional)</span></label>
                  <textarea id="su-note" rows="3" placeholder="Use case, deployment size, timeline…"
                value={state.note} onChange={(e) => setState((s) => ({ ...s, note: e.target.value }))} />
                </div>

                {state.error && <div className="signup__error">{state.error}</div>}

                <div className="signup__actions">
                  <button type="submit" className="btn btn--primary" disabled={state.busy}>
                    {state.busy ? "Sending…" : <>Join the list <Icon.arrow /></>}
                  </button>
                  <span className="signup__fineprint">No spam. Unsubscribe in one click. Read by a human.</span>
                </div>
              </>
            }
          </form>
        </div>
      </div>
    </section>);

}

function WhatsNew() {
  const items = [
  {
    tag: "0.6.0",
    date: "2026-05-16",
    title: "perfSONAR hardening sprint",
    body: "Five HIGH-priority follow-ups closed: drift-correlation cleanup on device/finding delete, non-blocking urlopen wrapped in asyncio.to_thread, idempotent INSERT OR REPLACE on drift rows, server-startup hook tested, schema migrations tested.",
    meta: "+17 tests · 1,742 Net Intel"
  },
  {
    tag: "0.5.9",
    date: "2026-05-16",
    title: "perfSONAR SSRF hotfix",
    body: "CRITICAL: esmond Step-2 fetch previously followed an absolute URL without re-checking the host against TRUSTED_HOSTS — a hostile esmond could redirect SPECTR at AWS IMDS or internal admin endpoints. Closed with _is_url_trusted re-check on every absolute URI.",
    meta: "+3 regression tests"
  },
  {
    tag: "0.5.8",
    date: "2026-05-15",
    title: "Drift correlation (B4) — strategic differentiator",
    body: "Net Intel detects config drift → automatically schedules a perfSONAR throughput + latency test on every affected path, persists pre/post deltas to the finding. \"throughput: 1000 → 750 Mbps (Δ -25%)\" appears in the findings modal.",
    meta: "perfSONAR plan complete"
  },
  {
    tag: "0.5.3",
    date: "2026-05-15",
    title: "iPerf3 throughput testing in Tools",
    body: "New Throughput subtab. TCP/UDP, reverse mode, live canvas chart of throughput-over-time, color-coded summary cards. Bundled iperf3 binary for macOS (Apple Silicon + Intel) and Windows. WebSocket-streamed events.",
    meta: "+71 tests · bundled binary"
  }];

  return (
    <section className="section section--tight" id="whatsnew" style={{ borderTop: 0, paddingTop: 40, paddingBottom: 40 }}>
      <div className="container">
        <div className="section__head" style={{ marginBottom: 24 }}>
          <div className="section__eyebrow">What's new · changelog</div>
          <h2 className="section__title">SPECTR 0.6.0 · Net Intel 1.7.0</h2>
          <p className="section__sub">Eight releases shipped the full throughput-visibility stack — active iPerf3 testing in Tools, plus a five-phase perfSONAR integration culminating in automatic drift correlation. Capped by an SSRF hotfix and the v0.6.0 hardening sprint.</p>
        </div>
        <div className="whatsnew">
          {items.map((it, i) => {
            const isNi = it.tag.startsWith("1") || ["0.5.8", "0.5.7", "0.5.6", "0.5.5", "0.5.4", "0.5.9", "0.6.0"].includes(it.tag);
            return (
              <div key={i} className={`whatsnew__card whatsnew__card--${isNi ? "ni" : "core"}`}>
                <div className="whatsnew__head">
                  <span className="whatsnew__tag">{it.tag.startsWith("1") ? `Net Intel ${it.tag}` : `SPECTR ${it.tag}`}</span>
                  <span className="whatsnew__date">{it.date}</span>
                </div>
                <div className="whatsnew__title">{it.title}</div>
                <p className="whatsnew__body">{it.body}</p>
                <div className="whatsnew__meta">{it.meta}</div>
              </div>);

          })}
        </div>
      </div>
    </section>);

}

function NetIntelDivider() {
  return (
    <section className="ni-divider" aria-label="Network Intelligence section start">
      <div className="container ni-divider__inner">
        <div className="ni-divider__rule" aria-hidden="true" />
        <div className="ni-divider__core">
          <div className="ni-divider__eyebrow">Part 02 · separately licensed product</div>
          <div className="ni-divider__title">
            <span>Net Intelligence</span>
            <span className="ni-divider__sep">·</span>
            <span className="ni-divider__sub">Active network management for the same fleet</span>
          </div>
          <div className="ni-divider__meta">5 transports · 5 vendors · perfSONAR · CVE · SBOM · NERC CIP-010</div>
        </div>
        <div className="ni-divider__rule" aria-hidden="true" />
      </div>
    </section>);

}

/* HomePage */
function HomePage() {
  const defaults = window.__SPECTR_TWEAKS__ || { tagline: "see_everything", hero_variant: "centered" };
  const [tagline, setTagline] = useState(defaults.tagline || "see_everything");
  const [heroVariant, setHeroVariant] = useState(defaults.hero_variant || "centered");
  const [tweaksOpen] = useEditMode();

  return (
    <>
      <div className="grid-bg" />
      <div className="page">
        <Header current="home" />
        <Hero tagline={tagline} variant={heroVariant} />
        <ProductCaption />
        <HowItWorks />
        <Coverage />
        <AnomalyShowcase />
        <AIIntelligence />
        <Compare />
        <Privacy />
        <WhatsNew />
        <NetIntelDivider />
        <NetIntel />
        <Throughput />
        <Compliance />
        <Enterprise />
        <Pricing />
        <Signup />
        <Footer />
      </div>
      <TweaksPanel
        open={tweaksOpen}
        tagline={tagline}
        onTagline={(v) => {setTagline(v);persist("tagline", v);}}
        heroVariant={heroVariant}
        onHero={(v) => {setHeroVariant(v);persist("hero_variant", v);}} />
      
    </>);

}


window.HomePage = HomePage;