// Maqueta · sincronización directa del equipo (Piixi-team), 12 estados con barras animadas.
// Reemplaza el modelo «publicar / revisar cada 5 minutos» (archivado en
// _archive/sincronizacion-por-nube-2026-10-10/). Sin imports: scripts clásicos.
// useState/useEffect/useRef vienen de primitives.jsx.

const EQS_POLIZAS = 2855;
const EQS_MB = 640;
const eqsN = (n) => Math.round(n).toLocaleString('es-MX');

// Avance simulado: sube `paso` cada `ms`. Al llegar a 1 llama alTerminar (o reinicia si `ciclo`).
function eqsUseAvance({ pausa, paso, ms, ciclo, alTerminar }) {
  const [t, setT] = useState(0);
  const cb = useRef(alTerminar);
  cb.current = alTerminar;
  useEffect(() => { if (!pausa) setT((x) => (x >= 1 ? 0 : x)); }, [pausa]);
  useEffect(() => {
    if (pausa) return undefined;
    const id = setInterval(() => {
      setT((x) => {
        if (x >= 1) return ciclo ? 0 : 1;
        const n = Math.min(1, x + paso);
        if (n >= 1 && cb.current) setTimeout(() => cb.current && cb.current(), 600);
        return n;
      });
    }, ms);
    return () => clearInterval(id);
  }, [pausa, paso, ms, ciclo]);
  return t;
}

function EqsBarra({ valor, indet, delgada, quieta }) {
  const h = delgada ? 3 : 8;
  return (
    <div style={{ height: h, borderRadius: h, background: 'var(--ax-bg-4)', overflow: 'hidden', position: 'relative' }}>
      {indet ? (
        <div className="eqs-indet" style={{ position: 'absolute', top: 0, bottom: 0, width: '35%', background: 'var(--ax-accent)', borderRadius: h }} />
      ) : (
        <div style={{ height: '100%', width: Math.round((valor || 0) * 100) + '%', background: quieta ? 'var(--ax-fg-faint)' : 'var(--ax-accent)', borderRadius: h, transition: 'width 380ms linear' }} />
      )}
    </div>
  );
}

function EqsParte({ etiqueta, detalle, valor, quieta }) {
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: 'var(--ax-fg-strong)', marginBottom: 6 }}>
        <span>{etiqueta}</span>
        <span className="ax-mono" style={{ color: 'var(--ax-fg-muted)' }}>{detalle}</span>
      </div>
      <EqsBarra valor={valor} quieta={quieta} />
    </div>
  );
}

// Barra superior de la computadora del miembro
function EqsBarraSuperior({ texto, sub, icono, spinner, progreso, indet, quieta }) {
  return (
    <div data-eqs="barra-superior" style={{ background: 'var(--ax-bg-2)', border: '1px solid var(--ax-border)', borderRadius: 8, overflow: 'hidden' }}>
      <div style={{ height: 56, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 20px', gap: 16 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--ax-fg-muted)', fontSize: 13 }}>
          <AxIcon name="search" size={15} /> Buscar póliza, cliente…
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, textAlign: 'right' }}>
          {spinner && <span className="ax-spinner" style={{ width: 12, height: 12 }} />}
          {icono && <AxIcon name={icono} size={14} />}
          <div>
            <div className="ax-mono" style={{ fontSize: 11, letterSpacing: '0.06em', color: 'var(--ax-fg-strong)' }}>{texto}</div>
            {sub && <div style={{ fontSize: 11, color: 'var(--ax-fg-faint)', marginTop: 2 }}>{sub}</div>}
          </div>
        </div>
      </div>
      {(progreso != null || indet) ? <EqsBarra valor={progreso} indet={indet} delgada quieta={quieta} /> : <div style={{ height: 3 }} />}
    </div>
  );
}

function EqsTarjeta({ titulo, cuerpo, acciones, children }) {
  return (
    <div data-eqs="tarjeta" style={{ background: 'var(--ax-bg-2)', border: '1px solid var(--ax-border)', borderRadius: 10, padding: 20 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 16 }}>
        <div>
          <AxEyebrow>Ajustes › Equipo</AxEyebrow>
          <div style={{ fontSize: 18, color: 'var(--ax-fg-strong)', marginTop: 6 }}>{titulo}</div>
          {cuerpo && <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)', marginTop: 6, maxWidth: 560, lineHeight: 1.5 }}>{cuerpo}</div>}
        </div>
        {acciones}
      </div>
      {children && <div style={{ marginTop: 18, display: 'flex', flexDirection: 'column', gap: 14 }}>{children}</div>}
    </div>
  );
}

function EqsNota({ children }) {
  return <div style={{ fontSize: 12, color: 'var(--ax-fg-faint)', lineHeight: 1.5 }}>{children}</div>;
}

