/* ASISBOT — Panel
   ─────────────────────────────────────────────────────────────────
   Pensado para leerse en una pantalla de oficina y en un móvil. Lo
   segundo no es un extra: la decisión del 04/09/2026 fue responsive
   justamente porque el uso real es «el jefe mira desde el móvil».

   Sin librerías de estilos: son cuatrocientas líneas y así no hay nada
   que actualizar en la VM de cada empresa. */

/* ── Los dos modos ────────────────────────────────────────────────
   El modo NO se decide aquí con `prefers-color-scheme`, sino con el
   atributo `data-tema` del `<html>`. Lo pone el trocito de JavaScript que
   hay en la cabecera de `index.html`, ANTES de que se pinte nada: mira si
   hay una elección guardada y, si no la hay, usa la del sistema.

   ⚠️ POR QUÉ NO HAY ADEMÁS UN `@media (prefers-color-scheme: dark)`:
   harían falta los mismos catorce colores escritos dos veces, y el día que
   alguien cambiara uno solo en una de las dos copias tendríamos un modo
   con un color desparejado y ninguna forma de enterarse. Se escriben una
   vez. El panel no funciona sin JavaScript de todas formas —sin él no hay
   ni tabla que mirar—, así que no se pierde nada. */
:root {
  color-scheme: light;
  --fondo: #f4f6f8;
  --papel: #ffffff;
  --papel-2: #eef1f5;
  --texto: #131820;
  --apagado: #5d6874;
  --borde: #dce1e8;
  --borde-suave: #e8ecf1;
  --acento: #1f6feb;
  --acento-suave: #e7f0fe;
  --bien: #117a45;
  --ojo: #9a5b00;
  --mal: #b5321f;
  --radio: 12px;
  --radio-chico: 8px;
  --sombra: 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .06);
}

/* ⚠️ TODO COLOR QUE SE AÑADA ARRIBA TIENE QUE APARECER TAMBIÉN AQUÍ. Si
   falta, el modo oscuro se queda con el valor claro y nadie lo ve venir:
   texto casi blanco sobre fondo casi blanco, y solo en un modo. Hay una
   prueba que lo comprueba (`test_estaticos_web.py`) precisamente porque es
   un fallo que no se nota hasta que lo ve un cliente. */
:root[data-tema="oscuro"] {
  color-scheme: dark;
  --fondo: #0f1319;
  --papel: #171c24;
  --papel-2: #1f262f;
  --texto: #e9edf2;
  --apagado: #98a4b3;
  --borde: #2a323d;
  --borde-suave: #232a34;
  --acento: #5b9dff;
  --acento-suave: #18263c;
  --bien: #47c485;
  --ojo: #e2a84a;
  --mal: #f0776a;
  --sombra: none;
}

* { box-sizing: border-box; }

/* ⚠️ ESTO NO ES DECORACIÓN, ES LO QUE HACE QUE LA APLICACIÓN FUNCIONE
   (17/09/2026). El navegador oculta un elemento con `hidden` aplicándole
   `display: none`, pero CUALQUIER regla propia que ponga `display` le
   gana. `#pantalla-entrar` lleva `.centrado`, que es `display: flex`, así
   que al entrar el panel se pintaba debajo y la pantalla de login se
   quedaba encima sin ocultarse: sesión iniciada y nada que ver.
   Síntoma engañoso, porque en el servidor todo salía bien. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--fondo);
  color: var(--texto);
  -webkit-text-size-adjust: 100%;
}

main { padding: 20px 16px 48px; max-width: 1180px; margin: 0 auto; }

h1 { font-size: 1.45rem; margin: 0 0 4px; letter-spacing: -.01em; }
h2 { font-size: 1rem; margin: 0 0 14px; letter-spacing: -.005em; }
h3 { font-size: .95rem; margin: 0 0 6px; }

.apagado { color: var(--apagado); }
.crece { flex: 1; }
.chico { font-size: .85rem; }

/* ── Barra superior ───────────────────────────────────────────── */
.barra {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  background: var(--papel);
  border-bottom: 1px solid var(--borde);
  position: sticky; top: 0; z-index: 20;
}
.barra .marca { font-weight: 700; letter-spacing: .02em; }

/* El botón de claro/oscuro. En una pantalla estrecha se queda solo el
   símbolo: el texto ocuparía el sitio del correo de quien ha entrado. */
button.tema { white-space: nowrap; }
button.tema .simbolo { font-size: 1rem; line-height: 1; }
@media (max-width: 560px) {
  button.tema .palabra { display: none; }
  button.tema { padding-left: 10px; padding-right: 10px; }
}

