// app.jsx — Cortality landing page. Hero = "Gaze Grid" (direction B) with a
// true eye-tracking heatmap ramp behind the live red cursor. Restrained crimson
// elsewhere. Scroll-reveal on sections. Tweaks for accent / gaze field / intensity.
const { useRef, useEffect, useState, useCallback } = React;

const PREFERS_REDUCE = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

/* ---------- tweakable defaults ---------- */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#b3242c",
  "fieldMode": "grid",
  "intensity": 0.5,
  "speed": 2,
  "heroFont": "Geist"
}/*EDITMODE-END*/;

const HERO_FONTS = {
  "Geist": "'Geist', system-ui, sans-serif",
  "Space Grotesk": "'Space Grotesk', sans-serif",
  "Sora": "'Sora', sans-serif",
  "Archivo": "'Archivo', sans-serif"
};

function hexToRgb(hex) {
  const m = hex.replace('#', '');
  const n = parseInt(m.length === 3 ? m.split('').map(c => c + c).join('') : m, 16);
  return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}

/* ---------- scroll reveal ---------- */
function Reveal({ children, delay = 0, as = 'div', className = '', style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { el.classList.add('in'); io.unobserve(el); }
      });
    }, { threshold: 0.18, rootMargin: '0px 0px -8% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const Tag = as;
  return <Tag ref={ref} className={'reveal ' + className} style={{ transitionDelay: delay + 'ms', ...style }}>{children}</Tag>;
}

/* ---------- gaze canvas ---------- */
function GazeCanvas({ mode, accentRgb, intensity, speed, enabled }) {
  const ref = useRef(null);
  useEffect(() => {
    if (!enabled || !ref.current) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const stop = window.initGazeField(ref.current, {
      mode, accent: accentRgb, density: intensity, speed, reduce
    });
    return stop;
  }, [mode, enabled, intensity, speed, accentRgb[0], accentRgb[1], accentRgb[2]]);
  return <canvas ref={ref} className="gaze-canvas" />;
}

/* ---------- nav ---------- */
function Nav() {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const f = () => setScrolled(window.scrollY > 24);
    window.addEventListener('scroll', f, { passive: true });
    return () => window.removeEventListener('scroll', f);
  }, []);
  return (
    <nav className={'nav' + (scrolled ? ' nav--scrolled' : '')}>
      <a className="brand" href="#top">
        <img className="brand-logo" src="assets/cortality-logo.png" alt="Cortality" />
      </a>
      <div className="nav-links">
        <a href="#thesis">Thesis</a>
        <a href="#capture">What we capture</a>
        <a href="#asset">The asset</a>
      </div>
      <a className="nav-cta" href="#contact">Get in touch</a>
    </nav>
  );
}

/* ---------- hero ---------- */
function Hero({ accentRgb, fieldMode, intensity, speed }) {
  return (
    <header className="hero" id="top">
      <div className="hero-field" aria-hidden="true">
        <GazeCanvas mode={fieldMode} accentRgb={accentRgb} intensity={intensity} speed={speed} enabled={fieldMode !== 'off'} />
        <div className="hero-field-mask" />
      </div>
      <div className="hero-inner">
        <div className="eyebrow">Behavioral intelligence</div>
        <h1 className="hero-h1">The prediction engine<br />for human attention</h1>
        <p className="hero-sub">We measure how real people respond to content. Passively, at scale, with no hardware.</p>
        <div className="hero-actions">
          <a className="btn btn--primary" href="#contact">Get in touch <span className="arr">→</span></a>
          <a className="btn btn--ghost" href="#capture">What we measure</a>
        </div>
      </div>
      <div className="hero-readout">
        <span className="mono">live gaze model</span>
        <span className="mono dim">webcam · no hardware</span>
      </div>
    </header>
  );
}

/* ---------- thesis ---------- */
function Thesis() {
  return (
    <section className="section thesis" id="thesis">
      <Reveal className="container">
        <div className="eyebrow">The thesis</div>
        <p className="thesis-statement">
          Attention is not a black box. <span className="dim">We map how real people perceive and react to content, so decisions rest on behavioral signal, not guesswork.</span>
        </p>
      </Reveal>
    </section>
  );
}

