// Snare landing page — main composition
const { useState, useEffect, useRef } = React;

// Field Reports — threat-actor intel (Tier 1 static, schema future-proofed for Tier 2 OSINT pull).
// Source-of-truth markdown lives at /content/threats/*.md. This array mirrors the front-matter
// of those files so the no-build prototype can render without a fetch/parse step. To promote to
// Tier 2: replace this array with the result of a fetch to a Cloudflare Worker that scrapes
// OSINT feeds + emits this same shape on a daily cron.
const FIELD_REPORTS = [
  {
    slug: '2026-04-30-payments-phishing-kit-cellnumber-incorporation',
    title: 'Phishing kit incorporating fresh customer cellphone numbers from a payment-processor breach',
    publishedAt: '2026-04-30',
    updatedAt: '2026-05-02',
    status: 'monitoring',
    severity: 'high',
    threatActor: { name: 'Unknown — kit author', region: 'VN-speaking forum, infra HK' },
    sectorTargeted: ['payments', 'card-issuing'],
    channels: ['sms-phishing', 'fake-bank-app', 'otp-relay'],
    seededRecordsTriggered: 2,
    iocs: [
      'short-code-rotation:UK/+44-shadow',
      'apk-host:bankapp-secure-v2[.]click',
      'otp-relay-c2:hk-host-203.0.113[.]14',
    ],
    excerpt: "Two Snare-seeded payment-customer profiles received SMS phishing referencing real card-last-4 digits — a level of personalization indicating a fresh breach. Kit traced to a private forum; source data still unclear. Active monitoring.",
  },
  {
    slug: '2026-04-22-tg-blacksuit-broker-vip-resale',
    title: 'Telegram channel "BlackSuit" reselling EU broker VIP client lists',
    publishedAt: '2026-04-22',
    updatedAt: '2026-04-25',
    status: 'active',
    severity: 'critical',
    threatActor: { name: 'BlackSuit Curator', region: 'EE / RU-speaking' },
    sectorTargeted: ['broker', 'vip-tier'],
    channels: ['telegram', 'darkweb-forum'],
    seededRecordsTriggered: 3,
    iocs: [
      'telegram:@blacksuit_vip',
      'forum-thread:exploit[.]in/thread-882104',
      'btc-payout:bc1qexample-redacted',
    ],
    excerpt: 'Three seeded VIP profiles surfaced on a 200-member private Telegram channel within 11 days of CRM injection — priced per-record by net-worth tier, paid in crypto, resold to competitor outreach within 72 hours.',
  },
  {
    slug: '2026-03-14-me-casino-sms-cold-outreach',
    title: 'Russian-language gaming syndicate cold-SMS-ing seeded ME casino VIPs',
    publishedAt: '2026-03-14',
    updatedAt: '2026-04-04',
    status: 'resolved',
    severity: 'medium',
    threatActor: { name: 'Unknown gaming network', region: 'EE / infra in BG' },
    sectorTargeted: ['casino', 'vip-tier'],
    channels: ['sms', 'phone-call'],
    seededRecordsTriggered: 4,
    iocs: [
      'sms-from:+44-7700-900-184',
      'voice-cli:rotating-bg-gateway',
      'landing-page:vip-bonus-week-only[.]net',
    ],
    excerpt: 'Four seeded VIP-tier casino profiles received cold SMS within 14 days of seed activation. Outreach copy referenced segment-specific bonus offers; narrowed to outsourced support team in Sofia. Resolved in three weeks.',
  },
];

function formatReportDate(iso) {
  const d = new Date(iso + 'T00:00:00Z');
  return d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).toUpperCase();
}