const EQS_DIRECTO = 'Tus datos viajan directo desde la computadora principal; no pasan por la nube de Piixi.';
const EQS_CIFRADA = 'Cifrada en tu computadora: ni Piixi ni el proveedor de la nube pueden leerla.';
const EQS_AMBAS = 'Llega directo desde la computadora principal. Si no se alcanzan, por la nube, cifrada en tu computadora: ni Piixi ni el proveedor de la nube pueden leerla.';
const eqsNota = (via) => (via === 'nube' ? EQS_CIFRADA : via === 'ambas' ? EQS_AMBAS : EQS_DIRECTO);

// ── 1. Primera copia ────────────────────────────────────────────────────────
function EqsPrimera({ via }) {
  const nube = via === 'nube';
  const [pausa, setPausa] = useState(false);
  const t = eqsUseAvance({ pausa, paso: 0.012, ms: 400, ciclo: true });
  const pol = 0.434 + 0.566 * t;
  const pdf = 0.144 + 0.856 * t;
  const gen = (pol + pdf) / 2;
  const pct = Math.round(gen * 100);
  const min = Math.max(1, Math.ceil((1 - t) * 8));
  const boton = (
    <AxButton variant="secondary" icon={pausa ? 'refresh' : 'x'} onClick={() => setPausa(!pausa)}>
      {pausa ? 'Simular que vuelven a coincidir' : 'Simular interrupción'}
    </AxButton>
  );
  return (
    <>
      <EqsBarraSuperior
        texto={pausa ? 'PRIMERA COPIA PAUSADA · ' + pct + ' %' : (nube ? 'DESCARGANDO DESDE LA NUBE · ' : via === 'ambas' ? 'COPIANDO DIRECTO · ' : 'COPIANDO LA CARTERA · ') + pct + ' %'}
        sub={pausa ? 'Sigue sola cuando las dos vuelvan a coincidir' : 'Quedan unos ' + min + ' min · puedes seguir trabajando'}
        spinner={!pausa} icono={pausa ? 'alert' : null} progreso={gen} quieta={pausa} />
      <EqsTarjeta
        titulo={pausa ? 'La primera copia se interrumpió' : 'Haciendo tu primera copia'}
        cuerpo={pausa ? 'Se quedó en ' + pct + ' %; sigue sola cuando las dos vuelvan a coincidir.' : (nube ? 'Estamos descargando la cartera desde la nube, cifrada. No hace falta que la computadora principal esté encendida.' : 'Estamos trayendo la cartera directo desde la computadora principal.')}
        acciones={boton}>
        <div>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, color: 'var(--ax-fg-strong)', marginBottom: 6 }}>
            <span>Avance general</span><span className="ax-mono">{pct} %</span>
          </div>
          <EqsBarra valor={gen} quieta={pausa} />
        </div>
        <EqsParte etiqueta="Pólizas" detalle={eqsN(EQS_POLIZAS * pol) + ' de ' + eqsN(EQS_POLIZAS)} valor={pol} quieta={pausa} />
        <EqsParte etiqueta="PDFs" detalle={eqsN(EQS_POLIZAS * pdf) + ' de ' + eqsN(EQS_POLIZAS) + ' · ' + eqsN(EQS_MB * pdf) + ' MB de ' + EQS_MB + ' MB'} valor={pdf} quieta={pausa} />
        <EqsNota>{pausa ? 'Nada se pierde: lo que ya llegó se queda en esta computadora.' : 'Tiempo restante estimado: unos ' + min + ' min. Puedes seguir trabajando.'} {eqsNota(via)}</EqsNota>
      </EqsTarjeta>
    </>
  );
}

// ── 2. Sincronizado ─────────────────────────────────────────────────────────
function EqsSincronizado({ via }) {
  const nube = via === 'nube';
  const amb = via === 'ambas';
  const [recibiendo, setRecibiendo] = useState(true);
  const t = eqsUseAvance({ pausa: !recibiendo, paso: 0.05, ms: 500, ciclo: false, alTerminar: () => setRecibiendo(false) });
  const pct = Math.round(t * 100);
  return (
    <>
      <EqsBarraSuperior
        texto={recibiendo ? (nube ? 'DESCARGANDO DESDE LA NUBE · ' + pct + ' %' : amb ? 'RECIBIENDO DIRECTO · ' + pct + ' %' : 'RECIBIENDO 3 PDFs NUEVOS · ' + pct + ' %') : (amb ? 'SINCRONIZADO DIRECTO · HACE UN MOMENTO' : 'SINCRONIZADO · HACE UN MOMENTO')}
        spinner={recibiendo} icono={recibiendo ? null : 'check'} progreso={recibiendo ? t : null} />
      <EqsTarjeta
        titulo={recibiendo ? (nube ? 'Descargando desde la nube · ' + pct + ' %' : amb ? 'Recibiendo directo · ' + pct + ' %' : 'Recibiendo 3 PDFs nuevos · ' + pct + ' %') : (amb ? 'Sincronizado directo · hace un momento' : 'Sincronizado · hace un momento')}
        cuerpo={nube ? 'La computadora principal sube lo nuevo a la nube y esta computadora lo baja sola, en los dos sentidos.' : 'Cuando las dos computadoras están abiertas y se alcanzan, se sincronizan solas en segundos, en los dos sentidos.'}
        acciones={<AxButton variant="secondary" icon="refresh" disabled={recibiendo} onClick={() => setRecibiendo(true)}>Simular llegada de PDFs nuevos</AxButton>}>
        {recibiendo ? <EqsParte etiqueta="PDFs nuevos" detalle={Math.min(3, Math.floor(t * 3)) + ' de 3 · ' + pct + ' %'} valor={t} /> : <EqsNota>Todo al día. Tus cambios también viajan solos hacia la computadora principal.</EqsNota>}
        <EqsNota>{eqsNota(via)}</EqsNota>
      </EqsTarjeta>
    </>
  );
}