/* Las pestañas. En móvil se quedan en su fila y se deslizan de lado. */
.pestanas {
  display: flex; gap: 4px;
  padding: 0 16px;
  background: var(--papel);
  border-bottom: 1px solid var(--borde);
  position: sticky; top: 53px; z-index: 19;
  overflow-x: auto; scrollbar-width: none;
}
.pestanas::-webkit-scrollbar { display: none; }
.pestanas button {
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 11px 14px; margin-bottom: -1px;
  color: var(--apagado); font: inherit; font-weight: 600;
  white-space: nowrap; cursor: pointer; border-radius: 0;
}
.pestanas button:hover { color: var(--texto); }
.pestanas button[aria-selected="true"] {
  color: var(--acento); border-bottom-color: var(--acento);
}

/* ── Tarjetas ─────────────────────────────────────────────────── */
.tarjeta {
  background: var(--papel);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: 18px;
  margin-bottom: 16px;
  box-shadow: var(--sombra);
}
.tarjeta > h2 { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }

.centrado {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.estrecha { width: 100%; max-width: 380px; margin: 0; }
.pie-entrar { display: flex; justify-content: center; margin-top: 16px; }

.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 16px;
  margin-bottom: 20px;
}

.fila { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.fila input { flex: 1; min-width: 180px; }

/* ── Formularios ──────────────────────────────────────────────── */
label { display: block; margin: 12px 0 4px; font-weight: 600; font-size: .9rem; }

input, select {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--borde); border-radius: var(--radio-chico);
  background: var(--fondo); color: var(--texto);
  font: inherit;
}
input:focus, select:focus { outline: 2px solid var(--acento); outline-offset: 1px; }

button {
  padding: 9px 16px; border: 0; border-radius: var(--radio-chico);
  background: var(--acento); color: #fff;
  font: inherit; font-weight: 600; cursor: pointer;
}
button:disabled { opacity: .5; cursor: progress; }
button.secundario {
  background: transparent; color: var(--acento);
  border: 1px solid var(--borde);
}
button.secundario:hover { background: var(--acento-suave); }
button.chico { padding: 5px 11px; font-size: .85rem; }
#boton-entrar { width: 100%; margin-top: 16px; }

.error {
  margin-top: 12px; padding: 10px 12px;
  background: color-mix(in srgb, var(--mal) 13%, transparent);
  border-radius: var(--radio-chico); color: var(--mal);
}
.aviso {
  padding: 10px 12px; margin-bottom: 14px;
  background: color-mix(in srgb, var(--ojo) 14%, transparent);
  border-radius: var(--radio-chico); color: var(--ojo);
  font-size: .88rem;
}

/* ── Estado de los robots ─────────────────────────────────────── */
/* Las tres tarjetas de los robots son lo primero que se ve al entrar y lo
   que de verdad contesta «¿esto está funcionando?». Con el tamaño de una
   fila de tabla quedaban perdidas en una pantalla vacía. */
.robot {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 22px 20px; min-height: 124px;
}
.robot .nombre {
  font-weight: 700; text-transform: capitalize;
  font-size: 1.15rem; letter-spacing: -.01em; margin-bottom: 2px;
}
.robot .estado-texto { font-size: .95rem; }
.robot button { align-self: center; }
.punto { width: 12px; height: 12px; border-radius: 50%; flex: none; margin-top: 8px; }
.punto.bien { background: var(--bien); box-shadow: 0 0 0 4px color-mix(in srgb, var(--bien) 20%, transparent); }
.punto.ojo  { background: var(--ojo);  box-shadow: 0 0 0 4px color-mix(in srgb, var(--ojo) 20%, transparent); }
.punto.mal  { background: var(--mal);  box-shadow: 0 0 0 4px color-mix(in srgb, var(--mal) 20%, transparent); }

/* El punto verde late despacio: dice «esto se está moviendo ahora mismo»
   sin necesidad de leer nada. Quien haya pedido menos animación, no la ve. */
.punto.bien { animation: pulso 2.4s ease-in-out infinite; }
@keyframes pulso {
  50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--bien) 6%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .punto.bien { animation: none; } }

/* ⚠️ EL ÚLTIMO ERROR DE UN ROBOT SE VE. Se estaba guardando en la base sin
   que la pantalla lo enseñara, y así los tres robots pasaron una noche
   entera con un 404 de INVESTEL sin que nadie se enterara (17/09/2026). */