function App() {
  const tweaks = window.useTweaks ? window.useTweaks(window.SNARE_DEFAULTS) : [window.SNARE_DEFAULTS, () => {}];
  const [tw, setTw] = tweaks;
  const [demoOpen, setDemoOpen] = useState(false);
  const [submitted, setSubmitted] = useState(false);

  // reveal-on-scroll
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);

  // headline variant — index 0 (Always on…) is also the rotating slot
  const headlines = [
    { plain: 'Always on.', em: 'Never noticed.' },
    { plain: 'The leak is already out.', em: 'Snare finds out who.' },
    { plain: 'Bait the leak.', em: 'Trace the source.' },
    { plain: 'Your CRM is leaking.', em: 'Snare names the employee.' },
  ];

  // When tweak is at default (0), rotate per session/visitor instead of always showing 0.
  // Persist a single random pick in sessionStorage so the headline is stable for the visit
  // but different visitors land on different lines.
  const [rotatedIdx] = useState(() => {
    if (typeof window === 'undefined') return 0;
    try {
      const k = 'snare.headline.session';
      const stored = sessionStorage.getItem(k);
      if (stored !== null) return Number(stored);
      const pick = Math.floor(Math.random() * headlines.length);
      sessionStorage.setItem(k, String(pick));
      return pick;
    } catch { return Math.floor(Math.random() * headlines.length); }
  });

  // If the editor explicitly sets a headline (non-zero), honor it. If 0 (the rotating sentinel),
  // serve the random per-session pick.
  const effectiveIdx = (tw.headline === 0 || tw.headline == null) ? rotatedIdx : tw.headline;
  const hl = headlines[effectiveIdx] || headlines[0];

  // Trusted-by section headline — same per-session-rotation pattern as the hero, with a
  // separate sessionStorage key so the two don't collide. Each visitor gets one random
  // line stable across the visit but different across visitors / new browser sessions.
  const trustedHeadlines = [
    { plain: 'The kind of incident nobody talks about', em: 'until somebody traces it.' },
    { plain: 'The kind of incident nobody talks about', em: 'until somebody names the source.' },
    { plain: 'The leaks nobody admits to', em: 'until somebody surfaces them.' },
    { plain: "Incidents your peers don't disclose —", em: 'we find, name, and trace.' },
  ];
  const [trustedIdx] = useState(() => {
    if (typeof window === 'undefined') return 0;
    try {
      const k = 'snare.trusted.session';
      const stored = sessionStorage.getItem(k);
      if (stored !== null) return Number(stored);
      const pick = Math.floor(Math.random() * trustedHeadlines.length);
      sessionStorage.setItem(k, String(pick));
      return pick;
    } catch { return Math.floor(Math.random() * trustedHeadlines.length); }
  });
  const trustedHL = trustedHeadlines[trustedIdx] || trustedHeadlines[0];

  // Three-tier accent override — Chrome caches computed values for var() in some
  // browsers when --accent is changed dynamically. We emit a stylesheet that hardcodes
  // each accent color into the rules that use it, overriding var() expressions entirely.
  // Roles per Snare design language: signal-orange (primary brand), ember (CTAs),
  // oxblood (incident / alert UI).
  useEffect(() => {
    const id = 'snare-accent-override';
    let el = document.getElementById(id);
    if (!el) {
      el = document.createElement('style');
      el.id = id;
      document.head.appendChild(el);
    }
    // Fallbacks below MUST mirror the EDITMODE-fenced SNARE_DEFAULTS block in
    // Snare.html and Snare-standalone-src.html. If you change one, change all three —
    // they each have a different reason to live (HTML = on-disk source of truth for
    // the host bundler; CSS :root = static base value; here = runtime safety net).
    const accent = tw.accent || '#FF6A00';
    const ember = tw.accentCta || '#D4622A';
    const oxblood = tw.accentIncident || '#B8412A';
    el.textContent = `
      :root {
        --accent: ${accent} !important;
        --accent-cta: ${ember} !important;
        --accent-incident: ${oxblood} !important;
        --danger: ${oxblood} !important;
      }
      ::selection { background: ${accent} !important; color: var(--bg) !important; }
      .accent { color: ${accent} !important; }
      .brand-word em { color: ${accent} !important; }
      .hero-h1 em { color: ${accent} !important; }
      .hero-anim-header .live-dot { background: ${accent} !important; }
      .stat-counter .val,
      .stat-counter .val .unit { color: ${accent} !important; }
      .how-header h2 em { color: ${accent} !important; }
      .frame-num strong { color: ${accent} !important; }
      .frame-example .hl { color: ${accent} !important; }
      .proof-quote .mark { color: ${accent} !important; }
      .proof-metric .num { color: ${accent} !important; }
      .cmp-table th.snare-col { color: ${accent} !important; }
      .cmp-table .check.hot { color: ${accent} !important; }
      .deploy h2 em { color: ${accent} !important; }
      .sec-head h2 em { color: ${accent} !important; }
      .trusted-line em, .trusted-headline em { color: ${accent} !important; }

      /* Ember — CTAs / hot states */
      .nav-cta:hover { border-color: ${ember} !important; }
      .nav-cta-primary,
      .nav-cta-primary:hover,
      .nav-cta-primary:focus,
      .nav-cta-primary:active {
        background-color: ${ember} !important;
        border-color: ${ember} !important;
      }
      .btn-primary { background: ${ember} !important; border-color: ${ember} !important; }
      .field input:focus, .field select:focus, .field textarea:focus { border-bottom-color: ${ember} !important; }
      .contact-success { border-color: ${ember} !important; color: ${ember} !important; }

      /* Oxblood — incident states (only true alert/incident UI uses oxblood). */
      .incident, .incident-tag { color: ${oxblood} !important; }
    `;
  }, [tw.accent, tw.accentCta, tw.accentIncident]);

  // Apply body-level classes for tweak variants
  useEffect(() => {
    const b = document.body;
    b.className = [
      `serif-${tw.serif || 'newsreader'}`,
      `voice-${tw.voice || 'operator'}`,
      `density-${tw.diagramDensity || 'current'}`,
      `cmp-tone-${tw.tableTone || 'neutral'}`,
      tw.formLayout === 'split' ? 'form-split' : '',
      tw.torch ? 'torch-on' : '',
    ].filter(Boolean).join(' ');
  }, [tw.serif, tw.voice, tw.diagramDensity, tw.tableTone, tw.formLayout, tw.torch]);

  const ctaCopyMap = { book: 'Book a call →', access: 'Request access →', see: 'See it bait one →' };
  const ctaCopy = ctaCopyMap[tw.ctaCopy] || ctaCopyMap.book;

  return (
    <div className="page">
      {window.ScrollAtmosphere ? <window.ScrollAtmosphere tw={tw} /> : null}
      <Nav onCta={() => document.getElementById('contact').scrollIntoView({ behavior: 'smooth' })} ctaCopy={ctaCopy} brandMark={tw.brandMark || 'crosshair'} />

      {/* HERO */}
      <section className="hero" id="hero">
        <div className="hero-video-wrap">
          <PingPongVideo src="uploads/trapdoor-spider-hero.mp4" />
          <div className="hero-video-overlay"></div>
          <div className="hero-video-grain"></div>
        </div>

        <div className="container hero-inner-v2">
          <div className="hero-copy-v2 reveal">
            <div className="section-label">Snare / Insider Exfiltration Intelligence</div>
            <h1 className="serif hero-h1">
              {hl.plain}<br/><em>{hl.em}</em>
            </h1>
            <p className="hero-sub">
              Synthetic-PII honeytokens, seeded into your CRM. They surface where your customer data ends up — and trace it back to the source.
            </p>
            <div className="cta-row">
              <button className="btn btn-primary" onClick={() => setDemoOpen(true)}>
                See it catch a leak <span className="arr">→</span>
              </button>
              <a className="btn btn-ghost" href="#contact">
                Book a 20-min call <span className="arr">→</span>
              </a>
            </div>
          </div>

          <aside className="hero-feed reveal">
            <window.HeroAnim />
          </aside>
        </div>

        <div className="container">
          <div className="hero-foot reveal">
            <div className="hero-foot-item">
              <div className="lbl">Detection median</div>
              <div className="val">11 days</div>
            </div>
            <div className="hero-foot-item">
              <div className="lbl">Industry average</div>
              <div className="val">227 days</div>
            </div>
            <div className="hero-foot-item">
              <div className="lbl">False positives</div>
              <div className="val">0</div>
            </div>
            <div className="hero-foot-item">
              <div className="lbl">Endpoints touched</div>
              <div className="val">None</div>
            </div>
          </div>
        </div>
      </section>

      {/* SECTION 2 — the number */}
      <section className="stat-section">
        <div className="container">
          <div className="reveal" style={{ display: 'inline-block' }}>
            <div className="section-label" style={{ justifyContent: 'center' }}>Detection · 02</div>
          </div>
          <div className="stat-big serif reveal">
            227<span className="unit"> days</span>
          </div>
          <p className="stat-caption reveal">
            Industry average time-to-detect for an insider data leak. By then, your client list has been resold three times.
          </p>
          <div className="stat-source reveal">
            <a href="https://www.ibm.com/reports/data-breach" target="_blank" rel="noopener noreferrer">IBM Cost of a Data Breach Report 2025 ↗</a>
          </div>
          <div className="stat-counter reveal">
            <div className="small">Snare median</div>
            <div className="val serif">11<span className="unit"> days</span></div>
          </div>
        </div>
      </section>

      {/* SECTION 3 — How */}
      <section className="how-section" id="how">
        <div className="container">
          <div className="how-header reveal">
            <div className="section-label">How it works · 03</div>
            <div>
              <h2 className="serif">Seed. Detect. <em>Trace.</em></h2>
              <p>Three stages. No agents on endpoints. No copy/paste required for detection. Works on data that has already left your perimeter.</p>
            </div>
          </div>

          <div className="frame reveal">
            <div>
              <div className="frame-num"><strong>01</strong> · Seed</div>
              <h3 className="frame-title serif">Synthetic identities, indistinguishable from real customers.</h3>
              <p className="frame-desc">
                Snare injects synthetic records into your CRM, call-center, and support stack — fake names, real-looking emails on owned domains, real working phone numbers via Twilio, plausible addresses. To the insider browsing the CRM, they look identical to real high-value customers.
              </p>
            </div>
            <div className="frame-vis"><window.SeedDiagram /></div>
            <div>
              <div className="section-label" style={{ marginBottom: 12 }}>Sample seeded record</div>
              <pre className="frame-example" dangerouslySetInnerHTML={{ __html:
`<span class="com"># crm.accounts (synthetic)</span>
<span class="key">account_id</span>:   <span class="hl">ACC-882104</span>
<span class="key">name</span>:         Marek Kovacs
<span class="key">email</span>:        m.kovacs+a3f2@bayhill.co
<span class="key">phone</span>:        +43 720 884 271   <span class="com"># live SIM</span>
<span class="key">region</span>:       Vienna, AT
<span class="key">segment</span>:      VIP-Tier · 480k EUR
<span class="key">source</span>:       <span class="hl">snare/seed.v3</span>`
              }} />
            </div>
          </div>

          <div className="frame reveal">
            <div>
              <div className="frame-num"><strong>02</strong> · Detect</div>
              <h3 className="frame-title serif">Surveillance across the surfaces leaks travel through.</h3>
              <p className="frame-desc">
                Telegram channels. Russian-language darkweb markets. Competitor SMS outreach. Phishing kits resold in private forums. Breached-data dumps. When a seeded identity receives an email, SMS, or call — Snare knows immediately, and which exact synthetic record was used.
              </p>
            </div>
            <div className="frame-vis"><window.DetectDiagram /></div>
            <div>
              <div className="section-label" style={{ marginBottom: 12 }}>Capture event</div>
              <pre className="frame-example" dangerouslySetInnerHTML={{ __html:
`<span class="com">[2026-04-22 14:22:41Z] inbound</span>
<span class="key">channel</span>:     sms / +44 7700 900 184
<span class="key">to</span>:          +43 720 884 271
<span class="key">match</span>:       <span class="hl">m.kovacs+a3f2 · ACC-882104</span>
<span class="key">payload</span>:     "Mr Kovacs — exclusive
              FX bonus this week only…"
<span class="key">trace</span>:       <span class="hl">→ engage</span>`
              }} />
            </div>
          </div>

          <div className="frame reveal">
            <div>
              <div className="frame-num"><strong>03</strong> · Trace</div>
              <h3 className="frame-title serif">An AI persona engages on the channel — quietly.</h3>
              <p className="frame-desc">
                A locally-hosted Qwen-class model takes the persona and replies in voice. It captures attacker infrastructure, language patterns, tooling, and payment requests — then cross-references which synthetic record was exposed against CRM access logs to name the specific employee or compromised system.
              </p>
            </div>
            <div className="frame-vis"><window.TraceDiagram /></div>
            <div>
              <div className="section-label" style={{ marginBottom: 12 }}>Attribution report (redacted)</div>
              <pre className="frame-example" dangerouslySetInnerHTML={{ __html:
`<span class="com"># incident.r-882104.attribution</span>
<span class="key">leaked_record</span>: ACC-882104 (synthetic)
<span class="key">crm_access</span>:    7 employees within window
<span class="key">narrowed_by</span>:   segment · region · last-touch
<span class="key">named_source</span>:  <span class="hl">agent_id 0473</span>
<span class="key">team</span>:          ███████ · outsourced (BG)
<span class="key">ttps</span>:          screen-photo · personal phone
<span class="key">days_to_detect</span>: <span class="hl">11</span>`
              }} />
            </div>
          </div>
        </div>
      </section>

      {/* SECTION 4 — Trusted by */}
      <section className="trusted-section" id="proof">
        <div className="container">
          <div className="sec-head reveal">
            <div className="section-label">Trusted by · 04</div>
            <h2 className="serif">{trustedHL.plain} <em>{trustedHL.em}</em></h2>
            <p>Trusted by payment processors, regulated brokers, and leading casino operators across the EU, UK, and Middle East. Client names withheld by contract — references available under NDA.</p>
          </div>

          {/* Anonymized sector lockup */}
          <div className="exemplar-grid reveal">
            <div className="exemplar-card">
              <div className="exemplar-glyph serif">B</div>
              <div className="exemplar-sector">Banks</div>
              <div className="exemplar-meta">EU · UK · ME</div>
            </div>
            <div className="exemplar-card">
              <div className="exemplar-glyph serif">Br</div>
              <div className="exemplar-sector">Brokers</div>
              <div className="exemplar-meta">FX · Equities · Crypto</div>
            </div>
            <div className="exemplar-card">
              <div className="exemplar-glyph serif">C</div>
              <div className="exemplar-sector">Casinos</div>
              <div className="exemplar-meta">EU-licensed</div>
            </div>
            <div className="exemplar-card">
              <div className="exemplar-glyph serif">P</div>
              <div className="exemplar-sector">Payment processors</div>
              <div className="exemplar-meta">Card · ACH · SEPA</div>
            </div>
          </div>

          {/* Quantitative stamp */}
          <div className="exemplar-stamp reveal">
            <div className="exemplar-stamp-row">
              <strong className="serif">4</strong>
              <span>of EU's top-10 regulated brokers</span>
            </div>
            <div className="exemplar-stamp-row">
              <strong className="serif">3</strong>
              <span>EU-licensed casino operators</span>
            </div>
            <div className="exemplar-stamp-row">
              <strong className="serif">2</strong>
              <span>payment processors with cross-border PII flows</span>
            </div>
          </div>

          {/* Redacted case-study cards */}
          <div className="exemplar-cases reveal">
            <article className="case-card">
              <div className="case-meta">
                <span className="case-tag">Broker · 2026 Q1 · EU</span>
              </div>
              <h3 className="serif">Snare-seeded VIP record surfaced in a private Telegram channel within <em>11 days</em>.</h3>
              <p>Client list resold to a competitor outreach team. Snare narrowed the leak by segment and last-touch to a single CRM agent on a regional support team. Capture data and attribution delivered to client IR within 36 hours of seed activation.</p>
              <div className="case-foot">
                <span className="case-meta-item">Days to detect <strong>11</strong></span>
                <span className="case-meta-item">Channel <strong>Telegram</strong></span>
                <span className="case-meta-item">Attribution <strong>Named agent</strong></span>
              </div>
            </article>
            <article className="case-card">
              <div className="case-meta">
                <span className="case-tag">Casino · 2025 Q4 · ME</span>
              </div>
              <h3 className="serif">Three seeded VIP profiles received cold SMS outreach from a Russian-language gaming network.</h3>
              <p>Cross-referenced against CRM access logs over a 14-day window — narrowed to an outsourced support team in Sofia. Engagement persona collected attacker tooling, payment infrastructure, and the resale price list.</p>
              <div className="case-foot">
                <span className="case-meta-item">Days to detect <strong>14</strong></span>
                <span className="case-meta-item">Channel <strong>SMS</strong></span>
                <span className="case-meta-item">Attribution <strong>Outsourced team</strong></span>
              </div>
            </article>
          </div>
        </div>
      </section>

      {/* SECTION 5 — compare */}
      <section className="compare-section" id="compare">
        <div className="container">
          <div className="sec-head reveal">
            <div className="section-label">DLP &amp; SIEM blind spots · 05</div>
            <h2 className="serif">Why this works <em>when DLP doesn't.</em></h2>
            <p>Traditional controls watch your perimeter. Snare watches what comes back through other people's channels.</p>
          </div>

          <table className="cmp-table reveal">
            <thead>
              <tr>
                <th>Capability</th>
                <th>Traditional DLP</th>
                <th>SIEM rules</th>
                <th className="snare-col">Snare</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td className="cap">Detects exfil while data is on your network</td>
                <td className="check">✓</td>
                <td className="check">✓</td>
                <td className="dash">—</td>
              </tr>
              <tr>
                <td className="cap">Detects exfil <em>after</em> data has left your perimeter</td>
                <td className="dash">—</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Detects exfil on company-sensitive PII data</td>
                <td className="partial">partial</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Every alert is a real incident (no false positives)</td>
                <td className="dash">—</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Works on data accessed via call-center screens (no copy/paste)</td>
                <td className="dash">—</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Works on data screenshotted, photographed, or memorized</td>
                <td className="dash">—</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Attributes leak to specific employee or system</td>
                <td className="partial">partial</td>
                <td className="partial">partial</td>
                <td className="check hot">✓</td>
              </tr>
              <tr>
                <td className="cap">Captures attacker infrastructure &amp; TTPs</td>
                <td className="dash">—</td>
                <td className="dash">—</td>
                <td className="check hot">✓</td>
              </tr>
            </tbody>
          </table>
        </div>
      </section>

      {/* SECTION 6 — Field Reports (threat-actor intel, Tier 1 static) */}
      <section className="field-reports-section" id="reports">
        <div className="container">
          <div className="sec-head reveal">
            <div className="section-label">Field Reports · 06</div>
            <h2 className="serif">What our deployed sensors are <em>actively watching.</em></h2>
            <p>Pulled from active customer honeytoken triggers — anonymized for publication. Curated weekly. Each report is a real seeded-record activation, attribution, and response.</p>
          </div>

          <div className="reports-grid reveal">
            {FIELD_REPORTS.map((r) => (
              <article key={r.slug} className={`report-card status-${r.status}`}>
                <header className="report-card-meta">
                  <span className={`report-status status-${r.status}`}>
                    <span className="report-status-dot"></span>
                    {r.status}
                  </span>
                  <span className="report-date">{formatReportDate(r.publishedAt)}</span>
                </header>
                <h3 className="serif report-title">{r.title}</h3>
                <p className="report-excerpt">{r.excerpt}</p>
                <dl className="report-tags">
                  <div>
                    <dt>Threat actor</dt>
                    <dd>{r.threatActor.name} <span className="dim">· {r.threatActor.region}</span></dd>
                  </div>
                  <div>
                    <dt>Sector</dt>
                    <dd>{r.sectorTargeted.join(' · ')}</dd>
                  </div>
                  <div>
                    <dt>Channels</dt>
                    <dd>{r.channels.join(' · ')}</dd>
                  </div>
                  <div>
                    <dt>Seeds triggered</dt>
                    <dd><strong>{r.seededRecordsTriggered}</strong></dd>
                  </div>
                </dl>
              </article>
            ))}
          </div>

          <div className="reports-foot reveal">
            <span className="reports-foot-meta">Field Reports updated weekly · Anonymized at publication · Customer detail under NDA</span>
            <a className="reports-foot-cta" href="#contact">Subscribe via 20-min call →</a>
          </div>
        </div>
      </section>

      {/* SECTION 7 — Contact */}
      <section className="contact-section" id="contact">
        <div className="container contact-grid">
          <div className="deploy reveal">
            <div className="section-label">Deploy · 07</div>
            <h2 className="serif">Two to four weeks. <em>No agents.</em></h2>
            <p className="deploy-text">
              Runs as a managed service or on-prem appliance. Integrates with Salesforce, HubSpot, Dynamics, Zendesk, Genesys, Five9, AWS Connect, and most custom CRMs via API. Data residency: EU, US, or customer-controlled.
            </p>
            <div className="deploy-meta">
              <div className="row"><span className="k">Deploy time</span><span className="v">2–4 weeks</span></div>
              <div className="row"><span className="k">Endpoint agents</span><span className="v">None</span></div>
              <div className="row"><span className="k">Data residency</span><span className="v">EU · US · Self</span></div>
              <div className="row"><span className="k">Integration</span><span className="v">API · No agents</span></div>
            </div>
          </div>

          <div className="contact-form reveal">
            <h3 className="serif">Book a 20-min technical call.</h3>
            <p className="h-sub">Architect-to-architect. No SDR.</p>
            {!submitted ? (
              <form onSubmit={(e) => { e.preventDefault(); setSubmitted(true); }}>
                <div className="field">
                  <label>Work email</label>
                  <input type="email" required placeholder="you@firm.com" />
                </div>
                <div className="field-row">
                  <div className="field">
                    <label>Company</label>
                    <input type="text" required placeholder="Acme Capital" />
                  </div>
                  <div className="field">
                    <label>Role</label>
                    <select required defaultValue="">
                      <option value="" disabled>Select…</option>
                      <option>CISO</option>
                      <option>Head of Compliance</option>
                      <option>Head of Fraud</option>
                      <option>Other</option>
                    </select>
                  </div>
                </div>
                <div className="field">
                  <label>What's leaking? <span style={{ color: 'var(--fg-faint)', textTransform: 'none', letterSpacing: '0.04em' }}>(optional)</span></label>
                  <textarea rows="2" placeholder="Client lists hitting competitor outreach two weeks after onboarding…"></textarea>
                </div>
                <button type="submit" className="btn btn-primary contact-submit">
                  Request call <span className="arr">→</span>
                </button>
              </form>
            ) : (
              <div className="contact-success">
                ✓ Received. A Honey Badger architect will reply within 1 business day.<br/>
                Reference: SNARE-{Math.floor(Math.random() * 9000 + 1000)}
              </div>
            )}
          </div>
        </div>
      </section>

      {/* Footer */}
      <footer className="footer">
        <div className="container footer-inner">
          <div>A Honey Badger Security product · honeybadgersec.com · Tel Aviv · London</div>
          <div className="links">
            <a href="#">Privacy</a>
            <a href="#">Terms</a>
            <a href="#">Security</a>
          </div>
        </div>
      </footer>

      {/* Demo modal */}
      {demoOpen && <DemoModal onClose={() => setDemoOpen(false)} />}

      {/* Tweaks panel */}
      <SnareTweaks tw={tw} setTw={setTw} />
    </div>
  );
}