// ── 3. Computadora principal fuera de línea ─────────────────────────────────
const EQS_CAMBIOS = [
  { t: 'Nota nueva en la póliza de Ana Torres Ruiz', h: '9:52 a.m.' },
  { t: 'Teléfono corregido en la ficha de Luis Herrera Paz', h: '10:15 a.m.' },
  { t: 'Recibo marcado como pagado · póliza de Marta Solís', h: '10:31 a.m.' },
];
function EqsFuera({ via }) {
  const amb = via === 'ambas';
  const nube = via === 'nube' || amb;
  const [fase, setFase] = useState('fuera'); // fuera | bajando | enviando | listo
  const tb = eqsUseAvance({ pausa: fase !== 'bajando', paso: 0.05, ms: 400, ciclo: false, alTerminar: () => setFase('fuera') });
  const pb = Math.round(tb * 100);
  const t = eqsUseAvance({ pausa: fase !== 'enviando', paso: 0.04, ms: 300, ciclo: false, alTerminar: () => setFase('listo') });
  const n = Math.min(3, Math.floor(t * 3) + 1);
  const hechos = fase === 'listo' ? 3 : fase === 'enviando' ? n - 1 : 0;
  const texto = fase === 'bajando' ? 'DESCARGANDO DESDE LA NUBE · ' + pb + ' %' : fase === 'fuera' ? (amb ? 'LLEGÓ POR LA NUBE, CIFRADA · AL CORTE DE LAS 9:40 A.M.' : nube ? 'AL CORTE DE LAS 9:40 A.M. · LA PRINCIPAL NO HA SUBIDO NADA NUEVO' : 'LA COMPUTADORA PRINCIPAL NO ESTÁ EN LÍNEA') : fase === 'enviando' ? 'ENVIANDO TUS CAMBIOS · ' + n + ' DE 3' : 'SINCRONIZADO · HACE UN MOMENTO';
  return (
    <>
      <EqsBarraSuperior texto={texto}
        sub={fase === 'fuera' || fase === 'bajando' ? (amb ? 'No se alcanzaron directo; se usó la nube · 3 cambios tuyos esperando a que la principal los aplique' : nube ? 'La principal está apagada · 3 cambios tuyos esperando a que los aplique' : 'Trabajas con la copia de las 9:40 a.m. · 3 cambios tuyos esperando') : null}
        spinner={fase === 'enviando' || fase === 'bajando'} icono={fase === 'fuera' ? 'alert' : fase === 'listo' ? 'check' : null}
        progreso={fase === 'enviando' ? t : fase === 'bajando' ? tb : null} />
      <EqsTarjeta
        titulo={fase === 'bajando' ? 'Descargando desde la nube · ' + pb + ' %' : fase === 'fuera' ? (amb ? 'Llegó por la nube, cifrada · al corte de las 9:40 a.m.' : nube ? 'Al corte de las 9:40 a.m. · la principal no ha subido nada nuevo' : 'La computadora principal no está en línea') : fase === 'enviando' ? 'Enviando tus cambios · ' + n + ' de 3' : 'Tus 3 cambios ya llegaron'}
        cuerpo={fase === 'bajando' ? 'La principal subió esto antes de apagarse. Lo recibes aunque ya no esté en línea.' : fase === 'fuera' ? (amb ? 'No se alcanzaron directo; se usó la nube. La principal está apagada, pero tienes lo último que subió, cifrado. Puedes seguir viendo, descargando y escribiendo: tus cambios esperan a que la principal los aplique.' : nube ? 'La principal está apagada, pero tienes lo último que subió a la nube. Puedes seguir viendo, descargando y escribiendo: tus cambios esperan a que la principal los aplique.' : 'Trabajas con la copia de las 9:40 a.m. Puedes seguir viendo, descargando y escribiendo: tus cambios se guardan aquí y viajan cuando las dos coincidan en línea.') : fase === 'enviando' ? 'La computadora principal volvió. Estamos enviando lo que hiciste mientras no estaba.' : 'La computadora principal ya los tiene.'}
        acciones={<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          <AxButton variant="secondary" icon="refresh" onClick={() => setFase(fase === 'fuera' ? 'enviando' : 'fuera')} disabled={fase === 'enviando' || fase === 'bajando'}>{fase === 'fuera' ? 'Simular que vuelve la principal' : 'Volver a simular'}</AxButton>
          {nube && <AxButton variant="tertiary" icon="refresh" onClick={() => setFase('bajando')} disabled={fase !== 'fuera'}>Simular descarga de lo último subido</AxButton>}
        </div>}>
        {fase === 'bajando' && <EqsParte etiqueta="Descargando desde la nube" detalle={pb + ' %'} valor={tb} />}
        {fase === 'enviando' && <EqsParte etiqueta="Enviando tus cambios" detalle={n + ' de 3'} valor={t} />}
        {nube && <EqsNota>{EQS_CIFRADA}</EqsNota>}
        <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8 }}>
          <div style={{ padding: '10px 14px', borderBottom: '1px solid var(--ax-border)' }}><AxEyebrow>{fase === 'listo' ? 'Cambios enviados' : '3 cambios tuyos esperando'}</AxEyebrow></div>
          {EQS_CAMBIOS.map((c, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', borderTop: i ? '1px solid var(--ax-border)' : 'none' }}>
              <span style={{ width: 16, display: 'flex' }}>{i < hechos ? <AxIcon name="check" size={13} /> : fase === 'enviando' && i === hechos ? <span className="ax-spinner" style={{ width: 11, height: 11 }} /> : null}</span>
              <div style={{ flex: 1, fontSize: 13, color: 'var(--ax-fg-strong)' }}>{c.t}</div>
              <span className="ax-mono" style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>{c.h}</span>
            </div>
          ))}
        </div>
      </EqsTarjeta>
    </>
  );
}

