/*
 * Admin Panel — Stepfy
 *
 * Misma paleta que el panel de comercios y que la web, con una diferencia
 * deliberada: el fondo y la cabecera son oscuros. Desde acá se mueven números
 * que afectan a todo el mundo, y ver de un vistazo que no estás en el panel
 * del comercio evita el peor error posible, que es creer que estás en el otro.
 *
 * Es para una pantalla grande, de escritorio, sin apuro. Al revés que el panel
 * del comercio, que se mira de pie y de reojo.
 */

:root {
  --ink: #0F1B2D;
  --ink-soft: #16283F;
  --deep: #0B1421;
  --acc: #01A060;
  --acc-dk: #0B7A52;
  --acc-lo: #4FCB94;
  --wash: #EFF9F4;
  --white: #FFFFFF;
  --gris: #8A97A8;
  --gris-cl: #B8C3D0;
  --linea: #E4EAF1;
  --rojo: #D9344A;
  --rojo-lo: #FDECEE;
  --ambar: #B8860B;
  --ambar-lo: #FFF6E0;

  --f-d: 'Bricolage Grotesque', system-ui, -apple-system, sans-serif;
  --f-b: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  --f-m: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;

  /* Mismos valores que el panel, a propósito: antes --r era 14px acá y 16px
     allá, y el fondo #F4F7FA contra #F6F9FC. Nadie lo nota por separado y
     juntos hacen que se vean como dos productos distintos. */
  --r: 16px;
  --sombra: 0 2px 10px rgba(15, 27, 45, .06);
  --sombra-alta: 0 18px 50px rgba(15, 27, 45, .18);
}

* { box-sizing: border-box; }

/*
 * El atributo hidden tiene que ganar siempre.
 *
 * El navegador lo aplica con `display: none` en su hoja propia, que pierde
 * contra cualquier regla nuestra. Sin esta línea, un `#entrar { display: grid }`
 * deja la pantalla de entrada tendida encima del panel después de entrar:
 * invisible para el navegador, tapando todo para la persona.
 *
 * Es un error que ya pasó dos veces en este proyecto. Por eso está arriba de
 * todo y con !important.
 */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  font-family: var(--f-b);
  color: var(--ink);
  background: #F6F9FC;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { font-family: var(--f-d); font-weight: 800; letter-spacing: -.02em; margin: 0; }
h2 { font-size: 23px; }
h3 { font-size: 15px; margin: 26px 0 10px; }

button, input, select, textarea { font: inherit; color: inherit; }
code { font-family: var(--f-m); font-size: .92em; }

/* --------------------------------------------------------------- entrar */

/*
 * Igual que el panel de comercios, con la misma caja y el mismo degradado.
 * Son dos puertas del mismo producto y antes se veían como dos productos.
 */
.entrar {
  min-height: 100vh;
  display: grid; place-items: center;
  padding: 24px;
  background: linear-gradient(170deg, var(--ink), var(--deep));
}
.entrar-caja {
  width: 100%; max-width: 420px;
  background: var(--white);
  border-radius: 22px;
  padding: 32px 28px;
  box-shadow: var(--sombra-alta);
}
.entrar-marca { text-align: center; margin-bottom: 4px; }
.entrar-marca img { height: 52px; width: auto; }
.entrar-caja h1 { font-size: 22px; text-align: center; margin: 14px 0 4px; }
.entrar-caja .ayuda { text-align: center; color: var(--gris); font-size: 13.5px; margin: 0 0 20px; }

/* --------------------------------------------------------------- estructura */

/*
 * La barra de arriba, azul marino.
 *
 * El fondo oscuro no es decoración: desde acá se mueven números que afectan a
 * todo el mundo, y ver de un vistazo que no estás en el panel de un comercio
 * evita el peor error posible, que es creer que estás en el otro.
 */
#barra {
  position: sticky; top: 0; z-index: 30;
  background: var(--ink);
  color: var(--white);
  box-shadow: var(--sombra);
}
.barra-interna {
  padding: 11px 20px;
  display: flex; align-items: center; gap: 12px;
}
.barra-interna .crece { flex: 1; }
.marca img { height: 24px; width: auto; display: block; }

#quien {
  font-family: var(--f-m); font-size: 12px; color: #B9C6D6;
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#btn-salir {
  background: rgba(255, 255, 255, .1);
  border: 0; color: var(--white);
  border-radius: 10px; padding: 7px 12px;
  font-size: 13px; cursor: pointer;
}
#btn-salir:hover { background: rgba(255, 255, 255, .18); }

/*
 * El timbre de alertas.
 *
 * Apagado es un icono gris más de la barra. Encendido se pone rojo y el globo
 * queda pegado arriba a la derecha. La diferencia tiene que verse sin leer:
 * quien mira esta barra no la está leyendo, está trabajando en otra pantalla.
 */
.timbre {
  position: relative;
  background: rgba(255, 255, 255, .1);
  border: 0; color: #B9C6D6;
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; cursor: pointer;
}
.timbre svg { width: 18px; height: 18px; }
.timbre:hover { background: rgba(255, 255, 255, .18); color: var(--white); }
.timbre.encendido { color: #FFD9DE; background: rgba(217, 52, 74, .28); }
.timbre .globo {
  position: absolute; top: -5px; right: -5px;
  box-shadow: 0 0 0 2px var(--ink);
}

/*
 * La columna de la izquierda.
 *
 * Era una barra horizontal de pestañas que ya venía envolviendo en dos filas
 * con ocho secciones. En vertical no hay un número a partir del cual se
 * rompa, y acá van a seguir apareciendo pantallas.
 */
.nav {
  position: fixed; inset: 0 auto 0 0; z-index: 25;
  width: 252px; height: 100vh;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--white);
  border-right: 1px solid var(--linea);
  padding: 0 12px 14px;
  overflow-y: auto;
}
.nav-marca { padding: 18px 10px 16px; }
.nav-marca img { height: 24px; width: auto; display: block; }

