/* Light landing — CVI positioning. v2 (2026-07-27):
   - ONE product (Causal Engine); Sovereign = deployment form, roadmap = cross-industry
   - Method upgraded to 4 steps (extract → structure → identify → validate & simulate)
   - Founder strip (photo + one line + LinkedIn) for operational transparency
   - GraphFlow: subtle animated background — dots drifting through a graph net,
     cyan signal particles flowing toward a convergence point. Reduced-motion safe. */
function LandingPage() {
  return (
    <div className="min-h-screen flex flex-col bg-paper">
      <PublicNav/>
      <main className="flex-1">
        <Hero/>
        <ProductSection/>
        <HowItWorks/>
        <FounderStrip/>
        <Quote/>
        <CTA/>
      </main>
      <Footer/>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* GraphFlow — canvas particle network in the hero background.
   Faint ink nodes drift slowly; edges appear between close nodes; a few
   cyan "signal" particles travel left → right toward a sink (feedback
   flowing through the causal net to insight). Pauses when the tab is
   hidden. prefers-reduced-motion → static dot grid (no canvas).        */
const { useEffect: gfUseEffect, useRef: gfUseRef, useState: gfUseState } = React;

function GraphFlowCanvas() {
  const canvasRef = gfUseRef(null);

  gfUseEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf = null;
    let running = true;
    let W = 0, H = 0;
    const DPR = Math.min(window.devicePixelRatio || 1, 2);

    /* Brand palette, theme-aware. Navy -> cyan is the one allowed gradient
       (same as .grad-word), so the net reads as part of the system. */
    const isDark = () => document.documentElement.getAttribute('data-theme') === 'dark';
    let PAL = null;
    const readColors = () => {
      PAL = isDark()
        ? { edge: [96, 165, 250],  node: [170, 190, 220], cyan: [34, 211, 238] }
        : { edge: [30, 58, 138],   node: [30, 58, 138],   cyan: [8, 145, 178] };
    };
    readColors();
    const themeObs = new MutationObserver(readColors);
    themeObs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });

    const rand = (a, b) => a + Math.random() * (b - a);

    /* ── 3D network cloud ──
       Points live on a loose ellipsoid shell in 3D. Topology is fixed
       (2-nearest neighbours + component stitching = ONE connected net).
       The whole cloud rotates slowly around Y with a slight X wobble;
       perspective projection gives genuine depth: near nodes are larger
       and brighter, far ones recede. */
    let nodes = [], edges = [], adj = [];
    let signals = [];
    const SIGNALS = 12;
    let CX = 0, CY = 0, RX = 0, RY = 0, RZ = 0, F = 1;

    const buildGraph = () => {
      const N = 150;
      nodes = [];
      for (let i = 0; i < N; i++) {
        /* direction on unit sphere, radius biased to a shell band */
        const th = rand(0, Math.PI * 2);
        const ph = Math.acos(rand(-1, 1));
        const r = 0.55 + 0.45 * Math.random();
        nodes.push({
          x0: Math.sin(ph) * Math.cos(th) * r,
          y0: Math.cos(ph) * r,
          z0: Math.sin(ph) * Math.sin(th) * r,
          x: 0, y: 0, s: 1, d: 0,
        });
      }
      const d2 = (a, b) => {
        const dx = a.x0 - b.x0, dy = a.y0 - b.y0, dz = a.z0 - b.z0;
        return dx * dx + dy * dy + dz * dz;
      };
      const key = (i, j) => (i < j ? i * 100000 + j : j * 100000 + i);
      const seen = new Set();
      edges = [];
      const pushEdge = (i, j) => {
        if (i === j) return;
        const k = key(i, j);
        if (seen.has(k)) return;
        seen.add(k); edges.push([i, j]);
      };
      for (let i = 0; i < N; i++) {
        const order = nodes.map((n, j) => [d2(nodes[i], n), j]).sort((a, b) => a[0] - b[0]);
        pushEdge(i, order[1][1]);
        pushEdge(i, order[2][1]);
      }
      const parent = Array.from({ length: N }, (_, i) => i);
      const find = (x) => { while (parent[x] !== x) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; };
      const union = (a, b) => { parent[find(a)] = find(b); };
      for (const [i, j] of edges) union(i, j);
      let guard = 0;
      while (guard++ < N) {
        const roots = new Set();
        for (let i = 0; i < N; i++) roots.add(find(i));
        if (roots.size <= 1) break;
        const rootA = Array.from(roots)[0];
        let best = null;
        for (let i = 0; i < N; i++) {
          if (find(i) !== rootA) continue;
          for (let j = 0; j < N; j++) {
            if (find(j) === rootA) continue;
            const d = d2(nodes[i], nodes[j]);
            if (!best || d < best[0]) best = [d, i, j];
          }
        }
        pushEdge(best[1], best[2]); union(best[1], best[2]);
      }
      adj = Array.from({ length: nodes.length }, () => []);
      for (const [i, j] of edges) { adj[i].push(j); adj[j].push(i); }
    };

    /* Bubbles: random walk along the edges, in 3D */
    const newWalk = (s) => {
      s.from = Math.floor(Math.random() * nodes.length);
      const nb = adj[s.from];
      s.to = nb[Math.floor(Math.random() * nb.length)];
      s.t = Math.random() * 0.6;
      s.v = rand(0.10, 0.16);                     /* edge fractions per second */
    };
    const buildSignals = () => {
      signals = [];
      for (let i = 0; i < SIGNALS; i++) { const s = {}; newWalk(s); signals.push(s); }
    };
    const advanceWalk = (s) => {
      const nb = adj[s.to].filter(n => n !== s.from);
      const pool = nb.length ? nb : adj[s.to];
      const next = pool[Math.floor(Math.random() * pool.length)];
      s.from = s.to; s.to = next; s.t = 0;
    };

    const resize = () => {
      const rect = canvas.parentElement.getBoundingClientRect();
      W = rect.width; H = rect.height;
      canvas.width = W * DPR; canvas.height = H * DPR;
      canvas.style.width = W + 'px'; canvas.style.height = H + 'px';
      ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
      /* Large globe anchored AT the right screen edge, reaching into the
         page — partially clipped right, dissolving toward the centre. */
      CX = W * 0.88; CY = H * 0.47;
      RX = Math.max(W * 0.48, H * 0.60);
      RY = H * 0.55;
      RZ = RX;
      F  = RX * 2.6;                              /* perspective focal length */
      buildGraph();
      buildSignals();
    };

    const project = (n, sinA, cosA, sinB, cosB) => {
      /* rotate around Y, then slight X wobble */
      const x1 = n.x0 * cosA + n.z0 * sinA;
      const z1 = -n.x0 * sinA + n.z0 * cosA;
      const y1 = n.y0 * cosB - z1 * sinB;
      const z2 = n.y0 * sinB + z1 * cosB;
      const per = F / (F + z2 * RZ);
      n.x = CX + x1 * RX * per;
      n.y = CY + y1 * RY * per;
      n.s = per;
      n.d = Math.min(1, Math.max(0, (1.18 - per) * -4 + 1));  /* 0 far .. 1 near */
      /* simpler + stable: normalize via z2 in [-1,1] */
      n.d = 1 - (z2 + 1) / 2;
    };

    let last = performance.now();
    const step = (now) => {
      if (!running) return;
      const dt = Math.min(50, now - last); last = now;
      ctx.clearRect(0, 0, W, H);

      const a = now * 0.000055;                    /* ~1 rev / 115 s */
      const b = Math.sin(now * 0.000031) * 0.16;   /* gentle wobble */
      const sinA = Math.sin(a), cosA = Math.cos(a);
      const sinB = Math.sin(b), cosB = Math.cos(b);
      for (const n of nodes) project(n, sinA, cosA, sinB, cosB);

      /* edges — depth-cued, navy base with a whisper of cyan on near edges */
      ctx.lineWidth = 1;
      const [er, eg, eb] = PAL.edge;
      const [cr, cg, cb] = PAL.cyan;
      for (const [i, j] of edges) {
        const A = nodes[i], B = nodes[j];
        const depth = (A.d + B.d) / 2;             /* 0 far .. 1 near */
        const mix = depth * 0.45;                  /* cyan share on near edges */
        const R2 = Math.round(er + (cr - er) * mix);
        const G2 = Math.round(eg + (cg - eg) * mix);
        const B2 = Math.round(eb + (cb - eb) * mix);
        const alpha = 0.025 + 0.105 * depth * depth;
        ctx.strokeStyle = `rgba(${R2}, ${G2}, ${B2}, ${alpha.toFixed(3)})`;
        ctx.beginPath();
        ctx.moveTo(A.x, A.y);
        ctx.lineTo(B.x, B.y);
        ctx.stroke();
      }

      /* nodes — size + brightness by depth */
      const [nr, ng, nb2] = PAL.node;
      for (const n of nodes) {
        const alpha = 0.05 + 0.26 * n.d * n.d;
        const rad = 0.7 + 1.5 * n.d * n.s;
        ctx.fillStyle = `rgba(${nr}, ${ng}, ${nb2}, ${alpha.toFixed(3)})`;
        ctx.beginPath();
        ctx.arc(n.x, n.y, rad, 0, Math.PI * 2);
        ctx.fill();
      }

      /* bubbles — cyan, flowing through the net, depth-scaled */
      for (const s of signals) {
        s.t += s.v * dt / 1000;
        if (s.t >= 1) { advanceWalk(s); continue; }
        const A = nodes[s.from], B = nodes[s.to];
        const x = A.x + (B.x - A.x) * s.t;
        const y = A.y + (B.y - A.y) * s.t;
        const d = A.d + (B.d - A.d) * s.t;
        const alpha = 0.20 + 0.45 * d;
        const rad = 1.2 + 1.5 * d;
        ctx.save();
        ctx.shadowColor = `rgba(${cr}, ${cg}, ${cb}, 0.65)`;
        ctx.shadowBlur = 9;
        ctx.fillStyle = `rgba(${cr}, ${cg}, ${cb}, ${alpha.toFixed(3)})`;
        ctx.beginPath();
        ctx.arc(x, y, rad, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
      }

      raf = requestAnimationFrame(step);
    };

    const onVisibility = () => {
      if (document.hidden) {
        running = false;
        if (raf) cancelAnimationFrame(raf);
      } else if (!running) {
        running = true;
        last = performance.now();
        raf = requestAnimationFrame(step);
      }
    };

    resize();
    /* Observe the ELEMENT, not the window: fonts/layout can grow the hero
       after mount, which used to leave a tiny stale canvas in the corner. */
    const ro = new ResizeObserver(() => resize());
    ro.observe(canvas.parentElement);
    document.addEventListener('visibilitychange', onVisibility);
    raf = requestAnimationFrame(step);

    return () => {
      running = false;
      if (raf) cancelAnimationFrame(raf);
      ro.disconnect();
      document.removeEventListener('visibilitychange', onVisibility);
      themeObs.disconnect();
    };
  }, []);

  /* Full presence at the right edge, dissolving toward the page centre. */
  return (
    <canvas
      ref={canvasRef}
      className="absolute inset-0"
      style={{
        WebkitMaskImage: 'linear-gradient(to left, black 0%, black 34%, transparent 92%)',
        maskImage: 'linear-gradient(to left, black 0%, black 34%, transparent 92%)',
      }}
    />
  );
}