/* ---------- what we capture ---------- */
function CaptureIcon({ kind }) {
  if (kind === 'eye') {
    return (
      <svg viewBox="0 0 64 64" className="cap-svg">
        <path d="M5 32 Q32 13 59 32 Q32 51 5 32 Z" className="stroke-dim" />
        <g className="gaze">
          <circle cx="32" cy="32" r="9.5" className="stroke-accent" />
          <circle cx="32" cy="32" r="4" className="fill-accent" />
        </g>
      </svg>
    );
  }
  if (kind === 'face') {
    return (
      <svg viewBox="0 0 64 64" className="cap-svg">
        <rect x="13" y="11" width="38" height="42" rx="16" className="stroke-dim" />
        <circle cx="25" cy="29" r="2.6" className="fill-dim" />
        <circle cx="39" cy="29" r="2.6" className="fill-dim" />
        <path className="stroke-accent" fill="none" strokeLinecap="round" d="M23 38 Q32 47 41 38">
          {!PREFERS_REDUCE && (
            <animate attributeName="d" dur="3.4s" repeatCount="indefinite"
              keyTimes="0;0.5;1" calcMode="spline"
              keySplines="0.45 0 0.55 1;0.45 0 0.55 1"
              values="M23 38 Q32 47 41 38;M23 43 Q32 33 41 43;M23 38 Q32 47 41 38" />
          )}
        </path>
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 64 64" className="cap-svg">
      <circle cx="26" cy="25" r="10" className="stroke-accent ripple" />
      <path d="M22 16 L22 47 L30 39 L35 50 L40 48 L35 37 L45 37 Z" className="fill-dim cursor-arrow" />
    </svg>
  );
}

function Capture() {
  const blocks = [
    { k: 'eye', t: 'Eye movement', d: 'Where attention goes, where it dwells, and the moment it drops.' },
    { k: 'face', t: 'Facial response', d: 'Real-time micro-expression and emotional signal as content unfolds.' },
    { k: 'cursor', t: 'Interaction behavior', d: 'How people move, hover, and hesitate. Intent read from motion.' },
  ];
  return (
    <section className="section capture" id="capture">
      <Reveal className="container">
        <div className="section-head">
          <div className="eyebrow">What we capture</div>
          <h2 className="section-h2">Three signals. One source.</h2>
          <p className="section-lede">Webcam and device only. No hardware, no headsets, no instrumentation.</p>
        </div>
      </Reveal>
      <div className="container cap-grid">
        {blocks.map((b, i) => (
          <Reveal key={b.k} className="cap-card" delay={i * 90}>
            <div className="cap-icon"><CaptureIcon kind={b.k} /></div>
            <h3 className="cap-title">{b.t}</h3>
            <p className="cap-desc">{b.d}</p>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

/* ---------- the asset ---------- */
function Asset() {
  return (
    <section className="section asset" id="asset">
      <div className="container asset-inner">
        <Reveal className="asset-copy">
          <div className="eyebrow">The asset</div>
          <h2 className="section-h2">Today, analytics.<br />Tomorrow, prediction.</h2>
          <p className="section-lede">
            Every interaction compounds into a proprietary behavioral dataset, the kind that cannot be bought, only measured. That dataset becomes a model: the ability to know how people will respond before a dollar is spent.
          </p>
        </Reveal>
        <Reveal className="asset-visual" delay={120}>
          <img src="assets/neuro-composition.png" alt="Gaze heatmap dashboard, neural model, and facial response analysis" />
        </Reveal>
      </div>
    </section>
  );
}

/* ---------- stats ---------- */
function Stats() {
  const stats = [
    { n: '95%', l: 'of purchasing decisions happen subconsciously' },
    { n: '$1 in $4', l: 'of digital ad spend wasted on poor targeting and creative' },
  ];
  return (
    <section className="section stats">
      <div className="container stats-grid">
        {stats.map((s, i) => (
          <Reveal key={i} className="stat" delay={i * 120}>
            <div className="stat-n">{s.n}</div>
            <div className="stat-l mono">{s.l}</div>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

/* ---------- CTA / contact ---------- */
function Contact() {
  const [email, setEmail] = useState('');
  const [sent, setSent] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  const submit = async (e) => {
    e.preventDefault();
    if (!valid || submitting) return;
    setSubmitting(true);
    try {
      await fetch('https://formsubmit.co/ajax/colton@allbci.com', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
        body: JSON.stringify({
          email,
          _subject: 'New Cortality lead: ' + email,
          _template: 'table',
          _captcha: 'false',
        }),
      });
    } catch (err) {
      console.error('FormSubmit failed', err);
    } finally {
      setSubmitting(false);
      setSent(true);
    }
  };
  return (
    <section className="section contact" id="contact">
      <Reveal className="container contact-inner">
        <div className="eyebrow">Get in touch</div>
        <h2 className="contact-h2">See it before you spend a dollar.</h2>
        <p className="section-lede contact-lede">For investors, partners, and prospective hires. Leave an address and we'll reach out.</p>
        {!sent ? (
          <form className="capture-form" onSubmit={submit}>
            <input
              type="email" className="capture-input" placeholder="you@company.com"
              value={email} onChange={(e) => setEmail(e.target.value)} aria-label="Email address" />
            <button type="submit" className={'btn btn--primary' + (valid && !submitting ? '' : ' btn--disabled')}>
              {submitting ? 'Sending…' : 'Request access'} <span className="arr">→</span>
            </button>
          </form>
        ) : (
          <div className="capture-done mono">
            <span className="brand-dot" /> Thanks, we'll be in touch at {email}.
          </div>
        )}
        <a className="contact-email mono" href="mailto:colton@allbci.com">or email colton@allbci.com</a>
      </Reveal>
    </section>
  );
}

/* ---------- footer ---------- */
function Footer() {
  return (
    <footer className="footer">
      <div className="container footer-inner">
        <div className="footer-brand">
          <img className="footer-logo" src="assets/cortality-logo.png" alt="Cortality" />
          <span className="footer-tag mono">The prediction engine for human attention</span>
        </div>
        <div className="footer-links mono">
          <a href="mailto:colton@allbci.com">colton@allbci.com</a>
        </div>
        <div className="footer-copy mono">© 2026 Cortality</div>
      </div>
    </footer>
  );
}

/* ---------- app ---------- */
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const accentRgb = hexToRgb(t.accent);
  useEffect(() => {
    document.documentElement.style.setProperty('--accent', t.accent);
    const [r, g, b] = accentRgb;
    document.documentElement.style.setProperty('--accent-rgb', r + ',' + g + ',' + b);
  }, [t.accent]);
  useEffect(() => {
    document.documentElement.style.setProperty('--font-display', HERO_FONTS[t.heroFont] || HERO_FONTS.Geist);
  }, [t.heroFont]);

  return (
    <>
      <Nav />
      <main>
        <Hero accentRgb={accentRgb} fieldMode={t.fieldMode} intensity={t.intensity} speed={t.speed} />
        <Thesis />
        <Capture />
        <Asset />
        <Stats />
        <Contact />
      </main>
      <Footer />

      <TweaksPanel>
        <TweakSection label="Accent" />
        <TweakColor label="Accent color" value={t.accent}
          options={['#d6353f', '#b3242c', '#e2483d', '#4f7cff', '#8b5cf6']}
          onChange={(v) => setTweak('accent', v)} />
        <TweakSection label="Hero background" />
        <TweakSelect label="Field" value={t.fieldMode}
          options={['grid', 'bloom', 'scan', 'off']}
          onChange={(v) => setTweak('fieldMode', v)} />
        <TweakSlider label="Intensity" value={t.intensity} min={0.3} max={1.8} step={0.1}
          onChange={(v) => setTweak('intensity', v)} />
        <TweakSlider label="Speed" value={t.speed} min={0.4} max={2} step={0.1}
          onChange={(v) => setTweak('speed', v)} />
        <TweakSection label="Typography" />
        <TweakSelect label="Headline font" value={t.heroFont}
          options={['Geist', 'Space Grotesk', 'Sora', 'Archivo']}
          onChange={(v) => setTweak('heroFont', v)} />
      </TweaksPanel>
    </>
  );
}

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