function PingPongVideo({ src }) {
  const ref = useRef(null);
  useEffect(() => {
    const v = ref.current;
    if (!v) return;
    let raf;
    let reversing = false;
    const FPS = 30;
    const step = () => {
      if (!v || v.paused) { raf = requestAnimationFrame(step); return; }
      if (reversing) {
        v.currentTime = Math.max(0, v.currentTime - 1 / FPS);
        if (v.currentTime <= 0.02) {
          reversing = false;
          v.play().catch(() => {});
        }
      }
      raf = requestAnimationFrame(step);
    };
    const onEnded = () => {
      reversing = true;
      v.pause();
      v.currentTime = Math.max(0, v.duration - 0.02);
    };
    const onLoaded = () => { v.play().catch(() => {}); };
    v.addEventListener('ended', onEnded);
    v.addEventListener('loadeddata', onLoaded);
    raf = requestAnimationFrame(step);
    return () => {
      cancelAnimationFrame(raf);
      v.removeEventListener('ended', onEnded);
      v.removeEventListener('loadeddata', onLoaded);
    };
  }, [src]);
  return (
    <video
      ref={ref}
      className="hero-video"
      src={src}
      autoPlay
      muted
      playsInline
      preload="auto"
    ></video>
  );
}

// Trapdoor-spider brand mark, hover-animated. The `variant` prop is accepted (and
// ignored) for backwards compatibility with the tweaks panel — the brand has landed
// on this single trapdoor mark from the assets/snare_final_assets/ design pack and
// the four placeholder variants (crosshair/pinhole/coiled/seal) are gone.
//
// Layers (all in one SVG so the :hover transition is local to the mark):
//   • ring     — segmented trapdoor ring with orange hinge at top, always visible
//   • burrow   — the dark hatch lip, always visible
//   • spider   — body + head + 8 legs; hidden (translateY 28px, opacity 0) by default,
//                slides up to opacity 0.85 on hover ("the spider gets out and tries to grab")
//   • eyesIdle — two faint orange glints inside the burrow, visible by default,
//                fade out as the spider emerges
//   • eyesHover — bright orange eyes on the spider's head, hidden by default, revealed with the spider
function BrandMark({ size = 28, variant: _variant }) {
  // _variant is intentionally unused; see comment above.
  return (
    <svg
      className="snare-mark"
      width={size}
      height={size}
      viewBox="0 0 320 320"
      xmlns="http://www.w3.org/2000/svg"
      role="img"
      aria-label="Snare"
    >
      <g transform="translate(160 145)">
        {/* Inner well */}
        <circle r="142" fill="#050607" stroke="#171A1E" strokeWidth="10"/>
        {/* Segmented ring with orange hinge at top */}
        <g className="snare-ring" fill="none" strokeLinecap="butt">
          <path d="M -35 -137 A 142 142 0 0 1 35 -137" stroke="#FF6A00" strokeWidth="19"/>
          <path d="M 55 -131 A 142 142 0 0 1 133 -49" stroke="#8D939A" strokeWidth="18"/>
          <path d="M 140 -25 A 142 142 0 0 1 108 92" stroke="#6E737A" strokeWidth="18"/>
          <path d="M 82 116 A 142 142 0 0 1 18 141" stroke="#555A61" strokeWidth="18"/>
          <path d="M -18 141 A 142 142 0 0 1 -82 116" stroke="#555A61" strokeWidth="18"/>
          <path d="M -108 92 A 142 142 0 0 1 -140 -25" stroke="#6E737A" strokeWidth="18"/>
          <path d="M -133 -49 A 142 142 0 0 1 -55 -131" stroke="#8D939A" strokeWidth="18"/>
        </g>
        {/* Burrow lip */}
        <g className="snare-burrow">
          <path d="M -92 104 C -55 76, 55 76, 92 104 C 65 123, -65 123, -92 104Z" fill="#050607"/>
          <path d="M -82 102 C -44 88, 44 88, 82 102" stroke="#23272C" strokeWidth="8" strokeLinecap="round" opacity="0.9"/>
          <path d="M -72 97 C -36 89, 36 89, 72 97" stroke="#101317" strokeWidth="8" strokeLinecap="round" opacity="0.85"/>
        </g>
        {/* Spider — hover-revealed, slides up from below the burrow lip */}
        <g className="snare-spider" fill="#A0A6AD" stroke="#0B0D10" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round">
          <ellipse cx="0" cy="92" rx="32" ry="26" fill="#777D84"/>
          <circle cx="0" cy="65" r="22" fill="#90969D"/>
          <path d="M -25 78 C -50 62, -79 65, -105 91"/>
          <path d="M -26 94 C -57 88, -83 103, -109 132"/>
          <path d="M 25 78 C 50 62, 79 65, 105 91"/>
          <path d="M 26 94 C 57 88, 83 103, 109 132"/>
          <path d="M -15 106 C -35 122, -39 143, -48 161"/>
          <path d="M 15 106 C 35 122, 39 143, 48 161"/>
        </g>
        {/* Idle eyes — faint glints inside the burrow */}
        <g className="snare-eyes-idle" fill="#FF6A00" opacity="0.72">
          <path d="M -30 105 C -22 98, -12 99, -7 107 C -17 110, -25 110, -30 105Z"/>
          <path d="M 30 105 C 22 98, 12 99, 7 107 C 17 110, 25 110, 30 105Z"/>
        </g>
        {/* Hover eyes — bright eyes on the spider's head */}
        <g className="snare-eyes-hover" fill="#FF6A00" opacity="0">
          <path d="M -17 66 C -10 61, -4 62, -1 68 C -8 71, -14 71, -17 66Z"/>
          <path d="M 17 66 C 10 61, 4 62, 1 68 C 8 71, 14 71, 17 66Z"/>
        </g>
      </g>
    </svg>
  );
}

