// ContinuousSecurityHero — a self-contained, full-bleed landing hero for
// sekura.ai. Conforms to this site's actual stack: in-browser Babel loads this
// file as a global (no ESM imports, no TypeScript, no Tailwind — none of which
// the site builds). React comes off `window`; the component registers itself as
// `window.ContinuousSecurityHero` and is mounted through app/page.jsx, exactly
// like every other component here.
//
// All styling is plain CSS scoped under `.cs-hero` and injected once via a
// <style> tag, so the component is fully self-contained with no new stylesheet
// dependency and no external assets. Brand tokens mirror :root in styles.css.
//
//  - Cursor-interactive particle constellation in vanilla canvas 2D.
//  - Respects prefers-reduced-motion (one settle pass, no rAF loop).
//  - Pauses the loop when the tab is hidden or the canvas scrolls offscreen.
//  - DPR-aware + resize-aware so it stays crisp on retina with no layout shift.

function ContinuousSecurityHero({ children }) {
  const { React } = window;
  const { useEffect, useRef } = React;

  // ── brand tokens (mirror :root in styles.css) ────────────────────────────
  const COLORS = {
    ink: '#0B0F0E', // --term-bg
    inkDeep: '#0E1413', // --term-bg-2
    forest: '#1E3429', // --forest-deep
    sage: '#7FB394', // --term-phase
    coral: '#E8847C', // --coral
    cream: '#F5F2EB', // --cream
    fg: '#D7DDD9', // --term-fg
  };

  // ── content (edit freely) ─────────────────────────────────────────────────
  const VALUE_PROPS = [
    { title: 'CI/CD integration', body: 'Every build tested automatically, on every pull request.' },
    { title: 'Adversarial testing', body: 'Threat models tailored to your real attack surface.' },
    { title: 'Verified remediation', body: 'Every finding ships with a proof-of-exploit and a fix.' },
  ];

  // Add/remove badges here — e.g. push 'Post-Quantum Ready'.
  const BADGES = ['SOC 2 Type II', 'OWASP recognized'];

  const TICKER_ITEMS = [
    'AGENTS: ACTIVE',
    'VERDICTGATE: ENFORCING',
    'ATTACK SURFACE: MAPPED',
    'PROTOCOL: CONTINUOUS',
    'SANDBOX: ISOLATED',
    'FINDINGS: POC-VERIFIED',
    'REMEDIATION: AUTO',
  ];
  const TICKER_TEXT = TICKER_ITEMS.join('  ·  ');

  // ── canvas constellation ──────────────────────────────────────────────────
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // tuning
    const LINK_DISTANCE = 130; // px: particle↔particle line threshold
    const CURSOR_RADIUS = 160; // px: repel + cursor-line radius
    const MAX_PUSH = 0.9; // cap on per-frame repel acceleration (subtle)
    const DRIFT = 0.14; // base drift speed (px/frame)
    const PUSH_DECAY = 0.9; // how fast the repel impulse eases back to drift

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

    let particles = [];
    let width = 0;
    let height = 0;
    let dpr = 1;
    let rafId = 0;
    let running = false;

    // Mouse state in CSS pixels; active=false means "no cursor over hero".
    const mouse = { x: -1, y: -1, active: false };

    const rand = (min, max) => min + Math.random() * (max - min);

    const targetCount = () => {
      // Scale by screen area, fewer on mobile. Clamp to ~40–120.
      const n = Math.round((width * height) / 14000);
      return Math.max(40, Math.min(120, n));
    };

    const spawn = (n) =>
      Array.from({ length: n }, () => {
        const a = rand(0, Math.PI * 2);
        return {
          x: rand(0, width),
          y: rand(0, height),
          vx: Math.cos(a) * DRIFT,
          vy: Math.sin(a) * DRIFT,
          px: 0, // transient push velocity (decays → ease back to free drift)
          py: 0,
        };
      });

    const resize = () => {
      const rect = canvas.getBoundingClientRect();
      dpr = Math.min(window.devicePixelRatio || 1, 2); // cap DPR for perf
      width = Math.max(1, Math.round(rect.width));
      height = Math.max(1, Math.round(rect.height));
      canvas.width = Math.round(width * dpr);
      canvas.height = Math.round(height * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // draw in CSS px, crisp on retina

      const want = targetCount();
      if (particles.length === 0) {
        particles = spawn(want);
      } else if (want > particles.length) {
        particles = particles.concat(spawn(want - particles.length));
      } else if (want < particles.length) {
        particles = particles.slice(0, want);
        for (const p of particles) {
          if (p.x > width) p.x = rand(0, width);
          if (p.y > height) p.y = rand(0, height);
        }
      }
      if (reduceMotion) draw(); // keep static field correct after resize
    };

    const step = () => {
      for (const p of particles) {
        // Cursor repel: push along (cursor → particle), strength ∝ 1/dist, capped.
        if (mouse.active) {
          const dx = p.x - mouse.x;
          const dy = p.y - mouse.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < CURSOR_RADIUS * CURSOR_RADIUS && d2 > 0.0001) {
            const d = Math.sqrt(d2);
            const force = Math.min(MAX_PUSH, ((CURSOR_RADIUS - d) / CURSOR_RADIUS) * MAX_PUSH);
            p.px += (dx / d) * force;
            p.py += (dy / d) * force;
          }
        }

        // Ease the transient push back toward free drift.
        p.px *= PUSH_DECAY;
        p.py *= PUSH_DECAY;

        p.x += p.vx + p.px;
        p.y += p.vy + p.py;

        // Bounce at edges (base drift only — keeps motion calm).
        if (p.x <= 0) { p.x = 0; p.vx = Math.abs(p.vx); }
        else if (p.x >= width) { p.x = width; p.vx = -Math.abs(p.vx); }
        if (p.y <= 0) { p.y = 0; p.vy = Math.abs(p.vy); }
        else if (p.y >= height) { p.y = height; p.vy = -Math.abs(p.vy); }
      }
    };

    const draw = () => {
      ctx.clearRect(0, 0, width, height);

      // Particle-to-particle links (closer = brighter).
      for (let i = 0; i < particles.length; i++) {
        const a = particles[i];
        for (let j = i + 1; j < particles.length; j++) {
          const b = particles[j];
          const dx = a.x - b.x;
          const dy = a.y - b.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < LINK_DISTANCE * LINK_DISTANCE) {
            const d = Math.sqrt(d2);
            const o = (1 - d / LINK_DISTANCE) * 0.22;
            ctx.strokeStyle = `rgba(127,179,148,${o})`; // sage
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y);
            ctx.lineTo(b.x, b.y);
            ctx.stroke();
          }
        }
      }

      // Cursor → particle links (brighter, coral) + the cursor node.
      if (mouse.active) {
        for (const p of particles) {
          const dx = p.x - mouse.x;
          const dy = p.y - mouse.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < CURSOR_RADIUS * CURSOR_RADIUS) {
            const d = Math.sqrt(d2);
            const o = (1 - d / CURSOR_RADIUS) * 0.5;
            ctx.strokeStyle = `rgba(232,132,124,${o})`; // coral
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(mouse.x, mouse.y);
            ctx.lineTo(p.x, p.y);
            ctx.stroke();
          }
        }
        ctx.fillStyle = 'rgba(232,132,124,0.9)';
        ctx.beginPath();
        ctx.arc(mouse.x, mouse.y, 2.5, 0, Math.PI * 2);
        ctx.fill();
      }

      // Particle dots.
      ctx.fillStyle = 'rgba(215,221,217,0.85)'; // --term-fg
      for (const p of particles) {
        ctx.beginPath();
        ctx.arc(p.x, p.y, 1.5, 0, Math.PI * 2);
        ctx.fill();
      }
    };

    const loop = () => {
      step();
      draw();
      rafId = requestAnimationFrame(loop);
    };

    const start = () => {
      if (running || reduceMotion) return;
      running = true;
      rafId = requestAnimationFrame(loop);
    };
    const stop = () => {
      running = false;
      cancelAnimationFrame(rafId);
    };

    // ── pointer tracking (canvas is pointer-events:none, listen on window) ───
    const onPointerMove = (e) => {
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      if (x >= 0 && y >= 0 && x <= rect.width && y <= rect.height) {
        mouse.x = x;
        mouse.y = y;
        mouse.active = true;
      } else {
        mouse.active = false; // off the hero → particles ease back to drift
      }
    };
    const onPointerLeave = () => { mouse.active = false; };

    // ── visibility + offscreen gating ────────────────────────────────────────
    let onScreen = true;
    const updateRun = () => {
      if (onScreen && document.visibilityState === 'visible') start();
      else stop();
    };
    const onVisibility = () => updateRun();

    const io = new IntersectionObserver(
      ([entry]) => {
        onScreen = entry.isIntersecting;
        updateRun();
      },
      { threshold: 0 },
    );
    io.observe(canvas);

    let resizeRaf = 0;
    const onResize = () => {
      cancelAnimationFrame(resizeRaf);
      resizeRaf = requestAnimationFrame(resize);
    };

    // ── init ─────────────────────────────────────────────────────────────────
    resize();
    if (reduceMotion) {
      step(); // one settle pass for a non-degenerate static field
      draw();
    } else {
      updateRun();
    }

    window.addEventListener('resize', onResize);
    window.addEventListener('pointermove', onPointerMove, { passive: true });
    window.addEventListener('pointerleave', onPointerLeave);
    document.addEventListener('visibilitychange', onVisibility);

    return () => {
      stop();
      cancelAnimationFrame(resizeRaf);
      io.disconnect();
      window.removeEventListener('resize', onResize);
      window.removeEventListener('pointermove', onPointerMove);
      window.removeEventListener('pointerleave', onPointerLeave);
      document.removeEventListener('visibilitychange', onVisibility);
    };
  }, []);

  return (
    <section className="cs-hero" aria-label="Continuous Security">
      {/* scoped, self-contained styling — no Tailwind, no external stylesheet */}
      <style>{`
        .cs-hero {
          position: relative;
          isolation: isolate;
          display: flex;
          flex-direction: column;
          width: 100%;
          min-height: 100svh;
          overflow: hidden;
          background: ${COLORS.forest}; /* match .scan-band (--forest-deep) */
          color: ${COLORS.cream};
          font-family: 'Inter Tight', ui-sans-serif, system-ui, sans-serif;
          -webkit-font-smoothing: antialiased;
        }

        /* full-bleed animated background, behind all content */
        .cs-bg { position: absolute; inset: 0; z-index: -10; }
        .cs-bg-ground {
          position: absolute; inset: 0;
          background:
            radial-gradient(1100px 520px at 78% -8%, rgba(11,15,14,0.45), transparent 60%),
            radial-gradient(900px 460px at 12% 12%, rgba(127,179,148,0.10), transparent 60%),
            linear-gradient(180deg, ${COLORS.forest} 0%, ${COLORS.forest} 100%);
        }
        .cs-canvas {
          position: absolute; inset: 0;
          width: 100%; height: 100%;
          pointer-events: none; /* never blocks clicks */
        }
        .cs-bg-veil {
          position: absolute; inset: 0;
          background:
            radial-gradient(120% 90% at 50% 38%, transparent 30%, rgba(20,34,27,0.55) 100%),
            linear-gradient(180deg, transparent 55%, ${COLORS.forest} 100%);
        }

        /* centered content column */
        .cs-content {
          margin: 0 auto;
          display: flex;
          flex: 1 1 auto;
          flex-direction: column;
          align-items: center;
          width: 100%;
          max-width: 64rem;
          padding: 6rem 1.5rem 7rem;
          text-align: center;
        }

        .cs-eyebrow {
          display: inline-flex;
          align-items: center;
          gap: 0.5rem;
          margin-bottom: 1.5rem;
          padding: 0.375rem 0.875rem;
          border: 1px solid rgba(127,179,148,0.25);
          border-radius: 999px;
          background: rgba(127,179,148,0.06);
          font-family: 'JetBrains Mono', ui-monospace, monospace;
          font-size: 11px;
          text-transform: uppercase;
          letter-spacing: 0.18em;
          color: ${COLORS.sage};
        }
        .cs-eyebrow-dot { position: relative; display: inline-flex; width: 6px; height: 6px; }
        .cs-eyebrow-dot::before {
          content: ''; position: absolute; inset: 0; border-radius: 999px;
          background: ${COLORS.sage}; opacity: 0.6;
          animation: cs-ping 1.6s cubic-bezier(0,0,0.2,1) infinite;
        }
        .cs-eyebrow-dot::after {
          content: ''; position: relative; width: 6px; height: 6px;
          border-radius: 999px; background: ${COLORS.sage};
        }
        @keyframes cs-ping {
          75%, 100% { transform: scale(2.2); opacity: 0; }
        }

        .cs-h1 {
          margin: 0;
          font-size: clamp(2.75rem, 8vw, 5.25rem);
          font-weight: 600;
          line-height: 0.98;
          letter-spacing: -0.03em;
          text-transform: lowercase;
          text-wrap: balance;
        }
        .cs-h1 em {
          font-family: 'Fraunces', Georgia, serif;
          font-weight: 400;
          font-style: italic;
          color: ${COLORS.coral};
        }

        .cs-lede {
          margin: 1.5rem 0 0;
          max-width: 42rem;
          font-size: 1rem;
          line-height: 1.6;
          color: #C9D2CC;
          text-wrap: pretty;
        }

        /* value props */
        .cs-props {
          list-style: none;
          margin: 3rem 0 0;
          padding: 0;
          width: 100%;
          max-width: 56rem;
          display: grid;
          grid-template-columns: 1fr;
          gap: 1px;
          overflow: hidden;
          border: 1px solid rgba(245,242,235,0.08);
          border-radius: 0.75rem;
          background: rgba(245,242,235,0.06);
          text-align: left;
        }
        .cs-prop {
          background: rgba(11,15,14,0.55);
          padding: 1.25rem 1.5rem;
          -webkit-backdrop-filter: blur(4px);
          backdrop-filter: blur(4px);
        }
        .cs-prop h2 {
          margin: 0;
          font-size: 15px;
          font-weight: 600;
          letter-spacing: -0.01em;
          color: ${COLORS.cream};
        }
        .cs-prop p {
          margin: 0.375rem 0 0;
          font-size: 0.875rem;
          line-height: 1.6;
          color: #9BA8A1;
        }

        /* trust badges */
        .cs-badges {
          list-style: none;
          margin: 2rem 0 0;
          padding: 0;
          display: flex;
          flex-wrap: wrap;
          align-items: center;
          justify-content: center;
          gap: 0.625rem;
        }
        .cs-badge {
          padding: 0.375rem 0.875rem;
          border: 1px solid rgba(245,242,235,0.12);
          border-radius: 999px;
          background: rgba(245,242,235,0.03);
          font-family: 'JetBrains Mono', ui-monospace, monospace;
          font-size: 11px;
          text-transform: uppercase;
          letter-spacing: 0.12em;
          color: #8A948F;
        }

        /* overlay slot — sits in the hero's lower free space, right above the
           ticker. .cs-content (flex:1 1 auto) absorbs the slack above it, so
           this hugs the ticker with the free space collecting overhead. */
        .cs-overlay-slot {
          position: relative;
          z-index: 5;
          width: 100%;
        }
        /* the scan band, when nested here, floats on the hero: no solid forest
           fill, no 84px nav-clearing top padding (the hero already clears it). */
        .cs-hero .scan-band {
          background: transparent;
          padding: 0 1.5rem 0.5rem;
        }

        /* infinite ticker, pinned near the bottom of the hero */
        .cs-ticker {
          position: relative;
          z-index: 10;
          width: 100%;
          overflow: hidden;
          border-top: 1px solid rgba(245,242,235,0.08);
          background: rgba(30,52,41,0.7); /* forest-deep, blends into .scan-band */
          padding: 0.75rem 0;
          -webkit-backdrop-filter: blur(4px);
          backdrop-filter: blur(4px);
        }
        .cs-ticker-fade {
          position: absolute; inset-block: 0; z-index: 10; width: 4rem;
          pointer-events: none;
        }
        .cs-ticker-fade--l { left: 0; background: linear-gradient(90deg, ${COLORS.forest}, transparent); }
        .cs-ticker-fade--r { right: 0; background: linear-gradient(270deg, ${COLORS.forest}, transparent); }
        .cs-ticker-track {
          display: flex;
          width: max-content;
          white-space: nowrap;
          font-family: 'JetBrains Mono', ui-monospace, monospace;
          font-size: 11px;
          text-transform: uppercase;
          letter-spacing: 0.16em;
          color: #6E7A73;
          animation: cs-ticker 38s linear infinite;
          will-change: transform;
        }
        .cs-ticker-track > span { padding: 0 1rem; }
        .cs-ticker:hover .cs-ticker-track { animation-play-state: paused; }
        @keyframes cs-ticker {
          from { transform: translate3d(0, 0, 0); }
          to   { transform: translate3d(-50%, 0, 0); }
        }

        /* responsive: 3-up props, roomier spacing on larger screens */
        @media (min-width: 640px) {
          .cs-content { padding: 7rem 2rem 7rem; max-width: 64rem; }
          .cs-lede { font-size: 1.125rem; }
          .cs-props { grid-template-columns: repeat(3, 1fr); }
          .cs-prop { padding: 1.5rem; }
          .cs-prop h2 { font-size: 1rem; }
          .cs-ticker-fade { width: 7rem; }
          .cs-ticker-track { font-size: 12px; }
        }
        @media (min-width: 768px) {
          .cs-lede { font-size: 1.25rem; }
        }
        @media (min-width: 1024px) {
          .cs-content { padding: 8rem 2rem 8rem; }
        }

        /* motion guards — freeze ticker + ping, canvas freezes itself */
        @media (prefers-reduced-motion: reduce) {
          .cs-ticker-track { animation: none; }
          .cs-eyebrow-dot::before { animation: none; }
        }
      `}</style>

      <div className="cs-bg" aria-hidden="true">
        <div className="cs-bg-ground" />
        <canvas ref={canvasRef} className="cs-canvas" aria-hidden="true" />
        <div className="cs-bg-veil" />
      </div>

      <div className="cs-content">
        <div className="cs-eyebrow">
          <span className="cs-eyebrow-dot" />
          autonomous penetration testing
        </div>

        <h1 className="cs-h1">
          Continuous <em>Security</em>
        </h1>

        <p className="cs-lede">
          Autonomous AI agents continuously attack your systems, prove every
          exploit, and ship verified fixes — before real adversaries find the
          gap.
        </p>

        <ul className="cs-props" aria-label="what you get">
          {VALUE_PROPS.map((vp) => (
            <li className="cs-prop" key={vp.title}>
              <h2>{vp.title}</h2>
              <p>{vp.body}</p>
            </li>
          ))}
        </ul>

        <ul className="cs-badges" aria-label="trust and compliance">
          {BADGES.map((badge) => (
            <li className="cs-badge" key={badge}>{badge}</li>
          ))}
        </ul>
      </div>

      {/* Optional slot rendered in the hero's lower free space, above the
          ticker — used on the landing page to overlay the scan band. */}
      {children ? <div className="cs-overlay-slot">{children}</div> : null}

      <div className="cs-ticker" aria-hidden="true">
        <div className="cs-ticker-fade cs-ticker-fade--l" />
        <div className="cs-ticker-fade cs-ticker-fade--r" />
        <div className="cs-ticker-track">
          {/* duplicated so a -50% translate loops seamlessly with no gap */}
          <span>{TICKER_TEXT}</span>
          <span>{TICKER_TEXT}</span>
        </div>
      </div>
    </section>
  );
}

window.ContinuousSecurityHero = ContinuousSecurityHero;