.robot-error {
  margin-top: 8px; padding: 7px 9px;
  background: color-mix(in srgb, var(--mal) 12%, transparent);
  border-radius: 6px; color: var(--mal);
  font-size: .82rem; line-height: 1.4;
}
.robot-error .cuando { font-size: .78rem; opacity: .85; }

/* Un error de hace días no es una alarma: es historia. Se sigue viendo
   —perderlo de vista fue el fallo anterior— pero en gris, porque si la
   pantalla está roja todas las mañanas se deja de mirar el rojo. */
.robot-error.pasado {
  background: var(--papel-2);
  color: var(--apagado);
}

/* ── Etiquetas ────────────────────────────────────────────────── */
.etiquetas { display: flex; flex-wrap: wrap; gap: 8px; }
.etiqueta {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 5px 11px; border-radius: 999px;
  background: var(--papel-2); border: 1px solid var(--borde-suave);
  font-size: .85rem;
}
.etiqueta b { font-variant-numeric: tabular-nums; font-size: .95rem; }

/* Estados de un servicio, con color. El color va por lo que significa, no
   por bonito: verde acabado, azul en marcha, ámbar esperando algo, rojo lo
   que hay que mirar. */
.estado {
  display: inline-block; padding: 3px 9px; border-radius: 999px;
  font-size: .8rem; font-weight: 600; white-space: nowrap;
  background: var(--papel-2); color: var(--apagado);
}
.estado.e-finalizado { background: color-mix(in srgb, var(--bien) 16%, transparent); color: var(--bien); }
.estado.e-asignado,
.estado.e-en_camino,
.estado.e-localizado { background: var(--acento-suave); color: var(--acento); }
.estado.e-aceptado,
.estado.e-detectado { background: color-mix(in srgb, var(--ojo) 16%, transparent); color: var(--ojo); }
.estado.e-error,
.estado.e-rechazado,
.estado.e-derivado_encargado { background: color-mix(in srgb, var(--mal) 15%, transparent); color: var(--mal); }

/* ── Tablas ───────────────────────────────────────────────────── */
.desplazable { overflow-x: auto; margin: 0 -18px; padding: 0 18px; }

table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th, td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--borde-suave); }
thead th {
  color: var(--apagado); font-weight: 600; font-size: .78rem;
  text-transform: uppercase; letter-spacing: .04em;
  white-space: nowrap; border-bottom-color: var(--borde);
}
tbody tr { cursor: pointer; }
tbody tr:hover { background: var(--papel-2); }
tbody tr:last-child td { border-bottom: 0; }
td.expediente {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .85rem; white-space: nowrap;
}
td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
td.recorta { max-width: 230px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cuantos { color: var(--apagado); font-weight: 400; font-size: .85rem; }

/* ── Atención ─────────────────────────────────────────────────── */
/* Lo primero de la página y lo único que pide una acción. Cuando no hay
   nada, se dice: una tarjeta en blanco parece que no ha cargado. */
#atencion h2 { display: flex; align-items: center; gap: 10px; }
#atencion .contador {
  background: var(--mal); color: #fff;
  border-radius: 999px; padding: 1px 9px;
  font-size: .8rem; font-variant-numeric: tabular-nums;
}
#atencion.todo-bien { border-color: color-mix(in srgb, var(--bien) 35%, var(--borde)); }
#atencion .bien-mensaje { color: var(--bien); margin: 0; font-weight: 600; }

.frase { margin: 0 0 12px; font-size: 1.05rem; line-height: 1.5; }
.frase b { font-variant-numeric: tabular-nums; }

.etiqueta.bien { border-color: color-mix(in srgb, var(--bien) 45%, transparent); color: var(--bien); }
.etiqueta.ojo  { border-color: color-mix(in srgb, var(--ojo) 45%, transparent); color: var(--ojo); }

/* ── Conmutadores ─────────────────────────────────────────────── */
/* Un filtro encendido tiene que verse encendido de lejos. Una casilla
   marcada son cuatro píxeles; esto es el botón entero. */
.conmutadores { align-items: center; }

button.conmutador {
  background: transparent; color: var(--apagado);
  border: 1px solid var(--borde);
  border-radius: 999px; padding: 7px 14px;
  font-weight: 600; font-size: .87rem;
}
button.conmutador:hover { color: var(--texto); border-color: var(--apagado); }
button.conmutador[aria-pressed="true"] {
  background: var(--acento); color: #fff; border-color: var(--acento);
}
/* El directo encendido parpadea despacio: dice «esto se está moviendo»
   sin robar atención. Quien haya pedido menos animación, no la ve. */
