/* Componentes de la CONSOLA de licencias de Tuurt Trading (era cerberus.css
   hasta el 2026-08-25: la consola sirve a todos los bots, no a uno). Los tokens viven en tokens.css,
   que enlazan las tres superficies; esto lo enlaza solo index.html porque
   describe SU marcacion.

   QUE DESAPARECIO el 2026-08-03, y por que:
   - 3 animaciones decorativas (drift 90s infinita, beat 2.4s, enter en
     cada cambio de vista). El movimiento se reserva para cuando CAMBIA UN
     DATO; una animacion permanente es ruido.
   - 11 resplandores (hasta 0 0 40px). Un halo sobre una cifra no la
     destaca: le baja el contraste efectivo.
   - El grano de pelicula al 4% con z-index:99, o sea POR ENCIMA de los
     numeros que hay que leer.
   - 13 bloques en mayuscula con tracking. Si todo enfatiza, nada
     jerarquiza.
   - `table{min-width:1060px}` como regla global. Ya causo un bug: recorto
     la columna de detalle del informe, que solo tiene tres columnas.

   Las 23 clases que panel.js escribe siguen todas estiladas aqui. Las
   tres que se asignan en caliente son las que mas duelen si faltan:
   .pulse/.pulse.bad, .stat.alarm/.stat.calm y .on. */

html,body{height:100%}
body{
  margin:0;background:var(--page);color:var(--ink);
  /* La unica fuente de luz de Direction A: una lampara arriba a la
     izquierda, no un degradado decorativo. Va DESPUES del shorthand
     `background` a proposito -- ese shorthand resetea background-image
     a `none`, asi que si este orden se invierte el gradiente desaparece
     en silencio. */
  background-image:radial-gradient(1200px 600px at 12% -10%, rgba(78,168,255,.07), transparent 60%);
  font:14px/1.6 var(--text);
  -webkit-font-smoothing:antialiased;
}
/* Las cifras se alinean en columna alla donde aparezcan. */
.num,code.key,td.num,input,.thekey,.clock,.stat .n,.spark-v,
.stat .d .up,.stat .d .dn,.head .count,.tag,.legend-item,
table td:has(.num){font-variant-numeric:tabular-nums}

/* El dato en monoespaciada SIEMPRE (ver TESIS en tokens.css). Vence, Cuentas
   y Precio en Licencias, y Cuenta en Riesgo, comparten `.dim` con celdas que
   NO son datos -- Concepto en Negocio usa esa MISMA clase para un rotulo, no
   para una cifra -- asi que se seleccionan por POSICION de columna y no por
   clase: renombrar una clase esta fuera de esta tarea (ver panel.js). Si el
   orden de columnas cambia esto se desincroniza; no hay test que lo cubra. */
#tbLicences td:nth-child(5),   /* Vence */
#tbLicences td:nth-child(6),   /* Cuentas */
#tbLicences td:nth-child(8),   /* Precio */
#tbRisk td:nth-child(3){       /* Cuenta */
  font-family:var(--mono);font-variant-numeric:tabular-nums;
}

/* tabular-nums iguala el ANCHO de cada digito, pero no basta por si sola: a
   la izquierda, "$79.00" y "$129.00" siguen sin alinear el punto porque uno
   tiene un digito menos delante. Alinear a la derecha SI lo garantiza, y es
   lo que "confirma que los decimales cuadran" al verificar la vista. Mismo
   truco de POSICION que arriba: estas columnas son td sin clase propia. */
