/* ============================================================
   CAPA DE DISEÑO — SystemTrack
   ============================================================
   Va DESPUÉS del <style> de index.html y solo reescribe la piel: espaciados,
   tipografía, bordes y color. No cambia ninguna estructura ni ningún
   identificador, así que todo el JavaScript que ya funcionaba sigue igual.

   El lenguaje visual sale de Tremor Blocks y shadcn/ui, que es lo que usan hoy
   los productos serios de tablero. Tres reglas lo gobiernan todo:

     1. El color SIGNIFICA algo. Verde reportando, ámbar sin reportar, rojo
        vencido. Nada de color decorativo: si todo resalta, no resalta nada.
     2. La jerarquía se hace con TAMAÑO y PESO, no con cajas y sombras.
     3. Los números van tabulares. En una columna de kilómetros, con dígitos de
        ancho variable las cifras bailan y no se pueden comparar de un vistazo.

   Los tokens de tema (--bg, --card, --line...) ya existían y se respetan; aquí
   solo se añaden los que faltaban.
   ============================================================ */

/* ---------- 1. TOKENS QUE FALTABAN ---------- */
:root, html[data-tema="oscuro"] {
  /* Escala de espaciado de 4 px. Tener una escala y no números sueltos es lo
     que hace que una pantalla se vea ordenada aunque nadie sepa explicar por qué. */
  --e1: 4px;  --e2: 8px;  --e3: 12px; --e4: 16px; --e5: 24px; --e6: 32px;
  --r-sm: 6px; --r: 10px; --r-lg: 14px; --r-full: 999px;

  /* Superficies: una sola sombra, muy suave. La sombra se reserva para lo que
     de verdad flota (menús, diálogos), no para cada tarjeta. */
  --elev: 0 1px 2px rgba(0,0,0,.28);
  --elev-alta: 0 12px 32px -8px rgba(0,0,0,.55);
  --anillo: rgba(56,189,248,.35);

  /* Estado. Un solo tono por significado, con su fondo tenue para las píldoras. */
  --ok: #22c55e;   --ok-suave: rgba(34,197,94,.14);
  --avi: #f59e0b;  --avi-suave: rgba(245,158,11,.14);
  --mal: #ef4444;  --mal-suave: rgba(239,68,68,.14);
  --info: #38bdf8; --info-suave: rgba(56,189,248,.14);
  --neutro-suave: rgba(148,163,184,.14);
}
html[data-tema="claro"] {
  --elev: 0 1px 2px rgba(15,23,42,.06), 0 1px 3px rgba(15,23,42,.05);
  --elev-alta: 0 12px 32px -8px rgba(15,23,42,.18);
  --anillo: rgba(2,132,199,.28);
  --ok: #16a34a;   --ok-suave: rgba(22,163,74,.10);
  --avi: #d97706;  --avi-suave: rgba(217,119,6,.10);
  --mal: #dc2626;  --mal-suave: rgba(220,38,38,.10);
  --info: #0284c7; --info-suave: rgba(2,132,199,.10);
  --neutro-suave: rgba(100,116,139,.10);
}

/* ---------- 2. BASE ---------- */
body {
  /* Inter si el sistema la tiene; si no, la del sistema. Sin descargar fuentes:
     una fuente web bloquea el primer pintado y aquí se abre la plataforma
     cincuenta veces al día. */
  font-family: Inter, "Segoe UI Variable", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "cv11", "ss01";
}
/* Todo lo que sea una cifra se alinea en columna. */
table td, table th, .kpi-num, .mono, code, input[type=number] { font-variant-numeric: tabular-nums; }

/* ---------- 3. TARJETAS ---------- */
/* Borde en vez de sombra: es lo que separa una tarjeta de 2016 de una de hoy. */
.card, .form {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--e4);
  box-shadow: var(--elev);
}
.card { margin-bottom: var(--e3); }
.card h2 {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--txt);            /* antes iba en color de acento: envejecía la pantalla */
  margin: 0 0 var(--e3);
  align-items: center;
  gap: var(--e2);
}
.card h2 > span:first-child { display: flex; align-items: center; gap: var(--e2); }
.form h3 {
  font-size: 13px; font-weight: 600; letter-spacing: -.01em;
  margin: 0 0 var(--e3); color: var(--txt);
}

/* Separador de sección: fino, en mayúsculas, sin gritar. */
.dsec {
  font-size: 10px; font-weight: 600; letter-spacing: .06em;
  color: var(--mut); text-transform: uppercase;
  margin: var(--e4) 0 var(--e2); padding-top: var(--e3);
  border-top: 1px solid var(--line);
}

/* ---------- 4. TABLAS ---------- */
table { font-size: 13px; }
th {
  font-size: 10.5px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--mut);
  padding: var(--e2) var(--e3);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
td {
  padding: 10px var(--e3);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
tbody tr { transition: background .12s ease; }
tbody tr:hover td { background: var(--fila-hover); }
tbody tr:last-child td { border-bottom: 0; }

/* ---------- 5. BOTONES ---------- */
/* Tres niveles y no más. Si todo es un botón azul, nada es la acción principal. */
/* Solo el botón de enviar, no CUALQUIER botón del formulario. La regla sin
   excepciones pintaba de azul las cabeceras de sección (`.acc-head`), que son
   grises por diseño; al pasar el ratón recuperaban su gris y el texto blanco
   que les había puesto yo desaparecía. */
.form button:not(.acc-head):not(.btn-sm):not([style*="background"]), button.primario {
  background: var(--acc2); color: #fff;
  border: 1px solid transparent; border-radius: var(--r-sm);
  padding: 9px var(--e4); font-size: 13px; font-weight: 500;
  transition: filter .12s ease, transform .04s ease;
}
.form button:not(.acc-head):not(.btn-sm):hover, button.primario:hover { filter: brightness(1.08); }
.form button:not(.acc-head):not(.btn-sm):active, button.primario:active { transform: translateY(.5px); }
.form button:disabled { opacity: .55; cursor: not-allowed; filter: none; }
/* La cabecera de sección conserva su gris propio y su texto normal. */
.form .acc-head { background: var(--btn) !important; color: var(--txt) !important; }
.form .acc-head:hover { background: var(--hover) !important; filter: none; }

.btn-sm {
  background: transparent; color: var(--txt);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 5px 10px; font-size: 12px; font-weight: 500;
  transition: background .12s ease, border-color .12s ease;
}
/* OJO con el hover: hay botones que traen su propio color de fondo escrito en
   el atributo style (las cabeceras azules de sección, Editar, Borrar). Si el
   hover les cambia el fondo a gris claro, el texto blanco queda sobre un fondo
   claro y desaparece. A esos se les aclara el color que ya tienen; el gris solo
   se le pone a los que no traen fondo propio. */
.btn-sm:not([style*="background"]):hover { background: var(--hover); }
.btn-sm[style*="background"]:hover { filter: brightness(1.08); }
.btn-sm:disabled { opacity: .5; cursor: not-allowed; filter: none; }

/* ---------- 6. CAMPOS ---------- */
.winp, .form input, .form select, .form textarea {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 8px 10px; font-size: 13px;
  background: var(--campo); color: var(--txt);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.winp:focus, .form input:focus, .form select:focus, .form textarea:focus {
  outline: 0; border-color: var(--acc2);
  box-shadow: 0 0 0 3px var(--anillo);     /* el anillo de foco es accesibilidad, no adorno */
}
.winp::placeholder, .form input::placeholder, .form textarea::placeholder { color: var(--mut); opacity: .75; }
.form label { font-size: 11.5px; font-weight: 500; color: var(--mut); margin: var(--e3) 0 var(--e1); }

/* ---------- 7. PÍLDORAS DE ESTADO ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--r-full);
  font-size: 11px; font-weight: 500; line-height: 18px;
  background: var(--neutro-suave); color: var(--mut);
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill.ok  { background: var(--ok-suave);  color: var(--ok); }
.pill.avi { background: var(--avi-suave); color: var(--avi); }
.pill.mal { background: var(--mal-suave); color: var(--mal); }
.pill.info{ background: var(--info-suave);color: var(--info); }
.pill.plano::before { display: none; }

/* ---------- 8. TARJETAS DE INDICADOR ---------- */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--e2); }
.kpi {
  border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--e3); background: var(--bg2);
}
.kpi-lbl {
  font-size: 11px; font-weight: 500; color: var(--mut);
  display: flex; align-items: center; gap: 5px; margin-bottom: 6px;
}
.kpi-num { font-size: 24px; font-weight: 650; letter-spacing: -.02em; line-height: 1.1; }
.kpi-sub { font-size: 11px; color: var(--mut); margin-top: 3px; }
.kpi.ok  .kpi-num { color: var(--ok); }
.kpi.avi .kpi-num { color: var(--avi); }
.kpi.mal .kpi-num { color: var(--mal); }

/* ---------- 9. ESTADO VACÍO ---------- */
/* Una tabla vacía con un "no hay datos" en gris no dice qué hacer. */
.vacio {
  text-align: center; padding: var(--e5) var(--e4); color: var(--mut);
}
.vacio .ic { width: 26px; height: 26px; opacity: .5; margin-bottom: var(--e2); }
.vacio b { display: block; color: var(--txt); font-size: 13px; font-weight: 550; margin-bottom: 3px; }
.vacio span { font-size: 12px; line-height: 1.5; display: block; max-width: 320px; margin: 0 auto; }

/* ---------- 10. ICONOS ---------- */
/* Trazo, no emoji. El emoji se ve distinto en cada sistema, no se puede colorear
   y es lo que primero delata una interfaz improvisada. */
.ic {
  width: 15px; height: 15px; flex: 0 0 auto;
  stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -2px;
}
.ic-lg { width: 18px; height: 18px; }

/* ---------- 11. NAVEGACIÓN DE PESTAÑAS ---------- */
/* Con catorce pestañas, dejarlas envolver parte los rótulos en dos líneas y
   descuadra la fila entera. Se quedan en una sola línea y se desplazan. */
#admin .subnav, .subnav {
  gap: var(--e1);
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  border-bottom: 1px solid var(--line);
  padding-bottom: 0; margin-bottom: var(--e4);
}
#admin .subnav::-webkit-scrollbar, .subnav::-webkit-scrollbar { display: none; }
#admin .subnav button, .subnav button {
  flex: 0 0 auto; white-space: nowrap;
  background: transparent; color: var(--mut);
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  padding: 9px var(--e3); font-size: 13px; font-weight: 500;
  box-shadow: none;
  transition: color .12s ease, border-color .12s ease;
}
#admin .subnav button:hover, .subnav button:hover { color: var(--txt); background: transparent; }
/* La pestaña activa se marca con una línea bajo el rótulo, no con una caja:
   ocupa menos y se lee antes. */
#admin .subnav button.act, .subnav button.act {
  color: var(--txt); background: transparent;
  border-bottom-color: var(--acc2); box-shadow: none;
}

/* ---------- 11b. LA VISTA DE ALERTAS ---------- */
/* "Alertas" vuelve al menú lateral: en Administración se arma el catálogo de
   reglas y eventos, pero las alertas ya configuradas de cada vehículo las mira
   el usuario, y este botón es el único camino que tiene. La de IA de cámara ya
   NO se esconde por CSS: ahora es un servicio en la nube real y su visibilidad
   la controla comprobarIA() por el id #nav-ia (aparece solo si la cuenta tiene
   al menos una cámara con eventos). */
/* Alertas y Alertas de cámara vivían en el menú lateral y traían su propio
   título y su propio relleno de pantalla completa. Dentro de una pestaña eso
   sobra: la pestaña ya dice dónde estás, y repetirlo roba una franja entera. */
#rulv-alertas > .view > div, #rulv-ia > .view > div,
#rulv-alertas > div > div[id$="-wrap"], #rulv-ia > div > div[id$="-wrap"] { padding: 0 !important; }
#rulv-alertas h2[style*="var(--acc)"], #rulv-ia h2[style*="var(--acc)"] { display: none; }
#rulv-alertas #alerts-wrap, #rulv-ia > div { height: auto !important; overflow: visible !important; }

/* Botones de acción dentro de una tabla: uno solo destaca. Con Editar en azul
   sólido, Pausar gris y Borrar en rojo, la fila entera grita y el ojo no sabe
   dónde ir. Aquí el color se reserva para el que hace daño. */
#alerts-tb .btn-sm, #alerts-tb button {
  background: transparent !important; color: var(--txt) !important;
  border: 1px solid var(--line) !important; font-weight: 500;
}
#alerts-tb .btn-sm:hover, #alerts-tb button:hover { background: var(--hover) !important; }
#alerts-tb button[onclick*="orrar"], #alerts-tb button[onclick*="liminar"] {
  color: var(--mal) !important; border-color: transparent !important;
}
#alerts-tb button[onclick*="orrar"]:hover, #alerts-tb button[onclick*="liminar"]:hover {
  background: var(--mal-suave) !important;
}

/* ============================================================
   11c. COMPOSICIÓN — lo que de verdad estaba mal
   ============================================================
   Los tokens arreglan la piel; el problema era la DISPOSICIÓN. Esta sección
   corrige lo que se veía en la pantalla de Usuarios: un bloque de filtros con
   un hueco, una caja dentro de otra caja, y un formulario de diez campos en
   fila india sin ninguna jerarquía.
   ============================================================ */

/* --- Filtros en rejilla, no en flex con envoltura ---
   Con `flex-wrap` y anchos fijos, la última fila queda a medias y deja un vacío
   enorme; y como los campos tienen alturas distintas, nada se alinea. Una
   rejilla de columnas iguales llena el ancho siempre y alinea las etiquetas. */
.filtros {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  align-items: start;
  gap: var(--e3);
  padding: var(--e3);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  margin: 0 0 var(--e3);
}
/* Cada filtro es etiqueta + control, y la etiqueta ocupa SIEMPRE el mismo alto.
   Sin eso, un filtro con dos controles apilados empuja al vecino y la fila
   entera queda torcida: era lo que se veía en "Gerente superior". */
.filtros .campo {
  flex: none !important; max-width: none !important; min-width: 0;
  display: flex; flex-direction: column; justify-content: flex-end;
}
.filtros .campo > span {
  font-size: 11px; font-weight: 500; color: var(--mut);
  height: 15px; line-height: 15px; margin-bottom: 5px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.filtros .winp, .filtros input, .filtros select {
  width: 100% !important; height: 34px; padding: 0 9px;
}
.filtros .campo > div { display: flex; gap: 6px; }

/* --- El buscador sobrante ---
   El buscador automático se metía ENCIMA de la lista de gerentes: dos controles
   apilados donde los demás tienen uno, y por eso la fila quedaba desalineada.
   Dentro de un filtro sobra: un <select> ya busca solo al teclear. Se deja
   funcionando en las tablas, que es donde sí hace falta. */
.filtros .busca-caja { display: none !important; }

/* El botón de limpiar va al final de la fila, pegado a la derecha, no en una
   celda cualquiera en mitad de la rejilla. */
.filtros .campo:has(> button) { grid-column: -2 / -1; }
.filtros .campo > button { height: 34px; }
/* El contador cierra el bloque a la derecha. */
.filtros .cuenta { grid-column: 1 / -1; margin-left: 0; text-align: right; padding: 0; font-size: 11px; }

/* --- Formularios largos: agrupar en dos columnas ---
   Diez campos en una sola columna obligan a rodar la pantalla para crear un
   usuario. Con dos columnas cabe todo de un vistazo. */
.form.form-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--e3); align-items: start; }
.form.form-2col > h3, .form.form-2col > .dsec, .form.form-2col > button,
.form.form-2col > .msg, .form.form-2col > .ancho { grid-column: 1 / -1; }

