// V1 — MONOCHROME POLISHED SAAS (dark, minimal accents)
// True-dark palette, monochrome surfaces, saffron used ONLY as a precision accent.
// Heavy on motion: scroll-reveal, parallax, marquees, sweep shimmers, typewriter.

const C = window.ROAM_COPY;

// Driven by CSS variables set in index.html from TWEAK_DEFAULTS.
// Raw hex fallbacks used only if index.html script didn't run.
const T = {
  bg: 'var(--v1-bg, #050506)',
  bg2: '#08080A',
  panel: 'var(--v1-panel, #0C0C10)',
  panelHi: '#101016',
  line: 'rgba(255,255,255,0.05)',
  lineHi: 'rgba(255,255,255,0.09)',
  white: '#FFFFFF',
  ink: 'var(--v1-ink, #EDEDEF)',
  ink2: 'var(--v1-ink2, #B8B8BC)',
  ink3: '#7C7C82',
  ink4: '#4A4A50',
  ink5: '#2A2A30',
  saffron: 'var(--v1-accent, #FAC761)',
  saffronDim: 'var(--v1-accent-dim, rgba(250,199,97,0.35))',
  red: '#E5484D',
};
const F = {
  display: 'var(--v1-font-display, "Space Grotesk", -apple-system, sans-serif)',
  body: 'var(--v1-font-body, Inter, -apple-system, sans-serif)',
  mono: 'var(--v1-font-mono, "JetBrains Mono", "Courier New", monospace)',
};

// ══════════════ inject styles & IntersectionObserver scroll-reveal ══════════════
if (typeof document !== 'undefined' && !document.getElementById('v1-styles')) {
  const s = document.createElement('style');
  s.id = 'v1-styles';
  s.textContent = `
    @keyframes v1-rise { from { opacity: 0; transform: translateY(24px); filter: blur(6px); } to { opacity: 1; transform: none; filter: none; } }
    @keyframes v1-fade { from { opacity: 0 } to { opacity: 1 } }
    @keyframes v1-pulse { 0%,100% { opacity: .35 } 50% { opacity: 1 } }
    @keyframes v1-sweep { 0% { transform: translateX(-100%) } 100% { transform: translateX(400%) } }
    @keyframes v1-marquee { from { transform: translateX(0) } to { transform: translateX(-50%) } }
    @keyframes v1-grid-drift { from { background-position: 0 0 } to { background-position: 80px 80px } }
    @keyframes v1-caret { 0%,49% { opacity: 1 } 50%,100% { opacity: 0 } }
    @keyframes v1-orb { 0%,100% { transform: translate(0,0) scale(1) } 50% { transform: translate(40px,-30px) scale(1.08) } }
    @keyframes v1-dash { to { stroke-dashoffset: -40 } }

    .v1-reveal { opacity: 0; transform: translateY(28px); filter: blur(6px); transition: opacity 1s cubic-bezier(.22,.75,.3,1), transform 1s cubic-bezier(.22,.75,.3,1), filter 1s; }
    .v1-reveal.on { opacity: 1; transform: none; filter: none; }
    .v1-reveal[data-d="1"] { transition-delay: 80ms }
    .v1-reveal[data-d="2"] { transition-delay: 160ms }
    .v1-reveal[data-d="3"] { transition-delay: 240ms }
    .v1-reveal[data-d="4"] { transition-delay: 320ms }
    .v1-reveal[data-d="5"] { transition-delay: 400ms }
    .v1-reveal[data-d="6"] { transition-delay: 480ms }

    .v1-cta-pri {
      position: relative; overflow: hidden;
      background: #F5F5F5; color: #050506;
      border: 1px solid rgba(255,255,255,0.2);
      box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 0 0 1px rgba(255,255,255,0.02), 0 20px 40px -16px rgba(0,0,0,0.8);
      transition: transform .3s cubic-bezier(.22,.75,.3,1), box-shadow .3s, background .3s;
      font-family: ${F.body}; font-weight: 600;
    }
    .v1-cta-pri::after {
      content: ""; position: absolute; inset: 0;
      background: linear-gradient(90deg, transparent 30%, rgba(255,255,255,0.9) 50%, transparent 70%);
      transform: translateX(-100%);
      transition: transform .8s cubic-bezier(.22,.75,.3,1);
      pointer-events: none;
    }
    .v1-cta-pri:hover { transform: translateY(-1px); background: #FFF; box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 28px 50px -16px rgba(0,0,0,0.9); }
    .v1-cta-pri:hover::after { transform: translateX(100%); }

    .v1-cta-ghost {
      background: transparent; color: ${T.ink};
      border: 1px solid ${T.lineHi};
      transition: border-color .3s, background .3s, transform .3s;
      font-family: ${F.body}; font-weight: 500;
    }
    .v1-cta-ghost:hover { border-color: rgba(255,255,255,0.3); background: rgba(255,255,255,0.03); transform: translateY(-1px); }

    .v1-card {
      position: relative;
      background: ${T.panel};
      border: 1px solid ${T.line};
      border-radius: 16px;
      transition: border-color .4s, background .4s, transform .4s;
      overflow: hidden;
    }
    .v1-card::before {
      content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px;
      background: linear-gradient(135deg, transparent 30%, rgba(255,255,255,0.08) 50%, transparent 70%);
      -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      -webkit-mask-composite: xor; mask-composite: exclude;
      opacity: 0; transition: opacity .4s;
      pointer-events: none;
    }
    .v1-card:hover { border-color: rgba(255,255,255,0.14); transform: translateY(-2px); }
    .v1-card:hover::before { opacity: 1 }

    .v1-pill {
      display: inline-flex; align-items: center; gap: 10px;
      padding: 6px 14px 6px 12px;
      border: 1px solid ${T.lineHi};
      background: rgba(255,255,255,0.02);
      border-radius: 999px;
      font-family: ${F.mono}; font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase;
      color: ${T.ink2}; font-weight: 500;
    }

    /* Founder portrait hover reveal */
    .v1-portrait__stamp-declass { display: none; }
    .v1-portrait:hover .v1-portrait__redact { opacity: 0; }
    .v1-portrait:hover .v1-portrait__hint { opacity: 0; }
    .v1-portrait:hover .v1-portrait__stamp { color: ${T.white}; border-color: rgba(255,255,255,0.35); }
    .v1-portrait:hover .v1-portrait__stamp-redact { display: none; }
    .v1-portrait:hover .v1-portrait__stamp-declass { display: inline; }
    .v1-pill::before {
      content: ""; width: 5px; height: 5px; border-radius: 50%;
      background: ${T.saffron}; box-shadow: 0 0 8px ${T.saffron};
      animation: v1-pulse 2.2s ease-in-out infinite;
    }

    .v1-h-sweep {
      background: linear-gradient(90deg, ${T.ink} 0%, ${T.ink} 40%, ${T.white} 50%, ${T.ink} 60%, ${T.ink} 100%);
      background-size: 200% 100%;
      -webkit-background-clip: text; background-clip: text; color: transparent;
      animation: v1-fade 1.2s ease-out both;
    }

    .v1-link { color: ${T.ink}; text-decoration: none; position: relative; display: inline-flex; align-items: center; gap: 6px; }
    .v1-link .arrow { transition: transform .3s cubic-bezier(.22,.75,.3,1); display: inline-block; }
    .v1-link:hover .arrow { transform: translateX(4px); }
    .v1-link::after {
      content: ""; position: absolute; left: 0; right: 16px; bottom: -2px; height: 1px;
      background: ${T.ink}; transform: scaleX(0); transform-origin: left;
      transition: transform .35s cubic-bezier(.22,.75,.3,1);
    }
    .v1-link:hover::after { transform: scaleX(1); }

    @media (prefers-reduced-motion: reduce) {
      .v1-reveal { opacity: 1 !important; transform: none !important; filter: none !important }
      .v1-pill::before, .v1-h-sweep { animation: none !important }
    }
  `;
  document.head.appendChild(s);
}