.nav button {
  background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; gap: 11px;
  padding: 10px 13px; border-radius: 11px;
  font-size: 14.5px; font-weight: 600; color: var(--gris);
  text-align: left; position: relative;
  transition: background .14s ease, color .14s ease;
}
/* Los iconos son SVG y toman el color del botón: cambian solos cuando la
   sección está activa, sin una segunda versión de cada uno. */
.nav button svg.ico { width: 20px; height: 20px; flex: none; }
.nav button:hover { background: #F4F7FA; color: var(--ink); }
.nav button.activo { background: var(--wash); color: var(--acc-dk); }
/* La barrita verde: con siete secciones el fondo claro solo no alcanza para
   ver cuál está elegida de un vistazo. */
.nav button.activo::before {
  content: ''; position: absolute; left: 0; top: 9px; bottom: 9px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--acc);
}
.nav button .globo { margin-left: auto; }

/*
 * El hueco de la columna se hace con padding en el body y no con márgenes.
 *
 * Y va atado a `.dentro`, que se pone y se saca junto con el `hidden` de la
 * columna, desde el mismo booleano. Sin esa condición el hueco queda
 * reservado también en la pantalla de entrada: una franja blanca de 252 px a
 * la izquierda con el degradado arrancando corrido.
 */
body.dentro { padding-left: 252px; }
#app { padding: 0 0 90px; }
/*
 * Más ancho que el panel del comercio, a propósito.
 *
 * Eran 1040 px copiados del panel, que es una pantalla de formularios y se
 * mira en un teléfono. Acá hay tablas de ocho columnas: con 1040 la de países
 * no entraba y aparecía una barra de desplazamiento horizontal adentro de la
 * tabla, con la columna de acciones cortada por la mitad. Una tabla que hay
 * que deslizar para ver el botón de «Editar» es una tabla que no se puede
 * usar.
 */
.envoltura { max-width: 1400px; margin: 0 auto; padding: 0 22px; }

/*
 * Ventana angosta: la columna pasa a ser una fila que se desliza.
 *
 * El admin es de escritorio y no hace falta la barra inferior del panel, pero
 * una notebook de 13" con el navegador a media pantalla existe, y ahí 252 px
 * fijos se comen la tabla de Parametría.
 */
@media (max-width: 900px) {
  body.dentro { padding-left: 0; }
  .nav {
    position: static; width: auto; height: auto;
    flex-direction: row; gap: 4px;
    border-right: 0; border-bottom: 1px solid var(--linea);
    padding: 8px 12px; overflow-x: auto;
  }
  .nav-marca { display: none; }
  .nav button { white-space: nowrap; padding: 9px 12px; font-size: 13.5px; }
  .nav button.activo::before { display: none; }
  .envoltura { padding: 0 16px; }
}

.globo {
  background: var(--rojo); color: #fff;
  font-size: 11px; font-weight: 700;
  min-width: 18px; height: 18px; line-height: 18px;
  border-radius: 9px; padding: 0 5px;
  text-align: center;
}

main { margin-top: 20px; }
.pista { color: var(--gris); font-size: 13.5px; margin: 6px 0 18px; max-width: 70ch; line-height: 1.5; }
.pie { color: var(--gris); font-size: 12px; margin: 10px 0 0; }

/* --------------------------------------------------------------- tarjetas */

.tarjeta {
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 16px;
  box-shadow: var(--sombra);
  margin-bottom: 12px;
}

.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.dato {
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 14px;
  box-shadow: var(--sombra);
}
.dato b {
  display: block;
  font-family: var(--f-d); font-size: 25px; font-weight: 800;
  letter-spacing: -.02em;
}
.dato span { display: block; color: var(--gris); font-size: 12px; margin-top: 2px; }
.dato .extra { color: var(--acc-dk); font-weight: 600; }

/* --------------------------------------------------------------- gráfico */

.grafico {
  display: flex; align-items: flex-end; gap: 2px;
  height: 120px;
}
.grafico i {
  flex: 1; min-width: 2px;
  background: linear-gradient(180deg, var(--acc-lo), var(--acc));
  border-radius: 3px 3px 0 0;
  min-height: 2px;
}
.grafico i.sin-pasos { background: var(--linea); }

/* --------------------------------------------------------------- filas */

.fila {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 0;
  border-bottom: 1px solid var(--linea);
}
.fila:last-child { border-bottom: 0; }
.fila .cuerpo { flex: 1; min-width: 0; }
.fila b { font-size: 14.5px; display: block; }
.fila .sub { color: var(--gris); font-size: 12.5px; margin-top: 2px; }
.fila .acciones { display: flex; gap: 6px; flex-shrink: 0; }

.etiqueta {
  display: inline-block;
  font-size: 11px; font-weight: 700;
  padding: 3px 8px; border-radius: 99px;
  white-space: nowrap;
}
.etiqueta.ok    { background: var(--wash);     color: var(--acc-dk); }
.etiqueta.mal   { background: var(--rojo-lo);  color: var(--rojo); }
.etiqueta.tibia { background: var(--ambar-lo); color: var(--ambar); }
.etiqueta.gris  { background: #F0F3F7;         color: var(--gris); }

.chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.chips .chico.on { background: var(--wash); color: var(--acc-dk); border-color: #BFE7D4; }
.chips .chico b { color: var(--gris); font-weight: 700; margin-left: 2px; }
.chips .chico.on b { color: var(--acc-dk); }

/* Lo que mandó el formulario de la web, que es lo que se mira para decidir. */
.datos-extra {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 8px;
}
.datos-extra span {
  background: #F0F3F7; border-radius: 7px;
  padding: 3px 8px; font-size: 11.5px; color: var(--gris);
}
.datos-extra b { color: var(--ink); font-weight: 600; }

/* --------------------------------------------------------------- formularios */

.campo { margin-bottom: 13px; }
.campo label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 5px; }
.campo input, .campo select, .buscador input {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--linea);
  border-radius: 11px;
  background: var(--white);
}
.campo input:focus, .campo select:focus, .buscador input:focus {
  outline: 2px solid var(--acc-lo); outline-offset: 1px; border-color: transparent;
}