table:has(#tbLicences) thead th:nth-child(7),  /* Tope lote */
table:has(#tbLicences) thead th:nth-child(8),  /* Precio */
#tbLicences td:nth-child(7),
#tbLicences td:nth-child(8),
table:has(#tbRisk) thead th:nth-child(4),      /* Balance */
table:has(#tbRisk) thead th:nth-child(5),      /* Flotante */
table:has(#tbRisk) thead th:nth-child(6),      /* Patas */
#tbRisk td:nth-child(4),
#tbRisk td:nth-child(5),
#tbRisk td:nth-child(6),
table:has(#tbReport) thead th:nth-child(2),    /* Valor */
#tbReport td:nth-child(2){
  text-align:right;
}

.shell{display:grid;grid-template-columns:var(--rail-w) 1fr;min-height:100%}

/* ------------------------------------------------------------- rail */
aside{
  background:var(--surface);border-right:1px solid var(--rule);
  position:sticky;top:0;height:100vh;display:flex;flex-direction:column;
}
.brand{padding:18px 18px 16px;border-bottom:1px solid var(--rule);
       display:flex;align-items:center;gap:10px}
/* El gradiente de marca, sitio 1 de 2. */
.brand .mk{width:24px;height:24px;border-radius:7px;flex:0 0 auto;background:var(--brand)}
.brand h1{margin:0;font:600 17px/1 var(--text);letter-spacing:-.01em;color:var(--ink)}
.brand h1 b{font-weight:600}
.brand small{display:block;margin-top:3px;font-size:11.5px;color:var(--muted);letter-spacing:0}

/* Cambio de idioma del área de clientes. Mismo registro que .note: un enlace
   discreto, no un botón que compita con «Ver mis descargas». */
.lang-switch{margin-left:auto;flex:0 0 auto;font-size:12px;color:var(--muted);
  text-decoration:none;padding:5px 10px;border:1px solid var(--rule);
  border-radius:2px;letter-spacing:0}
.lang-switch:hover{color:var(--ink);border-color:var(--muted)}
.lang-switch:focus-visible{outline:2px solid var(--brand);outline-offset:2px}

nav{padding:10px 10px;flex:1;display:flex;flex-direction:column;gap:2px}
nav button{
  position:relative;display:flex;align-items:center;gap:10px;width:100%;
  background:none;border:0;padding:8px 10px;color:var(--muted);cursor:pointer;
  font:500 13.5px/1.2 var(--text);text-align:left;border-radius:var(--r-sm);
  transition:background .12s,color .12s;
}
/* El numero de vista se queda porque las cuatro SON una secuencia de
   trabajo (vives en 01, intervienes desde 02, cobras con 03, das de alta
   en 04), no porque numerar decore. */
nav button i{font-style:normal;font-size:11px;font-family:var(--mono);
             color:var(--muted);opacity:.7;transition:opacity .12s}
nav button:hover{background:var(--sel-bg);color:var(--ink)}
nav button.on{background:var(--sel-bg);color:var(--sel-ink);font-weight:600}
nav button.on i{opacity:1}
/* El gradiente de marca, sitio 2 de 2. */
nav button.on::before{
  content:"";position:absolute;left:-10px;top:6px;bottom:6px;width:3px;
  border-radius:0 3px 3px 0;background:var(--brand);
}
nav button.guide{margin-top:6px;border-top:1px solid var(--rule);
                 padding-top:12px;border-radius:0 0 var(--r-sm) var(--r-sm)}

/* HERRAMIENTAS. Reusa `nav button` entero -- hover, marcador y tipografia
   identicos a las vistas -- y solo añade el separador y el rotulo del bot.
   Sin `.on`: estas abren pestaña y nunca son la vista activa, asi que el rail
   de marca (sitio 2 de 2) no les corresponde. */
nav.tools{padding:0 10px;margin-top:8px;border-top:1px solid var(--rule);padding-top:10px}
nav.tools .tools-h{margin:0 0 4px;padding:0 10px;
  font:600 10px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}

.rail-foot{padding:12px 14px;border-top:1px solid var(--rule);
           display:flex;flex-direction:column;gap:7px}
.rail-foot button{
  width:100%;background:var(--surface);border:1px solid var(--rule);
  color:var(--ink-2);padding:8px;cursor:pointer;border-radius:var(--r-sm);
  font:500 12.5px/1 var(--text);transition:background .12s,border-color .12s;
}
.rail-foot button:hover{background:var(--sel-bg);border-color:var(--muted)}

main{min-width:0;display:flex;flex-direction:column}

/* ------------------------------------------------------------- vitals */
.vitals{background:var(--surface);border-bottom:1px solid var(--rule);padding:16px 24px 18px}
.status-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:18px}
.link{display:flex;align-items:center;gap:8px;font:500 13px/1 var(--text);color:var(--ink-2)}
/* Estatico. Antes latia cada 2.4 s para siempre; un punto que parpadea
   sin parar no informa de nada. El cambio de estado lo dice el color y
   el texto de al lado. */
.pulse{width:8px;height:8px;border-radius:50%;background:var(--m-ok);flex:0 0 auto}
.pulse.bad{background:var(--m-bad)}
.clock{margin-left:auto;color:var(--muted);font-size:12px;font-family:var(--mono)}

/* Jerarquia de tres niveles. Antes eran cinco .stat identicos: el MRR
   pesaba lo mismo que "Cuentas reportando". */
.hero{display:grid;gap:20px 30px;align-items:start;
      grid-template-columns:minmax(190px,1.4fr) repeat(auto-fit,minmax(146px,1fr))}
.stat{display:flex;flex-direction:column;gap:5px;min-width:0}
.stat .t{font-size:11.5px;font-weight:500;color:var(--muted);order:-1}
.stat .n{font:600 21px/1.05 var(--mono);letter-spacing:-.02em;color:var(--ink)}
.stat .d{font-size:11.5px;color:var(--muted);display:flex;align-items:center;gap:5px;
         flex-wrap:wrap}
.stat .d .up{color:var(--i-ok);font-weight:600}
.stat .d .dn{color:var(--i-bad);font-weight:600}
/* Nivel 1: el titular. */
.stat.lead .n{font-size:34px;letter-spacing:-.03em}

/* Nivel 2: la alarma. panel.js:205 escribe "stat alarm" o "stat calm" en
   #kpiDangerBox -- si el CSS no contempla .alarm, la alarma de clientes
   en peligro deja de verse. Con danger>0 ocupa la fila entera. */
/* `order` para que la franja caiga DEBAJO de los KPI en vez de partir la fila
   por la mitad, sin mover el elemento en el HTML: #kpiDangerBox tiene que
   seguir donde esta porque panel.js le escribe la clase por id. */
.stat.alarm{order:1;grid-column:1/-1;flex-direction:row;align-items:center;gap:12px;
            padding:11px 14px;border-radius:var(--r);
            background:color-mix(in srgb,var(--m-bad) 9%,var(--surface));
            border:1px solid color-mix(in srgb,var(--m-bad) 26%,var(--surface))}
.stat.alarm .t{order:0;color:var(--i-bad);font-weight:600;font-size:13px}
.stat.alarm .n{font-size:21px;color:var(--i-bad)}
.stat.alarm .d{margin-left:auto;text-align:right}
.stat.calm .n{color:var(--ink)}

.share{display:flex;height:6px;border-radius:99px;overflow:hidden;gap:2px;
       background:var(--rule-soft);margin-top:18px}
.share .seg{height:100%;transition:flex-grow .4s ease}
.legend{display:flex;gap:16px;flex-wrap:wrap;padding:9px 0 0}
.legend-item{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
.legend-item i{width:9px;height:9px;border-radius:2px;flex:0 0 auto}

/* -------------------------------------------------------------- views */
.body{padding:22px 24px 34px;flex:1}
.view{display:none}
.view.on{display:block}

.head{display:flex;align-items:baseline;gap:12px;margin-bottom:5px}
.head h2{margin:0;font:600 19px/1.2 var(--text);letter-spacing:-.02em;color:var(--ink)}
.head .count{color:var(--muted);font-size:13px;font-family:var(--mono)}
p.lead{margin:0 0 18px;color:var(--muted);font-size:13.5px;max-width:68ch;line-height:1.65}

/* charts */
.charts{display:grid;gap:16px;margin-bottom:20px}
@media (min-width:1180px){ .charts.two{grid-template-columns:1fr 1fr} }
.chart-card{border:1px solid var(--rule);background:var(--surface);
            border-radius:var(--r);padding:16px 18px 12px;box-shadow:var(--shadow-1)}
.chart-card h4{margin:0 0 3px;font:600 13.5px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
.chart-card .caption{margin:2px 0 12px;font-size:12.5px;color:var(--muted);
                     line-height:1.6;max-width:72ch}
.empty-chart{padding:24px 0;text-align:center;color:var(--muted);font-size:13px}

.table{border:1px solid var(--rule);background:var(--surface);border-radius:var(--r);
       overflow-x:auto;box-shadow:var(--shadow-1)}
table{width:100%;border-collapse:collapse}
/* Cada tabla declara SU ancho minimo. La regla global recortaba la
   columna de detalle del informe ("...pueden opera"), que no lo necesita. */
#tbLicences, #tbRisk{min-width:1000px}
thead th{
  position:sticky;top:0;z-index:1;background:var(--surface-2);
  text-align:left;padding:10px 14px;border-bottom:1px solid var(--rule);
  font:600 10.5px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap;
}
tbody td{padding:13px 14px;border-bottom:1px solid var(--rule-soft);
         vertical-align:top;white-space:nowrap}
tbody td.wrap-text{white-space:normal}
#tbReport td:last-child{white-space:normal}
tbody tr{transition:background .12s}
tbody tr:hover{background:var(--surface-2)}
tbody tr:last-child td{border-bottom:0}
/* Forma ademas de color: la severidad no depende solo del tono. */
tbody tr[data-level="danger"] td:first-child{box-shadow:inset 3px 0 0 var(--m-bad)}
tbody tr[data-level="warning"] td:first-child{box-shadow:inset 3px 0 0 var(--m-warn)}
tbody tr[data-level="ok"] td:first-child{box-shadow:inset 3px 0 0 var(--m-ok)}
tbody tr[data-level="unknown"] td:first-child{box-shadow:inset 3px 0 0 var(--muted)}
.table::-webkit-scrollbar{height:9px}
.table::-webkit-scrollbar-track{background:var(--surface-2)}
.table::-webkit-scrollbar-thumb{background:var(--rule);border-radius:9px}
.table{scrollbar-width:thin;scrollbar-color:var(--rule) var(--surface-2)}

/* Los TRES estados, que antes eran uno. Un fallo de backend no tenia
   representacion ninguna: se pintaba como "0 licencias, todo en orden". */
.empty{padding:44px 15px;text-align:center;color:var(--muted);font-size:13.5px;
       white-space:normal;line-height:1.7}
.empty b{color:var(--ink-2);font-weight:600}
/* `hidden` es un atributo del navegador y CUALQUIER `display` de autor le gana.
   Sin esta linea la caja de error se ve siempre, vacia y rosa, que es
   exactamente la pinta de roto que este rediseño existe para quitar. */
[hidden]{display:none !important}
.failed{margin:0 0 18px;padding:13px 16px;border-radius:var(--r);
        border:1px solid color-mix(in srgb,var(--m-bad) 30%,var(--surface));
        background:color-mix(in srgb,var(--m-bad) 8%,var(--surface));
        color:var(--ink-2);font-size:13.5px;line-height:1.6;
        display:flex;align-items:flex-start;gap:11px;flex-wrap:wrap}
.failed b{color:var(--i-bad)}
.failed code{font-family:var(--mono);font-size:12.5px;color:var(--i-bad)}
.failed button{margin-left:auto;background:var(--surface);border:1px solid var(--rule);
               color:var(--ink);padding:6px 12px;border-radius:var(--r-sm);cursor:pointer;
               font:500 12.5px/1 var(--text)}
.failed button:hover{background:var(--sel-bg)}
.skeleton{border-radius:var(--r-sm);background:var(--rule-soft);height:13px;
          animation:pulse-sk 1.1s ease-in-out infinite}
/* La UNICA animacion que queda, y solo existe mientras se espera: dice
   "sigo trabajando", que es informacion. */
@keyframes pulse-sk{50%{opacity:.45}}

/* El mono se queda donde se gana el sitio: keys, cuentas, importes. */
code.key{font-family:var(--mono);color:var(--m-data);letter-spacing:0;
         white-space:nowrap;font-size:12.5px}
.client{font:600 14px/1.35 var(--text);color:var(--ink)}
.mail{color:var(--muted);font-size:12.5px}
.dim{color:var(--muted)} .faint{color:var(--muted);opacity:.75}
.neg{color:var(--i-bad);font-weight:500} .pos{color:var(--i-ok);font-weight:500}
.num{font-family:var(--mono);font-size:13px}
.note{font-size:12.5px;color:var(--muted);line-height:1.6}

/* Una pildora SIEMPRE lleva su texto: el color nunca es el unico canal.
   En Papel eso no es una cortesia -- las tintas no pasan separacion CVD
   sobre blanco y no pueden, asi que el texto ES el canal. */
.tag{display:inline-block;padding:3px 9px;font-size:11.5px;font-weight:600;
     border-radius:99px;white-space:nowrap;border:1px solid transparent;
     font-family:var(--text)}
/* Fondo ~10% del color semantico, borde ~30%, texto a fuerza completa. El
   ambar de "atencion" es el par de mas riesgo sobre una superficie oscura:
   medido en --surface #0f141b da ~8.4:1 con --i-warn, sobra margen. Si algun
   par no alcanzara contraste la palanca es SUBIR el fondo, nunca tocar el
   hex semantico -- estan validados por dataviz/scripts/validate_palette.js
   (ver tokens.css) y fijados por un test. */
.tag.ok{color:var(--i-ok);
        background:color-mix(in srgb,var(--m-ok) 10%,var(--surface));
        border-color:color-mix(in srgb,var(--m-ok) 30%,var(--surface))}
.tag.warning{color:var(--i-warn);
        background:color-mix(in srgb,var(--m-warn) 10%,var(--surface));
        border-color:color-mix(in srgb,var(--m-warn) 30%,var(--surface))}
.tag.danger{color:var(--i-bad);
        background:color-mix(in srgb,var(--m-bad) 10%,var(--surface));
        border-color:color-mix(in srgb,var(--m-bad) 30%,var(--surface))}
.tag.unknown{color:var(--muted);background:var(--rule-soft);border-color:var(--rule)}

.sev{width:84px;height:5px;background:var(--rule-soft);margin-top:8px;
     border-radius:99px;overflow:hidden}
.sev span{display:block;height:100%;border-radius:99px;transition:width .4s ease}
.sev span.danger{background:var(--m-bad)}
.sev span.warning{background:var(--m-warn)}
.sev span.ok{background:var(--m-ok)}
.sev span.unknown{background:var(--muted)}

.dd{width:92px;height:4px;background:var(--rule-soft);margin-top:7px;border-radius:99px}
.dd span{display:block;height:100%;background:var(--m-bad);border-radius:99px}

.actions{display:flex;flex-wrap:nowrap;gap:5px}
button.act{background:var(--surface);border:1px solid var(--rule);color:var(--ink-2);
           padding:5px 10px;cursor:pointer;border-radius:var(--r-sm);
           font:500 12.5px/1 var(--text);transition:background .12s,border-color .12s}
button.act:hover{background:var(--sel-bg);border-color:var(--muted);color:var(--ink)}
button.act.danger{color:var(--i-bad)}
button.act.danger:hover{border-color:var(--m-bad);
                        background:color-mix(in srgb,var(--m-bad) 8%,var(--surface))}
button.act.only{padding:4px 8px;font-size:12px}

/* forms */
form.issue{border:1px solid var(--rule);background:var(--surface);border-radius:var(--r);
           padding:22px;max-width:460px;box-shadow:var(--shadow-1)}
label{display:block;margin-bottom:14px}
label span{display:block;font-size:12.5px;font-weight:500;color:var(--ink-2);margin-bottom:6px}
input{width:100%;background:var(--surface);border:1px solid var(--rule);color:var(--ink);
      padding:9px 11px;border-radius:var(--r-sm);font:13.5px var(--text);outline:none;
      transition:border-color .12s,box-shadow .12s}
input:focus{border-color:var(--ink);box-shadow:0 0 0 3px var(--sel-bg)}
/* Un <select> hereda NADA de `input`: sin esto sale el desplegable nativo del
   navegador, gris y de otra altura, entre campos que si estan vestidos. Misma
   caja que el input, la flecha del sistema fuera y una propia dibujada. */
select{width:100%;background:var(--surface);border:1px solid var(--rule);color:var(--ink);
       padding:9px 34px 9px 11px;border-radius:var(--r-sm);font:13.5px var(--text);outline:none;
       cursor:pointer;appearance:none;-webkit-appearance:none;
       background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23888' stroke-width='1.6' stroke-linecap='round'/></svg>");
       background-repeat:no-repeat;background-position:right 12px center;
       transition:border-color .12s,box-shadow .12s}
select:focus{border-color:var(--ink);box-shadow:0 0 0 3px var(--sel-bg)}
select option{background:var(--surface);color:var(--ink)}
button.primary{width:100%;margin-top:4px;border:1px solid var(--ink);cursor:pointer;
               padding:11px;border-radius:var(--r-sm);background:var(--ink);
               color:var(--surface);font:600 13.5px/1 var(--text);
               transition:opacity .12s}
button.primary:hover{opacity:.87}

#issueOut{display:none;margin-top:18px;max-width:460px;padding:20px;border-radius:var(--r);
          border:1px solid var(--rule);background:var(--surface);box-shadow:var(--shadow-2)}
#issueOut .rot{font-size:12px;font-weight:600;color:var(--muted)}
#issueOut .thekey{margin:12px 0;font:600 19px/1.45 var(--mono);word-break:break-all;color:var(--ink)}
#issueOut .meta{font-size:12.5px;color:var(--muted);line-height:1.7}
#issueOut .warn{margin-top:12px;font-size:12.5px;color:var(--i-warn);line-height:1.6;font-weight:500}
#issueOut button.act{margin-right:6px}

/* Los manuales por version salian como diez enlaces sueltos en fila: azul del
   navegador, subrayados y envueltos en una caja de 460px, gritando mas que la
   propia key. Son un recurso de respaldo -- el cliente que no va en la version
   actual --, asi que van plegados y en fichas del mismo material que
   button.act. La clase es `mlink` y no `act` porque la hoja de estilo califica
   esa por elemento: un <a class="act"> sale desnudo. */
#issueOut .manuals{margin-top:12px;padding-top:12px;border-top:1px solid var(--rule-soft)}
#issueOut .manuals>summary{font-size:12.5px;color:var(--muted);cursor:pointer;
                           list-style:none;display:flex;align-items:center;gap:6px;
                           user-select:none}
#issueOut .manuals>summary::-webkit-details-marker{display:none}
#issueOut .manuals>summary::before{content:"";width:0;height:0;flex:0 0 auto;
                                   border:4px solid transparent;border-left-color:var(--muted);
                                   margin-left:1px;transition:transform .12s}
#issueOut .manuals[open]>summary::before{transform:rotate(90deg)}
#issueOut .manuals>summary:hover{color:var(--ink-2)}
#issueOut .manuals .grp{margin-top:10px}
#issueOut .manuals .grp-t{margin-bottom:6px;font-size:11px;font-weight:600;
                          letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
#issueOut .manuals .chips{display:flex;flex-wrap:wrap;gap:5px}
#issueOut a.mlink{background:var(--surface);border:1px solid var(--rule);color:var(--ink-2);
                  padding:4px 9px;border-radius:var(--r-sm);text-decoration:none;
                  font:500 12px/1.25 var(--text);white-space:nowrap;
                  transition:background .12s,border-color .12s,color .12s}
#issueOut a.mlink:hover{background:var(--sel-bg);border-color:var(--muted);color:var(--ink)}

/* El resultado del alta de un reto, con la misma caja que #issueOut. Son DOS
   cajas y no una desde que el formulario vive en un dialogo: el alta que sale
   bien lo cierra, asi que su recibo (#challengeCreated) tiene que caer en el
   cuerpo de la vista, sobre la tabla que acaba de cambiar; el fallo
   (#challengeOut) se queda dentro del dialogo abierto, junto al campo que hay
   que corregir. `.failed` trae su propio fondo rojo, asi que un fallo se
   distingue de un alta hecha sin leer una palabra. */
#challengeOut,
#challengeCreated{display:none;margin-top:18px;max-width:460px;padding:20px;border-radius:var(--r);
              border:1px solid var(--rule);background:var(--surface);box-shadow:var(--shadow-2)}
#challengeOut .rot,
#challengeCreated .rot{font-size:12px;font-weight:600;color:var(--muted)}
#challengeOut .meta,
#challengeCreated .meta{margin-top:8px;font-size:12.5px;color:var(--muted);line-height:1.7}
#challengeOut .warn,
#challengeCreated .warn{margin-top:12px;font-size:12.5px;color:var(--i-warn);line-height:1.6;
                    font-weight:500}