// scroll reveal hook
function useReveal() {
  React.useEffect(() => {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      document.querySelectorAll('.v1-reveal').forEach(el => el.classList.add('on'));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('on'); io.unobserve(e.target); } });
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    // Belt-and-suspenders: anything already in view on mount reveals immediately.
    // IO sometimes defers callbacks past the first frame and users see a blank hero.
    const vh = window.innerHeight;
    document.querySelectorAll('.v1-reveal').forEach(el => {
      const r = el.getBoundingClientRect();
      if (r.top < vh && r.bottom > 0) el.classList.add('on');
      else io.observe(el);
    });
    return () => io.disconnect();
  }, []);
}

// ══════════════ BACKGROUND — slow orbs + drifting grid ══════════════
const AmbientBg = () => (
  <div aria-hidden style={{ position: 'fixed', inset: 0, zIndex: 0, pointerEvents: 'none', overflow: 'hidden' }}>
    {/* slow-drifting grid */}
    <div style={{
      position: 'absolute', inset: -40,
      backgroundImage: `linear-gradient(rgba(255,255,255,0.018) 1px, transparent 1px),
                        linear-gradient(90deg, rgba(255,255,255,0.018) 1px, transparent 1px)`,
      backgroundSize: '80px 80px',
      maskImage: 'radial-gradient(ellipse at center, black 20%, transparent 75%)',
      WebkitMaskImage: 'radial-gradient(ellipse at center, black 20%, transparent 75%)',
      animation: 'v1-grid-drift 40s linear infinite',
    }} />
    {/* two faint white-gray orbs, slow drift */}
    <div style={{
      position: 'absolute', top: '-20%', left: '-10%', width: 900, height: 900,
      background: 'radial-gradient(circle at center, rgba(255,255,255,0.04) 0%, transparent 60%)',
      filter: 'blur(20px)', animation: 'v1-orb 22s ease-in-out infinite',
    }} />
    <div style={{
      position: 'absolute', bottom: '-30%', right: '-10%', width: 1000, height: 1000,
      background: 'radial-gradient(circle at center, rgba(255,255,255,0.025) 0%, transparent 60%)',
      filter: 'blur(20px)', animation: 'v1-orb 28s ease-in-out infinite reverse',
    }} />
  </div>
);