// ── 4. En línea, sin conexión directa ───────────────────────────────────────
function EqsSinDirecta({ via }) {
  if (via === 'ambas') return <EqsSinDirectaAmbas />;
  const [busca, setBusca] = useState(false);
  const [intentos, setIntentos] = useState(0);
  const tm = useRef(null);
  useEffect(() => () => clearTimeout(tm.current), []);
  const reintentar = () => {
    setBusca(true);
    tm.current = setTimeout(() => { setBusca(false); setIntentos((x) => x + 1); }, 5000);
  };
  return (
    <>
      <EqsBarraSuperior
        texto={busca ? 'BUSCANDO A LA COMPUTADORA PRINCIPAL…' : 'SIN CONEXIÓN DIRECTA CON LA PRINCIPAL'}
        sub={busca ? null : 'Trabajas con tu copia · tus cambios esperan'} spinner={busca} icono={busca ? null : 'alert'} indet={busca} />
      <EqsTarjeta
        titulo="La computadora principal está en línea, pero esta red no permite conectarse directo"
        cuerpo="Se sincroniza cuando estén en la misma red, por ejemplo el Wi-Fi de la oficina."
        acciones={<AxButton variant="primary" icon="refresh" loading={busca} disabled={busca} onClick={reintentar}>{busca ? 'Reintentando…' : 'Reintentar'}</AxButton>}>
        {busca && (
          <div>
            <div style={{ fontSize: 12, color: 'var(--ax-fg-strong)', marginBottom: 6 }}>Buscando a la computadora principal…</div>
            <EqsBarra indet />
          </div>
        )}
        {!busca && intentos > 0 && <EqsNota>Sigue sin conexión directa (intento {intentos}). Prueba de nuevo desde el Wi-Fi de la oficina.</EqsNota>}
        <EqsNota>Los datos del despacho no se mandan por la nube de Piixi, así que sin conexión directa no se sincroniza a distancia. Mientras tanto puedes seguir trabajando: tus cambios se guardan y viajan después.</EqsNota>
      </EqsTarjeta>
    </>
  );
}