#challengeOut .failed,
#challengeCreated .failed{margin:0}
/* Dentro del dialogo la caja no necesita techo de 460 px: el dialogo YA lo
   tiene, y un max-width mas estrecho que su contenedor deja el fallo
   descolgado a la izquierda del formulario que lo produjo. */
#challengeDialog #challengeOut{max-width:none;margin-top:16px}
/* El recibo va sobre la tabla, no debajo de un formulario que ya no esta ahi. */
#challengeCreated{margin:0 0 18px}

/* El desenlace vive en la celda de acciones, asi que no puede heredar el
   `width:100%` de un <select> de formulario: reventaria la columna. */
.actions select.outcome{width:auto;min-width:126px;padding:5px 26px 5px 9px;
                        font-size:12.5px;background-position:right 8px center}

/* El formulario de alta lista clientes y numeros de cuenta de la firma. En
   presentacion se esconde entero, igual que la vista de Alta de licencias:
   enmascarar el desplegable no basta si el resto del formulario invita a
   teclear los datos de un cliente delante de un visitante. Desde que vive en un
   dialogo hay que esconder tambien EL BOTON que lo abre y el dialogo entero: un
   formulario oculto detras de un boton visible sigue siendo un formulario al
   que se llega delante del visitante. */
body.present #challengeForm,
body.present #challengeNew,
body.present #challengeDialog,
body.present #challengeCreated,
body.present #challengeOut{display:none !important}