function HeroDotNet() {
  // Right-side hero backdrop. Animated graph net when motion is allowed,
  // the original static dot grid otherwise. Both sit under the same cyan
  // whisper glow and dissolve toward the right edge.
  const reduced = typeof window !== 'undefined'
    && window.matchMedia
    && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  return (
    <div aria-hidden
      className="absolute pointer-events-none hidden md:block"
      style={{ top: 0, right: 0, bottom: 0, width: '58%', zIndex: 0 }}>
      {/* Whisper of cyan glow — anchored upper-right, ~5% opacity */}
      <div className="absolute inset-0" style={{
        background: 'radial-gradient(ellipse 60% 70% at 72% 46%, rgba(34, 211, 238, 0.06), transparent 72%)',
      }}/>
      {reduced ? (
        <div className="absolute inset-0" style={{
          backgroundImage: 'radial-gradient(rgb(var(--c-ink) / 0.16) 1.2px, transparent 1.2px)',
          backgroundSize: '22px 22px',
          WebkitMaskImage: 'linear-gradient(to right, transparent 0%, black 32%, black 58%, transparent 100%)',
          maskImage: 'linear-gradient(to right, transparent 0%, black 32%, black 58%, transparent 100%)',
        }}/>
      ) : (
        <GraphFlowCanvas/>
      )}
    </div>
  );
}