function EqsSinDirectaAmbas() {
  const [busca, setBusca] = useState(false);
  const [intentos, setIntentos] = useState(0);
  const [bajando, setBajando] = useState(true);
  const tb = eqsUseAvance({ pausa: !bajando, paso: 0.05, ms: 400, ciclo: false, alTerminar: () => setBajando(false) });
  const tm = useRef(null);
  useEffect(() => () => clearTimeout(tm.current), []);
  const reintentar = () => {
    setBusca(true);
    tm.current = setTimeout(() => { setBusca(false); setIntentos((x) => x + 1); }, 5000);
  };
  const pb = Math.round(tb * 100);
  return (
    <>
      <EqsBarraSuperior
        texto={bajando ? 'DESCARGANDO DESDE LA NUBE · ' + pb + ' %' : busca ? 'BUSCANDO A LA COMPUTADORA PRINCIPAL…' : 'LLEGÓ POR LA NUBE, CIFRADA · AL CORTE DE LAS 9:40 A.M.'}
        sub={bajando ? 'No se alcanzaron directo; se usó la nube' : busca ? null : 'No se alcanzaron directo; se usó la nube · tus cambios esperan a la principal'}
        spinner={bajando || busca} icono={bajando || busca ? null : 'check'} progreso={bajando ? tb : null} indet={!bajando && busca} />
      <EqsTarjeta
        titulo={bajando ? 'Descargando desde la nube · ' + pb + ' %' : 'Llegó por la nube, cifrada · al corte de las 9:40 a.m.'}
        cuerpo="La computadora principal está en línea, pero esta red no permite conectarse directo. No se alcanzaron directo; se usó la nube. Cuando estén en la misma red, por ejemplo el Wi-Fi de la oficina, vuelve a ir directo."
        acciones={<AxButton variant="primary" icon="refresh" loading={busca} disabled={busca || bajando} onClick={reintentar}>{busca ? 'Reintentando…' : 'Reintentar directo'}</AxButton>}>
        {bajando && <EqsParte etiqueta="Descargando desde la nube" detalle={pb + ' %'} valor={tb} />}
        {busca && (
          <div>
            <div style={{ fontSize: 12, color: 'var(--ax-fg-strong)', marginBottom: 6 }}>Buscando a la computadora principal…</div>
            <EqsBarra indet />
          </div>
        )}
        {!busca && intentos > 0 && <EqsNota>Sigue sin conexión directa (intento {intentos}); se sigue usando la nube.</EqsNota>}
        <EqsNota>Sus cambios igual esperan a que la computadora principal los aplique. {EQS_CIFRADA}</EqsNota>
      </EqsTarjeta>
    </>
  );
}

// ── 5. Conflicto ────────────────────────────────────────────────────────────
function EqsConflicto() {
  const [visto, setVisto] = useState(false);
  return (
    <>
      <EqsBarraSuperior texto={visto ? 'SINCRONIZADO · HACE UN MOMENTO' : '1 CAMBIO TUYO NO SE APLICÓ'} sub={visto ? null : 'La computadora principal lo cambió antes'} icono={visto ? 'check' : 'alert'} />
      <EqsTarjeta
        titulo="1 cambio tuyo no se aplicó porque la computadora principal lo cambió antes"
        cuerpo="El resto de tus cambios sí se aplicó. Aquí está el que quedó fuera."
        acciones={<AxButton variant="secondary" icon="check" disabled={visto} onClick={() => setVisto(true)}>Entendido</AxButton>}>
        <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8, padding: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>Teléfono en la ficha de Luis Herrera Paz</div>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            <div style={{ flex: 1, minWidth: 220, background: 'var(--ax-bg-3)', borderRadius: 6, padding: 12 }}>
              <AxPill tone="ghost">Tu cambio · 10:15 a.m. · no se aplicó</AxPill>
              <div className="ax-mono" style={{ fontSize: 13, color: 'var(--ax-fg-muted)', marginTop: 8 }}>55 5555 0142</div>
            </div>
            <div style={{ flex: 1, minWidth: 220, background: 'var(--ax-bg-3)', borderRadius: 6, padding: 12 }}>
              <AxPill tone="accent" dot>Quedó · computadora principal · 10:02 a.m.</AxPill>
              <div className="ax-mono" style={{ fontSize: 13, color: 'var(--ax-fg-strong)', marginTop: 8 }}>55 5555 0188</div>
            </div>
          </div>
          <EqsNota>Si crees que tu versión es la correcta, vuelve a escribirla desde la ficha; viajará de nuevo a la computadora principal.</EqsNota>
        </div>
      </EqsTarjeta>
    </>
  );
}

// ── 6. Dado de baja ─────────────────────────────────────────────────────────
function EqsBaja() {
  const [fin, setFin] = useState(false);
  const t = eqsUseAvance({ pausa: fin, paso: 0.02, ms: 400, ciclo: false, alTerminar: () => setFin(true) });
  const pct = Math.round(t * 100);
  return (
    <>
      <EqsBarraSuperior texto={fin ? 'COPIA LOCAL BORRADA' : 'BORRANDO LA COPIA LOCAL · ' + pct + ' %'} spinner={!fin} icono={fin ? 'check' : null} progreso={fin ? null : t} />
      <EqsTarjeta
        titulo="Esta computadora ya no es parte del equipo"
        cuerpo={fin ? 'Se borró la copia de la cartera de esta computadora. Ya puedes cerrar Piixi.' : 'Por seguridad, estamos borrando de esta computadora la copia de la cartera del despacho.'}
>
        {!fin && <EqsParte etiqueta="Borrando la copia local" detalle={eqsN(EQS_POLIZAS * t) + ' de ' + eqsN(EQS_POLIZAS) + ' pólizas · PDFs'} valor={t} />}
        {fin && <EqsNota>La computadora principal conserva todo; aquí no queda nada del despacho.</EqsNota>}
      </EqsTarjeta>
    </>
  );
}

