// === F9 · Flex — Réplica en tiempo real (12s) — cierre del bloque de personalización ===
// El aporte de valor contra el Excel: un archivo frágil en un solo ordenador
// frente a tus datos replicados en tiempo real en varios centros.
// Beats: archivo .xlsx triste y tenue (0.5-3.2) → GOLPE: el archivo se disuelve
// en datos, entra el titular grande y el mapa de Europa punteado se despliega
// (3.2-6.0) → 3 nodos conectados con pulsos que laten desfasados y chips
// "≈ tiempo real" (6.0-9.0) → claim en verde "Si un centro cae, tu negocio
// sigue." con caída y recuperación de un nodo EN ESCENA (9.0-11.2). Reposo 11.2.
// Sincronizado con CAPTIONS.slide_replica (0.5-3.2 / 3.2-6.0 / 6.0-9.0 / 9.0-11.7).
// Prefijo FXRP_ para no colisionar con consts globales de otros scripts babel.

// --- Mapa de Europa punteado (bitmap 48×28 → puntos) ---
const FXRP_EU = [
  '................................#####...########',
  '..............................#########.########',
  '............................###########..#######',
  '..........................############....######',
  '.######..................#############.....#####',
  '.#######................##############......####',
  '..####.................##############........###',
  '......................###############.........##',
  '.....................###############.###########',
  '....................###############.############',
  '.............###....####.####..#####.###########',
  '.............###.......######..#####.###########',
  '..........###.###......#####..#####.############',
  '..........###.####....##########################',
  '..........###.####..############################',
  '..............####.#############################',
  '...............#################################',
  '...............################################.',
  '...............###############################..',
  '...............##########################.......',
  '...............#########################........',
  '................#####..####.###########.........',
  '...........#########..#.###..##########.........',
  '...........#########..#..####.#####..#####......',
  '...........########...#...#####.####.#########..',
  '............#######........###.###..##########..',
  '.............#####.......###...##....########...',
  '..............###........##.....###.............',
];
const FXRP_CELL = 22, FXRP_MX = 432, FXRP_MY = 210;
const FXRP_DOTS = (()=>{
  const land = (r, c) => r >= 0 && r < FXRP_EU.length && c >= 0 && c < 48 && FXRP_EU[r][c] === '#';
  const out = [];
  FXRP_EU.forEach((row, r)=>{
    for (let c = 0; c < 48; c++){
      if (row[c] !== '#') continue;
      const coast = land(r-1,c) === false || land(r+1,c) === false || land(r,c-1) === false || land(r,c+1) === false;
      const eastFade = c >= 40 ? 1 - (c - 39)*0.09 : 1;   // la masa del este se difumina — el foco es Europa
      out.push({ x: FXRP_MX + c*FXRP_CELL, y: FXRP_MY + r*FXRP_CELL, v: ((r*48+c)*7919) % 13, coast, f: eastFade });
    }
  });
  return out;
})();