/* --------------------------------------------------- challenge intake dialog
   El alta de un reto (ver ChallengeDialog.astro). Comparte la caja con
   #licDialog -- misma superficie, mismo backdrop, mismo acento -- porque es el
   mismo objeto de la consola: un dialogo con un formulario largo. Y como aquel,
   lleva techo y scroll: son diecisiete campos, y sin max-height el boton de
   crear cae fuera de la pantalla en un portatil. */
#challengeDialog{
  border:1px solid var(--rule);border-radius:var(--r);background:var(--surface);
  color:var(--ink);padding:22px;width:100%;max-width:520px;box-shadow:var(--shadow-2);
  max-height:88vh;overflow:auto;
}
#challengeDialog::backdrop{background:rgba(4,8,13,.62)}
#challengeDialog h3{margin:0 0 4px;font:600 16px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
#challengeDialog .sub{margin:0 0 16px;font-family:var(--mono);font-size:12.5px;color:var(--muted)}
#challengeDialog :focus-visible{outline-color:var(--accent)}
#challengeDialog .act.primary{border-color:var(--accent);background:var(--accent);color:var(--page)}
#challengeDialog .callout{margin:0 0 16px}
#challengeDialog details.help{margin:0 0 16px;background:var(--page)}
/* El formulario conserva `class="issue"` -- de ahi salen el fieldset de «demo o
   real» y el resto de su vestido -- pero pierde la tarjeta: una caja con borde
   y sombra dentro de otra caja con borde y sombra es un marco de mas. */
#challengeDialog form.issue{border:0;background:none;border-radius:0;padding:0;
  max-width:none;box-shadow:none}
#challengeDialog form.issue .prod-acts{margin-top:4px}
/* .primary generico es `width:100%`, que aqui pondria «Dar de alta el reto» a
   lo ancho y «Cancelar» minusculo a su lado. En la hilera de acciones mandan
   las medidas de .act, como en los otros dos dialogos. */
#challengeDialog .prod-acts .primary{width:auto;margin-top:0;padding:5px 10px;
  font:500 12.5px/1 var(--text)}

/* La correccion de un reto. Nacio SIN una sola linea de CSS y salio con el
   <dialog> por defecto del navegador: caja blanca, sin techo, sin backdrop y
   tan ancha como la frase mas larga, con el formulario de 460px pegado a la
   izquierda y media pantalla vacia a la derecha. Un dialogo sin estilo no se
   ve «sencillo», se ve roto.
   Mismo objeto que #challengeDialog y por eso el mismo vestido, pero con mas
   del doble de campos: ademas de los terminos lleva el ajuste manual, las dos
   mitades, el desenlace y la bitacora. En UNA columna eso es un kilometro de
   scroll, asi que desde 720px los campos sueltos van a dos y las cajas siguen
   ocupando el ancho entero. */
#challengeEditDialog{
  border:1px solid var(--rule);border-radius:var(--r);background:var(--surface);
  color:var(--ink);padding:22px;width:calc(100% - 32px);max-width:780px;
  box-shadow:var(--shadow-2);max-height:88vh;overflow:auto;
}
#challengeEditDialog::backdrop{background:rgba(4,8,13,.62)}
#challengeEditDialog h3{margin:0 0 4px;font:600 16px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
#challengeEditDialog .sub{margin:0 0 16px;font-family:var(--mono);font-size:12.5px;color:var(--muted)}
#challengeEditDialog :focus-visible{outline-color:var(--accent)}
#challengeEditDialog .act.primary{border-color:var(--accent);background:var(--accent);color:var(--page)}
#challengeEditDialog details.help{margin:16px 0 0;background:var(--page)}
#challengeEditDialog form.issue{border:0;background:none;border-radius:0;padding:0;
  max-width:none;box-shadow:none}
#challengeEditDialog .prod-acts .primary{width:auto;margin-top:0;padding:5px 10px;
  font:500 12.5px/1 var(--text)}
#challengeEditDialog .prod-note{margin:0 0 16px}
/* El separador entre «los terminos» y «el dinero». Una regla fina y nada mas:
   lo que separa de verdad son los titulos de las cajas de abajo. */
#challengeEditDialog hr.sep{border:0;border-top:1px solid var(--rule-soft);margin:6px 0 16px}

@media (min-width:720px){
  #challengeEditDialog form.issue{display:grid;grid-template-columns:1fr 1fr;
    column-gap:18px;align-items:start}
  /* Todo lo que NO es un campo suelto cruza las dos columnas. Partir un
     fieldset o la hilera de acciones por la mitad es peor que no tener rejilla. */
  #challengeEditDialog form.issue > .productos,
  #challengeEditDialog form.issue > .prod-note,
  #challengeEditDialog form.issue > .lic-slots,
  #challengeEditDialog form.issue > .prod-acts,
  #challengeEditDialog form.issue > .reason,
  #challengeEditDialog form.issue > hr.sep{grid-column:1/-1}
  /* El ajuste manual SI va a dos columnas por dentro: son dos porcentajes
     hermanos y leerlos en vertical los desempareja. */
  #challengeEditDialog #challengeEditManualBox{display:grid;
    grid-template-columns:1fr 1fr;column-gap:16px}
  #challengeEditDialog #challengeEditManualBox legend,
  #challengeEditDialog #challengeEditManualBox > p,
  #challengeEditDialog #challengeEditManualBox > label:nth-of-type(3){grid-column:1/-1}
}