// ── Computadora principal: lista de miembros ────────────────────────────────
const EQS_MIEMBROS = [
  { k: 'sync', persona: 'Sofía', nombre: 'Escritorio de Sofía', tipo: 'Windows', l: 'Sincronizado', seg: 12 },
  { k: 'copiando', persona: 'Marco', nombre: 'Laptop de Marco', tipo: 'Mac', l: 'Primera copia', seg: 38 },
  { k: 'recibiendo', persona: 'Valeria', nombre: 'Mesa de Valeria', tipo: 'Windows', l: 'Recibiendo sus cambios', seg: 24 },
  { k: 'fuera', persona: 'Diego', nombre: 'Laptop de Diego', tipo: 'Mac', l: 'Sin conexión' },
  { k: 'sindirecta', persona: 'Paula', nombre: 'Escritorio de Paula', tipo: 'Windows', l: 'Sin conexión directa' },
  { k: 'aplicados', persona: 'Iván', nombre: 'Laptop de Iván', tipo: 'Mac', l: 'Cambios aplicados' },
];

function EqsFilaBase({ m, pill, children, k }) {
  return (
    <div data-eqs={'fila-' + k} style={{ padding: '14px 20px', borderTop: '1px solid var(--ax-border)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <AxAvatar name={m.persona} size={32} />
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, color: 'var(--ax-fg-strong)' }}>{m.nombre}</div>
          <div style={{ fontSize: 12, color: 'var(--ax-fg-muted)' }}>Computadora {m.tipo}</div>
        </div>
        {pill}
      </div>
      {children && <div style={{ marginTop: 10, marginLeft: 44 }}>{children}</div>}
    </div>
  );
}

function EqsFilaPrincipal({ m, via }) {
  const nube = via === 'nube';
  const amb = via === 'ambas';
  const tCopia = eqsUseAvance({ pausa: m.k !== 'copiando', paso: 0.012, ms: 400, ciclo: true });
  const tCambios = eqsUseAvance({ pausa: m.k !== 'recibiendo', paso: 0.04, ms: 300, ciclo: true });
  // Vía que entregó la última tanda (escenario «las dos encendidas»)
  const porNube = m.k === 'fuera' || m.k === 'sindirecta';
  const viaTxt = porNube ? 'por la nube, cifrada' : 'directo';
  let pill, barra = null, vivo = false;
  if (m.k === 'sync') pill = <AxPill tone="info" dot>Sincronizado hace 2 min</AxPill>;
  if (m.k === 'copiando') {
    const v = 0.29 + 0.71 * tCopia;
    pill = <AxPill tone="accent" dot>{nube ? 'Descargando desde la nube' : 'Copiando la primera copia'} · {Math.round(v * 100)} %</AxPill>;
    barra = <EqsBarra valor={v} />; vivo = true;
  }
  if (m.k === 'recibiendo') {
    const n = Math.min(5, Math.floor(tCambios * 5) + 1);
    pill = <AxPill tone="accent" dot>Recibiendo sus cambios · {n} de 5</AxPill>;
    barra = <EqsBarra valor={tCambios} />; vivo = true;
  }
  if (m.k === 'fuera') pill = <AxPill tone="ghost">Sin conexión desde ayer 6:10 p.m.</AxPill>;
  if (m.k === 'sindirecta') pill = <AxPill tone="warm" dot>En línea, pero sin conexión directa</AxPill>;
  if (m.k === 'aplicados') pill = <AxPill tone="info">3 cambios suyos aplicados hoy</AxPill>;
  if (amb) {
    const v = m.k === 'copiando' ? 0.29 + 0.71 * tCopia : m.k === 'recibiendo' ? tCambios : 1;
    barra = (
      <div>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ax-fg-muted)', marginBottom: 4 }}>
          <span>{vivo ? 'Esta tanda va ' : 'Última tanda entregada '}{viaTxt}</span><span className="ax-mono">{Math.round(v * 100)} %</span>
        </div>
        <EqsBarra valor={v} quieta={!vivo} />
      </div>
    );
  }
  return <EqsFilaBase m={m} k={m.k} pill={pill}>{barra}</EqsFilaBase>;
}

// Comparar las dos vías: la misma tanda, dos barras lado a lado
function EqsFilaComparar({ m }) {
  const bloqueada = m.k === 'sindirecta';
  const [fin, setFin] = useState(false);
  const tD = eqsUseAvance({ pausa: bloqueada || fin, paso: 0.05, ms: 500, ciclo: false });
  const tN = eqsUseAvance({ pausa: fin, paso: 0.03, ms: 500, ciclo: false, alTerminar: () => setFin(true) });
  const lbl = (t) => Math.round(t * 100) + ' %';
  return (
    <EqsFilaBase m={m} k={'cmp-' + m.k}
      pill={fin ? <AxPill tone="info" dot>{bloqueada ? 'Llegó por la nube; directo no pudo conectar' : 'Llegó primero: directo, ' + m.seg + ' s antes'}</AxPill> : <AxPill tone="accent" dot>Misma tanda · comparando</AxPill>}>
      <div style={{ display: 'flex', gap: 16 }}>
        <div style={{ flex: 1 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ax-fg-muted)', marginBottom: 4 }}>
            <span>Directo</span><span className="ax-mono">{bloqueada ? 'sin conexión directa' : lbl(tD)}</span>
          </div>
          <EqsBarra valor={tD} quieta={bloqueada} />
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ax-fg-muted)', marginBottom: 4 }}>
            <span>Por la nube, cifrada</span><span className="ax-mono">{lbl(tN)}</span>
          </div>
          <EqsBarra valor={tN} />
        </div>
      </div>
    </EqsFilaBase>
  );
}