function Nav({ onCta, ctaCopy, brandMark }) {
  return (
    <nav className="nav">
      <div className="nav-inner">
        <div className="brand">
          <BrandMark variant={brandMark} />
          <span className="brand-word serif">snar<em>e</em></span>
        </div>
        <div className="nav-links">
          <a href="#how">How</a>
          <a href="#proof">Proof</a>
          <a href="#compare">Compare</a>
          <a href="#reports">Reports</a>
          <a href="#contact">Deploy</a>
        </div>
        <button className="nav-cta nav-cta-primary" onClick={onCta}>{ctaCopy || 'Book a call →'}</button>
      </div>
    </nav>
  );
}

function DemoModal({ onClose }) {
  return (
    <div className="demo-modal" onClick={onClose}>
      <div className="demo-modal-inner" onClick={e => e.stopPropagation()}>
        <button className="demo-modal-close" onClick={onClose}>×</button>
        <div style={{
          position: 'absolute', inset: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexDirection: 'column', gap: 24,
          background: 'var(--bg-2)',
        }}>
          <div style={{
            fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: 'var(--fg-faint)'
          }}>SNARE / DEMO · 90s · silent</div>
          <div style={{ width: '70%', height: 4, background: 'var(--rule)' }}>
            <div style={{
              width: '0%', height: '100%', background: 'var(--accent)',
              animation: 'progress 90s linear forwards'
            }}></div>
          </div>
          <div style={{ fontFamily: 'var(--serif)', fontSize: 24, color: 'var(--fg-dim)', fontStyle: 'italic' }}>
            [ video placeholder — production drop-in ]
          </div>
        </div>
      </div>
    </div>
  );
}