.buscador { display: flex; gap: 8px; margin-bottom: 14px; }
.buscador input { flex: 1; }

.boton {
  width: 100%;
  padding: 12px;
  border: 0; border-radius: 12px;
  background: var(--acc); color: #fff;
  font-weight: 700; font-size: 15px;
  cursor: pointer;
}
.boton:hover { background: var(--acc-dk); }
.boton[disabled] { opacity: .55; cursor: default; }

.chico {
  padding: 8px 13px;
  border: 1px solid var(--linea); border-radius: 10px;
  background: var(--white);
  font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.chico:hover { background: #F4F7FA; }
.chico.verde { background: var(--acc); color: #fff; border-color: var(--acc); }
.chico.verde:hover { background: var(--acc-dk); }
.chico.rojo { color: var(--rojo); border-color: #F3C9CF; }
.chico[disabled] { opacity: .5; cursor: default; }

.error { color: var(--rojo); font-size: 13px; margin: 10px 0 0; }

/* --------------------------------------------------------------- parámetros */

/*
 * Los grupos, plegables.
 *
 * Con treinta perillas en una sola tira, la que se busca está siempre abajo
 * de todo. Plegados, la pantalla cabe entera y se abre el grupo que importa.
 */
.grupo {
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  box-shadow: var(--sombra);
  margin-bottom: 10px;
  overflow: hidden;
}
.grupo-cab {
  width: 100%; border: 0; background: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; text-align: left;
  font-family: var(--f-d); font-weight: 800; font-size: 15px; color: var(--ink);
}
.grupo-cab:hover { background: #F8FAFC; }
.grupo-cab .chev {
  width: 16px; height: 16px; flex: none; color: var(--gris);
  transition: transform .16s ease;
}
.grupo.abierto .grupo-cab .chev { transform: rotate(90deg); }
.grupo-nombre { flex: 1; }
.grupo-cuantas {
  font-family: var(--f-m); font-size: 11.5px; font-weight: 500;
  color: var(--gris); background: #F2F5F9;
  border-radius: 999px; padding: 2px 9px;
}
/* Plegado con `display:none` y no con altura cero: una altura animada sobre
   contenido de alto variable pide saber cuánto mide, y lo que se gana es una
   transición que acá nadie va a mirar. */
.grupo-cuerpo { display: none; padding: 0 16px 6px; }
.grupo.abierto .grupo-cuerpo { display: block; }

.perilla {
  display: grid;
  grid-template-columns: 1fr 230px;
  gap: 14px;
  align-items: start;
  padding: 15px 0;
  border-bottom: 1px solid var(--linea);
}
.perilla:last-child { border-bottom: 0; }
.perilla .rotulo {
  font-weight: 700; font-size: 14.5px;
  display: flex; align-items: center; gap: 7px;
}
.perilla .ayuda {
  color: var(--gris); font-size: 12.5px; line-height: 1.55;
  margin-top: 4px; max-width: 62ch;
}
/* La clave de la tabla, en chico. Es lo que hay que buscar cuando alguien
   pregunta por un valor desde un log del servidor o desde la base. */
.perilla .clave {
  display: inline-block; margin-top: 6px;
  font-size: 11px; color: var(--gris-cl);
}
.perilla .control-fila { display: flex; gap: 6px; align-items: center; }
.perilla .control input, .perilla .control select {
  flex: 1; min-width: 0;
  padding: 9px 11px;
  border: 1px solid var(--linea); border-radius: 10px;
  font-family: var(--f-m); font-size: 13.5px;
}
.perilla .unidad { color: var(--gris); font-size: 12px; white-space: nowrap; }
/* El rango, escrito. El `max` del navegador es una pared invisible: se tipea
   un número de más, no pasa nada que se vea, y queda la duda de si se guardó. */
.perilla .rango {
  display: block; margin-top: 5px;
  font-family: var(--f-m); font-size: 11px; color: var(--gris-cl);
}
.perilla.sucia .control input, .perilla.sucia .control select { border-color: var(--ambar); background: var(--ambar-lo); }

/* El relojito que abre el historial de esa perilla. */
.reloj {
  border: 0; background: none; cursor: pointer; padding: 2px;
  color: var(--gris-cl); line-height: 0; border-radius: 6px;
}
.reloj svg { width: 15px; height: 15px; }
.reloj:hover { color: var(--acc); background: var(--wash); }

/*
 * El antes y el después, en la confirmación.
 *
 * Los dos valores uno al lado del otro y del mismo tamaño. Es lo único que
 * delata un dedo de más: el campo donde se acaba de tipear ya muestra el
 * valor nuevo, así que leer la pantalla no dice de dónde se viene.
 */
.cambio {
  display: flex; align-items: stretch; gap: 10px;
  margin: 4px 0 14px;
}
.cambio-lado {
  flex: 1; min-width: 0;
  background: #F6F9FC; border: 1px solid var(--linea);
  border-radius: 12px; padding: 10px 12px;
}
.cambio-lado span { display: block; font-size: 11px; color: var(--gris); margin-bottom: 3px; }
.cambio-lado b {
  font-family: var(--f-m); font-size: 16px; word-break: break-all;
}
.cambio-lado.nuevo { background: var(--wash); border-color: #BFE7D4; }
.cambio-lado.nuevo b { color: var(--acc-dk); }
.cambio-flecha { align-self: center; color: var(--gris); font-size: 17px; }

.dlg-ayuda {
  color: var(--gris); font-size: 12.5px; line-height: 1.55; margin: 0 0 10px;
}
.dlg-ayuda b { color: var(--ink); }

/* El historial adentro del diálogo: alto acotado y con su propio desliz. Sin
   esto, treinta cambios empujan los botones abajo de la ventana. */
.tabla-caja.historial { max-height: 320px; overflow-y: auto; margin-bottom: 12px; }
.tabla.mini .dif { font-family: var(--f-m); font-size: 12px; }
.tabla.mini .dif s { color: var(--gris); }
.tabla.mini .dif i { color: var(--gris-cl); font-style: normal; margin: 0 3px; }
.tabla.mini .dif b { color: var(--acc-dk); }
.nowrap { white-space: nowrap; }

/* --------------------------------------------------------------- credenciales */

/*
 * La caja donde aparece la contraseña recién generada.
 *
 * Oscura y grande a propósito: es la única vez que ese dato se puede ver.
 * Después se guarda hasheado y no hay forma de recuperarlo, así que la caja
 * no se cierra sola ni con un clic al costado — se cierra con su botón,
 * cuando quien la leyó decidió que ya está.
 */
.credenciales {
  background: var(--deep);
  border-radius: var(--r);
  padding: 18px 20px;
  margin-bottom: 14px;
  color: #fff;
}
.credenciales .rot {
  font-size: 11px; letter-spacing: 1.6px; font-weight: 700;
  color: var(--acc-lo); margin-bottom: 8px;
}
.credenciales .dato-clave {
  font-family: var(--f-m); font-size: 21px; letter-spacing: 1px;
  word-break: break-all;
}
.credenciales .dato-usuario { font-family: var(--f-m); font-size: 14px; word-break: break-all; }
.credenciales .pie { color: var(--gris-cl); margin-top: 14px; }
.credenciales .chico { margin-top: 12px; }

/* --------------------------------------------------------------- alarma */

/*
 * Va adentro de la envoltura y no a lo ancho de la ventana: pegado al borde
 * izquierdo, arrancando donde termina la columna, se leía como parte del
 * menú y no de la pantalla.
 */
.alarma {
  max-width: 1400px; margin: 16px auto 0;
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--rojo-lo);
  border: 1px solid #F3C9CF;
  border-left: 4px solid var(--rojo);
  border-radius: 11px;
  padding: 13px 15px;
  font-size: 13.5px; line-height: 1.55;
  color: #7E1E2C;
}
.alarma > div { flex: 1; }
.alarma b { display: block; margin-bottom: 2px; }
.alarma-cerrar {
  flex: none; border: 0; background: none; cursor: pointer;
  color: #7E1E2C; opacity: .6;
  font-size: 22px; line-height: 1; padding: 0 2px;
  border-radius: 6px;
}
.alarma-cerrar:hover { opacity: 1; background: rgba(217, 52, 74, .12); }

/* ------------------------------------------------- filtros y paginado */

/*
 * La barra de filtros, igual en las cuatro listas.
 *
 * Se dibuja una vez y no se vuelve a tocar: lo que se repinta en cada
 * búsqueda es la lista y el pie. Un campo de texto reemplazado mientras
 * alguien escribe pierde el foco, y en este panel eso ya se arregló dos
 * veces devolviéndolo a mano, que es tapar el agujero en vez de cerrarlo.
 */
.filtros {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px;
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  box-shadow: var(--sombra);
  padding: 12px 14px;
  margin-bottom: 14px;
}
.filtros:empty { display: none; }

/* El campo de texto se lleva el lugar que sobra: es el que más se usa. */
.f-texto {
  flex: 1 1 220px; min-width: 180px;
  padding: 9px 12px;
  border: 1px solid var(--linea); border-radius: 10px;
  font-size: 13.5px;
}
.f-campo { display: flex; flex-direction: column; gap: 4px; }
.f-campo > span { font-size: 11px; font-weight: 600; color: var(--gris); }
.f-campo select, .f-campo input {
  padding: 8px 10px;
  border: 1px solid var(--linea); border-radius: 10px;
  font-size: 13px; background: var(--white);
}

/*
 * Una marca es un sí/no con forma de chip.
 *
 * Va para los filtros que o están o no están —«sin premios», «dormidos»—.
 * Un desplegable de dos opciones ocupa el triple, pide dos clics y se lee
 * peor que una palabra que se enciende.
 */
.f-marca {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 12px;
  border: 1px solid var(--linea); border-radius: 999px;
  font-size: 13px; font-weight: 600; color: var(--gris);
  cursor: pointer; user-select: none;
}
.f-marca input { accent-color: var(--acc); margin: 0; }
.f-marca:hover { background: #F4F7FA; }
.f-marca:has(input:checked) {
  background: var(--wash); border-color: #BFE7D4; color: var(--acc-dk);
}
/* El botón de limpiar se va a la derecha y aparece sólo si hay algo puesto:
   siempre visible es un botón más que no hace nada casi nunca. */
.f-limpiar { margin-left: auto; }

/*
 * El pie con el conteo.
 *
 * Va el total y no sólo el número de página. «Página 2 de 173» no dice
 * nada; «mostrando 26 a 50 de 4.312» dice cuánto hay y cuánto falta, que es
 * lo que hace falta para decidir si conviene afinar el filtro o seguir
 * pasando páginas.
 */
.paginador {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 2px 0;
  font-size: 12.5px; color: var(--gris);
}
.pag-cuantos b { color: var(--ink); font-variant-numeric: tabular-nums; }
.pag-botones { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.pag-botones .chico { min-width: 34px; font-size: 15px; line-height: 1; }
.pag-botones .chico:disabled { opacity: .4; cursor: default; }
.pag-cual { font-family: var(--f-m); font-size: 12px; min-width: 56px; text-align: center; }
.pag-tamano { display: flex; align-items: center; gap: 6px; }
.pag-tamano select {
  padding: 5px 8px; border: 1px solid var(--linea); border-radius: 8px;
  font-size: 12.5px; background: var(--white);
}

/* --------------------------------------------------------------- bitácora */

/*
 * Cada línea se abre.
 *
 * Arriba va el resumen —cuándo, qué, sobre qué, y el cambio— que es lo que
 * se escanea pasando la vista. Abajo está todo: los valores enteros, la
 * nota, la IP y la fecha con hora y año. Antes eso no estaba en ningún
 * lado: lo que no entraba en la línea no se podía ver.
 */
.log { border-bottom: 1px solid var(--linea); }
.log:last-child { border-bottom: 0; }

.log-cab {
  width: 100%; border: 0; background: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 4px; text-align: left; font-size: 13px; color: var(--ink-soft);
}
.log-cab:hover { background: #FAFCFE; }
.log-cuando {
  color: var(--gris); font-family: var(--f-m); font-size: 11.5px;
  min-width: 96px; flex: none;
}
.log-que { font-weight: 600; }
.log-cab .dif { font-family: var(--f-m); font-size: 12px; }
.log-cab .chev {
  width: 15px; height: 15px; flex: none; margin-left: auto; color: var(--gris-cl);
  transition: transform .14s ease;
}
.log.abierto .chev { transform: rotate(90deg); }

/* Plegado con display:none y no con altura cero: animar una altura que no se
   conoce de antemano pide medirla, y lo que se gana es una transición que
   acá nadie va a mirar. */
.log-detalle { display: none; padding: 2px 4px 14px 106px; }
.log.abierto .log-detalle { display: block; }
.log-detalle dl {
  display: grid; grid-template-columns: 90px minmax(0, 1fr);
  gap: 6px 14px; margin: 0; font-size: 12.5px;
}
.log-detalle dt { color: var(--gris); font-weight: 600; }
.log-detalle dd { margin: 0; color: var(--ink-soft); word-break: break-word; }
.log-detalle dd.val { font-family: var(--f-m); font-size: 12px; }
.log-detalle code { font-size: 11.5px; color: var(--gris); }

@media (max-width: 760px) {
  .log-detalle { padding-left: 4px; }
  .log-detalle dl { grid-template-columns: 1fr; gap: 2px; }
  .log-detalle dt { margin-top: 8px; }
}

/* --------------------------------------------------------------- diálogo */

#dialogo { position: fixed; inset: 0; z-index: 80; display: flex;
           align-items: center; justify-content: center; padding: 20px; }
.dialogo-fondo { position: absolute; inset: 0; background: rgba(11, 20, 33, .55); }
.dialogo-caja {
  position: relative;
  width: 100%; max-width: 440px;
  /* El ancho lo decide el contenido: un formulario de siete campos en una
     caja de 440 px es una tira vertical que no entra en la pantalla. Con
     `.ancho` pasa a dos columnas y entra entero. */
  background: var(--white);
  border-radius: 18px;
  padding: 24px;
  box-shadow: 0 28px 70px rgba(15, 27, 45, .35);
  animation: dlg-entra .16s ease-out;
  /* El formulario del ABM tiene seis campos y no entra en una pantalla de
     portátil con el navegador a media altura.
     Lo que se desplaza es el formulario, NO la caja entera: con la caja
     entera desplazándose, «Guardar» queda abajo del borde y hay que bajar a
     buscarlo cada vez. Así los botones se quedan siempre a la vista y lo
     único que se mueve son los campos. */
  max-height: calc(100vh - 40px);
  display: flex; flex-direction: column;
}
.dialogo-caja > h3, .dialogo-caja > p, .dialogo-botones { flex: none; }
@keyframes dlg-entra {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
/* Quien prefiere menos movimiento no tiene por qué ver la animación. */
@media (prefers-reduced-motion: reduce) { .dialogo-caja { animation: none; } }

.dialogo-caja h3 { font-size: 19px; margin-bottom: 8px; }
.dialogo-caja p { color: var(--gris); font-size: 14px; line-height: 1.6; margin: 0; }
.dialogo-caja p b { color: var(--ink); }
#dlg-campo { margin-top: 16px; }
#dlg-campo label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 5px; }
#dlg-campo textarea {
  width: 100%; padding: 11px 12px;
  border: 1px solid var(--linea); border-radius: 11px;
  resize: vertical; font-family: inherit;
}
#dlg-campo textarea:focus { outline: 2px solid var(--acc-lo); outline-offset: 1px; border-color: transparent; }

.dialogo-botones { display: flex; gap: 8px; justify-content: flex-end; margin-top: 20px; }
.dialogo-botones .boton { width: auto; padding: 11px 20px; }
.dialogo-botones .boton.rojo { background: var(--rojo); }
.dialogo-botones .boton.rojo:hover { background: #B8293C; }

/* --------------------------------------------------------------- aviso */

#aviso {
  position: fixed; left: 50%; bottom: 22px;
  transform: translate(-50%, 70px);
  background: var(--ink); color: #fff;
  padding: 12px 20px; border-radius: 12px;
  font-size: 14px; font-weight: 600;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .3);
  opacity: 0; pointer-events: none;
  transition: transform .22s, opacity .22s;
  z-index: 60;
  max-width: calc(100vw - 32px);
}
#aviso.on { transform: translate(-50%, 0); opacity: 1; }
#aviso.mal { background: var(--rojo); }

.vacio { color: var(--gris); font-size: 13.5px; padding: 22px 0; text-align: center; }
/*
 * .vacio marcaba TRES cosas distintas, y eso rompió una prueba.
 *
 * Era el cartel de «no hay nada», el de «Cargando…», y también cada barra en
 * cero del gráfico por hora. La prueba de la bandeja de revisiones esperaba a
 * que apareciera un .vacio para leer el cartel de bandeja vacía, y lo
 * encontraba al instante: las barras en cero del gráfico que todavía estaba
 * en pantalla ya eran .vacio. Leía el texto equivocado y fallaba, pero el
 * código estaba bien.
 *
 * Ahora cada una tiene su nombre: .vacio es el cartel, .esperando el que está
 * a la espera de una respuesta, y .sin-pasos la barra en cero.
 */

/* --------------------------------------------------------------- angosto */

@media (max-width: 700px) {
  .perilla { grid-template-columns: 1fr; }
  .linea-log { grid-template-columns: 1fr; gap: 3px; }
  .fila { flex-wrap: wrap; }
  nav { position: static; }
}

/* --------------------------------------------------------- revisiones */

/*
 * Cada revisión es una tarjeta con el día entero dibujado. El gráfico ocupa
 * más lugar que el texto a propósito: lo que decide si un día fue caminado o
 * no es la forma, no los números. Un rectángulo perfecto de ocho horas no
 * necesita que nadie lea nada.
 */
.revision { margin-bottom: 14px; }
.revision .senales { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 14px; }

/* Más alto que el gráfico del tablero: acá la forma es el dato. */
.grafico.dia { height: 86px; gap: 1px; }

/* Las horas vacías se dibujan igual, en gris. Los huecos son la prueba. */
.grafico.dia i.sin-pasos { background: var(--linea); opacity: .55; }

.pie.horas {
  display: flex; justify-content: space-between;
  margin-top: 4px; font-variant-numeric: tabular-nums;
}
.pie.tecnico { margin-top: 10px; }
.pie.tecnico a { color: var(--acc-dk); }

.revision .historial { margin-top: 10px; }
.revision table.mini { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.revision table.mini td {
  padding: 5px 8px 5px 0;
  border-bottom: 1px solid var(--linea);
  color: var(--gris);
}
.revision table.mini tr:last-child td { border-bottom: 0; }

/* De qué apps salieron los pasos. Con Health Connect, el dato que más
   rápido decide una revisión: a ese almacén le escribe cualquier app. */
.pie.origenes { margin-top: 10px; }
.pie.origenes code {
  background: var(--wash); color: var(--acc-dk);
  padding: 2px 6px; border-radius: 5px;
  font-size: 11.5px; margin-right: 4px;
}

/* ------------------------------------------------- sello de Play */
/*
 * El veredicto de un envío y el recuento de la semana. Los colores no son
 * decoración: quien revisa mira veinte filas en cinco minutos y el color es
 * lo único que se lee de reojo.
 */
.sello { margin-top: 6px; }
.sello.ok    { color: var(--acc); }   /* era var(--verde), que no existe en ningún lado */
.sello.mal   { color: var(--rojo); }
.sello.tibio { color: var(--ambar, #B07D1A); }
.sello.gris  { color: var(--gris); }

.medidor-sello {
  border: 1px solid var(--linea); border-left-width: 4px;
  border-radius: 10px; padding: 12px 14px; margin-bottom: 14px;
}
.medidor-sello.ok    { border-left-color: var(--acc); }
.medidor-sello.tibio { border-left-color: var(--ambar, #B07D1A); }
.medidor-sello b { font-size: 13.5px; }
.medidor-sello .pie { margin-top: 4px; }

/* ------------------------------------------------------ ABM de parametría
 *
 * Una tabla por entidad, con solapas arriba. La versión anterior eran
 * tarjetas con las ciudades adentro: se veía la relación, pero no servía
 * para trabajar —con cincuenta ciudades hay que bajar media pantalla para
 * llegar a una, y los órdenes no se pueden comparar entre sí—.
 */
/*
 * Índice a la izquierda, tabla a la derecha.
 *
 * Eran solapas horizontales: andaban con cuatro, ya envolvían con seis, y el
 * día que haya veinte listas de formulario una fila de botones es una pared
 * donde no se encuentra nada. En columna no hay un número a partir del cual
 * se rompa — crece hacia abajo y se desliza.
 */
.abm {
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  gap: 20px;
  margin-top: 16px;
  align-items: start;
}
.abm-indice {
  /* Baja lo mismo que mide la fila del botón de la derecha. Sin esto las dos
     columnas arrancan parejas en el grid pero se ven desfasadas, porque de un
     lado lo primero es una tarjeta y del otro un botón suelto. */
  margin-top: 50px;
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  box-shadow: var(--sombra);
  padding: 8px;
  /* Pegado arriba: con una tabla de trescientas ciudades, el índice tiene que
     seguir ahí cuando se bajó a mitad de la lista. */
  position: sticky; top: 64px;
  max-height: calc(100vh - 84px);
  overflow-y: auto;
}
.indice-familia {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--gris-cl);
  padding: 12px 10px 5px;
}
.indice-familia:first-child { padding-top: 4px; }
.abm-indice button {
  width: 100%; border: 0; background: transparent; cursor: pointer;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 9px;
  font-size: 13.5px; font-weight: 600; color: var(--gris);
  text-align: left;
}
.abm-indice button span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.abm-indice button:hover { color: var(--ink); background: #F4F7FA; }
.abm-indice button.on { color: var(--acc-dk); background: var(--wash); }
.abm-indice button b {
  background: var(--linea); color: var(--gris);
  border-radius: 999px; padding: 1px 7px;
  font-size: 11.5px; font-weight: 700; flex: none;
}
.abm-indice button.on b { background: #D5F1E3; color: var(--acc-dk); }

/* El buscador del índice aparece recién cuando hay suficientes listas como
   para necesitarlo. Un campo de búsqueda sobre cinco ítems es ruido. */
.indice-buscar {
  width: 100%; margin-bottom: 4px;
  padding: 8px 10px;
  border: 1px solid var(--linea); border-radius: 9px;
  font-size: 13px;
}

/* Angosto: el índice vuelve arriba, en una fila que se desliza. */
@media (max-width: 860px) {
  /* `minmax(0, 1fr)` y no `1fr`: una columna de grid mide por omisión al
     menos lo que su contenido, así que una tabla de siete columnas ensancha
     la columna, la columna ensancha la página, y a 360 px queda todo corrido
     con un desplazamiento horizontal que no debería existir. El `minmax(0,…)`
     le da permiso de ser más angosta que su contenido, que es lo que hace que
     la tabla se deslice adentro de su caja en vez de estirar la página. */
  .abm { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .abm-indice {
    margin-top: 0;
    position: static; max-height: none;
    display: flex; gap: 4px; overflow-x: auto; padding: 8px;
  }
  .indice-familia { display: none; }
  .abm-indice button { width: auto; white-space: nowrap; }
  .indice-buscar { display: none; }
}

/*
 * La fila del botón «Agregar».
 *
 * Sin margen arriba. Lo tenía, de 14 px, y eso dejaba el índice de la
 * izquierda arrancando una fila más arriba que la tabla: las dos columnas
 * empiezan en la misma línea del grid, pero una tenía margen y la otra no,
 * así que todo el panel se veía corrido contra la tabla.
 *
 * El alto queda fijo para que la tabla arranque siempre a la misma altura,
 * tenga o no botón —las listas vacías dibujan una cabecera distinta— y el
 * índice no se mueva al cambiar de solapa.
 */
.abm-cabecera {
  display: flex; align-items: center; justify-content: flex-end;
  min-height: 38px; margin: 0 0 12px;
}

.abm-filtros { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.abm-filtros select, .abm-filtros input {
  padding: 9px 11px;
  border: 1px solid var(--linea); border-radius: 10px;
  background: var(--white);
  font-size: 13.5px;
}
.abm-filtros input { flex: 1; min-width: 160px; }
.abm-filtros select:focus, .abm-filtros input:focus {
  outline: 2px solid var(--acc-lo); outline-offset: 1px; border-color: transparent;
}

/* La tabla se desplaza sola adentro de su caja. Sin esto, en un teléfono la
   tabla estira la página entera y todo lo demás queda corrido. */
.tabla-caja {
  background: var(--white);
  border: 1px solid var(--linea);
  border-radius: 12px;
  overflow-x: auto;
}
.tabla { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.tabla th {
  text-align: left;
  padding: 11px 14px;
  font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--gris);
  border-bottom: 1px solid var(--linea);
  white-space: nowrap;
}
.tabla td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--linea);
  color: var(--ink-soft);
  vertical-align: middle;
}
.tabla tbody tr:last-child td { border-bottom: 0; }
.tabla tbody tr:hover td { background: #FAFCFE; }

/*
 * Pantalla de portátil: la tabla se aprieta en vez de deslizarse.
 *
 * `overflow-x: auto` está arriba como red de seguridad y tiene que seguir
 * estando —una lista con un nombre larguísimo lo va a necesitar— pero una
 * tabla que hay que deslizar para llegar al botón de «Editar» es una tabla
 * que no se puede usar, y a 1280 px la de países se pasaba por 73 px.
 *
 * Se gana de los dos lados: el índice de la izquierda se angosta y las
 * celdas pierden unos píxeles de aire. Ninguna de las dos cosas se nota; la
 * barra de desplazamiento sí.
 */
@media (max-width: 1400px) {
  .abm { grid-template-columns: 184px minmax(0, 1fr); gap: 14px; }
  .tabla { font-size: 13px; }
  .tabla th, .tabla td { padding: 10px 9px; }
  .tabla .acciones { gap: 4px; }
}
.tabla .principal { font-weight: 600; color: var(--ink); }
/* Los números a la derecha: así se comparan de un vistazo en vertical, que
   es para lo que sirve tener una columna de orden. */
.tabla .num { text-align: right; font-variant-numeric: tabular-nums; }
.tabla code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--gris);
  background: #F4F7FA; border-radius: 6px; padding: 2px 6px;
}
.tabla .acciones-col { white-space: nowrap; text-align: right; }
.tabla .acciones-col .chico + .chico { margin-left: 6px; }
.tabla .alerta { color: var(--ambar); margin-left: 4px; cursor: help; }
/* Un dato que falta pero no es un error: se lee, y no grita. Lo usa la columna
   de moneda para los países a los que todavía nadie se la cargó. */
.tabla .flojo { color: var(--gris-cl); font-style: italic; cursor: help; }

/* El símbolo de la moneda, un poco más grande. No es adorno: son uno o dos
   caracteres en una columna de texto, y a tamaño normal «₡» y «¢» se
   distinguen mal, que es justo lo que hay que poder mirar de un vistazo. */
.tabla .simbolo-moneda { font-size: 17px; font-weight: 600; }

/* Un campo que se muestra pero no se edita. Se ve apagado para que nadie
   intente teclear ahí y crea que el formulario está roto. */
.campo input[readonly] {
  background: var(--wash, #F2F5F9);
  color: var(--gris, #6B7785);
  cursor: not-allowed;
}

/* Apagado se atenúa pero se sigue leyendo: es lo que distingue «no está» de
   «está y no se ofrece». No se esconde nunca — lo que no se ve no se puede
   volver a encender. */
.tabla tr.apagado td { opacity: .5; }
.tabla tr.apagado .acciones-col { opacity: 1; }

.estado {
  display: inline-block;
  padding: 2px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700;
}
.estado.si { background: var(--wash); color: var(--acc-dk); }
.estado.no { background: #F4F7FA; color: var(--gris); }

/* ------------------------------------------------------ el formulario del diálogo */

#dlg-form {
  margin-top: 16px; text-align: left;
  /* Lo único que se desplaza. El padding lateral deja respirar el contorno
     de foco de los campos, que si no queda cortado contra el borde. */
  overflow-y: auto; min-height: 0;
  padding: 2px;
}
#dlg-form .campo:last-child { margin-bottom: 0; }

/*
 * Los formularios largos, en dos columnas.
 *
 * Agregar un país eran siete campos en una tira de 440 px de ancho: una
 * ventana angosta y altísima que no entraba en la pantalla, con el nombre
 * arriba de todo y el botón de guardar abajo de un desplazamiento. Y la
 * mayoría de esos campos son cortos —«HN», «+504», «HNL», «L», «100»—, o sea
 * que el espacio desperdiciado era casi todo.
 *
 * Dos columnas, y los campos largos ocupan las dos. El que escribe no tiene
 * que recorrer la ventana para ver qué le falta.
 */
.dialogo-caja.ancho { max-width: 680px; }
.dialogo-caja.ancho #dlg-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 18px;
  align-items: start;
}
/* Un campo marcado como ancho ocupa la fila entera: los nombres y las
   direcciones no entran en media columna. */
.dialogo-caja.ancho #dlg-form .campo.entero { grid-column: 1 / -1; }
/* El sí/no también: es una línea sola y partida al medio queda colgando. */
.dialogo-caja.ancho #dlg-form .campo-si-no { grid-column: 1 / -1; }

@media (max-width: 620px) {
  .dialogo-caja.ancho #dlg-form { grid-template-columns: 1fr; }
}
#dlg-form .campo .pie { margin-top: 5px; font-size: 11.5px; line-height: 1.5; }

.campo-si-no label {
  display: flex; align-items: center; gap: 9px;
  font-size: 14px; cursor: pointer; margin: 0;
}
.campo-si-no input { width: auto; accent-color: var(--acc); }

/* El error del formulario, abajo y en rojo. El diálogo NO se cierra cuando
   aparece: lo tecleado se queda donde estaba, que es toda la diferencia con
   los prompt() encadenados que había antes. */
.dialogo-caja .dlg-error {
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--rojo-lo);
  border-radius: 10px;
  color: var(--rojo);
  font-size: 13px; font-weight: 600;
  text-align: left;
}

/* ----------------------------------------------------------------- banderas
 *
 * El dibujo lo sirve la API, no la fuente del sistema. El emoji no servía:
 * Windows dibuja los dos «indicadores regionales» como las dos letras, así
 * que donde tenía que haber una bandera se leía «CR».
 *
 * El borde tenue existe por Costa Rica y Argentina: sus franjas de los
 * extremos son claras y, sin borde, la bandera se derrama sobre el fondo
 * blanco de la tabla y parece cortada.
 */
.bandera {
  width: 24px; height: 16px;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(15, 27, 45, .12);
  object-fit: cover;
  flex: none;
  display: block;
}
/* El respaldo cuando de ese país todavía no hay dibujo. Ocupa lo mismo que
   una bandera para que las filas no se corran, y se ve deliberado: un hueco
   parecería que la imagen no cargó. */
.bandera-codigo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 16px;
  border-radius: 3px;
  background: #F4F7FA;
  box-shadow: 0 0 0 1px rgba(15, 27, 45, .12);
  color: var(--gris);
  font-size: 9px; font-weight: 700; letter-spacing: .02em;
  flex: none;
}
.con-bandera { display: inline-flex; align-items: center; gap: 9px; }


/* ------------------------------------------------- el tablero del negocio */

/*
 * El embudo de los comercios.
 *
 * Lo que importa no es cada número sino la CAÍDA entre dos. «40 activos y 31
 * con premios» significa nueve locales que dijeron que sí y no cargaron
 * nada: eso es una lista de llamadas para mañana, no una estadística. Por
 * eso cada fuga es un botón rojo que lleva a la lista con el filtro puesto,
 * y no un número más.
 */
.embudo { display: grid; gap: 2px; margin-top: 12px; }
.escalon {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: 10px;
  font-size: 13.5px;
}
/* La barra va de fondo y no al lado: con una barra aparte, el número y su
   largo se leen como dos cosas distintas. */
.esc-barra {
  position: absolute; inset: 0 auto 0 0;
  width: var(--p, 0%);
  background: var(--wash);
  border-radius: 10px;
}
.escalon > b, .escalon > span, .escalon > .fuga { position: relative; }
.escalon > b {
  font-family: var(--f-d); font-size: 18px; font-weight: 800;
  min-width: 62px; text-align: right; font-variant-numeric: tabular-nums;
}
.escalon > span { flex: 1; color: var(--ink-soft); }

.fuga {
  border: 1px solid #F3C9CF; background: var(--rojo-lo); color: #9B2434;
  border-radius: 999px; padding: 4px 11px;
  font-size: 12px; font-weight: 700; cursor: pointer;
  white-space: nowrap;
}
.fuga:hover { background: #FBD9DE; }

/* Un dato con semáforo. El color va sólo cuando significa algo: pintar de
   verde un número que nadie sabe si es bueno es decorar, no informar. */
.dato.bien b { color: var(--acc-dk); }
.dato.tibio b { color: var(--ambar); }
.dato.mal b { color: var(--rojo); }

/* ------------------------------------------------- las señales de una alerta */

/*
 * Qué se encontró, qué significa y qué hacer.
 *
 * Lo del medio estaba en un `title` —se ve pasando el mouse, y sólo si uno
 * sabe que está ahí— y lo último no estaba en ningún lado. Estas señales no
 * se deciden igual entre sí, y esa diferencia vivía en la cabeza de quien
 * escribió el detector.
 */
.senal {
  border-left: 3px solid var(--linea);
  padding: 8px 0 8px 12px;
  margin: 10px 0;
}
.senal-que { margin-bottom: 5px; }
.senal-dice { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--ink-soft); }
.senal-hacer {
  margin: 6px 0 0; font-size: 12.5px; line-height: 1.55;
  color: var(--gris); background: #F6F9FC;
  border-radius: 8px; padding: 7px 10px;
}
.senal-hacer b { color: var(--ink); }