function SlideFlexReplica({ t }){
  // --- Timeline (sincronizada con cues slide_replica) ---
  const fileT     = 0.5;                 // cue 0.5-3.2 · el archivo frágil
  const legendT   = 1.1;                 // "Un archivo, en un ordenador"
  const dissolveT = 3.2;                 // cue 3.2-6.0 · GOLPE: el archivo se disuelve
  const headT     = 3.45;                // titular grande
  const mapT      = 3.7;                 // el mapa se despliega detrás
  const nodeTs    = [6.45, 6.15, 6.75];  // cue 6.0-9.0 · A suroeste · B central · C noreste (B primero: es el origen)
  const edgeTs    = [6.9, 7.15, 7.45];   // B→A · B→C · A→C (triángulo, la última tenue)
  const pulseT    = 7.4;                 // pulsos continuos desfasados desde el nodo central
  const chipTs    = [7.7, 8.0];          // chips "≈ tiempo real" sobre las líneas
  const claimT    = 9.2;                 // cue 9.0-11.7 · claim en verde
  const fallT     = 9.7;                 // el nodo C cae…
  const recoverT  = 10.8;                // …y el sistema lo recupera. Reposo a 11.2 (dur 12)

  // --- Geometría (sobre el mapa 432-1466 × 210-804) ---
  const nodes = [ { x:751, y:727 }, { x:949, y:551 }, { x:1059, y:408 } ];
  const mainEdges = [ { from:1, to:0, phase:0 }, { from:1, to:2, phase:0.45 } ];
  const chips = [ { x:818, y:627 }, { x:1030, y:496 } ];

  // 0 = vivo · 1 = caído. Sube rápido al caer, baja suave al recuperarse.
  const fallMix = t < fallT ? 0 : t < recoverT ? clamp((t - fallT)/0.35, 0, 1) : 1 - clamp((t - recoverT)/0.45, 0, 1);

  // --- Beat 1: el archivo frágil ---
  const fIn  = clamp((t - fileT)/0.7, 0, 1);
  const fInE = Easing.easeOutCubic(fIn);
  const fOut = clamp((t - dissolveT)/0.8, 0, 1);
  const fOutE = Easing.easeInQuad(fOut);
  const legP = clamp((t - legendT)/0.6, 0, 1);
  const sway = Math.sin(t*1.35)*1.6;                              // se balancea, frágil
  const flicker = 0.72 + 0.16*Math.sin(t*6.3)*Math.sin(t*2.4);    // luz tenue que tiembla

  return (
    <SlideCanvas variant="dark-deep">

      {/* ===== Mapa punteado + nodos + pulsos (fondo, desde el GOLPE) ===== */}
      {t >= mapT - 0.1 && (
        <svg width="1920" height="1080" viewBox="0 0 1920 1080" style={{position:'absolute', inset:0, pointerEvents:'none'}}>
          {/* Puntos de tierra: cascada radial desde el centro */}
          {FXRP_DOTS.map((d, i)=>{
            const dist = Math.hypot(d.x - 960, d.y - 520);
            const p = clamp((t - mapT - dist*0.0008)/0.5, 0, 1);
            if (p <= 0) return null;
            const baseOp = d.coast ? 0.42 + (d.v/13)*0.10 : 0.15 + (d.v/13)*0.08;
            return <circle key={i} cx={d.x} cy={d.y} r={d.coast ? 2.7 : 2.3} fill="#6FBFFF" opacity={baseOp * d.f * p}/>;
          })}

          {/* Líneas del triángulo: dos principales + una tenue */}
          {[ [1,0], [1,2], [0,2] ].map((ed, i)=>{
            const a = nodes[ed[0]], b = nodes[ed[1]];
            const p = clamp((t - edgeTs[i])/0.8, 0, 1);
            if (p <= 0) return null;
            const e = Easing.easeInOutSine(p);
            const faint = i === 2;
            const touchesC = ed[0] === 2 || ed[1] === 2;
            const dim = touchesC ? lerp(1, 0.12, fallMix) : 1;
            const op = (faint ? 0.14 : 0.5) * clamp(p*1.3, 0, 1) * dim;
            return (
              <g key={'e'+i}>
                <line x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="#00C1FF" strokeWidth="4.5" opacity={op*0.25} pathLength="1" strokeDasharray="1" strokeDashoffset={1-e}/>
                <line x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="#00C1FF" strokeWidth="1.6" opacity={op} pathLength="1" strokeDasharray="1" strokeDashoffset={1-e} strokeLinecap="round"/>
              </g>
            );
          })}

          {/* Pulsos: cada dato viaja del nodo central a los otros dos, desfasados, continuo */}
          {mainEdges.map((ed, i)=>{
            if (t < pulseT) return null;
            const a = nodes[ed.from], b = nodes[ed.to];
            const hide = ed.to === 2 ? fallMix : 0;
            const u = (((t - pulseT)/1.7 + ed.phase) % 1 + 1) % 1;
            const fadeIn = clamp((t - pulseT)/0.6, 0, 1);
            const op = fadeIn * (0.35 + 0.65*Math.sin(u*Math.PI)) * (1 - hide);
            if (op <= 0.01) return null;
            const u2 = Math.max(0, u - 0.05), u3 = Math.max(0, u - 0.1);
            return (
              <g key={'p'+i} opacity={op}>
                <circle cx={lerp(a.x,b.x,u)} cy={lerp(a.y,b.y,u)} r="9" fill="rgba(0,193,255,0.20)"/>
                <circle cx={lerp(a.x,b.x,u)} cy={lerp(a.y,b.y,u)} r="4.4" fill="#BFE9FF"/>
                <circle cx={lerp(a.x,b.x,u2)} cy={lerp(a.y,b.y,u2)} r="2.9" fill="#8FD4FF" opacity="0.55"/>
                <circle cx={lerp(a.x,b.x,u3)} cy={lerp(a.y,b.y,u3)} r="2" fill="#5FB8F5" opacity="0.3"/>
              </g>
            );
          })}

          {/* Onda de llegada en el nodo receptor */}
          {mainEdges.map((ed, i)=>{
            if (t < pulseT + 0.5) return null;
            const u = (((t - pulseT)/1.7 + ed.phase) % 1 + 1) % 1;
            if (u < 0.86) return null;
            const b = nodes[ed.to];
            const hide = ed.to === 2 ? fallMix : 0;
            const fp = (u - 0.86)/0.14;
            return <circle key={'w'+i} cx={b.x} cy={b.y} r={10 + fp*20} fill="none" stroke="#9BE1FF" strokeWidth="1.6" opacity={(1-fp)*0.55*(1-hide)}/>;
          })}

          {/* Nodos: laten desfasados. El C cae en el beat 4 y se recupera. */}
          {nodes.map((n, i)=>{
            const p = clamp((t - nodeTs[i])/0.5, 0, 1);
            if (p <= 0) return null;
            const e = Easing.easeOutBack(p);
            const mix = i === 2 ? fallMix : 0;
            const ph = (((t - nodeTs[i]) % 1.8) + 1.8) % 1.8 / 1.8;
            return (
              <g key={'n'+i} opacity={clamp(p*1.3,0,1)*(1 - mix*0.45)} transform={`translate(${n.x} ${n.y}) scale(${lerp(0.4,1,e)})`}>
                <circle r="26" fill={`rgba(0,193,255,${0.14*(1-mix)})`}/>
                {mix < 0.5 && <circle r={10 + ph*22} fill="none" stroke="#00C1FF" strokeWidth="1.6" opacity={(1-ph)*0.6*(1-mix)}/>}
                <circle r="8" fill="#0B1729" stroke={mix > 0.5 ? '#5B6B7E' : '#00C1FF'} strokeWidth="2.2"/>
                <circle r="3.6" fill={mix > 0.5 ? '#64748B' : '#E8F7FF'}/>
              </g>
            );
          })}

          {/* Onda gris al caer el nodo C */}
          {t >= fallT && t < fallT + 0.7 && (()=>{
            const p = clamp((t - fallT)/0.7, 0, 1);
            return <circle cx={nodes[2].x} cy={nodes[2].y} r={8 + p*26} fill="none" stroke="#64748B" strokeWidth="1.8" opacity={(1-p)*0.7}/>;
          })()}

          {/* Estallido verde al recuperarse — "tu negocio sigue" */}
          {t >= recoverT && t < recoverT + 0.8 && (()=>{
            const p = clamp((t - recoverT)/0.8, 0, 1);
            return <circle cx={nodes[2].x} cy={nodes[2].y} r={8 + p*34} fill="none" stroke="#56E16A" strokeWidth="2" opacity={(1-p)*0.8}/>;
          })()}
        </svg>
      )}

      {/* Rótulo del contraste: el presente replicado — entra con el mapa */}
      {t >= 3.95 && (()=>{
        const p = clamp((t - 3.95)/0.55, 0, 1);
        const e = Easing.easeOutBack(p);
        return (
          <div style={{position:'absolute', left:905, top:336, transform:`translate(-50%,-50%) scale(${lerp(0.7,1,e)})`, opacity:clamp(p*1.25,0,1), zIndex:4}}>
            <span className="f-mono" style={{display:'inline-flex',alignItems:'center',gap:9,padding:'7px 16px',borderRadius:100,border:'1px solid rgba(0,193,255,0.45)',background:'rgba(0,133,255,0.16)',color:'#9BE1FF',fontSize:12,fontWeight:700,letterSpacing:'2.5px',whiteSpace:'nowrap',boxShadow:'0 6px 24px rgba(0,133,255,0.25)',backdropFilter:'blur(4px)'}}>
              <span style={{width:7,height:7,borderRadius:100,background:'#56E16A',boxShadow:'0 0 10px rgba(86,225,106,0.8)',flexShrink:0}}/>
              EN DINAUP
            </span>
          </div>
        );
      })()}

      {/* Chips "≈ tiempo real" sobre las líneas */}
      {chips.map((c, i)=>{
        const p = clamp((t - chipTs[i])/0.5, 0, 1);
        if (p <= 0) return null;
        const e = Easing.easeOutBack(p);
        const hide = i === 1 ? fallMix : 0;
        return (
          <div key={'c'+i} style={{
            position:'absolute', left:c.x, top:c.y,
            transform:`translate(-50%,-50%) scale(${lerp(0.6,1,e)})`,
            opacity: clamp(p*1.2,0,1)*(1 - hide*0.75),
            padding:'5px 13px', borderRadius:100,
            background:'rgba(2,20,38,0.74)', border:'1px solid rgba(0,193,255,0.35)',
            boxShadow:'0 4px 16px rgba(0,0,0,0.35)',
          }}>
            <span className="f-mono" style={{fontSize:11.5, fontWeight:600, color:'#9BE1FF', letterSpacing:'0.06em', whiteSpace:'nowrap'}}>≈ tiempo real</span>
          </div>
        );
      })}

      {/* ===== GOLPE: destello sobrio al disolverse el archivo ===== */}
      {t >= dissolveT && t < dissolveT + 1.2 && (()=>{
        const p = clamp((t - dissolveT)/1.2, 0, 1);
        return <div style={{position:'absolute', inset:0, background:'radial-gradient(ellipse 60% 45% at 50% 42%, rgba(155,225,255,1), transparent 70%)', opacity:Math.sin(p*Math.PI)*0.09, pointerEvents:'none'}}/>;
      })()}

      {/* ===== Beat 1: el archivo .xlsx frágil, luz tenue, casi triste ===== */}
      {fOut < 1 && t >= fileT && (
        <div style={{
          position:'absolute', left:320, top:330, width:340, textAlign:'center',
          opacity: fInE * (1 - fOutE),
          filter:`blur(${fOutE*6}px)`,
          transform:`translateY(${(1-fInE)*18 + fOutE*16}px) scale(${lerp(1, 0.93, fOutE)})`,
        }}>
          {/* Luz tenue que tiembla */}
          <div style={{position:'absolute', left:-40, top:-70, width:420, height:460, borderRadius:'50%', background:'radial-gradient(closest-side, rgba(148,163,184,0.10), transparent 70%)', opacity:flicker}}/>
          {/* Rótulo del contraste: el pasado frágil */}
          {(()=>{
            const p = clamp((t - 0.85)/0.5, 0, 1);
            const e = Easing.easeOutCubic(p);
            return (
              <div style={{marginBottom:18, opacity:p, transform:`translateY(${(1-e)*8}px)`}}>
                <span className="f-mono" style={{display:'inline-flex',alignItems:'center',gap:8,padding:'6px 14px',borderRadius:100,border:'1px solid rgba(148,163,184,0.30)',background:'rgba(148,163,184,0.08)',color:'rgba(226,232,240,0.60)',fontSize:11.5,fontWeight:600,letterSpacing:'2.5px',whiteSpace:'nowrap'}}>EL EXCEL DE ANTES</span>
              </div>
            );
          })()}
          <div style={{position:'relative', display:'inline-block', transform:`rotate(${sway}deg)`}}>
            <svg width="96" height="116" viewBox="0 0 96 116">
              <path d="M16 5 H60 L84 29 V101 A9 9 0 0 1 75 110 H16 A9 9 0 0 1 7 101 V14 A9 9 0 0 1 16 5 Z" fill="rgba(34,60,50,0.55)" stroke="#4E8F6C" strokeWidth="1.8"/>
              <path d="M60 5 V29 H84" fill="none" stroke="#4E8F6C" strokeWidth="1.8" strokeLinejoin="round"/>
              <rect x="22" y="45" width="48" height="42" fill="none" stroke="rgba(158,199,178,0.40)" strokeWidth="1.4"/>
              <path d="M22 59 H70 M22 73 H70" stroke="rgba(158,199,178,0.32)" strokeWidth="1.4"/>
              <path d="M38 45 V87 M54 45 V87" stroke="rgba(158,199,178,0.32)" strokeWidth="1.4"/>
              <text x="46" y="103" textAnchor="middle" fill="#7FB89B" fontSize="12" fontFamily="'JetBrains Mono',monospace" fontWeight="600">.xlsx</text>
            </svg>
          </div>
          {/* Leyenda: un ordenador, un archivo */}
          <div style={{display:'flex', alignItems:'center', justifyContent:'center', gap:9, marginTop:24, opacity:legP, transform:`translateY(${(1-Easing.easeOutCubic(legP))*8}px)`}}>
            <svg width="19" height="19" viewBox="0 0 24 24" fill="none">
              <rect x="3" y="4.5" width="18" height="12.5" rx="1.8" stroke="rgba(255,255,255,0.5)" strokeWidth="1.7"/>
              <path d="M9 20.5 H15 M12 17 V20.5" stroke="rgba(255,255,255,0.5)" strokeWidth="1.7" strokeLinecap="round"/>
            </svg>
            <span className="f-plex" style={{fontSize:19, fontWeight:500, color:'rgba(255,255,255,0.55)', letterSpacing:'-0.01em', whiteSpace:'nowrap'}}>Un archivo, en un ordenador</span>
          </div>
        </div>
      )}

      {/* El archivo se disuelve EN datos que vuelan hacia el mapa */}
      {t >= dissolveT && t < dissolveT + 1.5 && (
        <svg width="1920" height="1080" viewBox="0 0 1920 1080" style={{position:'absolute', inset:0, pointerEvents:'none'}}>
          {[0,1,2,3,4,5,6,7,8].map((i)=>{
            const d0 = dissolveT + 0.05 + (i%3)*0.09;
            const p = clamp((t - d0)/1.05, 0, 1);
            if (p <= 0 || p >= 1) return null;
            const e = Easing.easeInOutCubic(p);
            const sx = 470 + ((i*37) % 60) - 30, sy = 420 + ((i*61) % 120) - 40;
            const tx = 760 + ((i*97) % 420), ty = 330 + ((i*53) % 330);
            return <circle key={i} cx={lerp(sx,tx,e)} cy={lerp(sy,ty,e) - Math.sin(p*Math.PI)*40} r={3.2 - p*1.2} fill="#6FBFFF" opacity={Math.sin(p*Math.PI)*0.75}/>;
          })}
        </svg>
      )}

      {/* ===== Titular grande (el GOLPE) ===== */}
      {t >= headT && (()=>{
        const p = clamp((t - headT)/0.85, 0, 1);
        const e = Easing.easeOutCubic(p);
        return (
          <div style={{position:'absolute', top:0, left:0, right:0, zIndex:5, pointerEvents:'none'}}>
            <div style={{position:'absolute', top:30, left:'50%', transform:'translateX(-50%)', width:1100, height:260, background:'radial-gradient(closest-side, rgba(0,133,255,0.14), transparent 72%)', opacity:e}}/>
            <div style={{position:'absolute', top:108, left:0, right:0, textAlign:'center', opacity:p, transform:`translateY(${(1-e)*20}px) scale(${lerp(1.06,1,e)})`}}>
              <h2 className="f-plex" style={{fontSize:62, fontWeight:700, letterSpacing:'-0.035em', margin:0, color:'#fff', lineHeight:1.05}}>
                Tus datos viven <span className="grad-text">replicados.</span>
              </h2>
            </div>
          </div>
        );
      })()}

      {/* ===== Claim final en verde ===== */}
      {t >= claimT && (()=>{
        const p = clamp((t - claimT)/0.7, 0, 1);
        const e = Easing.easeOutCubic(p);
        return (
          <div style={{position:'absolute', top:836, left:0, right:0, display:'flex', alignItems:'center', justifyContent:'center', gap:13, opacity:p, transform:`translateY(${(1-e)*16}px)`, zIndex:5}}>
            <svg width="28" height="28" viewBox="0 0 24 24" fill="none">
              <path d="M12 2.5 L4.5 5.8 V11.5 C4.5 16.6 7.7 20.4 12 21.8 C16.3 20.4 19.5 16.6 19.5 11.5 V5.8 L12 2.5 Z" stroke="#56E16A" strokeWidth="1.8" strokeLinejoin="round"/>
              <path d="M8.6 12 L11 14.4 L15.6 9.8" stroke="#56E16A" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
            <span className="f-plex" style={{fontSize:29, fontWeight:600, letterSpacing:'-0.015em', color:'#56E16A', whiteSpace:'nowrap'}}>
              Si un centro cae, <span style={{fontWeight:800}}>tu negocio sigue.</span>
            </span>
          </div>
        );
      })()}

      {/* ===== Eyebrow ===== */}
      {(()=>{
        const p = clamp((t - 0.25)/0.6, 0, 1);
        return (
          <div className="f-plex" style={{position:'absolute', top:58, left:0, right:0, textAlign:'center', fontSize:14, fontWeight:600, letterSpacing:'2.5px', color:'#62B4FF', opacity:p, zIndex:5}}>
            A DIFERENCIA DE UN EXCEL
          </div>
        );
      })()}

      <SocialCaption t={t} cues={CAPTIONS.slide_replica}/>
    </SlideCanvas>
  );
}

Object.assign(window, { SlideFlexReplica });