function SnareTweaks({ tw, setTw }) {
  if (!window.TweaksPanel) return null;
  const { TweaksPanel, TweakSection, TweakRadio, TweakColor, TweakSelect, TweakSlider, TweakToggle } = window;
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Headline">
        <TweakSelect
          value={tw.headline}
          onChange={(v) => setTw('headline', Number(v))}
          options={[
            { value: 0, label: 'Rotate (random per visitor)' },
            { value: 1, label: 'The leak is already out…' },
            { value: 2, label: 'Bait the leak. Trace…' },
            { value: 3, label: 'Your CRM is leaking…' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Accent">
        <TweakRadio
          value={tw.accent}
          onChange={(v) => setTw('accent', v)}
          options={[
            { value: '#FF6A00', label: 'Signal' },
            { value: '#D4622A', label: 'Amber' },
            { value: '#C8A45C', label: 'Brass' },
            { value: '#B8412A', label: 'Blood' },
          ]}
        />
      </TweakSection>

      <TweakSection label="Atmosphere — vignette">
        <TweakSlider min={0} max={100} value={tw.vignette ?? 65} onChange={(v) => setTw('vignette', Number(v))} />
      </TweakSection>
      <TweakSection label="Atmosphere — grain">
        <TweakSlider min={0} max={100} value={tw.grain ?? 35} onChange={(v) => setTw('grain', Number(v))} />
      </TweakSection>
      <TweakSection label="Atmosphere — parallax depth">
        <TweakSlider min={0} max={100} value={tw.parallax ?? 25} onChange={(v) => setTw('parallax', Number(v))} />
      </TweakSection>
      <TweakSection label="Scroll-depth tint">
        <TweakToggle value={!!tw.scrollTint} onChange={(v) => setTw('scrollTint', !!v)} />
      </TweakSection>
      <TweakSection label="Tint hue">
        <TweakRadio
          value={tw.tintHue || 'warm'}
          onChange={(v) => setTw('tintHue', v)}
          options={[
            { value: 'warm', label: 'Smoky' },
            { value: 'blue', label: 'Cave' },
            { value: 'oxblood', label: 'Oxblood' },
            { value: 'black', label: 'Pitch' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Cursor torch">
        <TweakToggle value={!!tw.torch} onChange={(v) => setTw('torch', !!v)} />
      </TweakSection>

      <TweakSection label="Headline serif">
        <TweakSelect
          value={tw.serif || 'newsreader'}
          onChange={(v) => setTw('serif', v)}
          options={[
            { value: 'newsreader', label: 'Newsreader (current)' },
            { value: 'cormorant', label: 'Cormorant Garamond' },
            { value: 'playfair', label: 'Playfair Display' },
            { value: 'plex', label: 'IBM Plex Serif' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Body voice">
        <TweakRadio
          value={tw.voice || 'operator'}
          onChange={(v) => setTw('voice', v)}
          options={[
            { value: 'operator', label: 'Operator' },
            { value: 'noir', label: 'Noir' },
            { value: 'clinical', label: 'Clinical' },
          ]}
        />
      </TweakSection>
      <TweakSection label="CTA copy">
        <TweakRadio
          value={tw.ctaCopy || 'book'}
          onChange={(v) => setTw('ctaCopy', v)}
          options={[
            { value: 'book', label: 'Book a call' },
            { value: 'access', label: 'Request access' },
            { value: 'see', label: 'See it bait one' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Diagram density">
        <TweakRadio
          value={tw.diagramDensity || 'current'}
          onChange={(v) => setTw('diagramDensity', v)}
          options={[
            { value: 'minimal', label: 'Minimal' },
            { value: 'current', label: 'Default' },
            { value: 'dense', label: 'Dense' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Comparison table tone">
        <TweakRadio
          value={tw.tableTone || 'neutral'}
          onChange={(v) => setTw('tableTone', v)}
          options={[
            { value: 'neutral', label: 'Neutral' },
            { value: 'redteam', label: 'Red-team' },
            { value: 'wanted', label: 'Wanted' },
          ]}
        />
      </TweakSection>
      <TweakSection label="Form layout">
        <TweakRadio
          value={tw.formLayout || 'single'}
          onChange={(v) => setTw('formLayout', v)}
          options={[
            { value: 'single', label: 'Single column' },
            { value: 'split', label: 'Split + quote' },
          ]}
        />
      </TweakSection>

      <TweakSection label="Background mode">
        <TweakRadio
          value={tw.videoMode || 'placeholder'}
          onChange={(v) => setTw('videoMode', v)}
          options={[
            { value: 'placeholder', label: 'Gradient placeholders' },
            { value: 'video', label: 'Video clips (when set)' },
          ]}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

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