import React from "react";
import ReactDOM from "react-dom/client";
import { useState, useEffect, useRef, useCallback } from "react";
import {
  Play, Pause, RotateCcw, Edit3, Save, ChevronRight,
  Plus, Trash2, CheckCircle, XCircle, GitBranch,
  BookOpen, X, AlertCircle,
  MessageSquare, Phone, Bot, LogIn, Eye, EyeOff,
  Lock, User, Volume2, Mic, Send,
  PhoneCall, PhoneOff, Radio, Wifi, Signal, Delete, Smile,
  Upload, Image, ArrowRight, Download, FlaskConical,
  BarChart2, MicOff, GitCompare
} from "lucide-react";

const FL=document.createElement("link");FL.rel="stylesheet";FL.href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&display=swap";document.head.appendChild(FL);

const DS={
  font:"'Montserrat',sans-serif",
  color:{
    deepBlue:"#001A7B",midBlue:"#3048B1",brightBlue:"#0BBBEF",
    cyan50:"#DDF4FC",cyan100:"#A9E1F8",cyan200:"#6DCDF3",
    purple:"#A259FE",purple100:"#D9BCFD",green:"#09CF82",
    neutral100:"#F6F6F6",neutral200:"#F0F0F0",neutral300:"#E5DEE7",neutral400:"#ADAEAF",neutral700:"#655F67",white:"#FFFFFF",
    success:"#35C759",successLight:"#C0EBC5",
    error:"#F5434E",errorLight:"#FFCAD2",
    warning:"#FFC700",warningLight:"#FFEBAF",
    info:"#2445F2",infoLight:"#C7C9FC",
    waDark:"#075E54",waPanel:"#128C7E",waLight:"#25D366",waBubbleOut:"#DCF8C6",waBubbleIn:"#FFFFFF",
  },
  radius:{xs:4,sm:8,md:12,lg:16,xl:20,full:999},
  space:{xs:8,sm:12,md:16,lg:24,xl:32},
  shadow:{A1:"0 1px 3px rgba(0,26,123,0.08)",A2:"0 4px 12px rgba(0,26,123,0.12)",B1:"0 8px 24px rgba(0,26,123,0.14)",B2:"0 16px 40px rgba(0,26,123,0.18)"},
};

const TYPE_THEME={
  IVR:{gradient:`linear-gradient(135deg,${DS.color.deepBlue},${DS.color.midBlue},${DS.color.brightBlue})`,panelBg:DS.color.cyan50,lcdBg:DS.color.white,lcdBorder:DS.color.cyan200,keyBg:"rgba(11,187,239,0.07)",keyBorder:DS.color.cyan200,keyText:DS.color.deepBlue,keySubText:DS.color.midBlue,accent:DS.color.brightBlue,accentDark:DS.color.midBlue,logBg:DS.color.cyan50,logText:DS.color.deepBlue,validText:DS.color.midBlue,lcdText:DS.color.deepBlue,lcdSub:DS.color.midBlue,desc:"IVR"},
  Chatbot:{gradient:`linear-gradient(135deg,${DS.color.deepBlue},${DS.color.midBlue})`,accent:DS.color.brightBlue,accentDark:DS.color.midBlue,desc:"Chatbot"},
  Voicebot:{gradient:`linear-gradient(135deg,${DS.color.deepBlue},${DS.color.purple})`,panelBg:"#F5F3FF",lcdBg:DS.color.white,lcdBorder:DS.color.purple100,keyBg:"rgba(162,89,254,0.07)",keyBorder:DS.color.purple100,keyText:DS.color.deepBlue,keySubText:DS.color.purple,accent:DS.color.purple,accentDark:"#7B2FE5",optBg:"rgba(162,89,254,0.07)",optBorder:DS.color.purple100,labelText:DS.color.deepBlue,msgText:"#4A1D96",logBg:"rgba(162,89,254,0.05)",logText:DS.color.deepBlue,desc:"Voicebot"},
  WhatsApp:{gradient:`linear-gradient(135deg,${DS.color.waDark},${DS.color.waPanel},${DS.color.waLight})`,accent:DS.color.waLight,accentDark:DS.color.waPanel,desc:"WhatsApp"},
};

const NODE_ST={
  start:    {bg:DS.color.cyan50,       border:DS.color.brightBlue,text:DS.color.deepBlue},
  action:   {bg:"#EEF2FF",             border:DS.color.midBlue,   text:DS.color.deepBlue},
  decision:{bg:DS.color.warningLight, border:DS.color.warning,   text:"#7A4F00"},
  end_call: {bg:DS.color.successLight, border:DS.color.success,   text:"#1A4D2E"},
  transfer: {bg:"#F5F3FF",             border:DS.color.purple,    text:"#4C1D95"},
  error:   {bg:DS.color.errorLight,   border:DS.color.error,     text:"#7F1D1D"},
};
const NODE_LABELS={
  start:"Inicio",action:"Acción",decision:"Decisión",end_call:"Finalizar llamada",transfer:"Transferir",error:"Error",
};
// Un nodo "terminal": cierra el flujo (finalizar llamada o transferir a un agente)
const isTerminalType=t=>t==="end_call"||t==="transfer";

let _voices=[];
const loadVoices=()=>{if(window.speechSynthesis)_voices=window.speechSynthesis.getVoices();};
if(window.speechSynthesis){loadVoices();window.speechSynthesis.addEventListener("voiceschanged",loadVoices);}
// Lista de voces en español disponibles en ESTE navegador/sistema (nombres reales, sin adivinar género).
function getSpanishVoices(){
  const all=_voices.length?_voices:(window.speechSynthesis?.getVoices()||[]);
  const es=all.filter(v=>v.lang&&v.lang.toLowerCase().startsWith("es"));
  return (es.length?es:all).slice().sort((a,b)=>a.name.localeCompare(b.name));
}
// Busca la voz elegida por su nombre exacto; si no existe (o no se ha elegido ninguna), usa la primera voz en español disponible.
function getVoice(name){
  const list=getSpanishVoices();
  if(!list.length)return null;
  if(name){const found=list.find(v=>v.name===name);if(found)return found;}
  return list[0];
}
function speak(text,voiceName,onEnd){if(!window.speechSynthesis)return;window.speechSynthesis.cancel();const u=new SpeechSynthesisUtterance(text);const v=getVoice(voiceName);u.lang=v?.lang||"es-ES";u.pitch=1;u.rate=1;u.volume=1;if(v)u.voice=v;if(onEnd)u.onend=onEnd;setTimeout(()=>window.speechSynthesis.speak(u),80);}

const USERS=[
  {id:1,name:"Admin Principal",role:"admin",     initials:"AP",color:DS.color.deepBlue,username:"admin",    password:"dsxp2026",photo:"data:image/png;base64,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"},
  {id:2,name:"Diseñadora UX",  role:"designer",  initials:"DX",color:DS.color.green,   username:"ux",       password:"ux123"},
  {id:3,name:"Tester 1",       role:"tester",    initials:"T1",color:DS.color.error,   username:"tester1",  password:"test1"},
  {id:4,name:"Tester 2",       role:"tester",    initials:"T2",color:DS.color.purple,  username:"tester2",  password:"test2"},
  {id:5,name:"Operador IVR",   role:"operator",  initials:"OP",color:DS.color.midBlue, username:"operador", password:"ivr123"},
  {id:6,name:"Supervisor QA",  role:"supervisor",initials:"SQ",color:DS.color.warning, username:"supervisor",password:"qa2024"},
];

function useTimer(){const[t,setT]=useState(0);const[on,setOn]=useState(false);const ref=useRef();useEffect(()=>{if(on)ref.current=setInterval(()=>setT(x=>x+1),1000);else clearInterval(ref.current);return()=>clearInterval(ref.current);},[on]);const fmt=s=>`${String(Math.floor(s/60)).padStart(2,"0")}:${String(s%60).padStart(2,"0")}`;return{fmt:fmt(t),t,running:on,start:()=>setOn(true),pause:()=>setOn(false),reset:()=>{setOn(false);setT(0);}};}
const normOpts=opts=>(opts||[]).map(o=>typeof o==="string"?{label:o,next:""}:o);
// Resuelve a qué nodo saltar según la ruta configurada en la opción elegida.
// Si la opción no tiene "next" configurado (o no existe ya en el árbol), cae al siguiente nodo en secuencia.
function resolveNextStep(nodes,currentStep,options,choiceLabel){
  const opt=(options||[]).find(o=>o.label===choiceLabel);
  if(opt&&opt.next){
    const idx=nodes.findIndex(n=>n.id===opt.next);
    if(idx>=0)return idx;
  }
  return currentStep+1;
}
function dlJSON(data,fn){const b=new Blob([JSON.stringify(data,null,2)],{type:"application/json"});const u=URL.createObjectURL(b);const a=document.createElement("a");a.href=u;a.download=fn;a.click();URL.revokeObjectURL(u);}
function dlCSV(rows,fn){const h=Object.keys(rows[0]||{});const csv=[h.join(","),...rows.map(r=>h.map(k=>`"${(r[k]||"").toString().replace(/"/g,'""')}"`).join(","))].join("\n");const b=new Blob(["\uFEFF"+csv],{type:"text/csv;charset=utf-8"});const u=URL.createObjectURL(b);const a=document.createElement("a");a.href=u;a.download=fn;a.click();URL.revokeObjectURL(u);}

/* ─── ATOMS ────────────────────────────────────────────────────────────────── */
function Btn({children,variant="filled",onClick,disabled,full,style={}}){
  const base={fontFamily:DS.font,fontWeight:600,borderRadius:DS.radius.full,cursor:disabled?"default":"pointer",display:"flex",alignItems:"center",justifyContent:"center",gap:6,border:"none",transition:"all 0.15s",fontSize:13,padding:"9px 20px",width:full?"100%":undefined,...style};
  const v={
    filled:{background:`linear-gradient(135deg,${DS.color.midBlue},${DS.color.deepBlue})`,color:DS.color.white,boxShadow:DS.shadow.A2},
    ghost:{background:"transparent",color:DS.color.midBlue,border:`1px solid ${DS.color.cyan200}`},
    success:{background:DS.color.successLight,color:"#1A4D2E",border:`1px solid ${DS.color.success}`},
    danger:{background:DS.color.errorLight,color:DS.color.error,border:`1px solid ${DS.color.error}`},
  }[variant]||{};
  return <button onClick={onClick} disabled={disabled} style={{...base,...v,opacity:disabled?0.5:1}}>{children}</button>;
}
function Tag({label,color=DS.color.brightBlue}){return <span style={{fontSize:10,padding:"2px 8px",borderRadius:DS.radius.full,border:`1px solid ${color}`,color,fontFamily:DS.font,fontWeight:600,whiteSpace:"nowrap"}}>{label}</span>;}
function Toast({type="info",children}){const c={success:{bg:DS.color.successLight,b:DS.color.success,t:"#1A4D2E"},error:{bg:DS.color.errorLight,b:DS.color.error,t:DS.color.error},warning:{bg:DS.color.warningLight,b:DS.color.warning,t:"#7A4F00"},info:{bg:DS.color.infoLight,b:DS.color.info,t:DS.color.info}}[type];return <div style={{background:c.bg,border:`1px solid ${c.b}`,borderRadius:DS.radius.sm,padding:"7px 10px",fontSize:11,color:c.t,display:"flex",alignItems:"center",gap:5,fontFamily:DS.font,fontWeight:500,marginBottom:DS.space.xs}}><AlertCircle size={12}/>{children}</div>;}
function Overlay({onClose,children}){return <div style={{position:"fixed",inset:0,background:"rgba(0,26,123,0.5)",backdropFilter:"blur(4px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999}} onClick={e=>{if(e.target===e.currentTarget)onClose();}}>{children}</div>;}
function Card({children,style={}}){return <div style={{background:DS.color.white,border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.lg,padding:DS.space.lg,boxShadow:DS.shadow.A2,...style}}>{children}</div>;}

/* ─── AVATAR UPLOADER ─────────────────────────────────────────────────────── */
function AvatarUploader({avatar,onUpload,size=34}){
  const inp=useRef();
  return(
    <div style={{display:"flex",alignItems:"center",gap:DS.space.xs,flexShrink:0}}>
      <div style={{width:size,height:size,borderRadius:DS.radius.full,background:DS.color.neutral200,overflow:"hidden",border:`2px solid ${DS.color.neutral300}`,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}} onClick={()=>inp.current.click()}>
        {avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="av"/>:<Image size={size*0.38} style={{color:DS.color.neutral400}}/>}
      </div>
      <button onClick={()=>inp.current.click()} style={{fontSize:10,padding:"3px 8px",border:`1px dashed ${DS.color.brightBlue}`,borderRadius:DS.radius.full,background:"none",cursor:"pointer",color:DS.color.midBlue,fontFamily:DS.font,fontWeight:600,display:"flex",alignItems:"center",gap:3}}><Upload size={9}/>Foto</button>
      <input ref={inp} type="file" accept="image/*" style={{display:"none"}} onChange={e=>{const f=e.target.files?.[0];if(!f)return;const r=new FileReader();r.onload=ev=>onUpload(ev.target.result);r.readAsDataURL(f);e.target.value="";}}/>
    </div>
  );
}

/* ─── KEYPAD ─────────────────────────────────────────────────────────────── */
const KEYS=[["1","2","3"],["4","5","6"],["7","8","9"],["*","0","#"]];
const KSUB={"1":"","2":"ABC","3":"DEF","4":"GHI","5":"JKL","6":"MNO","7":"PQRS","8":"TUV","9":"WXYZ","0":"+","*":"","#":""};
function PhoneKeypad({onPress,disabled,kbg,kbd,kt,ks}){
  return(
    <div style={{display:"flex",flexDirection:"column",gap:DS.space.xs,padding:`0 ${DS.space.xs}px`}}>
      {KEYS.map((row,ri)=>(
        <div key={ri} style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:DS.space.xs}}>
          {row.map(k=>(
            <button key={k} onClick={()=>!disabled&&onPress(k)} disabled={disabled}
              style={{background:disabled?"rgba(0,0,0,0.03)":kbg,border:`1px solid ${disabled?"rgba(0,0,0,0.08)":kbd}`,borderRadius:DS.radius.md,padding:"10px 4px 8px",cursor:disabled?"default":"pointer",display:"flex",flexDirection:"column",alignItems:"center",gap:1,fontFamily:DS.font,transition:"all 0.1s"}}
              onMouseDown={e=>{if(!disabled)e.currentTarget.style.transform="scale(0.93)";}}
              onMouseUp={e=>{e.currentTarget.style.transform="scale(1)";}}
              onMouseLeave={e=>{e.currentTarget.style.transform="scale(1)";}}>
              <span style={{fontSize:22,fontWeight:300,color:disabled?"#ccc":kt,lineHeight:1}}>{k}</span>
              <span style={{fontSize:7,color:disabled?"#ddd":ks,letterSpacing:1.5}}>{KSUB[k]}</span>
            </button>
          ))}
        </div>
      ))}
    </div>
  );
}

/* ─── EDIT NODE MODAL ─────────────────────────────────────────────────────── */
function EditNodeModal({node,allNodes,onSave,onClose}){
  const[f,setF]=useState({...node,options:[...normOpts(node.options)]});
  const otherNodes=(allNodes||[]).filter(n=>n.id!==node.id);
  return(
    <Overlay onClose={onClose}>
      <Card style={{width:460,maxHeight:"85vh",overflowY:"auto"}}>
        <div style={{display:"flex",justifyContent:"space-between",marginBottom:DS.space.md}}>
          <h3 style={{margin:0,fontSize:16,fontWeight:700,color:DS.color.deepBlue}}>Editar nodo</h3>
          <button onClick={onClose} style={{background:"none",border:"none",cursor:"pointer",color:DS.color.neutral400}}><X size={16}/></button>
        </div>
        {[["Etiqueta","label","input"],["Mensaje","message","textarea"]].map(([lbl,key,t])=>(
          <div key={key} style={{marginBottom:DS.space.sm}}>
            <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:3,fontWeight:600}}>{lbl}</label>
            {t==="textarea"?<textarea value={f[key]} onChange={e=>setF(x=>({...x,[key]:e.target.value}))} rows={3} style={{width:"100%",boxSizing:"border-box",fontFamily:DS.font,fontSize:12,padding:DS.space.xs,resize:"vertical",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue}}/>:<input value={f[key]} onChange={e=>setF(x=>({...x,[key]:e.target.value}))} style={{width:"100%",boxSizing:"border-box",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:`${DS.space.xs}px`,fontFamily:DS.font}}/>}
          </div>
        ))}
        <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:3,fontWeight:600}}>Tipo</label>
        <select value={f.type} onChange={e=>setF(x=>({...x,type:e.target.value}))} style={{width:"100%",marginBottom:DS.space.sm,border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:`${DS.space.xs}px`,fontFamily:DS.font}}>
          {Object.keys(NODE_ST).map(t=><option key={t} value={t}>{NODE_LABELS[t]||t}</option>)}
        </select>
        <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:3,fontWeight:600}}>Opciones y rutas</label>
        {f.options.map((o,i)=>(
          <div key={i} style={{display:"flex",gap:DS.space.xs,marginBottom:DS.space.xs,alignItems:"center"}}>
            <input value={o.label||o} onChange={e=>setF(x=>({...x,options:x.options.map((v,j)=>j===i?{...(typeof v==="object"?v:{label:v}),label:e.target.value}:v)}))} placeholder="Texto" style={{flex:1,border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:"5px 8px",fontFamily:DS.font,fontSize:12}}/>
            <select value={o.next||""} onChange={e=>setF(x=>({...x,options:x.options.map((v,j)=>j===i?{...(typeof v==="object"?v:{label:v}),next:e.target.value}:v)}))} style={{flex:1,border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:"5px 6px",fontFamily:DS.font,fontSize:11}}>
              <option value="">(automático — siguiente en orden)</option>
              {otherNodes.map(n=><option key={n.id} value={n.id}>→ {n.label}</option>)}
            </select>
            <button onClick={()=>setF(x=>({...x,options:x.options.filter((_,j)=>j!==i)}))} style={{background:"none",border:`1px solid ${DS.color.error}`,borderRadius:DS.radius.sm,cursor:"pointer",color:DS.color.error,padding:"0 7px"}}><Trash2 size={11}/></button>
          </div>
        ))}
        <button onClick={()=>setF(x=>({...x,options:[...x.options,{label:"Nueva opción",next:""}]}))} style={{fontSize:11,padding:"4px 10px",border:`1px dashed ${DS.color.brightBlue}`,borderRadius:DS.radius.sm,background:"none",cursor:"pointer",display:"flex",alignItems:"center",gap:4,color:DS.color.midBlue,fontFamily:DS.font,fontWeight:600}}><Plus size={11}/>Agregar opción</button>
        <div style={{display:"flex",gap:DS.space.xs,marginTop:DS.space.md,justifyContent:"flex-end"}}>
          <Btn variant="ghost" onClick={onClose}>Cancelar</Btn>
          <Btn variant="success" onClick={()=>onSave({...f,options:normOpts(f.options)})}><Save size={11}/>Guardar</Btn>
        </div>
      </Card>
    </Overlay>
  );
}