/* --- Densidad de tabla ---
   Con filas de 60 px caben cuatro registros en pantalla. La consulta de una
   lista se hace comparando, y para comparar hay que ver varios a la vez. */
td { padding: 7px var(--e3); }
th { padding: 6px var(--e3); }
td b, td strong { font-weight: 550; }
/* La segunda línea gris de cada fila (nombre completo bajo el usuario) no
   necesita el mismo alto que la principal. */
td .k { line-height: 1.35; }

/* --- Panel de dos columnas: la lista manda ---
   Lista y formulario tenían casi el mismo ancho. La lista es lo que se consulta
   todos los días; el formulario se usa una vez por usuario nuevo. */
#admin .panel { display: grid; grid-template-columns: minmax(0, 1.9fr) minmax(300px, .85fr); gap: var(--e3); align-items: start; }
@media (max-width: 1100px) { #admin .panel { grid-template-columns: 1fr; } }

/* ---------- 11d. FORMULARIO EN VENTANA ---------- */
/* Ancha de verdad: dos columnas de campos caben sin apretarse, que es lo que
   no se podía hacer en la columna estrecha de al lado de la tabla. */
#form-vent {
  display: none; position: fixed; inset: 0; z-index: 4000;
  background: rgba(15,23,42,.55); backdrop-filter: blur(2px);
  align-items: flex-start; justify-content: center; padding: 4vh var(--e4);
  overflow: auto;
}
#form-vent .fv-caja {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--elev-alta);
  width: min(620px, 100%); max-height: 92vh; display: flex; flex-direction: column;
}
#form-vent .fv-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e3) var(--e4); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--card); border-radius: var(--r-lg) var(--r-lg) 0 0;
}
#form-vent .fv-top b { font-size: 14px; font-weight: 600; }
#form-vent #fv-cuerpo { overflow: auto; padding: var(--e4); }
/* Dentro de la ventana el formulario ya no es una tarjeta: la ventana lo es. */
/* Una sola columna, con la etiqueta ENCIMA de su campo.
   Se probó a dos columnas y quedó mal: la rejilla reparte los hijos uno a uno,
   así que un texto de ayuda entre medias desplaza todo y las etiquetas dejan de
   corresponder con su campo. Agruparlas de verdad exigiría reescribir el HTML
   de cada formulario; no compensa para ganar una columna. */
#form-vent .form {
  border: 0 !important; box-shadow: none !important; padding: 0 !important;
  background: transparent !important;
}
#form-vent .form { display: block !important; }
#form-vent .form > h3 { display: none; }     /* el título ya está en la barra */
#form-vent .form label:first-of-type { margin-top: 0; }

/* Con el formulario fuera, la tabla se queda con todo el ancho. */
#admin .panel.panel-full { grid-template-columns: 1fr; }
/* El formulario descansa dentro de administración —de ahí lo toma la ventana y
   ahí vuelve al cerrarse—, pero NO debe verse: se llega a él por el botón de
   arriba. Dentro de la ventana sí se muestra, porque la ventana cuelga del
   cuerpo del documento y esta regla ya no le alcanza. */
#admin #form-usuario, #admin #form-objeto { display: none; }
/* Sin esto, una tabla ancha empuja su celda de la rejilla más allá del borde de
   la pantalla y se lleva por delante la cabecera de la tarjeta. El desborde
   tiene que quedarse DENTRO de la tabla, no salirse del panel. */
#admin .panel > * { min-width: 0; }
#admin .panel .card > div[style*="overflow"] { overflow-x: auto; }

/* ---------- 11e. ANCHO Y DESPLAZAMIENTO DE LA TABLA ---------- */
/* El problema no era el número de columnas sino que ninguna tenía tope: un
   correo largo estiraba su columna todo lo que hiciera falta y arrastraba la
   tabla entera fuera de la pantalla. Con un tope, el texto parte en dos líneas
   —no se oculta nada— y la tabla cabe. */
/* Se probó a limitar el ancho de cada celda y a dejar que el texto partiera:
   quedó peor. Un correo se rompía en tres trozos («ronaldm / ontoya99 /
   8@gmail.com») y el nombre de usuario igual. Un dato partido a mitad de
   palabra cuesta más de leer que uno que se sale.
   Ahora cada celda va en UNA línea y el ancho se gana por otro lado: menos
   relleno, la segunda línea más pequeña, y la barra de arriba para moverse. */
#admin td, #admin th { padding: 6px 10px; white-space: nowrap; }
/* La segunda línea de cada fila (el nombre completo bajo el usuario) es
   contexto, no dato principal: va más pequeña y no manda en el ancho. */
#admin td .k { font-size: 10.5px; }
/* OJO: aquí había un `display: block` para el texto gris de las celdas. Estaba
   pensado para la segunda línea bajo el nombre de usuario —que ya trae su
   propio <br>, así que no lo necesitaba— y de paso partía en tres renglones la
   celda de créditos: el número, el «/ 20» y el botón «+», cada uno en su línea.
   Un texto gris dentro de una celda va EN LÍNEA con lo que lo acompaña. */
#admin td .k { display: inline; }
/* La celda de créditos lleva número, total y botón: los tres en una línea y
   centrados entre sí. */
#admin td > b + .k { margin-left: 2px; }
#admin td .btn-sm { vertical-align: middle; }
/* El correo es lo más largo de la tabla y casi nunca se lee entero: se recorta
   con puntos suspensivos y se ve completo al pasar el ratón. Nada se pierde. */
#admin td.recorta, #admin td:nth-child(3) {
  max-width: 240px; overflow: hidden; text-overflow: ellipsis;
}
/* Celdas que SÍ pueden partirse en dos líneas: rótulos de dos palabras como
   «Créditos prepagados», que en una sola línea estiran su columna y desplazan
   toda la tabla a la derecha.

   OJO: aquí NO se puede usar `display:-webkit-box` para recortar a dos
   renglones. Un <td> con un display distinto de `table-cell` se sale de la
   tabla: la columna deja de alinearse con su cabecera y aparecen líneas
   sueltas. Basta con permitir el salto y poner un tope de ancho. */
#admin td.dos-lineas {
  white-space: normal;
  max-width: 130px;
  line-height: 1.3;
}

/* --- Barra de desplazamiento ARRIBA ---
   La barra del navegador queda al fondo de la tabla: con treinta filas hay que
   bajar hasta abajo para poder moverse a los lados. Esta es un espejo de la de
   abajo, puesta encima, y las dos van sincronizadas. */
.scroll-espejo {
  overflow-x: auto; overflow-y: hidden;
  height: 12px; margin-bottom: 2px;
}
.scroll-espejo > div { height: 1px; }
.scroll-espejo::-webkit-scrollbar { height: 9px; }
.scroll-espejo::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: var(--r-full);
}
.scroll-espejo::-webkit-scrollbar-thumb:hover { background: var(--mut); }
.scroll-espejo::-webkit-scrollbar-track { background: transparent; }

/* ---------- 12. AVISOS ---------- */
.msg { font-size: 12px; line-height: 1.5; }
.msg.ok  { color: var(--ok); }
.msg.err { color: var(--mal); }

/* ---------- 13. FILAS DE LISTA ---------- */
.row { padding: var(--e2) 0; font-size: 12.5px; }
.row:last-child { border-bottom: 0; }

/* ---------- 14. DETALLE ---------- */
code, .mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 11.5px; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--r-full); border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--mut); background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

/* ===== 11f · LA FILA DE HERRAMIENTAS DE OBJETOS =====
   El buscador, los tres botones y los dos avisos ocupaban cuatro franjas
   apiladas: más de un tercio del alto útil antes de empezar la tabla. Van en
   una sola línea, con las acciones a la izquierda y los avisos a la derecha.
   Ojo: `.filtros` es `display:grid !important`, así que esto tiene que ser
   igual de terminante o la caja se sigue repartiendo en columnas de 180 px
   y todo se envuelve. */
#atab-devices .busca-caja {
  display: flex !important;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 10px;
}
#atab-devices .busca-caja > .campo { flex: 0 0 240px; order: 1; }
#atab-devices .busca-caja > #devs-barra { order: 2; }
#atab-devices .busca-caja > #devs-avisos { order: 3; margin-left: auto; }
#atab-devices .busca-caja > .cuenta { order: 4; margin-left: 8px; }

#devs-barra, #devs-avisos {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0;
}
/* Las etiquetas de aviso son botones: se les quita el aire de botón y se les
   deja el de etiqueta, que es lo que son hasta que se pulsan. */
#devs-avisos .pill { border: 0; cursor: pointer; font: inherit; }
#devs-avisos .pill:hover { filter: brightness(1.12); }

/* ===== 11g · NOTIFICACIONES: CANALES, PRUEBA Y DÍA A DÍA =====
   Eran ocho tarjetas apiladas y había que rodar la pantalla entera para
   responder la única pregunta que trae aquí a la gente: ¿está todo puesto? */

/* Los tres canales, misma anchura y misma altura de cabecera. */
#atab-notify .canales {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--e3);
  margin-bottom: var(--e3);
  /* Las tres del mismo alto, y el botón pegado abajo. Rellenar con espacios
     alinearía solo con los textos de hoy: en cuanto uno cambie, se tuerce
     otra vez. Con la tarjeta en columna y la explicación estirándose, el
     botón queda a la misma altura diga lo que diga cada canal. */
  align-items: stretch;
}
#atab-notify .canales > .card {
  margin: 0; display: flex; flex-direction: column;
}
#atab-notify .canales > .card > .canal-sub { flex: 1; }
#atab-notify .canales h2 { display: flex; align-items: center; gap: 8px; }
/* La explicación es contexto, no el contenido: dos líneas y a otra cosa. */
#atab-notify .canal-sub {
  font-size: 11.5px; line-height: 1.5; margin-bottom: 10px;
}

/* El formulario de cada canal vive en una ventana, no desplegándose hacia
   abajo: al abrirse empujaba la página entera y las tres tarjetas dejaban de
   estar alineadas, que era justo lo que se ganaba poniéndolas en fila.
   Se esconde por identificador de ancestro (#admin), no por clase suelta:
   la ventana cuelga de <body>, fuera de #admin, así que allí sí se ve. */
#admin .canal-form { display: none; }
/* Dentro de la ventana ya hay una caja; otra dentro sería caja sobre caja. */
#fv-cuerpo > .canal-form { border: 0; padding: 0; background: none; }
#fv-cuerpo > .canal-form > .form { margin-top: 12px; }

/* La prueba: una línea, no una tarjeta con título. */
#atab-notify .barra-prueba {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: var(--e3);
}
#atab-notify .barra-prueba .bp-ico { display: flex; color: var(--mut); }
#atab-notify .barra-prueba .bp-tit { font-size: 13px; font-weight: 500; }
#atab-notify .barra-prueba select { width: 120px; flex: 0 0 auto; }
#atab-notify .barra-prueba input { flex: 1; min-width: 180px; }
#atab-notify .barra-prueba .msg { flex: 1 0 100%; margin: 0; }
#atab-notify .barra-prueba .msg:empty { display: none; }

/* Abajo: la lista corta a la izquierda, la tabla que sí se mira a la derecha. */
#atab-notify .notif-abajo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: var(--e3);
}
#atab-notify .notif-abajo > .card { margin: 0; }
@media (max-width: 760px) {
  #atab-notify .notif-abajo { grid-template-columns: 1fr; }
}

/* La ventana de Firebase lleva una tabla de cinco columnas; en 620 px sale
   con desplazamiento lateral desde el primer proyecto. */
#form-vent:has(#form-canal-push) .fv-caja { width: min(880px, 100%); }

/* ===== 11h · LA VENTANA DE UN CANAL, POR DENTRO =====
   La de Firebase no es solo un formulario: es una lista y además un alta. Sin
   separarlas, la tabla y los campos parecían la misma cosa y no se entendía
   qué estabas mirando. */

/* Rótulo de sección. No se usa <h3> porque dentro de la ventana los <h3> están
   escondidos a propósito (el título ya está en la barra de arriba), y aquí sí
   hacen falta dos rótulos: uno para la lista y otro para el alta. */
#fv-cuerpo .sec {
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
  color: var(--mut); text-transform: uppercase;
  margin: 0 0 8px;
}
/* El alta va en su propia caja, separada de la lista por una línea. */
#fv-cuerpo .bloque-alta {
  margin-top: var(--e4); padding-top: var(--e4) !important;
  border-top: 1px solid var(--line) !important;
}

/* Un <textarea> sin ancho cae en su `cols` de fábrica —veinte caracteres— y
   sale como una rendija al lado de campos de ochocientos píxeles. */
.form textarea, #fv-cuerpo textarea { width: 100%; box-sizing: border-box; }
#fv-cuerpo textarea.mono { font-size: 12px; line-height: 1.45; }

/* El texto de ayuda es ayuda, no un párrafo más del formulario. */
#fv-cuerpo .ayuda {
  font-size: 11px; line-height: 1.5; color: var(--mut); margin-top: 5px;
}

/* Casilla y su explicación: el cuadro arriba a la izquierda, el texto al lado
   sin saltar de línea por debajo del cuadro. */
#fv-cuerpo .casilla {
  align-items: flex-start; gap: 9px; margin-top: var(--e3);
  cursor: pointer; font-weight: 400;
}
#fv-cuerpo .casilla > input { width: 15px; height: 15px; margin: 2px 0 0; flex: 0 0 auto; }
#fv-cuerpo .casilla > span { font-size: 12.5px; }
#fv-cuerpo .casilla .k { display: block; font-size: 11px; margin-top: 2px; }

/* Guardar no es una franja azul de lado a lado: es un botón, y va a la derecha
   donde acaba la lectura del formulario. */
#fv-cuerpo .acciones {
  display: flex; justify-content: flex-end; gap: var(--e2); margin-top: var(--e4);
}
/* Los botones del formulario llevan `width:100%` de base —tienen sentido
   cuando son el único elemento de la columna—, pero en una fila de acciones
   eso los convierte en una franja de lado a lado. */
#fv-cuerpo .acciones button { width: auto !important; flex: 0 0 auto; padding: 8px 18px; }

/* ===== 11i · LA MATRIZ DE PERMISOS =====
   Permisos en filas, grupos en columnas. Lo que importa aquí es poder seguir
   una fila con el ojo sin perderla: por eso la columna de nombres se queda
   fija al desplazar y las filas se resaltan al pasar por encima. */

#pm-tabla { width: auto; min-width: 100%; border-collapse: separate; border-spacing: 0; }

/* La columna del permiso no se va con el desplazamiento lateral. Sin esto, con
   ocho grupos dejas de saber qué permiso estás marcando. */