// Subida de la principal a la nube (vía nube y comparación)
function EqsSubida({ respaldo }) {
  const [listo, setListo] = useState(false);
  const t = eqsUseAvance({ pausa: listo, paso: 0.05, ms: 500, ciclo: false, alTerminar: () => setListo(true) });
  const pct = Math.round(t * 100);
  return (
    <div data-eqs="subida" style={{ padding: '16px 20px', borderTop: '1px solid var(--ax-border)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16 }}>
        <div>
          <div style={{ fontSize: 14, color: 'var(--ax-fg-strong)' }}>{listo ? 'Lista en la nube · hace 2 min' : 'Subiendo cifrada a la nube · ' + pct + ' %'}</div>
          <div style={{ fontSize: 12, color: 'var(--ax-fg-muted)', marginTop: 2 }}>{respaldo ? 'Respaldo en la nube · ' : ''}Espacio en la nube: 640 MB</div>
        </div>
        <AxButton variant="secondary" size="sm" icon="upload" disabled={!listo} onClick={() => setListo(false)}>Simular nueva subida</AxButton>
      </div>
      {!listo && <div style={{ marginTop: 10 }}><EqsBarra valor={t} /></div>}
      <div style={{ fontSize: 12, color: 'var(--ax-fg-faint)', marginTop: 8 }}>{EQS_CIFRADA}</div>
    </div>
  );
}

function EqsPrincipal({ filtro, via }) {
  const nube = via === 'nube';
  const amb = via === 'ambas';
  let lista = EQS_MIEMBROS.filter((m) => filtro === 'todos' || m.k === filtro);
  if (nube) lista = lista.filter((m) => m.k !== 'sindirecta');
  const comparables = EQS_MIEMBROS.filter((m) => ['sync', 'copiando', 'recibiendo', 'sindirecta'].includes(m.k));
  const intro = nube
    ? 'La computadora principal sube la cartera cifrada a la nube y los miembros la bajan de ahí, aunque la principal esté apagada. Sus cambios esperan a que la principal los aplique.'
    : amb
      ? 'Las computadoras se sincronizan solas. Directo entre ellas es lo preferido; si no se alcanzan (principal apagada o una red que no deja conectar), se usa la nube, cifrada. Abajo ves por dónde llegó la última tanda de cada miembro.'
      : 'Cuando las dos computadoras están abiertas y se alcanzan, se sincronizan solas en segundos, en los dos sentidos. Los datos viajan directo entre ellas; la nube de Piixi sólo sirve para que se reconozcan.';
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div style={{ background: 'var(--ax-bg-2)', border: '1px solid var(--ax-border)', borderRadius: 10 }}>
        <div style={{ padding: '16px 20px' }}>
          <AxEyebrow>Ajustes › Equipo · miembros</AxEyebrow>
          <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)', marginTop: 6, lineHeight: 1.5, maxWidth: 640 }}>{intro}</div>
        </div>
        {(nube || amb) && <EqsSubida respaldo={amb} />}
        {lista.map((m) => <EqsFilaPrincipal key={m.k} m={m} via={via} />)}
      </div>
      {amb && (
        <div data-eqs="medicion" style={{ background: 'var(--ax-bg-2)', border: '1px dashed var(--ax-border-strong)', borderRadius: 10 }}>
          <div style={{ padding: '16px 20px' }}>
            <AxEyebrow>Medición (sólo durante las pruebas)</AxEyebrow>
            <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)', marginTop: 6, lineHeight: 1.5, maxWidth: 640 }}>La misma tanda viaja por las dos vías a la vez para medir cuál llega primero. Los tiempos de la maqueta son simulados.</div>
          </div>
          {comparables.map((m) => <EqsFilaComparar key={m.k} m={m} />)}
        </div>
      )}
    </div>
  );
}

// ── Pantalla ────────────────────────────────────────────────────────────────
const EQS_ESTADOS_M = [
  { k: 'primera', l: '1 · Primera copia', C: EqsPrimera },
  { k: 'sincronizado', l: '2 · Sincronizado', C: EqsSincronizado },
  { k: 'fuera', l: '3 · Principal fuera de línea', C: EqsFuera },
  { k: 'sindirecta', l: '4 · Sin conexión directa', C: EqsSinDirecta, soloDirecto: true },
  { k: 'conflicto', l: '5 · Conflicto', C: EqsConflicto },
  { k: 'baja', l: '6 · Dado de baja', C: EqsBaja },
];
const EQS_VIAS = [
  { k: 'ambas', l: 'Las dos encendidas (lo que se va a probar)' },
  { k: 'directo', l: 'Si al final sólo queda la directa' },
  { k: 'nube', l: 'Si al final sólo queda la nube' },
];