// ══════════════ LINKS ══════════════
const LINKS = {
  app: 'https://app.roamintelligence.com',
  signup: 'https://app.roamintelligence.com',
  signin: 'https://app.roamintelligence.com',
  brief: 'https://roamintelligence.beehiiv.com/',
  linkedin: 'https://www.linkedin.com/company/roam-intelligence/',
};

// Nav label → in-page anchor
const NAV_ANCHORS = {
  'Platform': '#platform',
  "Who it's for": '#missions',
  'How it works': '#pipeline',
  'Pricing': '#pricing',
  'Weekly Brief': '#weekly',
};

// ══════════════ NAV ══════════════
const V1Nav = () => {
  const [scrolled, setScrolled] = React.useState(false);
  React.useEffect(() => {
    const h = () => setScrolled(window.scrollY > 20);
    window.addEventListener('scroll', h, { passive: true });
    return () => window.removeEventListener('scroll', h);
  }, []);
  return (
    <nav style={{
      position: 'sticky', top: 0, zIndex: 50,
      padding: scrolled ? '12px 32px' : '18px 32px',
      display: 'grid', gridTemplateColumns: '1fr auto 1fr', alignItems: 'center', gap: 24,
      background: scrolled ? 'rgba(5,5,6,0.85)' : 'rgba(5,5,6,0.4)',
      backdropFilter: 'blur(16px)', WebkitBackdropFilter: 'blur(16px)',
      borderBottom: `1px solid ${scrolled ? T.line : 'transparent'}`,
      transition: 'padding .3s, background .3s, border-color .3s',
    }}>
      <a href="#top" style={{ display: 'flex', alignItems: 'center', gap: 10, color: T.white, textDecoration: 'none' }}>
        <img src="../../assets/roam-logo-white.png" alt="ROAM" style={{ height: 44 }} />
      </a>
      <div style={{
        display: 'flex', gap: 4, justifySelf: 'center',
        background: 'rgba(255,255,255,0.02)',
        border: `1px solid ${T.line}`,
        borderRadius: 999, padding: 4,
      }}>
        {C.nav.links.map(l => (
          <a key={l} href={NAV_ANCHORS[l] || '#'} style={{
            fontFamily: F.body, fontSize: 12.5, fontWeight: 500,
            color: T.ink2, textDecoration: 'none',
            padding: '8px 16px', borderRadius: 999,
            transition: 'background .25s, color .25s',
          }}
            onMouseEnter={e => { e.currentTarget.style.background = 'rgba(255,255,255,0.04)'; e.currentTarget.style.color = T.white; }}
            onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = T.ink2; }}
          >{l}</a>
        ))}
      </div>
      <div style={{ justifySelf: 'end', display: 'flex', gap: 10, alignItems: 'center' }}>
        <a href={LINKS.signup} className="v1-cta-pri" style={{
          fontSize: 12.5, borderRadius: 999, padding: '9px 18px', cursor: 'pointer',
          textDecoration: 'none', display: 'inline-flex', alignItems: 'center',
        }}>{C.nav.cta}</a>
      </div>
    </nav>
  );
};

// ══════════════ HERO ══════════════
const V1Hero = () => {
  // parallax scroll for dashboard
  const ref = React.useRef(null);
  const [y, setY] = React.useState(0);
  React.useEffect(() => {
    const h = () => setY(Math.min(window.scrollY * 0.15, 60));
    window.addEventListener('scroll', h, { passive: true });
    return () => window.removeEventListener('scroll', h);
  }, []);

  return (
    <section id="top" style={{ position: 'relative', padding: '72px 32px 0', overflow: 'hidden' }}>
      <div style={{ position: 'relative', maxWidth: 1200, margin: '0 auto', zIndex: 2 }}>
        <div className="v1-reveal" style={{ textAlign: 'center' }}>
          <div className="v1-pill">{C.hero.eyebrow}</div>
        </div>

        <h1 className="v1-reveal v1-h-sweep" data-d="1" style={{
          fontFamily: F.display, fontWeight: 400, fontSize: 84, lineHeight: 1.0,
          letterSpacing: -2.8, margin: '32px auto 0',
          textAlign: 'center', textWrap: 'balance', maxWidth: 980,
        }}>
          {C.hero.h1_prefix}{' '}
          <span style={{ fontStyle: 'italic', color: T.saffron, WebkitTextFillColor: T.saffron }}>
            {C.hero.h1_italic}
          </span>{C.hero.h1_suffix}
        </h1>

        <p className="v1-reveal" data-d="2" style={{
          fontFamily: F.body, fontSize: 18, lineHeight: 1.55,
          color: T.ink2, maxWidth: 700, margin: '28px auto 0',
          textAlign: 'center', textWrap: 'pretty',
        }}>{C.hero.subhead}</p>

        <div className="v1-reveal" data-d="3" style={{
          display: 'flex', gap: 12, justifyContent: 'center', marginTop: 40, flexWrap: 'wrap',
        }}>
          <a href={LINKS.signup} className="v1-cta-pri" style={{
            fontSize: 14.5, borderRadius: 999, padding: '13px 26px', cursor: 'pointer',
            display: 'inline-flex', alignItems: 'center', gap: 10, textDecoration: 'none',
          }}>
            {C.hero.cta_primary} <span style={{ fontSize: 16 }}>→</span>
          </a>
        </div>

        <div className="v1-reveal" data-d="4" style={{
          fontFamily: F.body, fontStyle: 'italic', textAlign: 'center',
          marginTop: 28, fontSize: 12, color: T.ink4,
        }}>
          {C.hero.scripture.text}
          <span style={{
            fontStyle: 'normal', fontFamily: F.mono, marginLeft: 10,
            color: T.ink5, letterSpacing: 1,
          }}>{C.hero.scripture.cite}</span>
        </div>

        {/* dashboard with parallax */}
        <div ref={ref} className="v1-reveal" data-d="5" style={{
          position: 'relative', marginTop: 72, marginBottom: -80,
          transform: `translateY(${-y}px)`,
        }}>
          <DashboardMock />
        </div>
      </div>

      <div style={{ position: 'relative', marginTop: 96, padding: '0 32px', zIndex: 2 }}>
        <div style={{ maxWidth: 1200, margin: '0 auto' }}>
          <KPIStrip />
        </div>
      </div>
    </section>
  );
};