/* El motivo NO es un campo mas de la lista: es la condicion para que se guarde
   cualquier cosa. Va marcado, ancho entero y pegado a los botones. */
#challengeEditDialog .reason{margin:2px 0 16px;padding:12px 14px;background:var(--page);
  border:1px solid var(--rule);border-left:3px solid var(--accent);border-radius:var(--r-sm)}
#challengeEditDialog .reason label{margin:0}

/* Una mitad: su titulo y su estado arriba, sus dos campos debajo, sus botones
   al final. Antes reusaba .lic-slots-head, que es un flex de una linea pensado
   para «etiqueta ... valor»: con dos inputs y dos botones dentro se apretaba
   todo en una fila ilegible. */
#challengeEditDialog .half{padding:12px 14px;border:1px solid var(--rule);
  border-radius:var(--r-sm);background:var(--page)}
#challengeEditDialog .half + .half{margin-top:10px}
#challengeEditDialog .half-head{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
#challengeEditDialog .half-head b{font:600 13px/1 var(--mono);color:var(--ink)}
#challengeEditDialog .half-fields{display:grid;grid-template-columns:1fr 1fr;
  column-gap:12px;margin-bottom:4px}
#challengeEditDialog .half-fields label{margin-bottom:10px}
#challengeEditDialog .lic-slots > .slots-t{margin-bottom:10px;font-size:12.5px;
  font-weight:500;color:var(--ink-2)}
#challengeEditDialog .lic-slots .actions{justify-content:flex-start}

/* El recibo y el fallo, con la misma caja que #challengeCreated. */
#challengeEditOut{margin-top:14px}
#challengeEditOut .rot{font-size:12px;font-weight:600;color:var(--muted)}
#challengeEditOut .failed{margin:0}
#challengeEditLog .meta{padding:10px 0;border-bottom:1px solid var(--rule-soft)}
#challengeEditLog .meta:last-child{border-bottom:0}
#challengeEditLog b{display:block;margin-bottom:4px;font:600 12.5px/1.4 var(--text);color:var(--ink)}
#challengeEditLog .note{font-family:var(--mono);font-size:11.5px}

/* La barra que encabeza una vista: su frase a la izquierda, la accion que la
   crea a la derecha. Existe para que la tabla empiece arriba -- antes el alta
   de un reto era un muro de formulario debajo de ella. */
.view-bar{display:flex;align-items:flex-start;justify-content:space-between;
  gap:20px;margin:0 0 18px}
.view-bar p.lead{margin:0}
.view-bar .act.primary{flex:0 0 auto;border-color:var(--ink);background:var(--ink);
  color:var(--surface);width:auto;margin-top:0}
.view-bar .act.primary:hover{opacity:.87;background:var(--ink);border-color:var(--ink)}

/* help — <details> nativo: sin JS y accesible por teclado de fabrica */
details.help{margin:0 0 20px;border:1px solid var(--rule);border-radius:var(--r);
             background:var(--surface)}
details.help summary{
  cursor:pointer;padding:10px 15px;list-style:none;border-radius:var(--r);
  font-size:13px;font-weight:500;color:var(--ink-2);
  display:flex;align-items:center;gap:8px;user-select:none;
}
details.help summary::-webkit-details-marker{display:none}
details.help summary::before{content:"?";display:inline-flex;align-items:center;
  justify-content:center;width:17px;height:17px;border-radius:50%;
  background:var(--sel-bg);font-size:11px;color:var(--ink-2);flex:0 0 auto;font-weight:600}
details.help[open] summary{border-bottom:1px solid var(--rule);border-radius:var(--r) var(--r) 0 0}
details.help .inner{padding:15px 17px 17px;font-size:13.5px;line-height:1.7;color:var(--ink-2)}
details.help dl{margin:0;display:grid;grid-template-columns:auto 1fr;gap:9px 17px}
details.help dt{color:var(--ink);white-space:nowrap;font-size:13px;font-weight:600}
details.help dd{margin:0;color:var(--muted)}
details.help b{color:var(--ink);font-weight:600}

/* guide */
.guide-grid{display:grid;gap:18px;max-width:900px}
.card{border:1px solid var(--rule);background:var(--surface);border-radius:var(--r);
      padding:22px;box-shadow:var(--shadow-1)}
.card h3{margin:0 0 12px;font:600 15.5px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
.card p{margin:0 0 11px;font-size:13.5px;line-height:1.7;color:var(--ink-2);max-width:70ch}
.card p:last-child{margin-bottom:0}
.card strong{color:var(--ink);font-weight:600}

ol.steps{margin:0;padding:0;list-style:none;counter-reset:step}
ol.steps li{counter-increment:step;position:relative;padding:0 0 18px 40px;
            font-size:13.5px;line-height:1.7;color:var(--ink-2);max-width:70ch}
ol.steps li::before{
  content:counter(step);position:absolute;left:0;top:1px;
  width:25px;height:25px;display:flex;align-items:center;justify-content:center;
  border-radius:50%;background:var(--sel-bg);color:var(--ink);font-size:12px;font-weight:600;
}
ol.steps li::after{content:"";position:absolute;left:12px;top:27px;bottom:0;width:1px;
                   background:var(--rule)}
ol.steps li:last-child{padding-bottom:0}
ol.steps li:last-child::after{display:none}
ol.steps b{color:var(--ink)}
ol.steps .where{display:inline-block;padding:1px 7px;border-radius:var(--r-sm);
                background:var(--sel-bg);color:var(--ink);font-size:12px;
                margin:0 2px;white-space:nowrap;font-weight:500}

table.plain{width:100%;border-collapse:collapse;min-width:0}
table.plain td{padding:10px 0;border-bottom:1px solid var(--rule-soft);vertical-align:top;
               font-size:13.5px;line-height:1.65;color:var(--ink-2);white-space:normal}
table.plain tr:last-child td{border-bottom:0}
table.plain td:first-child{width:136px;padding-right:16px}
table.plain .btn{display:inline-block;padding:4px 9px;border-radius:var(--r-sm);
                 border:1px solid var(--rule);background:var(--surface-2);color:var(--ink);
                 font-size:12px;white-space:nowrap;font-weight:500}
table.plain .btn.red{border-color:color-mix(in srgb,var(--m-bad) 35%,var(--surface));
                     color:var(--i-bad)}

.callout{border-left:3px solid var(--m-warn);border-radius:0 var(--r-sm) var(--r-sm) 0;
         background:color-mix(in srgb,var(--m-warn) 8%,var(--surface));
         padding:13px 16px;font-size:13.5px;line-height:1.7;color:var(--ink-2)}
.callout b{color:var(--ink)}

/* ---------------------------------------------------- modo presentacion
   Enmascara la PII y esconde TODO lo destructivo. El enmascarado real lo
   hace panel.js sobre el DOM -- esto solo esconde lo que no debe estar en
   pantalla delante de alguien. Un filter:blur no valdria: se quita desde
   devtools y sale nitido en una captura. */
body.present .actions,
body.present button.act.danger,
body.present nav button[data-v="issue"],
body.present #v-issue,
body.present .mail,
body.present code.key,
body.present details.help{display:none !important}
body.present .body{padding:26px 30px 40px}
body.present .stat .n{font-size:24px}
body.present .stat.lead .n{font-size:40px}
body.present .vitals{padding:20px 30px 22px}
#presentBadge{display:none}
body.present #presentBadge{
  display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;
  color:var(--ink-2);background:var(--sel-bg);padding:5px 11px;border-radius:99px;
}