#pm-tabla th.pm-h-perm, #pm-tabla td.pm-perm, #pm-tabla tr.pm-mod > td:first-child {
  position: sticky; left: 0; z-index: 2;
  background: var(--card);
  text-align: left; white-space: nowrap;
  min-width: 220px; padding: 6px 14px 6px 10px;
}
#pm-tabla tr.pm-mod > td:first-child { background: var(--hover); }
#pm-tabla td.pm-perm { font-size: 12.5px; }
#pm-tabla td.pm-perm .ic { width: 13px; height: 13px; opacity: .5; vertical-align: -2px; }

/* Cabecera de columna: nombre, a cuánta gente afecta, y qué se puede hacer con
   ella. Eso era todo lo que aportaba la tabla de grupos que se quitó. */
#pm-tabla th.pm-col {
  min-width: 128px; padding: 8px 10px 7px; text-align: center; vertical-align: bottom;
}
#pm-tabla th.pm-col .pm-col-tit { font-size: 13px; font-weight: 600; margin-bottom: 2px; }
#pm-tabla th.pm-col .k { font-size: 10.5px; font-weight: 400; }
#pm-tabla th.pm-col .pm-defecto { font-size: 10.5px; font-weight: 500; color: var(--ok); }
#pm-tabla th.pm-col .pm-col-acc {
  display: flex; justify-content: center; gap: 4px; margin-top: 6px; min-height: 22px;
  align-items: center;
}
#pm-tabla th.pm-col .pm-col-acc .btn-sm { padding: 2px 6px; }

/* Fila de módulo: es un encabezado, no un permiso más. */
#pm-tabla tr.pm-mod > td {
  background: var(--hover);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
  padding: 6px 10px; border-top: 1px solid var(--line);
}
#pm-tabla tr.pm-mod > td .k { font-weight: 400; text-transform: none; letter-spacing: 0; }

#pm-tabla tbody td { text-align: center; padding: 5px 10px; border-top: 1px solid var(--line); }
#pm-tabla tbody tr:not(.pm-mod):hover > td { background: var(--fila-hover); }
#pm-tabla tbody tr:not(.pm-mod):hover > td.pm-perm { background: var(--fila-hover); }
#pm-tabla input[type=checkbox] { width: 16px; height: 16px; cursor: pointer; margin: 0; }
#pm-tabla input[type=checkbox]:disabled { cursor: not-allowed; opacity: .3; }

/* El pie solo grita cuando hay algo que perder. */
#pm-pie {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--e3);
  margin-top: var(--e3); padding-top: var(--e3); border-top: 1px solid var(--line);
}
#pm-pie #pm-aviso:empty { display: none; }
#pm-pie #pm-guardar { width: auto !important; padding: 8px 18px; }
#pm-pie #pm-guardar:disabled { opacity: .45; cursor: not-allowed; }

/* El formulario de alta descansa dentro de administración —de ahí lo toma la
   ventana— pero no debe verse ahí. Igual que #form-usuario y #form-objeto. */
#admin #form-grupo { display: none; }

/* El buscador automático se cuela aquí porque la matriz es una tabla de más de
   ocho filas, pero filtrar por texto la rompe: esconde permisos y deja las
   cabeceras de módulo colgando sobre nada. Y su contador dice "28 filas",
   sumando las ocho cabeceras a los veinte permisos. */
#atab-permisos .busca-caja { display: none !important; }

/* El botón azul se quedaba en blanco al pasar por encima y su texto —blanco—
   desaparecía. La culpa era de la regla genérica `.btn-sm:not([style])::hover`,
   que pinta el fondo de gris: tiene tres clases de especificidad y le ganaba a
   `button.primario:hover`, que solo ajustaba el brillo. Se iguala aquí. */
.btn-sm.primario, button.primario { background: var(--acc2); color: #fff; border-color: transparent; }
.btn-sm.primario:hover { background: var(--acc2); color: #fff; filter: brightness(1.1); }
.btn-sm.primario:disabled, .btn-sm.primario:disabled:hover { filter: none; }

/* ===== 11j · MEMBRESÍAS: PRECIOS CON LA CUENTA HECHA =====
   La tabla de créditos y la de niveles eran dos tarjetas separadas, y para saber
   lo que paga un gerente había que multiplicar de cabeza saltando entre ambas.
   Aquí el peso va debajo del crédito, en gris, para que se lea sin cruzar nada. */
#atab-membresias .mb-nivel {
  background: var(--fond); border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--e3); margin-bottom: var(--e3);
}
/* Los seis niveles de un vistazo: sustituyen a la tabla que estaba aparte.
   Se comparan sin abrir nada y el que se pulsa es el que se edita abajo. */
#atab-membresias .mb-tira {
  display: flex; flex-wrap: wrap; gap: var(--e2); margin-bottom: var(--e3);
}
#atab-membresias .mb-nv {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  min-width: 118px; padding: 8px 12px; text-align: left; cursor: pointer;
  background: var(--card); color: var(--txt);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  width: auto; font-size: 13px; transition: border-color .12s ease, background .12s ease;
}
#atab-membresias .mb-nv:hover { border-color: var(--acc2); background: var(--card); }
#atab-membresias .mb-nv.act {
  border-color: var(--acc2); background: var(--card);
  box-shadow: inset 0 -2px 0 var(--acc2);
}
#atab-membresias .mb-nv.tocada { border-color: var(--avi); }
#atab-membresias .mb-nv-n { font-size: 11px; color: var(--mut); }
#atab-membresias .mb-nv-v { font-size: 15px; font-weight: 650; letter-spacing: -.02em; }
#atab-membresias .mb-nv-p {
  font-size: 10.5px; color: var(--mut); max-width: 150px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

#atab-membresias .mb-nivel-edit {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--e3);
  border-top: 1px solid var(--line); padding-top: var(--e3);
}
#atab-membresias .mb-nivel-edit .campo { margin: 0; }
#atab-membresias .mb-nivel-edit .campo label {
  display: block; font-size: 11.5px; font-weight: 500; color: var(--mut); margin-bottom: var(--e1);
}
#atab-membresias .mb-equiv {
  margin-left: auto; align-self: center; font-size: 13px; color: var(--mut);
}
#atab-membresias .mb-equiv b { color: var(--txt); font-size: 15px; }

/* Estos campos viven fuera de un `.form`, así que no les llegaba ninguna de las
   reglas de la sección 6 y salían con el borde gris de fábrica del navegador. */
#atab-membresias .mb-nivel-edit input,
#atab-membresias .mb-cr input {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 8px 10px; font-size: 13px;
  background: var(--campo); color: var(--txt);
  transition: border-color .12s ease, box-shadow .12s ease;
}
#atab-membresias .mb-nivel-edit input:focus,
#atab-membresias .mb-cr input:focus {
  outline: 0; border-color: var(--acc2); box-shadow: 0 0 0 3px var(--anillo);
}
#atab-membresias .mb-nivel-edit input::placeholder { color: var(--mut); opacity: .75; }
#atab-membresias .mb-nivel-edit .campo input { width: 190px; margin: 0; }

#atab-membresias .mb-celda { white-space: nowrap; }
#atab-membresias .mb-cr { display: flex; align-items: center; gap: 6px; }
#atab-membresias .mb-cr input { width: 84px; margin: 0; }
/* El equivalente en pesos es consecuencia, no dato que se teclee: va debajo,
   más pequeño y apagado, para que no compita con la casilla editable. */
#atab-membresias .mb-eq { font-size: 11.5px; color: var(--mut); margin-top: 3px; }

/* Ámbar en el borde izquierdo = esta celda cambió y todavía no se ha guardado. */
#atab-membresias .mb-celda.tocada { box-shadow: inset 3px 0 0 var(--avi); }
#atab-membresias .mb-celda.tocada .mb-cr input { border-color: var(--avi); }

#mb-pend:empty { display: none; }
#mb-guardar { width: auto !important; padding: 8px 18px; }
#mb-guardar:disabled { opacity: .45; cursor: not-allowed; }

/* Vive dentro de administración —de ahí lo toma la ventana— pero no se ve ahí.
   Igual que #form-grupo y #form-usuario. */
#admin #form-inventario { display: none; }

/* La fila de herramientas del inventario, igual que la de Objetos (11f): el
   buscador que inyecta el observador a la izquierda y los filtros a la derecha.
   Dentro del <h2> los selects se estiraban a la altura del título. */
#mbv-inventario .busca-caja {
  display: flex !important; align-items: flex-end; flex-wrap: wrap; gap: 10px;
}
#mbv-inventario .busca-caja > .campo { flex: 0 0 220px; order: 1; }
#mbv-inventario .busca-caja > .cuenta { order: 2; }
/* Los controles acaban siendo hijos directos de la caja (ver mbJuntarBarra). */
/* El `width: auto` va con !important a la fuerza: la caja lleva también la clase
   `filtros`, y `.filtros select { width: 100% !important }` (sección 10) le gana
   a cualquier regla sin marcar por especificidad que tenga. */
#mbv-inventario .busca-caja > .mb-ctl {
  margin: 0; width: auto !important; flex: 0 0 auto; height: 34px;
  font-size: 13px; order: 3;
}
#mbv-inventario .busca-caja > select.mb-ctl { min-width: 165px; }
#mbv-inventario .busca-caja > select.mb-ctl:first-of-type { margin-left: auto; }
#mbv-inventario .busca-caja > button.mb-ctl {
  width: auto !important; height: 34px; padding: 0 14px; white-space: nowrap; order: 4;
}
#mb-barra:empty { display: none; }

/* La tabla de precios tiene cuatro filas: un buscador ahí sobra y su contador
   ("4 filas") no le dice nada a nadie. */
#mbv-precios .busca-caja { display: none !important; }

/* ===== 11k · COMANDOS E INTEGRACIONES: LA TABLA MANDA =====
   Los dos tenían la lista a media pantalla y, al lado, un formulario permanente
   que solo se usa al crear o editar. Mismo tratamiento que Usuarios y Objetos:
   el formulario se muda a la ventana y la lista se queda con todo el ancho. */
#admin #form-comando, #admin #integ-editor { display: none; }
/* Dentro de la ventana ya no son una tarjeta: el marco lo pone la ventana. */
#fv-cuerpo > #integ-editor { border: 0; padding: 0; background: none; }
#form-vent:has(#integ-editor) .fv-caja { width: min(820px, 100%); }
/* Los botones del pie van en fila, no como barras apiladas de ancho completo. */
#fv-cuerpo > #integ-editor > div[style*="flex-wrap"] button { width: auto !important; }
#admin #form-informe, #admin #form-envio { display: none; }
#admin #form-sensor { display: none; }
/* El editor de sensores es largo (plantilla, tipo, origen, bits, calibración):
   con el ancho de una columna estrecha no cabía nada. */
#form-vent:has(#form-sensor) .fv-caja { width: min(760px, 100%); }

/* Sensores: los grupos a la izquierda, sus sensores a la derecha. Va con clase
   propia porque `.grid2` no tiene ninguna regla —se usa en seis sitios y no hace
   nada—, y darle estilo cambiaría de golpe otras cinco pantallas. */
.sen-2col {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--e3); align-items: start;
}
.sen-2col > * { min-width: 0; margin: 0; }
@media (max-width: 1100px) { .sen-2col { grid-template-columns: 1fr; } }
/* Veintidós grupos son mil quinientos píxeles de alto: la segunda columna
   quedaba fuera de la pantalla y había que rodar para saber que existía. */
#sg-lista, #sl-lista { max-height: 420px; overflow: auto; }
/* El observador engancha un buscador a los <select> largos. Dentro de la ventana
   sale con su propia etiqueta "Buscar" en medio del formulario, partiendo la
   pareja etiqueta–campo. Un <select> nativo ya busca al teclear. */
#fv-cuerpo .busca-caja { display: none !important; }

/* ===== 11l · ADMINISTRACIÓN EN COLUMNA =====
   Diecinueve pestañas en fila no caben en ningún monitor: se cortaban "Sistema"
   e "Iconos", y ya se habían escondido cuatro tras "Técnico" sin que bastara.
   En columna la etiqueta larga no compite por espacio y el panel puede crecer.
   No cambia ninguna ruta: showAdmin() y #admin/<tab> siguen igual. */
#admin {
  display: grid; grid-template-columns: 190px minmax(0, 1fr);
  gap: var(--e4); align-items: start;
}
/* Los dos modales de crédito son `position: fixed`: fuera del flujo, no ocupan
   celda. El resto de pestañas comparte la segunda columna; solo una se ve. */
#admin > .atab { grid-column: 2; }

#admin > .subnav {
  flex-direction: column; gap: 0; margin: 0;
  position: sticky; top: 0;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r); padding: 6px;
  /* Dieciséis entradas más los rótulos pasan del alto de un portátil: el menú
     rueda por dentro en vez de empujar el contenido. */
  max-height: calc(100vh - 36px); overflow-y: auto;
}
#admin > .subnav button {
  width: 100%; text-align: left; padding: 6px 10px;
  font-size: 12.5px; line-height: 1.35; border-radius: var(--r-sm); background: none;
}
#admin > .subnav button:hover { background: var(--hover); color: var(--txt); }
/* La pestaña abierta se marca con fondo, no con el subrayado de la barra: en
   columna un `inset 0 -2px` queda debajo del texto y no se lee como selección. */
#admin > .subnav button.act {
  background: var(--acc2); color: #fff; box-shadow: none;
}
#admin > .subnav button.act:hover { background: var(--acc2); color: #fff; }

/* Rótulos de sección: dicen dónde buscar, no se pulsan. */
#admin > .subnav .sn-sec {
  font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--mut); padding: 9px 10px 2px;
}
#admin > .subnav .sn-sec:first-child { padding-top: 4px; }

#nav-tecnico {
  margin-top: 6px; border-top: 1px solid var(--line) !important;
  border-radius: 0 !important; padding-top: 9px !important;
}
#nav-tecnico::before { content: "▸ "; }
#admin > .subnav.tec-abierto #nav-tecnico::before { content: "▾ "; }
#admin > .subnav.tec-abierto .tec-item.permitido { display: block; }
#nav-tecnico.act { box-shadow: none; }

/* En pantalla estrecha no hay ancho que ceder: vuelve a ser una fila que rueda,
   igual que antes. */
@media (max-width: 900px) {
  #admin { display: block; }
  #admin > .subnav {
    flex-direction: row; position: static; padding: 0; border: 0;
    background: none; gap: 6px; margin-bottom: 8px;
  }
  #admin > .subnav button { width: auto; }
  #admin > .subnav .sn-sec { display: none; }
  #nav-tecnico { margin-top: 0; border-top: 0 !important; padding-top: 9px !important; }
}

/* Comandos: seis columnas cortas repartidas a mano. Sin anchos, las cuatro
   primeras se apelotonaban a la izquierda y las acciones quedaban a mil
   píxeles, con un desierto en medio. La descripción se lleva el sobrante. */