const DashboardMock = () => (
  <div style={{
    position: 'relative', borderRadius: 14,
    background: T.panel, border: `1px solid ${T.lineHi}`,
    boxShadow: '0 1px 0 rgba(255,255,255,0.04) inset, 0 60px 100px -30px rgba(0,0,0,0.9)',
    overflow: 'hidden',
  }}>
    <div style={{
      height: 36, padding: '0 14px', display: 'flex', alignItems: 'center', gap: 8,
      borderBottom: `1px solid ${T.line}`,
    }}>
      {['#ff5f57', '#febc2e', '#28c840'].map(c => (
        <div key={c} style={{ width: 11, height: 11, borderRadius: '50%', background: c, opacity: 0.55 }} />
      ))}
    </div>
    <div style={{ position: 'relative' }}>
      <img src="../../assets/dashboard-map.png" alt="ROAM dashboard"
        style={{ width: '100%', display: 'block', height: 'auto' }} />
      {/* sweep shimmer over dashboard */}
      <div aria-hidden style={{
        position: 'absolute', inset: 0, overflow: 'hidden', pointerEvents: 'none',
      }}>
        <div style={{
          position: 'absolute', top: 0, bottom: 0, width: '25%',
          background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.06), transparent)',
          animation: 'v1-sweep 5s cubic-bezier(.22,.75,.3,1) infinite',
        }} />
      </div>
    </div>
    <div aria-hidden style={{
      position: 'absolute', left: 0, right: 0, bottom: 0, height: 120,
      background: `linear-gradient(180deg, transparent 0%, ${T.bg} 90%)`,
    }} />
  </div>
);

// Live feed ticker (marquee, clickable pause)
const Ticker = () => {
  const items = [
    { c: 'PAKISTAN', r: 'Jaranwala, Punjab', k: 'MOB VIOLENCE · CRIT' },
    { c: 'USA', r: 'Nashville, TN', k: 'ACTIVE SHOOTER · CRIT' },
    { c: 'NICARAGUA', r: 'Managua', k: 'NGO EXPULSION · HI' },
    { c: 'INDIA', r: 'Manipur', k: 'TARGETED ATTACK · HI' },
    { c: 'LIBYA', r: 'Tripoli', k: 'KIDNAPPING · MED' },
    { c: 'NIGERIA', r: 'Plateau State', k: 'RAID · CRIT' },
  ];
  const all = [...items, ...items];
  return (
    <div style={{
      position: 'relative', height: 48, overflow: 'hidden',
      border: `1px solid ${T.line}`, borderRadius: 10, background: 'rgba(255,255,255,0.012)',
    }}>
      <div style={{
        position: 'absolute', top: 0, bottom: 0, left: 0, width: 180, zIndex: 2,
        background: `linear-gradient(90deg, ${T.bg} 60%, transparent)`,
        display: 'flex', alignItems: 'center', paddingLeft: 16, gap: 10,
      }}>
        <span style={{ width: 7, height: 7, borderRadius: '50%', background: T.red, boxShadow: `0 0 10px ${T.red}`, animation: 'v1-pulse 1.6s ease-in-out infinite' }} />
        <span style={{ fontFamily: F.mono, fontSize: 10.5, color: T.ink, letterSpacing: '0.2em', fontWeight: 600 }}>LIVE FEED</span>
      </div>
      <div style={{
        position: 'absolute', top: 0, bottom: 0, right: 0, width: 80, zIndex: 2,
        background: `linear-gradient(-90deg, ${T.bg} 60%, transparent)`,
      }} />
      <div style={{
        display: 'flex', gap: 40, whiteSpace: 'nowrap', height: '100%', alignItems: 'center',
        paddingLeft: 200, animation: 'v1-marquee 55s linear infinite',
      }}>
        {all.map((it, i) => (
          <span key={i} style={{ fontFamily: F.mono, fontSize: 11, color: T.ink2, letterSpacing: '0.08em' }}>
            <span style={{ color: T.ink4 }}>◆</span>
            <span style={{ color: T.white, marginLeft: 10, marginRight: 10, fontWeight: 600 }}>{it.c}</span>
            <span style={{ color: T.ink3 }}>{it.r}</span>
            <span style={{ color: T.ink4, margin: '0 10px' }}>·</span>
            <span style={{ color: T.saffron }}>{it.k}</span>
          </span>
        ))}
      </div>
    </div>
  );
};