#gate{position:fixed;inset:0;z-index:50;background:var(--page);
      display:flex;align-items:center;justify-content:center;padding:20px}
#gate form{border:1px solid var(--rule);background:var(--surface);border-radius:var(--r);
           padding:32px;width:100%;max-width:410px;box-shadow:var(--shadow-2)}
#gate .mk{width:34px;height:34px;border-radius:9px;background:var(--brand);margin-bottom:16px}
#gate h1{margin:0 0 6px;font:600 25px/1.15 var(--text);letter-spacing:-.02em;color:var(--ink)}
#gate h1 b{font-weight:600}
#gate .tagline{margin:0 0 26px;font-size:13.5px;color:var(--muted)}
#gate .hint{margin:14px 0 0;font-size:12.5px;color:var(--muted);line-height:1.6}

@media (max-width:900px){
  /* minmax(0,1fr) y min-width:0 en el aside: la fila del menu (nav, con
     overflow-x:auto) mide ~875px de contenido, y sin esto la unica columna
     de la rejilla crecia hasta ese ancho y arrastraba la pagina entera a
     desplazarse de lado en el telefono. Medido el 2026-08-25 al anadir
     «Resultados» al menu. */
  .shell{grid-template-columns:minmax(0,1fr)}
  aside{position:static;height:auto;border-right:0;border-bottom:1px solid var(--rule);min-width:0}
  nav{min-width:0}
  nav{flex-direction:row;overflow-x:auto;padding:6px 8px}
  nav button{white-space:nowrap;padding:9px 12px}
  nav button.on::before{left:8px;right:8px;top:auto;bottom:0;width:auto;height:2px;
                        border-radius:2px 2px 0 0}
  nav button.guide{margin-top:0;border-top:0;padding-top:9px}
  .rail-foot{flex-direction:row;border-top:1px solid var(--rule)}
  .vitals{padding:10px 14px 12px}
  .body{padding:16px 14px 30px}
  /* minmax(0,…) y no 1fr a secas: un 1fr no baja de min-content, y la lista
     de cuentas en «reportando» empujaba la rejilla fuera de la pantalla. */
  .hero{grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
  .stat .d{overflow-wrap:anywhere}
  .rail-foot{flex-wrap:wrap}
  .rail-foot button{width:auto;flex:1 1 40%}
  .shell{overflow-x:hidden}
  /* Vitales plegados por defecto en movil. */
  .vitals-brief{display:flex}
  .vitals:not(.open) .vitals-full{display:none}
  .vitals.open .vitals-brief .chev{transform:rotate(180deg)}
  .stat.lead .n{font-size:28px}
  .stat.alarm{flex-wrap:wrap}
  .stat.alarm .d{margin-left:0;width:100%;text-align:left}
}

/* Selector de productos del alta. Un fieldset y no dos checkboxes sueltos: lo
   que se marca aqui decide que robots abre la clave, y agruparlos bajo su
   pregunta es lo que impide que se lean como dos ajustes mas de la lista. */
.issue .productos{grid-column:1/-1;margin:4px 0 2px;padding:12px 14px;
  border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--page)}
.issue .productos legend{padding:0 6px;font-size:11.5px;font-weight:500;color:var(--muted)}
.issue .productos .check{display:inline-flex;align-items:center;gap:7px;
  margin-right:18px;font:500 13.5px/1 var(--text);color:var(--ink);cursor:pointer}
.issue .productos .check input{width:15px;height:15px;accent-color:var(--sel-bg);cursor:pointer}
.issue .productos .check small{color:var(--muted);font-size:11px;font-family:var(--mono)}

/* --------------------------------------------------- products dialog
   Que bots cubre una clave ya emitida (ver ProductsDialog.astro). <dialog>
   nativo: el navegador ya pone backdrop y foco atrapado, asi que esto solo
   lo viste en Direction A -- superficie oscura, borde de un pixel, y el
   acento azul frio reservado para lo unico que importa aqui: guardar. */
#prodDialog{
  border:1px solid var(--rule);border-radius:var(--r);background:var(--surface);
  color:var(--ink);padding:22px;width:100%;max-width:420px;box-shadow:var(--shadow-2);
}
#prodDialog::backdrop{background:rgba(4,8,13,.62)}
#prodDialog h3{margin:0 0 4px;font:600 16px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
#prodDialog .sub{margin:0 0 16px;font-family:var(--mono);font-size:12.5px;color:var(--muted)}
/* El acento propio del dialogo: mas fuerte que el --ink generico de
   button.primary en el resto de la consola porque aqui es la unica accion
   destacada de la pantalla. */
#prodDialog :focus-visible{outline-color:var(--accent)}

.prod-list{display:flex;flex-direction:column;gap:10px;margin:0 0 14px;
  padding:12px 14px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--page)}
.prod-list .check{display:flex;align-items:center;gap:9px;
  font:500 13.5px/1 var(--text);color:var(--ink);cursor:pointer}
.prod-list .check input{width:15px;height:15px;accent-color:var(--accent);cursor:pointer}
.prod-list .check small{margin-left:auto;font-family:var(--mono);font-size:11px;color:var(--muted)}

.prod-warn{margin:0 0 12px;padding:10px 12px;border-radius:var(--r-sm);
  font-size:12.5px;line-height:1.6;color:var(--i-warn);
  background:color-mix(in srgb,var(--m-warn) 9%,var(--surface));
  border:1px solid color-mix(in srgb,var(--m-warn) 26%,var(--surface))}

.prod-note{margin:0 0 18px;font-size:12.5px;line-height:1.6;color:var(--muted)}
.prod-note b{color:var(--ink-2);font-weight:600}

.prod-acts{display:flex;justify-content:flex-end;gap:8px}
#prodDialog .act.primary{border-color:var(--accent);background:var(--accent);color:var(--page)}
#prodDialog .act.primary:hover{opacity:.87;background:var(--accent);border-color:var(--accent)}

/* --------------------------------------------------- licence detail dialog
   La ficha de una clave emitida (ver LicenceDialog.astro). Comparte la caja
   con #prodDialog -- misma superficie, mismo backdrop, mismo acento -- porque
   son el mismo objeto de la consola: un dialogo que edita una licencia. Lo
   unico propio es que este tiene formulario largo, asi que se le pone techo y
   scroll: sin max-height, con seis campos y cuatro cuentas activadas, el boton
   de guardar cae fuera de la pantalla en un portatil. */
#licDialog{
  border:1px solid var(--rule);border-radius:var(--r);background:var(--surface);
  color:var(--ink);padding:22px;width:100%;max-width:460px;box-shadow:var(--shadow-2);
  max-height:88vh;overflow:auto;
}
#licDialog::backdrop{background:rgba(4,8,13,.62)}
#licDialog h3{margin:0 0 4px;font:600 16px/1.3 var(--text);letter-spacing:-.01em;color:var(--ink)}
#licDialog .sub{margin:0 0 16px;font-family:var(--mono);font-size:12.5px;color:var(--muted)}
#licDialog :focus-visible{outline-color:var(--accent)}
#licDialog .act.primary{border-color:var(--accent);background:var(--accent);color:var(--page)}

/* Los datos que NO se editan aqui: se leen de un vistazo y no compiten con los
   campos. De ahi la retícula y no otra lista de <label>. */
.lic-facts{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:0 0 14px;
  padding:12px 14px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--page)}
.lic-fact span{display:block;font-size:11px;color:var(--muted);margin-bottom:3px}
.lic-fact b{font:600 13px/1.3 var(--text);color:var(--ink)}

.lic-slots{margin:0 0 16px;padding:12px 14px;border:1px solid var(--rule);
  border-radius:var(--r-sm);background:var(--page)}
.lic-slots-head{display:flex;align-items:baseline;justify-content:space-between;
  margin-bottom:8px;font-size:12.5px;color:var(--ink-2)}