.cc-tabla { table-layout: fixed; width: 100%; }
.cc-tabla th:nth-child(1), .cc-tabla td:nth-child(1) { width: auto; }
.cc-tabla th:nth-child(2), .cc-tabla td:nth-child(2) { width: 110px; }
.cc-tabla th:nth-child(3), .cc-tabla td:nth-child(3) { width: 160px; }
.cc-tabla th:nth-child(4), .cc-tabla td:nth-child(4) { width: 180px; }
.cc-tabla th:nth-child(5), .cc-tabla td:nth-child(5) { width: 150px; }
.cc-tabla th:nth-child(6), .cc-tabla td:nth-child(6) { width: 96px; text-align: right; }
.cc-tabla code { word-break: break-all; }
.ig-tabla { table-layout: fixed; width: 100%; }
.ig-tabla th:nth-child(1), .ig-tabla td:nth-child(1) { width: auto; }
.ig-tabla th:nth-child(2), .ig-tabla td:nth-child(2) { width: 110px; }
.ig-tabla th:nth-child(3), .ig-tabla td:nth-child(3) { width: 90px; }
.ig-tabla th:nth-child(4), .ig-tabla td:nth-child(4) { width: 130px; }
.ig-tabla th:nth-child(5), .ig-tabla td:nth-child(5) { width: 80px; }
.ig-tabla th:nth-child(6), .ig-tabla td:nth-child(6) { width: 120px; }
.ig-tabla th:nth-child(7), .ig-tabla td:nth-child(7) { width: 60px; }
.ig-tabla td:nth-child(1) span { word-break: break-all; }

/* Informes: encendidos y apagados separados. Antes iban mezclados y lo único
   que distinguía a un apagado era medio punto de opacidad en el nombre. */
#ri-lista .ri-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 10px; border-radius: var(--r-sm); cursor: pointer;
  font-weight: 400; margin: 0;
}
#ri-lista .ri-item:hover { background: var(--fila-hover); }
#ri-lista .ri-item input { width: 15px; height: 15px; margin-top: 3px; flex: 0 0 auto; }
#ri-lista .ri-txt { flex: 1; min-width: 0; font-size: 12.5px; }
#ri-lista .ri-acc { flex: 0 0 auto; white-space: nowrap; }
#ri-lista .ri-grupo.apagado .ri-txt b { color: var(--mut); font-weight: 400; }
#ri-lista .ri-sep {
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--mut); margin: 14px 0 4px; padding-top: 10px;
  border-top: 1px solid var(--line);
}
#ri-lista .ri-sep .k { text-transform: none; letter-spacing: 0; }

/* Sensores: el grupo abierto se marcaba con un azul translúcido en línea que en
   modo oscuro casi no se veía. Y las cifras iban en texto gris corrido. */
#sg-lista .sg-item {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 8px 10px; border-radius: var(--r-sm);
  border-left: 3px solid transparent;
}
#sg-lista .sg-item:hover { background: var(--fila-hover); }
#sg-lista .sg-item.sel { background: var(--fila-hover); border-left-color: var(--acc2); }
#sg-lista .sg-txt { flex: 1; min-width: 0; cursor: pointer; font-size: 12.5px; line-height: 1.5; }
#sg-lista .sg-acc { flex: 0 0 auto; white-space: nowrap; }

/* Reglas de alerta: una sola vista. Los dos formularios —regla y evento— vivían
   fijos al lado de sus tablas; ahora se abren en ventana como los demás. */
#admin #form-regla, #admin #form-evento { display: none; }
#form-vent:has(#form-evento) .fv-caja { width: min(720px, 100%); }
/* Las secciones de la pestaña se separan entre sí, que ya no las divide nada. */
#atab-rules > #rulv-reglas > .card { margin-top: 14px; }

/* Reglas y eventos en una sola lista y un solo formulario. */
#admin #form-rul { display: none; }
#form-vent:has(#form-rul) .fv-caja { width: min(760px, 100%); }
#ru-bloque-evento { display: none; }
.rul-tabla { table-layout: fixed; width: 100%; }
.rul-tabla th:nth-child(1), .rul-tabla td:nth-child(1) { width: auto; }
.rul-tabla th:nth-child(2), .rul-tabla td:nth-child(2) { width: 118px; }
.rul-tabla th:nth-child(3), .rul-tabla td:nth-child(3) { width: 220px; }
.rul-tabla th:nth-child(4), .rul-tabla td:nth-child(4) { width: 190px; }
.rul-tabla th:nth-child(5), .rul-tabla td:nth-child(5) { width: 120px; }
.rul-tabla th:nth-child(6), .rul-tabla td:nth-child(6) { width: 110px; }
.rul-tabla th:nth-child(7), .rul-tabla td:nth-child(7) { width: 96px; text-align: right; }
.rul-tabla td:nth-child(4) .pill { margin: 1px 2px 1px 0; }
/* El bloque de cada tipo, dentro de la ventana, no vuelve a enmarcarse. */
#fv-cuerpo #ru-bloque-regla, #fv-cuerpo #ru-bloque-evento { border: 0; padding: 0; }

/* Las condiciones, dentro de la ventana. El observador engancha un buscador al
   <input list="ev-taglist"> y ese intruso, sin `flex`, se comía el reparto: los
   tres campos quedaban en veinte píxeles y el botón de borrar en una barra. */
#ev-conds .busca-caja, #ev-conds .campo > .winp { display: none !important; }
#ev-conds .ev-cond { display: flex !important; gap: 6px; align-items: center; margin-bottom: 6px; }
#ev-conds .ev-c-tag { flex: 1 1 30% !important; width: auto !important; min-width: 0; margin: 0; }
#ev-conds .ev-c-op  { flex: 1 1 34% !important; width: auto !important; min-width: 0; margin: 0; }
#ev-conds .ev-c-val { flex: 1 1 30% !important; width: auto !important; min-width: 0; margin: 0; }
#ev-conds .ev-cond > button { flex: 0 0 auto !important; width: auto !important; padding: 6px 9px; }

/* Dentro de la ventana, un botón secundario no es una barra de ancho completo:
   "+ Añadir condición" y "Probar" son acciones menores, no la principal. */
#fv-cuerpo #form-rul button.btn-sm { width: auto !important; }
#fv-cuerpo #form-rul .acciones button { padding: 8px 18px; }
#fv-cuerpo #form-rul .sec:first-child { margin-top: 0; }
/* El probador va en una línea: campo ancho, botón al lado. */
#form-rul #ev-probar-no { flex: 1 1 auto; min-width: 0; }
/* Una sola acción principal por ventana: Cancelar no puede ir del mismo azul. */
.btn-sm.secundario, .btn-sm.secundario:hover {
  background: var(--card); color: var(--mut); border: 1px solid var(--line);
}
.btn-sm.secundario:hover { color: var(--txt); background: var(--hover); }

/* Las etiquetas que manda el equipo, a la vista. El <datalist> las escondía: no
   se sabía que existían treinta y siete, y Chrome no despliega nada cuando lo
   escrito ya coincide entero. */
.ev-tags-caja {
  background: var(--fond); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 9px 10px; margin: 8px 0 4px;
}
.ev-tags-tit {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  font-size: 11.5px; color: var(--mut); margin-bottom: 7px;
}
.ev-tags-tit input { width: 130px !important; margin: 0; padding: 5px 8px; font-size: 12px; }
#ev-tags { display: flex; flex-wrap: wrap; gap: 5px; max-height: 132px; overflow-y: auto; }
#ev-tags button.ev-tag {
  width: auto !important; padding: 4px 9px; font-size: 11.5px;
  font-family: ui-monospace, monospace;
  background: var(--card) !important; color: var(--txt) !important;
  border: 1px solid var(--line); border-radius: var(--r-full); cursor: pointer;
  font-weight: 400;
}
#ev-tags button.ev-tag:hover {
  border-color: var(--acc2); color: var(--acc) !important;
  background: var(--card) !important; filter: none;
}
/* Con 258 protocolos, el filtro y el contador de marcados no son adorno. */
.ev-p-tit { display: flex; justify-content: space-between; align-items: baseline;
  font-size: 11.5px; font-weight: 500; color: var(--mut); margin: var(--e3) 0 var(--e1); }
#ev-puerto-q { margin-bottom: 5px !important; }
#ev-puerto optgroup { font-style: normal; font-weight: 500; color: var(--mut); }
#ev-puerto option { padding: 3px 6px; color: var(--txt); }

/* Condiciones de una regla: mismo reparto que las de trama cruda. */
#rl-conds .rl-cond { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
#rl-conds .rl-c-var { flex: 1 1 34% !important; width: auto !important; min-width: 0; margin: 0; }
#rl-conds .rl-c-op  { flex: 1 1 32% !important; width: auto !important; min-width: 0; margin: 0; }
#rl-conds .rl-c-val, #rl-conds .rl-c-val2 { flex: 1 1 22% !important; width: auto !important; min-width: 0; margin: 0; }
#rl-conds .rl-c-del { flex: 0 0 auto !important; width: auto !important; padding: 6px 9px;
  background: var(--no-bg) !important; color: var(--no-tx) !important; }
#rl-conds .busca-caja { display: none !important; }
/* Cuantas veces se ha visto la etiqueta: separa la que llega siempre de la que
   aparecio seis veces en un mes, que suele ser justo la que hay que nombrar. */
#ev-tags .ev-tag-n { margin-left: 5px; font-size: 10px; color: var(--mut); }
#ev-tags button.ev-tag.fija { border-style: dashed; }

/* ============================================================
   12 · TELÉFONO — SEGUNDA PASADA (operar todo desde el celular)
   ============================================================
   La primera pasada (bloque TELEFONO de index.html) arregló blancos de toque,
   tablas-tarjeta y ventanas como hoja inferior. Esta cubre lo que faltaba:

   1. El menú lateral se vuelve BARRA INFERIOR: en 375 px, la columna de 56
      robaba el 15% del ancho y quedaba lejos del pulgar. Abajo, el contenido
      recupera todo el ancho y las pestañas quedan donde llega el dedo.
   2. Geocercas NO TENÍA ninguna regla móvil: el panel de 340 px dejaba 35 px
      de mapa. Ahora mapa arriba, panel abajo, como Monitoreo.
   3. Historial: la fila del medio (mapa + resumen de 240 px + clips de 300 px)
      se apila en columna; los laterales fijos se comían el mapa entero.
   4. El formulario en ventana (#form-vent) pasa a hoja inferior, como ya
      hacían los demás modales.
   5. Los paneles flotantes de Monitoreo (herramientas) dejan de abrirse en
      x=222 con 330 px de ancho: se anclan a los bordes.
   Va aquí y no en index.html porque esta hoja carga última y a igual
   especificidad gana; varias de estas reglas corrigen a las secciones 11x. */

