/* PROCESO — detailed page with timeline & flow animation */
const { useState: useStateP, useEffect: useEffectP, useRef: useRefP } = React;

const FlowAnimation = ({ kind }) => {
  const ref = useRefP(null);
  useEffectP(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext('2d');
    let raf, t = 0;
    const GREEN = '#22c55e', CYAN = '#06b6d4', AMBER = '#f59e0b';
    const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
    const ease = (x) => x < 0.5 ? 2*x*x : 1 - Math.pow(-2*x+2, 2)/2;
    const rr = (x, y, ww, hh, rad) => {
      const k = Math.min(rad, ww/2, hh/2);
      ctx.beginPath();
      ctx.moveTo(x+k, y);
      ctx.arcTo(x+ww, y, x+ww, y+hh, k);
      ctx.arcTo(x+ww, y+hh, x, y+hh, k);
      ctx.arcTo(x, y+hh, x, y, k);
      ctx.arcTo(x, y, x+ww, y, k);
      ctx.closePath();
    };

    const resize = () => {
      const r = c.getBoundingClientRect();
      const dpr = window.devicePixelRatio || 1;
      c.width = r.width * dpr; c.height = r.height * dpr;
      ctx.setTransform(1,0,0,1,0,0); ctx.scale(dpr, dpr);
    };
    resize();
    const ro = new ResizeObserver(resize); ro.observe(c);

    const draw = () => {
      t += 1/60;
      const r = c.getBoundingClientRect();
      const w = r.width, h = r.height;
      const P = 22; // inner padding
      ctx.clearRect(0,0,w,h);

      if (kind === 'discover') {
        /* DISCOVERY — matriz Impacto / Esfuerzo: las oportunidades se grafican
           y las 3 mejores (alto impacto, bajo esfuerzo) se rankean 1·2·3.
           Justo lo que entrega la etapa: "Top 3 priorizadas por impacto/esfuerzo". */
        const gx0 = P + 30, gx1 = w - P - 8, gy0 = P + 12, gy1 = h - P - 22;
        const cyc = 7.5, lt = t % cyc;

        // "quick wins" zone (alto impacto, bajo esfuerzo)
        const qzW = (gx1-gx0)*0.42, qzH = (gy1-gy0)*0.5;
        const scanning = lt > 2 && lt < 4.3;
        ctx.fillStyle = 'rgba(34,197,94,0.06)';
        rr(gx0, gy0, qzW, qzH, 8); ctx.fill();
        ctx.setLineDash([4,3]); ctx.lineWidth = 1;
        ctx.strokeStyle = scanning
          ? `rgba(34,197,94,${0.4 + ((Math.sin(t*4)+1)/2)*0.4})`
          : 'rgba(34,197,94,0.22)';
        rr(gx0, gy0, qzW, qzH, 8); ctx.stroke(); ctx.setLineDash([]);

        // axes + arrows
        ctx.strokeStyle = 'rgba(255,255,255,0.16)'; ctx.lineWidth = 1.5;
        ctx.beginPath(); ctx.moveTo(gx0, gy0-4); ctx.lineTo(gx0, gy1); ctx.lineTo(gx1, gy1); ctx.stroke();
        ctx.fillStyle = 'rgba(255,255,255,0.3)';
        ctx.beginPath(); ctx.moveTo(gx0, gy0-8); ctx.lineTo(gx0-3.5, gy0-2); ctx.lineTo(gx0+3.5, gy0-2); ctx.fill();
        ctx.beginPath(); ctx.moveTo(gx1+7, gy1); ctx.lineTo(gx1+1, gy1-3.5); ctx.lineTo(gx1+1, gy1+3.5); ctx.fill();
        // labels
        ctx.fillStyle = 'rgba(255,255,255,0.42)'; ctx.font = '600 9px monospace';
        ctx.save(); ctx.translate(gx0-15, (gy0+gy1)/2); ctx.rotate(-Math.PI/2);
        ctx.textAlign = 'center'; ctx.fillText('IMPACTO', 0, 0); ctx.restore();
        ctx.textAlign = 'center'; ctx.fillText('ESFUERZO', (gx0+gx1)/2, gy1+15);
        ctx.textAlign = 'start';

        const opp = [
          { e:0.15, i:0.83, rank:1 }, { e:0.30, i:0.66, rank:2 }, { e:0.22, i:0.54, rank:3 },
          { e:0.55, i:0.80 }, { e:0.72, i:0.58 }, { e:0.83, i:0.33 },
          { e:0.50, i:0.30 }, { e:0.66, i:0.17 }, { e:0.42, i:0.44 }, { e:0.87, i:0.71 },
        ];
        const cxp = (gx0+gx1)/2, cyp = (gy0+gy1)/2;
        opp.forEach((o, idx) => {
          const tx = gx0 + o.e*(gx1-gx0), ty = gy1 - o.i*(gy1-gy0);
          const a = ease(clamp((lt - idx*0.09)/0.7, 0, 1));
          const px = cxp + (tx-cxp)*a, py = cyp + (ty-cyp)*a;
          const isWin = !!o.rank;
          ctx.globalAlpha = 0.3 + a*0.7;
          ctx.fillStyle = isWin ? GREEN : 'rgba(255,255,255,0.42)';
          ctx.beginPath(); ctx.arc(px, py, isWin ? 5.5 : 4, 0, Math.PI*2); ctx.fill();
          ctx.globalAlpha = 1;
          if (isWin) {
            const bt = lt - (4.4 + o.rank*0.4);
            if (bt > 0) {
              const ba = ease(clamp(bt/0.5, 0, 1));
              const pulse = (Math.sin(t*3 + o.rank) + 1)/2;
              ctx.strokeStyle = `rgba(34,197,94,${0.45*ba + pulse*0.35})`; ctx.lineWidth = 2;
              ctx.beginPath(); ctx.arc(px, py, 9 + pulse*3, 0, Math.PI*2*ba); ctx.stroke();
              ctx.fillStyle = GREEN;
              ctx.beginPath(); ctx.arc(px+10, py-10, 7.5*ba, 0, Math.PI*2); ctx.fill();
              if (ba > 0.6) {
                ctx.fillStyle = '#04140b'; ctx.font = '700 9px monospace';
                ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
                ctx.fillText(String(o.rank), px+10, py-9.5);
                ctx.textAlign = 'start'; ctx.textBaseline = 'alphabetic';
              }
            }
          }
        });

      } else if (kind === 'design') {
        /* DISEÑO — editor tipo Figma: rail de capas + una "pasada de diseño"
           que convierte el wireframe (gris) en diseño visual (color) de arriba
           a abajo; luego el cursor hace clic en el CTA (prototipo interactivo)
           y aparecen los componentes del design system. */
        const wx = P, wy = P, ww = w - 2*P, wh = h - 2*P;
        ctx.fillStyle = 'rgba(255,255,255,0.025)';
        ctx.strokeStyle = 'rgba(255,255,255,0.12)'; ctx.lineWidth = 1;
        rr(wx, wy, ww, wh, 12); ctx.fill(); ctx.stroke();

        const barH = 24;
        ctx.strokeStyle = 'rgba(255,255,255,0.08)';
        ctx.beginPath(); ctx.moveTo(wx, wy+barH); ctx.lineTo(wx+ww, wy+barH); ctx.stroke();
        ['#ef4444','#f59e0b','#22c55e'].forEach((col,i)=>{
          ctx.fillStyle = col; ctx.globalAlpha = 0.6;
          ctx.beginPath(); ctx.arc(wx+15+i*11, wy+12, 3, 0, Math.PI*2); ctx.fill();
        });
        ctx.globalAlpha = 1;

        const cyc = 7, lt = t % cyc;

        // left rail — layers panel
        const sbW = 66, sbX = wx, sbY = wy+barH;
        ctx.strokeStyle = 'rgba(255,255,255,0.07)';
        ctx.beginPath(); ctx.moveTo(sbX+sbW, sbY); ctx.lineTo(sbX+sbW, wy+wh); ctx.stroke();
        ctx.fillStyle = 'rgba(255,255,255,0.32)'; ctx.font = '600 8px monospace';
        ctx.fillText('CAPAS', sbX+11, sbY+15);
        for (let i=0;i<5;i++){
          const ly = sbY+26+i*14;
          const activeLayer = lt < 2.8 && Math.floor((lt/2.8)*5) === i;
          ctx.fillStyle = activeLayer ? GREEN : 'rgba(255,255,255,0.35)';
          ctx.beginPath(); ctx.arc(sbX+13, ly, 2.4, 0, Math.PI*2); ctx.fill();
          ctx.fillStyle = activeLayer ? 'rgba(34,197,94,0.5)' : 'rgba(255,255,255,0.12)';
          rr(sbX+21, ly-2.5, 32 - (i%2)*8, 5, 2); ctx.fill();
        }

        // main canvas
        const mx0 = sbX+sbW+14, my0 = sbY+12;
        const mw = wx+ww-14-mx0, mh = wy+wh-12-my0-16;
        const sweepP = ease(clamp(lt/2.8, 0, 1));
        const sweepY = my0 + sweepP*mh;

        const els = [
          { y:0.02, h:0.11, w:0.55, t:'title' },
          { y:0.18, h:0.30, w:1.00, t:'img'   },
          { y:0.54, h:0.045, w:0.92, t:'text' },
          { y:0.62, h:0.045, w:0.74, t:'text' },
          { y:0.70, h:0.045, w:0.58, t:'text' },
          { y:0.82, h:0.13, w:0.40, t:'btn'   },
        ];
        const btn = els[5];
        const btnX = mx0, btnY = my0 + btn.y*mh, btnW = btn.w*mw, btnH = btn.h*mh;
        els.forEach(e => {
          const ex = mx0, ey = my0 + e.y*mh, ew = e.w*mw, eh = e.h*mh;
          const designed = ey + eh/2 < sweepY;
          if (e.t === 'img') {
            if (designed) {
              const g = ctx.createLinearGradient(ex, ey, ex+ew, ey+eh);
              g.addColorStop(0, 'rgba(6,182,212,0.28)'); g.addColorStop(1, 'rgba(34,197,94,0.18)');
              ctx.fillStyle = g;
            } else ctx.fillStyle = 'rgba(255,255,255,0.05)';
            rr(ex, ey, ew, eh, 8); ctx.fill();
            ctx.strokeStyle = designed ? 'rgba(6,182,212,0.5)' : 'rgba(255,255,255,0.14)';
            ctx.lineWidth = 1; rr(ex, ey, ew, eh, 8); ctx.stroke();
            if (!designed) {
              ctx.strokeStyle = 'rgba(255,255,255,0.12)'; ctx.lineWidth = 1;
              ctx.beginPath();
              ctx.moveTo(ex, ey); ctx.lineTo(ex+ew, ey+eh);
              ctx.moveTo(ex+ew, ey); ctx.lineTo(ex, ey+eh); ctx.stroke();
            }
          } else if (e.t === 'btn') {
            const clicked = lt > 4.2 && lt < 5.4;
            ctx.fillStyle = designed ? (clicked ? '#16a34a' : GREEN) : 'rgba(255,255,255,0.08)';
            rr(ex, ey, ew, eh, 6); ctx.fill();
            if (!designed) { ctx.strokeStyle = 'rgba(255,255,255,0.16)'; ctx.lineWidth = 1; rr(ex, ey, ew, eh, 6); ctx.stroke(); }
          } else if (e.t === 'title') {
            ctx.fillStyle = designed ? 'rgba(74,222,128,0.9)' : 'rgba(255,255,255,0.16)';
            rr(ex, ey, ew, eh, 3); ctx.fill();
          } else {
            ctx.fillStyle = designed ? 'rgba(255,255,255,0.5)' : 'rgba(255,255,255,0.12)';
            rr(ex, ey, ew, eh, 2.5); ctx.fill();
          }
        });

        // design sweep glow line
        if (sweepP < 0.999) {
          const g = ctx.createLinearGradient(0, sweepY-10, 0, sweepY+10);
          g.addColorStop(0, 'rgba(34,197,94,0)'); g.addColorStop(0.5, 'rgba(34,197,94,0.22)'); g.addColorStop(1, 'rgba(34,197,94,0)');
          ctx.fillStyle = g; ctx.fillRect(mx0, sweepY-10, mw, 20);
          ctx.strokeStyle = 'rgba(74,222,128,0.8)'; ctx.lineWidth = 1.5;
          ctx.beginPath(); ctx.moveTo(mx0, sweepY); ctx.lineTo(mx0+mw, sweepY); ctx.stroke();
        }

        // design-system component chips (bottom strip)
        const chY = wy+wh-13;
        ['#22c55e','#06b6d4','rgba(255,255,255,0.4)','#f59e0b'].forEach((col,i)=>{
          const cha = ease(clamp((lt - 3 - i*0.2)/0.5, 0, 1));
          if (cha <= 0) return;
          ctx.globalAlpha = cha; ctx.fillStyle = col;
          rr(mx0 + i*28, chY-6, 20, 9, 3); ctx.fill(); ctx.globalAlpha = 1;
        });

        // click ripple + cursor (prototipo interactivo)
        const bcx = btnX+btnW/2, bcy = btnY+btnH/2;
        if (lt > 4.2 && lt < 5.4) {
          const rp = (lt - 4.2)/1.2;
          ctx.strokeStyle = `rgba(34,197,94,${0.6*(1-rp)})`; ctx.lineWidth = 2;
          ctx.beginPath(); ctx.arc(bcx, bcy, 6 + rp*30, 0, Math.PI*2); ctx.stroke();
        }
        const cp = ease(clamp((lt - 3)/1.3, 0, 1));
        const sX = mx0 + mw*0.9, sY = my0 + mh*0.1;
        const cx = sX + (bcx - sX)*cp, cy = sY + (bcy - sY)*cp;
        ctx.fillStyle = '#fff'; ctx.strokeStyle = 'rgba(0,0,0,0.4)'; ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(cx, cy); ctx.lineTo(cx, cy+15); ctx.lineTo(cx+4, cy+11);
        ctx.lineTo(cx+7, cy+17); ctx.lineTo(cx+9, cy+16); ctx.lineTo(cx+6, cy+10);
        ctx.lineTo(cx+11, cy+10); ctx.closePath();
        ctx.fill(); ctx.stroke();

      } else if (kind === 'build') {
        /* DESARROLLO — tablero kanban de sprint: las tarjetas fluyen de
           Backlog → En curso → Listo. En "En curso" muestran barra de
           progreso; al llegar a "Listo" se marcan con check. */
        const labels = ['BACKLOG', 'EN CURSO', 'LISTO'];
        const usableW = w - 2*P, zoneW = usableW/3;
        // column zones + headers
        for (let i = 0; i < 3; i++) {
          const zx = P + i*zoneW;
          ctx.fillStyle = i === 2 ? 'rgba(34,197,94,0.055)' : 'rgba(255,255,255,0.025)';
          rr(zx + 3, P + 2, zoneW - 6, h - 2*P - 4, 10); ctx.fill();
          ctx.fillStyle = i === 2 ? 'rgba(74,222,128,0.85)' : 'rgba(255,255,255,0.38)';
          ctx.font = '600 10px monospace'; ctx.textAlign = 'center';
          ctx.fillText(labels[i], zx + zoneW/2, P + 17);
        }
        ctx.textAlign = 'start';

        const rows = 4;
        const cw = Math.min(zoneW - 26, 148), ch = 38;
        const areaTop = P + 28, areaH = h - 2*P - 34;
        const rowH = areaH / rows;
        for (let rI = 0; rI < rows; rI++) {
          const phase = (t*0.26 + rI*0.72) % 3;      // 0..3 across the 3 columns
          const zone = Math.floor(phase);
          const cx = P + (phase/3)*(usableW - cw);
          const cy = areaTop + rI*rowH + (rowH - ch)/2;
          const inProg = zone === 1, done = zone === 2;
          const tagCol = done ? GREEN : inProg ? CYAN : AMBER;

          // card
          ctx.fillStyle = done ? 'rgba(34,197,94,0.10)' : 'rgba(255,255,255,0.05)';
          ctx.strokeStyle = done ? 'rgba(34,197,94,0.5)' : inProg ? 'rgba(6,182,212,0.4)' : 'rgba(255,255,255,0.14)';
          ctx.lineWidth = 1;
          rr(cx, cy, cw, ch, 8); ctx.fill(); ctx.stroke();
          // colored tag bar (left accent)
          ctx.fillStyle = tagCol; rr(cx, cy, 3, ch, 1.5); ctx.fill();
          // skeleton lines
          ctx.fillStyle = 'rgba(255,255,255,0.28)'; rr(cx+12, cy+10, cw*0.5, 4, 2); ctx.fill();
          ctx.fillStyle = 'rgba(255,255,255,0.14)'; rr(cx+12, cy+19, cw*0.66, 3, 1.5); ctx.fill();
          // progress bar while en curso
          if (inProg) {
            const pr = phase - 1;
            ctx.fillStyle = 'rgba(255,255,255,0.10)'; rr(cx+12, cy+ch-9, cw-24, 3, 1.5); ctx.fill();
            const gp = ctx.createLinearGradient(cx, 0, cx+cw, 0);
            gp.addColorStop(0, GREEN); gp.addColorStop(1, CYAN);
            ctx.fillStyle = gp; rr(cx+12, cy+ch-9, (cw-24)*pr, 3, 1.5); ctx.fill();
          }
          // check when done
          if (done) {
            const mx = cx + cw - 13, my = cy + ch/2;
            ctx.fillStyle = 'rgba(34,197,94,0.18)';
            ctx.beginPath(); ctx.arc(mx, my, 7, 0, Math.PI*2); ctx.fill();
            ctx.strokeStyle = GREEN; ctx.lineWidth = 1.6; ctx.lineCap = 'round';
            ctx.beginPath();
            ctx.moveTo(mx-3, my); ctx.lineTo(mx-0.5, my+2.5); ctx.lineTo(mx+3.5, my-3);
            ctx.stroke(); ctx.lineCap = 'butt';
          }
        }

      } else if (kind === 'launch') {
        /* LANZAMIENTO — despliegue por etapas: arranca con el equipo piloto y
           se expande a toda la organización en oleadas. La etiqueta de fase va
           de Piloto → Ampliando → En producción, y abajo corre el monitoreo
           en vivo (latido) de las primeras semanas. */
        const cyc = 8, lt = t % cyc;
        const cols = 18, rows = 4;
        const gx0 = P + 6, gx1 = w - P - 6;
        const gridTop = P + 32, gridH = (h - 2*P) * 0.46;
        const gridBot = gridTop + gridH;
        const sx = (gx1 - gx0) / (cols - 1);
        const sy = rows > 1 ? gridH / (rows - 1) : 0;

        // activation front expands from the piloto cluster (col0,row0)
        let maxD = 0;
        for (let r=0;r<rows;r++) for (let cc=0;cc<cols;cc++){ const d=Math.hypot(cc, r*1.3); if(d>maxD) maxD=d; }
        const front = ease(clamp(lt/5, 0, 1)) * (maxD + 0.8);

        let activated = 0; const total = cols*rows;
        for (let r=0;r<rows;r++){
          for (let cc=0;cc<cols;cc++){
            const px = gx0 + cc*sx, py = gridTop + r*sy;
            const d = Math.hypot(cc, r*1.3);
            const on = front > d;
            if (on) activated++;
            if (on && (front - d) < 0.9) {
              const pr = 1-(front-d)/0.9;
              ctx.fillStyle = `rgba(34,197,94,${0.28*pr})`;
              ctx.beginPath(); ctx.arc(px, py, 3.4+pr*7, 0, Math.PI*2); ctx.fill();
            }
            ctx.fillStyle = on ? GREEN : 'rgba(255,255,255,0.14)';
            ctx.beginPath(); ctx.arc(px, py, 3.2, 0, Math.PI*2); ctx.fill();
          }
        }

        // piloto cluster outline (2×2) + label
        ctx.strokeStyle = 'rgba(6,182,212,0.55)'; ctx.setLineDash([3,2]); ctx.lineWidth = 1;
        rr(gx0-5, gridTop-5, sx+10, sy+10, 5); ctx.stroke(); ctx.setLineDash([]);
        ctx.fillStyle = 'rgba(34,211,238,0.85)'; ctx.font = '600 8px monospace';
        ctx.fillText('PILOTO', gx0-5, gridTop-9);

        // stage label + progress %
        const pct = activated/total;
        const stage = pct < 0.16 ? 'PILOTO · 1 EQUIPO' : pct < 0.8 ? 'AMPLIANDO A LA EMPRESA' : 'EN PRODUCCIÓN';
        ctx.fillStyle = 'rgba(255,255,255,0.6)'; ctx.font = '600 11px monospace'; ctx.textAlign = 'start';
        ctx.fillText(stage, gx0, P+12);
        ctx.fillStyle = GREEN; ctx.textAlign = 'end';
        ctx.fillText(Math.round(pct*100)+'%', gx1, P+12); ctx.textAlign = 'start';

        // monitoring heartbeat (monitoreo intensivo)
        const mLabelY = gridBot + 20, monY = gridBot + 44;
        ctx.fillStyle = 'rgba(255,255,255,0.4)'; ctx.font = '600 8px monospace';
        ctx.fillText('MONITOREO EN VIVO', gx0, mLabelY);
        const pulse = (Math.sin(t*4)+1)/2;
        ctx.fillStyle = `rgba(34,197,94,${0.4+pulse*0.5})`;
        ctx.beginPath(); ctx.arc(gx0+100, mLabelY-3, 2.4+pulse*1.6, 0, Math.PI*2); ctx.fill();

        ctx.strokeStyle = 'rgba(255,255,255,0.07)'; ctx.lineWidth = 1;
        ctx.beginPath(); ctx.moveTo(gx0, monY); ctx.lineTo(gx1, monY); ctx.stroke();
        const gm = ctx.createLinearGradient(gx0, 0, gx1, 0);
        gm.addColorStop(0, GREEN); gm.addColorStop(1, CYAN);
        ctx.strokeStyle = gm; ctx.lineWidth = 2; ctx.lineJoin = 'round'; ctx.beginPath();
        for (let x = gx0; x <= gx1; x++) {
          const s = (x - gx0) + t*70;
          const beat = s % 130;
          const spike = Math.exp(-Math.pow(beat-65, 2)/28);
          const y = monY - spike*(11 + pulse*3) + Math.sin((x-gx0)*0.14)*1.4;
          if (x === gx0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
        }
        ctx.stroke();

      } else {
        /* EVOLUCIÓN — roadmap que se extiende: la línea de tiempo crece y
           va revelando nuevos módulos uno a uno, mes a mes. Un tip luminoso
           lidera el avance; cada módulo aparece con un pop + su etiqueta. */
        const baseY = h/2 + 6;
        const x0 = P + 4, x1 = w - P - 4;
        // full faint track + month ticks
        ctx.strokeStyle = 'rgba(255,255,255,0.08)'; ctx.lineWidth = 2;
        ctx.beginPath(); ctx.moveTo(x0, baseY); ctx.lineTo(x1, baseY); ctx.stroke();
        for (let m = 0; m <= 6; m++) {
          const tx = x0 + (m/6)*(x1-x0);
          ctx.strokeStyle = 'rgba(255,255,255,0.10)'; ctx.lineWidth = 1;
          ctx.beginPath(); ctx.moveTo(tx, baseY-3); ctx.lineTo(tx, baseY+3); ctx.stroke();
        }

        const g = clamp((t*0.14) % 1.28, 0, 1);   // grow, then brief pause
        const tipX = x0 + g*(x1 - x0);
        // grown portion
        const gl = ctx.createLinearGradient(x0, 0, x1, 0);
        gl.addColorStop(0, GREEN); gl.addColorStop(1, CYAN);
        ctx.strokeStyle = gl; ctx.lineWidth = 3.5; ctx.lineCap = 'round';
        ctx.beginPath(); ctx.moveTo(x0, baseY); ctx.lineTo(tipX, baseY); ctx.stroke();
        ctx.lineCap = 'butt';

        const mods = [
          { fx: 0.13, up: true,  label: 'SLA' },
          { fx: 0.31, up: false, label: 'Roadmap' },
          { fx: 0.50, up: true,  label: 'Módulo' },
          { fx: 0.69, up: false, label: 'Integración' },
          { fx: 0.87, up: true,  label: 'Reporte' },
        ];
        const cardW = Math.min(104, (x1-x0)/5.4), cardH = 42, gapV = 15;
        mods.forEach((m) => {
          const mx = x0 + m.fx*(x1-x0);
          const revealed = tipX >= mx;
          if (!revealed) {
            ctx.fillStyle = 'rgba(255,255,255,0.16)';
            ctx.beginPath(); ctx.arc(mx, baseY, 3, 0, Math.PI*2); ctx.fill();
            return;
          }
          const ap = ease(clamp((tipX - mx)/26, 0, 1));
          const dir = m.up ? -1 : 1;
          const off = (1 - ap) * 10 * dir;
          const connEnd = baseY + dir*gapV + off;
          const cardY = m.up ? connEnd - cardH : connEnd;
          let cardX = mx - cardW/2;
          cardX = clamp(cardX, x0, x1 - cardW);

          ctx.globalAlpha = ap;
          // connector
          ctx.strokeStyle = 'rgba(34,197,94,0.45)'; ctx.lineWidth = 1.5;
          ctx.beginPath(); ctx.moveTo(mx, baseY); ctx.lineTo(mx, connEnd); ctx.stroke();
          // card
          ctx.fillStyle = 'rgba(20,30,28,0.92)';
          ctx.strokeStyle = 'rgba(34,197,94,0.4)'; ctx.lineWidth = 1;
          rr(cardX, cardY, cardW, cardH, 8); ctx.fill(); ctx.stroke();
          // "+" badge
          const bx2 = cardX + 12, by2 = cardY + 13;
          ctx.strokeStyle = GREEN; ctx.lineWidth = 1.6; ctx.lineCap = 'round';
          ctx.beginPath(); ctx.moveTo(bx2-3, by2); ctx.lineTo(bx2+3, by2);
          ctx.moveTo(bx2, by2-3); ctx.lineTo(bx2, by2+3); ctx.stroke(); ctx.lineCap = 'butt';
          // label + subline
          ctx.fillStyle = 'rgba(255,255,255,0.9)'; ctx.font = '600 10px monospace';
          ctx.fillText(m.label, cardX + 22, cardY + 16);
          ctx.fillStyle = 'rgba(255,255,255,0.14)'; rr(cardX+12, cardY+26, cardW-24, 3, 1.5); ctx.fill();
          ctx.fillStyle = 'rgba(255,255,255,0.10)'; rr(cardX+12, cardY+33, cardW*0.5, 3, 1.5); ctx.fill();
          ctx.globalAlpha = 1;

          // node on baseline
          const pulse = (Math.sin(t*2.2 + m.fx*10) + 1)/2;
          ctx.fillStyle = `rgba(34,197,94,${0.18 + pulse*0.22*ap})`;
          ctx.beginPath(); ctx.arc(mx, baseY, 4 + pulse*4*ap, 0, Math.PI*2); ctx.fill();
          ctx.fillStyle = GREEN;
          ctx.beginPath(); ctx.arc(mx, baseY, 3.5, 0, Math.PI*2); ctx.fill();
        });

        // leading glow tip while growing
        if (g < 0.999) {
          const tp = (Math.sin(t*4) + 1)/2;
          ctx.fillStyle = 'rgba(6,182,212,0.25)';
          ctx.beginPath(); ctx.arc(tipX, baseY, 6 + tp*4, 0, Math.PI*2); ctx.fill();
          ctx.fillStyle = '#fff'; ctx.shadowColor = CYAN; ctx.shadowBlur = 12;
          ctx.beginPath(); ctx.arc(tipX, baseY, 3.5, 0, Math.PI*2); ctx.fill();
          ctx.shadowBlur = 0;
        }
      }
      raf = requestAnimationFrame(draw);
    };
    draw();
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [kind]);
  return <canvas ref={ref} style={{ width: '100%', height: '100%', display: 'block' }} />;
};

const ProcHero = () => (
  <section className="page-hero">
    <div className="page-hero-bg" />
    <div className="container">
      <div className="crumb"><a href="../index.html">Inicio</a><span className="sep">/</span><span>Proceso</span></div>
      <h1>Un proceso <span className="grad">transparente</span>, diseñado para que duermas tranquilo.</h1>
      <p className="lede">Trabajar con un equipo de software no debería sentirse como una caja negra. Estas son las 5 etapas por las que vas a pasar — qué entregamos, cuánto tarda, qué decisiones tomas tú.</p>
    </div>
  </section>
);

const stages = [
  {
    n: '01', id: 'discovery', t: 'Discovery', h: 'Entender tu negocio antes de tocar código',
    p: 'Una semana intensiva: mapeamos procesos, entrevistamos a tu equipo, identificamos los 3 cuellos de botella que más dinero te están costando. Sales con claridad sobre qué construir primero — y qué no.',
    deliv: [
      { t: 'Mapa de operación', d: 'Diagrama visual de tus flujos actuales' },
      { t: 'Top 3 oportunidades', d: 'Priorizadas por impacto/esfuerzo' },
      { t: 'Especificación funcional', d: 'Documento vivo en Notion compartido' },
      { t: 'Estimación honesta', d: 'Rango de inversión + cronograma' },
    ],
    dur: '1–2 semanas', kind: 'discover',
  },
  {
    n: '02', id: 'design', t: 'Diseño', h: 'Prototipos clickeables antes de cualquier línea de código',
    p: 'Diseñamos la experiencia completa en Figma. Tú haces clic, lo pruebas, lo destrozas, lo cambias. Iteramos hasta que sientas que el sistema ya está vivo. Solo entonces pasamos a desarrollo.',
    deliv: [
      { t: 'Wireframes de baja fidelidad', d: 'Para validar la estructura' },
      { t: 'Diseño visual', d: 'Tu marca, tu identidad, tu look' },
      { t: 'Prototipo interactivo', d: 'Clickeable como si fuera real' },
      { t: 'Design system', d: 'Componentes reusables documentados' },
    ],
    dur: '2–3 semanas', kind: 'design',
  },
  {
    n: '03', id: 'build', t: 'Desarrollo', h: 'Sprints de 2 semanas con demos en vivo',
    p: 'Cada 14 días te mostramos lo que hicimos en una llamada de 30 minutos. Pruebas, comentas, priorizamos. Tu sistema crece a la vista — sin sorpresas el día del lanzamiento, sin "ya casi".',
    deliv: [
      { t: 'Demo bisemanal en vivo', d: 'Sin slides — el producto real' },
      { t: 'Acceso a staging', d: 'Pruébalo cuando quieras' },
      { t: 'Backlog priorizado', d: 'Tu equipo decide qué sigue' },
      { t: 'Tests automatizados', d: 'Cobertura en la lógica central' },
    ],
    dur: '6–16 semanas', kind: 'build',
  },
  {
    n: '04', id: 'launch', t: 'Lanzamiento', h: 'De staging a producción sin drama',
    p: 'Hacemos el cutover por etapas: piloto con un equipo, luego ampliamos. Capacitamos a tu gente con sesiones grabadas. Monitoreamos cada métrica las primeras 2 semanas para resolver fricción antes de que la sientas.',
    deliv: [
      { t: 'Piloto controlado', d: 'Empieza con 1 equipo o sucursal' },
      { t: 'Capacitación grabada', d: 'Para nuevos usuarios futuros' },
      { t: 'Migración de datos', d: 'De tu sistema actual sin pérdidas' },
      { t: 'Monitoreo intensivo', d: 'Las primeras 2 semanas en vivo' },
    ],
    dur: '1–2 semanas', kind: 'launch',
  },
  {
    n: '05', id: 'evolve', t: 'Evolución', h: 'Tu sistema crece contigo, no se queda en el día 1',
    p: 'Después del lanzamiento seguimos contigo: nuevos módulos cuando los necesites, integraciones según vayas adoptando herramientas, mejoras basadas en uso real. Slack directo con los devs, no tickets fríos.',
    deliv: [
      { t: 'Soporte por escrito', d: 'Tiempos de respuesta acordados contigo' },
      { t: 'Roadmap mensual', d: 'Tú priorizas, nosotros ejecutamos' },
      { t: 'Reporte mensual', d: 'Qué cambió, qué métricas mejoraron' },
      { t: 'Slack directo', d: 'Con los developers que conocen tu sistema' },
    ],
    dur: 'Continua', kind: 'evolve',
  },
];

const Timeline = () => {
  const [active, setActive] = useStateP(0);
  const [direction, setDirection] = useStateP(0);
  const tabRefs = useRefP([]);

  const nextStage = () => {
    if (active < stages.length - 1) {
      setDirection(1);
      setActive(active + 1);
    }
  };

  const prevStage = () => {
    if (active > 0) {
      setDirection(-1);
      setActive(active - 1);
    }
  };

  const currentStage = stages[active];
  const selectStage = (index, focus = false) => {
    const next = (index + stages.length) % stages.length;
    setDirection(next > active ? 1 : -1);
    setActive(next);
    requestAnimationFrame(() => {
      const tab = tabRefs.current[next];
      if (!tab) return;
      if (focus) tab.focus();
      if (window.innerWidth <= 700) tab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
    });
  };
  const handleTabKey = (e, index) => {
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); selectStage(index + 1, true); }
    if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); selectStage(index - 1, true); }
    if (e.key === 'Home') { e.preventDefault(); selectStage(0, true); }
    if (e.key === 'End') { e.preventDefault(); selectStage(stages.length - 1, true); }
  };

  return (
    <section className="section">
      <div className="container">
        <div className="section-head">
          <div className="section-eyebrow">Nuestro proceso</div>
          <h2 className="section-title">5 etapas claras. Cero sorpresas.</h2>
        </div>

        {/* Tabs */}
        <div className="proc-tabs proc-stepper" role="tablist" aria-label="Etapas del proceso" style={{ '--proc-progress': `${(active / (stages.length - 1)) * 100}%` }}>
          {stages.map((s, i) => (
            <button
              key={s.id}
              ref={el => tabRefs.current[i] = el}
              id={`proc-tab-${s.id}`}
              role="tab"
              aria-selected={active === i}
              aria-controls="proc-stage-panel"
              tabIndex={active === i ? 0 : -1}
              className={`proc-tab ${active === i ? 'active' : ''} ${i < active ? 'completed' : ''}`}
              onClick={() => selectStage(i)}
              onKeyDown={e => handleTabKey(e, i)}
            >
              <span className="proc-tab-node"><span className="proc-tab-num">{s.n}</span></span>
              <span className="proc-tab-label">{s.t}</span>
            </button>
          ))}
        </div>

        {/* Content Window */}
        <div className="proc-window">
          <div key={currentStage.id} id="proc-stage-panel" role="tabpanel" aria-labelledby={`proc-tab-${currentStage.id}`} className="proc-content proc-content-enter">
            <div className="proc-stage-header">
              <span className="pill">{currentStage.n}</span>
              <span className="proc-stage-dur">{currentStage.dur}</span>
            </div>
            <h2 className="proc-stage-title">{currentStage.h}</h2>
            <p className="proc-stage-desc">{currentStage.p}</p>

            <div className="tl-deliverables">
              {currentStage.deliv.map((d, i) => (
                <div key={i} className="tl-deliverable">
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                  <div><strong>{d.t}</strong>{d.d}</div>
                </div>
              ))}
            </div>

            <div className="flow-anim">
              <FlowAnimation kind={currentStage.kind} />
            </div>
          </div>

          {/* Navigation */}
          <div className="proc-nav">
            <button
              className="proc-nav-btn"
              onClick={prevStage}
              disabled={active === 0}
              aria-label="Anterior"
            >
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
            </button>
            <div className="proc-nav-dots">
              {stages.map((_, i) => (
                <span key={i} className={`proc-dot ${active === i ? 'active' : ''}`} />
              ))}
            </div>
            <button
              className="proc-nav-btn"
              onClick={nextStage}
              disabled={active === stages.length - 1}
              aria-label="Siguiente"
            >
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
            </button>
          </div>
        </div>
      </div>
    </section>
  );
};