.lic-slots-head b{font:600 13px/1 var(--mono);color:var(--ink)}
/* Lleno se dice en rojo, no solo en numeros: es la razon por la que se abre
   esta ficha. */
.lic-slots-head b.neg{color:var(--i-bad)}
.lic-acct{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:5px 0;font:13px/1.4 var(--mono);color:var(--ink-2)}
.lic-acct + .lic-acct{border-top:1px solid var(--rule)}
.lic-slots .faint{font-family:var(--text);font-size:12.5px}

/* ==================================================================
   CUENTAS EN VIVO — el tablero de operacion.

   Una TARJETA por cuenta, no una fila de tabla. La fila trataba todas
   las columnas como iguales; aqui las dos cifras que este proyecto
   considera decisivas -- neto y PEOR FLOTANTE (ver CLAUDE.md: "judge
   by net USD and worst floating, never by win rate") -- van en grande
   y el resto queda de contexto. En la version anterior el peor
   flotante estaba enterrado en una tabla y no se veia.

   Las tarjetas SON el selector: pulsar una cambia el detalle de abajo.
   Antes habia un <select> aparte que solo mostraba el numero de cuenta,
   sin el nombre -- dos sitios para decir lo mismo y el peor de los dos
   elegia.
   ================================================================== */
/* La franja de cuentas compartidas. Borde rojo y no un simple color de texto:
   es la unica cosa de esta vista que no describe una cuenta sino una
   inconsistencia entre licencias, y tiene que leerse como tal. */
.acct-conflicts{display:grid;gap:6px;margin:0 0 14px;padding:10px 12px;
  border:1px solid var(--i-bad);border-radius:8px;background:var(--rule-soft)}
.conflict-line{font-size:12.5px;color:var(--txt)}
.conflict-line b{color:var(--i-bad)}

.acct-board{display:grid;gap:12px;margin:14px 0 4px;
  grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}

.acct-card{position:relative;text-align:left;width:100%;
  border:1px solid var(--rule);background:var(--surface);
  border-radius:2px;padding:13px 14px 12px;cursor:pointer;
  /* La lampara de arriba a la izquierda del sistema, en pequeno. */
  background-image:linear-gradient(160deg,var(--surface-2) 0%,var(--surface) 46%);
  transition:border-color .12s ease, transform .12s ease}
.acct-card:hover{border-color:var(--rule);transform:translateY(-1px)}
.acct-card.on{border-color:var(--i-accent,var(--m-data))}
/* La barra izquierda dice el estado de captura SIN depender del color:
   la tarjeta seleccionada tambien lo lleva, asi que forma y color no
   compiten por significar lo mismo. */
.acct-card.on::before{content:"";position:absolute;left:-1px;top:-1px;bottom:-1px;
  width:2px;background:var(--m-data)}