// Count-up KPI numbers
const CountUp = ({ value, duration = 1600 }) => {
  const [n, setN] = React.useState(0);
  const ref = React.useRef(null);
  const num = parseFloat(String(value).replace(/[^\d.]/g, '')) || 0;
  const suffix = String(value).replace(/[\d.,]/g, '');
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        io.disconnect();
        const start = performance.now();
        const tick = (t) => {
          const p = Math.min((t - start) / duration, 1);
          const eased = 1 - Math.pow(1 - p, 3);
          setN(num * eased);
          if (p < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
      }
    }, { threshold: 0.3 });
    io.observe(el);
    return () => io.disconnect();
  }, [num, duration]);
  const display = Number.isInteger(num) ? Math.round(n).toLocaleString() : n.toFixed(1);
  return <span ref={ref}>{display}{suffix}</span>;
};

const KPIStrip = () => (
  <div className="v1-reveal" style={{
    marginTop: 32, paddingTop: 32, paddingBottom: 32,
    borderTop: `1px solid ${T.line}`,
    display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 16,
  }}>
    {C.hero.kpis.map(([n, l], i) => (
      <div key={i} style={{
        textAlign: 'center', padding: '0 8px',
        borderLeft: i > 0 ? `1px solid ${T.line}` : 'none',
      }}>
        <div style={{
          fontFamily: F.display, color: T.white,
          fontSize: 40, lineHeight: 1, fontWeight: 400, letterSpacing: -1.4,
        }}>
          {/^\d+\D*$/.test(n) ? <CountUp value={n} /> : n}
        </div>
        <div style={{
          fontFamily: F.mono, fontSize: 9.5, fontWeight: 500,
          color: T.ink3, textTransform: 'uppercase',
          letterSpacing: '0.18em', marginTop: 12, lineHeight: 1.5,
        }}>{l}</div>
      </div>
    ))}
  </div>
);

// ══════════════ SECTION HEADER ══════════════
const SecHead = ({ pill, title, titleAccent, lede }) => {
  // Strip "§ NN · " prefix so section numbers don't show.
  const cleanPill = typeof pill === 'string' ? pill.replace(/^§\s*\d+\s*·\s*/, '') : pill;
  return (
  <div style={{ textAlign: 'center', marginBottom: 72 }}>
    <div className="v1-reveal"><span className="v1-pill">{cleanPill}</span></div>
    <h2 className="v1-reveal" data-d="1" style={{
      fontFamily: F.display, fontWeight: 400, fontSize: 56, lineHeight: 1.05,
      letterSpacing: -1.8, color: T.white, margin: '22px auto 0', textWrap: 'balance',
      maxWidth: 860,
    }}>
      {title}
      {titleAccent && <span style={{ color: T.ink3 }}> {titleAccent}</span>}
    </h2>
    {lede && (
      <p className="v1-reveal" data-d="2" style={{
        fontFamily: F.body, fontSize: 17, lineHeight: 1.55,
        color: T.ink3, maxWidth: 640, margin: '20px auto 0', textWrap: 'pretty',
      }}>{lede}</p>
    )}
  </div>
  );
};