@media (max-width: 760px) {

  /* ---- 12a. BARRA DE NAVEGACIÓN ABAJO ---- */
  /* html:has(#leftnav.mini) vale (1,1,1) y le ganaba al :root de aquí: si el
     usuario dejó el menú contraído en escritorio, --nav-w volvía a 56. */
  :root, html:has(#leftnav.mini) { --nav-w: 0px; }
  #app { flex-direction: column; }
  #body { min-height: 0; }
  #leftnav, #leftnav.mini {
    order: 2; width: 100%; flex: 0 0 auto;
    flex-direction: row; align-items: stretch;
    border-right: 0; border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  #leftnav .ln-logo, #ln-version, .ln-toggle, #leftnav .ln-txt { display: none; }
  #leftnav nav {
    flex-direction: row; flex: 1 1 auto; min-width: 0;
    overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding: 4px 6px; gap: 2px;
  }
  #leftnav nav::-webkit-scrollbar { display: none; }
  #leftnav nav button {
    flex: 1 0 auto; min-width: 48px; min-height: 46px;
    justify-content: center; padding: 0;
  }
  #leftnav nav button i { font-size: 20px; width: auto; }
  #leftnav .ln-foot {
    display: flex; align-items: center; gap: 2px;
    border-top: 0; border-left: 1px solid var(--line); padding: 4px 6px;
  }
  /* El width:100% en línea de "Mi vendedor" aplastaría a los demás en la fila.
     Solo hijos directos: el botón de "Volver a mi cuenta" vive DENTRO de
     #imp-barra y necesita su relleno propio. */
  #leftnav .ln-foot > button, #leftnav .ln-user {
    width: auto !important; flex: 0 0 auto;
    min-width: 44px; min-height: 46px; justify-content: center;
    padding: 0 !important;
  }
  /* El aviso de sesión prestada flota ENCIMA de la barra: dentro de la fila
     sería una tira ilegible de veinte píxeles. */
  #leftnav #imp-barra {
    position: absolute; bottom: 100%; left: 8px; right: 8px;
    margin-bottom: 6px; z-index: 1300;
  }

  /* ---- 12b. GEOCERCAS: MAPA ARRIBA, PANEL ABAJO ---- */
  /* El mapa se lleva el 58%: es donde se DIBUJA la geocerca, que es a lo que
     se viene. La lista y el formulario ruedan por dentro en su 42%. */
  #gmap { right: 0; bottom: 42%; }
  #gpanel {
    width: auto; left: 0; top: 58%;
    border-left: 0; border-top: 2px solid var(--line);
  }

  /* ---- 12c. HISTORIAL EN COLUMNA ---- */
  #h-medio { flex-direction: column; }
  #hmap { min-height: 170px; }
  /* Los laterales llevan su ancho en línea: sin !important no hay quien gane. */
  #h-summary {
    width: auto !important; flex: 0 0 auto; max-height: 128px;
    border-left: 0 !important; border-top: 1px solid var(--line);
  }
  #h-sd-side {
    width: auto !important; flex: 0 0 auto; max-height: 40%;
    border-left: 0 !important; border-top: 1px solid var(--line);
  }
  /* La barra de consulta: cada campo a media fila, sin mínimos de escritorio. */
  #h-barra > div { flex: 1 1 46%; min-width: 0; }
  #h-barra .winp { width: 100%; min-width: 0 !important; }
  #h-barra > button { flex: 1 1 auto; }
  #h-playbar { flex-wrap: wrap; }
  /* La franja de Registro/Viajes/Clips: al 42% dejaba el mapa en 170 px,
     porque la barra de consulta ya se lleva 200 arriba. */
  #view-historial > div > div:last-child { height: 34% !important; min-height: 150px !important; }

  /* ---- 12d. MONITOREO: PANELES FLOTANTES A LOS BORDES ---- */
  #tool-panel {
    left: 10px !important; right: 10px !important; width: auto !important;
    top: 10px !important; max-height: calc(50% - 20px) !important;
  }
  #tools-menu {
    max-height: calc(50% - 70px) !important; overflow: auto !important;
  }

  /* ---- 12e. VENTANA DE FORMULARIO COMO HOJA INFERIOR ---- */
  /* Centrada, los botones de guardar caían bajo la barra del navegador. */
  #form-vent { align-items: flex-end; padding: 0; }
  #form-vent .fv-caja {
    width: 100% !important; max-width: none;
    max-height: 94vh; max-height: 94dvh;
    border-radius: 16px 16px 0 0;
  }
  #form-vent #fv-cuerpo { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }

  /* ---- 12f. RELLENOS: 18 px de marco no caben en 375 ---- */
  #admin { padding: 10px; }
  #alerts-wrap, #billing-wrap { padding: 10px !important; }
  #mpanel { padding: 8px; }
  .card, .form { padding: var(--e3); }

  /* ---- 12g. FORMULARIOS Y REJILLAS A UNA COLUMNA ---- */
  .form.form-2col { grid-template-columns: 1fr; }
  #al-filtergeos { grid-template-columns: 1fr !important; }
  .kpis { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }

  /* ---- 12h. TABLAS: lo que la tarjeta-móvil no cubría ---- */
  /* Las de columnas fijas (Comandos, Integraciones, Reglas) conservaban sus
     anchos de 110-220 px dentro de la tarjeta y partían cada renglón. */
  table.tabla-movil th, table.tabla-movil td {
    width: auto !important; max-width: none;
  }
  /* #admin td lleva nowrap por identificador: en la tarjeta parte el layout. */
  #admin table.tabla-movil td { white-space: normal; max-width: none; }
  /* La matriz de permisos se queda de tabla (sticky), pero su columna fija de
     220 px dejaba 100 px para las casillas: se estrecha y el rótulo parte. */
  #pm-tabla th.pm-h-perm, #pm-tabla td.pm-perm, #pm-tabla tr.pm-mod > td:first-child {
    min-width: 132px; max-width: 150px; white-space: normal;
  }

  /* ---- 12i. CONDICIONES DE REGLAS: QUE ENVUELVAN ---- */
  /* Tres selectores en una fila de 340 px quedaban de 90 px cada uno. */
  #ev-conds .ev-cond, #rl-conds .rl-cond { flex-wrap: wrap; }
  #ev-conds .ev-c-tag, #ev-conds .ev-c-op { flex: 1 1 44% !important; }
  #ev-conds .ev-c-val { flex: 1 1 70% !important; }
  #rl-conds .rl-c-var, #rl-conds .rl-c-op { flex: 1 1 44% !important; }
  #rl-conds .rl-c-val, #rl-conds .rl-c-val2 { flex: 1 1 30% !important; }

  /* ---- 12j. BARRAS DE HERRAMIENTAS DE OBJETOS/INVENTARIO ---- */
  #atab-devices .busca-caja > .campo,
  #mbv-inventario .busca-caja > .campo { flex: 1 1 100%; }
  #mbv-inventario .busca-caja > select.mb-ctl:first-of-type { margin-left: 0; }
  #atab-membresias .mb-nivel-edit .campo { flex: 1 1 46%; }
  #atab-membresias .mb-nivel-edit .campo input { width: 100%; }
  #atab-membresias .mb-equiv { margin-left: 0; flex: 1 1 100%; }

  /* ---- 12k. TECLEAR SIN QUE EL iPHONE HAGA ZOOM ---- */
  /* Safari amplía la página entera al tocar un campo con letra menor de 16 px,
     y luego no vuelve solo. Los clientes finales entran desde iPhone. */
  input[type=text], input[type=password], input[type=email], input[type=number],
  input[type=search], input[type=date], input[type=time], input[type=datetime-local],
  select:not([multiple]), textarea { font-size: 16px !important; }

  /* ---- 12l. MONITOREO EN EL TELÉFONO: LA HOJA ----
     (Los botones flotantes y las pastillas son comunes a escritorio y celular
     y viven en la sección 13.) Estados en #view-monitoring: hoja-oculta (solo
     mapa) · hoja-lista (buscador + lista) · hoja-ficha (solo la ficha) ·
     hoja-llena (ficha alta). */

  /* La hoja: tarjeta flotante con aire a los lados, como FichaMapa. */
  #view-monitoring #mpanel {
    top: auto; left: 10px; right: 10px; bottom: 10px; width: auto;
    height: auto; max-height: 56%;
    background: var(--card); border: 1px solid var(--line);
    border-radius: 16px; box-shadow: 0 8px 28px var(--sombra);
    z-index: 1250; padding: 2px 10px 8px;
  }
  /* Doble id a propósito: la regla que la esconde en escritorio va al final de
     la hoja y a igual especificidad ganaría también aquí. */
  #view-monitoring #mpanel .hoja-asa {
    flex: 0 0 auto; display: flex; flex-direction: column; align-items: center;
    padding: 4px 0 2px; cursor: pointer; touch-action: none; gap: 1px;
  }
  #view-monitoring #mpanel .hoja-asa span {
    width: 40px; height: 4px; border-radius: 999px; background: var(--line);
  }
  #view-monitoring #mpanel .hoja-asa i {
    font-style: normal; color: var(--mut); font-size: 14px; line-height: 12px; font-weight: 700;
  }
  /* Oculta = se esconde el CONTENIDO, no el panel: la tarjeta de cámara
     (#cam-card) vive dentro y es position:fixed — con display:none en el
     ancestro desaparecía también, y en el teléfono no había video. */
  #view-monitoring.hoja-oculta #mpanel {
    background: transparent; border: 0; box-shadow: none;
    padding: 0; height: auto; pointer-events: none;
  }
  #view-monitoring.hoja-oculta #mpanel > *:not(#cam-card) { display: none; }
  #view-monitoring.hoja-oculta #cam-card { pointer-events: auto; }
  /* Lista: buscador + vehículos (+ alertas). La ficha no. */
  #view-monitoring.hoja-lista #panel-bottom { display: none; }
  /* Ficha: SOLO el vehículo elegido, como la tarjeta de la app. */
  #view-monitoring.hoja-ficha #mpanel { max-height: 46%; }
  #view-monitoring.hoja-ficha #veh-search,
  #view-monitoring.hoja-ficha #veh-list,
  #view-monitoring.hoja-ficha #alertas-panel { display: none; }
  #view-monitoring.hoja-ficha #panel-bottom,
  #view-monitoring.hoja-llena #panel-bottom {
    border-top: 0; padding-top: 0; max-height: none; flex: 1 1 auto; overflow-y: auto;
  }
  #view-monitoring.hoja-llena #mpanel { max-height: calc(100% - 20px); }
  #view-monitoring.hoja-llena #veh-search,
  #view-monitoring.hoja-llena #veh-list,
  #view-monitoring.hoja-llena #alertas-panel { display: none; }
  /* Los avisos flotantes bajan un poco y dejan libre la esquina de los
     botones (#avisos es hijo de <body>, no de la vista). */
  body:has(#view-monitoring.act) #avisos { top: 66px; right: 68px; }

  /* ---- 12m. ADMINISTRACIÓN COMO MENÚ DE LISTA ---- */
  /* En 375 px la fila de pestañas no cabe ni deslizando con gracia. En el
     celular: primero un MENÚ vertical con todos los módulos; al tocar uno se
     abre a pantalla completa con su barra de volver (la pone movilInit). */
  #admin.mv-menu > .subnav {
    display: flex; flex-direction: column; position: static;
    border: 0; background: none; overflow: visible;
    margin: 0; padding: 0; gap: 0; max-height: none;
  }
  #admin.mv-menu > .subnav button {
    width: 100%; text-align: left; flex: 0 0 auto;
    padding: 13px 14px; min-height: 48px; font-size: 14px;
    background: var(--card); border: 0; border-bottom: 1px solid var(--line);
    border-radius: 0; color: var(--txt); white-space: normal;
  }
  #admin.mv-menu > .subnav button::after { content: '›'; float: right; color: var(--mut); font-size: 16px; }
  #admin.mv-menu > .subnav button.act { background: var(--card); color: var(--txt); box-shadow: none; }
  #admin.mv-menu > .subnav .sn-sec { display: block; padding: 16px 12px 6px; }
  /* El grupo Técnico sigue plegable, pero como fila del menú. */
  #admin.mv-menu #nav-tecnico { margin-top: 0; border-top: 0 !important; padding-top: 13px !important; border-radius: 0 !important; }
  /* Menú a la vista = ningún módulo a la vista, y al revés. */
  #admin.mv-menu > .atab { display: none !important; }
  #admin.mv-menu.mv-abierto > .atab.act { display: block !important; }
  #admin.mv-menu.mv-abierto > .subnav { display: none; }
  #admin.mv-abierto #mv-volver {
    display: flex; align-items: center; gap: 10px;
    position: sticky; top: -10px; z-index: 60;
    background: var(--bg); padding: 10px 0;
    margin: -10px 0 8px; border-bottom: 1px solid var(--line);
  }
  #mv-volver button { flex: 0 0 auto; }
  #mv-volver b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* ---- 12n. PROPORCIONES: EL DATO MANDA, EL ADORNO CEDE ----
     En cada módulo de datos lo que se viene a mirar es LA TABLA o LA LISTA.
     Los KPIs y los filtros son contexto: útiles, pero en un celular no pueden
     quedarse con la mitad del alto antes de que empiece el contenido. */

  /* KPIs: de rejilla (2-3 filas apiladas) a UNA tira que se desliza de lado.
     Cuatro tarjetas medían ~200 px de alto; ahora son 64. */
  .kpis {
    display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; gap: var(--e2); padding-bottom: 2px;
  }
  .kpis::-webkit-scrollbar { display: none; }
  .kpi { flex: 0 0 128px; }
  .kpi-num { font-size: 20px; }

  /* Filtros: dos columnas compactas. La rejilla de 180 px dejaba UNA columna
     y cada filtro era una franja; a dos columnas el bloque mide la mitad. */
  .filtros {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--e2); padding: var(--e2);
  }
  .filtros .campo:has(> button) { grid-column: auto; }
  .filtros .cuenta { grid-column: 1 / -1; }

  /* Tarjetas más pegadas: el aire entre tarjetas no informa nada. */
  .card { margin-bottom: var(--e2); }

  /* La ficha del vehículo se lee A LA DISTANCIA DEL DEDO: los 10.5 px de
     escritorio en el teléfono son ilegibles. Es el contenido principal de la
     hoja: letra de verdad. */
  .drow { font-size: 12px; padding: 3.5px 0; }
  .tile .tv { font-size: 14px; }
  .tile .tl { font-size: 9.5px; }
  .st-pill { font-size: 10px; }
  #dev-detail .dh b { font-size: 13px; }
  #alertas-lista .al-item { font-size: 12px; }
  #alertas-lista .al-item .meta { font-size: 10.5px; }

  /* El registro de datos del recorrido: 9.5 px era letra de lupa. */
  #day-grid table, #h-grid table { font-size: 11px; }
  #day-grid td { padding: 2px 6px; }

  /* Historial: la barra de consulta se usa UNA vez por consulta; el mapa y los
     datos se miran todo el tiempo. Tras consultar se pliega sola (lo hace
     movilInit) y queda el botón para reabrirla. */
  /* Doble id: la regla que lo esconde en escritorio va al final de la hoja. */
  #h-barra #h-plegar { display: inline-flex; flex: 1 1 100% !important; min-height: 40px; align-items: center; justify-content: center; }
  #h-barra.h-plegada { padding: 6px 10px; }
  #h-barra.h-plegada > * { display: none !important; }
  #h-barra.h-plegada > #h-plegar { display: inline-flex !important; flex: 1 1 auto !important; }
  #h-barra.h-plegada > #h-status { display: inline !important; }

  /* ---- 12o. HISTORIAL CON EL DISEÑO DE LA APP ----
     Copiado de src/pantallas/Historial.js: arriba una tira de pastillas con
     los últimos días —del más viejo a Hoy, que el presente va al final— y el
     chip 📅 Rango que abre la consulta completa. El resumen deja de ser una
     lista de renglones y pasa a las métricas de la app: el valor en negrita
     arriba y la etiqueta chiquita debajo, cuatro por fila. */
  #view-historial #h-dias {
    display: flex; gap: 6px; overflow-x: auto; flex: 0 0 auto;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    padding: 7px 10px; background: var(--bg2); border-bottom: 1px solid var(--line);
  }
  #view-historial #h-dias::-webkit-scrollbar { display: none; }
  #view-historial #h-dias button {
    flex: 0 0 auto; min-height: 34px; padding: 0 13px;
    background: var(--card); border: 1px solid var(--line); color: var(--txt);
    border-radius: 999px; font-size: 12px; font-weight: 600;
  }
  #view-historial #h-dias button.act { background: var(--acc2); border-color: var(--acc); color: #fff; }
  #view-historial #h-dias button.cal { border-color: var(--acc); }

  /* La columna de objetos trae su display:flex EN LÍNEA: la regla vieja de
     index.html sin !important nunca pudo esconderla de verdad. */
  #view-historial #h-flota-wrap { display: none !important; }
  /* El resumen sale sobrando en el teléfono (Ronald, 2026-08-09): la mitad de
     sus casillas llegaban en "—" y el bloque entero le robaba el alto al mapa
     y al registro. En escritorio sigue. */
  #view-historial #h-summary { display: none !important; }
  #view-historial #h-summary h3 { display: none; }
  #view-historial #h-summary .row {
    width: 25%; border-bottom: 0; padding: 2px 4px 2px 0;
    display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: 0;
  }
  #view-historial #h-summary .row b { font-size: 11.5px; line-height: 1.25; }
  #view-historial #h-summary .row .k {
    font-size: 8.5px; line-height: 1.2; letter-spacing: .04em; text-transform: uppercase;
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  }
  /* Inicio y Fin traen fecha y hora completas: a un cuarto no caben. */
  #view-historial #h-summary .row:nth-child(6),
  #view-historial #h-summary .row:nth-child(7) { width: 50%; }

  /* La consulta abierta, ordenada: el dispositivo a lo ancho (compartía fila
     con las fechas y quedaba desfasado), y las dos cajas de fecha se van — en
     el teléfono el rango se elige en UN calendario, como en la app. */
  #view-historial #h-barra { align-items: stretch !important; }
  #h-barra > .busca-no { flex: 1 1 100%; }
  #h-barra > div:has(> #h-from), #h-barra > div:has(> #h-to) { display: none; }
  #h-barra #h-cal-abrir {
    display: inline-flex; align-items: center; justify-content: center;
    flex: 1 1 46%; min-height: 42px;
  }
  /* Antes de la primera consulta, ni el resumen vacío ni las pestañas sin
     datos aportan nada: el mapa se queda con todo el alto. */
  #view-historial:not(.h-con-datos) > div > div:last-child { display: none !important; }
  #view-historial:not(.h-con-datos) #h-summary { display: none !important; }
  /* Cada registro del historial, como una tabla de verdad y no como 22
     renglones sueltos: dos columnas parejas de filas ETIQUETA→valor, cada
     fila con su línea, la etiqueta gris a la izquierda y el valor en negrita
     pegado a la derecha. La rejilla alinea las dos columnas entre sí, que era
     lo que el reparto suelto no lograba. Las casillas vacías ya las esconde
     el observador (clase "vacia"). */
  #h-grid table.tabla-movil tr, #day-grid table.tabla-movil tr {
    display: grid; grid-template-columns: 1fr 1fr;
    column-gap: 16px; align-items: stretch; padding: 6px 12px 8px;
  }
  #h-grid table.tabla-movil td, #day-grid table.tabla-movil td {
    width: auto !important; display: flex; flex-wrap: nowrap;
    justify-content: space-between; align-items: baseline; gap: 8px;
    border: 0; border-bottom: 1px solid var(--line);
    padding: 5.5px 0; font-size: 12.5px; font-weight: 600;
    min-width: 0;
  }
  #h-grid table.tabla-movil td::before, #day-grid table.tabla-movil td::before {
    flex: 0 0 auto; font-size: 9px; font-weight: 500; letter-spacing: .04em;
    text-transform: uppercase; color: var(--mut);
  }
  /* El valor, pegado a la derecha y sin desbordar la celda. */
  #h-grid table.tabla-movil td, #day-grid table.tabla-movil td { text-align: right; }
  #h-grid table.tabla-movil td > *, #day-grid table.tabla-movil td > * { min-width: 0; overflow-wrap: anywhere; }
  /* La hora del equipo encabeza la tarjeta, a lo ancho y en color de acento. */
  #h-grid table.tabla-movil td:first-child, #day-grid table.tabla-movil td:first-child {
    grid-column: 1 / -1; font-size: 13px; color: var(--acc);
    justify-content: flex-start; border-bottom: 1px solid var(--line);
  }

  /* Los módulos de Administración (Usuarios, Objetos, Inventario…): las
     tarjetas con la MISMA tabla estructurada del historial — dos columnas
     parejas de filas etiqueta→valor con su línea. */
  #admin table.tabla-movil tr {
    display: grid; grid-template-columns: 1fr 1fr;
    column-gap: 16px; padding: 6px 12px 8px; position: relative;
  }
  #admin table.tabla-movil td {
    width: auto !important; display: flex;
    justify-content: space-between; align-items: baseline; gap: 8px;
    border: 0; border-bottom: 1px solid var(--line);
    padding: 5.5px 0; font-size: 12.5px; font-weight: 600;
    min-width: 0; text-align: right;
  }
  #admin table.tabla-movil td::before {
    flex: 0 0 auto; font-size: 9px; font-weight: 500; letter-spacing: .04em;
    text-transform: uppercase; color: var(--mut); text-align: left;
  }
  #admin table.tabla-movil td > * { min-width: 0; overflow-wrap: anywhere; }
  /* La primera columna con rótulo encabeza la tarjeta, a lo ancho y en acento. */
  #admin table.tabla-movil td:first-child:not([data-etq=""]),
  #admin #users-tb td:nth-child(2) {
    grid-column: 1 / -1; font-size: 13px; color: var(--acc);
    justify-content: flex-start; text-align: left;
  }
  /* Los botones van al pie, en su propia franja sin línea. */
  #admin table.tabla-movil td.acciones {
    grid-column: 1 / -1; justify-content: flex-start; flex-wrap: wrap;
    border-bottom: 0; padding-top: 8px; gap: 6px; text-align: left;
  }
  /* La casilla de selección (celda sin rótulo) flota arriba a la derecha. */
  #admin table.tabla-movil td[data-etq=""]:first-child {
    position: absolute; top: 9px; right: 12px;
    border: 0; padding: 0; grid-column: auto;
  }

  /* El buscador que el observador le engancha a tablas y selectores largos:
     en el teléfono roba una franja entera cada vez que aparece, y aparece en
     cualquier lista de más de ocho filas. Fuera TODOS en el celular; en
     escritorio siguen estando, que ahí sí filtran mil filas con el teclado. */
  .busca-caja { display: none !important; }
  /* MENOS las de Objetos e Inventario: ahí la caja ES la barra de herramientas
     — juntarBarraObjetos y mbJuntarBarra le meten los botones dentro — y
     esconderla se llevaría las acciones enteras del módulo. */
  #atab-devices .busca-caja, #mbv-inventario .busca-caja { display: flex !important; }
}