function Hero() {
  return (
    <section className="relative overflow-hidden" data-variant="D">
      <HeroDotNet/>
      <div className="relative mx-auto max-w-[1280px] px-8 lg:px-16" style={{ zIndex: 1 }}>
        <div className="pt-28 sm:pt-40 lg:pt-48 pb-32 sm:pb-44 lg:pb-56 max-w-[1080px]">
          <h1
            className="display text-ink"
            style={{ fontSize: 'clamp(50px, 7.4vw, 92px)' }}>
            Quantify what <em className="grad-word">drives</em> customer
            behavior — and the levers to <em className="grad-word">change</em> it.
          </h1>

          <div
            aria-hidden
            className="mt-16 sm:mt-20"
            style={{
              width: '34%',
              maxWidth: 360,
              height: 1,
              background: 'rgb(var(--c-ink) / 0.18)',
            }}
          />

          <p className="mt-8 mono text-[11.5px] text-mute tracking-wide uppercase">
            Causal AI for Customer Analytics — at population scale.
          </p>

          <div className="mt-14 flex flex-wrap items-center gap-6">
            <a
              href="#/lab?demo"
              className="inline-flex items-center gap-2 rounded-full bg-ink text-paper hover:bg-ink/90 px-6 py-3 text-[14px] font-medium transition-colors">
              See it in Action <Icon.Arrow className="w-4 h-4"/>
            </a>
            <a
              href="#/demo"
              className="mono text-[11px] text-mute hover:text-ink transition-colors inline-flex items-center gap-1.5">
              REQUEST DEMO ACCESS <Icon.ArrowUR className="w-3 h-3"/>
            </a>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ONE product, ONE deployment model (on-premises), two stages: NOW and SOON. */
function ProductSection() {
  const cols = [
    {
      eyebrow: <span className="mono text-[10px] text-cyan inline-flex items-center gap-1.5"><span className="h-1.5 w-1.5 rounded-full bg-cyan pulse"></span>NOW</span>,
      t: 'Automotive',
      b: <>Built and validated on millions of real-world automotive customer experiences — <a href="#/lab?demo" className="text-ink underline decoration-line underline-offset-2 hover:decoration-ink">see the interactive demo in the Lab</a>. Runs fully on-premises — locally on your own infrastructure, not in the cloud.</>,
      hot: true,
    },
    {
      eyebrow: <span className="mono text-[10px] text-mute">SOON</span>,
      t: 'Cross-industry',
      b: <>The same causal engine, opened to new industries — pharma, hospitality, retail and beyond. Same fully local deployment: your data never leaves your infrastructure.</>,
      hot: false,
    },
  ];
  return (
    <section className="border-t border-line bg-off">
      <div className="mx-auto max-w-[1200px] px-8 lg:px-16 py-24">
        <div className="max-w-3xl mx-auto text-center">
          <div className="mono text-[10px] text-mute">PRODUCT</div>
          <h2 className="mt-3 text-[34px] sm:text-[42px] font-semibold tracking-[-0.022em] leading-[1.05]">
            One causal engine.<br/>From feedback to <span className="grad-word">levers</span>.
          </h2>
          <p className="mt-5 text-[15px] text-mute leading-relaxed max-w-2xl mx-auto">
            The GenData Causal Engine turns unstructured customer feedback into quantified
            cause-and-effect evidence — which drivers move which outcomes, for whom, and by how much.
          </p>
        </div>
        <div className="mt-14 grid grid-cols-1 md:grid-cols-2 gap-5 max-w-[920px] mx-auto">
          {cols.map(c => (
            <div
              key={c.t}
              className={`rounded-2xl bg-paper p-8 relative text-center flex flex-col items-center ${c.hot ? 'border-2 border-cyan/60' : 'border border-line'}`}
              style={c.hot ? { boxShadow: '0 0 54px rgba(34, 211, 238, 0.10)' } : undefined}>
              <div>{c.eyebrow}</div>
              <h3 className="mt-4 text-[26px] font-bold tracking-[-0.015em]">{c.t}</h3>
              <p className="mt-4 text-[13.5px] text-mute leading-relaxed max-w-sm">{c.b}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function HowItWorks() {
  const steps = [
    { n:'01', t:'Extract', b:'Every piece of feedback is decomposed into typed cause and effect aspects — multilingual, with verbatim evidence quotes.' },
    { n:'02', t:'Structure', b:'Aspects roll up into a steerable driver taxonomy and a unit-by-time panel — the shape causal inference actually needs.' },
    { n:'03', t:'Identify', b:'Causal graph discovery and effect estimation under confounder control — heterogeneous effects, not just averages.' },
    { n:'04', t:'Validate & simulate', b:'Every effect is stress-tested against a refutation battery. Then simulate interventions: what moves, by how much, with confidence intervals.' },
  ];
  return (
    <section className="border-t border-line">
      <div className="mx-auto max-w-[1200px] px-8 lg:px-16 py-24">
        <div className="max-w-2xl">
          <div className="mono text-[10px] text-mute">METHOD</div>
          <h2 className="mt-3 text-[34px] sm:text-[42px] font-semibold tracking-[-0.022em] leading-[1.05]">From raw text to audited cause.</h2>
        </div>
        <div className="mt-14 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-10 md:gap-2">
          {steps.map(s => (
            <div key={s.n} className="md:px-5 first:md:pl-0">
              <div className="mono text-[10px] text-cyan">{s.n}</div>
              <h3 className="mt-3 text-[18px] font-semibold tracking-tight">{s.t}</h3>
              <p className="mt-3 text-[13px] text-mute leading-relaxed">{s.b}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* Operational transparency — founder, verifiable via LinkedIn. Kept to a
   single line by design. */
function FounderStrip() {
  return (
    <section className="border-t border-line">
      <div className="mx-auto max-w-[1200px] px-8 lg:px-16 py-14 flex flex-wrap items-center justify-center gap-x-6 gap-y-4 text-center">
        <img
          src="src/assets/founder-moritz-gentner-v4.jpg"
          alt="Moritz Gentner, Founder & Managing Director of GenData"
          className="h-12 w-12 rounded-full object-cover border border-line"
          style={{ objectPosition: '50% 25%' }}
        />
        <p className="text-[14.5px] text-mute leading-relaxed max-w-xl text-left">
          <span className="text-ink font-medium">Moritz Gentner · Founder &amp; Managing Director.</span>{' '}
          Eight years at a global premium OEM — management consulting, aftersales,
          working directly with top management.
        </p>
        <a
          href="https://www.linkedin.com/in/moritz-g-60b356ab/"
          target="_blank" rel="noopener noreferrer"
          className="inline-flex items-center gap-2 rounded-full border border-line hover:border-ink/40 px-4 py-2 text-[13px] text-ink transition-colors">
          <Icon.LinkedIn className="w-4 h-4"/> LinkedIn <Icon.ArrowUR className="w-3 h-3 text-mute"/>
        </a>
      </div>
    </section>
  );
}

function Quote() {
  return (
    <section className="border-t border-line bg-off">
      <div className="mx-auto max-w-[1000px] px-8 lg:px-16 py-24 text-center">
        <p className="text-[26px] sm:text-[34px] font-medium leading-[1.25] tracking-[-0.012em]">
          From customer feedback to <span className="grad-word">causal levers</span> — quantified, with confidence intervals, at population scale.
        </p>
        <div className="mt-8 mono text-[10px] text-mute">RESEARCH NOTE · GENDATA LABS · 2026</div>
      </div>
    </section>
  );
}

function CTA() {
  return (
    <section className="border-t border-line">
      <div className="mx-auto max-w-[1100px] px-8 lg:px-16 py-24 text-center">
        <h2 className="text-[36px] sm:text-[48px] font-semibold tracking-[-0.022em] leading-[1.05]">
          Move the levers that<br/>
          <span className="grad-word">actually move outcomes.</span>
        </h2>
        <div className="mt-10 flex flex-col sm:flex-row items-center justify-center gap-3">
          <a href="#/lab?demo" className="rounded-full bg-ink text-paper hover:bg-ink/90 px-6 py-3 text-[14px] font-medium inline-flex items-center gap-2 transition-colors">
            See it in Action <Icon.Arrow className="w-4 h-4"/>
          </a>
          <a href="#/demo" className="rounded-full border border-line hover:border-ink/40 px-6 py-3 text-[14px] text-ink transition-colors">Request Demo Access</a>
        </div>
      </div>
    </section>
  );
}

window.LandingPage = LandingPage;
window.LandingStreams = ProductSection;   /* legacy alias — old name kept for any external refs */
window.LandingHowItWorks = HowItWorks;
window.LandingQuote = Quote;
window.LandingCTA = CTA;