function EqsSel({ opciones, valor, onChange }) {
  return (
    <div style={{ display: 'inline-flex', gap: 6, flexWrap: 'wrap' }}>
      {opciones.map((o) => (
        <AxButton key={o.k} size="sm" variant={valor === o.k ? 'primary' : 'secondary'} onClick={() => onChange(o.k)}>{o.l}</AxButton>
      ))}
    </div>
  );
}

function EquipoSyncScreen() {
  const [vista, setVista] = useState('miembro');
  const [estadoM, setEstadoM] = useState('primera');
  const [filtroP, setFiltroP] = useState('todos');
  const [corrida, setCorrida] = useState(0);
  const [via, setViaState] = useState(window.__eqsVia || 'ambas');
  const setVia = (v) => {
    window.__eqsVia = v;
    setViaState(v);
    if (v === 'nube' && estadoM === 'sindirecta') setEstadoM('primera');
    if (v === 'nube' && filtroP === 'sindirecta') setFiltroP('todos');
    setCorrida((c) => c + 1);
  };
  useEffect(() => {
    const h = (e) => setVia(e.detail);
    window.addEventListener('eqs-via', h);
    return () => window.removeEventListener('eqs-via', h);
  });
  const nube = via === 'nube';
  const estados = EQS_ESTADOS_M.filter((e) => !(nube && e.soloDirecto));
  const Actual = EQS_ESTADOS_M.find((e) => e.k === estadoM).C;
  const miembros = nube ? EQS_MIEMBROS.filter((m) => m.k !== 'sindirecta') : EQS_MIEMBROS;
  const sub = via === 'ambas' ? 'Qué ve cada computadora mientras se sincronizan: directo entre ellas, y por la nube, cifrada, si no se alcanzan.' : via === 'directo' ? 'Qué ve cada computadora mientras se sincronizan directo, sin pasar por la nube de Piixi.'
    : nube ? 'Qué ve cada computadora mientras la cartera viaja por la nube, cifrada en la computadora principal.'
    : '';
  return (
    <div style={{ flex: 1, overflow: 'auto' }} className="ax-fade-in">
      <style>{'@keyframes eqs-indet{0%{left:-35%}100%{left:100%}} .eqs-indet{animation:eqs-indet 1.3s ease-in-out infinite}'}</style>
      <AxPageHeader eyebrow="Ajustes › Equipo" title="Sincronización del equipo" subtitle={sub} />
      <div style={{ padding: '24px 32px', display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 920 }}>
        <div data-eqs="simulador" style={{ border: '1px dashed var(--ax-border-strong)', borderRadius: 8, padding: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
          <AxEyebrow>Maqueta · simular estado de sincronización</AxEyebrow>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <span style={{ fontSize: 12, color: 'var(--ax-fg-muted)' }}>Escenario:</span>
            <EqsSel valor={via} onChange={setVia} opciones={EQS_VIAS} />
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <span style={{ fontSize: 12, color: 'var(--ax-fg-muted)' }}>Ver como:</span>
            <EqsSel valor={vista} onChange={setVista} opciones={[{ k: 'principal', l: 'Computadora principal' }, { k: 'miembro', l: 'Miembro del equipo' }]} />
          </div>
          {vista === 'miembro' ? (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 12, color: 'var(--ax-fg-muted)' }}>Estado:</span>
              <EqsSel valor={estadoM} onChange={(k) => { setEstadoM(k); setCorrida((c) => c + 1); }} opciones={estados} />
              <AxButton size="sm" variant="tertiary" icon="refresh" onClick={() => setCorrida((c) => c + 1)}>Reiniciar</AxButton>
              {nube && <span style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>«Sin conexión directa» no existe por la nube: no hace falta que las dos se alcancen.</span>}
            </div>
          ) : (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 12, color: 'var(--ax-fg-muted)' }}>Miembro:</span>
              <EqsSel valor={filtroP} onChange={setFiltroP} opciones={[{ k: 'todos', l: 'Todos' }, ...miembros]} />
              {via === 'ambas' && <AxButton size="sm" variant="tertiary" icon="refresh" onClick={() => setCorrida((c) => c + 1)}>Repetir medición</AxButton>}
            </div>
          )}
        </div>

        {vista === 'miembro' ? (
          <div key={estadoM + corrida + via} style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
            {false && <EqsNota>Comparando: aquí se ve la vía directa de este estado. Elige «Por la nube, cifrada» para ver la otra; la comparación por miembro está en «Computadora principal».</EqsNota>}
            <Actual via={via} />
          </div>
        ) : (
          <EqsPrincipal key={via + corrida} filtro={filtroP} via={via} />
        )}
      </div>
    </div>
  );
}

Object.assign(window, { EquipoSyncScreen });