/* ─── TREE VIEW ───────────────────────────────────────────────────────────── */
function TreeView({nodes,setNodes,editMode,canEdit,testName}){
  const[editing,setEditing]=useState(null);
  const[activeId,setActiveId]=useState(null);
  const activeNode=nodes.find(n=>n.id===activeId)||nodes[0]||null;

  return(
    <div style={{height:"100%",display:"flex",flexDirection:"column",background:DS.color.neutral100,fontFamily:DS.font}}>
      {editing&&<EditNodeModal node={editing} allNodes={nodes} onSave={upd=>{setNodes(p=>p.map(n=>n.id===upd.id?upd:n));setEditing(null);}} onClose={()=>setEditing(null)}/>}
      <div style={{padding:`${DS.space.xs}px ${DS.space.sm}px`,borderBottom:`1px solid ${DS.color.neutral200}`,display:"flex",alignItems:"center",gap:DS.space.xs,flexShrink:0,background:DS.color.white,flexWrap:"wrap"}}>
        {canEdit&&editMode&&<button onClick={()=>{const id=`n${Date.now()}`;setNodes(p=>[...p,{id,label:"Nuevo nodo",type:"action",message:"",options:[]}]);setActiveId(id);}} style={{fontSize:10,padding:"4px 9px",border:`1px solid ${DS.color.brightBlue}`,borderRadius:DS.radius.sm,background:DS.color.cyan50,cursor:"pointer",color:DS.color.midBlue,display:"flex",alignItems:"center",gap:3,fontFamily:DS.font,fontWeight:600}}><Plus size={10}/>Nodo</button>}
      </div>
      <div style={{flex:1,overflow:"hidden",display:"flex"}}>
        <div style={{width:165,flexShrink:0,overflowY:"auto",borderRight:`1px solid ${DS.color.neutral200}`,padding:DS.space.xs,background:DS.color.white}}>
          {nodes.map((nd,i)=>{
            const s=NODE_ST[nd.type]||NODE_ST.action;const isA=nd.id===activeId||(activeId===null&&i===0);
            return(
              <div key={nd.id} onClick={()=>setActiveId(nd.id)} style={{display:"flex",alignItems:"center",gap:5,padding:"6px 8px",borderRadius:DS.radius.sm,background:isA?s.bg:"none",border:isA?`1.5px solid ${s.border}`:"1px solid transparent",cursor:"pointer",marginBottom:3}}>
                <div style={{width:16,height:16,borderRadius:DS.radius.full,background:s.bg,border:`2px solid ${s.border}`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:8,fontWeight:700,color:s.text,flexShrink:0}}>{i+1}</div>
                <div style={{flex:1,overflow:"hidden"}}><div style={{fontSize:11,fontWeight:isA?700:500,color:isA?s.text:DS.color.neutral700,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{nd.label}</div><div style={{fontSize:9,color:isA?s.text:DS.color.neutral400}}>{NODE_LABELS[nd.type]||nd.type}</div></div>
                {canEdit&&editMode&&<button onClick={e=>{e.stopPropagation();setEditing({...nd,options:normOpts(nd.options)});}} style={{background:"none",border:"none",cursor:"pointer",color:s.text,padding:2,opacity:0.7}}><Edit3 size={9}/></button>}
              </div>
            );
          })}
        </div>
        {activeNode&&(()=>{
          const nd=activeNode;const s=NODE_ST[nd.type]||NODE_ST.action;const opts=normOpts(nd.options);
          return(
            <div style={{flex:1,overflowY:"auto",padding:DS.space.md}}>
              <div style={{background:s.bg,border:`1.5px solid ${s.border}`,borderRadius:DS.radius.md,padding:DS.space.md,marginBottom:DS.space.md,boxShadow:DS.shadow.A2}}>
                <div style={{display:"flex",alignItems:"center",gap:DS.space.xs,marginBottom:DS.space.xs}}>
                  <Tag label={NODE_LABELS[nd.type]||nd.type} color={s.border}/>
                  <span style={{fontSize:13,fontWeight:700,color:s.text,flex:1}}>{nd.label}</span>
                  {canEdit&&editMode&&<>
                    <button onClick={()=>setEditing({...nd,options:normOpts(nd.options)})} style={{background:"none",border:`1px solid ${s.border}`,borderRadius:DS.radius.sm,cursor:"pointer",padding:"3px 7px",fontSize:10,color:s.text,display:"flex",alignItems:"center",gap:3,fontFamily:DS.font,fontWeight:600}}><Edit3 size={9}/>Editar</button>
                    <button onClick={()=>{setNodes(p=>p.filter(x=>x.id!==nd.id));setActiveId(nodes.find(n=>n.id!==nd.id)?.id||null);}} style={{background:"none",border:`1px solid ${DS.color.error}`,borderRadius:DS.radius.sm,cursor:"pointer",padding:"3px 7px",fontSize:10,color:DS.color.error,display:"flex",alignItems:"center",gap:3,fontFamily:DS.font,fontWeight:600}}><Trash2 size={9}/>Eliminar</button>
                  </>}
                </div>
                <p style={{fontSize:12,color:s.text,margin:0,lineHeight:1.6,opacity:0.9}}>{nd.message}</p>
              </div>
              {opts.length>0&&<div>
                <div style={{fontSize:11,color:DS.color.neutral700,fontWeight:700,marginBottom:DS.space.xs,display:"flex",alignItems:"center",gap:5}}><ArrowRight size={12} style={{color:DS.color.midBlue}}/>Rutas por opción</div>
                <div style={{display:"flex",flexDirection:"column",gap:DS.space.xs}}>
                  {opts.map((opt,i)=>{
                    const nextNode=opt.next?(nodes.find(n=>n.id===opt.next)||null):(nodes[nodes.findIndex(n=>n.id===nd.id)+1]||null);
                    const ds2=nextNode?(NODE_ST[nextNode.type]||NODE_ST.action):null;
                    return(
                      <div key={i} style={{display:"flex",alignItems:"center",gap:DS.space.xs}}>
                        <div style={{background:DS.color.white,border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,padding:"7px 12px",flex:1,display:"flex",alignItems:"center",gap:DS.space.xs,boxShadow:DS.shadow.A1}}>
                          <span style={{fontSize:12,fontWeight:600,color:DS.color.midBlue,minWidth:20}}>{i+1}.</span>
                          <span style={{fontSize:12,color:DS.color.deepBlue,flex:1}}>{typeof opt==="string"?opt:opt.label}</span>
                        </div>
                        <ChevronRight size={14} style={{color:DS.color.neutral400,flexShrink:0}}/>
                        {nextNode?(
                          <div onClick={()=>setActiveId(nextNode.id)} style={{background:ds2.bg,border:`1.5px solid ${ds2.border}`,borderRadius:DS.radius.sm,padding:"7px 12px",minWidth:110,cursor:"pointer",boxShadow:DS.shadow.A1}}>
                            <div style={{fontSize:9,color:ds2.text,fontWeight:600,opacity:0.7}}>{NODE_LABELS[nextNode.type]||nextNode.type}</div>
                            <div style={{fontSize:11,fontWeight:700,color:ds2.text}}>{nextNode.label}</div>
                          </div>
                        ):(
                          <div style={{background:DS.color.neutral200,border:`1px dashed ${DS.color.neutral400}`,borderRadius:DS.radius.sm,padding:"7px 12px",minWidth:110}}>
                            <div style={{fontSize:11,color:DS.color.neutral400}}>Fin del flujo</div>
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              </div>}
            </div>
          );
        })()}
      </div>
    </div>
  );
}

/* ─── IVR SIMULATOR ───────────────────────────────────────────────────────── */
function IVRSimulator({nodes,timer,voiceProfile,voiceOn,onComplete,minimal}){
  const th=TYPE_THEME.IVR;
  const[step,setStep]=useState(0);const[input,setInput]=useState("");const[log,setLog]=useState([]);
  const[speaking,setSpeaking]=useState(false);const[callActive,setCallActive]=useState(false);const[flash,setFlash]=useState(null);
  const node=nodes[Math.min(step,nodes.length-1)];
  const reset=useCallback(()=>{setStep(0);setInput("");setLog([]);timer.reset();window.speechSynthesis?.cancel();setSpeaking(false);setCallActive(false);setFlash(null);},[]);
  useEffect(()=>reset(),[nodes]);
  useEffect(()=>{if(voiceOn&&node&&callActive){setSpeaking(true);speak(node.message,voiceProfile,()=>setSpeaking(false));}else{window.speechSynthesis?.cancel();setSpeaking(false);}},[step,voiceOn,callActive]);
  useEffect(()=>{if(isTerminalType(node?.type)&&callActive&&onComplete)onComplete(node);},[step,callActive]);
  const advance=choice=>{setFlash(choice);setTimeout(()=>{setLog(l=>[...l,{label:node.label,choice}]);if(!timer.running)timer.start();setFlash(null);setInput("");const nx=resolveNextStep(nodes,step,normOpts(node?.options||[]),choice);if(nx<nodes.length)setStep(nx);},500);};
  const pressKey=k=>{
    const valid=normOpts(node?.options||[]).map(o=>o.label);
    if(k==="#"){if(input)advance(input);return;}
    setInput(p=>p+k);
    if(valid.includes(k))advance(k);
  };
  const pct=Math.round(((step+1)/nodes.length)*100);const vk=normOpts(node?.options||[]).map(o=>o.label);
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%",background:th.panelBg,fontFamily:DS.font}}>
      <div style={{padding:`${DS.space.sm}px ${DS.space.md}px ${DS.space.xs}px`,background:`linear-gradient(180deg,${DS.color.cyan50},transparent)`,flexShrink:0}}>
        <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:DS.space.xs}}>
          <div style={{display:"flex",alignItems:"center",gap:5}}><Signal size={10} style={{color:th.accentDark}}/><Wifi size={10} style={{color:th.accentDark}}/><span style={{fontSize:9,color:th.accentDark,letterSpacing:1.5,fontWeight:700}}>IVR SYSTEM</span></div>
          <div style={{display:"flex",alignItems:"center",gap:6}}>{speaking&&<div style={{display:"flex",gap:2,alignItems:"flex-end"}}>{[8,13,10,16,8].map((h,i)=><div key={i} style={{width:2.5,height:h,background:th.accent,borderRadius:2}}/>)}</div>}<span style={{fontFamily:"monospace",fontSize:11,color:timer.running?DS.color.success:th.lcdSub,fontWeight:700}}>{timer.fmt}</span></div>
        </div>
        {!minimal&&<>
          <div style={{background:th.lcdBg,borderRadius:DS.radius.md,padding:`${DS.space.sm}px ${DS.space.md}px`,border:`1.5px solid ${th.lcdBorder}`,boxShadow:DS.shadow.A2,minHeight:86}}>
            <div style={{fontSize:9,color:th.lcdSub,letterSpacing:2,marginBottom:DS.space.xs,fontWeight:700}}>{callActive?node?.label?.toUpperCase():"MARCANDO..."}</div>
            <p style={{fontSize:12,color:callActive?th.lcdText:DS.color.neutral400,margin:`0 0 ${DS.space.xs}px`,lineHeight:1.65,fontStyle:callActive?"italic":"normal"}}>{!callActive?"Presiona ☎ para iniciar":"🔊 Reproduciendo mensaje de voz..."}</p>
            <div style={{fontFamily:"monospace",fontSize:20,color:th.accent,letterSpacing:5,minHeight:26,textAlign:"right",fontWeight:700}}>{flash?<span style={{color:DS.color.success}}>{flash}</span>:input}</div>
          </div>
          <div style={{marginTop:DS.space.xs,height:3,background:DS.color.cyan50,borderRadius:2}}><div style={{width:`${pct}%`,height:"100%",background:th.accent,borderRadius:2,transition:"width 0.4s"}}/></div>
          {callActive&&vk.length>0&&<div style={{marginTop:3,fontSize:9,color:th.validText,textAlign:"center",fontWeight:700}}>TECLAS: {vk.join(" · ")}</div>}
          {callActive&&<div style={{marginTop:2,fontSize:9,color:th.lcdSub,textAlign:"center"}}>Para ingresar números largos, finaliza con #</div>}
        </>}
        {minimal&&!callActive&&<div style={{textAlign:"center",fontSize:12,color:DS.color.neutral400,padding:`${DS.space.sm}px 0`}}>Presiona ☎ para iniciar</div>}
        {minimal&&callActive&&<div style={{marginTop:DS.space.xs,height:3,background:DS.color.cyan50,borderRadius:2}}><div style={{width:`${pct}%`,height:"100%",background:th.accent,borderRadius:2,transition:"width 0.4s"}}/></div>}
      </div>
      <div style={{flex:1,overflowY:"auto",padding:`${DS.space.sm}px ${DS.space.sm}px ${DS.space.xs}px`,display:"flex",flexDirection:"column",gap:DS.space.xs}}>
        {!minimal&&node?.type==="end_call"&&callActive&&<Toast type="success">Llamada finalizada exitosamente</Toast>}
        {!minimal&&node?.type==="transfer"&&callActive&&<Toast type="success">Llamada transferida a un agente</Toast>}
        {!minimal&&log.length>0&&<div style={{background:th.logBg,borderRadius:DS.radius.sm,padding:`${DS.space.xs}px ${DS.space.sm}px`,border:`1px solid ${th.lcdBorder}`}}>
          <div style={{fontSize:8,color:th.logText,marginBottom:3,letterSpacing:1.5,fontWeight:700}}>REGISTRO</div>
          {log.map((e,i)=><div key={i} style={{fontSize:10,color:th.logText,display:"flex",gap:5,marginBottom:1,fontWeight:500}}><span style={{color:DS.color.success}}>▶</span>{e.label} → [{e.choice}]</div>)}
        </div>}
        <PhoneKeypad onPress={pressKey} disabled={!callActive||isTerminalType(node?.type)||node?.type==="error"} kbg={th.keyBg} kbd={th.keyBorder} kt={th.keyText} ks={th.keySubText}/>
        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:DS.space.xs,padding:`0 ${DS.space.xs}px`,marginTop:4}}>
          <button onClick={()=>setInput(p=>p.slice(0,-1))} style={{background:th.keyBg,border:`1px solid ${th.keyBorder}`,borderRadius:DS.radius.sm,padding:"10px 4px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}}><Delete size={16} style={{color:th.keyText}}/></button>
          {!callActive?<button onClick={()=>{setCallActive(true);if(!timer.running)timer.start();}} style={{background:DS.color.success,border:"none",borderRadius:DS.radius.sm,padding:"10px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 14px rgba(53,199,89,0.35)"}}><PhoneCall size={20} style={{color:"#fff"}}/></button>:<button onClick={reset} style={{background:DS.color.error,border:"none",borderRadius:DS.radius.sm,padding:"10px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 14px rgba(245,67,78,0.3)"}}><PhoneOff size={20} style={{color:"#fff"}}/></button>}
          <button onClick={timer.running?timer.pause:timer.start} style={{background:th.keyBg,border:`1px solid ${th.keyBorder}`,borderRadius:DS.radius.sm,padding:"10px 4px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}}>{timer.running?<Pause size={14} style={{color:th.keyText}}/>:<Play size={14} style={{color:th.keyText}}/>}</button>
        </div>
      </div>
    </div>
  );
}

/* ─── CHATBOT SIMULATOR ───────────────────────────────────────────────────── */
function ChatbotSim({nodes,timer,voiceProfile,voiceOn,msgs,setMsgs,step,setStep,avatar,onComplete}){
  const[speaking,setSpeaking]=useState(false);const[typing,setTyping]=useState(false);
  const[txt,setTxt]=useState("");const[waiting,setWaiting]=useState(false);
  const bottom=useRef();const inputRef=useRef();
  const node=nodes[Math.min(step,nodes.length-1)];
  useEffect(()=>{if(msgs.length===0&&node){botSay(node);}},[nodes]);
  const botSay=useCallback((n)=>{setTyping(true);setTimeout(()=>{setTyping(false);setMsgs(m=>[...m,{from:"bot",text:n.message,label:n.label,type:n.type,options:normOpts(n.options)}]);if(voiceOn){setSpeaking(true);speak(n.message,voiceProfile,()=>setSpeaking(false));}if(isTerminalType(n.type)&&onComplete)onComplete(n);setWaiting(true);setTimeout(()=>inputRef.current?.focus(),100);},800);},[voiceOn,voiceProfile,onComplete]);
  useEffect(()=>{bottom.current?.scrollIntoView({behavior:"smooth"});},[msgs,typing]);
  const send=text=>{if(!text.trim())return;setWaiting(false);setMsgs(m=>[...m,{from:"user",text}]);setTxt("");if(!timer.running)timer.start();const next=resolveNextStep(nodes,step,normOpts(node?.options||[]),text);if(next<nodes.length){setStep(next);setTimeout(()=>botSay(nodes[next]),500);}};
  const c=DS.color;const lastOpts=msgs.length>0?normOpts(msgs[msgs.length-1]?.options||[]):[];
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%",background:c.neutral100,fontFamily:DS.font}}>
      <div style={{background:`linear-gradient(135deg,${c.deepBlue},${c.midBlue})`,padding:`${DS.space.sm}px ${DS.space.md}px`,display:"flex",alignItems:"center",gap:DS.space.sm,flexShrink:0,boxShadow:DS.shadow.A2}}>
        <div style={{width:36,height:36,borderRadius:c.full,overflow:"hidden",background:"rgba(255,255,255,0.15)",border:"2px solid rgba(255,255,255,0.3)",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
          {avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="bot"/>:<Bot size={18} style={{color:c.white}}/>}
        </div>
        <div><div style={{fontSize:13,fontWeight:700,color:c.white}}>Asistente</div><div style={{fontSize:10,color:c.cyan100,display:"flex",alignItems:"center",gap:4}}><div style={{width:5,height:5,borderRadius:DS.radius.full,background:speaking?c.warning:c.green}}/>{typing?"Escribiendo...":speaking?"Hablando...":"En línea"}</div></div>
        <div style={{marginLeft:"auto",display:"flex",alignItems:"center",gap:8}}><span style={{fontFamily:"monospace",fontSize:10,color:c.cyan100}}>{timer.fmt}</span><button onClick={timer.running?timer.pause:timer.start} style={{background:"none",border:"none",cursor:"pointer",color:c.cyan100}}>{timer.running?<Pause size={12}/>:<Play size={12}/>}</button></div>
      </div>
      <div style={{flex:1,overflowY:"auto",padding:`${DS.space.md}px ${DS.space.sm}px`,display:"flex",flexDirection:"column",gap:DS.space.sm}}>
        <div style={{textAlign:"center",fontSize:10,color:c.neutral400,background:"rgba(0,0,0,0.04)",borderRadius:DS.radius.full,padding:"3px 10px",alignSelf:"center",fontWeight:500}}>Conversación iniciada</div>
        {msgs.map((m,i)=>(
          <div key={i} style={{display:"flex",justifyContent:m.from==="user"?"flex-end":"flex-start"}}>
            {m.from==="bot"&&<div style={{width:26,height:26,borderRadius:DS.radius.full,overflow:"hidden",background:c.midBlue,display:"flex",alignItems:"center",justifyContent:"center",marginRight:6,flexShrink:0,alignSelf:"flex-end"}}>{avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="b"/>:<Bot size={12} style={{color:c.white}}/>}</div>}
            <div style={{maxWidth:"78%",background:m.from==="user"?`linear-gradient(135deg,${c.midBlue},${c.deepBlue})`:c.white,color:m.from==="user"?c.white:c.deepBlue,borderRadius:m.from==="user"?`${DS.radius.md}px ${DS.radius.md}px 4px ${DS.radius.md}px`:`${DS.radius.md}px ${DS.radius.md}px ${DS.radius.md}px 4px`,padding:`${DS.space.xs}px ${DS.space.sm}px`,fontSize:12,lineHeight:1.5,boxShadow:DS.shadow.A1}}>
              {m.from==="bot"&&<div style={{fontSize:9,color:c.brightBlue,fontWeight:700,marginBottom:2}}>{m.label?.toUpperCase()}</div>}
              {m.text}{isTerminalType(m.type)&&<div style={{fontSize:10,color:c.success,marginTop:3,display:"flex",alignItems:"center",gap:3}}><CheckCircle size={11}/>✓ {m.type==="transfer"?"Transferido":"Resuelto"}</div>}
            </div>
            {m.from==="user"&&<div style={{width:26,height:26,borderRadius:DS.radius.full,background:c.deepBlue,display:"flex",alignItems:"center",justifyContent:"center",marginLeft:6,flexShrink:0,alignSelf:"flex-end",fontSize:9,color:c.white,fontWeight:700}}>U</div>}
          </div>
        ))}
        {typing&&<div style={{display:"flex",alignItems:"flex-end",gap:6}}><div style={{width:26,height:26,borderRadius:DS.radius.full,overflow:"hidden",background:c.midBlue,display:"flex",alignItems:"center",justifyContent:"center"}}>{avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="b"/>:<Bot size={12} style={{color:c.white}}/>}</div><div style={{background:c.white,borderRadius:`${DS.radius.md}px ${DS.radius.md}px ${DS.radius.md}px 4px`,padding:"10px 14px",boxShadow:DS.shadow.A1}}><div style={{display:"flex",gap:4}}>{[0,1,2].map(i=><div key={i} style={{width:7,height:7,borderRadius:DS.radius.full,background:c.neutral400}}/>)}</div></div></div>}
        <div ref={bottom}/>
      </div>
      {!typing&&waiting&&lastOpts.length>0&&<div style={{padding:`${DS.space.xs}px ${DS.space.sm}px`,background:"rgba(255,255,255,0.9)",borderTop:`1px solid ${c.neutral200}`,display:"flex",flexWrap:"wrap",gap:6}}>
        {lastOpts.map((opt,i)=><button key={i} onClick={()=>send(typeof opt==="string"?opt:opt.label)} style={{fontSize:11,padding:"5px 12px",borderRadius:DS.radius.full,border:`1.5px solid ${c.brightBlue}`,background:c.white,color:c.midBlue,cursor:"pointer",fontFamily:DS.font,fontWeight:600}}>{typeof opt==="string"?opt:opt.label}</button>)}
      </div>}
      <div style={{padding:`${DS.space.sm}px`,background:c.white,borderTop:`1px solid ${c.neutral200}`,display:"flex",gap:DS.space.xs,alignItems:"flex-end",flexShrink:0}}>
        <textarea ref={inputRef} value={txt} onChange={e=>setTxt(e.target.value)} onKeyDown={e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send(txt);}}} disabled={typing||!waiting} placeholder={typing?"Esperando...":waiting?"Escribe un mensaje...":"Iniciando..."} rows={1} style={{flex:1,resize:"none",border:`1px solid ${c.neutral300}`,borderRadius:DS.radius.xl,padding:`${DS.space.xs}px ${DS.space.sm}px`,fontSize:12,fontFamily:DS.font,background:typing?c.neutral100:c.white,color:c.deepBlue,outline:"none",maxHeight:80}}/>
        <button onClick={()=>send(txt)} disabled={!txt.trim()||typing} style={{width:36,height:36,borderRadius:DS.radius.full,background:txt.trim()&&!typing?`linear-gradient(135deg,${c.midBlue},${c.deepBlue})`:c.neutral200,border:"none",cursor:txt.trim()&&!typing?"pointer":"default",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}><Send size={14} style={{color:c.white}}/></button>
      </div>
    </div>
  );
}

/* ─── WHATSAPP SIMULATOR ──────────────────────────────────────────────────── */
const WA_SVG=`<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'><rect width='100%' height='100%' fill='%23e5ddd5'/><g fill='none' stroke='%23c8bfb5' stroke-width='0.6' opacity='0.45'>${Array.from({length:6},(_,r)=>Array.from({length:5},(_,c)=>`<circle cx='${c*80+40}' cy='${r*70+35}' r='28'/>`).join("")).join("")}</g></svg>`;
const WA_BG=`data:image/svg+xml,${WA_SVG}`;

function WhatsAppSim({nodes,timer,msgs,setMsgs,step,setStep,avatar,onComplete}){
  const c=DS.color;const[typing,setTyping]=useState(false);const[txt,setTxt]=useState("");const[waiting,setWaiting]=useState(false);
  const bottom=useRef();const inputRef=useRef();const node=nodes[Math.min(step,nodes.length-1)];
  useEffect(()=>{if(msgs.length===0&&node){botSay(node);}},[nodes]);
  const botSay=useCallback((n)=>{setTyping(true);setTimeout(()=>{setTyping(false);setMsgs(m=>[...m,{from:"bot",text:n.message,label:n.label,type:n.type,options:normOpts(n.options)}]);if(isTerminalType(n.type)&&onComplete)onComplete(n);setWaiting(true);setTimeout(()=>inputRef.current?.focus(),100);},900);},[onComplete]);
  useEffect(()=>{bottom.current?.scrollIntoView({behavior:"smooth"});},[msgs,typing]);
  const send=text=>{if(!text.trim())return;setWaiting(false);setMsgs(m=>[...m,{from:"user",text}]);setTxt("");if(!timer.running)timer.start();const next=resolveNextStep(nodes,step,normOpts(node?.options||[]),text);if(next<nodes.length){setStep(next);setTimeout(()=>botSay(nodes[next]),700);}};
  const now=new Date();const ts=`${now.getHours()}:${String(now.getMinutes()).padStart(2,"0")}`;
  const lastOpts=msgs.length>0?normOpts(msgs[msgs.length-1]?.options||[]):[];
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%",fontFamily:DS.font}}>
      <div style={{background:c.waDark,padding:`${DS.space.xs}px ${DS.space.md}px`,display:"flex",alignItems:"center",gap:DS.space.sm,flexShrink:0,boxShadow:"0 1px 3px rgba(0,0,0,0.25)"}}>
        <div style={{width:38,height:38,borderRadius:DS.radius.full,overflow:"hidden",background:c.waLight,border:"2px solid rgba(255,255,255,0.3)",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
          {avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="wa"/>:<Bot size={18} style={{color:c.white}}/>}
        </div>
        <div style={{flex:1}}><div style={{fontSize:13,fontWeight:700,color:c.white}}>Soporte Emtelco</div><div style={{fontSize:10,color:"rgba(255,255,255,0.75)",display:"flex",alignItems:"center",gap:4}}><div style={{width:5,height:5,borderRadius:DS.radius.full,background:c.waLight}}/>{typing?"escribiendo...":"en línea"}</div></div>
        <div style={{display:"flex",alignItems:"center",gap:10}}><span style={{fontFamily:"monospace",fontSize:10,color:"rgba(255,255,255,0.75)"}}>{timer.fmt}</span><button onClick={timer.running?timer.pause:timer.start} style={{background:"none",border:"none",cursor:"pointer",color:"rgba(255,255,255,0.75)"}}>{timer.running?<Pause size={12}/>:<Play size={12}/>}</button></div>
      </div>
      <div style={{flex:1,overflowY:"auto",padding:`${DS.space.sm}px`,display:"flex",flexDirection:"column",gap:DS.space.xs,backgroundImage:`url("${WA_BG}")`,backgroundSize:"400px 400px",backgroundRepeat:"repeat"}}>
        <div style={{alignSelf:"center",background:"rgba(255,255,255,0.85)",borderRadius:DS.radius.xl,padding:"3px 12px",fontSize:10,color:c.neutral700,boxShadow:DS.shadow.A1,fontWeight:500,marginBottom:4}}>HOY</div>
        {msgs.map((m,i)=>(
          <div key={i} style={{display:"flex",justifyContent:m.from==="user"?"flex-end":"flex-start",marginBottom:1}}>
            {m.from==="bot"&&<div style={{width:28,height:28,borderRadius:DS.radius.full,overflow:"hidden",background:c.waLight,display:"flex",alignItems:"center",justifyContent:"center",marginRight:5,flexShrink:0,alignSelf:"flex-end",border:"2px solid rgba(255,255,255,0.5)"}}>
              {avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="wa"/>:<Bot size={13} style={{color:c.white}}/>}
            </div>}
            <div style={{maxWidth:"75%",background:m.from==="user"?c.waBubbleOut:c.waBubbleIn,borderRadius:m.from==="user"?"12px 2px 12px 12px":"2px 12px 12px 12px",padding:"7px 10px 5px",fontSize:12,lineHeight:1.5,boxShadow:"0 1px 2px rgba(0,0,0,0.13)",color:"#111"}}>
              {m.from==="bot"&&<div style={{fontSize:9,color:c.waPanel,fontWeight:700,marginBottom:2}}>Soporte Emtelco</div>}
              <div style={{whiteSpace:"pre-line"}}>{m.text}</div>
              {isTerminalType(m.type)&&<div style={{fontSize:10,color:c.waPanel,marginTop:3,display:"flex",alignItems:"center",gap:3}}><CheckCircle size={10}/>✓ {m.type==="transfer"?"Transferido":"Resuelto"}</div>}
              <div style={{fontSize:9,color:c.neutral400,textAlign:"right",marginTop:3,display:"flex",alignItems:"center",justifyContent:"flex-end",gap:3}}>{ts}{m.from==="user"&&<span style={{color:"#53bdeb",fontSize:12}}>✓✓</span>}</div>
            </div>
          </div>
        ))}
        {typing&&<div style={{display:"flex",justifyContent:"flex-start",marginBottom:1}}>
          <div style={{width:28,height:28,borderRadius:DS.radius.full,overflow:"hidden",background:c.waLight,display:"flex",alignItems:"center",justifyContent:"center",marginRight:5,flexShrink:0,alignSelf:"flex-end"}}>{avatar?<img src={avatar} style={{width:"100%",height:"100%",objectFit:"cover"}} alt="wa"/>:<Bot size={13} style={{color:c.white}}/>}</div>
          <div style={{background:c.waBubbleIn,borderRadius:"2px 12px 12px 12px",padding:"10px 14px",boxShadow:"0 1px 2px rgba(0,0,0,0.1)"}}><div style={{display:"flex",gap:4}}>{[0,1,2].map(i=><div key={i} style={{width:7,height:7,borderRadius:DS.radius.full,background:"#aaa"}}/>)}</div></div>
        </div>}
        {!typing&&waiting&&lastOpts.length>0&&<div style={{display:"flex",flexWrap:"wrap",gap:6,justifyContent:"flex-end",marginTop:4}}>
          {lastOpts.map((opt,i)=><button key={i} onClick={()=>send(typeof opt==="string"?opt:opt.label)} style={{fontSize:11,padding:"6px 14px",borderRadius:DS.radius.full,border:`1.5px solid ${c.waPanel}`,background:c.white,color:c.waPanel,cursor:"pointer",fontFamily:DS.font,fontWeight:600,boxShadow:DS.shadow.A1}}>{typeof opt==="string"?opt:opt.label}</button>)}
        </div>}
        <div ref={bottom}/>
      </div>
      <div style={{padding:`${DS.space.xs}px ${DS.space.sm}px`,background:"#F0F0F0",borderTop:"1px solid #ddd",display:"flex",gap:DS.space.xs,alignItems:"flex-end",flexShrink:0}}>
        <div style={{width:34,height:34,borderRadius:DS.radius.full,background:c.neutral300,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}><Smile size={20} style={{color:c.neutral700}}/></div>
        <textarea value={txt} onChange={e=>setTxt(e.target.value)} ref={inputRef} onKeyDown={e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send(txt);}}} disabled={typing||!waiting} placeholder="Escribe un mensaje" rows={1} style={{flex:1,resize:"none",border:"none",borderRadius:DS.radius.xl,padding:"9px 14px",fontSize:13,fontFamily:DS.font,background:c.white,color:"#111",outline:"none",maxHeight:80,boxShadow:DS.shadow.A1}}/>
        <button onClick={()=>send(txt)} disabled={!txt.trim()||typing} style={{width:40,height:40,borderRadius:DS.radius.full,background:txt.trim()&&!typing?c.waLight:c.neutral300,border:"none",cursor:txt.trim()&&!typing?"pointer":"default",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
          {txt.trim()?<Send size={16} style={{color:c.white}}/>:<Mic size={16} style={{color:c.neutral700}}/>}
        </button>
      </div>
    </div>
  );
}

/* ─── VOICEBOT SIMULATOR (STT mejorado) ──────────────────────────────────── */
function VoicebotSim({nodes,timer,voiceProfile,voiceOn,onComplete,minimal}){
  const th=TYPE_THEME.Voicebot;
  const[step,setStep]=useState(0);const[input,setInput]=useState("");const[log,setLog]=useState([]);
  const[active,setActive]=useState(false);const[flash,setFlash]=useState(null);
  const[listening,setListening]=useState(false);const[liveText,setLiveText]=useState("");const[sttErr,setSttErr]=useState("");
  const[speaking,setSpeaking]=useState(false);
  const recRef=useRef(null);const node=nodes[Math.min(step,nodes.length-1)];
  const reset=useCallback(()=>{setStep(0);setInput("");setLog([]);timer.reset();window.speechSynthesis?.cancel();setActive(false);setFlash(null);setListening(false);setLiveText("");setSttErr("");setSpeaking(false);},[]);
  useEffect(()=>reset(),[nodes]);
  useEffect(()=>{if(isTerminalType(node?.type)&&active&&onComplete)onComplete(node);},[step,active]);
  useEffect(()=>{if(voiceOn&&node&&active){setSpeaking(true);speak(node.message,voiceProfile,()=>setSpeaking(false));}else{window.speechSynthesis?.cancel();setSpeaking(false);}},[step,voiceOn,active]);

  const pressKey=k=>{setInput(p=>p+k);const valid=normOpts(node?.options||[]).map(o=>o.label);if(valid.includes(k))doSelect(k);};
  const doSelect=k=>{setFlash(k);setTimeout(()=>{setLog(l=>[...l,{label:node.label,choice:k}]);if(!timer.running)timer.start();setFlash(null);setInput("");const nx=resolveNextStep(nodes,step,normOpts(node?.options||[]),k);if(nx<nodes.length)setStep(nx);},500);};

  const startListening=()=>{
    const SR=window.SpeechRecognition||window.webkitSpeechRecognition;
    if(!SR){setSttErr("Reconocimiento de voz no disponible. Usa Chrome en escritorio.");return;}
    setSttErr("");setLiveText("");
    const rec=new SR();rec.lang="es-ES";rec.continuous=false;rec.interimResults=true;recRef.current=rec;
    rec.onstart=()=>setListening(true);
    rec.onresult=e=>{
      const interims=Array.from(e.results).map(r=>r[0].transcript).join(" ").toLowerCase().trim();
      setLiveText(interims);
    };
    rec.onend=()=>{
      setListening(false);
      const finalT=liveText;
      const opts=normOpts(node?.options||[]);
      // Buscar coincidencia por nombre exacto o número
      const match=opts.find(o=>{
        const lbl=(o.label||"").toLowerCase();
        if(finalT.includes(lbl))return true;
        const nums={"uno":"1","dos":"2","tres":"3","cuatro":"4","cinco":"5","seis":"6","siete":"7","ocho":"8","nueve":"9","cero":"0","asterisco":"*"};
        return Object.keys(nums).some(n=>finalT.includes(n)&&nums[n]===o.label);
      });
      if(match){setSttErr("");doSelect(match.label);}
      else if(finalT)setSttErr(`No reconocí una opción válida en: "${finalT}"`);
      setLiveText("");
    };
    rec.onerror=ev=>{setListening(false);setSttErr(ev.error==="not-allowed"?"Permiso de micrófono denegado. Actívalo en el navegador.":"Error al escuchar. Intenta de nuevo.");};
    rec.start();
  };
  const stopListening=()=>{recRef.current?.stop();setListening(false);};

  const pct=Math.round(((step+1)/nodes.length)*100);const vk=normOpts(node?.options||[]).map(o=>o.label);
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%",background:th.panelBg,fontFamily:DS.font}}>
      <div style={{padding:`${DS.space.sm}px ${DS.space.md}px ${DS.space.xs}px`,background:"linear-gradient(180deg,rgba(162,89,254,0.08),transparent)",flexShrink:0}}>
        <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:DS.space.xs}}>
          <div style={{display:"flex",alignItems:"center",gap:5}}><Radio size={10} style={{color:th.accent}}/><span style={{fontSize:9,color:th.labelText,letterSpacing:1.5,fontWeight:700}}>VOICEBOT · NLU</span></div>
          <div style={{display:"flex",alignItems:"center",gap:6}}>{speaking&&<div style={{display:"flex",gap:2,alignItems:"flex-end"}}>{[8,13,10,16,8].map((h,i)=><div key={i} style={{width:2.5,height:h,background:th.accent,borderRadius:2}}/>)}</div>}<span style={{fontFamily:"monospace",fontSize:11,color:timer.running?DS.color.success:th.labelText,fontWeight:700}}>{timer.fmt}</span></div>
        </div>
        {!minimal&&<>
          <div style={{background:th.lcdBg,borderRadius:DS.radius.md,padding:`${DS.space.sm}px ${DS.space.md}px`,border:`1.5px solid ${th.lcdBorder}`,boxShadow:DS.shadow.A2,minHeight:86}}>
            <div style={{fontSize:9,color:th.labelText,letterSpacing:2,marginBottom:DS.space.xs,fontWeight:700}}>{active?node?.label?.toUpperCase():"ASISTENTE DE VOZ"}</div>
            <p style={{fontSize:12,color:active?th.msgText:DS.color.neutral400,margin:`0 0 ${DS.space.xs}px`,lineHeight:1.65,fontStyle:active?"italic":"normal"}}>{!active?"Presiona ☎ para iniciar":"🔊 Reproduciendo mensaje de voz..."}</p>
            {listening&&<div style={{fontSize:11,color:th.accent,display:"flex",alignItems:"center",gap:6,background:"rgba(162,89,254,0.08)",borderRadius:DS.radius.sm,padding:"4px 8px"}}>
              <div style={{width:8,height:8,borderRadius:DS.radius.full,background:DS.color.error,flexShrink:0}}/>
              <span style={{fontStyle:"italic",flex:1,color:th.msgText}}>{liveText||"Escuchando..."}</span>
            </div>}
            <div style={{fontFamily:"monospace",fontSize:20,color:th.accent,letterSpacing:5,minHeight:26,textAlign:"right",fontWeight:700}}>{flash?<span style={{color:DS.color.success}}>{flash}</span>:input}</div>
          </div>
          <div style={{marginTop:DS.space.xs,height:3,background:"rgba(162,89,254,0.12)",borderRadius:2}}><div style={{width:`${pct}%`,height:"100%",background:th.accent,borderRadius:2,transition:"width 0.4s"}}/></div>
          {active&&vk.length>0&&<div style={{marginTop:3,fontSize:9,color:th.labelText,textAlign:"center",fontWeight:700}}>DI O MARCA: {vk.join(" · ")}</div>}
          {sttErr&&<div style={{marginTop:4,fontSize:10,color:DS.color.error,textAlign:"center",padding:"4px 8px",background:DS.color.errorLight,borderRadius:DS.radius.xs}}>{sttErr}</div>}
        </>}
        {minimal&&!active&&<div style={{textAlign:"center",fontSize:12,color:DS.color.neutral400,padding:`${DS.space.sm}px 0`}}>Presiona el micrófono para iniciar</div>}
        {minimal&&active&&<div style={{marginTop:DS.space.xs,height:3,background:"rgba(162,89,254,0.12)",borderRadius:2}}><div style={{width:`${pct}%`,height:"100%",background:th.accent,borderRadius:2,transition:"width 0.4s"}}/></div>}
      </div>
      <div style={{flex:1,overflowY:"auto",padding:`${DS.space.sm}px ${DS.space.sm}px ${DS.space.xs}px`,display:"flex",flexDirection:"column",gap:DS.space.xs}}>
        {!minimal&&node?.type==="end_call"&&active&&<Toast type="success">Interacción completada</Toast>}
        {!minimal&&node?.type==="transfer"&&active&&<Toast type="success">Transferido a un agente</Toast>}
        {!minimal&&log.length>0&&<div style={{background:th.logBg,borderRadius:DS.radius.sm,padding:`${DS.space.xs}px ${DS.space.sm}px`,border:`1px solid ${th.lcdBorder}`}}>
          <div style={{fontSize:8,color:th.logText,marginBottom:3,letterSpacing:1.5,fontWeight:700}}>TRANSCRIPCIÓN</div>
          {log.map((e,i)=><div key={i} style={{fontSize:10,color:th.logText,display:"flex",gap:5,marginBottom:1,fontWeight:500}}><span style={{color:DS.color.success}}>▶</span>{e.label} → [{e.choice}]</div>)}
        </div>}
        <PhoneKeypad onPress={pressKey} disabled={!active||isTerminalType(node?.type)||node?.type==="error"} kbg={th.optBg} kbd={th.optBorder} kt={th.labelText} ks={th.accent}/>
        {!active?<div style={{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:DS.space.sm,paddingTop:DS.space.sm}}>
          <span style={{fontSize:11,color:th.labelText,fontWeight:500}}>Activa el asistente</span>
          <button onClick={()=>{setActive(true);if(!timer.running)timer.start();}} style={{width:56,height:56,borderRadius:DS.radius.full,background:`linear-gradient(135deg,${th.accent},${th.accentDark})`,border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 0 0 10px rgba(162,89,254,0.1)"}}><Mic size={22} style={{color:DS.color.white}}/></button>
        </div>:<div style={{display:"flex",flexDirection:"column",gap:DS.space.xs}}>
          {!minimal&&<div style={{padding:`0 ${DS.space.xs}px`}}>
            <button onClick={listening?stopListening:startListening} style={{width:"100%",padding:"10px",borderRadius:DS.radius.sm,border:`1.5px solid ${listening?DS.color.error:th.accent}`,background:listening?"rgba(245,67,78,0.1)":"rgba(162,89,254,0.1)",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",gap:6,fontFamily:DS.font,fontSize:12,fontWeight:700,color:listening?DS.color.error:th.accent}}>
              {listening?<><MicOff size={14}/>Detener escucha</>:<><Mic size={14}/>Hablar (reconocimiento de voz)</>}
            </button>
          </div>}
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:DS.space.xs,padding:`0 ${DS.space.xs}px`}}>
            <button onClick={()=>setInput(p=>p.slice(0,-1))} style={{background:th.optBg,border:`1px solid ${th.optBorder}`,borderRadius:DS.radius.sm,padding:"10px 4px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}}><Delete size={16} style={{color:th.labelText}}/></button>
            <button onClick={reset} style={{background:DS.color.error,border:"none",borderRadius:DS.radius.sm,padding:"10px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 14px rgba(245,67,78,0.3)"}}><PhoneOff size={20} style={{color:DS.color.white}}/></button>
            <button onClick={timer.running?timer.pause:timer.start} style={{background:th.optBg,border:`1px solid ${th.optBorder}`,borderRadius:DS.radius.sm,padding:"10px 4px",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}}>{timer.running?<Pause size={14} style={{color:th.labelText}}/>:<Play size={14} style={{color:th.labelText}}/>}</button>
          </div>
        </div>}
      </div>
    </div>
  );
}

/* ─── FLOW PANEL ──────────────────────────────────────────────────────────── */
function FlowPanel({testType,nodes,setNodes,editMode,canEdit,timer,voiceProfile,voiceOn,avatar,onAvatarChange,testName}){
  const[view,setView]=useState("simulate");
  const th=TYPE_THEME[testType]||TYPE_THEME.IVR;
  const[chatMsgs,setChatMsgs]=useState([]);const[chatStep,setChatStep]=useState(0);
  const[waMsgs,setWaMsgs]=useState([]);const[waStep,setWaStep]=useState(0);
  const showAvatar=testType==="Chatbot"||testType==="WhatsApp";
  const renderSim=()=>{
    if(testType==="WhatsApp")return <WhatsAppSim nodes={nodes} timer={timer} msgs={waMsgs} setMsgs={setWaMsgs} step={waStep} setStep={setWaStep} avatar={avatar}/>;
    if(testType==="Chatbot") return <ChatbotSim  nodes={nodes} timer={timer} voiceProfile={voiceProfile} voiceOn={false} msgs={chatMsgs} setMsgs={setChatMsgs} step={chatStep} setStep={setChatStep} avatar={avatar}/>;
    if(testType==="Voicebot")return <VoicebotSim nodes={nodes} timer={timer} voiceProfile={voiceProfile} voiceOn={voiceOn}/>;
    return <IVRSimulator nodes={nodes} timer={timer} voiceProfile={voiceProfile} voiceOn={voiceOn}/>;
  };
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%",overflow:"hidden"}}>
      <div style={{display:"flex",background:DS.color.white,borderBottom:`1px solid ${DS.color.neutral200}`,padding:`4px ${DS.space.sm}px`,gap:DS.space.xs,alignItems:"center",flexShrink:0}}>
        {showAvatar&&<AvatarUploader avatar={avatar} onUpload={onAvatarChange}/>}
        <span style={{fontSize:10,color:DS.color.neutral400,flex:1,fontFamily:DS.font,fontWeight:500}}>{nodes.length} nodos</span>
        <div style={{display:"flex",borderRadius:DS.radius.sm,overflow:"hidden",border:`1px solid ${DS.color.neutral300}`}}>
          {["simulate","tree"].map(v=>(
            <button key={v} onClick={()=>setView(v)} style={{padding:`3px ${DS.space.sm}px`,fontSize:10,border:"none",background:view===v?th.accentDark:DS.color.white,color:view===v?DS.color.white:DS.color.neutral700,cursor:"pointer",fontFamily:DS.font,fontWeight:600}}>
              {v==="simulate"?"▶ Simular":"Árbol"}
            </button>
          ))}
        </div>
      </div>
      <div style={{flex:1,overflow:"hidden",display:view==="simulate"?"block":"none"}}>{renderSim()}</div>
      <div style={{flex:1,overflow:"hidden",display:view==="tree"?"block":"none"}}><TreeView nodes={nodes} setNodes={setNodes} editMode={editMode} canEdit={canEdit} testName={testName}/></div>
    </div>
  );
}

/* ─── TESTER MODE (resultados compartidos via window.storage) ──────────────── */
const STORAGE_KEY="flowtester_v2_sessions";
const ACTIVE_TEST_KEY="flowtester_v2_active_test";
const TESTS_KEY="flowtester_v2_tests";
const AVATARS_KEY="flowtester_v2_avatars";
const VOICE_PROFILE_KEY="flowtester_v2_voice_profile";
const HIDDEN_CHANNELS_KEY="flowtester_v2_hidden_channels";

async function loadSharedSessions(){
  try{const r=await window.storage.get(STORAGE_KEY,true);return r?JSON.parse(r.value):[];}catch{return[];}
}
async function saveSharedSessions(arr){
  try{await window.storage.set(STORAGE_KEY,JSON.stringify(arr),true);}catch{}
}
async function loadActiveTestId(){
  try{const r=await window.storage.get(ACTIVE_TEST_KEY,true);return r?JSON.parse(r.value):null;}catch{return null;}
}
async function saveActiveTestId(id){
  try{await window.storage.set(ACTIVE_TEST_KEY,JSON.stringify(id),true);}catch{}
}
async function loadSharedJSON(key){
  try{const r=await window.storage.get(key,true);return r?JSON.parse(r.value):null;}catch{return null;}
}
async function saveSharedJSON(key,value){
  try{await window.storage.set(key,JSON.stringify(value),true);}catch{}
}

function TesterMode({test,avatar,onGoHome}){
  const[name,setName]=useState("");const[started,setStarted]=useState(false);
  const[msgs,setMsgs]=useState([]);const[step,setStep]=useState(0);
  const[saved,setSaved]=useState(false);
  const[completed,setCompleted]=useState(false);
  const[comment,setComment]=useState("");
  const[voiceName,setVoiceName]=useState("");
  useEffect(()=>{loadSharedJSON(VOICE_PROFILE_KEY).then(n=>{if(n)setVoiceName(n);});},[]);
  const[finished,setFinished]=useState(false);
  const timer=useTimer();
  const nodes=test?.proposed?.nodes||[];
  const testType=test?.type||"Chatbot";
  const canListen=testType==="IVR"||testType==="Voicebot";

  const saveSession=useCallback(async()=>{
    if(saved)return;
    const userMsgs=msgs.filter(m=>m.from==="user").map(m=>m.text);
    const session={id:Date.now(),name,testName:test?.name||"",type:testType,date:new Date().toLocaleString("es-CO"),steps:userMsgs,duration:timer.fmt,completed:true,comment:comment.trim()};
    const current=await loadSharedSessions();
    const updated=[...current,session];
    await saveSharedSessions(updated);
    setSaved(true);setFinished(true);
  },[name,test,testType,timer.fmt,saved,msgs,comment]);

  const startOver=()=>{setStarted(false);setFinished(false);setMsgs([]);setStep(0);setCompleted(false);setComment("");setSaved(false);timer.reset();};

  if(!started){
    return(
      <div style={{height:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:`linear-gradient(135deg,${DS.color.deepBlue},${DS.color.midBlue})`,fontFamily:DS.font,padding:DS.space.lg}}>
        <Card style={{maxWidth:360,width:"100%",textAlign:"center"}}>
          <div style={{width:56,height:56,borderRadius:DS.radius.full,background:DS.color.cyan50,border:`2px solid ${DS.color.brightBlue}`,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto",marginBottom:DS.space.md}}><FlaskConical size={26} style={{color:DS.color.midBlue}}/></div>
          <h2 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:20,fontWeight:700,color:DS.color.deepBlue}}>Modo Testeo</h2>
          <p style={{fontSize:12,color:DS.color.neutral700,marginBottom:DS.space.md,lineHeight:1.6}}>Vas a probar el <b>flujo propuesto</b> de <b>{test?.name}</b>.</p>
          <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:4,fontWeight:600,textAlign:"left"}}>Tu nombre completo</label>
          <input value={name} onChange={e=>setName(e.target.value)} onKeyDown={e=>e.key==="Enter"&&name.trim()&&setStarted(true)} placeholder="Ej. Ana Martínez" style={{width:"100%",boxSizing:"border-box",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,padding:`${DS.space.xs}px`,fontFamily:DS.font,fontSize:13,color:DS.color.deepBlue,marginBottom:DS.space.md}}/>
          <Btn full onClick={()=>name.trim()&&setStarted(true)} disabled={!name.trim()}><Play size={14}/>Iniciar prueba</Btn>
        </Card>
      </div>
    );
  }

  if(finished){
    return(
      <div style={{height:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:`linear-gradient(135deg,${DS.color.deepBlue},${DS.color.midBlue})`,fontFamily:DS.font,padding:DS.space.lg}}>
        <Card style={{maxWidth:360,width:"100%",textAlign:"center"}}>
          <div style={{width:56,height:56,borderRadius:DS.radius.full,background:DS.color.successLight,border:`2px solid ${DS.color.success}`,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto",marginBottom:DS.space.md}}><CheckCircle size={26} style={{color:DS.color.success}}/></div>
          <h2 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:20,fontWeight:700,color:DS.color.deepBlue}}>¡Gracias por tu prueba!</h2>
          <p style={{fontSize:12,color:DS.color.neutral700,marginBottom:DS.space.md,lineHeight:1.6}}>Tu resultado{comment?" y tu comentario ":" "}quedaron registrados.</p>
          <div style={{display:"flex",flexDirection:"column",gap:DS.space.xs}}>
            <Btn full onClick={startOver}><RotateCcw size={14}/>Realizar otra prueba</Btn>
            <Btn full variant="ghost" onClick={()=>onGoHome?onGoHome():startOver()}><GitBranch size={14}/>Volver al inicio</Btn>
          </div>
        </Card>
      </div>
    );
  }

  const SimComp=testType==="WhatsApp"?WhatsAppSim:testType==="Voicebot"?VoicebotSim:testType==="IVR"?IVRSimulator:ChatbotSim;
  const effectiveVoiceOn=canListen; // el audio siempre está activo para IVR y Voicebot
  return(
    <div style={{display:"flex",flexDirection:"column",height:"100%"}}>
      <div style={{flex:1,overflow:"hidden"}}>
        <SimComp nodes={nodes} timer={timer} msgs={msgs} setMsgs={setMsgs} step={step} setStep={setStep} avatar={avatar} voiceProfile={voiceName} voiceOn={effectiveVoiceOn} onComplete={()=>setCompleted(true)} minimal={canListen}/>
      </div>
      {completed&&(
        <div style={{padding:`${DS.space.sm}px ${DS.space.md}px`,background:DS.color.white,borderTop:`1px solid ${DS.color.neutral200}`,flexShrink:0}}>
          <Toast type="success">Flujo finalizado. Puedes dejar un comentario y finalizar cuando quieras.</Toast>
          <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:4,fontWeight:600}}>Comentarios (opcional)</label>
          <textarea value={comment} onChange={e=>setComment(e.target.value)} rows={2} placeholder="Cuéntanos cómo fue tu experiencia..." style={{width:"100%",boxSizing:"border-box",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,padding:DS.space.xs,fontFamily:DS.font,fontSize:12,color:DS.color.deepBlue,resize:"vertical",marginBottom:DS.space.sm}}/>
          <Btn full variant="success" onClick={saveSession}><CheckCircle size={13}/>Finalizar prueba</Btn>
        </div>
      )}
    </div>
  );
}

/* ─── LOGIN ───────────────────────────────────────────────────────────────── */
function LoginScreen({onLogin}){
  const[usr,setUsr]=useState("");const[pwd,setPwd]=useState("");const[show,setShow]=useState(false);const[err,setErr]=useState("");const[loading,setLoading]=useState(false);
  const go=()=>{setErr("");const u=USERS.find(u=>u.username===usr.trim()&&u.password===pwd);if(!u){setErr("Usuario o contraseña incorrectos.");return;}setLoading(true);setTimeout(()=>onLogin(u),700);};
  const c=DS.color;
  return(
    <div style={{minHeight:"100vh",background:`linear-gradient(135deg,${c.deepBlue},${c.midBlue},${c.brightBlue})`,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:DS.space.lg,fontFamily:DS.font}}>
      <div style={{textAlign:"center",marginBottom:DS.space.xl}}>
        <div style={{display:"inline-flex",alignItems:"center",justifyContent:"center",width:60,height:60,borderRadius:DS.radius.lg,background:"rgba(255,255,255,0.12)",border:"1.5px solid rgba(255,255,255,0.3)",marginBottom:DS.space.md,backdropFilter:"blur(8px)"}}><GitBranch size={28} style={{color:c.white}}/></div>
        <h1 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:32,fontWeight:800,color:c.white,letterSpacing:-0.5,textShadow:"0 2px 8px rgba(0,0,0,0.2)"}}>FlowTester</h1>
        <p style={{margin:0,fontSize:14,color:c.cyan100,fontWeight:500}}>Simulador de flujos conversacionales · emtelco DSXP</p>
      </div>
      <Card style={{maxWidth:400,width:"100%"}}>
        <h2 style={{fontSize:18,fontWeight:700,margin:`0 0 ${DS.space.md}px`,color:c.deepBlue}}>Iniciar sesión</h2>
        <label style={{fontSize:11,color:c.neutral700,display:"block",marginBottom:3,fontWeight:600}}>Usuario</label>
        <div style={{position:"relative",marginBottom:DS.space.sm}}>
          <User size={13} style={{position:"absolute",left:10,top:"50%",transform:"translateY(-50%)",color:c.neutral400}}/>
          <input value={usr} onChange={e=>setUsr(e.target.value)} onKeyDown={e=>e.key==="Enter"&&go()} placeholder="usuario" style={{paddingLeft:30,width:"100%",boxSizing:"border-box",fontFamily:DS.font,fontSize:13,padding:`${DS.space.xs}px ${DS.space.xs}px ${DS.space.xs}px 30px`,border:`1px solid ${c.neutral300}`,borderRadius:DS.radius.sm,color:c.deepBlue}}/>
        </div>
        <label style={{fontSize:11,color:c.neutral700,display:"block",marginBottom:3,fontWeight:600}}>Contraseña</label>
        <div style={{position:"relative",marginBottom:DS.space.md}}>
          <Lock size={13} style={{position:"absolute",left:10,top:"50%",transform:"translateY(-50%)",color:c.neutral400}}/>
          <input type={show?"text":"password"} value={pwd} onChange={e=>setPwd(e.target.value)} onKeyDown={e=>e.key==="Enter"&&go()} placeholder="contraseña" style={{paddingLeft:30,paddingRight:34,width:"100%",boxSizing:"border-box",fontFamily:DS.font,fontSize:13,padding:`${DS.space.xs}px 34px ${DS.space.xs}px 30px`,border:`1px solid ${c.neutral300}`,borderRadius:DS.radius.sm,color:c.deepBlue}}/>
          <button onClick={()=>setShow(s=>!s)} style={{position:"absolute",right:DS.space.xs,top:"50%",transform:"translateY(-50%)",background:"none",border:"none",cursor:"pointer",color:c.neutral400}}>{show?<EyeOff size={13}/>:<Eye size={13}/>}</button>
        </div>
        {err&&<Toast type="error">{err}</Toast>}
        <Btn full onClick={go} disabled={loading}><LogIn size={14}/>{loading?"Verificando...":"Ingresar"}</Btn>
      </Card>
    </div>
  );
}

/* ─── EDIT TEST MODAL ─────────────────────────────────────────────────────── */
function EditTestModal({test,onSave,onClose}){
  const[name,setName]=useState(test.name);const[desc,setDesc]=useState(test.description||"");const[type,setType]=useState(test.type);
  return(
    <Overlay onClose={onClose}>
      <Card style={{width:360}}>
        <div style={{display:"flex",justifyContent:"space-between",marginBottom:DS.space.md}}>
          <h3 style={{margin:0,fontSize:16,fontWeight:700,color:DS.color.deepBlue}}>Editar test</h3>
          <button onClick={onClose} style={{background:"none",border:"none",cursor:"pointer",color:DS.color.neutral400}}><X size={16}/></button>
        </div>
        {[["Nombre","name"],["Descripción","desc"]].map(([lbl,key])=>(
          <div key={key} style={{marginBottom:DS.space.sm}}>
            <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:3,fontWeight:600}}>{lbl}</label>
            <input value={key==="name"?name:desc} onChange={e=>key==="name"?setName(e.target.value):setDesc(e.target.value)} style={{width:"100%",boxSizing:"border-box",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:`${DS.space.xs}px`,fontFamily:DS.font}}/>
          </div>
        ))}
        <label style={{fontSize:11,color:DS.color.neutral700,display:"block",marginBottom:3,fontWeight:600}}>Tipo</label>
        <select value={type} onChange={e=>setType(e.target.value)} style={{width:"100%",border:`1px solid ${DS.color.neutral300}`,borderRadius:DS.radius.sm,color:DS.color.deepBlue,padding:`${DS.space.xs}px`,fontFamily:DS.font,marginBottom:DS.space.md}}>
          {["IVR","Chatbot","Voicebot","WhatsApp"].map(t=><option key={t} value={t}>{t}</option>)}
        </select>
        <div style={{display:"flex",gap:DS.space.xs,justifyContent:"flex-end"}}>
          <Btn variant="ghost" onClick={onClose}>Cancelar</Btn>
          <Btn onClick={()=>onSave({...test,name,description:desc,type})}><Save size={11}/>Guardar</Btn>
        </div>
      </Card>
    </Overlay>
  );
}

/* ─── INIT DATA ───────────────────────────────────────────────────────────── */
const INIT_TESTS=[
  {id:1,name:"Autenticación",type:"IVR",description:"IVR de acceso",
    current:{nodes:[{id:"n1",label:"Bienvenida",type:"start",message:"Bienvenido. Ingrese su número de cliente.",options:[{label:"1",next:""},{label:"0",next:""}]},{id:"n2",label:"Validación",type:"action",message:"Validando información...",options:[{label:"1",next:""},{label:"2",next:""}]},{id:"n3",label:"Confirmación",type:"decision",message:"Confirme los últimos 4 dígitos de su documento.",options:[{label:"1",next:""},{label:"2",next:""}]},{id:"n4",label:"Acceso OK",type:"end_call",message:"Autenticación exitosa.",options:[]},{id:"n5",label:"Acceso Denegado",type:"error",message:"No fue posible verificar. Comuníquese con soporte.",options:[{label:"0",next:""}]}]},
    proposed:{nodes:[{id:"p1",label:"Saludo",type:"start",message:"Hola. Detectamos tu número. ¿Eres el titular?",options:[{label:"1",next:""},{label:"2",next:""}]},{id:"p2",label:"Auth Biométrica",type:"action",message:"Di tu frase de seguridad o ingresa tu PIN.",options:[{label:"1",next:""},{label:"2",next:""}]},{id:"p3",label:"Acceso Inmediato",type:"end_call",message:"Verificado. ¿Qué deseas hacer?",options:[{label:"1",next:""},{label:"2",next:""}]}]}
  },
  {id:2,name:"Soporte Técnico",type:"Chatbot",description:"Chatbot de soporte nivel 1",
    current:{nodes:[{id:"n1",label:"Inicio",type:"start",message:"Hola, soy el asistente de soporte. ¿En qué te puedo ayudar hoy?",options:[{label:"Internet",next:""},{label:"Facturación",next:""},{label:"Equipos",next:""},{label:"Agente",next:""}]},{id:"n2",label:"Diagnóstico",type:"action",message:"¿El servicio está caído o presenta lentitud?",options:[{label:"Sin servicio",next:""},{label:"Servicio lento",next:""}]},{id:"n4",label:"Resuelto",type:"end_call",message:"¡Tu servicio fue restablecido!",options:[{label:"Otra consulta",next:""},{label:"No, gracias",next:""}]}]},
    proposed:{nodes:[{id:"p1",label:"Triaje",type:"start",message:"¡Hola! Cuéntame qué está pasando con tu servicio.",options:[{label:"Internet",next:""},{label:"Facturación",next:""},{label:"Equipos",next:""},{label:"Otro",next:""}]},{id:"p2",label:"Diagnóstico IA",type:"action",message:"Detectamos una incidencia en tu zona. ¿Persiste más de 10 min?",options:[{label:"Sí",next:""},{label:"Ya se resolvió",next:""}]},{id:"p3",label:"Solución",type:"action",message:"Te enviamos los pasos. ¿Probamos autodiagnóstico?",options:[{label:"Ver pasos",next:""},{label:"Autodiagnóstico",next:""}]},{id:"p4",label:"Confirmado",type:"end_call",message:"¡Incidencia resuelta! Reporte generado.",options:[{label:"Ver reporte",next:""},{label:"Calificar",next:""}]}]}
  },
  {id:4,name:"WhatsApp Bot",type:"WhatsApp",description:"Atención por WhatsApp",
    current:{nodes:[{id:"w1",label:"Bienvenida",type:"start",message:"👋 ¡Hola! ¿En qué te puedo ayudar?",options:[{label:"📋 Servicios",next:""},{label:"🔧 Soporte",next:""},{label:"💳 Pagos",next:""},{label:"👤 Agente",next:""}]},{id:"w2",label:"Soporte",type:"action",message:"🔧 ¿Cuál es tu inconveniente?",options:[{label:"Internet caído",next:""},{label:"Servicio lento",next:""},{label:"Otro",next:""}]},{id:"w3",label:"Solución",type:"end_call",message:"✅ ¡Listo! Servicio restablecido. ¿Algo más?",options:[{label:"Sí",next:""},{label:"No 😊",next:""}]}]},
    proposed:{nodes:[{id:"pw1",label:"Saludo",type:"start",message:"👋 ¡Hola! Soy emtelco Assistant. ¿En qué te ayudo?",options:[{label:"🔧 Tengo un problema",next:""},{label:"📊 Ver consumo",next:""},{label:"💰 Factura",next:""}]},{id:"pw2",label:"NLU",type:"decision",message:"Entendí que tienes un problema con internet. ¿Es correcto?",options:[{label:"✅ Sí",next:""},{label:"❌ No",next:""}]},{id:"pw3",label:"Resolución",type:"end_call",message:"✅ ¡Servicio restaurado!\n📊 Compensación: 1 día gratis. ¿Algo más?",options:[{label:"Ver compensación",next:""},{label:"Calificar ⭐",next:""}]}]}
  }
];

/* ─── HOME SCREEN (2 botones principales) ─────────────────────────────────── */
function HomeScreen({onSelect}){
  const c=DS.color;
  return(
    <div style={{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",background:`linear-gradient(135deg,${c.deepBlue}ee,${c.midBlue}dd)`,padding:DS.space.xl,gap:DS.space.xl,fontFamily:DS.font}}>
      <div style={{textAlign:"center",marginBottom:DS.space.md}}>
        <h2 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:24,fontWeight:700,color:c.white}}>¿Qué deseas hacer?</h2>
        <p style={{margin:0,fontSize:13,color:c.cyan100,fontWeight:400}}>Selecciona el modo de trabajo</p>
      </div>
      <div style={{display:"flex",gap:DS.space.xl,flexWrap:"wrap",justifyContent:"center"}}>
        {/* Testeo — primera opción, sin necesidad de iniciar sesión */}
        <button onClick={()=>onSelect("tester")}
          style={{background:"rgba(255,255,255,0.95)",borderRadius:DS.radius.lg,padding:`${DS.space.xl}px ${DS.space.xxl||48}px`,border:"none",cursor:"pointer",boxShadow:DS.shadow.B2,display:"flex",flexDirection:"column",alignItems:"center",gap:DS.space.md,transition:"transform 0.15s, box-shadow 0.15s",minWidth:220,fontFamily:DS.font}}
          onMouseEnter={e=>{e.currentTarget.style.transform="translateY(-4px)";e.currentTarget.style.boxShadow="0 20px 48px rgba(0,26,123,0.25)";}}
          onMouseLeave={e=>{e.currentTarget.style.transform="translateY(0)";e.currentTarget.style.boxShadow=DS.shadow.B2;}}>
          <div style={{width:64,height:64,borderRadius:DS.radius.full,background:`linear-gradient(135deg,${c.green},${c.success})`,display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 16px rgba(53,199,89,0.3)"}}>
            <FlaskConical size={30} style={{color:c.white}}/>
          </div>
          <div style={{textAlign:"center"}}>
            <div style={{fontSize:18,fontWeight:700,color:c.deepBlue,marginBottom:4}}>Testeo de Propuesta</div>
            <div style={{fontSize:12,color:c.neutral700,lineHeight:1.5}}>Prueba el flujo propuesto<br/>y guarda los resultados</div>
          </div>
          <div style={{background:c.successLight,borderRadius:DS.radius.full,padding:"5px 16px",fontSize:11,color:"#1A4D2E",fontWeight:600,border:`1px solid ${c.success}`}}>Modo Usuario / Tester</div>
        </button>

        {/* Comparativo — requiere iniciar sesión como Admin */}
        <button onClick={()=>onSelect("compare")}
          style={{background:"rgba(255,255,255,0.95)",borderRadius:DS.radius.lg,padding:`${DS.space.xl}px ${DS.space.xxl||48}px`,border:"none",cursor:"pointer",boxShadow:DS.shadow.B2,display:"flex",flexDirection:"column",alignItems:"center",gap:DS.space.md,transition:"transform 0.15s, box-shadow 0.15s",minWidth:220,fontFamily:DS.font}}
          onMouseEnter={e=>{e.currentTarget.style.transform="translateY(-4px)";e.currentTarget.style.boxShadow="0 20px 48px rgba(0,26,123,0.25)";}}
          onMouseLeave={e=>{e.currentTarget.style.transform="translateY(0)";e.currentTarget.style.boxShadow=DS.shadow.B2;}}>
          <div style={{width:64,height:64,borderRadius:DS.radius.full,background:`linear-gradient(135deg,${c.midBlue},${c.deepBlue})`,display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 16px rgba(0,26,123,0.3)"}}>
            <GitCompare size={30} style={{color:c.white}}/>
          </div>
          <div style={{textAlign:"center"}}>
            <div style={{fontSize:18,fontWeight:700,color:c.deepBlue,marginBottom:4}}>Comparativo</div>
            <div style={{fontSize:12,color:c.neutral700,lineHeight:1.5}}>Contrasta el flujo actual<br/>con la propuesta en paralelo</div>
          </div>
          <div style={{background:c.cyan50,borderRadius:DS.radius.full,padding:"5px 16px",fontSize:11,color:c.midBlue,fontWeight:600,border:`1px solid ${c.cyan200}`}}>Modo Admin / Diseño · requiere login</div>
        </button>
      </div>
    </div>
  );
}

/* ─── SESSIONS PANEL ─────────────────────────────────────────────────────── */
const toSec=str=>{const p=(str||"0:00").split(":").map(Number);return(p[0]||0)*60+(p[1]||0);};
const toMMSS=sec=>`${String(Math.floor(sec/60)).padStart(2,"0")}:${String(sec%60).padStart(2,"0")}`;
const SESSION_TYPE_ICON={IVR:<Phone size={12}/>,Chatbot:<MessageSquare size={12}/>,Voicebot:<Mic size={12}/>,WhatsApp:<span style={{fontSize:12}}>🟢</span>};
function SessionsPanel(){
  const c=DS.color;
  const[sessions,setSessions]=useState([]);const[loading,setLoading]=useState(true);
  useEffect(()=>{loadSharedSessions().then(s=>{setSessions(s);setLoading(false);});const t=setInterval(()=>loadSharedSessions().then(setSessions),3000);return()=>clearInterval(t);},[]);
  const clear=async()=>{await saveSharedSessions([]);setSessions([]);};
  const completedCount=sessions.filter(s=>s.completed).length;
  const avgSec=sessions.length?Math.round(sessions.reduce((a,s)=>a+toSec(s.duration),0)/sessions.length):0;
  const sorted=[...sessions].sort((a,b)=>(b.id||0)-(a.id||0));
  return(
    <div style={{padding:DS.space.md,fontFamily:DS.font,height:"100%",overflowY:"auto",background:c.neutral100}}>
      <div style={{display:"flex",alignItems:"center",gap:DS.space.sm,marginBottom:DS.space.md}}>
        <BarChart2 size={18} style={{color:c.midBlue}}/>
        <h3 style={{margin:0,fontSize:16,fontWeight:700,color:c.deepBlue}}>Resultados de testeo</h3>
        <span style={{marginLeft:"auto",fontSize:11,color:c.neutral400}}>Compartidos entre equipos</span>
      </div>

      {/* RESUMEN */}
      <div style={{display:"flex",gap:DS.space.sm,marginBottom:DS.space.md,flexWrap:"wrap"}}>
        {[
          {label:"Sesiones",value:sessions.length,icon:<FlaskConical size={14} style={{color:c.midBlue}}/>,bg:c.cyan50,bd:c.cyan200},
          {label:"Completadas",value:`${completedCount}/${sessions.length||0}`,icon:<CheckCircle size={14} style={{color:c.success}}/>,bg:c.successLight,bd:c.success},
          {label:"Duración promedio",value:toMMSS(avgSec),icon:<Radio size={14} style={{color:c.purple}}/>,bg:"#F5F3FF",bd:c.purple100},
        ].map((st,i)=>(
          <div key={i} style={{flex:"1 1 140px",background:st.bg,border:`1px solid ${st.bd}`,borderRadius:DS.radius.md,padding:`${DS.space.xs}px ${DS.space.sm}px`,display:"flex",alignItems:"center",gap:8}}>
            <div style={{width:28,height:28,borderRadius:DS.radius.full,background:c.white,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>{st.icon}</div>
            <div><div style={{fontSize:16,fontWeight:800,color:c.deepBlue,lineHeight:1.1}}>{st.value}</div><div style={{fontSize:9,color:c.neutral700,fontWeight:600}}>{st.label}</div></div>
          </div>
        ))}
      </div>

      <div style={{display:"flex",gap:DS.space.sm,marginBottom:DS.space.md}}>
        <button onClick={()=>dlCSV(sessions.map(s=>({Nombre:s.name,Test:s.testName,Tipo:s.type,Fecha:s.date,"Duración":s.duration,Pasos:s.steps.join(" → "),Completado:s.completed?"Sí":"No",Comentario:s.comment||""})),"resultados_testeo.csv")} disabled={!sessions.length} style={{fontSize:11,padding:"5px 14px",border:`1px solid ${c.success}`,borderRadius:DS.radius.full,background:c.successLight,cursor:sessions.length?"pointer":"default",color:"#1A4D2E",display:"flex",alignItems:"center",gap:4,fontFamily:DS.font,fontWeight:600,opacity:sessions.length?1:0.5}}><Download size={11}/>Descargar CSV</button>
        <button onClick={clear} disabled={!sessions.length} style={{fontSize:11,padding:"5px 14px",border:`1px solid ${c.error}`,borderRadius:DS.radius.full,background:c.errorLight,cursor:sessions.length?"pointer":"default",color:c.error,display:"flex",alignItems:"center",gap:4,fontFamily:DS.font,fontWeight:600,opacity:sessions.length?1:0.5}}><Trash2 size={11}/>Limpiar</button>
      </div>

      {loading?<div style={{textAlign:"center",padding:DS.space.xl,color:c.neutral400}}>Cargando...</div>:sorted.length===0?<div style={{textAlign:"center",padding:DS.space.xl,color:c.neutral400,fontSize:12}}>No hay sesiones registradas aún.</div>:sorted.map((s,i)=>{
        const th=TYPE_THEME[s.type]||TYPE_THEME.IVR;
        const accent=th.accentDark||th.accent||c.midBlue;
        return(
        <div key={s.id||i} style={{background:c.white,border:`1px solid ${c.neutral300}`,borderLeft:`4px solid ${accent}`,borderRadius:DS.radius.sm,padding:`${DS.space.sm}px ${DS.space.md}px`,marginBottom:DS.space.sm,boxShadow:DS.shadow.A1}}>
          <div style={{display:"flex",alignItems:"center",gap:DS.space.xs,marginBottom:6,flexWrap:"wrap"}}>
            <div style={{width:24,height:24,borderRadius:DS.radius.full,background:c.deepBlue,color:c.white,display:"flex",alignItems:"center",justifyContent:"center",fontSize:10,fontWeight:800,flexShrink:0}}>{(s.name||"?").trim().charAt(0).toUpperCase()}</div>
            <span style={{fontSize:13,fontWeight:700,color:c.deepBlue}}>{s.name}</span>
            <Tag label={s.testName} color={c.midBlue}/>
            <span style={{display:"flex",alignItems:"center",gap:3,fontSize:10,color:accent,fontWeight:700}}>{SESSION_TYPE_ICON[s.type]||null}{s.type}</span>
            <div style={{marginLeft:"auto",display:"flex",alignItems:"center",gap:6}}>
              <span style={{display:"flex",alignItems:"center",gap:3,fontSize:11,fontWeight:700,color:c.deepBlue,background:c.neutral100,borderRadius:DS.radius.full,padding:"3px 9px"}}><Radio size={10} style={{color:c.midBlue}}/>{s.duration}</span>
              <span style={{fontSize:10,color:s.completed?c.success:c.warning,fontWeight:700}}>{s.completed?"✓ Completado":"Parcial"}</span>
            </div>
          </div>
          <div style={{fontSize:10,color:c.neutral400,marginBottom:6}}>{s.date}</div>
          {s.steps.length>0&&(
            <div style={{marginBottom:s.comment?6:0}}>
              <div style={{fontSize:9,color:c.neutral700,fontWeight:700,letterSpacing:1,marginBottom:4}}>OPCIONES SELECCIONADAS</div>
              <div style={{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center"}}>
                {s.steps.map((opt,j)=>(
                  <span key={j} style={{display:"flex",alignItems:"center",gap:5}}>
                    <span style={{display:"flex",alignItems:"center",gap:4,fontSize:11,color:c.deepBlue,background:c.neutral100,border:`1px solid ${c.neutral300}`,borderRadius:DS.radius.full,padding:"3px 10px"}}>
                      <span style={{fontSize:9,fontWeight:800,color:accent}}>{j+1}</span>{opt}
                    </span>
                    {j<s.steps.length-1&&<ChevronRight size={12} style={{color:c.neutral400}}/>}
                  </span>
                ))}
              </div>
            </div>
          )}
          {s.comment&&(
            <div style={{display:"flex",gap:6,alignItems:"flex-start",background:"#FFFBEA",border:`1px solid ${c.warning}`,borderRadius:DS.radius.sm,padding:"6px 10px"}}>
              <MessageSquare size={12} style={{color:"#7A4F00",flexShrink:0,marginTop:1}}/>
              <span style={{fontSize:11,color:"#7A4F00",fontStyle:"italic",lineHeight:1.4}}>{s.comment}</span>
            </div>
          )}
        </div>
      );})}
    </div>
  );
}

/* ─── MAIN ────────────────────────────────────────────────────────────────── */
export default function App(){
  const[user,setUser]=useState(null);
  const[tests,setTests]=useState(INIT_TESTS);
  const[tid,setTid]=useState(1);
  const[editMode,setEditMode]=useState(false);
  const[showTests,setShowTests]=useState(false);
  const[showSave,setShowSave]=useState(false);
  const[showUserMenu,setShowUserMenu]=useState(false);
  const[saveName,setSaveName]=useState("");
  const[voiceName,setVoiceName]=useState("");
  const[voiceList,setVoiceList]=useState([]);
  const[editingTest,setEditingTest]=useState(null);
  const[avatars,setAvatars]=useState({});
  const[activeTestId,setActiveTestId]=useState(null);
  const[hiddenChannels,setHiddenChannels]=useState([]);
  const[showChannels,setShowChannels]=useState(false);
  const[dataLoaded,setDataLoaded]=useState(false);
  // "home" | "compare" | "tester" | "sessions"
  const[appMode,setAppMode]=useState("home");
  const timerL=useTimer();const timerR=useTimer();

  useEffect(()=>{
    const refresh=()=>{loadVoices();setVoiceList(getSpanishVoices());};
    refresh();
    if(window.speechSynthesis)window.speechSynthesis.onvoiceschanged=refresh;
  },[]);
  useEffect(()=>{loadActiveTestId().then(id=>setActiveTestId(id||tests[0]?.id||1));},[]);
  // Carga lo que ya esté guardado (compartido) de flujos y avatares, para que
  // Testeo siempre refleje exactamente lo que se guardó en Comparativo → Propuesta.
  useEffect(()=>{
    (async()=>{
      const[savedTests,savedAvatars,savedVoiceName,savedHidden]=await Promise.all([loadSharedJSON(TESTS_KEY),loadSharedJSON(AVATARS_KEY),loadSharedJSON(VOICE_PROFILE_KEY),loadSharedJSON(HIDDEN_CHANNELS_KEY)]);
      if(savedTests&&Array.isArray(savedTests)&&savedTests.length)setTests(savedTests);
      if(savedAvatars)setAvatars(savedAvatars);
      if(savedVoiceName)setVoiceName(savedVoiceName);
      if(savedHidden&&Array.isArray(savedHidden))setHiddenChannels(savedHidden);
      setDataLoaded(true);
    })();
  },[]);
  useEffect(()=>{if(dataLoaded)saveSharedJSON(TESTS_KEY,tests);},[tests,dataLoaded]);
  useEffect(()=>{if(dataLoaded)saveSharedJSON(AVATARS_KEY,avatars);},[avatars,dataLoaded]);
  useEffect(()=>{if(dataLoaded)saveSharedJSON(HIDDEN_CHANNELS_KEY,hiddenChannels);},[hiddenChannels,dataLoaded]);
  // Si el canal del test que se está viendo se oculta, cambia automáticamente a uno visible.
  useEffect(()=>{
    const currentTest=tests.find(t=>t.id===tid);
    if(currentTest&&hiddenChannels.includes(currentTest.type)){
      const fallback=tests.find(t=>!hiddenChannels.includes(t.type));
      if(fallback)setTid(fallback.id);
    }
  },[hiddenChannels,tests]);
  // Solo el modo Comparativo (edición de flujos) exige iniciar sesión.
  if(appMode==="compare"&&!user)return <LoginScreen onLogin={setUser}/>;

  const isAdmin=user?.role==="admin";
  const test=tests.find(t=>t.id===tid);
  const theme=TYPE_THEME[test?.type]||TYPE_THEME.IVR;
  const setNodes=(side,upd)=>setTests(p=>p.map(t=>t.id===tid?{...t,[side]:{...t[side],nodes:typeof upd==="function"?upd(t[side].nodes):upd}}:t));
  const saveNew=()=>{if(!saveName.trim())return;const n={...test,id:Date.now(),name:saveName};setTests(p=>[...p,n]);setTid(n.id);setShowSave(false);setSaveName("");};
  const getAvatar=side=>avatars[tid]?.[side]||null;
  const setAvatar=(side,url)=>setAvatars(a=>({...a,[tid]:{...a[tid],[side]:url}}));
  const markActiveForTesting=()=>{setActiveTestId(tid);saveActiveTestId(tid);};
  const toggleChannel=type=>{setHiddenChannels(prev=>prev.includes(type)?prev.filter(t=>t!==type):[...prev,type]);};
  const presentChannels=[...new Set(tests.map(t=>t.type))];
  const restoreDefaults=()=>{
    if(!window.confirm("Esto restablece TODOS los flujos (actual y propuesto de cada test) a la versión original, para todos los que usen esta app. Se perderán los cambios guardados. ¿Continuar?"))return;
    const fresh=JSON.parse(JSON.stringify(INIT_TESTS));
    setTests(fresh);setAvatars({});setTid(fresh[0]?.id||1);
    saveSharedJSON(TESTS_KEY,fresh);saveSharedJSON(AVATARS_KEY,{});
  };
  const TI={IVR:<Phone size={10}/>,Chatbot:<MessageSquare size={10}/>,Voicebot:<Mic size={10}/>,WhatsApp:<span style={{fontSize:10}}>🟢</span>};
  const c=DS.color;
  const showVoice=test?.type==="IVR"||test?.type==="Voicebot";
  const topGradient=appMode==="compare"?theme.gradient:`linear-gradient(135deg,${c.deepBlue},${c.midBlue})`;

  return(
    <div style={{display:"flex",flexDirection:"column",height:"100vh",background:c.neutral100,fontFamily:DS.font,overflow:"hidden"}}>
      {editingTest&&<EditTestModal test={editingTest} onSave={upd=>{setTests(p=>p.map(t=>t.id===upd.id?upd:t));setEditingTest(null);}} onClose={()=>setEditingTest(null)}/>}

      {/* TOPBAR */}
      <div style={{display:"flex",alignItems:"center",gap:DS.space.sm,padding:`0 ${DS.space.md}px`,height:48,background:topGradient,flexShrink:0,boxShadow:DS.shadow.B1}}>
        <button onClick={()=>setAppMode("home")} style={{background:"none",border:"none",cursor:"pointer",display:"flex",alignItems:"center",gap:6,padding:0}}>
          <GitBranch size={16} style={{color:c.white,opacity:0.9}}/>
          <span style={{fontSize:18,fontWeight:800,color:c.white,letterSpacing:-0.3,textShadow:"0 1px 4px rgba(0,0,0,0.2)"}}>FlowTester</span>
        </button>

        {/* MODE PILLS — solo visibles dentro de Comparativo (no en inicio ni en testeo) */}
        {appMode==="compare"&&<div style={{display:"flex",gap:4,background:"rgba(0,0,0,0.2)",borderRadius:DS.radius.full,padding:"3px 5px"}}>
          <button onClick={()=>setAppMode("sessions")} style={{display:"flex",alignItems:"center",gap:4,padding:`4px ${DS.space.sm}px`,fontSize:11,border:"none",borderRadius:DS.radius.full,background:appMode==="sessions"?"rgba(255,255,255,0.25)":"none",color:c.white,cursor:"pointer",fontFamily:DS.font,fontWeight:appMode==="sessions"?700:400}}>
            <BarChart2 size={11}/>Resultados
          </button>
        </div>}

        <div style={{flex:1}}/>

        {/* TEST TABS — solo en compare */}
        {appMode==="compare"&&<div style={{display:"flex",gap:2,background:"rgba(0,0,0,0.18)",borderRadius:DS.radius.sm,padding:3}}>
          {tests.filter(t=>!hiddenChannels.includes(t.type)).map(t=>(
            <div key={t.id} style={{display:"flex",alignItems:"center"}}>
              <button onClick={()=>setTid(t.id)} style={{display:"flex",alignItems:"center",gap:4,padding:`4px ${DS.space.sm}px`,fontSize:11,border:"none",borderRadius:DS.radius.xs,background:tid===t.id?"rgba(255,255,255,0.22)":"none",color:c.white,cursor:"pointer",fontFamily:DS.font,fontWeight:tid===t.id?700:400}}>
                {TI[t.type]}{t.name}
              </button>
              {isAdmin&&<button onClick={()=>setEditingTest(t)} style={{padding:"2px 3px",border:"none",background:"none",color:"rgba(255,255,255,0.45)",cursor:"pointer",display:"flex",alignItems:"center"}}><Edit3 size={9}/></button>}
            </div>
          ))}
          <button onClick={()=>setShowTests(true)} style={{padding:`3px ${DS.space.xs}px`,border:"none",background:"none",color:"rgba(255,255,255,0.45)",cursor:"pointer",display:"flex",alignItems:"center"}}><BookOpen size={13}/></button>
        </div>}

        {/* VOICE — el audio de IVR/Voicebot siempre está activo, sin interruptor */}

        {isAdmin&&appMode==="compare"&&<>
          <button onClick={()=>setEditMode(e=>!e)} style={{display:"flex",alignItems:"center",gap:4,padding:`5px ${DS.space.sm}px`,fontSize:12,border:`1px solid ${editMode?"#fff":"rgba(255,255,255,0.3)"}`,borderRadius:DS.radius.sm,background:editMode?"rgba(255,255,255,0.2)":"none",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:700}}>
            <Edit3 size={12}/>{editMode?"Editando":"Editar"}
          </button>
          <button onClick={()=>setShowSave(true)} style={{display:"flex",alignItems:"center",gap:4,padding:`5px ${DS.space.sm}px`,fontSize:12,border:"1px solid rgba(255,255,255,0.35)",borderRadius:DS.radius.sm,background:"rgba(255,255,255,0.15)",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:700}}>
            <Save size={12}/>Guardar
          </button>
          <button onClick={markActiveForTesting} title="Este será el flujo que verán los testers en Modo Testeo" style={{display:"flex",alignItems:"center",gap:3,padding:"4px 9px",fontSize:11,border:`1px solid ${tid===activeTestId?DS.color.success:"rgba(255,255,255,0.35)"}`,borderRadius:DS.radius.sm,background:tid===activeTestId?"rgba(53,199,89,0.28)":"rgba(255,255,255,0.15)",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:700,whiteSpace:"nowrap"}}>
            <FlaskConical size={11}/>{tid===activeTestId?"✓ Testeo":"Usar en Testeo"}
          </button>
          <button onClick={restoreDefaults} title="Si un flujo quedó mal guardado, esto lo restablece a la versión original de fábrica" style={{display:"flex",alignItems:"center",gap:3,padding:"4px 9px",fontSize:11,border:"1px solid rgba(255,255,255,0.35)",borderRadius:DS.radius.sm,background:"rgba(255,255,255,0.1)",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:700,whiteSpace:"nowrap"}}>
            <RotateCcw size={11}/>Restaurar flujos
          </button>
          <button onClick={()=>setShowChannels(true)} title="Mostrar u ocultar canales completos (IVR, Chatbot, Voicebot, WhatsApp)" style={{display:"flex",alignItems:"center",gap:3,padding:"4px 9px",fontSize:11,border:"1px solid rgba(255,255,255,0.35)",borderRadius:DS.radius.sm,background:"rgba(255,255,255,0.1)",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:700,whiteSpace:"nowrap"}}>
            <Eye size={11}/>Canales{hiddenChannels.length>0&&` (${hiddenChannels.length} oculto${hiddenChannels.length>1?"s":""})`}
          </button>
        </>}

        {/* USER — solo en Comparativo (única sección que exige sesión); solo se muestra la foto de perfil */}
        {appMode==="compare"&&(user?(
          <button onClick={()=>setShowUserMenu(s=>!s)} title={user.name} style={{display:"flex",alignItems:"center",padding:2,border:"1px solid rgba(255,255,255,0.25)",borderRadius:DS.radius.full,background:"rgba(255,255,255,0.1)",cursor:"pointer"}}>
            <div style={{width:26,height:26,borderRadius:DS.radius.full,background:user.color+"44",border:`2px solid ${user.color}`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:9,fontWeight:800,color:c.white,overflow:"hidden"}}>{user.photo?<img src={user.photo} alt={user.name} style={{width:"100%",height:"100%",objectFit:"cover"}}/>:user.initials}</div>
          </button>
        ):(
          <button onClick={()=>setAppMode("compare")} style={{display:"flex",alignItems:"center",gap:5,padding:`5px ${DS.space.sm}px`,border:"1px solid rgba(255,255,255,0.3)",borderRadius:DS.radius.sm,background:"rgba(255,255,255,0.12)",cursor:"pointer",color:c.white,fontFamily:DS.font,fontWeight:600,fontSize:11}}>
            <LogIn size={12}/>Iniciar sesión
          </button>
        ))}
      </div>

      {/* USER MENU — solo el usuario actual */}
      {showUserMenu&&user&&(<>
        <div style={{position:"fixed",inset:0,zIndex:8888}} onClick={()=>setShowUserMenu(false)}/>
        <div style={{position:"fixed",top:52,right:DS.space.md,zIndex:9999,minWidth:220,overflow:"hidden",boxShadow:DS.shadow.B2,borderRadius:DS.radius.md,border:`1px solid ${c.neutral200}`,background:c.white,fontFamily:DS.font}}>
          <div style={{padding:`${DS.space.sm}px ${DS.space.md}px`,borderBottom:`1px solid ${c.neutral200}`,background:c.cyan50}}>
            <div style={{display:"flex",alignItems:"center",gap:DS.space.sm}}>
              <div style={{width:36,height:36,borderRadius:DS.radius.full,background:user.color+"22",border:`2px solid ${user.color}`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:800,color:user.color}}>{user.initials}</div>
              <div><div style={{fontSize:13,fontWeight:700,color:c.deepBlue}}>{user.name}</div><div style={{fontSize:10,color:c.neutral400}}>{user.role}{isAdmin&&" · Admin"}</div></div>
            </div>
          </div>
          <button onClick={()=>{setUser(null);setShowUserMenu(false);setEditMode(false);window.speechSynthesis?.cancel();setAppMode("home");}} style={{display:"flex",alignItems:"center",gap:DS.space.xs,width:"100%",padding:`${DS.space.sm}px ${DS.space.md}px`,background:"none",border:"none",cursor:"pointer",color:c.error,fontSize:13,fontFamily:DS.font,fontWeight:700}}><LogIn size={13}/>Cerrar sesión</button>
        </div>
      </>)}

      {/* VOICE BAR */}
      {appMode==="compare"&&showVoice&&(
        <div style={{padding:`5px ${DS.space.md}px`,borderBottom:`1px solid ${c.cyan100}`,background:c.cyan50,display:"flex",alignItems:"center",gap:DS.space.sm,flexShrink:0,flexWrap:"wrap"}}>
          <Volume2 size={12} style={{color:c.midBlue}}/>
          <span style={{fontSize:11,color:c.midBlue,fontWeight:700}}>Voz:</span>
          {voiceList.length?(
            <select value={voiceName||voiceList[0]?.name||""} onChange={e=>{setVoiceName(e.target.value);saveSharedJSON(VOICE_PROFILE_KEY,e.target.value);}} style={{fontSize:11,padding:"3px 8px",border:`1px solid ${c.cyan200}`,borderRadius:DS.radius.sm,background:c.white,color:c.midBlue,fontFamily:DS.font,fontWeight:600,maxWidth:220}}>
              {voiceList.map(v=><option key={v.name} value={v.name}>{v.name}{v.lang?` (${v.lang})`:""}</option>)}
            </select>
          ):<span style={{fontSize:11,color:c.neutral400}}>No se encontraron voces en este navegador</span>}
          <button onClick={()=>speak("Hola, así sonará esta voz durante la prueba.",voiceName||voiceList[0]?.name)} disabled={!voiceList.length} style={{fontSize:10,padding:"3px 10px",border:`1px solid ${c.midBlue}`,borderRadius:DS.radius.full,background:c.white,color:c.midBlue,cursor:voiceList.length?"pointer":"default",fontFamily:DS.font,fontWeight:700,display:"flex",alignItems:"center",gap:4,opacity:voiceList.length?1:0.5}}><Play size={10}/>Probar</button>
          <span style={{fontSize:10,color:c.neutral400,marginLeft:"auto"}}>🔊 El audio siempre está activo para IVR y Voicebot</span>
        </div>
      )}

      {appMode==="compare"&&!isAdmin&&<div style={{background:c.warningLight,borderBottom:`1px solid ${c.warning}`,padding:`4px ${DS.space.md}px`,display:"flex",alignItems:"center",gap:6,flexShrink:0}}><AlertCircle size={12} style={{color:"#7A4F00"}}/><span style={{fontSize:11,color:"#7A4F00",fontWeight:600}}>Solo lectura — solo el Administrador puede editar flujos</span></div>}

      {/* MAIN CONTENT */}
      <div style={{flex:1,overflow:"hidden",display:"flex",flexDirection:"column"}}>
        {appMode==="home"&&<HomeScreen onSelect={setAppMode}/>}

        {appMode==="sessions"&&<SessionsPanel/>}

        {appMode==="tester"&&(()=>{
          const activeTest=tests.find(t=>t.id===activeTestId)||tests[0];
          const activeAvatar=avatars[activeTest?.id]?.["proposed"]||null;
          const channelHidden=activeTest&&hiddenChannels.includes(activeTest.type);
          if(!activeTest||channelHidden){
            return(
              <div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",background:`linear-gradient(135deg,${c.deepBlue},${c.midBlue})`,padding:DS.space.lg}}>
                <Card style={{maxWidth:340,textAlign:"center"}}>
                  <EyeOff size={26} style={{color:c.neutral400,marginBottom:DS.space.sm}}/>
                  <h2 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:16,fontWeight:700,color:c.deepBlue}}>No hay flujo disponible</h2>
                  <p style={{fontSize:12,color:c.neutral700,lineHeight:1.6}}>El canal de este flujo está oculto temporalmente. Pide al Administrador que lo haga visible desde Comparativo.</p>
                </Card>
              </div>
            );
          }
          return(
            <div style={{flex:1,overflow:"hidden"}}>
              <TesterMode key={activeTest?.id} test={activeTest} avatar={activeAvatar} onGoHome={()=>setAppMode("home")}/>
            </div>
          );
        })()}

        {appMode==="compare"&&test&&(
          <div style={{flex:1,display:"flex",overflow:"hidden"}}>
            {[{side:"current",label:"Flujo Actual",dot:c.error,txt:c.error,bg:c.errorLight},{side:"proposed",label:"Propuesta",dot:c.success,txt:c.success,bg:c.successLight}].map(({side,label,dot,txt,bg},idx)=>(
              <div key={side} style={{flex:1,borderRight:idx===0?`1px solid ${c.neutral200}`:"none",overflow:"hidden",display:"flex",flexDirection:"column"}}>
                <div style={{padding:`5px ${DS.space.sm}px`,background:bg+"55",borderBottom:`1px solid ${c.neutral200}`,flexShrink:0,display:"flex",alignItems:"center",gap:DS.space.xs}}>
                  <div style={{width:7,height:7,borderRadius:DS.radius.full,background:dot}}/>
                  <span style={{fontSize:11,fontWeight:700,color:txt}}>{label}</span>
                  <span style={{fontSize:10,color:dot,opacity:0.7}}>{test[side].nodes.length} nodos</span>
                </div>
                <div style={{flex:1,overflow:"hidden"}}>
                  <FlowPanel testType={test.type} nodes={test[side].nodes} setNodes={u=>setNodes(side,u)} editMode={editMode} canEdit={isAdmin} timer={idx===0?timerL:timerR} voiceProfile={voiceName} voiceOn={true} avatar={getAvatar(side)} onAvatarChange={url=>setAvatar(side,url)} testName={`${test.name}_${side}`}/>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* TESTS MODAL */}
      {showTests&&(
        <Overlay onClose={()=>setShowTests(false)}>
          <Card style={{width:440,maxHeight:"80vh",overflowY:"auto"}}>
            <div style={{display:"flex",alignItems:"center",marginBottom:DS.space.md}}>
              <BookOpen size={14} style={{marginRight:DS.space.xs,color:c.midBlue}}/>
              <h3 style={{margin:0,fontSize:16,fontWeight:700,color:c.deepBlue}}>Repositorio de Tests</h3>
              <span style={{marginLeft:"auto",fontSize:11,color:c.neutral400}}>{tests.filter(t=>!hiddenChannels.includes(t.type)).length} tests</span>
              <button onClick={()=>setShowTests(false)} style={{background:"none",border:"none",cursor:"pointer",color:c.neutral400,marginLeft:DS.space.sm}}><X size={15}/></button>
            </div>
            {tests.filter(t=>!hiddenChannels.includes(t.type)).map(t=>{const th2=TYPE_THEME[t.type]||TYPE_THEME.IVR;return(
              <div key={t.id} onClick={()=>{setTid(t.id);setShowTests(false);}} style={{border:`${tid===t.id?`2px solid ${c.brightBlue}`:`1px solid ${c.neutral200}`}`,borderRadius:DS.radius.sm,padding:`${DS.space.sm}px ${DS.space.md}px`,marginBottom:DS.space.xs,background:tid===t.id?c.cyan50:c.white,cursor:"pointer",boxShadow:DS.shadow.A1}}>
                <div style={{display:"flex",alignItems:"center",gap:DS.space.xs}}>
                  <span style={{fontSize:12,fontWeight:700,color:tid===t.id?c.deepBlue:c.neutral700,flex:1}}>{t.name}</span>
                  <Tag label={t.type} color={th2.accentDark}/>
                  {tid===t.id&&<CheckCircle size={13} style={{color:c.brightBlue}}/>}
                  {isAdmin&&<button onClick={e=>{e.stopPropagation();setEditingTest(t);setShowTests(false);}} style={{background:"none",border:"none",cursor:"pointer",color:c.neutral400,padding:3}}><Edit3 size={11}/></button>}
                  {isAdmin&&tests.length>1&&<button onClick={e=>{e.stopPropagation();const r=tests.filter(x=>x.id!==t.id);setTests(r);if(tid===t.id)setTid(r[0].id);}} style={{background:"none",border:"none",cursor:"pointer",color:c.error,padding:3}}><Trash2 size={11}/></button>}
                </div>
                <p style={{fontSize:11,color:c.neutral400,margin:`3px 0 ${DS.space.xs}px`}}>{t.description}</p>
              </div>
            );})}
          </Card>
        </Overlay>
      )}

      {/* CANALES MODAL */}
      {showChannels&&(
        <Overlay onClose={()=>setShowChannels(false)}>
          <Card style={{width:360}}>
            <div style={{display:"flex",alignItems:"center",marginBottom:DS.space.sm}}>
              <Eye size={14} style={{marginRight:DS.space.xs,color:c.midBlue}}/>
              <h3 style={{margin:0,fontSize:16,fontWeight:700,color:c.deepBlue}}>Canales visibles</h3>
              <button onClick={()=>setShowChannels(false)} style={{background:"none",border:"none",cursor:"pointer",color:c.neutral400,marginLeft:"auto"}}><X size={15}/></button>
            </div>
            <p style={{fontSize:11,color:c.neutral400,margin:`0 0 ${DS.space.md}px`,lineHeight:1.5}}>Oculta por completo un canal (y todos sus tests) de las pestañas, el repositorio y Testeo — útil si aún no está listo para mostrarse.</p>
            {presentChannels.map(ch=>{
              const hidden=hiddenChannels.includes(ch);
              const th2=TYPE_THEME[ch]||TYPE_THEME.IVR;
              return(
                <div key={ch} style={{display:"flex",alignItems:"center",gap:DS.space.sm,padding:`${DS.space.xs}px ${DS.space.sm}px`,border:`1px solid ${c.neutral200}`,borderRadius:DS.radius.sm,marginBottom:DS.space.xs,background:hidden?c.neutral100:c.white}}>
                  <span style={{width:22,textAlign:"center"}}>{TI[ch]}</span>
                  <span style={{fontSize:13,fontWeight:600,color:hidden?c.neutral400:c.deepBlue,flex:1}}>{ch}</span>
                  <button onClick={()=>toggleChannel(ch)} style={{display:"flex",alignItems:"center",gap:4,fontSize:11,padding:"4px 10px",borderRadius:DS.radius.full,border:`1px solid ${hidden?c.neutral400:c.success}`,background:hidden?c.neutral200:c.successLight,color:hidden?c.neutral700:"#1A4D2E",cursor:"pointer",fontFamily:DS.font,fontWeight:700}}>
                    {hidden?<><EyeOff size={11}/>Oculto</>:<><Eye size={11}/>Visible</>}
                  </button>
                </div>
              );
            })}
          </Card>
        </Overlay>
      )}

      {/* SAVE MODAL */}
      {showSave&&(
        <Overlay onClose={()=>setShowSave(false)}>
          <Card style={{width:330}}>
            <h3 style={{margin:`0 0 ${DS.space.xs}px`,fontSize:16,fontWeight:700,color:c.deepBlue}}>Guardar nueva versión</h3>
            <p style={{fontSize:12,color:c.neutral400,marginBottom:DS.space.sm}}>El test actual se duplica.</p>
            <input value={saveName} onChange={e=>setSaveName(e.target.value)} onKeyDown={e=>e.key==="Enter"&&saveNew()} placeholder="Ej. Autenticación v2" style={{width:"100%",marginBottom:DS.space.md,boxSizing:"border-box",border:`1px solid ${c.neutral300}`,borderRadius:DS.radius.sm,color:c.deepBlue,padding:`${DS.space.xs}px`,fontFamily:DS.font}}/>
            <div style={{display:"flex",gap:DS.space.xs,justifyContent:"flex-end"}}>
              <Btn variant="ghost" onClick={()=>setShowSave(false)}>Cancelar</Btn>
              <Btn variant="success" onClick={saveNew}><Save size={11}/>Guardar</Btn>
            </div>
          </Card>
        </Overlay>
      )}
    </div>
  );
}

/* ── Polyfill de window.storage usando localStorage (ver README) ── */
(function () {
  const NS = "flowtester_storage_v1";
  function readAll() {
    try { return JSON.parse(localStorage.getItem(NS) || "{}"); } catch { return {}; }
  }
  function writeAll(data) { localStorage.setItem(NS, JSON.stringify(data)); }
  window.storage = {
    async get(key) {
      const all = readAll();
      if (!(key in all)) return null;
      return { key, value: all[key], shared: false };
    },
    async set(key, value) {
      const all = readAll();
      all[key] = value;
      writeAll(all);
      return { key, value, shared: false };
    },
    async delete(key) {
      const all = readAll();
      if (!(key in all)) return null;
      delete all[key];
      writeAll(all);
      return { key, deleted: true, shared: false };
    },
    async list(prefix) {
      const all = readAll();
      const keys = Object.keys(all).filter((k) => !prefix || k.startsWith(prefix));
      return { keys, prefix, shared: false };
    },
  };
})();

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