// ══════════════ SIGNAL ══════════════
const V1Signal = () => (
  <section id="signal" style={{ padding: '140px 32px 80px', position: 'relative' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto' }}>
      <SecHead pill={C.signal.eyebrow} title={C.signal.h2} lede={C.signal.lede} />
      <div style={{ display: 'grid', gap: 16 }}>
        {C.signal.cards.map((card, i) => (
          <article key={i} className="v1-card v1-reveal" data-d={i + 1} style={{
            padding: '32px 36px',
            display: 'grid', gridTemplateColumns: '90px 1fr auto', gap: 36, alignItems: 'center',
          }}>
            <div style={{
              fontFamily: F.display, fontWeight: 300, fontSize: 64, lineHeight: 1,
              color: T.ink5, letterSpacing: -2,
            }}>{String(i + 1).padStart(2, '0')}</div>
            <div>
              <div style={{
                display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center', marginBottom: 12,
                fontFamily: F.mono, fontSize: 10.5, letterSpacing: '0.14em',
              }}>
                <span style={{
                  color: card.sev === 'CRITICAL' ? T.red : T.saffron,
                  fontWeight: 700,
                  padding: '3px 8px',
                  border: `1px solid ${card.sev === 'CRITICAL' ? 'rgba(229,72,77,0.3)' : T.saffronDim}`,
                  borderRadius: 3,
                }}>{card.sev}</span>
                <span style={{ color: T.ink }}>{card.country}</span>
                <span style={{ color: T.ink5 }}>·</span>
                <span style={{ color: T.ink3 }}>{card.cat}</span>
                <span style={{ color: T.ink5 }}>·</span>
                <span style={{ color: T.ink4 }}>{card.ts}</span>
              </div>
              <div style={{
                fontFamily: F.display, fontSize: 22, lineHeight: 1.3,
                color: T.white, fontWeight: 400, textWrap: 'pretty', letterSpacing: -0.2,
              }}>{card.headline}</div>
              <div style={{
                marginTop: 14, fontFamily: F.mono, fontSize: 10.5,
                color: T.ink4, letterSpacing: '0.12em',
              }}>{card.sources} SOURCES · {card.region.toUpperCase()}</div>
            </div>
            <a href={`${LINKS.app}/incidents/${i + 1}`} target="_blank" rel="noopener" className="v1-link" style={{
              fontFamily: F.body, fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap',
            }}>
              View incident <span className="arrow">→</span>
            </a>
          </article>
        ))}
      </div>
    </div>
  </section>
);

// ══════════════ PLATFORM — bento ══════════════
const V1Platform = () => {
  const t = C.platform.tiles;
  return (
    <section id="platform" style={{ padding: '120px 32px', position: 'relative' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <SecHead pill={C.platform.eyebrow} title={C.platform.h2} lede={C.platform.lede} />
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)',
          gridAutoRows: 'minmax(220px, auto)', gap: 16,
        }}>
          {/* TODO: swap MiniEzekiel / MiniRisk / tiles 2 & 4 for real product screenshots when available */}
          <article className="v1-card v1-reveal" data-d="1" style={{
            gridColumn: 'span 4', gridRow: 'span 2', padding: 0, overflow: 'hidden',
            display: 'flex', flexDirection: 'column',
          }}>
            <div style={{ padding: '32px 32px 24px' }}>
              <Kicker>{t[0].kicker}</Kicker><TileTitle>{t[0].title}</TileTitle><TileBody>{t[0].body}</TileBody>
            </div>
            <div style={{
              position: 'relative', flex: 1, minHeight: 220, overflow: 'hidden',
              borderTop: `1px solid ${T.line}`,
            }}>
              <img src="../../assets/dashboard-map.png" alt="ROAM global incident map"
                style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center', display: 'block' }} />
              {/* top fade into card */}
              <div aria-hidden style={{
                position: 'absolute', inset: 0, pointerEvents: 'none',
                background: `linear-gradient(180deg, ${T.panel} 0%, transparent 12%, transparent 70%, rgba(5,5,6,0.4) 100%)`,
              }} />
            </div>
          </article>
          <article className="v1-card v1-reveal" data-d="2" style={{ gridColumn: 'span 2', gridRow: 'span 2', padding: 28, display: 'flex', flexDirection: 'column' }}>
            <Kicker>{t[1].kicker}</Kicker><TileTitle>{t[1].title}</TileTitle><TileBody>{t[1].body}</TileBody>
            <MiniEzekiel />
          </article>
          <article className="v1-card v1-reveal" data-d="3" style={{ gridColumn: 'span 2', padding: 28 }}>
            <Kicker>{t[2].kicker}</Kicker><TileTitle>{t[2].title}</TileTitle><TileBody>{t[2].body}</TileBody>
          </article>
          <article className="v1-card v1-reveal" data-d="4" style={{ gridColumn: 'span 2', padding: 28 }}>
            <Kicker>{t[3].kicker}</Kicker><TileTitle>{t[3].title}</TileTitle><TileBody>{t[3].body}</TileBody>
            <MiniRisk />
          </article>
          <article className="v1-card v1-reveal" data-d="5" style={{
            gridColumn: 'span 2', padding: 28,
            display: 'flex', flexDirection: 'column',
          }}>
            <Kicker>{t[4].kicker}</Kicker><TileTitle>{t[4].title}</TileTitle><TileBody>{t[4].body}</TileBody>
            <a href={LINKS.brief} target="_blank" rel="noopener" style={{
              marginTop: 'auto', paddingTop: 20,
              fontFamily: F.body, fontSize: 13, fontWeight: 500, color: T.white,
              textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: 8,
              alignSelf: 'flex-start',
              padding: '10px 16px', borderRadius: 999,
              border: `1px solid ${T.lineHi}`, background: 'rgba(255,255,255,0.04)',
              transition: 'background 200ms ease, border-color 200ms ease, transform 200ms ease',
            }}
              onMouseEnter={e => { e.currentTarget.style.background = 'rgba(255,255,255,0.08)'; e.currentTarget.style.borderColor = 'rgba(255,255,255,0.25)'; e.currentTarget.style.transform = 'translateY(-1px)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'rgba(255,255,255,0.04)'; e.currentTarget.style.borderColor = T.lineHi; e.currentTarget.style.transform = 'none'; }}
            >
              Subscribe <span style={{ fontSize: 15 }}>→</span>
            </a>
          </article>
        </div>
      </div>
    </section>
  );
};

const Kicker = ({ children }) => (
  <div style={{
    fontFamily: F.mono, fontSize: 10.5, color: T.saffron,
    letterSpacing: '0.2em', fontWeight: 500, marginBottom: 16, textTransform: 'uppercase',
  }}>— {children}</div>
);
const TileTitle = ({ children }) => (
  <h3 style={{
    fontFamily: F.display, fontSize: 22, fontWeight: 400, color: T.white,
    margin: 0, lineHeight: 1.25, letterSpacing: -0.4,
  }}>{children}</h3>
);
const TileBody = ({ children }) => (
  <p style={{
    fontFamily: F.body, fontSize: 14, lineHeight: 1.55, color: T.ink3,
    margin: '10px 0 0', textWrap: 'pretty',
  }}>{children}</p>
);

const MiniMap = () => (
  <svg aria-hidden viewBox="0 0 600 340" style={{
    position: 'absolute', inset: 0, width: '100%', height: '100%',
    opacity: 0.55, pointerEvents: 'none',
  }}>
    <defs>
      <pattern id="v1dots" width="8" height="8" patternUnits="userSpaceOnUse">
        <circle cx="1" cy="1" r="0.7" fill="rgba(255,255,255,0.16)" />
      </pattern>
    </defs>
    <rect width="600" height="340" fill="url(#v1dots)"
      style={{ maskImage: 'radial-gradient(ellipse at 70% 60%, black 20%, transparent 70%)', WebkitMaskImage: 'radial-gradient(ellipse at 70% 60%, black 20%, transparent 70%)' }} />
    {[[180, 140, 0], [320, 180, 0.4], [420, 130, 0.8], [260, 220, 1.2], [490, 220, 1.6]].map(([x, y, d], i) => (
      <g key={i}>
        <circle cx={x} cy={y} r="3" fill={T.saffron} />
        <circle cx={x} cy={y} r="12" fill="none" stroke={T.saffron} strokeWidth="0.8" opacity="0.5">
          <animate attributeName="r" from="3" to="26" dur="2.4s" begin={`${d}s`} repeatCount="indefinite" />
          <animate attributeName="opacity" from="0.7" to="0" dur="2.4s" begin={`${d}s`} repeatCount="indefinite" />
        </circle>
      </g>
    ))}
    {/* connecting dashed path */}
    <path d="M 180 140 L 320 180 L 420 130 L 490 220" fill="none" stroke="rgba(255,255,255,0.1)" strokeWidth="0.8" strokeDasharray="3 4">
      <animate attributeName="stroke-dashoffset" from="0" to="-40" dur="2s" repeatCount="indefinite" />
    </path>
  </svg>
);

// Typewriter Ezekiel
const MiniEzekiel = () => {
  const full = "What happened to house churches in Henan?";
  const [t, setT] = React.useState('');
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        io.disconnect();
        let i = 0;
        const tick = () => {
          if (i <= full.length) { setT(full.slice(0, i)); i++; setTimeout(tick, 40); }
        };
        tick();
      }
    }, { threshold: 0.5 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} style={{ marginTop: 'auto', paddingTop: 20, display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div style={{
        background: 'rgba(255,255,255,0.02)', border: `1px solid ${T.line}`,
        borderRadius: 8, padding: '11px 14px', fontFamily: F.mono, fontSize: 11.5,
        color: T.ink, minHeight: 40,
      }}>
        <span style={{ color: T.saffron }}>&gt;</span> {t}
        <span style={{ animation: 'v1-caret 1s step-end infinite', color: T.saffron }}>▊</span>
      </div>
      <div style={{ fontFamily: F.mono, fontSize: 9.5, color: T.ink4, letterSpacing: '0.14em' }}>
        3 SOURCES · CONFIDENCE 94%
      </div>
    </div>
  );
};

// Risk bars animate in
const MiniRisk = () => {
  const items = [['PAKISTAN', 82], ['NIGERIA', 74], ['INDIA', 61]];
  const ref = React.useRef(null);
  const [on, setOn] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(e => { if (e[0].isIntersecting) { setOn(true); io.disconnect(); } }, { threshold: 0.5 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} style={{ marginTop: 20, display: 'flex', flexDirection: 'column', gap: 10 }}>
      {items.map(([c, v], i) => (
        <div key={c} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 72, fontFamily: F.mono, fontSize: 10, color: T.ink3, letterSpacing: '0.1em' }}>{c}</div>
          <div style={{ flex: 1, height: 3, background: 'rgba(255,255,255,0.06)', borderRadius: 2, overflow: 'hidden' }}>
            <div style={{
              width: on ? `${v}%` : '0%', height: '100%', background: T.white,
              transition: `width 1.6s cubic-bezier(.22,.75,.3,1) ${i * 120}ms`,
            }} />
          </div>
          <div style={{ fontFamily: F.mono, fontSize: 10, color: T.ink, width: 24, textAlign: 'right' }}>{v}</div>
        </div>
      ))}
    </div>
  );
};