const ProcWhy = () => (
  <section className="section section-soft">
    <div className="container">
      <div className="section-head">
        <div className="section-eyebrow">Por qué este proceso</div>
        <h2 className="section-title">Está diseñado para que tu inversión sea segura.</h2>
      </div>
      <div className="features">
        <div className="feature">
          <div className="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg></div>
          <h4>Iteración corta</h4>
          <p>Demos cada 2 semanas — si algo no va bien, lo descubres temprano, no al final.</p>
        </div>
        <div className="feature">
          <div className="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></div>
          <h4>Tu propiedad</h4>
          <p>El código vive en tu repositorio. Si quieres cambiar de equipo, no hay rehén tecnológico.</p>
        </div>
        <div className="feature">
          <div className="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg></div>
          <h4>Salida limpia</h4>
          <p>No firmas contratos eternos. Cada fase tiene un punto natural para parar si algo no encaja.</p>
        </div>
        <div className="feature">
          <div className="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
          <h4>Sin sobre-ingeniería</h4>
          <p>Construimos lo que necesitas hoy y lo que vas a necesitar mañana — no lo que se ve impresionante.</p>
        </div>
      </div>
    </div>
  </section>
);

const ProcApp = () => (
  <>
    <SiteNav current="proceso" />
    <ProcHero />
    <Timeline />
    <ProcWhy />
    <BigCTA />
    <SiteFooter />
  </>
);

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