/* ---- El calendario de rango del Historial, copiado de RangoFechas de la app:
   se toca la fecha de inicio y luego la de fin, el tramo queda pintado de azul
   y el futuro no se puede tocar. Vive fuera de la consulta de medios porque lo
   crea app.js al vuelo, pero solo el teléfono lo abre. ---- */
#h-cal { position: fixed; inset: 0; z-index: 6000; display: none; align-items: center; justify-content: center; padding: 16px; }
#h-cal .hc-velo { position: absolute; inset: 0; background: rgba(0,0,0,.6); }
#h-cal .hc-caja {
  position: relative; width: min(452px, 100%);
  background: var(--bg2); border: 1px solid var(--line);
  border-radius: 16px; padding: 12px;
}
/* Dos columnas: el calendario a la izquierda y las HORAS a la derecha. En
   pantallas angostas la de horas baja debajo del calendario. */
#h-cal .hc-cuerpo { display: flex; gap: 12px; flex-wrap: wrap; }
#h-cal .hc-fechas { flex: 1 1 260px; min-width: 0; }
/* El <input type=time> trae un ancho mínimo propio de ~130px que empujaba la
   columna a la fila de abajo: se fija la base y se anula el mínimo. */
#h-cal .hc-horas {
  flex: 0 0 128px; min-width: 0; display: flex; flex-direction: column; gap: 10px;
  justify-content: center; border-left: 1px solid var(--line); padding-left: 12px;
}
#h-cal .hc-horas input { min-width: 0; }
#h-cal .hc-horas label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 10px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--mut);
}
#h-cal .hc-horas input {
  border: 1px solid var(--line); border-radius: 8px; padding: 8px;
  background: var(--campo); color: var(--txt); font-size: 14px; width: 100%;
}
@media (max-width: 480px) {
  #h-cal .hc-horas { border-left: 0; border-top: 1px solid var(--line); padding: 10px 0 0; flex-direction: row; }
  #h-cal .hc-horas label { flex: 1; }
}
#h-cal .hc-cab { display: flex; align-items: center; justify-content: space-between; padding-bottom: 8px; }
#h-cal .hc-cab b { font-size: 14.5px; }
#h-cal .hc-cab button {
  width: 38px; height: 38px; background: none; border: 0; padding: 0;
  color: var(--acc); font-size: 24px; font-weight: 800;
}
#h-cal .hc-sem { display: flex; }
#h-cal .hc-sem span { flex: 1; text-align: center; color: var(--mut); font-size: 10px; font-weight: 700; }
#h-cal .hc-rej { display: flex; flex-wrap: wrap; margin-top: 4px; }
#h-cal .hc-celda {
  width: 14.28%; height: 38px; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; color: var(--txt); font-size: 12.5px;
}
#h-cal .hc-celda .d { width: 30px; height: 30px; border-radius: 15px; display: flex; align-items: center; justify-content: center; }
#h-cal .hc-celda.dentro { background: rgba(2,132,199,.27); }
#h-cal .hc-celda.dentro .d { color: var(--acc); font-weight: 700; }
#h-cal .hc-celda.extremo .d { background: var(--acc2); color: #fff; font-weight: 800; }
#h-cal .hc-celda.futuro { color: var(--line); }
#h-cal .hc-etq { color: var(--acc); font-size: 12px; font-weight: 700; text-align: center; margin-top: 8px; min-height: 15px; }
#h-cal .hc-pie { display: flex; gap: 8px; margin-top: 12px; }
#h-cal .hc-pie button { border-radius: 12px; min-height: 42px; font-size: 13px; font-weight: 700; }
#h-cal .hc-no { flex: 1; background: none; border: 1px solid var(--line); color: var(--mut); }
#h-cal .hc-si { flex: 1.4; background: var(--acc2); border: 0; color: #fff; font-weight: 800; }
#h-cal .hc-si:disabled { opacity: .4; }

/* El botón que abre el calendario solo existe en el teléfono. */
#h-cal-abrir { display: none; }

/* ============================================================
   13 · MONITOREO "TODO FLOTANTE" — escritorio y celular
   ============================================================
   Opción B elegida por Ronald (2026-08-09): el mapa ocupa el 100% en todas
   las pantallas y todo lo demás flota encima, como Google Maps. En el
   celular la lista/ficha es la hoja inferior (sección 12l); en escritorio la
   lista es un panel flotante a la izquierda que se pliega a solo el buscador
   y la ficha del vehículo es una tarjeta flotante abajo a la derecha. */

#view-monitoring #map { right: 0; bottom: 0; }

/* La columna de botones circulares translúcidos (la crea flotInit). Mismos
   valores que la app: se leen sobre calles y sobre satélite. */
#mv-flot {
  position: absolute; top: 10px; right: 10px; z-index: 1260;
  display: flex; flex-direction: column; gap: 10px; align-items: flex-end;
}
#mv-flot > button {
  width: 48px; height: 48px; border-radius: 24px;
  background: rgba(15,23,42,.55); backdrop-filter: blur(2px);
  border: 1px solid rgba(255,255,255,.22); color: #fff;
  font-size: 20px; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 5px rgba(0,0,0,.35); padding: 0; cursor: pointer;
}
#mv-flot > button.on { background: var(--acc2); border-color: var(--acc); }

/* Los toggles del mapa (Ver todos, Agrupar, Rastro, Nombres, Mapa…) viven
   SIEMPRE a la vista como iconos redondos translúcidos, en fila arriba —igual
   que quedaron en la app (pedido Jeferson 27-ago). Ya no hay barra plegable:
   el 🧰 del stack abre directo la lista de herramientas. El texto del botón se
   esconde con font-size:0 y el icono (.mt-em) recupera su tamaño. */
#view-monitoring #map-toolbar {
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  left: auto; right: 70px; top: 10px; bottom: auto;
  max-height: none; overflow: visible;
  background: transparent; padding: 0; box-shadow: none; border-radius: 0;
  z-index: 1260;
}
/* La rueda y el pellizco acercan y alejan: los botones de zoom sobran. */
#view-monitoring #map-toolbar .mt-zoom { display: none; }
#view-monitoring #map-toolbar button.mt-txt {
  font-size: 0; gap: 0; width: 44px; height: 44px; min-height: 0; padding: 0;
  border-radius: 22px; display: flex; align-items: center; justify-content: center;
  background: rgba(15,23,42,.55); backdrop-filter: blur(2px);
  border: 1px solid rgba(255,255,255,.22); color: #fff;
  box-shadow: 0 2px 5px rgba(0,0,0,.35);
}
#view-monitoring #map-toolbar button.mt-txt .mt-em { font-size: 18px; width: auto; flex: none; }
#view-monitoring #map-toolbar button.on {
  background: var(--acc2); border-color: var(--acc); color: #fff;
}

/* El menú de Herramientas se ancla junto a la pastilla que lo abre y caía
   ENCIMA de los botones circulares. Va a su izquierda, con !important porque
   anclarEnMapa le escribe la posición en línea. */
/* El top NO va fijo: toggleToolsMenu lo mide en vivo bajo el stack (campana
   incluida) — regla de oro: nada anclado bajo #mv-flot con top fijo. */
#view-monitoring #tools-menu {
  left: auto !important; right: 66px !important;
  bottom: auto !important;
  max-height: calc(100% - 20px) !important; overflow-y: auto !important;
}

/* Chips de estado DENTRO del panel, bajo el buscador: solo el punto de color
   y la cifra. Informan Y filtran — un toque deja en la lista solo los de ese
   estado; otro toque lo quita. */
#fl-chips {
  display: flex; gap: 5px; flex-wrap: wrap; flex: 0 0 auto;
  margin: 0; padding: 0;
}
#fl-chips button {
  display: inline-flex; align-items: center; gap: 6px; flex: 1 1 0;
  justify-content: center;
  background: var(--card); color: var(--txt);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 8px; font-size: 11.5px; font-weight: 600; cursor: pointer;
}
#fl-chips button .pt { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
#fl-chips button.on { border-color: var(--acc); background: var(--acc2); color: #fff; }
@media (max-width: 760px) { #fl-chips { display: none; } }

/* Selectores de icono con el catálogo grande (4.600+): rejilla con tope de
   alto y scroll, para que no hagan una página infinita. La carga diferida
   (loading=lazy en los <img>) evita bajar todas las imágenes de una. */
#d-icons, #fo-icons {
  display: flex; flex-wrap: wrap; gap: 5px;
  max-height: 240px; overflow-y: auto; align-content: flex-start;
  padding: 4px; border: 1px solid var(--line); border-radius: var(--r-sm);
}
#ic-lista { max-height: 60vh; overflow-y: auto; }

/* El asa de la ficha solo existe en escritorio; en el teléfono la ficha vive
   dentro de la hoja, que ya tiene la suya. */
#fi-asa { display: none; }

/* ---- El menú principal, más discreto ----
   Letra e iconos bajados bastante (pedido de Ronald): el menú se usa dos
   veces por sesión y estaba gritando al lado de un mapa que es lo que
   importa. En el teléfono la barra inferior conserva sus tamaños de dedo. */
@media (min-width: 761px) {
  #leftnav .ln-logo { font-size: 12.5px; padding: 10px 12px; gap: 7px; }
  #leftnav nav { gap: 1px; padding: 7px 6px; }
  #leftnav nav button {
    font-size: 11.5px; padding: 6.5px 9px; gap: 8px; border-radius: 7px;
  }
  #leftnav nav button i { font-size: 12px; width: 15px; }
  #leftnav .ln-user { font-size: 10.5px; padding: 5px 9px; }
  #leftnav .ln-user b { font-size: 11px; }
  #leftnav #logout, #leftnav #tema-btn, #leftnav #credito-barra { font-size: 11.5px; padding: 6px 9px; }
  /* "Mi vendedor" trae tamaño y relleno en línea. */
  #leftnav #btn-mi-gerente { font-size: 11.5px !important; padding: 6px 9px !important; }
  #leftnav #logout i, #leftnav #tema-btn i, #leftnav #credito-barra i,
  #leftnav #btn-mi-gerente i { font-size: 12px !important; width: 15px !important; }
}

/* La fila de cada vehículo: nombre que puede partir en dos renglones y la
   última conexión siempre a la derecha, en gris. */
#veh-list .vitem { align-items: center; }
#veh-list .vitem .v-nom { flex: 1 1 auto; min-width: 0; line-height: 1.25; overflow-wrap: anywhere; }
#veh-list .vitem .v-hora {
  flex: 0 0 auto; margin-left: auto; padding-left: 6px;
  font-size: 10px; color: var(--mut); white-space: nowrap;
}
/* Acceso rápido a comandos (⋮) al final de cada fila, para emergencias. */
#veh-list .vitem .vkebab {
  flex: 0 0 auto; margin-left: 4px; padding: 2px 5px; border-radius: 6px;
  font-size: 17px; line-height: 1; font-weight: 800; color: var(--mut); cursor: pointer;
}
#veh-list .vitem .vkebab:hover { background: rgba(128,128,128,.2); color: var(--acc); }
/* En escritorio la lista baja de letra: 13px era tamaño de dedo, no de ratón.
   Compacta (fuentes E iconos más chicos): quien quiera verla grande, hace zoom
   del navegador. El icono de cada fila es un emoji que escala con la fuente, así
   que bajar el font-size achica letra e icono a la vez. */
@media (min-width: 761px) {
  #veh-list .vitem { font-size: 8px; padding: 3px 8px; gap: 4px; margin-bottom: 1px; }
  #veh-list .vitem .dot { width: 5.5px; height: 5.5px; }
  #veh-list .vitem .v-nom { line-height: 1.2; }
  #veh-list .vitem .v-hora { font-size: 7px; }
  #veh-list .vitem .vkebab { font-size: 12px; padding: 1px 4px; }
  #veh-search { font-size: 11px; padding: 6px 9px; }
}