// ══════════════ PRICING ══════════════
const V1Pricing = () => (
  <section id="pricing" style={{ padding: '120px 32px', position: 'relative' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto' }}>
      <SecHead pill={C.pricing.eyebrow} title={C.pricing.h2_prefix} titleAccent={C.pricing.h2_suffix} lede={C.pricing.lede} />
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 16, alignItems: 'stretch' }}>
        {C.pricing.tiers.map((tier, i) => <TierCard key={tier.name} tier={tier} i={i} />)}
      </div>
    </div>
  </section>
);

const TierCard = ({ tier, i }) => {
  const rec = tier.recommended;
  return (
    <article className="v1-card v1-reveal" data-d={i + 1} style={{
      padding: 28, display: 'flex', flexDirection: 'column', position: 'relative',
      ...(rec ? {
        borderColor: T.saffronDim,
        background: `linear-gradient(180deg, rgba(250,199,97,0.04) 0%, transparent 40%), ${T.panel}`,
      } : {}),
    }}>
      {rec && (
        <div style={{
          display: 'inline-block', background: T.saffron, color: '#1a0f00',
          padding: '4px 10px', borderRadius: 999,
          fontFamily: F.mono, fontSize: 9.5, fontWeight: 700, letterSpacing: '0.18em',
          alignSelf: 'flex-start', marginBottom: 12, textTransform: 'uppercase', whiteSpace: 'nowrap',
        }}>RECOMMENDED</div>
      )}
      <div style={{
        fontFamily: F.display, fontWeight: 500, fontSize: 13, color: T.ink,
        letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 16,
      }}>{tier.name}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap', marginBottom: 24 }}>
        <span style={{
          fontFamily: F.display, fontSize: 44, color: T.white,
          letterSpacing: -1.8, lineHeight: 1, fontWeight: 400,
        }}>{tier.price}</span>
        {tier.unit && (
          <span style={{ fontFamily: F.body, fontSize: 12, color: T.ink3 }}>{tier.unit}</span>
        )}
      </div>
      <ul style={{ listStyle: 'none', padding: 0, margin: '0 0 28px', display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
        {tier.features.map((f, j) => (
          <li key={j} style={{
            display: 'flex', alignItems: 'flex-start', gap: 10,
            fontFamily: F.body, fontSize: 13, lineHeight: 1.5, color: T.ink2,
          }}>
            <span style={{ color: T.ink3, flexShrink: 0, fontSize: 11, lineHeight: '20px' }}>—</span>
            <span>{f}</span>
          </li>
        ))}
      </ul>
      {tier.ctaStyle === 'primary' ? (
        <a href={LINKS.app} target="_blank" rel="noopener" className="v1-cta-pri" style={{
          fontSize: 13.5, borderRadius: 8, padding: '11px 16px', cursor: 'pointer', width: '100%',
          textDecoration: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          boxSizing: 'border-box',
        }}>{tier.cta}</a>
      ) : (
        <a href={LINKS.app} target="_blank" rel="noopener" className="v1-cta-ghost" style={{
          fontSize: 13.5, borderRadius: 8, padding: '11px 16px', cursor: 'pointer', width: '100%',
          textDecoration: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          boxSizing: 'border-box',
        }}>{tier.cta}</a>
      )}
    </article>
  );
};

// ══════════════ ROOT ══════════════
function V1App() {
  useReveal();
  // Sections defined in sections-v1.jsx — pulled from window at render time
  // because Babel scripts don't share lexical scope.
  const { V1Gap, V1Origin, V1Missions, V1Ezekiel, V1Pipeline, V1Trust, V1Weekly, V1Founder, V1FinalCta, V1Footer } = window;
  return (
    <div style={{ background: T.bg, color: T.ink, minHeight: '100vh', position: 'relative' }}>
      <AmbientBg />
      <div style={{ position: 'relative', zIndex: 1 }}>
        <V1Nav />
        <V1Hero />
        <V1Signal />
        {V1Gap && <V1Gap />}
        {V1Origin && <V1Origin />}
        {V1Missions && <V1Missions />}
        <V1Platform />
        {V1Ezekiel && <V1Ezekiel />}
        {V1Pipeline && <V1Pipeline />}
        {V1Trust && <V1Trust />}
        <V1Pricing />
        {V1Weekly && <V1Weekly />}
        {V1FinalCta && <V1FinalCta />}
        {V1Footer && <V1Footer />}
      </div>
    </div>
  );
}

// Expose shared helpers + components for sections-v1.jsx (separate Babel scope)
Object.assign(window, { T, F, SecHead, useReveal, LINKS });

// Defer mount until sections-v1.jsx has had a chance to load + register.
// If sections-v1.jsx runs first (unlikely) it's a no-op; if app.jsx runs first
// we wait for it, then force a re-render by mounting after a tick.
(function mountWhenReady() {
  const needed = ['V1Gap','V1Origin','V1Missions','V1Ezekiel','V1Pipeline','V1Trust','V1Weekly','V1Founder','V1FinalCta','V1Footer'];
  if (needed.every(k => window[k])) {
    ReactDOM.createRoot(document.getElementById('root')).render(<V1App />);
  } else {
    setTimeout(mountWhenReady, 30);
  }
})();
