// === Shared primitives ===
const { useState: uS2, useEffect: uE2, useRef: uR2, useMemo: uM2 } = React;

// Dinaup logo (real asset)
function DinaupLogo({ size=26, mark=false, style }){
  const src = mark ? 'assets/dinaup-icon.svg' : 'assets/dinaup-logo.svg';
  const w = mark ? size : size * (3212.98878/750.80262);
  return <img src={src} alt="dinaup" style={{height:size, width:w, display:'block', ...style}}/>;
}

// Dinaup rueda 4-color divider + shimmer
function RuedaDivider({ style }){
  return (
    <div style={{position:'relative', ...style}}>
      <div className="rueda-glow"><div style={{background:'#00C1FF'}}/><div style={{background:'#FF6751'}}/><div style={{background:'#56E16A'}}/><div style={{background:'#FFDC18'}}/></div>
      <div className="rueda-divider">
        <div style={{background:'#00C1FF'}}/>
        <div style={{background:'#FF6751'}}/>
        <div style={{background:'#56E16A'}}/>
        <div style={{background:'#FFDC18'}}/>
        <div className="shimmer"/>
      </div>
    </div>
  );
}

// Browser chrome — Windows 11 Edge/Chrome style (tabs on top, window controls on right)
function BrowserChrome({ url="play.dinaup.com/App/Pymes", title="Dinaup — Gestión para pymes", style }){
  return (
    <div style={style}>
      {/* Tab bar row — dark Windows 11 browser tab strip */}
      <div style={{height:36,background:'#DEE1E6',display:'flex',alignItems:'flex-end',padding:'0 0 0 10px',borderBottom:'1px solid #C9CDD3',position:'relative'}}>
        {/* Active tab */}
        <div style={{height:30,minWidth:220,maxWidth:260,background:'#F4F5F7',borderRadius:'8px 8px 0 0',display:'flex',alignItems:'center',gap:8,padding:'0 10px 0 12px',fontSize:11,color:'#202124',borderTop:'1px solid #C9CDD3',borderLeft:'1px solid #C9CDD3',borderRight:'1px solid #C9CDD3',marginBottom:-1,position:'relative'}}>
          <img src="assets/dinaup-icon.svg" alt="" style={{width:14,height:14,flexShrink:0}}/>
          <span style={{flex:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',fontWeight:500}}>{title}</span>
          <span style={{fontSize:14,color:'#5F6368',cursor:'pointer',lineHeight:1,opacity:0.6}}>×</span>
        </div>
        {/* New tab button */}
        <div style={{width:26,height:26,display:'flex',alignItems:'center',justifyContent:'center',marginLeft:6,marginBottom:2,fontSize:14,color:'#5F6368'}}>+</div>
        <div style={{flex:1}}/>
        {/* Window controls (Windows 11 style — right side) */}
        <div style={{display:'flex',alignSelf:'stretch'}}>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><path d="M0 5 H10" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><rect x="0.5" y="0.5" width="9" height="9" fill="none" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><path d="M0 0 L10 10 M10 0 L0 10" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
        </div>
      </div>
      {/* Toolbar row — back/forward/reload + URL bar */}
      <div style={{height:40,background:'#F4F5F7',display:'flex',alignItems:'center',padding:'0 10px',gap:6,borderBottom:'1px solid #E3E5E8'}}>
        <div style={{width:28,height:28,borderRadius:100,display:'flex',alignItems:'center',justifyContent:'center',color:'#5F6368',cursor:'pointer'}}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M15 6 L9 12 L15 18" stroke="#1F1F1F" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
        <div style={{width:28,height:28,borderRadius:100,display:'flex',alignItems:'center',justifyContent:'center',color:'#BDC1C6',cursor:'default'}}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M9 6 L15 12 L9 18" stroke="#BDC1C6" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
        <div style={{width:28,height:28,borderRadius:100,display:'flex',alignItems:'center',justifyContent:'center',color:'#5F6368',cursor:'pointer'}}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M20 12 A8 8 0 1 1 12 4 L17 4 M17 4 V9" stroke="#1F1F1F" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
        <div style={{flex:1,height:28,background:'#fff',border:'1px solid #DADCE0',borderRadius:100,display:'flex',alignItems:'center',padding:'0 12px',gap:8,fontSize:11,color:'#202124'}}>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none"><path d="M12 2 L4 6 V12 C4 17 7.5 20.5 12 22 C16.5 20.5 20 17 20 12 V6 L12 2 Z" stroke="#5F6368" strokeWidth="1.8" strokeLinejoin="round"/></svg>
          <span style={{flex:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{url}</span>
          <span style={{color:'#5F6368'}}>⋆</span>
        </div>
        <div style={{width:28,height:28,borderRadius:100,display:'flex',alignItems:'center',justifyContent:'center',color:'#5F6368'}}>
          <div style={{width:18,height:18,borderRadius:100,background:'linear-gradient(135deg,#0085FF,#56E16A)',color:'#fff',fontSize:10,fontWeight:700,display:'flex',alignItems:'center',justifyContent:'center'}}>M</div>
        </div>
      </div>
    </div>
  );
}

// Windows 11 File Explorer chrome — for showing local folders
function WindowsExplorerChrome({ path="Documentos ▸ Facturas recibidas ▸ Noviembre" }){
  return (
    <div>
      {/* Title bar with window controls */}
      <div style={{height:32,background:'#F3F3F3',display:'flex',alignItems:'center',padding:'0 0 0 12px',borderBottom:'1px solid #E5E5E5'}}>
        <div style={{display:'flex',alignItems:'center',gap:8,fontSize:11,color:'#1F1F1F'}}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <path d="M3 7 L3 18 C3 19 4 20 5 20 L19 20 C20 20 21 19 21 18 L21 9 C21 8 20 7 19 7 L12 7 L10 5 L5 5 C4 5 3 6 3 7 Z" fill="#FFCB53" stroke="#E0A829" strokeWidth="0.8"/>
          </svg>
          <span style={{fontWeight:500}}>Explorador de archivos</span>
        </div>
        <div style={{flex:1}}/>
        <div style={{display:'flex',alignSelf:'stretch'}}>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><path d="M0 5 H10" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><rect x="0.5" y="0.5" width="9" height="9" fill="none" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
          <div style={{width:46,display:'flex',alignItems:'center',justifyContent:'center'}}>
            <svg width="10" height="10" viewBox="0 0 10 10"><path d="M0 0 L10 10 M10 0 L0 10" stroke="#1F1F1F" strokeWidth="1"/></svg>
          </div>
        </div>
      </div>
      {/* Ribbon-lite toolbar */}
      <div style={{height:36,background:'#F9F9F9',display:'flex',alignItems:'center',padding:'0 10px',gap:12,borderBottom:'1px solid #E5E5E5',fontSize:11,color:'#1F1F1F'}}>
        <span style={{display:'flex',alignItems:'center',gap:4,cursor:'pointer'}}><span style={{fontSize:13}}>+</span>Nuevo</span>
        <span style={{width:1,height:16,background:'#E5E5E5'}}/>
        <span style={{cursor:'pointer',opacity:0.8}}>✂</span>
        <span style={{cursor:'pointer',opacity:0.8}}>▤</span>
        <span style={{cursor:'pointer',opacity:0.8}}>▦</span>
        <span style={{cursor:'pointer',opacity:0.5}}>✏</span>
        <span style={{cursor:'pointer',opacity:0.5}}>🗑</span>
        <div style={{flex:1}}/>
        <span style={{cursor:'pointer',fontSize:10,color:'#5F6368'}}>Ordenar ∨</span>
        <span style={{cursor:'pointer',fontSize:10,color:'#5F6368'}}>Ver ∨</span>
      </div>
      {/* Address bar */}
      <div style={{height:36,background:'#F9F9F9',display:'flex',alignItems:'center',padding:'0 10px',gap:6,borderBottom:'1px solid #E5E5E5'}}>
        <div style={{display:'flex',gap:2}}>
          <span style={{width:22,height:22,display:'flex',alignItems:'center',justifyContent:'center',fontSize:11,color:'#1F1F1F',cursor:'pointer'}}>←</span>
          <span style={{width:22,height:22,display:'flex',alignItems:'center',justifyContent:'center',fontSize:11,color:'#BDC1C6'}}>→</span>
          <span style={{width:22,height:22,display:'flex',alignItems:'center',justifyContent:'center',fontSize:11,color:'#1F1F1F',cursor:'pointer'}}>↑</span>
        </div>
        <div style={{flex:1,height:24,background:'#fff',border:'1px solid #E0E0E0',borderRadius:4,display:'flex',alignItems:'center',padding:'0 8px',fontSize:11,color:'#1F1F1F',gap:4}}>
          <span style={{color:'#5F6368'}}>📁</span>
          <span>{path}</span>
        </div>
        <div style={{width:140,height:24,background:'#fff',border:'1px solid #E0E0E0',borderRadius:4,display:'flex',alignItems:'center',padding:'0 8px',fontSize:11,color:'#9AA0A6'}}>
          <span style={{marginRight:4}}>🔍</span>Buscar
        </div>
      </div>
    </div>
  );
}

// Dinaup app header (logo + avatar + rueda)
function DinaupAppHeader({ title, breadcrumb }){
  return (
    <div style={{position:'relative'}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',padding:'14px 24px',background:'#fff',borderBottom:'1px solid #E2E8F0'}}>
        <div style={{display:'flex',alignItems:'center',gap:14}}>
          <DinaupLogo size={22}/>
          {breadcrumb && <div style={{display:'flex',alignItems:'center',gap:8,fontSize:13,color:'#64748B'}}>
            <span style={{opacity:0.5}}>/</span>
            {breadcrumb.map((b,i)=>(<React.Fragment key={i}>
              <span style={{color:i===breadcrumb.length-1?'#0F172A':'#64748B',fontWeight:i===breadcrumb.length-1?600:400}}>{b}</span>
              {i<breadcrumb.length-1 && <span style={{opacity:0.5}}>/</span>}
            </React.Fragment>))}
          </div>}
        </div>
        <div style={{display:'flex',alignItems:'center',gap:16}}>
          <div style={{display:'flex',alignItems:'center',gap:6,fontSize:12,color:'#64748B'}}>
            <span>Panadería El Molino, S.L.</span>
            <span style={{color:'#CBD5E1'}}>▾</span>
          </div>
          <div style={{width:34,height:34,borderRadius:100,background:'linear-gradient(135deg,#0085FF,#56E16A)',color:'#fff',display:'flex',alignItems:'center',justifyContent:'center',fontWeight:700,fontSize:13,fontFamily:"'IBM Plex Sans',sans-serif"}}>MJ</div>
        </div>
      </div>
      <RuedaDivider/>
    </div>
  );
}

// Cinematic cursor (Windows-style arrow)
function CineCursor({ x, y, clicking=false, scale=1 }){
  return (
    <div className="cine-cursor" style={{left:0,top:0,transform:`translate(${x}px, ${y}px) scale(${scale})`}}>
      <svg width="22" height="28" viewBox="0 0 22 28">
        <path d="M2 2 L2 22 L8 17 L11 24 L14 22 L11 16 L19 16 Z" fill="#fff" stroke="#111" strokeWidth="1.2" strokeLinejoin="round"/>
      </svg>
      {clicking && <div style={{position:'absolute',left:-16,top:-10,width:44,height:44,border:'2px solid rgba(0,133,255,0.8)',borderRadius:100,animation:'ringPulse 0.6s ease-out forwards'}}/>}
      <style>{`@keyframes ringPulse{0%{transform:scale(0.2);opacity:1}100%{transform:scale(1.4);opacity:0}}`}</style>
    </div>
  );
}

// Animated cursor that follows keyframes
function ScriptedCursor({ frames, t, clickTimes=[] }){
  // frames: [{t, x, y}], t = current time
  let x=0, y=0;
  if (frames.length === 0) return null;
  if (t <= frames[0].t) { x=frames[0].x; y=frames[0].y; }
  else if (t >= frames[frames.length-1].t) { x=frames[frames.length-1].x; y=frames[frames.length-1].y; }
  else {
    for (let i=0;i<frames.length-1;i++){
      if (t>=frames[i].t && t<=frames[i+1].t){
        const p = (t-frames[i].t)/(frames[i+1].t-frames[i].t);
        const e = Easing.easeInOutCubic(p);
        x = lerp(frames[i].x, frames[i+1].x, e);
        y = lerp(frames[i].y, frames[i+1].y, e);
        // add arc if requested
        if (frames[i].arc) {
          y -= Math.sin(p*Math.PI) * frames[i].arc;
        }
        break;
      }
    }
  }
  const clicking = clickTimes.some(ct => t >= ct && t < ct + 0.6);
  return <CineCursor x={x} y={y} clicking={clicking}/>;
}

// Scan line component
function ScanLine({ y, height, progress, width, color='var(--dn-primary)' }){
  const x = progress * (width - 2);
  return (
    <div style={{position:'absolute',left:x,top:y,width:2,height,background:`linear-gradient(to bottom, transparent, ${color}, transparent)`,boxShadow:`0 0 14px ${color}`, pointerEvents:'none'}}/>
  );
}

// Count-up hook
function useCountUp(from, to, start, dur, t, ease=Easing.easeOutCubic){
  const p = clamp((t - start)/dur, 0, 1);
  return Math.round(lerp(from, to, ease(p)));
}

// Typewriter
function Typewriter({ text, start, cps=50, t, caret=false, style }){
  const elapsed = Math.max(0, t - start);
  const n = Math.min(text.length, Math.floor(elapsed * cps));
  return <span style={style}>{text.slice(0,n)}{caret && n < text.length && <span className="caret"/>}</span>;
}

// Dot particles (hero background)
function FloatingParticles({ count=12, color='rgba(0,133,255,0.35)', width=1920, height=1080 }){
  const particles = uM2(()=>{
    return Array.from({length:count}).map((_,i)=>({
      x: Math.random()*width,
      y: Math.random()*height,
      r: 2 + Math.random()*3,
      dx: (Math.random()-0.5)*0.2,
      dy: (Math.random()-0.5)*0.2,
      phase: Math.random()*Math.PI*2
    }));
  }, [count]);
  const t = useTime();
  return (
    <svg style={{position:'absolute',inset:0,pointerEvents:'none'}} width="100%" height="100%" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none">
      {particles.map((p,i)=>{
        const x = (p.x + p.dx * t * 10 + Math.sin(t*0.3 + p.phase)*20) % width;
        const y = (p.y + p.dy * t * 10 + Math.cos(t*0.3 + p.phase)*20) % height;
        const op = 0.3 + 0.3*Math.sin(t*0.5 + p.phase);
        return <circle key={i} cx={x} cy={y} r={p.r} fill={color} opacity={op}/>;
      })}
    </svg>
  );
}

// Status chip with overshoot entrance
function StatusChip({ label, color='success', start, t, icon }){
  const bg = { success:'rgba(16,185,129,0.12)', warning:'rgba(245,158,11,0.12)', danger:'rgba(239,68,68,0.12)', primary:'rgba(0,133,255,0.12)' }[color];
  const fg = { success:'#059669', warning:'#D97706', danger:'#DC2626', primary:'#0085FF' }[color];
  const brd = { success:'rgba(16,185,129,0.3)', warning:'rgba(245,158,11,0.3)', danger:'rgba(239,68,68,0.3)', primary:'rgba(0,133,255,0.3)' }[color];
  const p = clamp((t - start)/0.4, 0, 1);
  const e = Easing.easeOutBack(p);
  return (
    <span style={{display:'inline-flex',alignItems:'center',gap:5,padding:'3px 9px',background:bg,border:`1px solid ${brd}`,borderRadius:100,color:fg,fontSize:11,fontWeight:600,fontFamily:"'Open Sans',sans-serif",transform:`scale(${lerp(0.6,1,e)})`,opacity:clamp(p*1.2,0,1)}}>
      {icon && <span style={{fontSize:10}}>{icon}</span>}
      {label}
    </span>
  );
}

// Slide frame wrapper
function SlideFrame({ bg='#fff', dots=false, children }){
  return (
    <div style={{position:'absolute',inset:0,background:bg, overflow:'hidden'}}>
      {dots && <div className="dot-grid-bg" style={{position:'absolute',inset:0,maskImage:'radial-gradient(ellipse 80% 80% at 50% 50%, #000 30%, transparent 90%)',WebkitMaskImage:'radial-gradient(ellipse 80% 80% at 50% 50%, #000 30%, transparent 90%)'}}/>}
      {children}
    </div>
  );
}

// Caption bottom bar
function Caption({ children, start=0, t, style }){
  const p = clamp(((t ?? 0) - start)/0.6, 0, 1);
  return (
    <div style={{position:'absolute',left:'50%',bottom:48,transform:`translate(-50%, ${(1-p)*20}px)`,opacity:p,fontFamily:"'IBM Plex Sans',sans-serif",fontWeight:500,fontSize:22,color:'#334155',letterSpacing:'-0.01em',...style}}>
      {children}
    </div>
  );
}

// ProviderLogo — renders brand logo by name with a white tile background for legibility.
// Falls back to an initials tile if no logo is known.
function ProviderLogo({ name, size=24, style }){
  const n = (name||'').toLowerCase();
  let src = null;
  // Map known providers to their logo asset
  if (n.includes('vodafone')) src = 'assets/vodafone.svg';
  else if (n.includes('endesa')) src = 'assets/endesa.png';
  else if (n.includes('amazon')) src = 'assets/amazon.webp';
  else if (n.includes('movistar') || n.includes('telefónica') || n.includes('telefonica')) src = 'assets/movistar.webp';

  const baseStyle = {
    width:size, height:size, borderRadius:6, background:'#fff',
    display:'inline-flex',alignItems:'center',justifyContent:'center',
    flexShrink:0, overflow:'hidden',
    border:'1px solid #E2E8F0',
    ...style,
  };

  if (src){
    return (
      <div style={baseStyle}>
        <img src={src} alt={name} style={{width:'78%',height:'78%',objectFit:'contain',display:'block'}}/>
      </div>
    );
  }
  // Fallback: colored tile with initial
  const initialColors = {
    movistar:'#00C1FF', telefonica:'#0066D1', telefónica:'#0066D1',
  };
  const color = initialColors[n] || '#0085FF';
  const initial = (name||'?').charAt(0).toUpperCase();
  return (
    <div style={{...baseStyle, background:color, border:'none', color:'#fff'}}>
      <span style={{fontSize:size*0.5, fontWeight:700, fontFamily:"'IBM Plex Sans',sans-serif"}}>{initial}</span>
    </div>
  );
}

// Social caption — quick punchy subtitle for TikTok/Reels style narration.
// Usage: <SocialCaption t={t} cues={[{from:0.5,to:2.5,text:'click en Vodafone'}]}/>
// Always sits bottom-center, big white text on semi-opaque dark pill.
function SocialCaption({ t, cues=[], position='bottom', offset=120 }){
  const active = cues.find(c => t >= c.from && t < c.to);
  if (!active) return null;
  const inP  = clamp((t - active.from) / 0.18, 0, 1);
  const outP = clamp((active.to - t) / 0.18, 0, 1);
  const p = Math.min(inP, outP);
  const e = Easing.easeOutCubic(p);
  const yBase = position === 'top' ? offset : undefined;
  const posStyle = position === 'top'
    ? { top: yBase, bottom:'auto' }
    : { bottom: offset, top:'auto' };
  return (
    <div style={{
      position:'absolute',
      left:'50%',
      ...posStyle,
      transform:`translate(-50%, ${(1-e)*14}px) scale(${lerp(0.96,1,e)})`,
      opacity: e,
      pointerEvents:'none',
      zIndex: 60,
      maxWidth: '80%',
    }}>
      <div style={{
        display:'inline-flex',alignItems:'center',gap:10,
        padding:'14px 28px',
        background: active.bg || 'rgba(15,23,42,0.92)',
        color: active.fg || '#fff',
        borderRadius: 16,
        fontFamily:"'IBM Plex Sans',sans-serif",
        fontWeight: 700,
        fontSize: active.size || 30,
        letterSpacing:'-0.015em',
        lineHeight: 1.2,
        textAlign:'center',
        backdropFilter:'blur(12px)',
        WebkitBackdropFilter:'blur(12px)',
        border:'1px solid rgba(255,255,255,0.12)',
        boxShadow:'0 10px 40px rgba(0,0,0,0.35), 0 0 0 1px rgba(0,0,0,0.4)',
        whiteSpace:'nowrap',
      }}>
        {active.emoji && <span style={{fontSize:active.size ? active.size*0.9 : 26}}>{active.emoji}</span>}
        <span>{active.text}</span>
      </div>
    </div>
  );
}

// =====================================================================
// IntroDolorHeader — cabecera común de las slides A (PROBLEMA):
// badge "PROBLEMA" rojo + eyebrow contextual + h1 con quiebre.
// Va junto a un fondo problem con glow rojo sutil (variant="problem" en SlideCanvas).
// =====================================================================
function IntroDolorHeader({ t, eyebrow, titleTop, titleBottom, topOffset=80 }){
  const badgeP = clamp(t/0.6, 0, 1);
  const badgeE = Easing.easeOutBack(badgeP);
  const eyeP = clamp((t-0.2)/0.8, 0, 1);
  const hP   = clamp((t-0.5)/1.1, 0, 1);
  const hE   = Easing.easeOutCubic(hP);
  return (
    <>
      {/* Badge PROBLEMA */}
      <div style={{position:'absolute', top:topOffset, left:0, right:0, textAlign:'center', opacity:clamp(badgeP*1.3,0,1), transform:`scale(${lerp(0.7,1,badgeE)})`}}>
        <span className="f-mono" style={{
          display:'inline-flex', alignItems:'center', gap:7,
          fontSize:11, fontWeight:700, letterSpacing:'3px', color:'#DC2626',
          padding:'6px 14px',
          background:'#FEF2F2',
          borderRadius:100,
          border:'1px solid #FECACA',
          boxShadow:'0 4px 12px rgba(239,68,68,0.18)',
        }}>
          <span style={{width:6, height:6, borderRadius:100, background:'#EF4444', boxShadow:'0 0 0 3px rgba(239,68,68,0.2)'}}/>
          PROBLEMA
        </span>
      </div>
      {/* Eyebrow contextual */}
      <div style={{position:'absolute', top:topOffset+50, left:0, right:0, textAlign:'center', opacity:eyeP, transform:`translateY(${(1-eyeP)*-8}px)`}}>
        <span className="f-mono" style={{fontSize:12, fontWeight:600, letterSpacing:'2.5px', color:'#94A3B8'}}>
          {eyebrow}
        </span>
      </div>
      <div style={{position:'absolute', top:topOffset+110, left:0, right:0, textAlign:'center', opacity:hE, transform:`translateY(${(1-hE)*16}px)`}}>
        <h1 className="f-plex" style={{fontSize:68, fontWeight:700, letterSpacing:'-0.035em', color:'#0F172A', lineHeight:1.05, margin:0}}>
          {titleTop}
          {titleBottom && (<><br/><span style={{color:'#64748B', fontWeight:500}}>{titleBottom}</span></>)}
        </h1>
      </div>
    </>
  );
}

// =====================================================================
// IntroBridge — copy "puente" inferior que aparece al final de las A.
// Se compone con dos trozos: leading (negrita oscura) + trailing (gris).
// =====================================================================
function IntroBridge({ t, start=4.0, top=860, lead, tail }){
  const p = clamp((t-start)/0.9, 0, 1);
  const e = Easing.easeOutCubic(p);
  return (
    <div style={{position:'absolute', top, left:0, right:0, textAlign:'center', opacity:e, transform:`translateY(${(1-e)*12}px)`}}>
      <div className="f-plex" style={{fontSize:26, fontWeight:500, letterSpacing:'-0.02em', color:'#334155', lineHeight:1.3}}>
        {lead && <span style={{color:'#0F172A', fontWeight:700}}>{lead}</span>}
        {lead && tail ? ' ' : null}
        {tail && <span style={{color:'#64748B'}}>{tail}</span>}
      </div>
    </div>
  );
}

// =====================================================================
// IntroPromesa — slide B completa (PROMESA) de cada sección.
// Badge "PROMESA" verde + cue contextual + h2 bicolor (plano + grad-text).
// Variant="promise" en SlideCanvas → glow verde sutil de fondo.
// =====================================================================
function IntroPromesa({ t, cueTop='Y ahora mira.', titleTop, titleBottom, subtitle, cueBottom='Mira', titleSize=68, titleTopOffset=380, subtitleTopOffset=640 }){
  const badgeP = clamp(t/0.6, 0, 1);
  const badgeE = Easing.easeOutBack(badgeP);
  const eyeP = clamp((t-0.2)/0.6, 0, 1);
  const h2P  = clamp((t-0.5)/1.1, 0, 1);
  const h2e  = Easing.easeOutCubic(h2P);
  const subP = clamp((t-1.8)/0.9, 0, 1);
  const subE = Easing.easeOutCubic(subP);
  const cueP = clamp((t-3.5)/0.6, 0, 1);
  const cueE = Easing.easeOutCubic(cueP);
  return (
    <SlideCanvas variant="promise">
      {/* Badge PROMESA */}
      <div style={{position:'absolute', top:170, left:0, right:0, textAlign:'center', opacity:clamp(badgeP*1.3,0,1), transform:`scale(${lerp(0.7,1,badgeE)})`}}>
        <span className="f-mono" style={{
          display:'inline-flex', alignItems:'center', gap:7,
          fontSize:11, fontWeight:700, letterSpacing:'3px', color:'#059669',
          padding:'6px 14px',
          background:'#ECFDF5',
          borderRadius:100,
          border:'1px solid #A7F3D0',
          boxShadow:'0 4px 12px rgba(16,185,129,0.18)',
        }}>
          <span style={{width:6, height:6, borderRadius:100, background:'#10B981', boxShadow:'0 0 0 3px rgba(16,185,129,0.25)'}}/>
          PROMESA
        </span>
      </div>
      {/* Cue contextual */}
      <div style={{position:'absolute', top:titleTopOffset-60, left:0, right:0, textAlign:'center', opacity:eyeP}}>
        <div className="f-plex" style={{fontSize:18, fontWeight:600, letterSpacing:'2px', color:'#0085FF', textTransform:'uppercase'}}>
          {cueTop}
        </div>
      </div>
      <div style={{position:'absolute', top:titleTopOffset, left:0, right:0, textAlign:'center', opacity:h2e, transform:`translateY(${(1-h2e)*16}px)`}}>
        <h2 className="f-plex" style={{fontSize:titleSize, fontWeight:700, letterSpacing:'-0.03em', lineHeight:1.08, margin:0}}>
          <span style={{color:'#0F172A'}}>{titleTop}</span>{titleBottom && (<><br/><span className="grad-text">{titleBottom}</span></>)}
        </h2>
      </div>
      {subtitle && (
        <div style={{position:'absolute', top:subtitleTopOffset, left:0, right:0, textAlign:'center', opacity:subE, transform:`translateY(${(1-subE)*10}px)`}}>
          <div className="f-plex" style={{fontSize:24, fontWeight:400, color:'#64748B', letterSpacing:'-0.01em', lineHeight:1.4}}>
            {subtitle}
          </div>
        </div>
      )}
      <div style={{position:'absolute', bottom:80, left:0, right:0, textAlign:'center', opacity:cueE}}>
        <div className="f-plex" style={{fontSize:14, fontWeight:600, letterSpacing:'3px', color:'#94A3B8', textTransform:'uppercase', display:'inline-flex', alignItems:'center', gap:10}}>
          {cueBottom}
          <span style={{display:'inline-block', animation:'introArrow 1.4s ease-in-out infinite'}}>↓</span>
        </div>
      </div>
    </SlideCanvas>
  );
}

Object.assign(window, { DinaupLogo, RuedaDivider, BrowserChrome, WindowsExplorerChrome, DinaupAppHeader, CineCursor, ScriptedCursor, ScanLine, useCountUp, Typewriter, FloatingParticles, StatusChip, SlideFrame, Caption, SocialCaption, ProviderLogo, IntroDolorHeader, IntroBridge, IntroPromesa });

// =====================================================================
// SlideCanvas — preset de fondo + dot-grid, para no duplicar el <div> de
// background y dot-grid en cada slide. Uso:
//   <SlideCanvas variant="dark">   // fondo oscuro para mockups con chrome
//   <SlideCanvas variant="light">  // fondo claro con dot-grid
//   <SlideCanvas variant="hero">   // gradiente + partículas (portada)
// Cualquier variante extra se pasa por bg, grid, particles.
// =====================================================================
function SlideCanvas({ variant='light', children, bg, grid=true, particles=0, gridMask=true }){
  const presets = {
    light: {
      bg: 'linear-gradient(180deg,#fff,#F0F7FF)',
      gridOpacity: 0.4,
    },
    'light-soft': {
      bg: 'linear-gradient(180deg,#fff,#F8FAFC)',
      gridOpacity: 0.35,
    },
    problem: {
      bg: `radial-gradient(ellipse 70% 55% at 50% 25%, rgba(239,68,68,0.10), transparent 60%),
           radial-gradient(ellipse 80% 50% at 50% 100%, rgba(239,68,68,0.06), transparent 65%),
           linear-gradient(180deg,#FEFAFA 0%,#FDF2F2 100%)`,
      gridOpacity: 0.25,
    },
    promise: {
      bg: `radial-gradient(ellipse 70% 55% at 50% 25%, rgba(16,185,129,0.10), transparent 60%),
           radial-gradient(ellipse 80% 50% at 50% 100%, rgba(0,133,255,0.07), transparent 65%),
           linear-gradient(180deg,#FAFFFD 0%,#F0FDF6 100%)`,
      gridOpacity: 0.28,
    },
    dark: {
      bg: '#0F172A',
      gridOpacity: 0,
    },
    'dark-gradient': {
      bg: 'linear-gradient(180deg,#0F172A,#1E293B)',
      gridOpacity: 0,
    },
    'dark-deep': {
      bg: 'linear-gradient(180deg,#0B1729 0%, #0F172A 100%)',
      gridOpacity: 0.35,
      gridDark: true,
    },
    hero: {
      bg: `radial-gradient(ellipse 70% 50% at 20% 20%,rgba(0,133,255,0.10),transparent 60%),
           radial-gradient(ellipse 60% 40% at 85% 90%,rgba(86,225,106,0.07),transparent 60%),
           linear-gradient(180deg,#fff 0%,#F0F7FF 100%)`,
      gridOpacity: 0,
    },
  };
  const p = presets[variant] || presets.light;
  const finalBg = bg || p.bg;
  const gridOp = p.gridOpacity;
  const maskStyle = gridMask ? {
    maskImage:'radial-gradient(ellipse 80% 80% at 50% 50%, #000 30%, transparent 90%)',
    WebkitMaskImage:'radial-gradient(ellipse 80% 80% at 50% 50%, #000 30%, transparent 90%)',
  } : {};
  return (
    <SlideFrame>
      <div style={{position:'absolute',inset:0,background:finalBg}}/>
      {grid && gridOp > 0 && (
        <div className="dot-grid-bg" style={{position:'absolute',inset:0,opacity:gridOp,...maskStyle}}/>
      )}
      {particles > 0 && <FloatingParticles count={particles}/>}
      {children}
    </SlideFrame>
  );
}

// =====================================================================
// useScriptedCursor — hook para cursores tipo "confirma fila una a una"
// donde cada click va a la misma X pero distintas Y (o viceversa).
// Devuelve {x,y,visible,clicking} para cada momento t.
//
// Uso:
//   const cur = useScriptedCursor({
//     t, clicks:[1.6,2.6,3.6,4.6,5.6],
//     targetX: 1450,
//     getTargetY: (i) => rowTop + i*(rowHeight+rowGap) + rowHeight/2,
//     parkStart: {x:1700, y:950, t:0.8},
//   });
// =====================================================================
function useScriptedCursor({ t, clicks=[], targetX, getTargetY, parkStart={x:1700,y:950,t:0.8}, clickDuration=0.25, clickRippleDuration=0.15 }){
  if (t < parkStart.t) return { x: parkStart.x, y: parkStart.y, visible:false, clicking:false };

  for (let i = 0; i < clicks.length; i++){
    const ct = clicks[i];
    const targetY = getTargetY(i);
    if (t < ct){
      const prevCt = i === 0 ? parkStart.t : clicks[i-1] + clickDuration;
      const prevY  = i === 0 ? parkStart.y : getTargetY(i-1);
      const prevX  = i === 0 ? parkStart.x : targetX;
      const p = clamp((t - prevCt) / (ct - prevCt), 0, 1);
      const e = Easing.easeInOutCubic(p);
      return { x: lerp(prevX, targetX, e), y: lerp(prevY, targetY, e), visible:true, clicking:false };
    }
    if (t < ct + clickDuration){
      return { x: targetX, y: targetY, visible:true, clicking: t < ct + clickRippleDuration };
    }
  }
  const lastIdx = clicks.length - 1;
  return {
    x: targetX,
    y: getTargetY(lastIdx),
    visible: true,
    clicking: false,
  };
}

Object.assign(window, { SlideCanvas, useScriptedCursor });