/* Las banderitas con el nombre sobre cada vehículo, más chicas: a tamaño
   grande, con veinte carros el mapa era puro letrero. */
.leaflet-tooltip.veh-eti { font-size: 9.5px; padding: 1px 6px; border-radius: 5px; }

/* ---- Escritorio: lista flotante a la izquierda, ficha flotante a la derecha ---- */
@media (min-width: 761px) {
  #view-monitoring #mpanel {
    top: 12px; left: 12px; bottom: auto; right: auto; width: 296px;
    max-height: calc(100% - 24px);
    background: var(--flot); border: 1px solid var(--line);
    border-radius: 14px; box-shadow: 0 8px 28px var(--sombra);
    padding: 10px; z-index: 1250;
  }
  /* Plegado: queda solo el buscador, como la caja de búsqueda de Google Maps.
     Se pliega con el botón 🚚 y se abre al tocar el buscador. */
  /* Oculta DEL TODO el panel de la lista (tercer estado del 🚚). */
  #view-monitoring.fl-oculta #mpanel { display: none; }
  #view-monitoring.fl-plegada #veh-list,
  #view-monitoring.fl-plegada #fl-chips,
  #view-monitoring.fl-plegada #alertas-panel { display: none; }
  /* La ficha ya no vive dentro del panel: es su propia tarjeta flotante,
     abajo a la derecha, y solo existe con un vehículo elegido. Igual que
     FichaMapa en la app, arranca MINIMIZADA —cabecera y resumen— para no
     robarle el mapa; el asa la despliega y al cambiar de vehículo se vuelve
     a encoger. */
  #view-monitoring #panel-bottom {
    display: none;
    position: fixed; right: 12px; bottom: 12px; width: 330px;
    max-height: 248px; overflow: hidden;
    background: var(--flot); border: 1px solid var(--line);
    border-radius: 14px; box-shadow: 0 10px 30px var(--sombra);
    padding: 2px 10px 10px; margin: 0; border-top: 1px solid var(--line); z-index: 1300;
  }
  #view-monitoring.sel-activa #panel-bottom { display: block; }
  /* La ficha, otro punto más chica (pedido de Ronald): es tarjeta de consulta
     rápida, no una página. */
  #panel-bottom .rs-fila { font-size: 10.5px; padding: 2.5px 0; }
  #panel-bottom .rs-ico { font-size: 11.5px; }
  #panel-bottom .rs-link { font-size: 9.5px; }
  #panel-bottom #dev-detail .dh b { font-size: 11px; }
  #panel-bottom .st-pill { font-size: 8px; padding: 2px 6px; }
  #panel-bottom .drow { font-size: 10px; }
  #panel-bottom .tile .tv { font-size: 11.5px; }
  #panel-bottom .tile .tl { font-size: 7.5px; }
  #view-monitoring.fi-abierta #panel-bottom {
    max-height: 62vh; max-height: 62dvh; overflow-y: auto;
  }
  #view-monitoring #fi-asa {
    display: flex; flex-direction: column; align-items: center; gap: 1px;
    cursor: pointer; padding: 3px 0 4px;
  }
  #view-monitoring #fi-asa span { width: 40px; height: 4px; border-radius: 999px; background: var(--line); }
  #view-monitoring #fi-asa i { font-style: normal; color: var(--mut); font-size: 13px; line-height: 11px; font-weight: 700; }
  /* Con las cámaras abiertas —la banda de abajo o la tarjeta suelta— la lista
     de vehículos se ENCOGE a la mitad de arriba y rueda por dentro: antes
     seguía de largo y quedaba tapada debajo del video. */
  #view-monitoring:has(#cam-grid[style*="flex"]) #mpanel,
  #view-monitoring:has(#cam-card[style*="block"]) #mpanel {
    max-height: calc(46% - 20px);
  }
  /* La tarjeta de cámara suelta comparte esquina con la lista: se queda con
     la mitad de abajo (salvo en pantalla completa). */
  #view-monitoring #cam-card:not(.fs) { max-height: calc(52% - 20px); }

  /* Los avisos y las bandas flotantes se referían al panel derecho de 340 px
     que ya no existe: se corren a los nuevos bordes. */
  #avisos { right: 70px; }
  #day-panel { right: 404px; }
  #cmd-panel { right: 404px; }
  #cmd-panel.solo { right: 404px; }
  /* Las cámaras se topan ANTES de la ficha del vehículo (#panel-bottom: abajo-
     derecha, 330px). Así el mosaico no tapa la info del vehículo; al estirarlo,
     camGridLimites() lo frena en el mismo borde. */
  #cam-grid { right: 354px; }
  #cam-grid.con-comandos { right: 744px; }
  #pip { right: 70px; }
  /* Cero superposición: el menú de herramientas y su panel se abrían a la
     izquierda, encima del panel flotante de la lista. Se corren al lado
     derecho (junto a los botones circulares), sin taparla. */
  #view-monitoring #tools-menu { left: auto !important; right: 68px !important; top: 12px !important; }
  #view-monitoring #tool-panel { left: auto !important; right: 68px !important; top: 12px !important; max-height: calc(100% - 24px); }
}

/* ============================================================
   14 · HISTORIAL "TODO FLOTANTE" EN ESCRITORIO (opción A)
   ============================================================
   El mapa ocupa todo. La consulta es una tarjeta flotante a la izquierda con
   la lista de objetos dentro (la mueve histFlotInit); los días van arriba al
   centro; los datos son una hoja inferior plegable cuya cabecera lleva el
   asa, las métricas y las pestañas. Sin datos no hay hoja. */
@media (min-width: 761px) {
  #view-historial > div { position: relative; }
  /* La consulta: tarjeta flotante arriba a la izquierda. Sus estilos vienen
     EN LÍNEA (fondo, borde, radio): !important o no cambia nada. */
  /* La tarjeta al 75% del ancho anterior, en REJILLA de 3 columnas: el
     dispositivo, el contador y los objetos van de lado a lado; las tres
     acciones (Fechas · Buscar · CSV) comparten UNA fila de botones chicos.
     El display y align-items vienen EN LÍNEA de la barra vieja: !important. */
  #view-historial #h-barra {
    position: absolute; top: 10px; left: 10px; z-index: 1210; width: 250px;
    display: grid !important; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px 6px; align-items: stretch !important;
    background: var(--flot) !important; border: 1px solid var(--line) !important;
    border-radius: 14px !important; box-shadow: 0 8px 28px var(--sombra);
    padding: 10px !important; max-height: calc(100% - 20px);
    overflow-y: auto; overflow-x: hidden;
  }
  #h-barra > * { grid-column: 1 / -1; min-width: 0; margin: 0; }
  #h-barra > div:has(> #h-from), #h-barra > div:has(> #h-to) { display: none; }
  /* El buscador que inyecta el observador sobra dentro de la tarjeta. */
  #h-barra .busca-caja { display: none !important; }
  #h-barra #h-dev { width: 100%; min-width: 0 !important; }
  /* Las tres acciones, chicas y en una fila. */
  #h-barra > #h-cal-abrir,
  #h-barra > button[onclick="runHistorial()"],
  #h-barra > button[onclick="exportHistCsv()"] {
    grid-column: auto; width: 100%; min-height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 6px 4px !important; font-size: 11.5px; white-space: nowrap;
  }
  #h-barra #h-status { margin-left: 0 !important; text-align: center; }
  #h-barra #h-flota-wrap { min-width: 0; overflow: hidden; }
  /* Los objetos, dentro de la tarjeta, alineados con el resto. */
  #h-barra #h-flota-wrap {
    display: flex !important; width: auto !important;
    border-right: 0 !important; border-top: 1px solid var(--line);
    padding-top: 4px; max-height: 30vh; background: transparent !important;
  }
  #h-barra #h-flota-wrap > div:first-child { padding: 2px 0 2px !important; }
  /* La lista de objetos se dimensiona a SU contenido pero con TOPE y scroll, para
     no salir "extra grande". OJO: NO usar flex:1 aquí — el contenedor no tiene alto
     fijo (max-height por contenido), así que flex-grow con base 0 la colapsaría a 0
     y la lista desaparecía. Con max-height + overflow crece hasta el tope y rueda. */
  #h-barra #h-flota { padding: 0 0 4px !important; flex: 0 0 auto !important; max-height: 26vh !important; overflow-y: auto !important; }
  /* El contador pegajoso traía el fondo de la página; sobre la tarjeta
     flotante se veía como una franja gris de lado a lado. */
  #h-barra #h-flota > .k:first-child { background: var(--flot) !important; padding: 2px 0 7px !important; }
  #h-barra .h-flo-item { padding: 8px 9px; font-size: 12.5px; }
  /* La tira de días, arriba al centro del mapa. */
  #view-historial #h-dias {
    display: flex; position: absolute; left: 50%; top: 10px; transform: translateX(-50%);
    z-index: 1205; gap: 6px; max-width: 48%; overflow-x: auto;
    background: transparent; border: 0; padding: 0; scrollbar-width: none;
  }
  #view-historial #h-dias::-webkit-scrollbar { display: none; }
  #view-historial #h-dias button {
    flex: 0 0 auto; min-height: 34px; padding: 0 13px; cursor: pointer;
    background: var(--flot); color: var(--flot-txt);
    border: 1px solid var(--line); border-radius: 999px;
    font-size: 12px; font-weight: 600; box-shadow: 0 2px 8px var(--sombra);
  }
  #view-historial #h-dias button.act { background: var(--acc2); border-color: var(--acc); color: #fff; }
  #view-historial #h-dias button.cal { border-color: var(--acc); }
  /* La hoja inferior: plegada muestra asa + métricas + pestañas + reproductor. */
  #view-historial > div > div:last-child {
    position: absolute; left: 10px; right: 10px; bottom: 10px;
    height: auto !important; min-height: 0 !important; z-index: 1215;
    background: var(--flot); border: 1px solid var(--line);
    border-top: 1px solid var(--line) !important;
    border-radius: 14px; box-shadow: 0 10px 30px var(--sombra);
    padding: 2px 10px 8px;
  }
  /* Abierta ocupa poco más de un cuarto: los registros se recorren con su
     scroll interno y el mapa sigue mandando. */
  #view-historial.h-hoja-abierta > div > div:last-child { height: 28% !important; min-height: 210px !important; }
  /* REGLA 2: con la pestaña de Clips activa la hoja sube hasta el borde de los objetos
     (media pantalla). El alto lo calcula histTab en --sd-alto según dónde termina la
     tarjeta de objetos; si no, cae a 46%. Va DESPUÉS de .h-hoja-abierta para ganarle. */
  #view-historial.h-sd-activo > div > div:last-child { height: var(--sd-alto, 46%) !important; min-height: 300px !important; }
  #view-historial:not(.h-hoja-abierta) #h-grid,
  #view-historial:not(.h-hoja-abierta) #h-trips,
  #view-historial:not(.h-hoja-abierta) #h-sd { display: none !important; }
  /* Sin datos, ni hoja ni métricas: el mapa entero. */
  #view-historial:not(.h-con-datos) > div > div:last-child { display: none; }
  #view-historial #h-hoja-asa {
    display: flex; flex-direction: column; align-items: center; gap: 1px;
    cursor: pointer; padding: 3px 0 2px;
  }
  #view-historial #h-hoja-asa span { width: 40px; height: 4px; border-radius: 999px; background: var(--line); }
  #view-historial #h-hoja-asa i { font-style: normal; color: var(--mut); font-size: 13px; line-height: 11px; font-weight: 700; }
  /* Las métricas del resumen, en UNA línea en la cabecera de la hoja. */
  #view-historial #h-summary {
    display: flex !important; flex-wrap: nowrap; gap: 4px; overflow-x: auto;
    width: auto !important; border: 0 !important; background: transparent !important;
    padding: 0 4px !important;
  }
  #view-historial #h-summary h3 { display: none; }
  #view-historial #h-summary .row {
    display: flex; flex-direction: column-reverse; justify-content: flex-end;
    border: 0; padding: 0 12px 0 0; flex: 0 0 auto;
  }
  #view-historial #h-summary .row b { font-size: 10px; line-height: 1.2; }
  #view-historial #h-summary .row .k {
    font-size: 6.5px; letter-spacing: .04em; text-transform: uppercase; white-space: nowrap;
  }
  /* Todo a media letra y sin aire de sobra (pedido de Ronald): la hoja es de
     barrido, cada punto de relleno le roba una fila al registro. */
  #view-historial > div > div:last-child { padding: 0 8px 4px; }
  #view-historial #h-hoja-asa { padding: 1px 0 0; }
  #view-historial #h-hoja-asa span { height: 3px; width: 34px; }
  #view-historial #h-hoja-asa i { font-size: 10px; line-height: 8px; }
  #view-historial .subnav { margin-bottom: 2px; padding: 2px 4px 0 !important; }
  #view-historial .subnav button {
    font-size: 10.5px !important; padding: 4px 9px !important; min-height: 0 !important;
  }
  #h-grid table { font-size: 9px; }
  #h-grid th { font-size: 7px; padding: 2px 6px; }
  #h-grid td { font-size: 9px; padding: 1.5px 6px; }
  #h-trips .row { font-size: 9.5px; padding: 1px 6px; }
  #h-grid tr.h-trama td { font-size: 8px; }
  #view-historial #h-hoja-cerrar { min-height: 22px; padding: 0 8px; font-size: 11px; }
  #view-historial #h-playbar #h-playbtn { min-height: 26px; padding: 2px 10px; }
  #view-historial #h-playbar #h-speed { padding: 2px 4px !important; font-size: 11px; }
  #view-historial #h-playbar #h-seeklbl { font-size: 9.5px; }
  /* La cabecera de la hoja en una fila: métricas · reproductor · ✕. */
  #view-historial #h-hoja-cab { display: flex; align-items: center; gap: 16px; }
  #view-historial #h-hoja-cab #h-summary { flex: 0 1 auto; }
  #view-historial #h-hoja-cab #h-playbar {
    flex: 1 1 auto; min-width: 220px; margin: 0;
    border: 0 !important; background: transparent !important; padding: 0 !important;
  }
  #view-historial #h-hoja-cab #h-hoja-cerrar {
    flex: 0 0 auto; min-height: 28px; padding: 2px 10px; align-self: flex-start;
  }
  /* El lateral de clips, como tarjeta flotante a la derecha. */
  #view-historial #h-sd-side {
    position: absolute; right: 10px; top: 10px; width: 300px !important;
    max-height: calc(46% - 20px); z-index: 1210;
    background: var(--flot) !important; border: 1px solid var(--line) !important;
    border-radius: 14px;
  }
}
/* El asa de la hoja del historial no aparece en el teléfono. */
#h-hoja-asa { display: none; }

/* Los buscadores inyectados del Historial y del Recorrido de hoy: fuera en
   TODOS los anchos (Ronald, 2026-08-09). OJO: el observador NO siempre mete la
   caja dentro de #h-grid — cuando el contenedor tiene scroll la deja como
   HERMANA, fuera de él. Por eso se tapa por vista entera, no por tabla. */