#log-directo[aria-pressed="true"] { animation: latir 2s ease-in-out infinite; }
@keyframes latir { 50% { opacity: .72; } }
@media (prefers-reduced-motion: reduce) {
  #log-directo[aria-pressed="true"] { animation: none; }
}

/* ── Cabeceras ordenables ─────────────────────────────────────────── */
th.ordenable { cursor: pointer; user-select: none; white-space: nowrap; }
th.ordenable:hover { color: var(--texto); }
th .flecha { color: var(--acento); font-weight: 700; }
th[aria-sort] { color: var(--acento); }

/* ── Log ──────────────────────────────────────────────────────── */
.linea {
  display: flex; align-items: center; gap: 7px;
  margin: 0; font-weight: 400; font-size: .9rem; white-space: nowrap;
}
.linea input { width: auto; }

td.mensaje {
  white-space: normal; min-width: 340px;
  font-size: .87rem; line-height: 1.45;
}

/* El nivel se ve de un vistazo con una barra a la izquierda, no tiñendo la
   fila entera: con cientos de líneas, el fondo de color cansa y se deja de
   leer. Lo normal no lleva marca ninguna. */
tr.log-warn  td:first-child { box-shadow: inset 3px 0 0 var(--ojo); }
tr.log-error td:first-child,
tr.log-fatal td:first-child { box-shadow: inset 3px 0 0 var(--mal); }
tr.log-error td.mensaje,
tr.log-fatal td.mensaje { color: var(--mal); }
tr.log-debug td { opacity: .65; }

#tabla-log tbody tr { cursor: default; }
#tabla-log a { color: var(--acento); text-decoration: none; }
#tabla-log a:hover { text-decoration: underline; }

/* ── Línea de tiempo de la ficha ──────────────────────────────── */
.hito {
  border-left: 3px solid var(--borde);
  padding: 0 0 16px 14px; margin-left: 6px;
}
.hito:last-child { padding-bottom: 0; }
.hito.aplicada { border-left-color: var(--bien); }
.hito.fallida  { border-left-color: var(--mal); }
.cuando { font-variant-numeric: tabular-nums; color: var(--apagado); font-size: .82rem; }

.descartados { margin: 8px 0 0; padding: 0; list-style: none; }
.descartados li {
  display: flex; gap: 10px; padding: 5px 0;
  border-bottom: 1px dashed var(--borde-suave); font-size: .88rem;
}
.descartados li:last-child { border-bottom: 0; }
.descartados .quien { font-weight: 600; min-width: 4.5em; }

pre {
  background: var(--papel-2); border: 1px solid var(--borde-suave);
  border-radius: var(--radio-chico); padding: 12px; overflow-x: auto;
  font-size: .82rem; margin: 8px 0 0;
}
details summary { cursor: pointer; color: var(--acento); font-size: .9rem; padding: 4px 0; }

.vacio { color: var(--apagado); padding: 18px 0; }

/* ── Configuración ────────────────────────────────────────────── */
.regla {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
  gap: 10px 20px; align-items: start;
  padding: 14px 0; border-bottom: 1px solid var(--borde-suave);
}
.regla:last-child { border-bottom: 0; padding-bottom: 0; }
.regla:first-of-type { padding-top: 0; }

.regla .clave {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .88rem; font-weight: 600; word-break: break-word;
}
.regla .que-hace { color: var(--apagado); font-size: .87rem; margin-top: 3px; }
.regla .cuidado { margin-top: 7px; font-size: .84rem; color: var(--ojo); }

.valores { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.valor {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--papel-2); border: 1px solid var(--borde-suave);
  border-radius: var(--radio-chico); padding: 8px 10px;
}
.valor .dato {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-weight: 600; word-break: break-word; min-width: 0;
}
.valor .unidad { color: var(--apagado); font-size: .85rem; }
.valor form { display: flex; gap: 6px; width: 100%; flex-wrap: wrap; }
.valor form input, .valor form select { flex: 1; min-width: 130px; }
.valor .fallo { color: var(--mal); font-size: .84rem; width: 100%; }
.valor .hecho { color: var(--bien); font-size: .84rem; }

/* ── Guiones de las llamadas ──────────────────────────────────── */
/* La única estructura editable desde la web. Cada guion con su caja, su
   cuenta de caracteres y lo que va a costar la llamada. */
.valor.guiones { flex-direction: column; align-items: stretch; gap: 12px; }
.guion-clave {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .82rem; font-weight: 600; color: var(--apagado);
  margin-bottom: 4px;
}
.valor.guiones textarea {
  width: 100%; padding: 9px 11px;
  border: 1px solid var(--borde); border-radius: var(--radio-chico);
  background: var(--fondo); color: var(--texto);
  font: inherit; font-size: .9rem; line-height: 1.45; resize: vertical;
}
.valor.guiones textarea:focus { outline: 2px solid var(--acento); outline-offset: 1px; }
.guion-pie { margin-top: 4px; }
.guion-acciones { display: flex; flex-direction: column; gap: 6px; }