.acct-card .row1{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.acct-card .who{font:600 13px/1.25 var(--text);color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* El nombre que el terminal le da a la cuenta, cuando NO es el del cliente y
   dice algo. Va debajo y apagado: sirve para casar la tarjeta con MetaTrader,
   no para identificar al cliente. */
.acct-card .who-mt{font:11.5px/1.35 var(--text);color:var(--muted);
  margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-card .meta{font:11.5px/1.4 var(--mono);color:var(--muted);
  margin-top:2px;margin-bottom:11px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Dos cifras, mismo peso visual: lo que tiene en riesgo AHORA y lo que
   lleva ganado HOY. Ninguna de las dos cuenta la historia sola. */
.acct-card .pair{display:grid;grid-template-columns:1fr 1fr;gap:10px;
  padding-top:10px;border-top:1px solid var(--rule-soft)}
.acct-card .pair.three{grid-template-columns:1fr 1fr 1fr;gap:8px}
.acct-card .pair.three .v{font-size:16px}
/* Las tres etiquetas ocupan una linea cada una o las cifras dejan de alinearse
   entre si. */
.acct-card .pair.three .k{font-size:9.5px;letter-spacing:.02em;white-space:nowrap}
.acct-card .pair.three > div{min-width:0}
.acct-card .k{font-size:10.5px;font-weight:500;color:var(--muted);
  letter-spacing:.04em;text-transform:uppercase}
.acct-card .v{font:600 19px/1.1 var(--mono);letter-spacing:-.02em;color:var(--ink);
  font-variant-numeric:tabular-nums;margin-top:3px;white-space:nowrap}
/* Una cifra en centavos lleva cinco digitos y su unidad, y a 16px no cabe en
   un tercio de tarjeta. `:has(.vsub)` = solo las de centavos. */
.acct-card:has(.vsub) .pair.three .v{font-size:14.5px}
.acct-card:has(.vsub) .pair.three .k{font-size:9px}
.acct-card .v.pos{color:var(--i-ok)}
.acct-card .v.neg{color:var(--i-bad)}
/* El equivalente en dolares de una cuenta de centavos. Deliberadamente mas
   pequeno que la cifra de arriba: la que manda es la del broker, que es la
   unica que se puede cotejar contra el terminal. */
.acct-card .vsub{font:10.5px/1.2 var(--mono);color:var(--muted);
  font-variant-numeric:tabular-nums;margin-top:3px}

/* La linea de riesgo. Va separada y en rojo apagado porque es la cifra
   que la ganancia esconde, no un adorno del pie de la tarjeta. */
.acct-card .risk{display:flex;align-items:baseline;gap:6px;margin-top:11px;
  padding-top:9px;border-top:1px solid var(--rule-soft);
  font:11.5px/1.45 var(--mono);color:var(--muted)}
.acct-card .risk b{color:var(--i-bad);font-weight:600}
.acct-card .risk .sep{color:var(--rule)}

.acct-empty{border:1px dashed var(--rule);border-radius:2px;padding:22px 16px;
  text-align:center;color:var(--muted);font-size:13px}

/* cliente.html. `.actions` es nowrap para las celdas de tabla de la consola. */
#cliOut .actions{flex-wrap:wrap}
#cliOut .lic-slots{margin-bottom:10px}
#cliOut .lic-slots:last-child{margin-bottom:0}
#cliOut .card{margin-bottom:16px}
#cliOut .card h3{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}

/* Cabecera del detalle: dice SIEMPRE de que cuenta se esta hablando.
   Un panel donde las graficas cambian sin decir de quien son es un
   panel que se lee mal a los dos minutos. */
.acct-detail-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  margin:26px 0 2px;padding-top:18px;border-top:1px solid var(--rule)}
.acct-detail-head h3{margin:0;font:600 15px/1.3 var(--text);color:var(--ink)}
.acct-detail-head .sub{font:12px/1.4 var(--mono);color:var(--muted)}

.range-filter{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:10px 0 4px}
.range-btn{background:var(--surface);border:1px solid var(--rule);color:var(--ink-2);
  padding:6px 11px;cursor:pointer;border-radius:var(--r-sm);
  font:500 12px/1 var(--text);transition:background .12s,border-color .12s}
.range-btn:hover{background:var(--sel-bg);border-color:var(--muted)}
.range-btn.on{background:var(--sel-bg);color:var(--sel-ink);font-weight:600;
  border-color:var(--sel-bg)}
.range-custom{display:flex;align-items:center;gap:6px}
.range-custom input{width:auto;padding:5px 8px;font-size:12px}

.live-filters{display:flex;flex-wrap:wrap;gap:20px;margin-bottom:16px}
.filter-group{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.filter-label{font:600 11px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);margin-right:2px}
.chip{background:var(--surface);border:1px solid var(--rule);color:var(--ink-2);
  padding:6px 11px;cursor:pointer;border-radius:var(--r-sm);
  font:500 12px/1 var(--text);transition:background .12s,border-color .12s}
.chip:hover{background:var(--sel-bg);border-color:var(--muted)}
.chip.on{background:var(--sel-bg);color:var(--sel-ink);font-weight:600;border-color:var(--sel-bg)}

/* ------------------------------------------------------------ Resultados */
.res-kpis{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:16px 24px;
  margin:6px 0 14px;padding:14px 16px;border:1px solid var(--rule);background:var(--surface);
  border-radius:var(--r)}
@media (max-width:900px){ .res-kpis{grid-template-columns:repeat(2,minmax(0,1fr))} }
.res-kpis .n{font-size:22px}
.matrix-wrap{overflow:auto;max-height:70vh}
.matrix th,.matrix td{white-space:nowrap}
/* La primera columna (la cuenta) y la cabecera quedan fijas: con 30 dias la
   tabla se desplaza y sin esto se pierde de que cuenta es la fila. */
.matrix th:first-child,.matrix td:first-child{position:sticky;left:0;background:var(--surface);z-index:1}
.matrix thead th{position:sticky;top:0;background:var(--surface);z-index:2}
.matrix thead th:first-child{z-index:3}
.matrix td.cell{text-align:right;padding:6px 10px;line-height:1.25}
.matrix td.cell .fl{display:block;font-size:11px;color:var(--muted)}
.matrix td.cell .fl.neg{color:var(--danger)}
.matrix td.cell.empty{color:var(--rule);text-align:center}
.matrix td.tot,.matrix th.tot{border-left:1px solid var(--rule);font-weight:600}
.matrix tfoot td{border-top:1px solid var(--rule);font-weight:600;background:var(--surface-2)}
.matrix .who{display:block;font-weight:600}
.matrix .who-name{display:block;font-size:12px;color:var(--ink-2)}
.matrix .who-sub{display:block;font:11px var(--mono);color:var(--muted)}

/* ------------------------------------------------------- vitals (movil) */
.vitals-brief{display:none;width:100%;align-items:center;justify-content:space-between;gap:10px;
  background:var(--surface);border:1px solid var(--rule);color:var(--ink);cursor:pointer;
  padding:9px 12px;border-radius:var(--r-sm);font:500 12.5px/1.3 var(--mono);text-align:left}
.vitals-brief .chev{color:var(--muted);transition:transform .15s}
.vitals.open .vitals-brief{margin-bottom:14px}
/* Repetido aqui y no solo en el bloque movil de arriba: esta regla base
   viene DESPUES de aquel bloque en el fichero y le ganaba, dejando el boton
   oculto tambien en el telefono. */
@media (max-width:900px){ .vitals-brief{display:flex} }

/* --------------------------------------------------- ficha de cuenta */
.acct-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:14px}
.acct-head .acct-id h3{margin:0;font:600 16px/1.3 var(--text);color:var(--ink)}
.acct-head .acct-id .sub{font:12px/1.5 var(--mono);color:var(--muted)}
.acct-now{display:flex;align-items:center;gap:10px 18px;flex-wrap:wrap;
  border:1px solid var(--rule);background:var(--surface);border-radius:var(--r);
  padding:12px 14px;margin:10px 0 14px}
.acct-now .pair{display:flex;align-items:baseline;gap:6px;font:12.5px/1.3 var(--text);color:var(--muted)}
.acct-now .pair b{font:600 14px/1.2 var(--mono);color:var(--ink)}
.acct-now .pair b.neg{color:var(--i-bad)}
.acct-now .pair b.pos{color:var(--i-ok)}
.table.inner{border:0;box-shadow:none;background:transparent;max-height:224px;overflow:auto}
.table.log{max-height:320px;overflow:auto}
.table.log td{vertical-align:top}
.log-detail{font:11.5px/1.5 var(--mono);color:var(--muted);word-break:break-word}
#tbResults tr.clickable{cursor:pointer}
#tbResults tr.clickable:hover{background:var(--sel-bg)}

/* El historial de comandos de Odin. Una fila por comando, y el color dice el
   estado: ejecutado (confirmado por el robot) frente a en cola o entregado
   (todavia sin confirmar). La diferencia importa sobre una posicion viva. */
.cmdrow{display:flex;gap:.4rem;align-items:baseline;flex-wrap:wrap;
  padding:.3rem .55rem;border-left:3px solid var(--line);margin-bottom:.25rem;
  font-size:.86rem}
.cmdrow.ok{border-left-color:var(--ok)}
.cmdrow.wait{border-left-color:var(--warn)}
.odin-bar,.odin-cmd{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap;
  margin:.6rem 0}
.odin-cmdlog{margin:.5rem 0}

/* El area "tu robot" de la pagina de cliente. Separada del resto porque es la
   unica parte que pide la key: el robot se compila por licencia y ya no es un
   fichero que pueda descargar cualquiera. */
.mine{margin:22px 0 6px;padding:16px 18px;border:1px solid var(--line);border-radius:10px}
.mine-row{display:flex;gap:.5rem;flex-wrap:wrap;margin:.6rem 0}
.mine-row input{flex:1 1 22rem;min-width:16rem;padding:.55rem .7rem;font-family:inherit;
  font-size:.95rem;border:1px solid var(--line);border-radius:8px;
  background:var(--bg);color:var(--txt)}
.mine .dl{display:flex;gap:.5rem;align-items:baseline;flex-wrap:wrap;margin:.35rem 0}
.mine .wait{color:var(--amber)}
/* Los enlaces de descarga del robot son <a>, no <button>: el fichero vive en
   otro origen y una descarga por script se pierde en el bloqueo de ventanas.
   Sin esto heredan el azul subrayado del navegador y desentonan con el resto
   de los botones de la pagina. */
.mine .dl a.act{display:inline-block;text-decoration:none;font-weight:600}
.mine .dl a.act:hover{text-decoration:none}

/* La caja para enviar un aviso al terminal del cliente. */
.odin-alert{display:flex;gap:.5rem;margin:.6rem 0;flex-wrap:wrap}
.odin-alert input{flex:1 1 24rem;min-width:14rem;padding:.5rem .7rem;font-family:inherit;
  font-size:.9rem;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--txt)}

/* La descarga del robot en "Tu robot". Una tarjeta por producto, con el nombre
   y la version a la izquierda y el boton de descargar a la derecha -- no la
   lista de hashes que parecia un volcado de depuracion. */
.robotdl{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  flex-wrap:wrap;padding:.7rem .9rem;margin:.5rem 0;border:1px solid var(--line);
  border-radius:10px;background:var(--card)}
.robotdl-info{display:flex;align-items:baseline;gap:.55rem;flex-wrap:wrap}
.robotdl-info b{font-size:1rem}
.robotdl-ver{color:var(--dim);font-size:.9rem}
.robotdl-sha{color:var(--dim);font-size:.72rem;font-family:ui-monospace,Menlo,Consolas,monospace;opacity:.6}
.robotdl .actions{flex-wrap:wrap;align-items:center;gap:.5rem}
/* Las tres acciones de la tarjeta son elementos distintos -- <a> el robot,
   <button> los .set, <a> los documentos -- y la hoja califica `button.act`
   por elemento: sin esta regla el manual y la guia rapida salian con el
   morado subrayado del navegador al lado de dos botones con borde. Mismo
   caso que .manuals en #issueOut. */
.robotdl .act{display:inline-flex;align-items:center;padding:.45rem .85rem;
  border:1px solid var(--line);border-radius:8px;background:var(--card);
  color:var(--dim);font-family:inherit;font-size:.85rem;font-weight:500;
  line-height:1.2;text-decoration:none;cursor:pointer;
  transition:background .12s,border-color .12s,color .12s}
.robotdl .act:hover{border-color:var(--dim);color:var(--txt);text-decoration:none}
.robotdl .act.primary{background:var(--blue);color:#fff;border-color:var(--blue);
  padding:.45rem 1.1rem;font-weight:600;text-decoration:none;border-radius:8px}
.robotdl .act.primary:hover{opacity:.9;color:#fff;border-color:var(--blue)}
.robotdl.wait{opacity:.75}