#view-historial .busca-caja, #day-panel .busca-caja { display: none !important; }

/* La tira de días de los clips de la SD, con las mismas pastillas del
   Historial: un toque pone la fecha y le pregunta a la tarjeta. */
#sdc-dias {
  display: flex; gap: 5px; overflow-x: auto; flex: 0 0 auto;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
  padding: 4px 10px 2px;
}
#sdc-dias::-webkit-scrollbar { display: none; }
#sdc-dias button {
  flex: 0 0 auto; min-height: 24px; padding: 0 10px; cursor: pointer;
  background: var(--card); color: var(--txt);
  border: 1px solid var(--line); border-radius: 999px;
  font-size: 11px; font-weight: 600;
}
#sdc-dias button.act { background: var(--acc2); border-color: var(--acc); color: #fff; }

/* Compactación del panel de Clips SD (16-ago): el timeline ya navega el día, así
   que la fila de botones de HORA sobra; y las barras de control se aprietan para
   no comerse media pantalla. */
#sdc-horas { display: none !important; }
#day-sd #sdc-bar { padding: 4px 10px; gap: 5px; }
#sdc-timeline { padding: 5px 10px 2px !important; }
#tl-track { height: 34px !important; }
.tl-ticks { height: 12px !important; margin-top: 2px !important; }

/* La trama del registro (doble clic en una fila del historial): todas las
   etiquetas tal como llegaron, en letra pequeñita y de máquina. */
#h-grid tr.h-trama td {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 9px; line-height: 1.7; color: var(--mut);
  white-space: normal; word-break: break-word;
  background: var(--bg2); padding: 4px 10px;
}
#h-grid tr.h-trama td b { color: var(--acc); font-weight: 600; }
#h-grid tr.h-trama:hover td { background: var(--bg2); }
#h-grid tr.fila-sel td { background: var(--fila-hover); }

/* El navegador de clips DENTRO de la ficha: mismo contenido, a la medida de
   la tarjeta. Miniaturas CUADRADAS con su hora debajo; la rejilla rueda. */
#sd-clips-host #day-sd { display: flex; flex-direction: column; max-height: 420px; }
#sd-clips-host #sdc-bar { padding: 6px 0; border-bottom: 1px solid var(--line); }
#sd-clips-host #sdc-dias { padding: 4px 0 2px; }
#sd-clips-host #sdc-grid {
  max-height: 260px; padding: 8px 0;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
}
#sd-clips-host .sdc-mini { aspect-ratio: 1 / 1 !important; min-height: 92px; }
#sd-clips-host .sdc-pie { padding: 3px 5px; font-size: 10px; }
#sd-clips-host .sdc-pie b { font-size: 11px; }
#sd-clips-host #sdc-horas { padding: 6px 0; }

/* Reproductor de la grabación, ahora integrado en la pestaña de clips (ya no en
   un panel flotante aparte). En el Historial el panel es ancho, así que se acota
   para que el video no salga gigante; en la ficha/sidebar ya es angosto. */
#sd-player-box #sd-video { max-height: 42vh; }
#h-sd #sd-player-box { max-width: 640px; margin: 8px auto 4px; }
/* Botón "generar miniaturas": ahora icónico y discreto (era una frase larga que
   amontonaba la barra). Las miniaturas igual se generan solas al abrir la hora. */
#sdc-bar .sdc-sec { opacity: .85; }

/* Rejilla de miniaturas: SOLO 2 filas a la vista y el resto con scroll (pedido de
   Ronald). Se fija el alto de fila para que "2 filas" sea exacto sin depender del
   ancho de cada cuadro. #sdc-grid siempre vive dentro de #day-sd (en la ficha, en
   el panel del día y en el Historial), así que este selector cubre los tres. */
#day-sd #sdc-grid {
  flex: none;
  overflow-y: auto;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  grid-auto-rows: 112px;
  max-height: 254px;         /* 10 (pad) + 112 + 10 (gap) + 112 + 10 (pad) */
}
#day-sd .sdc-clip { display: flex; flex-direction: column; }
#day-sd .sdc-mini { flex: 1 1 auto; aspect-ratio: auto; min-height: 0; }
#day-sd .sdc-pie { flex: 0 0 auto; }
/* En el Historial, day-sd se reubica en #h-sd con display:flex pero SIN dirección:
   sus hijos (barra, horas, reproductor, rejilla) salían en fila y las miniaturas
   se veían como "líneas". Se fuerza columna para que se apilen y la rejilla mande. */
#h-sd #day-sd { display: flex; flex-direction: column; flex: 1; min-height: 0; }
#h-sd #sdc-grid { max-height: none; flex: 1; }

/* --- Clips de la SD en el PANEL INFERIOR (pestaña "Clips de la SD"): al abrirla la
   ventana se AGRANDA y las miniaturas cargan en su PROPORCIÓN REAL 16:9 (grandes, no
   "líneas chiquitas"), en una tira de 2 FILAS que se navega con SCROLL LATERAL. Pedido
   de Ronald (15-ago-2026). Solo aplica al panel del día; ficha/historial/ventana
   ampliada conservan su propio layout. --- */
#day-panel.con-clips { max-height: 72%; }
#day-panel.con-clips #day-sd #sdc-grid {
  display: grid !important;
  grid-auto-flow: column !important;
  grid-template-columns: none !important;
  grid-template-rows: repeat(2, min-content) !important;
  grid-auto-columns: 240px !important;
  gap: 12px !important;
  overflow-x: auto !important;
  overflow-y: hidden !important;
  max-height: none !important;
  padding: 12px !important;
  align-content: start !important;
}
#day-panel.con-clips #day-sd .sdc-clip { display: flex; flex-direction: column; }
#day-panel.con-clips #day-sd .sdc-mini { aspect-ratio: 16 / 9 !important; min-height: 0 !important; flex: none !important; height: auto !important; }
#day-panel.con-clips #day-sd .sdc-pie { flex: 0 0 auto; }
/* En pantallas medianas (tablet), miniaturas algo más pequeñas para que quepan 2 filas. */
@media (max-width: 760px) and (min-width: 601px) {
  #day-panel.con-clips #day-sd #sdc-grid { grid-auto-columns: 200px !important; }
}
/* Pantalla MUY pequeña (teléfono): UNA SOLA fila de miniaturas con scroll lateral,
   para no comerse el alto. Pedido de Ronald. */
@media (max-width: 600px) {
  #day-panel.con-clips #day-sd #sdc-grid {
    grid-template-rows: min-content !important;   /* 1 fila */
    grid-auto-columns: min(80vw, 260px) !important;
    flex: 0 0 auto !important;                     /* que la tira no crezca: el panel se ajusta a 1 fila */
  }
  #day-panel.con-clips { max-height: 66%; }
}

/* --- BARRA INFERIOR DE ANCHO COMPLETO Y BAJA (16-ago-2026, pedido de Ronald) ---
   El timeline ya navega el día, así que el panel deja de ser un bloque alto que
   tapa medio mapa: va de ancho COMPLETO (right:0), más bajo, con las miniaturas en
   UNA sola fila y el video a su lado (no apilado). --- */
#day-panel { right: 0 !important; }
#day-panel.con-clips { max-height: 46% !important; }
#sd-lower { display: flex; gap: 10px; padding: 0 10px 8px; align-items: flex-start; }
#day-panel.con-clips #day-sd #sd-player-box { flex: 0 0 clamp(260px, 34vw, 420px); max-width: 420px; margin: 8px 0 0; }
#day-panel.con-clips #day-sd #sd-video { max-height: 34vh; }
/* Las miniaturas se ocultan: el timeline ya es la navegación (como TrackSolid), así
   navegar el día deja el panel bajito. Se pueden mostrar con el botón 🖼️ de la barra. */
#day-panel.con-clips.sin-minis #day-sd #sdc-grid { display: none !important; }
#day-panel.con-clips #day-sd #sdc-grid {
  grid-template-rows: min-content !important;      /* UNA sola fila (antes 2) */
  grid-auto-columns: 170px !important;
  flex: 1 1 auto !important; min-width: 0 !important;
  margin: 0 !important;
}
@media (max-width: 760px) {
  #sd-lower { flex-direction: column; }
  #day-panel.con-clips #day-sd #sd-player-box { flex: none; max-width: none; width: 100%; }
  #day-panel.con-clips { max-height: 52% !important; }
}

/* ---- CLIPS DE LA SD EN VENTANA AMPLIA ----
   Al abrir "Grabaciones de la SD", el panel deja de ser la tarjeta angosta de la
   ficha y se abre como ventana flotante centrada: miniaturas 16:9 REALES en una
   rejilla de varias columnas, con scroll vertical cómodo (no la tira chiquita). */
#sd-veil { display: none; position: fixed; inset: 0; background: var(--velo); z-index: 10055; }
#sd-panel.sd-expandido {
  position: fixed; z-index: 10060;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(1040px, 95vw); max-height: 90vh; margin: 0 !important;
  display: flex; flex-direction: column;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 24px 70px var(--sombra); padding: 12px 16px; overflow: hidden;
}
#sd-panel.sd-expandido > .dh { margin-bottom: 10px; }
#sd-panel.sd-expandido #sd-clips-host { flex: 1; min-height: 0; display: flex; overflow: hidden; }
#sd-panel.sd-expandido #sd-clips-host #day-sd { max-height: none !important; flex: 1; min-height: 0; }
#sd-panel.sd-expandido #sd-clips-host #sdc-grid {
  max-height: none !important; padding: 10px 2px;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)) !important;
}
#sd-panel.sd-expandido #sd-clips-host .sdc-mini { aspect-ratio: 16 / 9 !important; min-height: 0 !important; }
#sd-panel.sd-expandido #sd-clips-host .sdc-pie { padding: 5px 8px; font-size: 11.5px; }
#sd-panel.sd-expandido #sd-clips-host .sdc-pie b { font-size: 12px; }
/* el reproductor del clip queda abajo, sin comerse la rejilla */
#sd-panel.sd-expandido #sd-player-box { max-height: 46vh; overflow: auto; margin-top: 10px; }
#sd-panel.sd-expandido #sd-player-box video { max-height: 36vh; }
@media (max-width: 760px) {
  #sd-panel.sd-expandido { width: 96vw; max-height: 92vh; padding: 10px 12px; }
  #sd-panel.sd-expandido #sd-clips-host #sdc-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)) !important; }
}

/* La tira de días del historial solo existe en el teléfono. */
#h-dias { display: none; }

/* El botón de plegar la consulta solo existe en el teléfono. */
#h-plegar { display: none; }

/* La barra de volver y el asa del modo móvil no existen en escritorio. Van
   fuera de la consulta de medios porque los elementos quedan en el DOM si la
   ventana se agranda después. */
#mv-volver { display: none; }
#mpanel .hoja-asa { display: none; }

/* ============================================================
   15 · ALTA DENSIDAD — Usuarios y Objetos (modo gerente)
   ============================================================
   Menos texto, más iconos. Botones de acción icónicos con tooltip, tabla
   compacta y fuentes reducidas para que quepa más sin rodar la pantalla. */

/* Botón icónico: cuadrado, compacto, solo el trazo. El tooltip lo da title. */
.btn-sm.ic-b {
  padding: 4px 6px; min-height: 0; line-height: 0;
  display: inline-flex; align-items: center; justify-content: center;
  margin: 1px; vertical-align: middle;
}
.btn-sm.ic-b .ic { width: 15px; height: 15px; vertical-align: middle; }
.btn-sm.ic-b.mb-obj { line-height: 1; font-size: 11px; padding: 3px 7px; }
/* Acciones en UNA sola línea. Antes iba con flex-wrap:wrap y los 6 botones se
   envolvían en varias filas, estirando el renglón ~75px de alto. En nowrap se
   quedan en línea (la tabla ya tiene scroll horizontal si no caben). */
#atab-users td.acciones, #atab-devices td.acciones { white-space: nowrap; }
#atab-users td.acciones > *, #atab-devices td.acciones > * { display: inline-flex; vertical-align: middle; }
/* Filas parejas y bajas: el contenido centrado, sin aire de más. */
#atab-users td, #atab-devices td { vertical-align: middle; }

/* Densidad de las tablas de Usuarios y Objetos: fuente y relleno reducidos. */
#atab-users table, #atab-devices table { font-size: 11px; }
#atab-users th, #atab-devices th { font-size: 9px; padding: 4px 6px; }
#atab-users td, #atab-devices td { padding: 3px 6px; }
#atab-users td .k, #atab-devices td .k { font-size: 9.5px; }
#atab-users td b, #atab-devices td b { font-weight: 600; }

/* Popup de la membresía fusionada: desglose del costo con cámaras incluidas. */
#mb-fusion {
  display: none; position: fixed; z-index: 9600; right: 24px; bottom: 24px;
  width: 260px; background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--elev-alta); padding: 10px 12px;
}
#mb-fusion .mbf-h { display: flex; align-items: center; justify-content: space-between; font-weight: 600; font-size: 13px; margin-bottom: 8px; }
#mb-fusion .mbf-x { background: none; border: 0; color: var(--mut); font-size: 15px; cursor: pointer; padding: 0 2px; }
#mb-fusion .mbf-l { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; padding: 3px 0; color: var(--mut); }
#mb-fusion .mbf-l b { color: var(--txt); }
#mb-fusion .mbf-sep { font-size: 10px; letter-spacing: .03em; text-transform: uppercase; color: var(--mut); margin: 8px 0 6px; padding-top: 6px; border-top: 1px solid var(--line); }
#mb-fusion .mbf-op { width: 100%; display: flex; justify-content: space-between; align-items: center; margin-top: 6px; padding: 8px 10px; }
#mb-fusion .mbf-op b { color: var(--acc); }

/* SEGUIR: mini-mapa flotante y arrastrable. Cero superposición con el resto:
   flota por encima y se mueve donde el gerente lo deje. */
#seguir-box {
  display: none; position: fixed; z-index: 9500; right: 24px; top: 90px;
  width: 300px; height: 280px; flex-direction: column;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--elev-alta); overflow: hidden;
}
#seguir-cab {
  display: flex; align-items: center; gap: 7px; padding: 7px 10px;
  border-bottom: 1px solid var(--line); cursor: move; user-select: none;
}
#seguir-cab .mira { display: flex; color: var(--acc); }
#seguir-cab b { flex: 1; font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#seguir-x { background: none; border: 0; color: var(--mut); font-size: 15px; cursor: pointer; padding: 0 2px; }
#seguir-map { flex: 1; min-height: 0; }
#seguir-pie { padding: 5px 10px; border-top: 1px solid var(--line); font-size: 11px; }

/* Sensores: el observador le pega un buscador al selector de vehículo, y ahí
   no sirve (el desplegable ya busca al teclear). Fuera. Y el selector de
   vehículo se ve como lo que es: la entrada principal de la pantalla. */
#atab-sensores .busca-caja { display: none !important; }
#atab-sensores #sl-dev { margin-top: 2px; }
#atab-sensores label[class="k"] { margin-top: 10px; }
