// Hero background: belt-driven gear loop (from uploads/Gear Loop.html), adapted to
// run as a full-bleed <canvas> sized to the hero element instead of the viewport.
// Ambient auto-drive; pointer over the hero speeds the belt and heats nearby gears.

const GearLoopBG = () => {
  const canvasRef = React.useRef(null);
  React.useEffect(() => {
    const cv = canvasRef.current;
    if (!cv) return;
    const ctx = cv.getContext('2d');
    const host = cv.parentElement;
    let W = 0, H = 0, DPR = 1, raf = 0;
    const LABELS = ['RECOGNIZE', 'ACQUIRE', 'ORGANIZE', 'REFLECT', 'APPLY', 'AMPLIFY'];
    const BASE_HUES = [8, 32, 48, 168, 262, 320];
    let track = null, gears = [], pulses = [], bursts = [], beltW = 0;
    const mouse = { x: -1e5, y: -1e5, in: false };
    let speed = 1, speedTarget = 0.85, lapHue = 262;
    let phase = 'sweep', phaseT = 0;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    function buildTrack() {
      const cx = W / 2, cy = H / 2;
      const a = Math.min(W * 0.40, 720), b = Math.min(H * 0.34, 320);
      const r = Math.min(a, b) * 0.62;
      beltW = Math.max(14, Math.min(a, b) * 0.07);
      const pts = [];
      const push = (x, y) => { pts.push({ x, y }); };
      const stepL = 3;
      const line = (x0, y0, x1, y1) => { const d = Math.hypot(x1 - x0, y1 - y0), n = Math.max(2, Math.round(d / stepL)); for (let i = 0; i < n; i++) { const t = i / n; push(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t); } };
      const arc = (ax, ay, a0, a1) => { const d = Math.abs(a1 - a0) * r, n = Math.max(4, Math.round(d / stepL)); for (let i = 0; i < n; i++) { const t = i / n, an = a0 + (a1 - a0) * t; push(ax + Math.cos(an) * r, ay + Math.sin(an) * r); } };
      line(cx - a + r, cy - b, cx + a - r, cy - b);
      arc(cx + a - r, cy - b + r, -Math.PI / 2, 0);
      line(cx + a, cy - b + r, cx + a, cy + b - r);
      arc(cx + a - r, cy + b - r, 0, Math.PI / 2);
      line(cx + a - r, cy + b, cx - a + r, cy + b);
      arc(cx - a + r, cy + b - r, Math.PI / 2, Math.PI);
      line(cx - a, cy + b - r, cx - a, cy - b + r);
      arc(cx - a + r, cy - b + r, Math.PI, Math.PI * 1.5);
      let acc = 0;
      for (let i = 0; i < pts.length; i++) {
        const p = pts[i], q = pts[(i + 1) % pts.length];
        p.s = acc; acc += Math.hypot(q.x - p.x, q.y - p.y);
        const n = pts[(i + 1) % pts.length], m = pts[(i - 1 + pts.length) % pts.length];
        let tx = n.x - m.x, ty = n.y - m.y; const L = Math.hypot(tx, ty) || 1; tx /= L; ty /= L;
        p.tx = tx; p.ty = ty; p.nx = -ty; p.ny = tx;
      }
      track = { pts, len: acc, cx, cy, a, b, r };
    }
    function at(s) {
      const { pts, len } = track; s = ((s % len) + len) % len;
      let lo = 0, hi = pts.length - 1;
      while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (pts[mid].s <= s) lo = mid; else hi = mid - 1; }
      return pts[lo];
    }
    function layout() {
      buildTrack();
      const L = track.len;
      gears = [];
      for (let i = 0; i < 6; i++) {
        const R = Math.min(W, H) * (i % 2 ? 0.058 : 0.075);
        gears.push({ s: (i / 6) * L, R, teeth: Math.round(R / 6) + 8, hue: BASE_HUES[i], base: BASE_HUES[i], rot: Math.random() * 6, label: LABELS[i], heat: 0, big: true, synced: false });
      }
      for (let i = 0; i < 6; i++) {
        const R = Math.min(W, H) * 0.024;
        gears.push({ s: ((i + 0.5) / 6) * L, R, teeth: 10, hue: BASE_HUES[(i * 2) % 6], base: BASE_HUES[(i * 2) % 6], rot: 0, label: null, heat: 0, big: false, synced: false });
      }
      for (let pass = 0; pass < 14; pass++) {
        const order = [...gears].sort((p, q) => p.s - q.s);
        for (let i = 0; i < order.length; i++) {
          const a = order[i], b = order[(i + 1) % order.length];
          let gap = b.s - a.s; if (gap < 0) gap += L;
          const need = a.R + b.R + 12;
          if (gap < need) { const push = (need - gap) / 2; a.s = (a.s - push + L) % L; b.s = (b.s + push) % L; }
        }
      }
      pulses = [{ s: 0, prev: 0, hue: lapHue, alpha: 1 }];
      phase = 'sweep'; phaseT = 0;
    }
    function resize() {
      DPR = Math.min(window.devicePixelRatio || 1, 2);
      W = host.clientWidth; H = host.clientHeight;
      cv.width = W * DPR; cv.height = H * DPR; ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
      layout();
    }
    function nearestS(x, y) {
      const { pts } = track; let bi = 0, bd = Infinity;
      for (let i = 0; i < pts.length; i += 3) { const d = (pts[i].x - x) ** 2 + (pts[i].y - y) ** 2; if (d < bd) { bd = d; bi = i; } }
      return pts[bi].s;
    }
    const onMove = (e) => { const r = cv.getBoundingClientRect(); mouse.x = e.clientX - r.left; mouse.y = e.clientY - r.top; mouse.in = true; };
    const onLeave = () => { mouse.in = false; mouse.x = -1e5; mouse.y = -1e5; };
    const onDown = (e) => {
      const r = cv.getBoundingClientRect(), mx = e.clientX - r.left, my = e.clientY - r.top;
      const s = nearestS(mx, my);
      lapHue = (lapHue + 95 + Math.random() * 70) % 360;
      pulses.push({ s, prev: s, start: s, hue: lapHue, alpha: 1 });
      pulses[0].hue = lapHue;
      gears.forEach(g => g.synced = false);
      phase = 'sweep';
      bursts.push({ x: mx, y: my, t: 0, hue: lapHue });
      if (pulses.length > 4) pulses.shift();
    };
    host.addEventListener('mousemove', onMove);
    host.addEventListener('mouseleave', onLeave);
    host.addEventListener('mousedown', onDown);

    function gearPath(x, y, R, teeth, rot) {
      const ri = R * 0.80, rt = R;
      ctx.beginPath();
      for (let i = 0; i < teeth; i++) {
        const a0 = rot + (i / teeth) * Math.PI * 2, step = (Math.PI * 2 / teeth) / 4;
        const p = (rr, aa) => [x + Math.cos(aa) * rr, y + Math.sin(aa) * rr];
        const A = p(ri, a0), B = p(rt, a0 + step * 0.9), C = p(rt, a0 + step * 2.1), D = p(ri, a0 + step * 3);
        if (i === 0) ctx.moveTo(A[0], A[1]); else ctx.lineTo(A[0], A[1]);
        ctx.lineTo(B[0], B[1]); ctx.lineTo(C[0], C[1]); ctx.lineTo(D[0], D[1]);
      }
      ctx.closePath();
    }
    function drawGear(g, x, y) {
      const hue = g.hue, heat = g.heat, R = g.R;
      const light = 52 + heat * 16, sat = 88;
      ctx.save();
      ctx.shadowColor = `hsla(${hue},100%,60%,${0.5 + heat * 0.5})`;
      ctx.shadowBlur = (g.big ? 22 : 12) + heat * 30;
      const grd = ctx.createLinearGradient(x - R, y - R, x + R, y + R);
      grd.addColorStop(0, `hsl(${hue},${sat}%,${light + 12}%)`);
      grd.addColorStop(1, `hsl(${(hue + 18) % 360},${sat}%,${light - 14}%)`);
      ctx.fillStyle = grd;
      gearPath(x, y, R, g.teeth, g.rot);
      ctx.fill();
      ctx.shadowBlur = 0;
      ctx.strokeStyle = `hsla(${hue},100%,${78 + heat * 15}%,${0.55 + heat * 0.45})`;
      ctx.lineWidth = 1.2;
      ctx.stroke();
      ctx.fillStyle = 'rgba(8,8,12,0.92)';
      ctx.beginPath(); ctx.arc(x, y, R * (g.big ? 0.50 : 0.42), 0, 7); ctx.fill();
      ctx.strokeStyle = `hsla(${hue},100%,72%,${0.5 + heat * 0.5})`; ctx.lineWidth = 1.4; ctx.stroke();
      ctx.strokeStyle = `hsla(${hue},90%,68%,0.45)`; ctx.lineWidth = Math.max(1.5, R * 0.055);
      const sp = g.big ? 6 : 4;
      for (let i = 0; i < sp; i++) {
        const a = g.rot * 1 + (i / sp) * Math.PI * 2;
        ctx.beginPath();
        ctx.moveTo(x + Math.cos(a) * R * 0.46, y + Math.sin(a) * R * 0.46);
        ctx.lineTo(x + Math.cos(a) * R * 0.74, y + Math.sin(a) * R * 0.74);
        ctx.stroke();
      }
      ctx.fillStyle = `hsla(${hue},100%,${80 + heat * 15}%,0.95)`;
      ctx.beginPath(); ctx.arc(x, y, R * 0.13, 0, 7); ctx.fill();
      ctx.restore();
    }

    let last = performance.now();
    function frame(now) {
      const dt = Math.min(0.05, (now - last) / 1000); last = now;
      const L = track.len;
      if (mouse.in) {
        const d = Math.hypot(mouse.x - track.cx, mouse.y - track.cy);
        speedTarget = 0.55 + Math.min(2.4, d / Math.max(160, track.a) * 1.9);
      } else speedTarget = 0.85;
      speed += (speedTarget - speed) * 0.05;

      ctx.clearRect(0, 0, W, H);
      const amb = ctx.createRadialGradient(track.cx, track.cy, 0, track.cx, track.cy, Math.max(W, H) * 0.62);
      amb.addColorStop(0, `hsla(${lapHue},70%,50%,0.10)`);
      amb.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle = amb; ctx.fillRect(0, 0, W, H);

      const { pts } = track;
      const trackPath = () => { ctx.beginPath(); ctx.moveTo(pts[0].x, pts[0].y); for (let i = 1; i < pts.length; i += 2) ctx.lineTo(pts[i].x, pts[i].y); ctx.closePath(); };
      ctx.lineJoin = 'round'; ctx.lineCap = 'round';
      trackPath(); ctx.strokeStyle = 'rgba(255,255,255,0.05)'; ctx.lineWidth = beltW + 10; ctx.stroke();
      trackPath(); ctx.strokeStyle = '#15151f'; ctx.lineWidth = beltW; ctx.stroke();
      trackPath(); ctx.strokeStyle = 'rgba(255,255,255,0.09)'; ctx.lineWidth = 1.2; ctx.stroke();

      const beltOffset = (now / 1000) * speed * 60;
      ctx.strokeStyle = 'rgba(255,255,255,0.16)'; ctx.lineWidth = 2;
      for (let s = 0; s < L; s += 13) {
        const p = at(s + beltOffset);
        const i0 = p.nx * (beltW * 0.5 - 2), j0 = p.ny * (beltW * 0.5 - 2);
        ctx.beginPath();
        ctx.moveTo(p.x + i0, p.y + j0);
        ctx.lineTo(p.x + p.nx * (beltW * 0.5 - 9), p.y + p.ny * (beltW * 0.5 - 9));
        ctx.stroke();
      }

      for (let i = pulses.length - 1; i >= 0; i--) {
        const p = pulses[i];
        p.prev = p.s;
        p.s += speed * 430 * dt;
        if (i > 0 && p.s - p.start > L) { pulses.splice(i, 1); }
      }

      const mp = pulses[0];
      if (phase === 'sweep') {
        mp.alpha += (1 - mp.alpha) * 0.12;
        if (gears.every(g => g.synced)) { phase = 'hold'; phaseT = 2.4; }
      } else {
        mp.alpha += (0 - mp.alpha) * 0.06;
        phaseT -= dt;
        if (phaseT <= 0) {
          if (phase === 'hold') { phase = 'diverge'; phaseT = 2.8; }
          else {
            lapHue = (lapHue + 118 + Math.random() * 46) % 360;
            mp.hue = lapHue;
            gears.forEach(g => g.synced = false);
            phase = 'sweep';
          }
        }
      }

      ctx.globalCompositeOperation = 'lighter';
      for (const p of pulses) {
        const pa = p.alpha === undefined ? 1 : p.alpha;
        if (pa < 0.02) continue;
        const TRAIL = 460;
        for (let d = 0; d < TRAIL; d += 9) {
          const k = 1 - d / TRAIL;
          const q = at(p.s - d);
          ctx.strokeStyle = `hsla(${p.hue},100%,${58 + k * 22}%,${k * k * 0.55 * pa})`;
          ctx.lineWidth = beltW * (0.55 + k * 0.5);
          ctx.beginPath(); ctx.moveTo(q.x, q.y);
          const q2 = at(p.s - d - 9); ctx.lineTo(q2.x, q2.y); ctx.stroke();
        }
        const head = at(p.s);
        const hg = ctx.createRadialGradient(head.x, head.y, 0, head.x, head.y, beltW * 3.2);
        hg.addColorStop(0, `hsla(${p.hue},100%,88%,${0.95 * pa})`);
        hg.addColorStop(0.35, `hsla(${p.hue},100%,62%,${0.45 * pa})`);
        hg.addColorStop(1, `hsla(${p.hue},100%,50%,0)`);
        ctx.fillStyle = hg; ctx.beginPath(); ctx.arc(head.x, head.y, beltW * 3.2, 0, 7); ctx.fill();
      }
      ctx.globalCompositeOperation = 'source-over';

      for (const g of gears) {
        const ds = speed * 112 * dt;
        g.s += ds;
        g.rot -= ds / g.R;
        const p = at(g.s);
        const off = beltW * 0.5 + g.R * 0.90;
        g.x = p.x + p.nx * off; g.y = p.y + p.ny * off;
        for (const pl of pulses) {
          if (pl === mp && phase !== 'sweep') continue;
          const gs = ((g.s % L) + L) % L;
          let a = ((pl.prev % L) + L) % L, b = ((pl.s % L) + L) % L;
          const hit = a <= b ? (gs >= a && gs <= b) : (gs >= a || gs <= b);
          if (hit) { g.hue = pl.hue; g.synced = true; g.heat = 1; }
        }
        if (phase === 'diverge') {
          const dh = ((g.base - g.hue + 540) % 360) - 180;
          g.hue = (g.hue + dh * (1 - Math.exp(-0.85 * dt)) + 360) % 360;
        }
        g.heat *= 0.965;
        if (mouse.in) {
          const md = Math.hypot(mouse.x - g.x, mouse.y - g.y);
          if (md < g.R * 2.2) g.heat = Math.max(g.heat, 1 - md / (g.R * 2.2));
        }
      }

      const big = gears.filter(g => g.big);
      ctx.globalCompositeOperation = 'lighter';
      for (let i = 0; i < big.length; i++) {
        const a = big[i], b = big[(i + 1) % big.length];
        const k = (a.heat + b.heat) / 2;
        ctx.strokeStyle = `hsla(${a.hue},95%,65%,${0.05 + k * 0.4})`;
        ctx.lineWidth = 0.8 + k * 2;
        ctx.beginPath(); ctx.moveTo(a.x, a.y);
        ctx.quadraticCurveTo(track.cx, track.cy, b.x, b.y); ctx.stroke();
      }
      ctx.globalCompositeOperation = 'source-over';

      for (const g of gears) drawGear(g, g.x, g.y);

      ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
      for (const g of gears) {
        if (!g.label) continue;
        ctx.font = `800 ${Math.max(9, g.R * 0.20)}px 'Plus Jakarta Sans','Inter',sans-serif`;
        ctx.fillStyle = `hsla(${g.hue},100%,86%,${0.55 + g.heat * 0.45})`;
        ctx.fillText(g.label, g.x, g.y + g.R * 1.52);
      }

      ctx.globalCompositeOperation = 'lighter';
      for (let i = bursts.length - 1; i >= 0; i--) {
        const b = bursts[i]; b.t += dt * 1.6;
        if (b.t >= 1) { bursts.splice(i, 1); continue; }
        const r = b.t * 260, al = (1 - b.t) ** 2;
        ctx.strokeStyle = `hsla(${b.hue},100%,72%,${al * 0.8})`;
        ctx.lineWidth = 2 + (1 - b.t) * 4;
        ctx.beginPath(); ctx.arc(b.x, b.y, r, 0, 7); ctx.stroke();
      }
      ctx.globalCompositeOperation = 'source-over';

      raf = requestAnimationFrame(frame);
    }

    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(host);
    if (reduce) { frame(performance.now()); cancelAnimationFrame(raf); }
    else raf = requestAnimationFrame(frame);

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      host.removeEventListener('mousemove', onMove);
      host.removeEventListener('mouseleave', onLeave);
      host.removeEventListener('mousedown', onDown);
    };
  }, []);
  return <canvas ref={canvasRef} className="lp-gearloop-canvas" aria-hidden="true" />;
};

Object.assign(window, { GearLoopBG });
