// BALLISTIC LEADS — marketing site
// Single-file app; mounted from index.html

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

// ────────────────────────────────────────────────────────────────────────────
// TWEAKS — default values block (host rewrites this on persist)
// ────────────────────────────────────────────────────────────────────────────
const BALLISTIC_TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#D4FF00",
  "scanlines": true,
  "gridOverlay": true,
  "heroHeadline": "Your lead gen & pipeline are broken. We fix it.",
  "tickerSpeed": 40
}/*EDITMODE-END*/;

// ────────────────────────────────────────────────────────────────────────────
// HOOKS
// ────────────────────────────────────────────────────────────────────────────

// Reveal-on-scroll helper. Returns ref + boolean.
function useReveal(opts = {}) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            setShown(true);
            io.unobserve(e.target);
          }
        });
      },
      { threshold: opts.threshold ?? 0.15, rootMargin: opts.rootMargin ?? '0px 0px -40px 0px' }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return [ref, shown];
}

// Live clock — bottom corner readout, sells the "war room" feel
function useClock() {
  const [t, setT] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setT(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return t;
}

// ────────────────────────────────────────────────────────────────────────────
// PRIMITIVES
// ────────────────────────────────────────────────────────────────────────────

function SectionLabel({ index, label, coord }) {
  return (
    <div className="section-label">
      <span className="sl-mark">§</span>
      <span className="sl-idx">{String(index).padStart(2, '0')}</span>
      <span className="sl-slash">//</span>
      <span className="sl-name">{label}</span>
      {coord && <span className="sl-coord">{coord}</span>}
    </div>
  );
}

function Reveal({ children, delay = 0, as: As = 'div', className = '', ...rest }) {
  const [ref, shown] = useReveal();
  return (
    <As
      ref={ref}
      className={`reveal ${shown ? 'reveal--in' : ''} ${className}`}
      style={{ transitionDelay: shown ? `${delay}ms` : '0ms' }}
      {...rest}
    >
      {children}
    </As>
  );
}

// Staggered word reveal — used by hero headline
function StaggerHeadline({ text, kickoff = 200 }) {
  const words = text.split(/\s+/);
  const [armed, setArmed] = useState(false);
  useEffect(() => {
    const id = setTimeout(() => setArmed(true), kickoff);
    return () => clearTimeout(id);
  }, [kickoff]);
  return (
    <h1 className="hero-headline">
      {words.map((w, i) => (
        <span key={i} className="word-wrap">
          <span
            className={`word ${armed ? 'word--in' : ''}`}
            style={{ transitionDelay: `${i * 80}ms` }}
          >
            {w}
          </span>
          {i < words.length - 1 && ' '}
        </span>
      ))}
    </h1>
  );
}

// Hard-edged button with kinetic hover
function Btn({ kind = 'solid', children, onClick, href, ...rest }) {
  const cls = `btn btn--${kind}`;
  const inner = (
    <>
      <span className="btn-label">{children}</span>
      <span className="btn-arrow" aria-hidden>→</span>
    </>
  );
  if (href) return <a className={cls} href={href} onClick={onClick} {...rest}>{inner}</a>;
  return <button className={cls} onClick={onClick} {...rest}>{inner}</button>;
}

// ────────────────────────────────────────────────────────────────────────────
// SECTIONS
// ────────────────────────────────────────────────────────────────────────────

function TopNav() {
  return (
    <nav className="nav">
      <div className="nav-inner">
        <a className="brand" href="#top" data-comment-anchor="brand">
          <span className="brand-mark" aria-hidden>
            <svg viewBox="0 0 24 24" width="22" height="22">
              <path d="M2 12 H22 M12 2 V22 M5 5 L19 19 M19 5 L5 19" stroke="currentColor" strokeWidth="1.5" />
              <circle cx="12" cy="12" r="3" fill="currentColor" />
            </svg>
          </span>
          <span className="brand-word">BALLISTIC</span>
          <span className="brand-sub">/ LEADS</span>
        </a>
        <div className="nav-links">
          <a href="#problem">PROBLEM</a>
          <a href="#services">SERVICES</a>
          <a href="#tools">FREE TOOLS</a>
          <a href="blog/index.html">JOURNAL</a>
          <a href="#contact">CONTACT</a>
        </div>
        <div className="nav-cta">
          <Btn kind="ghost-sm" href="#contact">BOOK CALL</Btn>
        </div>
      </div>
    </nav>
  );
}

function Hero({ headline, scanlines, gridOverlay }) {
  return (
    <section id="top" className="hero" data-screen-label="01 Hero">
      {gridOverlay && <div className="grid-overlay" aria-hidden />}
      {scanlines && <div className="scanlines" aria-hidden />}
      <div className="hero-corners" aria-hidden>
        <span className="corner tl" /><span className="corner tr" />
        <span className="corner bl" /><span className="corner br" />
      </div>

      <div className="hero-meta-top">
        <span className="meta-pill"><span className="dot" /> LIVE / ACQUISITION ENGINE</span>
        <span className="meta-coord">49.27°N · -123.12°W · HQ</span>
      </div>

      <div className="hero-body">
        <div className="hero-tag">
          <span className="bar" /> DONE-FOR-YOU LEAD GENERATION · CA / US
        </div>
        <StaggerHeadline text={headline} />
        <p className="hero-sub">
          Scalable lead generation &amp; automated follow up for real estate team leaders
          looking for higher ROI. We build the machine. You close.
        </p>
        <div className="hero-actions">
          <Btn kind="solid" href="#contact">GET LEADS NOW</Btn>
          <Btn kind="ghost" href="#tools">EXPLORE FREE TOOLS</Btn>
        </div>
      </div>

      <div className="hero-readout">
        <div className="ro-row">
          <span className="ro-k">LEADS / MO</span>
          <span className="ro-v">12,480</span>
          <span className="ro-d">+34.2%</span>
        </div>
        <div className="ro-row">
          <span className="ro-k">CONTACT RATE</span>
          <span className="ro-v">94.7%</span>
          <span className="ro-d">+12.1%</span>
        </div>
        <div className="ro-row">
          <span className="ro-k">CPL (USD)</span>
          <span className="ro-v">$8.20</span>
          <span className="ro-d ro-d--neg">−18.6%</span>
        </div>
        <div className="ro-row">
          <span className="ro-k">MARKETS</span>
          <span className="ro-v">17</span>
          <span className="ro-d">ACTIVE</span>
        </div>
      </div>

      <div className="hero-scrollcue" aria-hidden>
        <span>SCROLL</span>
        <span className="cue-line" />
      </div>
    </section>
  );
}

function Problem() {
  const stats = [
    { n: '73%', label: 'OF INBOUND LEADS NEVER GET A SECOND TOUCH', tag: 'NAR / 2024' },
    { n: '8 MIN', label: 'AVERAGE TIME-TO-CONTACT ON A DEAD PIPELINE', tag: 'INDUSTRY MEDIAN' },
    { n: '1.4×', label: 'YOY AGENT CHURN ON TEAMS WITH NO LEAD FLOW', tag: 'INTERNAL DATA' },
  ];
  return (
    <section id="problem" className="section problem" data-screen-label="02 Problem">
      <div className="container">
        <SectionLabel index={2} label="THE PROBLEM" coord="X-OBSERVED" />
        <Reveal as="h2" className="section-title">
          MOST TEAMS DON'T HAVE A PIPELINE.<br/>
          THEY HAVE A <span className="accent-strike">HOPE</span> MACHINE.
        </Reveal>
        <div className="stat-grid">
          {stats.map((s, i) => (
            <Reveal key={i} delay={i * 80} className="stat-cell">
              <div className="stat-rule" />
              <div className="stat-num">{s.n}</div>
              <div className="stat-label">{s.label}</div>
              <div className="stat-tag">{s.tag}</div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

function Services() {
  const items = [
    {
      id: 'PA-01',
      title: 'PAID ACQUISITION',
      desc: 'Targeted Meta and Google campaigns engineered for buyer and seller intent. Geo-fenced down to the polygon. We pull triggers daily.',
      bullets: ['META / GOOGLE / YOUTUBE', 'GEO-TIER BIDDING', 'CREATIVE ON 72H CYCLE'],
    },
    {
      id: 'LQ-02',
      title: 'LEAD QUALIFICATION',
      desc: 'Inbound is hit in under sixty seconds. Human plus AI ISA stack qualifies, books, and hands warm calendar slots to your closers.',
      bullets: ['< 60s SPEED-TO-LEAD', 'AI + HUMAN ISA', 'CALENDAR HANDOFF'],
    },
    {
      id: 'CR-03',
      title: 'CRM INTEGRATION',
      desc: 'Native pipelines in Follow Up Boss, Real Estate Webmasters, and HubSpot. Every event tracked. Every dollar attributed.',
      bullets: ['FUB / REW / HUBSPOT', 'EVENT-LEVEL ATTRIBUTION', 'DAILY OPS REPORTING'],
    },
  ];
  return (
    <section id="services" className="section services" data-screen-label="03 Services">
      <div className="container">
        <SectionLabel index={3} label="WHAT WE DO" coord="PROTOCOL.V3" />
        <Reveal as="h2" className="section-title">
          THREE SYSTEMS. ONE PIPELINE.<br/>
          BUILT TO <span className="accent-text">PRINT DEALS.</span>
        </Reveal>
      </div>
      <div className="services-grid">
        {items.map((s, i) => (
          <Reveal key={s.id} delay={i * 100} className="service-col">
            <div className="svc-id">{s.id}</div>
            <h3 className="svc-title">{s.title}</h3>
            <p className="svc-desc">{s.desc}</p>
            <ul className="svc-bullets">
              {s.bullets.map((b) => (
                <li key={b}><span className="b-mark">▸</span>{b}</li>
              ))}
            </ul>
            <div className="svc-foot">
              <span>0{i + 1} / 03</span>
              <span className="accent-text">OPERATIONAL</span>
            </div>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

function Marquee({ speed }) {
  const cities = [
    'VANCOUVER', 'TORONTO', 'CALGARY', 'EDMONTON', 'OTTAWA', 'MONTREAL',
    'SEATTLE', 'DENVER', 'PHOENIX', 'AUSTIN', 'MIAMI', 'NASHVILLE',
    'PORTLAND', 'SAN DIEGO', 'CHARLOTTE', 'DALLAS', 'BOISE',
  ];
  const row = [...cities, ...cities];
  return (
    <section className="marquee" aria-label="Markets" data-screen-label="04 Markets">
      <div className="mq-rail">
        <div className="mq-track" style={{ animationDuration: `${speed}s` }}>
          {row.map((c, i) => (
            <span key={i} className="mq-item">
              <span className="mq-bullet">◆</span>
              <span className="mq-text">{c}</span>
            </span>
          ))}
        </div>
      </div>
      <div className="mq-foot">
        <span>NORTH AMERICAN COVERAGE</span>
        <span>17 ACTIVE MARKETS · 4 PENDING Q3</span>
      </div>
    </section>
  );
}

function FreeTools() {
  const tools = [
    {
      name: 'CHAT WIDGET',
      slug: 'chat-widget',
      desc: 'Drop-in conversational lead capture. Streams to your CRM. Zero dependencies.',
      lang: 'TS · WEB COMPONENT',
      complexity: 'BEGINNER',
    },
    {
      name: 'REW + FUB BRIDGE',
      slug: 'rew-fub',
      desc: 'Webhook-based sync between Real Estate Webmasters and Follow Up Boss. Lossless field mapping.',
      lang: 'NODE / DENO',
      complexity: 'INTERMEDIATE',
    },
    {
      name: 'PARAGON MLS × CLAUDE',
      slug: 'paragon-claude',
      desc: 'Pull live MLS via Paragon, embed against listings, query with Claude. Built for power users.',
      lang: 'PYTHON · CLI',
      complexity: 'ADVANCED',
    },
    {
      name: 'FUB MCP SERVER',
      slug: 'fub-mcp',
      desc: 'Model Context Protocol server exposing Follow Up Boss to any MCP-compatible client.',
      lang: 'TS · MCP',
      complexity: 'ADVANCED',
    },
  ];
  return (
    <section id="tools" className="section tools" data-screen-label="05 Tools">
      <div className="container">
        <SectionLabel index={5} label="FREE TOOLS" coord="OSS / MIT" />
        <Reveal as="h2" className="section-title">
          OPEN SOURCE.<br/>
          <span className="accent-text">NO STRINGS.</span>
        </Reveal>
        <Reveal as="p" className="tools-lede">
          Built for the operators who want to build it themselves. Fork it, ship it, run it in prod.
          When you outgrow it — and you will — we'll build the production version.
        </Reveal>
      </div>

      <div className="tools-grid">
        {tools.map((t, i) => (
          <Reveal key={t.slug} delay={i * 60} className="tool-card">
            <div className="tc-head">
              <div className="tc-name">{t.name}</div>
              <div className={`tc-badge tc-badge--${t.complexity.toLowerCase()}`}>
                <span className="tcb-dot" /> {t.complexity}
              </div>
            </div>
            <div className="tc-lang">{t.lang}</div>
            <div className="tc-rule" />
            <p className="tc-desc">{t.desc}</p>
            <div className="tc-foot">
              <div className="tc-foot-actions">
                <Btn kind="solid-sm" href={`tools/${t.slug}.html`}>READ DOCS</Btn>
                <Btn kind="ghost-sm" href={`https://github.com/ballisticleads/${t.slug}`}>GITHUB</Btn>
              </div>
              <span className="tc-meta">v0.4 · MIT</span>
            </div>
          </Reveal>
        ))}
      </div>

      <div className="container tools-cta">
        <Reveal className="tcta-row">
          <span className="tcta-text">
            Need this built <span className="accent-text">for you</span>? We do that too.
          </span>
          <Btn kind="ghost" href="#contact">TALK TO ENGINEERING →</Btn>
        </Reveal>
      </div>
    </section>
  );
}

function CTAPanel() {
  const [email, setEmail] = useState('');
  const [submitted, setSubmitted] = useState(false);
  const onSubmit = (e) => {
    e.preventDefault();
    if (!email.includes('@')) return;
    setSubmitted(true);
  };
  return (
    <section id="contact" className="section cta-panel" data-screen-label="06 CTA">
      <div className="cta-frame">
        <SectionLabel index={6} label="ENGAGE" coord="UPLINK / OPEN" />
        <Reveal as="h2" className="cta-headline">
          STOP LEAVING DEALS<br/>
          ON THE <span className="accent-text">TABLE.</span>
        </Reveal>
        <Reveal as="p" className="cta-sub" delay={80}>
          Twenty-minute call. We audit your funnel. You leave with a number.
        </Reveal>
        {!submitted ? (
          <form className="cta-form" onSubmit={onSubmit}>
            <div className="cta-input-wrap">
              <span className="cta-prompt">{'>'}</span>
              <input
                type="email"
                placeholder="YOU@YOURTEAM.COM"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                className="cta-input"
                aria-label="Email"
              />
            </div>
            <button type="submit" className="btn btn--solid btn--cta">
              <span className="btn-label">BOOK A CALL</span>
              <span className="btn-arrow">→</span>
            </button>
          </form>
        ) : (
          <div className="cta-confirm">
            <span className="cc-dot" />
            UPLINK RECEIVED · {email.toUpperCase()} · WE'LL BE IN TOUCH WITHIN 24H
          </div>
        )}
        <div className="cta-foot">
          <span>NO SALES DECK · NO FLUFF · NO RETAINER GAMES</span>
          <span>AVG. RESPONSE 6H 12M</span>
        </div>
      </div>
    </section>
  );
}

function Footer() {
  const t = useClock();
  const ts = t.toISOString().replace('T', ' ').slice(0, 19);
  return (
    <footer className="footer" data-screen-label="07 Footer">
      <div className="container footer-inner footer-inner--5">
        <div className="foot-col foot-brand">
          <div className="brand">
            <span className="brand-mark" aria-hidden>
              <svg viewBox="0 0 24 24" width="22" height="22">
                <path d="M2 12 H22 M12 2 V22 M5 5 L19 19 M19 5 L5 19" stroke="currentColor" strokeWidth="1.5" />
                <circle cx="12" cy="12" r="3" fill="currentColor" />
              </svg>
            </span>
            <span className="brand-word">BALLISTIC</span>
            <span className="brand-sub">/ LEADS</span>
          </div>
          <p className="foot-tag">BUILT FOR TEAMS WHO SCALE.</p>
        </div>
        <div className="foot-col">
          <div className="foot-h">SERVICES</div>
          <a href="#services">Paid Acquisition</a>
          <a href="#services">Lead Qualification</a>
          <a href="#services">CRM Integration</a>
        </div>
        <div className="foot-col">
          <div className="foot-h">TOOLS</div>
          <a href="#tools">Chat Widget</a>
          <a href="#tools">REW + FUB</a>
          <a href="#tools">Paragon × Claude</a>
          <a href="#tools">FUB MCP</a>
        </div>
        <div className="foot-col">
          <div className="foot-h">JOURNAL</div>
          <a href="blog/index.html">All Posts</a>
          <a href="blog/speed-to-lead-60-second-rule.html">Speed-to-Lead</a>
          <a href="blog/paid-lead-math-2026.html">Paid Lead Math 2026</a>
        </div>
        <div className="foot-col">
          <div className="foot-h">COMPANY</div>
          <a href="#contact">Contact</a>
          <a href="#">Careers</a>
          <a href="#">Press</a>
        </div>
      </div>
      <div className="footer-bar">
        <span>© 2026 BALLISTIC LEADS INC.</span>
        <span className="fb-mid">SYS UPTIME 99.98%</span>
        <span>{ts} UTC</span>
      </div>
    </footer>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// TWEAKS PANEL
// ────────────────────────────────────────────────────────────────────────────

function TweaksUI({ t, setTweak }) {
  return (
    <TweaksPanel>
      <TweakSection title="Accent">
        <TweakColor
          label="Color"
          value={t.accent}
          onChange={(v) => setTweak('accent', v)}
          options={['#D4FF00', '#FF9500', '#FF3B30', '#00E5FF', '#A78BFA']}
        />
      </TweakSection>
      <TweakSection title="Hero">
        <TweakRadio
          label="Headline"
          value={t.heroHeadline}
          onChange={(v) => setTweak('heroHeadline', v)}
          options={[
            { value: 'Your lead gen & pipeline are broken. We fix it.', label: 'Broken' },
            { value: 'Done waiting for leads to come to you.', label: 'Done' },
            { value: 'We build acquisition engines. Period.', label: 'Engines' },
          ]}
        />
      </TweakSection>
      <TweakSection title="Texture">
        <TweakToggle label="Scanlines" value={t.scanlines} onChange={(v) => setTweak('scanlines', v)} />
        <TweakToggle label="Grid overlay" value={t.gridOverlay} onChange={(v) => setTweak('gridOverlay', v)} />
      </TweakSection>
      <TweakSection title="Marquee">
        <TweakSlider
          label="Speed"
          value={t.tickerSpeed}
          min={15} max={90} step={5}
          onChange={(v) => setTweak('tickerSpeed', v)}
          format={(v) => `${v}s`}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// APP ROOT
// ────────────────────────────────────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(BALLISTIC_TWEAK_DEFAULTS);

  // Push accent into CSS var
  useEffect(() => {
    document.documentElement.style.setProperty('--accent', t.accent);
  }, [t.accent]);

  return (
    <div className="app">
      <TopNav />
      <Hero headline={t.heroHeadline} scanlines={t.scanlines} gridOverlay={t.gridOverlay} />
      <Problem />
      <Services />
      <Marquee speed={t.tickerSpeed} />
      <FreeTools />
      <CTAPanel />
      <Footer />
      <TweaksUI t={t} setTweak={setTweak} />
    </div>
  );
}

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