/* Cruzar el minuto es donde se dobla la factura: eso se dice en ámbar, no
   en gris con el resto de la cuenta. */
.aviso-precio { color: var(--ojo); font-size: .82rem; font-weight: 600; }

/* ── Avisos de llamada ────────────────────────────────────────── */
.valor.disparadores { flex-direction: column; align-items: stretch; gap: 8px; }
.avisos { margin: 0; padding-left: 18px; font-size: .9rem; line-height: 1.6; }
.avisos li { margin-bottom: 2px; }
.pie-disparadores { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* El título de cada guion es el AVISO al que pertenece, no su nombre
   técnico. Ese va debajo y en pequeño, para cuadrarlo con la base. */
.guion-uso { font-size: .87rem; font-weight: 600; margin-bottom: 2px; }
.guion-uso.huerfano { color: var(--ojo); }

/* De dónde sale el valor. ⚠️ SE ENSEÑA SIEMPRE, incluso cuando es «todos»:
   una regla cargada con el ámbito equivocado no la lee nadie y no da
   ningún error, y esconder el ámbito es esconder justo eso. */
.ambito {
  font-size: .76rem; padding: 2px 8px; border-radius: 999px;
  background: var(--fondo); border: 1px solid var(--borde);
  color: var(--apagado); white-space: nowrap;
}
.ambito.acotado { color: var(--ojo); border-color: color-mix(in srgb, var(--ojo) 45%, transparent); }
.ambito.defecto { font-style: italic; }

.solo-sql { font-size: .78rem; color: var(--apagado); white-space: nowrap; }

.nav-secciones { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.nav-secciones a {
  font-size: .84rem; text-decoration: none; color: var(--acento);
  padding: 4px 10px; border-radius: 999px; background: var(--acento-suave);
}

/* ── Incidencias ──────────────────────────────────────────────── */
/* El número de abiertas, en la propia pestaña. Es lo que hace que alguien
   entre a mirarlas sin que nadie se lo diga. */
.globo {
  display: inline-block; min-width: 18px; padding: 0 6px;
  border-radius: 999px; background: var(--mal); color: #fff;
  font-size: .72rem; font-weight: 700; line-height: 18px;
  text-align: center; vertical-align: 1px;
}

dialog {
  border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--papel); color: var(--texto);
  padding: 0; width: min(560px, calc(100vw - 32px));
  box-shadow: 0 10px 40px rgba(0, 0, 0, .25);
}
dialog::backdrop { background: rgba(8, 12, 18, .55); }
.dialogo-cuerpo { padding: 20px; margin: 0; }
.dialogo-cuerpo textarea {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--borde); border-radius: var(--radio-chico);
  background: var(--fondo); color: var(--texto);
  font: inherit; line-height: 1.5; resize: vertical;
}
.dialogo-cuerpo textarea:focus { outline: 2px solid var(--acento); outline-offset: 1px; }
.pie-dialogo { display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px; }

.hecho-caja {
  margin-top: 12px; padding: 10px 12px;
  background: color-mix(in srgb, var(--bien) 14%, transparent);
  border-radius: var(--radio-chico); color: var(--bien);
}

.incidencia {
  padding: 14px 0; border-bottom: 1px solid var(--borde-suave);
}
.incidencia:last-child { border-bottom: 0; padding-bottom: 0; }
.incidencia:first-of-type { padding-top: 0; }
.incidencia .cabeza {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 6px;
}
.incidencia .numero { font-weight: 700; font-variant-numeric: tabular-nums; }
/* El texto es de una persona: los saltos de línea que escribió se
   respetan, y las palabras larguísimas no rompen la caja. */
.incidencia .texto { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; }
.incidencia.cerrada { opacity: .62; }

/* Un aviso que no salió tiene que verse. Es el caso en el que alguien ha
   contado un problema creyendo que ya lo sabe alguien más. */
.correo-mal { color: var(--ojo); font-size: .82rem; }

@media (max-width: 720px) {
  .regla { grid-template-columns: 1fr; gap: 8px; }
  main { padding: 16px 12px 40px; }
  .tarjeta { padding: 15px; }
  .desplazable { margin: 0 -15px; padding: 0 15px; }
  .pestanas { top: 53px; }
}
