/* ==========================================================================
   Sistema de Órdenes de Carga y Remitos
   Tema claro/oscuro, sin dependencias externas.
   ========================================================================== */

:root {
  color-scheme: light;

  --bg:            #f6f7f9;
  --bg-elev:       #ffffff;
  --bg-sunken:     #eef0f4;
  --bg-hover:      #f1f3f7;

  --border:        #e2e5ec;
  --border-strong: #cfd4de;

  --text:          #171a20;
  --text-soft:     #5b6472;
  --text-faint:    #8b95a5;

  --accent:        #3b5bdb;
  --accent-soft:   #eaeefc;
  --accent-text:   #2f49b0;
  --accent-contrast: #ffffff;

  --ok:            #167a4c;
  --ok-soft:       #e3f5ec;
  --warn:          #a55a00;
  --warn-soft:     #fdf1de;
  --danger:        #b3261e;
  --danger-soft:   #fdeceb;
  --info:          #1f6aa8;
  --info-soft:     #e6f1fa;

  --radius:    10px;
  --radius-sm: 7px;
  --radius-lg: 14px;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow:    0 4px 14px rgba(16, 24, 40, .07), 0 1px 3px rgba(16, 24, 40, .05);
  --shadow-lg: 0 18px 48px rgba(16, 24, 40, .16);

  --sidebar-w: 248px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Menlo, monospace;
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg:            #0e1116;
  --bg-elev:       #161a21;
  --bg-sunken:     #11151b;
  --bg-hover:      #1d222b;

  --border:        #262c37;
  --border-strong: #39414f;

  --text:          #e7eaf0;
  --text-soft:     #a3adbd;
  --text-faint:    #6f7a8b;

  --accent:        #7c93f5;
  --accent-soft:   #1c2440;
  --accent-text:   #a8b8ff;
  --accent-contrast: #0e1116;

  --ok:            #4ec38a;
  --ok-soft:       #11291f;
  --warn:          #e5a54b;
  --warn-soft:     #2b2113;
  --danger:        #f08079;
  --danger-soft:   #2e1917;
  --info:          #6fb3e8;
  --info-soft:     #12222f;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow:    0 4px 16px rgba(0, 0, 0, .45);
  --shadow-lg: 0 20px 52px rgba(0, 0, 0, .6);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #0e1116; --bg-elev: #161a21; --bg-sunken: #11151b; --bg-hover: #1d222b;
    --border: #262c37; --border-strong: #39414f;
    --text: #e7eaf0; --text-soft: #a3adbd; --text-faint: #6f7a8b;
    --accent: #7c93f5; --accent-soft: #1c2440; --accent-text: #a8b8ff; --accent-contrast: #0e1116;
    --ok: #4ec38a; --ok-soft: #11291f; --warn: #e5a54b; --warn-soft: #2b2113;
    --danger: #f08079; --danger-soft: #2e1917; --info: #6fb3e8; --info-soft: #12222f;
    --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
    --shadow: 0 4px 16px rgba(0,0,0,.45);
    --shadow-lg: 0 20px 52px rgba(0,0,0,.6);
  }
}

* { box-sizing: border-box; }

/* El `display: none` que trae el atributo `hidden` viene de la hoja del
   navegador, así que cualquier regla propia con `display` (`.btn`, `.tri`, …) le
   gana y el elemento se ve igual. Acá se usa `hidden` para mostrar y ocultar
   controles —el panel del multiselect, "Limpiar filtros"— y tiene que ganar. */
[hidden] { display: none !important; }

/* Tamaño por defecto de los íconos inline. Sin esto, un SVG sin ancho declarado
   se expande al espacio disponible. Las reglas específicas de más abajo lo pisan. */
svg { width: 16px; height: 16px; flex: none; }

/* …pero el mapa no es un ícono. Leaflet dibuja el recorrido y los círculos de
   las geocercas en un <svg> que tiene que ocupar el mapa entero, y la regla de
   arriba se lo llevaba puesto: lo aplastaba a 16×16 y las líneas quedaban
   invisibles (renderizadas, pero de 6 px y fuera del contenedor). Leaflet le
   pone width/height por atributo en cada zoom, así que alcanza con no pisarlos. */
.leaflet-container svg { width: auto; height: auto; flex: initial; }

html, body {
  margin: 0; padding: 0; height: 100%;
  /* Sin zoom del navegador: se permite arrastrar en los dos ejes —la página scrollea
     y la fila de iconos del header también— y nada más. Eso saca el pinch y, de
     paso, el doble toque, que es el que se dispara sin querer marcando una llegada
     con el teléfono en la mano.

     `touch-action` NO se hereda, pero el navegador cruza el valor del elemento tocado
     con el de todos sus ancestros, así que declararlo acá alcanza para toda la
     aplicación. Los mapas quedan afuera porque Leaflet le pone `touch-action: none` a
     su contenedor: le dice al navegador "no hagas nada, de este gesto me ocupo yo", y
     el zoom lo hace Leaflet en JS con el mismo pinch. */
  touch-action: pan-x pan-y;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }

::selection { background: var(--accent); color: var(--accent-contrast); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --------------------------------------------------------------- layout -- */

.app { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--bg-elev);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

/* Sólo cobra forma en el celular (ver la media query de 860px): ahí `.sidebar`
   puede desplegarse tapando el contenido, y esto es lo que se toca para
   cerrarlo. En escritorio no hace falta esconderla con JS: sin `display:block`
   ni `position` no ocupa lugar ni se puede tocar. */
.menu-scrim { display: none; }

.brand {
  display: flex; align-items: center; gap: 11px;
  padding: 18px 14px 16px 18px;
  border-bottom: 1px solid var(--border);
}
.menu-toggle { margin-left: auto; }
.brand-mark {
  width: 34px; height: 34px; flex: none;
  border-radius: 9px;
  background: linear-gradient(140deg, var(--accent), color-mix(in srgb, var(--accent) 65%, #9b5de5));
  color: #fff;
  display: grid; place-items: center;
  box-shadow: var(--shadow-sm);
}
.brand-mark svg { width: 19px; height: 19px; }
/* Los rombos de Leoni traen sus propios colores —el rojo y el celeste de la marca—
   así que van sueltos, sin la pastilla de fondo del .brand-mark: sobre el degradé
   violeta el celeste se pierde. */
.brand-logo {
  width: 34px; height: 34px; flex: none;
  object-fit: contain;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.brand-text strong { font-size: 13.5px; font-weight: 650; letter-spacing: -.01em; }
.brand-text span { font-size: 11.5px; color: var(--text-faint); }

.nav { padding: 12px 10px; display: flex; flex-direction: column; gap: 2px; flex: 1; overflow-y: auto; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font-size: 13.5px;
  font-weight: 500;
  transition: background .12s, color .12s;
}
.nav-item svg { width: 17px; height: 17px; flex: none; opacity: .85; }
.nav-item:hover { background: var(--bg-hover); color: var(--text); }
/* Ítem al que llegaron las flechas: se ve como el hover, porque es lo mismo
   —dónde está apuntando— con otro dispositivo. */
.nav-item.nav-foco:not(.active) { background: var(--bg-hover); color: var(--text); }
.nav-item.active { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; }
.nav-item.active svg { opacity: 1; }
.nav-badge {
  margin-left: auto;
  font-style: normal; font-size: 11px; font-weight: 650;
  background: var(--warn-soft); color: var(--warn);
  padding: 1px 7px; border-radius: 999px;
}
/* Los desvíos no son trabajo en una cola: son algo que está pasando ahora. El
   rojo los separa de los otros dos contadores para que no se lean como "tres
   pendientes más". */
.nav-badge-alerta { background: var(--danger-soft); color: var(--danger); }
.nav-sep { height: 1px; background: var(--border); margin: 10px 10px; }

/* Los tres módulos del menú: un encabezado plegable y sus ítems adentro. Uno
   solo abierto a la vez —acordeón, ver abrirGrupo() en app.js—; el chevron
   sigue el mismo lenguaje que .card-plegar (apunta a la derecha cerrado, abajo
   abierto), sin ser el mismo componente: acá sólo puede haber uno abierto a
   la vez, y allá cada tarjeta se pliega sola. */
.nav-grupo-cab {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: none; background: none;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font-size: 13.5px;
  font-weight: 500;
  text-align: left;
  transition: background .12s, color .12s;
}
button.nav-grupo-cab { cursor: pointer; }
.nav-grupo-cab svg { width: 17px; height: 17px; flex: none; opacity: .85; }
button.nav-grupo-cab:hover { background: var(--bg-hover); color: var(--text); }
.nav-grupo-chevron { margin-left: auto; transition: transform .15s; transform: rotate(-90deg); }
.nav-grupo.abierto .nav-grupo-chevron { transform: rotate(0deg); }
.nav-grupo-items { display: none; flex-direction: column; gap: 2px; padding-left: 14px; }
.nav-grupo.abierto .nav-grupo-items { display: flex; }
/* Sin pantallas todavía: el encabezado queda pero sin botón —no hay nada que
   desplegar— ni chevron, y algo más apagado para que se note que es distinto
   de los otros dos módulos, que sí llevan algo adentro. */
.nav-grupo-vacio .nav-grupo-cab { opacity: .6; }
.nav-grupo-nota { margin: 0 0 4px 42px; }

.sidebar-foot {
  border-top: 1px solid var(--border);
  padding: 10px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.pf-status { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--text-faint); min-width: 0; }
.pf-status .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); flex: none; }
.pf-status.ok    .dot { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.pf-status.warn  .dot { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-soft); }
.pf-status.off   .dot { background: var(--text-faint); }
.pf-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Menú plegado: una columna de iconos.
   El ancho sale de la misma variable que el menú desplegado, así que todo lo que se
   mide contra ella —el pie, las tablas anchas— se acomoda solo. No se oculta del
   todo a propósito: sin los iconos habría que desplegarlo para cambiar de pantalla,
   y plegarlo es para ganar ancho, no para dejar de navegar. */
:root.menu-min {
  --sidebar-w: 62px;
}
.menu-min .brand {
  flex-direction: column; gap: 8px;
  padding: 12px 8px 12px;
}
.menu-min .brand-text,
.menu-min .nav-item > span,
.menu-min .pf-label { display: none; }
.menu-min .menu-toggle { margin-left: 0; }
/* El chevron gira: es el mismo botón el que pliega y el que despliega. */
.menu-min .menu-toggle svg { transform: rotate(180deg); }
.menu-min .nav { padding: 12px 7px; }
.menu-min .nav-item { justify-content: center; padding: 9px 0; position: relative; }
.menu-min .nav-sep { margin: 10px 6px; }
/* El contador no se puede acomodar al lado del texto porque no hay texto: se monta
   sobre la esquina del icono. Sigue siendo el número y no un punto porque "3
   desvíos" y "12 desvíos" no se atienden igual. */
.menu-min .nav-badge {
  position: absolute; top: 1px; right: 1px; margin-left: 0;
  font-size: 9.5px; padding: 0 4px; line-height: 14px;
}
.menu-min .sidebar-foot { flex-direction: column; gap: 6px; padding: 10px 6px; }
.menu-min .pf-status { justify-content: center; }
/* Plegado no hay lugar para un encabezado con texto ni para el acordeón: los
   ítems de cada módulo pasan a ser iconos sueltos en la misma columna, igual
   que antes de agruparse. `display:contents` los saca del layout de
   `.nav-grupo-items` sin sacarlos del DOM: siguen siendo hijos de `.nav` para
   CSS y para el recorrido de `.nav-item` que ya hacen teclado.js y sesion.js. */
/* `.nav-grupo` también, y no sólo `.nav-grupo-items`: si sólo se destapa el de
   adentro, sus `.nav-item` promovidos quedan apilados dentro de `.nav-grupo`
   —que sigue siendo una caja normal— en vez de ser hijos directos de `.nav`. */
/* Con `.abierto` hay que repetirlo: el acordeón se lo pone al grupo de la
   pantalla activa aunque el menú esté plegado, y `.nav-grupo.abierto
   .nav-grupo-items { display: flex }` le gana por especificidad a la regla de
   acá abajo —tres clases contra dos— sin importar el orden en el archivo. */
.menu-min .nav-grupo,
.menu-min .nav-grupo-items,
.menu-min .nav-grupo.abierto .nav-grupo-items { display: contents; }
.menu-min .nav-grupo-cab,
.menu-min .nav-grupo-nota { display: none; }

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

.page { padding: 22px 28px 56px; max-width: 1400px; width: 100%; }

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
}
.page-title { margin: 0; font-size: 21px; font-weight: 650; letter-spacing: -.02em; }
.page-sub { margin: 3px 0 0; color: var(--text-soft); font-size: 13px; max-width: 68ch; }
.page-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* -------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px;
  border: 1px solid var(--border-strong);
  background: var(--bg-elev);
  color: var(--text);
  border-radius: var(--radius-sm);
  font-size: 13px; font-weight: 550;
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .06s;
  white-space: nowrap;
}
.btn svg { width: 15px; height: 15px; }
.btn:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--text-faint); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contrast);
}
.btn-primary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 87%, #000);
  border-color: color-mix(in srgb, var(--accent) 87%, #000);
}
.btn-danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }
.btn-danger:hover:not(:disabled) { background: var(--danger-soft); }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-ghost:hover:not(:disabled) { background: var(--bg-hover); border-color: transparent; }
.btn-sm { padding: 4px 9px; font-size: 12px; }

.btn-icon {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border: 1px solid transparent; background: transparent;
  border-radius: var(--radius-sm); cursor: pointer; color: var(--text-soft);
}
.btn-icon:hover { background: var(--bg-hover); color: var(--text); }
.btn-icon svg { width: 16px; height: 16px; }
.i-moon { display: none; }
:root[data-theme="dark"] .i-sun { display: none; }
:root[data-theme="dark"] .i-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .i-sun { display: none; }
  :root:not([data-theme="light"]) .i-moon { display: block; }
}

/* ---------------------------------------------------------------- cards -- */

.card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.card + .card { margin-top: 14px; }
.card-head {
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  /* Con `flex-wrap` el botón del encabezado baja a su propia línea antes que empujar
     el título afuera de la tarjeta: los botones son `white-space: nowrap` —no se
     encogen— y en el ancho de un teléfono un título de dos palabras más un "Editar"
     ya no entran en la misma fila. */
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap;
}
.card-title {
  font-size: 13px; font-weight: 650; letter-spacing: .01em; margin: 0;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.card-title svg { width: 14px; height: 14px; opacity: .6; }
/* El subtítulo ocupa su propia línea dentro del título flex. */
.card-title small { width: 100%; font-weight: 400; color: var(--text-faint); font-size: 11.5px; margin-top: 1px; }
.card-body { padding: 16px; }
.card-body.tight { padding: 0; }

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

/* El encabezado entero alterna la tarjeta (ver `plegables` en js/core.js), así
   que se comporta como algo apretable. El cursor va sobre el head y no sobre el
   `.card` para no marcar como clickeable también al cuerpo. */
.card[data-plegable] > .card-head { cursor: pointer; user-select: none; }
.card[data-plegable] > .card-head:hover { background: var(--bg-sunken); }

.card-plegar {
  flex: none; display: grid; place-items: center;
  width: 24px; height: 24px; padding: 0;
  background: none; border: none; border-radius: var(--radius-sm);
  color: var(--text-faint); cursor: pointer;
}
.card-plegar:hover { color: var(--text); background: var(--bg-elev); }
.card-plegar svg { width: 15px; height: 15px; transition: transform .15s; }

.card.plegada > .card-head { border-bottom: none; }
.card.plegada > .card-body { display: none; }
/* El chevron apunta abajo cuando está abierta —lo de abajo es el contenido— y a
   la izquierda cuando está plegada. */
.card.plegada .card-plegar svg { transform: rotate(-90deg); }

@media (prefers-reduced-motion: reduce) {
  .card-plegar svg { transition: none; }
  .nav-grupo-chevron { transition: none; }
}

/* -------------------------------------------------------------- conteo --- */

/* Cuántas filas trae el listado con los filtros puestos. Va chico y en gris entre
   la barra de filtros y la tabla: es la respuesta a lo que el operador acaba de
   preguntar con los filtros, no un titular. Reemplazó al tablero de tarjetas, que
   eran diez números fijos y cada uno un filtro disfrazado. */
.conteo {
  font-size: 11.5px; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  margin: 0 2px 8px;
}

/* --------------------------------------------------------------- pills --- */

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  border: 1px solid transparent;
}
.pill::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
/* Estados compuestos. El color acompaña el avance: gris cuando la orden todavía
   no arrancó, azul en viaje, y de ahí al verde a medida que se cierra el
   circuito administrativo. La anulada es la única que sale de la escala. */
.pill-e-asignado   { background: var(--bg-sunken);  color: var(--text-soft); border-color: var(--border); }
/* Pendiente de asignación: el borde punteado la separa de la escala de avance
   —todavía no empezó a avanzar— y es el mismo recurso que marca las colas de
   trabajo en el tablero. */
.pill-e-pendiente  { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); border-style: dashed; }
.pill-e-iniciado   { background: var(--info-soft);  color: var(--info); }
.pill-e-finalizado { background: var(--accent-soft); color: var(--accent-text); }
.pill-e-resuelto   { background: var(--warn-soft);  color: var(--warn); }
.pill-e-con-remito { background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ok); }
.pill-e-facturado  { background: var(--ok-soft);    color: var(--ok); }
.pill-e-anulada    { background: var(--danger-soft); color: var(--danger); }
/* Cerrada: el final del circuito. Sale de la escala de avance a propósito —es
   gris sólido, no verde— porque no es un paso más hacia adelante sino el punto
   en que la orden deja de moverse. */
.pill-e-cerrado    { background: var(--text-soft); color: var(--bg); border-color: transparent; }
.pill-plain { background: var(--bg-sunken); color: var(--text-soft); border-color: var(--border); }
.pill-plain::before { display: none; }

.tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 550; padding: 1px 7px;
  border-radius: 5px; background: var(--bg-sunken); color: var(--text-soft);
  border: 1px solid var(--border);
}
.tag-ok    { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.tag-warn  { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.tag-info  { background: var(--info-soft); color: var(--info); border-color: transparent; }
.tag-danger{ background: var(--danger-soft); color: var(--danger); border-color: transparent; }

/* ------------------------------------------------------------- filtros --- */

.filters {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-bottom: 12px;
}
.search {
  position: relative; flex: 1 1 300px; min-width: 220px; max-width: 460px;
}
.search svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--text-faint); pointer-events: none;
}
.search input { padding-left: 32px; width: 100%; }

/* El campo de texto de toda la aplicación.
   Va por descarte —todos los `input` menos los que se dibujan solos— y no por lista de
   tipos, que es como estaba y dejaba afuera a más de la mitad de los campos: el
   selector `input[type="text"]` NO alcanza a un `<input>` sin atributo `type`, que es
   como están escritos casi todos los del sistema —la razón social del cliente, el
   nombre del artículo, el CUIL del chofer—, y tampoco alcanzaba al email ni a la
   contraseña del login ni al momento de la carga de combustible.

   Lo que se veía era el dibujo del navegador: sin ancho declarado —o sea, el suyo, que
   son veinte caracteres y no entran en una columna de la grilla del celular—, con las
   esquinas cuadradas, con otro alto porque el aire de adentro es 2 px y no 7, y con el
   fondo del sistema. Y en el mismo formulario, al lado, un `type="number"` sí
   estilado: dos campos que hacen lo mismo y no se ven igual.

   Los excluidos son los que tienen dibujo propio y ninguna de estas propiedades les
   sirve: la casilla, el radio, el deslizador del radio de la geocerca, el selector de
   archivo —que tiene su regla más abajo, y por qué—, y los que no se ven. */
input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"],
          [type="hidden"], [type="submit"], [type="button"], [type="reset"],
          [type="image"], [type="color"]),
select, textarea {
  background: var(--bg-elev);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  font-size: 13px;
  width: 100%;
  transition: border-color .12s, box-shadow .12s;
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
  border-color: var(--text-faint);
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--bg-sunken); color: var(--text-faint); cursor: not-allowed;
}
/* El selector de archivo se quedó afuera de la regla de arriba —no es un `text`— y
   sin ancho declarado toma el suyo: el botón del navegador más el nombre del archivo
   elegido, en una línea que no corta. En el celular del chofer, con el nombre que le
   pone la cámara a la foto del remito, eso es más ancho que la pantalla; y como
   `min-width` en un ítem flex vale `auto`, tampoco lo dejaba encoger. El resultado
   no era sólo el campo desbordado: la página entera quedaba más ancha que la
   ventana, y el header —que mide 100% de la ventana— se cortaba antes del borde.

   `min-width: 0` es la mitad que importa; el 100% es para que se vea como los otros
   campos del formulario. */
input[type="file"] {
  width: 100%; max-width: 100%; min-width: 0;
  font-size: 13px;
}

textarea { resize: vertical; min-height: 62px; }
select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 8l3-3.5' fill='none' stroke='%238b95a5' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 12px;
  padding-right: 28px;
}
.field-inline { display: flex; align-items: center; gap: 7px; }
.field-inline label { font-size: 12px; color: var(--text-soft); white-space: nowrap; }
.field-inline input, .field-inline select { width: auto; min-width: 130px; }

/* --------------------------------------------------------------- tabla --- */

.table-wrap { overflow-x: auto; border-radius: var(--radius); }
table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
table.data th {
  text-align: left; font-weight: 600; font-size: 11.5px;
  color: var(--text-soft); text-transform: uppercase; letter-spacing: .04em;
  padding: 9px 12px;
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
  white-space: nowrap;
}
table.data td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
table.data tbody tr { transition: background .1s; }
table.data tbody tr:hover { background: var(--bg-hover); }
table.data tbody tr.clickable { cursor: pointer; }
table.data tbody tr:last-child td { border-bottom: none; }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mono { font-family: var(--mono); font-size: 12.5px; }
.nowrap { white-space: nowrap; }
.truncate { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.muted { color: var(--text-faint); }
.strong { font-weight: 600; }
/* Cantidad que resta. La usa el libro del pañol: en una columna donde conviven
   ingresos y egresos, el signo solo se pierde de vista al barrer la lista. */
.neg { color: var(--danger); }

.pagination {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 11px 14px; border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--text-soft); flex-wrap: wrap;
}
.pagination .pages { display: flex; gap: 6px; align-items: center; }

/* ------------------------------------------------------------- DataTable -- */

.dt-barra {
  display: flex; align-items: center; justify-content: flex-end; gap: 6px;
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.dt-btn {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; color: var(--text-soft);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-elev); padding: 4px 9px; cursor: pointer;
  transition: background .12s, color .12s;
}
.dt-btn:hover { background: var(--bg-hover); color: var(--text); }
.dt-btn svg { width: 13px; height: 13px; }

.dt-cols { position: relative; }
.dt-menu {
  position: absolute; right: 0; top: calc(100% + 5px); z-index: 30;
  min-width: 190px; max-height: 320px; overflow-y: auto;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: 5px;
}
.dt-menu-item {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 7px; border-radius: 5px; font-size: 12.5px; cursor: pointer;
}
.dt-menu-item:hover { background: var(--bg-hover); }
.dt-menu-item input { accent-color: var(--accent); cursor: pointer; margin: 0; }

.dt-scroll { overflow: auto; }
.dt-tabla th { position: relative; user-select: none; }
.dt-tabla th[draggable="true"] { cursor: grab; }
.dt-tabla th[draggable="true"]:active { cursor: grabbing; }
.dt-th { display: inline-flex; align-items: center; gap: 4px; }
.num .dt-th { flex-direction: row-reverse; }
.dt-ordenable .dt-th { cursor: pointer; }
.dt-ordenable:hover { color: var(--text); }
.dt-activa { color: var(--accent-text); }
.dt-flecha { font-style: normal; font-size: 10px; }

/* Handle de redimensión: franja angosta sobre el borde derecho del encabezado. */
.dt-resize {
  position: absolute; top: 0; right: 0; height: 100%; width: 6px;
  cursor: col-resize;
}
.dt-resize:hover { background: color-mix(in srgb, var(--accent) 45%, transparent); }

.dt-tabla tbody tr:nth-child(even) { background: color-mix(in srgb, var(--bg-sunken) 55%, transparent); }
.dt-tabla tbody tr:hover { background: var(--bg-hover); }

/* Fila marcada por el teclado.
   Gana sobre el :hover y sobre el rayado de las pares, que si no la tapan; y
   reemplaza al outline del foco, que alrededor de una <tr> queda cortado por las
   celdas y no se lee como "acá estoy". */
.dt-tabla tbody tr.dt-cursor,
.dt-tabla tbody tr.dt-cursor:hover { background: var(--accent-soft); }
.dt-tabla tbody tr.dt-cursor > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.dt-tabla tbody tr:focus, .dt-tabla tbody tr:focus-visible { outline: none; }

/* Ayuda de teclas de la barra: es lo que hace descubrible que la tabla se
   maneja con las flechas. Va al margen izquierdo, lejos de los botones. */
.dt-teclas {
  margin-right: auto; display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--text-faint); white-space: nowrap;
}
.dt-teclas svg { width: 13px; height: 13px; }
.dt-tabla[style*="fixed"] td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt-vacio { text-align: center; color: var(--text-faint); padding: 34px 16px !important; }

/* Filas desplegables. La columna del chevron es angosta y fija: si entra en el
   reordenado de columnas del DataTable, el usuario puede mandarla al final y
   dejar el control lejos de la fila que abre. */
.dt-exp-col { width: 30px; padding-right: 0 !important; }
.dt-exp {
  border: none; background: transparent; cursor: pointer; padding: 2px 4px;
  color: var(--text-soft); font-size: 11px; line-height: 1; border-radius: 3px;
}
.dt-exp:hover { background: var(--bg-hover); color: var(--text); }
table.data tbody tr.dt-abierta > td { background: var(--bg-hover); }
table.data tbody tr.dt-expansion > td { padding: 0 !important; background: var(--bg-sunken); }
.dt-expansion-cuerpo { padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.dt-expansion-cab { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dt-expansion-cab .grow { flex: 1; min-width: 0; }
.center { text-align: center; }

/* Celda que filtra al hacer clic. */
.dt-filtrable { cursor: pointer; }
.dt-filtrable:hover {
  color: var(--accent-text);
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}

/* ------------------------------------------------------------ MultiSelect -- */

.ms { position: relative; }
.ms-trigger {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-elev); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: 7px 10px;
  font-size: 13px; cursor: pointer; max-width: 230px;
  transition: border-color .12s, color .12s;
}
.ms-trigger:hover { border-color: var(--text-faint); }
.ms-resumen { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-chevron { opacity: .55; }
.ms-activo .ms-trigger {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-soft);
  font-weight: 550;
}

.ms-panel {
  position: absolute; left: 0; top: calc(100% + 5px); z-index: 40;
  width: 260px; padding: 8px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}
.ms-buscar { margin-bottom: 6px; }
.ms-acciones {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 3px 6px; margin-bottom: 4px; border-bottom: 1px solid var(--border);
}
.ms-limpiar {
  background: none; border: none; cursor: pointer; padding: 0;
  font-size: 11.5px; font-weight: 550; color: var(--accent-text);
}
.ms-limpiar:hover { text-decoration: underline; }
.ms-contador { font-size: 10.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.ms-lista { max-height: 230px; overflow-y: auto; }
.ms-item {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 6px; border-radius: 5px; font-size: 12.5px;
}
.ms-item:hover { background: var(--bg-hover); }
/* Opción marcada por el teclado: el foco se queda en la búsqueda del panel, así
   que esta marca es lo único que dice qué va a tildar el Enter. */
.ms-item.on, .ms-item.on:hover { background: var(--accent-soft); }
.ms-item input { accent-color: var(--accent); cursor: pointer; margin: 0; flex: none; }
.ms-solo {
  flex: 1; min-width: 0; text-align: left; cursor: pointer;
  background: none; border: none; padding: 0; font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ms-solo:hover { color: var(--accent-text); }
.ms-sin { text-align: center; color: var(--text-faint); font-size: 12.5px; padding: 10px 0; }

/* En un teléfono el filtro se lleva la fila entera y el panel cuelga de borde a borde.
   Los 260 px del panel son un ancho DECLARADO —no se encoge solo— y cuelgan del
   `left: 0` del disparador: con dos filtros en la misma fila, el segundo arranca a
   mitad de pantalla y su panel termina afuera, lo que ensancha la página y deja media
   lista de opciones del otro lado del borde.

   El `:has` es para el que manda el ancho, que no es el `.ms` sino el envoltorio que
   le toca a cada pantalla: unas lo meten en un `.field` y otras en un div pelado, y el
   ítem flex que hay que estirar es ese. Estirarlo tiene además el efecto de que la
   lista se abre debajo de un botón del ancho del dedo. */
@media (max-width: 640px) {
  .filters > *:has(.ms), .filters-row > *:has(.ms) { flex: 1 1 100%; }
  .ms { display: block; }
  .ms-trigger { width: 100%; max-width: none; justify-content: space-between; }
  .ms-panel { left: 0; right: 0; width: auto; }
}

.btn-limpiar {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  border-radius: var(--radius-sm); background: transparent;
  padding: 7px 12px; font-size: 12.5px; font-weight: 550;
  color: var(--danger); cursor: pointer; transition: background .12s;
}
.btn-limpiar:hover { background: var(--danger-soft); }
.btn-limpiar svg { width: 12px; height: 12px; }

.btn-export {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--bg-elev); padding: 7px 12px;
  font-size: 12.5px; font-weight: 600; color: var(--ok); cursor: pointer;
  transition: background .12s;
}
.btn-export:hover { background: var(--bg-hover); }
.btn-export svg { width: 13px; height: 13px; }

/* --------------------------------------------------------- autocompletar -- */

/* El componente envuelve al input para poder posicionar el panel debajo. */
.ac { position: relative; width: 100%; }
.ac-panel {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 60;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  max-height: 300px; overflow-y: auto; padding: 4px;
  /* Las sugerencias de equipo muestran tres datos por fila y no entran en el
     ancho de un campo de la grilla. */
  min-width: 320px;
}
/* …pero en un teléfono 320 px es MÁS que el campo, y más que la pantalla cuando el
   campo arranca corrido. El panel tiene `left: 0` y `right: 0`, así que con un ancho
   mínimo más grande que el hueco gana el mínimo, se estira hacia la derecha y se sale:
   adentro de un modal queda cortado por el borde y en el alta de una orden ensancha la
   página entera. Acá vale el ancho del campo y las tres columnas de la fila se
   envuelven, que es para lo que `.ac-fila` ya trae el `flex-wrap`. */
@media (max-width: 640px) {
  .ac-panel { min-width: 0; }
}
.ac-item {
  padding: 6px 8px; border-radius: 5px; cursor: pointer;
  font-size: 12.5px; line-height: 1.35;
}
.ac-item.on { background: var(--accent-soft); }
.ac-item.on .ac-principal { color: var(--accent-text); }
.ac-item b { font-weight: 700; color: var(--accent-text); }
.ac-fila { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ac-principal {
  font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.ac-patentes { font-size: 12px; white-space: nowrap; }
.ac-meta {
  margin-left: auto; font-size: 11px; color: var(--text-faint); white-space: nowrap;
}
.ac-vacio { padding: 12px 10px; font-size: 12.5px; color: var(--text-faint); text-align: center; }
.ac-pie {
  margin-top: 3px; padding: 5px 8px; border-top: 1px solid var(--border);
  font-size: 10.5px; color: var(--text-faint); text-align: right;
}

/* ----------------------------------------------------- selector de tramos */

.tf { display: flex; flex-direction: column; gap: 11px; }
.tf-barra { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; }
.tf-barra .search { max-width: none; }
.tf-lista {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  max-height: 48dvh; overflow: auto;
}
.tf-tabla { font-size: 12.5px; }
.tf-tabla th { padding: 7px 10px; }
.tf-tabla td { padding: 6px 10px; }
.tf-fila { cursor: pointer; }
/* Gana sobre el :hover de table.data, que si no pisa la fila marcada por teclado. */
.tf-tabla tbody tr.tf-fila.on,
.tf-tabla tbody tr.tf-fila.on:hover { background: var(--accent-soft); }
.tf-fila.on td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.tf-vacio { padding: 34px 18px; text-align: center; font-size: 13px; }
.tf-vacio p { margin: 0 0 5px; }
.tf-tope {
  padding: 8px 11px; border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-faint); text-align: center;
}
.tf-pie {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 11.5px; color: var(--text-faint); flex-wrap: wrap;
}
.tf-pie svg { width: 13px; height: 13px; vertical-align: -2px; }
.tf-teclas { white-space: nowrap; }

kbd {
  font-family: var(--mono); font-size: 10px;
  border: 1px solid var(--border-strong); border-bottom-width: 2px;
  border-radius: 4px; padding: 1px 4px; color: var(--text-faint);
  background: var(--bg-sunken); margin-left: 4px;
}

/* ---------------------------------------------------------- facturación -- */

/* La columna de las casillas: fija y angosta, para que el resto de la tabla no se
   corra según cuántas filas haya tildadas. */
.fa-sel { width: 34px; text-align: center; }
.fa-sel input { accent-color: var(--accent); cursor: pointer; margin: 0; width: 15px; height: 15px; }
/* La fila elegida, con el mismo realce que el cursor de la tabla del sistema: es lo
   que hace que al bajar la vista se vea de un golpe qué entra en la factura. */
.fa-tabla tbody tr.on, .fa-tabla tbody tr.on:hover { background: var(--accent-soft); }
.fa-tabla tbody tr.on > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.fa-importe { font-weight: 650; font-variant-numeric: tabular-nums; }

/* En un teléfono la fila pasa a ser una tarjeta, y acá no es por prolijidad: son nueve
   columnas y hacían falta unos 900 px, así que la tabla scrolleaba de costado con la
   CASILLA en un extremo y el IMPORTE con su botón «Cotizar» en el otro. Tildar una
   orden y ver por cuánto entra son las dos mitades del único gesto de esta pantalla, y
   estaban a dos arrastres de distancia. Apilada entran las dos juntas.

   La casilla y el número de orden comparten la primera línea —tildar y saber qué se
   tilda es una sola cosa—, así que esas dos celdas se ubican por posición y el resto
   toma el ancho entero con el nombre de su columna adelante, de `data-label`.

   Los selectores llevan `table.data` adelante porque el aire y la línea de la celda los
   pone `table.data td`, que es una clase y dos etiquetas y le gana a `.fa-tabla td`. */
@media (max-width: 720px) {
  table.data.fa-tabla thead { display: none; }
  table.data.fa-tabla, table.data.fa-tabla tbody { display: block; }
  table.data.fa-tabla tbody tr,
  table.data.fa-tabla tbody tr:hover {
    display: grid; grid-template-columns: auto minmax(0, 1fr);
    gap: 3px 10px; align-items: baseline;
    padding: 10px 12px; margin-bottom: 8px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--bg-elev);
  }
  table.data.fa-tabla tbody tr:last-child { margin-bottom: 0; }
  /* Tildada, la tarjeta entera se pinta: el filete de la izquierda que la marca en la
     tabla no se lee cuando la fila dejó de ser una fila. */
  table.data.fa-tabla tbody tr.on,
  table.data.fa-tabla tbody tr.on:hover {
    background: var(--accent-soft); border-color: var(--accent);
  }
  table.data.fa-tabla tbody tr.on > td:first-child { box-shadow: none; }

  table.data.fa-tabla tbody td,
  table.data.fa-tabla tbody tr:last-child td {
    grid-column: 1 / -1;
    display: flex; align-items: baseline; gap: 8px;
    padding: 0; border-bottom: none;
    white-space: normal; overflow: visible; max-width: none; text-align: left;
  }
  table.data.fa-tabla tbody td[data-label]::before {
    content: attr(data-label); flex: none; min-width: 96px;
    font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: var(--text-soft);
  }
  /* Las dos de la primera línea, por posición y no por etiqueta: son las únicas dos
     celdas de la fila que no la llevan. */
  table.data.fa-tabla tbody td:nth-child(1) {
    grid-column: 1; grid-row: 1; width: auto; justify-content: center;
  }
  table.data.fa-tabla tbody td:nth-child(2) {
    grid-column: 2; grid-row: 1; font-size: 14px;
  }
  /* La casilla es el blanco que se apunta con el dedo, y 15 px es la mitad de lo que
     hace falta. */
  table.data.fa-tabla tbody td.fa-sel input { width: 20px; height: 20px; }
  /* El importe cierra la tarjeta y es lo que se compara entre una y otra, así que se
     separa del bloque de datos y se lee más grande. */
  table.data.fa-tabla tbody td.fa-celda-importe {
    margin-top: 6px; padding-top: 6px;
    border-top: 1px dashed var(--border);
    font-size: 15px; flex-wrap: wrap;
  }
}

/* El pie con lo elegido. Se pega al borde de abajo y no queda al final de la tabla
   porque la lista es larga: con veinte órdenes, el total y el botón caerían fuera de
   la pantalla justo cuando hay más para revisar. Aparece recién con algo tildado, así
   que no le come alto a la lista mientras se mira. */
.fa-pie {
  /* El `env` lo sube arriba de la barra de gestos del iPhone, que si no le tapa el
     botón de facturar —que es el único que hay que apretar en esta pantalla—. */
  position: sticky; bottom: calc(12px + env(safe-area-inset-bottom)); z-index: 5;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 14px;
  padding: 11px 16px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.fa-pie-info { display: flex; flex-direction: column; gap: 1px; margin-right: auto; }
.fa-total { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; }
@media (max-width: 620px) {
  .fa-pie { gap: 9px; padding: 10px 12px; }
  .fa-total { font-size: 16px; }
  /* Apilado en tres líneas —qué está elegido, cuánto suma, y los dos botones— en vez de
     los cuatro bloques peleando por una fila de 300 px. El `margin-right: auto` del
     bloque de info es lo que en el escritorio pega los botones a la derecha, y acá
     empujaba a «Facturar» solo a una cuarta línea. */
  .fa-pie-info { flex: 1 1 100%; margin-right: 0; }
  .fa-total { flex: 1 1 100%; }
  .fa-pie .btn { flex: 1 1 auto; justify-content: center; }
}

/* ----------------------------------------------- chuleta de atajos (tecla ?) */

.atajos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 22px; }
.atajos h4 {
  margin: 0 0 7px; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-soft);
}
.atajos dl {
  margin: 0; display: grid; grid-template-columns: auto 1fr;
  align-items: baseline; gap: 5px 10px;
}
.atajos dt { justify-self: start; white-space: nowrap; }
.atajos dt kbd:first-child { margin-left: 0; }
.atajos dd { margin: 0; font-size: 12.5px; color: var(--text-soft); }
@media (max-width: 620px) { .atajos { grid-template-columns: 1fr; } }

/* -------------------------------------------------------------- stepper -- */

.stepper { display: flex; align-items: stretch; gap: 0; flex-wrap: wrap; }
.step {
  flex: 1 1 0; min-width: 132px;
  display: flex; align-items: center; gap: 9px;
  padding: 11px 13px;
  border: 1px solid var(--border);
  background: var(--bg-elev);
  position: relative;
  text-align: left;
  cursor: default;
}
.step:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.step:last-child  { border-radius: 0 var(--radius) var(--radius) 0; }
.step + .step { border-left: none; }
.step-num {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bg-sunken); color: var(--text-faint);
  font-size: 11px; font-weight: 650; border: 1px solid var(--border);
}
.step-num svg { width: 12px; height: 12px; }
.step-text { display: flex; flex-direction: column; min-width: 0; }
.step-text b { font-size: 12.5px; font-weight: 600; }
.step-text span { font-size: 11px; color: var(--text-faint); }
.step.done .step-num { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.step.current { background: var(--accent-soft); border-color: var(--accent); z-index: 1; }
.step.current .step-num { background: var(--accent); color: var(--accent-contrast); border-color: transparent; }
.step.current .step-text b { color: var(--accent-text); }
.step.actionable { cursor: pointer; }
.step.actionable:hover { background: var(--bg-hover); }
.step.current.actionable:hover { background: var(--accent-soft); }

/* ----------------------------------------------------------- formulario -- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 13px 14px;
}
.form-grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.field > label {
  font-size: 11.5px; font-weight: 600; color: var(--text-soft);
  display: flex; align-items: center; gap: 5px;
}
.field .hint { font-size: 11px; color: var(--text-faint); }
.field .err  { font-size: 11px; color: var(--danger); }
.field.span-2 { grid-column: span 2; }
.field.span-all { grid-column: 1 / -1; }
.req::after { content: "*"; color: var(--danger); font-weight: 700; }

.check {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 11px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); cursor: pointer;
  background: var(--bg-elev); font-size: 13px;
  transition: border-color .12s, background .12s;
}
.check:hover { border-color: var(--text-faint); }
.check input { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; margin: 0; flex: none; }
.check.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text); font-weight: 550; }

/* Selector de modo de tramo: reemplaza los radios sueltos del sistema viejo */
.segmented { display: inline-flex; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 2px; gap: 2px; }
.segmented button {
  border: none; background: transparent; cursor: pointer;
  padding: 5px 12px; border-radius: 5px;
  font-size: 12.5px; font-weight: 550; color: var(--text-soft);
  transition: background .12s, color .12s;
}
.segmented button:hover { color: var(--text); }
.segmented button.on { background: var(--bg-elev); color: var(--accent-text); box-shadow: var(--shadow-sm); font-weight: 600; }

/* Pestanas de "una de estas" con su numero al lado. Las usan el Modulo Logistica y el
   monitoreo de flota, que son las dos pantallas donde el numero de cada pestana ES la
   informacion: dice cuanto hay ahi antes de entrar. En un ancho de telefono la tira se
   desborda en vez de apretar los textos hasta romperlos. */
.segmented-num { margin-bottom: 14px; max-width: 100%; overflow-x: auto; }
.segmented-num button { white-space: nowrap; }
.segmented-num button em {
  font-style: normal; font-weight: 650; margin-left: 5px;
  font-variant-numeric: tabular-nums; color: var(--text-faint);
}
.segmented-num button.on em { color: inherit; }

/* Total calculado: el legacy usaba un recuadro rojo; acá es información, no alarma */
.total-box {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 11px 14px; border-radius: var(--radius-sm);
  background: var(--bg-sunken); border: 1px solid var(--border);
}
.total-box .label { font-size: 12px; color: var(--text-soft); font-weight: 550; }
.total-box .value { font-size: 18px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.total-box.accent { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
.total-box.accent .value { color: var(--accent-text); }

/* Bloque de campos que este sistema no gestiona (referencia a Sigma) */
.readonly-zone {
  background: var(--bg-sunken);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 13px;
}
.readonly-zone .zone-note {
  font-size: 11.5px; color: var(--text-faint); margin-bottom: 11px;
  display: flex; align-items: flex-start; gap: 6px;
}
.readonly-zone .zone-note svg { width: 14px; height: 14px; flex: none; margin-top: 1px; }

/* --------------------------------------------------------------- banner -- */

.banner {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 13px; border-radius: var(--radius-sm);
  font-size: 12.5px; line-height: 1.45;
  border: 1px solid transparent;
}
.banner svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }
.banner-info   { background: var(--info-soft);   color: var(--info); }
.banner-warn   { background: var(--warn-soft);   color: var(--warn); }
.banner-danger { background: var(--danger-soft); color: var(--danger); }
.banner-ok     { background: var(--ok-soft);     color: var(--ok); }
.banner b { font-weight: 650; }
.banner ul { margin: 5px 0 0; padding-left: 18px; }
.banner + .banner { margin-top: 8px; }

/* ------------------------------------------------------------- dropzone -- */

.dropzones { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }
.dropzone {
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius);
  padding: 26px 20px;
  text-align: center;
  background: var(--bg-elev);
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .1s;
}
.dropzone:hover { border-color: var(--accent); background: var(--accent-soft); }
.dropzone.over  { border-color: var(--accent); background: var(--accent-soft); transform: scale(1.01); }
.dropzone.busy  { pointer-events: none; opacity: .65; }
.dropzone-icon {
  width: 42px; height: 42px; margin: 0 auto 11px;
  border-radius: 11px; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-text);
}
.dropzone-icon svg { width: 21px; height: 21px; }
.dropzone h3 { margin: 0 0 4px; font-size: 14px; font-weight: 650; }
.dropzone p { margin: 0; font-size: 12.5px; color: var(--text-soft); }
.dropzone .formats { margin-top: 9px; font-size: 11px; color: var(--text-faint); }

/* ---------------------------------------------------------------- misc --- */

.empty {
  padding: 46px 24px; text-align: center; color: var(--text-faint);
}
.empty-icon {
  width: 42px; height: 42px; margin: 0 auto 12px; opacity: .45;
}
.empty-icon svg { width: 100%; height: 100%; }
.empty h3 { margin: 0 0 5px; font-size: 14.5px; font-weight: 600; color: var(--text-soft); }
.empty p { margin: 0; font-size: 13px; max-width: 46ch; margin-inline: auto; }

.loading-shell { display: grid; place-items: center; padding: 80px 0; }
.spinner {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2.5px solid var(--border);
  border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.btn .spinner { width: 13px; height: 13px; border-width: 2px; }

.skeleton {
  background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--bg-hover) 50%, var(--bg-sunken) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.3s infinite;
  border-radius: 5px; height: 13px;
}
@keyframes shimmer { to { background-position: -200% 0; } }

.grid-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; }
.grid-detail { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 14px; align-items: start; }
@media (max-width: 1080px) {
  .grid-detail, .grid-2 { grid-template-columns: minmax(0, 1fr); }
}

.kv { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; font-size: 12.5px; }
.kv dt { color: var(--text-soft); }
.kv dd { margin: 0; text-align: right; font-weight: 550; font-variant-numeric: tabular-nums; }

.list-plain { list-style: none; margin: 0; padding: 0; }
.list-plain li {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; border-bottom: 1px solid var(--border); font-size: 13px;
}
.list-plain li:last-child { border-bottom: none; }

.stack { display: flex; flex-direction: column; gap: 14px; }
.row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.row-end { margin-left: auto; }
.sticky-actions {
  position: sticky; bottom: 0;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--border);
  /* El aire de abajo se le suma el recorte del sistema: pegada al borde inferior, la
     barra de gestos del iPhone se come la mitad de los botones. */
  padding: 12px 0 calc(12px + env(safe-area-inset-bottom));
  margin-top: 18px;
  display: flex; gap: 9px; align-items: center; flex-wrap: wrap;
  z-index: 5;
}

/* -------------------------------------------------------------- toasts --- */

/* El aviso se corre arriba de la barra de gestos y adentro de la franja segura, igual
   que el de versión nueva: instalada en un iPhone, un toast pegado al borde de abajo
   queda partido por la barra y el texto de la segunda línea no se lee. */
.toasts {
  position: fixed; z-index: 200;
  bottom: calc(18px + env(safe-area-inset-bottom));
  right: calc(18px + env(safe-area-inset-right));
  display: flex; flex-direction: column; gap: 8px; max-width: 380px;
}
.toast {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 13px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  font-size: 13px;
  animation: slide-in .2s ease-out;
}
.toast.ok     { border-left-color: var(--ok); }
.toast.warn   { border-left-color: var(--warn); }
.toast.danger { border-left-color: var(--danger); }
.toast svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }
.toast.ok svg { color: var(--ok); }
.toast.warn svg { color: var(--warn); }
.toast.danger svg { color: var(--danger); }
.toast-body { min-width: 0; }
.toast-body b { display: block; font-weight: 600; margin-bottom: 1px; }
.toast-body span { color: var(--text-soft); font-size: 12.5px; word-break: break-word; }
@keyframes slide-in { from { opacity: 0; transform: translateX(16px); } }

/* --------------------------------------------------------------- modal --- */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 150;
  background: rgba(10, 13, 18, .5);
  backdrop-filter: blur(2px);
  display: grid; place-items: center;
  padding: 20px;
  animation: fade-in .14s ease-out;
}
@keyframes fade-in { from { opacity: 0; } }
.modal {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%; max-width: 520px;
  /* `dvh` y no `vh`: en el navegador de un celular `vh` mide la ventana SIN la barra
     de direcciones, que es más alta que lo que se ve mientras la barra está a la
     vista. Con `88vh` el pie del modal —los botones de Cancelar y Guardar— caía abajo
     del borde visible, y como el fondo es fijo no había cómo scrollear hasta él: se
     salía del diálogo tocando afuera. */
  max-height: 88dvh; display: flex; flex-direction: column;
  animation: pop .16s ease-out;
}
@keyframes pop { from { opacity: 0; transform: scale(.97) translateY(6px); } }
.modal.wide { max-width: 820px; }
.modal-head {
  padding: 15px 18px; border-bottom: 1px solid var(--border);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
}
.modal-head h2 { margin: 0; font-size: 15.5px; font-weight: 650; }
.modal-head p { margin: 3px 0 0; font-size: 12.5px; color: var(--text-soft); }
.modal-body { padding: 18px; overflow-y: auto; }
.modal-foot {
  padding: 13px 18px; border-top: 1px solid var(--border);
  display: flex; gap: 9px; justify-content: flex-end; flex-wrap: wrap;
}

/* En un teléfono los 20 px de aire de cada lado son 40 de los 360 que hay, y el
   formulario de adentro los paga en el ancho de sus campos. Se bajan a 12 y se les
   suma el recorte de la pantalla: instalada en un iPhone la aplicación dibuja abajo
   del notch y arriba de la barra de gestos, así que sin esto el diálogo queda con una
   esquina tapada —y en horizontal, con el borde entero de un lado—. */
@media (max-width: 640px) {
  .modal-backdrop {
    padding: calc(12px + env(safe-area-inset-top)) calc(12px + env(safe-area-inset-right))
             calc(12px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
  }
  .modal-head, .modal-body, .modal-foot { padding-left: 14px; padding-right: 14px; }
}

/* opciones de radio grandes (modo de importación) */
.radio-card {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 13px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); cursor: pointer;
  transition: border-color .12s, background .12s;
}
.radio-card:hover { border-color: var(--text-faint); }
.radio-card.on { border-color: var(--accent); background: var(--accent-soft); }
.radio-card input { margin-top: 2px; accent-color: var(--accent); flex: none; }
.radio-card b { display: block; font-size: 13px; font-weight: 600; }
.radio-card span { font-size: 12px; color: var(--text-soft); }
.radio-card + .radio-card { margin-top: 8px; }

/* barra de resumen de importación */
.summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.summary-item {
  padding: 12px 13px; border-radius: var(--radius-sm);
  background: var(--bg-sunken); border: 1px solid var(--border);
}
.summary-item .n { font-size: 21px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.summary-item .l { font-size: 11.5px; color: var(--text-soft); font-weight: 550; }
.summary-item.new    { background: var(--ok-soft);   border-color: transparent; }
.summary-item.new .n { color: var(--ok); }
.summary-item.exist  { background: var(--info-soft); border-color: transparent; }
.summary-item.exist .n { color: var(--info); }
.summary-item.err    { background: var(--danger-soft); border-color: transparent; }
.summary-item.err .n { color: var(--danger); }
.summary-item.warn   { background: var(--warn-soft); border-color: transparent; }
.summary-item.warn .n { color: var(--warn); }

/* En un teléfono el menú lateral sigue siendo una columna al costado, como en la
   compu: no se acuesta arriba. Por defecto es un RIEL angosto de iconos —lo mismo
   que `.menu-min` ya dibuja en escritorio cuando alguien pliega el menú—, y tocar
   el logo lo despliega tapando el contenido, con etiquetas y acordeón, como el
   sidebar de escritorio expandido. Se cierra tocando el logo de nuevo, tocando
   afuera (`#menu-scrim`, ver index.html y js/app.js) o eligiendo una pantalla.

   Hubo una versión que lo acostaba arriba como header: con las diecisiete pantallas
   habilitadas de un administrador entraban cinco de un vistazo y el resto quedaba
   sin etiqueta ni acordeón. Parado al costado entran más de un vistazo y, plegado,
   ocupa 58px en vez de los 48px de alto que le sacaba el header a las tablas.

   Los selectores llevan `.sidebar` adelante a propósito: tienen que ganarle a las
   reglas de `.menu-min`, que son de dos clases y quedan activas en el celular si el
   usuario dejó el menú plegado en el escritorio. Para el estado desplegado se usa
   `.sidebar.desplegado` —tres clases entre selector y regla— que le gana a las dos
   anteriores sin depender del orden en la hoja. */
@media (max-width: 860px) {
  /* Ancho del riel plegado y del panel desplegado. El desplegado no es fijo: en un
     teléfono muy angosto 260px no entra, y `min()` lo achica antes que desbordar. */
  :root { --riel-w: 58px; --panel-w: min(78vw, 260px); }

  .app { padding-left: calc(var(--riel-w) + env(safe-area-inset-left)); }

  .sidebar {
    /* `fixed` y no `sticky`: un elemento sticky mide 100% de su contenedor en flujo y
       se corre con el scroll horizontal de la página, así que cualquier tabla ancha
       lo empuja fuera de vista. Fijo al viewport se queda parado pase lo que pase
       en el contenido. El resto de la altura sale de `top:0; bottom:0`, no de un
       `height` fijo, porque acá —a diferencia del header que reemplaza— el alto es
       el de la pantalla entera y no algo que haya que declarar aparte. */
    position: fixed; top: 0; left: 0; bottom: 0; right: auto; z-index: 60;
    width: var(--riel-w); flex: none;
    /* Instalada en un iPhone, el riel arranca a la derecha del notch y no se lo tapa
       un gesto de borde izquierdo. */
    padding-left: env(safe-area-inset-left);
    padding-bottom: env(safe-area-inset-bottom);
    border-right: 1px solid var(--border); border-bottom: none;
    transition: width .18s ease;
  }
  /* Desplegado, el mismo elemento se ensancha tapando el contenido en vez de
     empujarlo: en un teléfono no hay ancho de sobra para correr el mapa o la tabla
     de al lado, y volver a acomodarlos en cada toque del logo sería más trabajo que
     el menú mismo. */
  .sidebar.desplegado { width: var(--panel-w); box-shadow: var(--shadow-lg); }

  .sidebar .brand {
    flex-direction: column; gap: 6px;
    padding: calc(10px + env(safe-area-inset-top)) 4px 8px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
  }
  /* "Órdenes de Carga y Remitos" no entra al lado del logo con el riel angosto, y
     el logo ya dice de qué aplicación se trata. Plegar/desplegar el menú de
     escritorio no significa nada acá —tocar el logo hace lo mismo—, así que el
     botón sólo estorbaría. */
  .sidebar .brand-text,
  .sidebar .menu-toggle { display: none; }
  .sidebar.desplegado .brand {
    flex-direction: row; align-items: center; gap: 10px;
    padding: calc(14px + env(safe-area-inset-top)) 14px 14px 16px;
  }
  .sidebar.desplegado .brand-text { display: flex; }

  .sidebar .nav {
    padding: 10px 7px; align-items: center;
    overflow-y: auto; overflow-x: hidden;
    scrollbar-width: none;
    /* Sin barra de scroll no queda ninguna pista de que hay más iconos más abajo —acá
       el equivalente del degradado que antes recortaba el borde derecho del header. */
    mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
    scroll-padding-block-end: 22px;
  }
  .sidebar .nav::-webkit-scrollbar { display: none; }
  .sidebar .nav-item { justify-content: center; width: 100%; padding: 9px 0; position: relative; }
  .nav-item span { display: none; }
  .nav-sep { display: none; }
  .sidebar .nav-badge {
    position: absolute; top: 2px; right: 8px; margin-left: 0;
    font-size: 9.5px; padding: 0 4px; line-height: 14px;
  }
  /* Ni acordeón ni encabezados en el riel: los ítems de cada módulo se suman sueltos
     a la columna de iconos —el mismo tratamiento que `.menu-min` en escritorio. */
  .sidebar .nav-grupo-cab,
  .sidebar .nav-grupo-nota { display: none; }
  .sidebar .nav-grupo,
  .sidebar .nav-grupo-items,
  .sidebar .nav-grupo.abierto .nav-grupo-items { display: contents; }

  /* Desplegado, el menú vuelve a ser el de escritorio: etiquetas, separadores y
     acordeón de a un módulo abierto por vez. */
  .sidebar.desplegado .nav {
    align-items: stretch; padding: 10px 8px;
    mask-image: none; scroll-padding-block-end: 0;
  }
  .sidebar.desplegado .nav-item {
    justify-content: flex-start; width: auto; padding: 8px 10px;
  }
  .sidebar.desplegado .nav-item span { display: inline; }
  .sidebar.desplegado .nav-sep { display: block; }
  .sidebar.desplegado .nav-badge { position: static; margin-left: auto; }
  .sidebar.desplegado .nav-grupo-cab,
  .sidebar.desplegado .nav-grupo-nota { display: flex; }
  .sidebar.desplegado .nav-grupo-items { display: none; }
  .sidebar.desplegado .nav-grupo.abierto .nav-grupo-items { display: flex; }

  .sidebar .sidebar-foot {
    flex-direction: column; align-items: center;
    gap: 8px; padding: 8px 4px calc(10px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--border);
  }
  /* Desplegado hay ancho de sobra: vuelve a estirarse como en escritorio en vez de
     quedar centrado en una columna angosta. */
  .sidebar.desplegado .sidebar-foot {
    align-items: stretch;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  }
  .sidebar .foot-row { flex-direction: column; gap: 8px; }
  /* Sin esto el punto de Powerfleet se estira para llenar la columna: la regla de
     base es para el pie horizontal de escritorio (`flex: 1` en una fila), y en
     columna ese mismo `flex-basis` crece a lo alto en vez de a lo ancho. */
  .sidebar .foot-row .pf-status { flex: none; }
  /* Sobre el estado de Powerfleet no se puede accionar desde un celular y los atajos
     de teclado no existen sin teclado: quedan ocultos plegado o desplegado. Plegado
     además no hay lugar para la palabra "Powerfleet", sólo para el punto de color. */
  .sidebar #atajos-toggle { display: none; }
  .sidebar .pf-label { display: none; }
  .sidebar.desplegado .pf-label { display: inline; }
  .sidebar.desplegado .foot-row { flex-direction: row; }
  /* Del bloque del usuario queda el avatar: el nombre y el rol se ven adentro del
     menú desplegado. */
  .sidebar .user-box { width: 100%; }
  .sidebar .user-txt,
  .sidebar .user-chevron { display: none; }
  .sidebar.desplegado .user-txt,
  .sidebar.desplegado .user-chevron { display: flex; }
  /* Estas tres llevan `.app` adelante para ganarle a las reglas de `.menu-min` del
     bloque de sesión, que están más abajo en el archivo y con la misma
     especificidad le ganarían por orden. Plegado el menú del usuario se abre AL
     COSTADO —mismo criterio que `.menu-min .user-menu` en escritorio, no hay
     lugar arriba del avatar—; desplegado vuelve a abrirse arriba, a todo el ancho. */
  .app .sidebar .user-btn { justify-content: center; padding: 6px 0; }
  .app .sidebar .user-menu { left: calc(100% + 6px); right: auto; bottom: 0; width: 210px; }
  .app .sidebar.desplegado .user-btn { justify-content: flex-start; padding: 7px 8px; }
  .app .sidebar.desplegado .user-menu { left: 0; right: 0; bottom: calc(100% + 6px); width: auto; }

  /* La cortina que se toca para cerrar el menú desplegado. Vive fuera de `.sidebar`
     en el HTML —hermana suya, ver index.html— así que alcanza con mirar si el
     hermano de al lado tiene `.desplegado`; no hace falta que js/app.js le toque
     una clase aparte. Tapa el contenido pero no el riel: por eso el `inset` no
     empieza en 0 sino después de `--riel-w`, y así el riel se seguiría pudiendo
     tocar para cerrar aunque el `pointer-events` de acá alcanzara más lejos. */
  .menu-scrim {
    display: block;
    position: fixed; top: 0; right: 0; bottom: 0; left: var(--riel-w); z-index: 55;
    background: rgba(10, 12, 16, .42);
    opacity: 0; pointer-events: none;
    transition: opacity .18s ease;
  }
  .sidebar.desplegado ~ .menu-scrim { opacity: 1; pointer-events: auto; }

  /* Sin header propio, nadie reserva el hueco del notch arriba del contenido: antes
     lo hacía el alto fijo del header. Se lo suma acá, al padding de siempre. */
  .page {
    padding: calc(16px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right))
             calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  }
  /* En un teléfono no hay flechas que mostrar, y la barra de la tabla necesita
     todo el ancho para los dos botones que sí sirven ahí. */
  .dt-teclas { display: none; }

  /* El chevron que despliega la fila es el único gesto de la tabla en un teléfono
     —no hay teclado y el resto de la fila abre la orden—, y con 11 px de tipografía y
     2 px de aire el blanco quedaba de 16×20: se le pasa el dedo por al lado y en vez
     de la ficha se abre la orden. Acá ocupa el alto de la fila. */
  .dt-exp { padding: 9px 7px; font-size: 13px; }
  .dt-exp-col { width: 36px; }

  /* Los botones chicos son los de las filas —Editar, Restaurar, la papelera— y con
     4 px de aire arriba y abajo miden 24: es el alto de una franja, no de un blanco
     para el dedo, y están pegados de a dos. En un teléfono el alto de la fila importa
     menos que no apretar el que borra queriendo apretar el que edita. */
  .btn-sm { padding: 7px 12px; }

  /* El contenido NO se recorta. Hubo una versión con `overflow-x: clip` acá para
     que un desborde no ensanchara la página, y el remedio era peor: quedaban
     cortados el mapa, el remito y el botón de llegada, que es lo que el chofer
     necesita. Con el riel fijo al viewport el desborde del contenido no lo mueve
     ni lo tapa, así que si algo se pasa de ancho se ve —scrolleando— y se arregla
     en el componente, que es donde está el bug. */

  /* Que no se pase de ancho por una palabra sin espacios: el nombre de una planta,
     un número de remito largo o una dirección pegada de OSM. Es la fuente de
     desborde más común y la que nadie ve venir hasta que aparece en producción. */
  .chofer, .chofer-card, .page { overflow-wrap: anywhere; }
}

/* ==========================================================================
   Flujo nuevo: marcas, itinerario y armador de tramos con mapa
   ========================================================================== */

/* ------------------------------------------------------- utilidades ------- */

.page.narrow { max-width: 880px; }
.grow { flex: 1; min-width: 0; }
.small  { font-size: 12px; }
.xsmall { font-size: 11px; }
.ta-right { text-align: right; }
.p-8  { padding: 8px; }
.p-12 { padding: 12px; }
.mt-6 { margin-top: 6px; }
.mt-8 { margin-top: 8px; }
/* Para resaltar un dato dentro de un texto: "en curso", "fuera de ruta",
   "falta el remito". El color va del tema, así que funciona en claro y en
   oscuro. Las tres existen porque las tres se usan: `txt-ok` la venía usando
   "estás en la zona" de la pantalla del chofer sin estar definida, y salía del
   color del texto común. */
.txt-ok     { color: var(--ok); }
.txt-warn   { color: var(--warn); }
.txt-danger { color: var(--danger); }
/* El cian de la marca del chofer en el mapa de una orden. Va con el valor escrito y no
   con una variable del tema porque tiene que ser EXACTAMENTE el color del pin —es su
   leyenda—, y el pin lo dibuja Leaflet sobre los tiles, que son siempre claros. Ver
   COLOR_CHOFER en js/mapa.js. */
.txt-chofer { color: #0891b2; }
/* El violeta del recorrido real que va sobre la ruta ideal, por lo mismo que el cian:
   la leyenda tiene que estar EXACTAMENTE en el color de la línea que nombra, y esa
   línea la dibuja Leaflet sobre los tiles. Ver COLOR_EN_RUTA en js/mapa.js. */
.txt-en-ruta { color: #7c3aed; }
.sep { border: none; border-top: 1px solid var(--border); margin: 10px 0; }
.card-head h2 { margin: 0; font-size: 13.5px; font-weight: 650; }
.card-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 13px 16px; border-top: 1px solid var(--border); background: var(--bg-sunken);
}
.btn-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-soft); text-decoration: none; margin-bottom: 6px;
}
.btn-link:hover { color: var(--accent-text); }
.btn-link svg { width: 13px; height: 13px; }

/* Grilla de 12 columnas para los formularios de los modales. */
.grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 12px; }
.col-2  { grid-column: span 2; }
.col-3  { grid-column: span 3; }
.col-4  { grid-column: span 4; }
.col-6  { grid-column: span 6; }
.col-12 { grid-column: span 12; }

/* En el celular la grilla pasa a dos columnas. Doce no entran: un `col-3` en una
   pantalla de 360px queda de 78px y un `input[type=date]` no puede achicar el
   `dd/mm/aaaa` que dibuja el navegador, así que el texto se le sale por encima
   del borde y se pisa con el campo de al lado —lo que se veía en la fecha y la
   hora del alta de orden—.
   Dos columnas y no una sola para que fecha y hora, que son un dato partido en
   dos, sigan yendo juntas: los campos angostos (2, 3 y 4) toman media pantalla y
   los que ya eran anchos (6 y 12) la toman entera, con lo que cada `hint` cae
   debajo de su campo en vez de al lado. */
@media (max-width: 640px) {
  .grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .col-2, .col-3, .col-4 { grid-column: span 1; }
  .col-6, .col-12 { grid-column: span 2; }
}

.input-icon { position: relative; display: flex; align-items: center; }
.input-icon svg {
  position: absolute; left: 10px; width: 14px; height: 14px;
  color: var(--text-faint); pointer-events: none;
}
.input-icon input { padding-left: 31px; width: 100%; }

.field-note { font-size: 11px; color: var(--text-faint); min-height: 14px; }
.field-note.ok   { color: var(--ok); }
.field-note.warn { color: var(--warn); }
.hint-ok   { color: var(--ok) !important; }
.hint-warn { color: var(--warn) !important; }

/* ------------------------------------------------- filtros por marca ------ */

.filters-row { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }
.filters-row + .filters-row { margin-top: 10px; }
.filters-marcas { align-items: center; }
.filters-label { font-size: 11.5px; font-weight: 600; color: var(--text-soft); }

/* Filtro de tres estados. Existe porque la columna Estado colapsa las marcas y
   sin esto no habría forma de pedir "facturadas sin remito físico". */
.tri {
  display: inline-flex; align-items: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-sunken); overflow: hidden;
}
.tri-label {
  font-size: 11.5px; color: var(--text-soft); font-weight: 550;
  padding: 0 8px; white-space: nowrap;
}
.tri button {
  border: none; background: transparent; cursor: pointer;
  padding: 4px 9px; font-size: 11.5px; color: var(--text-faint);
  border-left: 1px solid var(--border);
}
.tri button:hover { color: var(--text); background: var(--bg-hover); }
.tri button.on { background: var(--accent); color: var(--accent-contrast); font-weight: 600; }

/* --------------------------------------------------------- marcas --------- */

.marcas-linea { display: flex; gap: 6px; margin-top: 8px; }
.chip-marca {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; padding: 2px 8px;
  border-radius: 999px; border: 1px solid var(--border);
  background: var(--bg-sunken); color: var(--text-faint);
}
.chip-marca i {
  width: 7px; height: 7px; border-radius: 50%;
  border: 1.5px solid currentColor; background: transparent;
}
.chip-marca.on { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.chip-marca.on i { background: currentColor; }

/* --------------------------------------------------------- detalle -------- */

.detalle {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 14px; align-items: start;
}
.detalle-col { min-width: 0; }

.dato {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 6px 0; border-bottom: 1px dashed var(--border); font-size: 12.5px;
}
.dato:last-child { border-bottom: none; }
.dato span { color: var(--text-soft); }
.dato b { font-weight: 550; text-align: right; font-variant-numeric: tabular-nums; }

.remito {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}
.remito:last-child { border-bottom: none; }
/* Más de una foto en el mismo remito: los links se envuelven en su propia fila
   para no desbordar cuando son varios. */
.remito-archivos { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }

/* ----------------------------------------------- la pantalla del chofer --- */

/* Es la única vista pensada para un celular en una cabina, y eso decide el tamaño de
   todo: el botón que se aprieta con guantes, el texto que se lee de reojo y una sola
   columna, porque no hay ancho para dos ni manos libres para dos decisiones. */
.chofer { max-width: 640px; margin: 0 auto; padding: 14px 14px 28px; }
.chofer-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
  margin-bottom: 12px;
}
.chofer-head h1 { font-size: 19px; margin: 0; line-height: 1.25; }
.chofer-head-btns { display: flex; gap: 6px; flex: none; }
/* El ahorro de datos prendido se marca en el botón y no en un cartel: es un estado que
   dura horas, y un cartel que avisa todo el día se vuelve parte del fondo. */
#mv-datos.ahorrando { color: var(--warn); border-color: currentColor; }
/* Los dos avisos de la cabecera —que no se pudo actualizar, y el de la acción que el
   chofer acaba de intentar— separados de lo que explican: el .banner no trae margen
   propio y sin esto quedan pegados al mapa. */
#mv-viejo .banner, #mv-aviso .banner { margin-bottom: 12px; }
.chofer-h2 { font-size: 13.5px; margin: 0 0 8px; color: var(--text-soft); }

.chofer-card {
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 13px; margin-bottom: 12px;
}
.chofer-mapa {
  height: 260px; border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; margin-bottom: 12px;
}

.chofer-datos { display: grid; grid-template-columns: 1fr 1fr; gap: 9px 12px; margin-top: 11px; }
.chofer-datos > div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.chofer-datos span { font-size: 11px; color: var(--text-faint); }
.chofer-datos b { font-size: 14px; }

/* Las observaciones de la orden son instrucciones para el chofer —por qué portón entrar,
   a quién buscar— así que van resaltadas y no en el gris de los metadatos. */
.chofer-obs {
  display: flex; gap: 7px; margin-top: 11px; padding: 9px 10px;
  background: var(--info-soft); color: var(--info-text, var(--text));
  border-radius: var(--radius-sm); font-size: 13px; line-height: 1.4;
}

/* 52 px de alto y ancho completo: es el único control de la pantalla y se aprieta de pie,
   al costado del camión, a veces con guantes. Un botón del tamaño de los de escritorio
   obligaría a apuntar. */
.chofer-btn {
  width: 100%; min-height: 52px; font-size: 15.5px; font-weight: 600;
  justify-content: center;
}
/* La guía de ruta: el estado respecto del recorrido y cuánto falta. Se lee de un
   vistazo mientras se maneja, así que la etiqueta y los km van en la misma línea y con
   el cuerpo más grande que el resto de los metadatos. Envuelve en pantallas angostas en
   vez de recortar los km, que son el dato. */
.chofer-guia {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: 14.5px; line-height: 1.35;
}
/* Los resultados del buscador de "Nuevo viaje": una lista de tramos entre los
   que elegir, no un formulario con sus propios campos. Toca uno para
   marcarlo, que es lo único que se hace acá antes de "Pedir viaje". */
.tramo-opt {
  display: block; width: 100%; text-align: left;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 9px 12px; margin-top: 6px; font: inherit; color: inherit; cursor: pointer;
}
.tramo-opt:hover { border-color: var(--text-faint); }
.tramo-opt.on { background: var(--accent-soft); border-color: var(--accent); }
.tramo-opt b { display: block; font-size: 13.5px; }

.chofer-listo { text-align: center; }
.chofer-vacio { text-align: center; padding: 34px 16px; color: var(--text-soft); }
.chofer-vacio h2 { font-size: 17px; margin: 10px 0 6px; color: var(--text); }
.chofer-vacio p { margin: 0; font-size: 13.5px; line-height: 1.5; }

/* En un teléfono el mapa se lleva más alto: es donde el chofer mira si está entrando al
   círculo, y 260 px sobre una pantalla vertical dejan la mitad de la información afuera. */
@media (max-width: 640px) {
  /* La pantalla del chofer no vive dentro de `.page`, así que el recorte del sistema
     se lo tiene que sumar ella. */
  .chofer {
    padding: 12px calc(11px + env(safe-area-inset-right))
             calc(26px + env(safe-area-inset-bottom)) calc(11px + env(safe-area-inset-left));
  }
  .chofer-mapa { height: 300px; }
  .chofer-datos { grid-template-columns: 1fr; }
}

/* ------------------------------------------- el acceso del chofer --------- */

/* El panel de la ficha desde donde se le da acceso a la aplicación. Va separado de la
   documentación con una línea porque es otra cosa: si puede entrar, no si puede manejar. */
.acceso { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.acceso-caja {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; background: var(--bg-sunken);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}

/* ------------------------------------------------------- itinerario ------- */

.itinerario { display: flex; flex-direction: column; gap: 8px; }
.itin {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-sunken);
}
.itin.hecha { background: var(--ok-soft); border-color: transparent; }
/* El tramo desviado que se está mirando solo en el mapa. El borde y no el fondo:
   el fondo ya dice si el tramo está cerrado, y son dos cosas distintas. */
.itin-sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.itin-num, .tn-num {
  display: grid; place-items: center; flex: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--bg-elev); border: 1px solid var(--border);
  font-size: 11.5px; font-weight: 650;
}
.itin.hecha .itin-num { background: var(--ok); color: var(--accent-contrast); border-color: transparent; }
.itin-ok { font-size: 11.5px; color: var(--ok); font-weight: 550; margin-top: 2px; }
/* La geocerca del maestro ya no es la que el viaje congeló. En warn y no en danger:
   el viaje sigue funcionando, lo que pasa es que detecta contra el círculo viejo. */
.itin-viejo { font-size: 11.5px; color: var(--warn); font-weight: 550; margin-top: 2px; }
/* Una parada puede ofrecer dos correcciones a la vez —la hora y la geocerca—, así que
   los botones van en su propia caja y no como hijos directos del flex de .itin. */
.itin-acciones { display: flex; align-items: center; gap: 4px; flex: none; }
.itin-editar { margin-top: 4px; }

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

.timeline { display: flex; flex-direction: column; }
.tl {
  display: grid; grid-template-columns: 118px minmax(0, 1fr); gap: 10px;
  padding: 9px 16px; border-bottom: 1px solid var(--border); font-size: 12.5px;
}
.tl:last-child { border-bottom: none; }
.tl-cuando { color: var(--text-faint); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.tl-cuerpo b { font-weight: 600; margin-right: 6px; }

/* ------------------------------------------------------------ tabs -------- */

.tabs { display: flex; gap: 6px; margin-bottom: 6px; flex-wrap: wrap; }
/* Un banner arriba de las pestañas necesita el aire que el banner no trae. */
.banner + .tabs { margin-top: 14px; }
.tab {
  border: 1px solid var(--border); background: var(--bg-elev); cursor: pointer;
  padding: 7px 13px; border-radius: var(--radius-sm);
  font-size: 12.5px; font-weight: 550; color: var(--text-soft);
}
.tab:hover { background: var(--bg-hover); color: var(--text); }
.tab.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text); }
.tab em {
  font-style: normal; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--warn); margin-left: 2px;
}

/* -------------------------------------------- selector y sugerencias ------ */

.selector { display: flex; flex-direction: column; gap: 11px; }
.selector-barra { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }
.selector-lista {
  max-height: 46dvh; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.selector-fila {
  display: flex; align-items: center; gap: 12px; cursor: pointer;
  padding: 8px 11px; border-bottom: 1px solid var(--border); font-size: 12.5px;
}
.selector-fila:last-child { border-bottom: none; }
.selector-fila:hover { background: var(--bg-hover); }
.selector-fila.sel { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }

.field { position: relative; }
.sugerencias {
  position: absolute; z-index: 30; top: 100%; left: 0;
  width: 100%; max-height: 260px; overflow-y: auto; margin-top: 2px;
  background: var(--bg-elev); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow);
}
.sug {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 7px 10px; font-size: 12.5px; border-bottom: 1px solid var(--border);
}
.sug:last-child { border-bottom: none; }
.sug:hover { background: var(--bg-hover); }
.sug.sel { background: var(--accent-soft); }
/* Provincia de una localidad homónima: es el dato que decide, así que no puede
   quedar en gris chico al lado del nombre. */
.sug-prov { font-size: 12px; font-weight: 650; color: var(--warn); }

/* ------------------------------------------------- alta: caja de tramo --- */

.tramo-box { display: flex; align-items: center; gap: 9px; }
.tramo-elegida {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--accent-soft); border: 1px solid var(--accent);
}

/* --------------------------------- alta: pendientes de asignación --------- */

/* Lista de órdenes esperando chofer, debajo del formulario del alta. Es una
   lista y no una DataTable a propósito: son pocas filas, cada una tiene una sola
   acción posible y lo que importa es leer el recorrido de un vistazo, no ordenar
   por columnas. */
.pend-lista { display: flex; flex-direction: column; }
.pend {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-bottom: 1px solid var(--border);
}
.pend:last-child { border-bottom: none; }
.pend:hover { background: var(--bg-hover); }
.pend-cab { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pend-ruta { font-size: 12.5px; margin-top: 2px; }
/* Contador al lado del título de la card. Vacío no ocupa lugar: una card que
   dice "Pendientes 0" pesa más que una que no dice nada. */
.cont:not(:empty) {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; margin-left: 6px;
  border-radius: 999px; background: var(--warn-soft); color: var(--warn);
  font-size: 11px; font-weight: 650; font-style: normal;
}

/* ------------------------------------- sugerencias del chofer más cercano -- */

/* El bloque de "quién la lleva" del alta: el mapa del tramo, la línea que explica qué
   está mostrando y la lista de recomendados. Apilado y no en dos columnas: el alta vive
   en una página angosta (880 px), y partido al medio ni el mapa muestra la provincia ni
   las filas entran sin cortarse. */
.sug-armado { display: flex; flex-direction: column; gap: 8px; }
/* Reserva el alto de una línea: el estado aparece y desaparece —"buscando…", "lleva la
   carga X"— y sin esto el mapa y la lista se corren solos cada vez que cambia. */
.sug-estado { min-height: 18px; line-height: 1.45; }

.sug-panel { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.sug-cab { font-size: 11.5px; color: var(--text-soft); }
.sug-cargando {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-faint); padding: 8px 0;
}
.sug-choferes {
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
}
.sug-chofer {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 8px 11px; border: none; border-bottom: 1px solid var(--border);
  background: transparent; color: inherit; text-align: left; cursor: pointer;
  font: inherit;
}
.sug-chofer:last-child { border-bottom: none; }
.sug-chofer:hover { background: var(--bg-hover); }
.sug-chofer.on { background: var(--accent-soft); }
/* La posición vencida se muestra atenuada: sigue siendo elegible —puede ser el
   camión correcto— pero el dato con el que se la ordenó es viejo. */
.sug-chofer.vieja { opacity: .72; }
/* El número de la fila es el mismo que lleva su pin en el mapa de arriba, y para eso
   tiene que leerse igual en los dos lados: círculo hueco, gris y del tamaño del pin.
   Es el único elemento de la fila que no es un dato del camión sino una referencia al
   dibujo, así que va apagado —no compite con la distancia, que es lo que ordena. */
.sc-n {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px;
  border: 1.5px solid var(--border-strong); border-radius: 50%;
  font-size: 11px; font-weight: 650; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
/* La distancia es lo que ordena la lista, así que es lo primero que se lee. */
.sc-km {
  flex: none; min-width: 54px; text-align: right;
  font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}
.sc-km em { font-size: 10.5px; font-style: normal; font-weight: 550; margin-left: 2px; color: var(--text-faint); }
.sc-cuerpo { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.sc-cuerpo b { font-size: 12.5px; font-weight: 600; }
.sc-cuerpo > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-cuando { flex: none; font-size: 11px; color: var(--text-faint); }
.sc-cuando.warn { color: var(--warn); font-weight: 550; }

.sug-ocupados { display: flex; flex-direction: column; gap: 3px; }
.sug-ocupado {
  display: flex; align-items: center; gap: 8px;
  font-size: 11.5px; color: var(--text-soft);
}

/* ------------------------------------------------- armador de tramos ----- */

.tramo-nueva { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; }
.tn-col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.tn-paradas {
  display: flex; flex-direction: column; gap: 6px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 8px;
  max-height: 220px; overflow-y: auto;
}
/* Panel del punto marcado a mano. El violeta lo ata al pin de la previa en el
   mapa: es lo que se está por agregar, todavía no una parada. */
.tn-punto {
  display: flex; flex-direction: column; gap: 9px;
  padding: 11px 12px; border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  border: 1px solid color-mix(in srgb, #7c3aed 40%, var(--border));
}
.tn-punto-cab { display: flex; align-items: baseline; gap: 8px; }
.tn-punto-cab b { font-size: 12.5px; }
.tn-punto-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px 10px; }
.tn-punto-acciones { display: flex; justify-content: flex-end; gap: 7px; }

/* Bloque del trayecto: dice si la ruta es la que calcula el ruteador o una
   redefinida a mano, y ahí mismo se vuelve atrás. El violeta es el del punto de
   paso en el mapa, igual que el panel del punto marcado a mano usa el de su pin:
   el color es lo que ata lo que se lee con lo que se ve. */
.tn-ruta {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  border: 1px solid color-mix(in srgb, #7c3aed 25%, var(--border));
}
.tn-ruta-cab { display: flex; align-items: baseline; gap: 10px; justify-content: space-between; }
.tn-ruta-cab b { font-size: 12.5px; }
.tn-ruta .hint { margin: 0; }

/* El registro de modificaciones del trayecto. Con tope de alto y scroll: son
   pocas líneas en el caso normal y no puede empujar el mapa fuera de la vista
   cuando alguien estuvo afinando la misma ruta veinte veces. */
.tr-registro {
  display: flex; flex-direction: column; gap: 6px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 9px 11px;
  max-height: 168px; overflow-y: auto;
}
.tr-registro-fila {
  display: flex; align-items: flex-start; gap: 10px;
  padding-top: 6px; border-top: 1px solid var(--border);
}
.tr-registro-fila:first-of-type { padding-top: 0; border-top: 0; }

.tn-parada { display: flex; align-items: center; gap: 9px; font-size: 12.5px; }
.tn-radio { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--text-soft); }
.tn-radio input { width: 64px; text-align: right; }
.tn-resumen {
  padding: 11px 13px; border-radius: var(--radius-sm);
  background: var(--bg-sunken); border: 1px solid var(--border);
}
.tn-nombre { font-size: 13px; font-weight: 650; }
.tn-km { font-size: 12.5px; color: var(--accent-text); font-weight: 600; margin-top: 2px; }

/* ------------------------------------------------------------- mapa ------- */

.tn-mapa, .mapa-detalle, .mapa-panel, .mapa-recorrido, .mapa-flota, .sug-mapa {
  min-height: 340px; height: 100%;
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg-sunken);
}
.mapa-detalle { min-height: 300px; border: none; border-radius: 0; }
/* El mapa de la flota en el tablero: se mira el conjunto del país, así que
   necesita más alto que el de un viaje solo. */
.mapa-flota { min-height: 460px; border: none; border-radius: 0; }
/* Mapa que ocupa el ancho de una card: el general de geocercas y el del
   recorrido desplegado en tramos. Más alto que el del detalle porque acá se
   mira el conjunto, no un punto. */
.mapa-panel { min-height: 420px; border: none; border-radius: 0; }
.mapa-recorrido { min-height: 320px; border: none; border-radius: var(--radius-sm); }
/* El mapa del alta de una orden: más bajo que el del detalle porque acá se mira un
   recorrido con unos pocos pines encima, no se audita un rastro, y va metido en un
   formulario que tiene que seguir entrando en la pantalla. Va DESPUÉS de la regla
   compartida de arriba a propósito: declarado antes, el min-height de allá le ganaría. */
.sug-mapa { min-height: 260px; }
.mapa-sin {
  display: grid; place-items: center; height: 100%; padding: 20px;
  font-size: 12.5px; color: var(--text-faint); text-align: center;
}

/* Mapa a pantalla completa.
   Es el mismo contenedor con otra clase —el mapa no se recrea— así que se vuelve al
   tamaño chico con el mismo zoom y lo mismo dibujado.
   Todo va con `!important` porque cada declaración de acá pelea con una regla de la
   misma especificidad: las alturas mínimas de cada variante de mapa, el borde de la
   card y, la que importa, el `position: relative` de .leaflet-container —que está
   más abajo en este archivo y por lo tanto le ganaría, dejando el mapa en el flujo
   y del tamaño de su columna—.
   El z-index queda por encima del fondo del modal (150) porque hay mapas que viven
   dentro de un modal: expandir uno desde ahí tiene que taparlo, no meterse debajo. */
.mapa-full {
  position: fixed !important; inset: 0 !important; z-index: 220 !important;
  width: 100% !important; height: 100% !important;
  min-height: 0 !important; max-height: none !important;
  border: none !important; border-radius: 0 !important;
}
/* La página de atrás no se scrollea mientras el mapa está expandido: la rueda es
   del mapa. */
body.con-mapa-full { overflow: hidden; }
/* El botón de expandir, con el mismo trazo que los controles de Leaflet. */
.mapa-ctl a { display: grid; place-items: center; color: #333; }
.mapa-ctl svg { width: 15px; height: 15px; }
/* El botón de seguimiento se pinta cuando está activo. Es la unica forma de que el chofer
   sepa por que el mapa se mueve solo -y de que entienda que arrastrarlo lo apago-: sin la
   marca, un mapa que se recentra sin motivo aparente se lee como que anda mal. */
.mapa-ctl a.mapa-ctl-on { color: #2563eb; background: #eff6ff; }

/* La flecha de "estas aca, yendo para alla".
   Es un triangulo hecho con bordes, con el vertice hacia arriba, sobre un disco blanco: el
   disco es lo que la despega del mapa de calles y de la satelital, que son fondos muy
   distintos. La rotacion la escribe el JS en el style del span, en grados de rumbo -0 es
   el norte, que es hacia donde apunta dibujada-, asi que aca no hay ningun angulo. */
.mapa-yo span {
  display: block; width: 28px; height: 28px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
  position: relative; transition: transform .3s ease-out;
}
.mapa-yo span::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -60%);
  border-left: 7px solid transparent; border-right: 7px solid transparent;
  border-bottom: 13px solid #2563eb;
}

/* Mapa de flota y su leyenda al costado.
   La lista es lo que hace legible el mapa: con un color por camión, es lo único que
   dice qué línea es de quién. Va al costado y no debajo para poder cruzar las dos
   cosas de un vistazo, y scrollea sola —el mapa se queda quieto— porque con treinta
   viajes activos la lista es más alta que el mapa. */
.flota-split { display: grid; grid-template-columns: minmax(0, 1fr) 288px; }
/* Sin ningún camión que dibujar no hay leyenda ni detalle, y el costado sería una
   franja con borde al lado del cartel de "no hay camiones". Se esconde entero en vez de
   dejarlo caer debajo del mapa, que es lo que hace una grilla de una sola columna. */
.flota-split:has(.flota-lista:empty) { grid-template-columns: minmax(0, 1fr); }
.flota-split:has(.flota-lista:empty) .flota-costado { display: none; }
/* La fila del buscador y las categorias, entre las pestanas y el mapa. */
.flota-filtros { align-items: flex-end; }

/* Las categorias de vehiculo del padron de Unity, una por chip.
   Son botones que se prenden y apagan de a uno —se pueden elegir varias— y por eso NO
   reusan .segmented, que es el control de "una de estas": mezclarlos haria que dos
   controles con la misma pinta se comporten distinto. Prendido lleva el acento, que es
   lo que hace que un recorte puesto se vea sin leer. */
.flota-cats { display: flex; flex-wrap: wrap; gap: 5px; padding-bottom: 2px; }
.flota-cat {
  font-size: 11.5px; font-weight: 600; padding: 5px 10px;
  border-radius: 999px; border: 1px solid var(--border);
  background: var(--bg-elev); color: var(--text-soft); cursor: pointer;
  white-space: nowrap;
}
.flota-cat:hover { color: var(--text); background: var(--bg-hover); }
.flota-cat.on {
  background: var(--accent); color: var(--accent-contrast);
  border-color: transparent;
}
.flota-cat:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* "limpiar" no es una categoria: va sin borde para que no se lea como una mas de la
   fila, y solo aparece cuando hay algo que limpiar. */
.flota-cat-limpiar { border-color: transparent; background: transparent; text-decoration: underline; }

/* El costado: arriba el detalle del camión elegido, abajo la lista. La lista es la que
   scrollea —el detalle es corto y tiene que quedar a la vista— así que el alto máximo
   del conjunto lo pone ella. */
.flota-costado {
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column; min-height: 0;
}
.flota-lista {
  overflow-y: auto; max-height: 460px;
  padding: 6px;
  display: flex; flex-direction: column; gap: 2px;
}
.flota-fila {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 7px 8px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
}
.flota-fila:hover { background: var(--bg-hover); }
.flota-fila.activa { background: var(--accent-soft); border-color: var(--accent); }
/* El cuadradito de color es el mismo que el de la ruta en el mapa. Redondo y del
   tamaño de un pin, para que se lean como la misma cosa. */
.flota-color {
  width: 12px; height: 12px; flex: none; border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--bg-elev), 0 0 0 2.5px var(--border);
}
/* Los disponibles son la mayoría del padrón, así que en la lista van detrás de este
   plegado: mezclados con los viajes ahogarían la leyenda de las rutas, que es para lo
   que la lista existe. */
.flota-mas {
  width: 100%; padding: 6px 8px; margin-top: 4px;
  border: none; border-top: 1px solid var(--border);
  background: transparent; color: var(--text-faint);
  font: inherit; font-size: 11px; font-weight: 600; text-align: left; cursor: pointer;
}
.flota-mas:hover { color: var(--text); background: var(--bg-hover); }
/* Un camión libre no tiene ruta de la que ser la leyenda, así que su punto no lleva
   color de la paleta: es el mismo hueco que su pin en el mapa. */
.flota-color-libre { background: var(--bg-elev); box-shadow: 0 0 0 2px var(--text-faint); }
/* El detalle del camión elegido. Con borde abajo y no card propia: está adentro del
   costado y lo que lo separa de la lista es la línea, igual que la lista del mapa. */
.flota-panel {
  padding: 10px 11px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
}
.flota-panel-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
/* Cada dato en dos líneas —etiqueta arriba, valor abajo— y no en dos columnas: en 288 px
   una columna de etiquetas dejaría a los valores con quince caracteres, y acá los
   valores son direcciones y nombres de localidad. */
.flota-dato { display: flex; flex-direction: column; gap: 1px; margin-top: 7px; }
.flota-etiqueta {
  font-size: 10px; font-weight: 650; text-transform: uppercase; letter-spacing: .03em;
  color: var(--text-faint);
}
/* La barra del avance. Va debajo del número y no en su lugar: el porcentaje es el dato
   y la barra es para leerlo de un vistazo. */
.flota-barra {
  height: 5px; margin-top: 5px; border-radius: 3px;
  background: var(--bg-sunken); overflow: hidden;
}
.flota-barra span { display: block; height: 100%; background: var(--accent); }
.flota-datos { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.flota-patente { font-size: 12.5px; font-weight: 650; }
.flota-sub {
  font-size: 11px; color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A pantalla completa se expande el bloque entero y no el mapa solo: la leyenda es
   lo que dice qué línea es de quién, y con veinte rutas —que es justo cuando se
   expande— sin ella no se lee nada.
   Las filas van a `1fr` porque el alto de una fila de grid lo fija su contenido, y
   el mapa pide 460 px de mínimo: sin esto el conjunto ocuparía la pantalla entera
   con el mapa de 460 px arriba y el resto vacío. */
.flota-split.mapa-full { grid-template-rows: minmax(0, 1fr); background: var(--bg-elev); }
.flota-split.mapa-full .mapa-flota,
.flota-split.mapa-full .flota-costado { min-height: 0; height: 100%; }
/* A pantalla completa la lista se estira hasta donde llegue: el tope de 460 px está para
   que la card no crezca más que el mapa, y acá el alto lo pone la pantalla. */
.flota-split.mapa-full .flota-lista { max-height: none; flex: 1; }
@media (max-width: 1000px) {
  /* Apilados, el costado va debajo y baja de alto: en pantalla angosta el mapa es lo
     que hay que preservar. */
  .flota-split { grid-template-columns: minmax(0, 1fr); }
  .flota-costado { border-left: none; border-top: 1px solid var(--border); }
  .flota-lista { max-height: 220px; }
}

/* El mapa se queda con sus z-index adentro.
   Leaflet apila lo suyo hasta z-index 1000 (los paneles de capas van en 400-700
   y los controles en 800-1000). Esos números están pensados para competir entre
   ellos, pero sin una pila propia compiten con toda la página y le ganan a todo:
   el encabezado fijo de la tabla, los desplegables de los filtros y hasta el
   fondo del modal —que está en 150— quedaban por debajo del mapa, así que el
   mapa aparecía encima de cualquier cosa que se abriera sobre él.
   `isolation: isolate` abre una pila nueva en el contenedor: los 1000 de Leaflet
   sólo valen adentro y el mapa entero participa como un bloque más, en 0. */
.leaflet-container { position: relative; z-index: 0; isolation: isolate; }

/* Mapa de geocercas y su panel de ajuste, al costado. El panel aparece recién al
   elegir una geocerca; hasta entonces el mapa ocupa todo el ancho. Es sticky
   porque la página sigue scrolleando: bajar a la tabla no tiene que dejar el
   botón de Guardar fuera de la pantalla. */
.geo-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
.geo-split.editando { grid-template-columns: minmax(0, 1fr) 330px; }
.geo-editor { position: sticky; top: 14px; }
.geo-editor .card-head h2 { font-size: 14px; }
@media (max-width: 1100px) {
  /* Apilado, el panel va primero: es lo que se acaba de abrir. El mapa queda
     abajo y a la vista, que es lo que un modal centrado no permitía. */
  .geo-split.editando { grid-template-columns: minmax(0, 1fr); }
  .geo-editor { position: static; order: -1; }
}
.mapa-pin span {
  display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: 50%; color: #fff; font-size: 11.5px; font-weight: 700; line-height: 1;
  box-shadow: 0 0 0 2px #fff, 0 1px 4px rgba(0, 0, 0, .3);
}
/* Un punto de paso es más chico y sin número: no es una parada —no tiene geocerca ni
   nadie detecta el paso por él—, sólo dice por dónde va la ruta. Con el mismo tamaño
   que las paradas, un trayecto con cuatro puntos de paso se leería como un recorrido
   de seis escalas. El cursor de agarre avisa que se puede arrastrar. */
.mapa-pin-via span { width: 14px; height: 14px; cursor: grab; }
.mapa-pin-via span:active { cursor: grabbing; }

/* En el tablero de flota el color del pin identifica al camión, así que "se fue de
   la ruta" y "es el que estoy mirando" se dicen con aros alrededor y no pintándolo
   de otro color: el operador no pierde de vista cuál es cuál justo cuando algo pasa.
   El rojo va afuera del borde blanco para que se vea sobre la satelital. */
.mapa-pin .pin-desviado { box-shadow: 0 0 0 2px #fff, 0 0 0 4.5px #dc2626, 0 1px 4px rgba(0, 0, 0, .35); }
.mapa-pin .pin-elegido { box-shadow: 0 0 0 2px #fff, 0 0 0 4.5px #0f172a, 0 1px 4px rgba(0, 0, 0, .35); }
.mapa-pin .pin-desviado.pin-elegido {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4.5px #dc2626, 0 0 0 6.5px #0f172a, 0 1px 4px rgba(0, 0, 0, .35);
}
/* Un camión detenido lleva aro ámbar y no rojo, con el mismo criterio que su badge en el
   menú: irse de la ruta es una llamada al chofer, quedarse quieto es una pregunta. Con
   los dos en rojo el operador no sabría cuál atender primero, que es exactamente lo que
   el tablero tiene que contestar de un vistazo. */
.mapa-pin .pin-detenido { box-shadow: 0 0 0 2px #fff, 0 0 0 4.5px #f59e0b, 0 1px 4px rgba(0, 0, 0, .35); }
/* La posición que reportó el teléfono del chofer y no el satelital del camión: el
   único caso que hay cuando el camión no está en Unity. Se dice desaturando el color
   —el mismo camión, señal más débil— y con el triángulo hueco, y NO con un aro: los
   tres aros ya están tomados por desviado, detenido y elegido, y un cuarto competiría
   con los que exigen una acción. El motivo entero se lee en el tooltip.
   `filter` se eligió justamente porque compone con el box-shadow en vez de pisarlo,
   así que un pin del teléfono que además está desviado muestra las dos cosas. */
.mapa-pin .pin-telefono { filter: saturate(.4); }
/* Un camión sin viaje: pin hueco, gris y sin aros. El hueco es lo que dice "no hay nada
   que seguirle" de un vistazo, sin gastar ninguno de los aros —que están reservados para
   lo que exige una acción— ni un color de la paleta, que identifica rutas.
   El relleno y el borde los pone el estilo en línea, por la misma razón que el de los
   otros pines: acá sólo va lo que no depende del color. */
.mapa-pin .pin-disponible { font-size: 9px; }
/* Hace rato que no reporta. El aro punteado dice que el pin está dibujado sobre un dato
   viejo, y el gris que no afirma el presente.
   `outline` y no `box-shadow` porque el punteado no existe en las sombras, y va con
   offset para no comerse el borde blanco que separa al pin del mapa. */
.mapa-pin .pin-viejo {
  outline: 2px dashed var(--text-faint); outline-offset: 2px;
  filter: grayscale(.75);
}
/* Y cuando ya hay un aro lleno —desviado, detenido, elegido— va sólo el gris: el aro de
   una alarma no se puede tapar con una advertencia sobre la antigüedad del dato.
   Va después de .pin-telefono a propósito: los `filter` de dos reglas distintas no se
   suman, se pisan, y entre "es del teléfono" y "es viejo" gana el segundo, que es el que
   dice que no se puede confiar en la posición. */
.mapa-pin .pin-viejo-gris { filter: grayscale(.75); }
.mapa-pin .pin-detenido.pin-elegido {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4.5px #f59e0b, 0 0 0 6.5px #0f172a, 0 1px 4px rgba(0, 0, 0, .35);
}
/* Los tiles son siempre claros: en tema oscuro se atenúa el crédito para que no
   quede como un parche blanco sobre el mapa. */
:root[data-theme="dark"] .leaflet-control-attribution { background: rgba(0, 0, 0, .55); color: #cbd5e1; }
:root[data-theme="dark"] .leaflet-control-attribution a { color: #93c5fd; }

@media (max-width: 1100px) {
  .detalle, .tramo-nueva { grid-template-columns: minmax(0, 1fr); }
  .tn-mapa { min-height: 260px; }
}

/* ==========================================================================
   Sesión: login, bloque del usuario y aviso de versión nueva
   ========================================================================== */

/* Hasta que la sesión esté resuelta, el menú no se dibuja: los ítems salen del
   HTML y recién después se esconden los que este usuario no tiene, así que sin esto
   se ve el menú completo por un instante en cada carga. */
html:not(.listo) .nav,
html:not(.listo) .sidebar-foot { visibility: hidden; }

.login-shell {
  position: fixed; inset: 0; z-index: 200;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 24px;
  background: var(--bg);
  /* La aplicación instalada en iPhone arranca abajo del notch. */
  padding-top: calc(24px + env(safe-area-inset-top));
}
.login-card {
  width: 100%; max-width: 350px;
  display: flex; flex-direction: column; gap: 14px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px;
  box-shadow: var(--shadow);
}
.login-brand { display: flex; align-items: center; gap: 11px; }
.login-brand > div { display: flex; flex-direction: column; line-height: 1.25; }
.login-brand strong { font-size: 14.5px; font-weight: 650; letter-spacing: -.01em; }
.login-brand span { font-size: 11.5px; color: var(--text-faint); }
.login-error {
  background: var(--danger-soft); color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  border-radius: var(--radius-sm);
  padding: 8px 11px; font-size: 12.5px;
}
.login-pie { margin: 0; font-size: 11px; color: var(--text-faint); }
.btn-block { width: 100%; justify-content: center; }

/* Bloque del usuario en el pie del menú. */
.sidebar-foot { flex-direction: column; align-items: stretch; }
.foot-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* El estado de Powerfleet se estira y los botones —atajos y tema— quedan juntos
   contra el borde derecho, en vez de repartidos por todo el ancho del pie. */
.foot-row .pf-status { flex: 1; }
.foot-row .btn-icon { flex: none; }
/* Plegado no hay ancho para el dato y los dos botones en la misma línea. */
.menu-min .foot-row { flex-wrap: wrap; justify-content: center; }
.user-box { position: relative; }
.user-btn {
  width: 100%; display: flex; align-items: center; gap: 9px;
  padding: 7px 8px; border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; cursor: pointer; color: var(--text);
  text-align: left; font: inherit;
  transition: background .12s, border-color .12s;
}
.user-btn:hover { background: var(--bg-hover); border-color: var(--border); }
.user-avatar {
  width: 27px; height: 27px; flex: none; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-text);
  display: grid; place-items: center;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
}
.user-txt { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.user-txt b { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-txt em { font-style: normal; font-size: 10.5px; color: var(--text-faint); }
.user-chevron { width: 14px; height: 14px; margin-left: auto; flex: none; color: var(--text-faint); }
.user-btn[aria-expanded="true"] .user-chevron { transform: rotate(180deg); }

.user-menu {
  position: absolute; bottom: calc(100% + 6px); left: 0; right: 0; z-index: 30;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 5px; display: flex; flex-direction: column; gap: 1px;
}
.user-menu button {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 9px; border: none; border-radius: var(--radius-sm);
  background: transparent; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--text); text-align: left;
}
.user-menu button:hover { background: var(--bg-hover); }
.user-menu button svg { width: 15px; height: 15px; opacity: .7; flex: none; }
.user-menu button.peligro { color: var(--danger); }
.user-menu button.peligro:hover { background: var(--danger-soft); }

/* Plegado no hay lugar para el nombre: queda sólo el círculo con las iniciales, y
   el menú se despliega al costado en vez de arriba. */
.menu-min .user-btn { justify-content: center; padding: 6px 0; }
.menu-min .user-txt, .menu-min .user-chevron { display: none; }
.menu-min .user-menu { left: calc(100% + 6px); right: auto; bottom: 0; width: 210px; }

/* Aviso de versión nueva. Va abajo y centrado, por encima del contenido y del
   menú, pero por debajo de los modales: un diálogo abierto no tiene que competir
   con el aviso. */
.aviso-version {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 150;
  display: flex; align-items: center; gap: 12px;
  max-width: min(440px, calc(100vw - 24px));
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 10px 8px 10px 14px;
}
.aviso-version-txt { display: flex; flex-direction: column; line-height: 1.35; min-width: 0; flex: 1; }
.aviso-version-txt b { font-size: 12.5px; font-weight: 600; }
.aviso-version-txt span { font-size: 11.5px; color: var(--text-faint); }

/* Pasos de instalación en iOS. */
.pasos-instalar { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 11px; }
.pasos-instalar li { display: flex; gap: 10px; font-size: 12.5px; line-height: 1.5; color: var(--text-soft); }
.pasos-instalar li > span {
  width: 20px; height: 20px; flex: none; border-radius: 50%;
  background: var(--bg-sunken); color: var(--text-soft);
  display: grid; place-items: center; font-size: 11px; font-weight: 700;
}

/* Una sola columna: los modales de contraseña tienen tres campos que no se leen en
   fila. */
.form-grid.cols-1 { grid-template-columns: minmax(0, 1fr); }

/* ---------------------------------------------------------------------------
   Maestros: clientes y choferes
   --------------------------------------------------------------------------- */

/* El semáforo del chofer. Es un punto y no una etiqueta porque va en la primera
   columna de una tabla de 224 filas que se recorre con la vista: el color se lee de
   un barrido y el texto no. El motivo va en el title, y la columna "Estado" repite
   el estado en palabras para quien no distingue los colores. */
.sem {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 18%, transparent);
}
.sem-verde    { background: var(--ok); color: var(--ok); }
.sem-amarillo { background: var(--warn); color: var(--warn); }
.sem-rojo     { background: var(--danger); color: var(--danger); }
/* Ocupado no es un problema: es un camión trabajando. Va en el gris del texto
   apagado para que no compita con el rojo, que sí pide una acción. */
.sem-ocupado  { background: var(--text-faint); color: var(--text-faint); }

/* La ficha desplegada del chofer. */
.ficha-datos {
  display: grid; gap: 8px 18px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-sunken);
}
.ficha-dato { display: flex; flex-direction: column; gap: 1px; min-width: 0; font-size: 12.5px; }
.ficha-dato > span { color: var(--text-soft); font-size: 11px; }
.ficha-dato > b { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.docs-tabla { width: 100%; }
/* Las renovaciones anteriores son el historial: se ven, pero apagadas, porque no
   dicen nada sobre si el chofer puede salir hoy. */
.docs-tabla tr.doc-historial td { opacity: .55; }
.docs-vacio {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 14px; border: 1px dashed var(--border-strong); border-radius: var(--radius);
  color: var(--text-soft); font-size: 12.5px;
}
.docs-vacio svg { width: 18px; height: 18px; flex: none; opacity: .6; }

/* En un teléfono estas dos tablas —la documentación del chofer y el libro del
   artículo— pasan a ser una tarjeta por fila.

   No es sólo que ocho columnas no entren en 360 px: las dos viven adentro de una fila
   desplegada de OTRA tabla, y en una tabla el ancho de una celda lo fija su contenido,
   así que la de adentro estiraba a la de afuera y el listado entero quedaba tres veces
   más ancho que la pantalla. Apilada, el ancho vuelve a ser el de la pantalla y cada
   dato se lee con el nombre de su columna al lado —de `data-label`— en vez de
   arrastrando la tabla de costado para adivinar de qué columna era el número.

   Los selectores llevan `table.data` adelante y no alcanza con `.docs-tabla`: el aire
   y la línea de abajo de una celda los pone `table.data td`, que es una clase y DOS
   etiquetas, así que le gana a `.docs-tabla td` —una clase y una etiqueta— y las
   tarjetas quedaban con el padding de una tabla. La media query no suma
   especificidad. */
@media (max-width: 720px) {
  table.data.docs-tabla thead { display: none; }
  table.data.docs-tabla,
  table.data.docs-tabla tbody,
  table.data.docs-tabla tbody tr { display: block; }
  table.data.docs-tabla tbody tr,
  table.data.docs-tabla tbody tr:hover {
    padding: 8px 10px; margin-bottom: 8px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--bg-elev);
  }
  table.data.docs-tabla tbody tr:last-child { margin-bottom: 0; }
  table.data.docs-tabla tbody td,
  table.data.docs-tabla tbody tr:last-child td {
    display: flex; align-items: baseline; gap: 10px;
    padding: 3px 0; border-bottom: none;
    /* Un dato largo —un domicilio, el nombre de un proveedor— corta en varias líneas
       en vez de estirar la tarjeta. Le gana al `.truncate` de la celda, que recorta
       con puntos suspensivos porque en la tabla la columna es angosta; acá el ancho
       es el de la pantalla y no hay por qué esconder la mitad del dato. */
    white-space: normal; overflow: visible; max-width: none;
  }
  table.data.docs-tabla tbody td[data-label]::before {
    content: attr(data-label); flex: none; min-width: 92px;
    font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: var(--text-soft);
  }
  /* La celda de los botones no lleva etiqueta —no es un dato— y va con aire arriba
     para no quedar pegada al último renglón de la tarjeta. */
  table.data.docs-tabla tbody td:not([data-label]) {
    margin-top: 6px; gap: 6px; flex-wrap: wrap;
  }
}

/* El resumen de la importación. Las cifras van grandes porque son la decisión: el
   operador confirma mirando cuántos se crean y cuántos se pisan. */
.imp-resumen { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.imp-cifras { display: flex; gap: 8px; flex-wrap: wrap; }
.imp-cifra {
  flex: 1 1 96px; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--bg-sunken); text-align: center;
}
.imp-cifra b { display: block; font-size: 18px; font-variant-numeric: tabular-nums; }
.imp-cifra span { font-size: 11px; color: var(--text-soft); }
.imp-cifra.ok   { border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: var(--ok-soft); }
.imp-cifra.ok b { color: var(--ok); }
.imp-cifra.warn { border-color: color-mix(in srgb, var(--warn) 45%, transparent); background: var(--warn-soft); }
.imp-cifra.warn b { color: var(--warn); }

.imp-avisos, .imp-detalle { font-size: 12.5px; }
.imp-avisos summary, .imp-detalle summary {
  cursor: pointer; color: var(--text-soft); padding: 4px 0;
}
.imp-avisos ul { margin: 4px 0 0; padding-left: 20px; color: var(--text-soft); }
.imp-avisos li { margin: 2px 0; }
/* El detalle puede traer 40 filas: se acota para que el modal no crezca fuera de
   pantalla y el botón de aplicar quede siempre alcanzable. */
.imp-detalle .table-wrap { max-height: 260px; overflow-y: auto; }

/* ---------------------------------------------------------------------------
   Escáner de remitos
   --------------------------------------------------------------------------- */

/* Fondo oscuro fijo en las dos claras, a propósito: acá lo que se mira es una
   foto, y el contraste de una foto se juzga mejor rodeada de negro que del gris
   claro u oscuro del tema —el mismo motivo por el que cualquier visor de fotos
   o app de cámara usa chrome oscuro sin importar el tema del resto del sistema.
   z-index por encima del mapa a pantalla completa (220): el escáner se abre
   desde el formulario del remito, que puede estar con el mapa expandido detrás. */
.scan-overlay {
  position: fixed; inset: 0; z-index: 260;
  display: flex; flex-direction: column;
  background: #0b0d11;
}
body.con-scan-overlay { overflow: hidden; }

/* fixed y no absolute: el visor del escaneo scrollea, y una X absoluta se iría
   con la primera hoja justo cuando hace falta para volver. */
.scan-cerrar {
  position: fixed; z-index: 2;
  top: calc(12px + env(safe-area-inset-top)); right: 12px;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .12); border: none; color: #fff; cursor: pointer;
}
.scan-cerrar svg { width: 17px; height: 17px; }

.scan-body {
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}

.scan-loading {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  color: #fff; text-align: center;
}
.scan-loading .spinner { border-color: rgba(255, 255, 255, .25); border-top-color: #fff; }
.scan-loading p { margin: 0; font-size: 13px; color: rgba(255, 255, 255, .85); }

/* El stage se ajusta al tamaño real del canvas (inline-block, sin más contenido
   que él) para que las esquinas —posicionadas en porcentaje sobre el stage—
   caigan siempre sobre la imagen, cualquiera sea su relación de aspecto. */
.scan-stage {
  position: relative; display: inline-block;
  max-width: 100%; max-height: 100%;
  touch-action: none;
}
.scan-canvas {
  display: block;
  max-width: 100%; max-height: calc(100dvh - 190px);
  width: auto; height: auto;
  border-radius: var(--radius-sm);
}
.scan-svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
}
.scan-poly {
  fill: color-mix(in srgb, var(--accent) 20%, transparent);
  stroke: var(--accent); stroke-width: 2px;
}
/* Botones y no <div>: un handle tiene que poder recibir foco y el pointer capture
   igual que cualquier control interactivo. touch-action:none es lo que evita que
   el navegador interprete el arrastre como un scroll de la página en el celular. */
.scan-handle {
  position: absolute; top: 0; left: 0;
  width: 28px; height: 28px; margin: -14px 0 0 -14px;
  border-radius: 50%; padding: 0;
  background: var(--accent); border: 3px solid #fff;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .5);
  cursor: grab; touch-action: none;
}
.scan-handle:active { cursor: grabbing; }

.scan-ayuda {
  margin: 0; padding: 0 16px 10px; text-align: center;
  font-size: 12.5px; color: rgba(255, 255, 255, .7);
}

.scan-actions {
  display: flex; gap: 10px; justify-content: center;
  padding: 0 16px calc(16px + env(safe-area-inset-bottom));
}
.scan-actions .btn { flex: 1; max-width: 220px; justify-content: center; }

/* La tira de páginas de la sesión. Aparece recién con la segunda foto: con una
   sola no habría entre qué elegir, y el cuadrito repetiría lo que ya se ve. */
.scan-tira {
  display: flex; gap: 8px; overflow-x: auto;
  padding: 0 16px 12px; scrollbar-width: none;
}
.scan-tira::-webkit-scrollbar { display: none; }
.scan-tira-item { position: relative; flex: none; }
.scan-tira-ver {
  display: block; padding: 0; width: 54px; height: 54px;
  border: 2px solid rgba(255, 255, 255, .3); border-radius: var(--radius-sm);
  background: #fff; cursor: pointer; overflow: hidden;
}
.scan-tira-item.activa .scan-tira-ver { border-color: var(--accent); }
.scan-tira-ver img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.scan-tira-num {
  position: absolute; left: 3px; bottom: 3px;
  min-width: 15px; padding: 0 3px; border-radius: 4px;
  background: rgba(0, 0, 0, .6); color: #fff;
  font-size: 10px; line-height: 15px; text-align: center;
}
.scan-tira-quitar {
  position: absolute; top: -5px; right: -5px;
  width: 19px; height: 19px; border-radius: 50%; padding: 0;
  display: grid; place-items: center;
  background: var(--danger); border: 2px solid #0b0d11; color: #fff; cursor: pointer;
}
.scan-tira-quitar svg { width: 10px; height: 10px; }

/* --- el escaneo terminado, del lado del chofer --- */

/* Una sola pieza y no una grilla de miniaturas: lo que tiene que reconocer de un
   vistazo es "este remito ya está escaneado", no cuántos archivos juntó. */
.mv-escaneo { display: flex; align-items: center; gap: 8px; }
.mv-escaneo-abrir {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  padding: 8px; text-align: left; cursor: pointer;
  background: var(--bg-sunken); border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: inherit; font: inherit;
}
.mv-escaneo-tapa { position: relative; flex: none; width: 46px; height: 46px; }
.mv-escaneo-tapa img {
  width: 100%; height: 100%; object-fit: cover; object-position: top;
  background: #fff; border-radius: 4px; border: 1px solid var(--border);
}
/* Cuántas hojas tiene, encima de la tapa: es el dato que distingue un escaneo de
   una hoja de uno de tres, y sin él las dos tapas se ven igual. */
.mv-escaneo-n {
  position: absolute; right: -5px; top: -5px;
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: 9px;
  background: var(--accent); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 18px; text-align: center;
}
.mv-escaneo-texto { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mv-escaneo-borrar {
  flex: none; display: grid; place-items: center;
  width: 38px; height: 38px; padding: 0;
  background: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--danger); cursor: pointer;
}
.mv-escaneo-borrar svg { width: 16px; height: 16px; }

/* --- tramos desviados --- */

/* Los dos botones de un tramo en la oficina. Se envuelven porque "Adoptar como
   ruta del tramo" es largo y la columna del detalle es angosta. */
.tramo-acciones { display: flex; flex-wrap: wrap; gap: 6px; }

/* Un tramo en el historial del chofer: el dato a la izquierda y el botón del mapa
   a la derecha, que es donde cae el pulgar. */
.mh-tramo {
  display: flex; align-items: center; gap: 10px;
  margin-top: 8px; padding: 9px 10px;
  background: var(--bg-sunken); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.mh-tramo .btn { flex: none; }
/* El mapa del tramo, alto fijo: sin alto declarado Leaflet mide cero y no dibuja. */
.mh-mapa { height: 260px; margin-top: 8px; border-radius: var(--radius-sm); overflow: hidden; }
.mh-mapa:not([hidden]) { border: 1px solid var(--border); }

/* La tarjeta que pide la ubicación. Va arriba de todo y sólo cuando el permiso no
   está dado: es lo único que la pantalla necesita antes de servir para algo. */
.mv-permiso { display: flex; flex-direction: column; gap: 10px; }
.mv-permiso p { margin: 3px 0 0; }

/* El estado del Wake Lock. Cuando está todo bien es una confirmación y nada más, así que
   va en una línea al pie del gris de los metadatos: no tiene que competir con el viaje,
   que es lo que el chofer vino a mirar. El caso que sí importa —la pantalla se va a
   bloquear— se dibuja con el banner de aviso y ocupa el mismo lugar. */
.mv-pantalla {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 0 2px; margin-bottom: 12px;
  font-size: 12px; line-height: 1.45; color: var(--text-faint);
}
.mv-pantalla svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }
#mv-pantalla .banner { margin-bottom: 12px; }

/* El visor: las hojas una abajo de la otra, para controlar que salieron legibles. */
.mv-visor {
  position: fixed; inset: 0; z-index: 260;
  overflow-y: auto; background: rgba(6, 8, 11, .96);
}
.mv-visor-hojas {
  display: flex; flex-direction: column; gap: 14px;
  padding: calc(56px + env(safe-area-inset-top)) 14px calc(20px + env(safe-area-inset-bottom));
}
.mv-visor-hojas figure { margin: 0; }
.mv-visor-hojas img {
  display: block; width: 100%; height: auto;
  background: #fff; border-radius: var(--radius-sm);
}
.mv-visor-hojas figcaption {
  padding-top: 5px; text-align: center;
  font-size: 12px; color: rgba(255, 255, 255, .65);
}

/* El fondo blanco fijo detrás de cada hoja —en la tapa, en la tira y en el
   visor— es a propósito: el resultado del escáner es blanco y negro de alto
   contraste, y mostrarlo sobre --bg-elev en tema oscuro lo haría ver recortado
   en gris en vez de la hoja blanca que realmente es. */


/* ==========================================================================
   Modulo Logistica: la cola de trabajo previo a la facturacion
   ========================================================================== */

/* Las pestanas de etapa son .segmented-num, que es el control compartido con el
   monitoreo de flota. */

.cola-lista { display: flex; flex-direction: column; }

/* Una fila por orden. Es un boton disfrazado: el unico gesto de esta pantalla es
   abrir la orden, porque las acciones viven alla. */
.cola-fila {
  display: grid; grid-template-columns: 92px minmax(0, 1fr) auto;
  gap: 12px; align-items: center;
  padding: 9px 16px; cursor: pointer;
  border-top: 1px solid var(--border);
}
.cola-lista > .cola-fila:first-child { border-top: none; }
.cola-fila:hover { background: var(--bg-sunken); }
.cola-fila:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.cola-id { display: flex; flex-direction: column; gap: 1px; }
.cola-que { min-width: 0; }
.cola-ruta {
  font-weight: 550; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cola-marcas { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }

/* En un telefono la fila se apila y las marcas pasan a la izquierda: alineadas a
   la derecha sobre 360 px quedarian colgando de un borde que ya no existe. */
@media (max-width: 720px) {
  .cola-fila { grid-template-columns: 1fr; gap: 4px; }
  .cola-id { flex-direction: row; align-items: baseline; gap: 8px; }
  .cola-marcas { justify-content: flex-start; }
}


/* El selector de zona de la tabla de geocercas. Compacto porque vive en una celda
   junto a otras seis columnas, y se clasifica de a 300 localidades. */
.sel-zona {
  width: auto; min-width: 112px; max-width: 150px;
  padding: 2px 6px; font-size: 12px; height: auto;
}

/* ------------------------------------- vista previa del pedido a cargar en Sigma */

/* Está calcada de la pantalla «Carga de Pedidos» de Sigma a propósito: quien la mira
   es el que hasta ahora tipeaba esos renglones del otro lado, y con los campos donde
   los tiene aprendidos revisar es leer. Ver el comentario de vistaPrevia(). */
.vp-cab {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 18px;
  padding: 10px 12px;
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.vp-cab-cols { grid-template-columns: minmax(0, 1fr); }
.vp-campo { display: flex; align-items: baseline; gap: 7px; min-width: 0; font-size: 13px; }
.vp-et { color: var(--text-soft); min-width: 68px; }
/* El código monoespaciado y la descripción al lado, como los muestra Sigma: el código
   solo obligaría a saberse la tabla de memoria. */
.vp-cod {
  font-family: var(--mono); font-size: 12.5px; font-weight: 600;
  padding: 1px 6px; border-radius: 5px;
  background: var(--bg-elev); border: 1px solid var(--border-strong);
}
.vp-desc { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.vp-cliente { margin: 10px 0; }
.vp-cliente-nombre { display: flex; align-items: baseline; gap: 8px; font-size: 15px; }
.vp-cliente-dir, .vp-cliente-doc { margin-top: 1px; }

.vp-dos { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: start; }
/* El panel de cuenta corriente. Va a la derecha y no mezclado con los campos del
   pedido porque no es parte de lo que se carga: es el contexto con el que alguien
   decide si emitir —cuánto debe, cuánto le queda de crédito—. */
.vp-cuenta {
  display: flex; flex-direction: column; gap: 3px;
  min-width: 210px;
  padding: 10px 12px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
}
.vp-cuenta > div { display: flex; justify-content: space-between; gap: 14px; }
.vp-cuenta b { font-variant-numeric: tabular-nums; }

.vp-grilla { margin: 12px 0 10px; }
.vp-grilla input.vp-descripcion {
  width: 100%; min-width: 0;
  padding: 3px 6px;
  font: inherit; font-size: 12.5px;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
}
/* El borde aparece al apuntarlo: la descripción es lo único editable de la ventana y
   tiene que poder descubrirse, pero diez recuadros dibujados de entrada harían parecer
   que todo lo demás también se edita. */
.vp-grilla input.vp-descripcion:hover { border-color: var(--border-strong); }
.vp-grilla input.vp-descripcion:focus {
  border-color: var(--accent); background: var(--bg-elev); outline: none;
}

.vp-pie { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: start; }
.vp-obs label { display: block; font-size: 12.5px; color: var(--text-soft); margin-bottom: 3px; }
.vp-obs textarea {
  width: 100%; resize: vertical;
  padding: 7px 9px;
  font: inherit; font-size: 12.5px;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--border); border-radius: 8px;
}
.vp-obs p { margin: 5px 0 0; }

.vp-totales {
  display: flex; flex-direction: column; gap: 3px;
  min-width: 210px;
  padding: 10px 12px;
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
}
.vp-totales > div { display: flex; justify-content: space-between; gap: 14px; }
.vp-totales b { font-variant-numeric: tabular-nums; }
.vp-total {
  margin-top: 4px; padding-top: 5px;
  border-top: 1px solid var(--border-strong);
  font-size: 15px;
}
.vp-total b { font-weight: 700; }
.vp-nota { margin: 10px 0 0; }

/* En angosto las dos columnas se apilan y los paneles pasan a ancho completo: leídos
   uno debajo del otro siguen en el mismo orden en que se revisan. */
@media (max-width: 700px) {
  .vp-cab { grid-template-columns: minmax(0, 1fr); }
  .vp-dos, .vp-pie { grid-template-columns: minmax(0, 1fr); }
  .vp-cuenta, .vp-totales { min-width: 0; }
  /* La grilla scrollea de costado adentro de su envoltorio, y repartiendo el ancho por
     el contenido la columna de la descripción es la que se queda sin nada: su input
     puede encogerse hasta cero y las de números no. Es la única cosa editable de la
     ventana, así que se le reserva lugar para escribir. */
  .vp-grilla th:nth-child(3), .vp-grilla td:nth-child(3) { min-width: 170px; }

  /* El campo del pedido deja de ser una línea sola: la etiqueta y el código arriba, la
     descripción abajo y entera. Con 300 px de ancho, «LEONI TRANSPORTES SRL» al lado de
     su etiqueta y de su código entraba recortada por la mitad —el recorte con puntos
     suspensivos existe porque en el escritorio la columna es angosta—, y lo que esta
     ventana promete es justamente que se PUEDE LEER lo que se va a cargar en Sigma. */
  .vp-campo { flex-wrap: wrap; }
  .vp-desc { white-space: normal; overflow: visible; }
}

/* ------------------------------------------ vincular clientes con Sigma --- */

/* La ventana es una lista larga con la que se trabaja de arriba hacia abajo, así que
   scrollea adentro del modal y no lleva el pie —los botones— fuera de la vista. */
.vs-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 14px; }

.vs-grupo {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--bg-sunken);
}
.vs-grupo > summary {
  display: flex; align-items: center; gap: 8px;
  cursor: pointer; font-size: 13.5px; user-select: none;
}
.vs-grupo > .hint { margin: 8px 0 10px; }
.vs-grupo-acciones { display: flex; gap: 6px; margin-bottom: 8px; }

.vs-filas { display: flex; flex-direction: column; gap: 6px; }

/* Dos columnas: a la izquierda quién es de este lado, a la derecha con qué se lo
   vincula. Que la lectura sea siempre nuestro-cliente -> ficha-de-Sigma es lo que hace
   que 344 filas se puedan recorrer sin volver a leer el encabezado en cada una. */
.vs-fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 12px; align-items: start;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--bg);
  font-size: 13px;
}
.vs-nuestro { min-width: 0; }
.vs-nuestro .hint { margin-top: 2px; }
.vs-sigma { min-width: 0; }
.vs-sigma select, .vs-sigma input { width: 100%; }
.vs-sigma .check { align-items: flex-start; width: 100%; }
.vs-sigma .check .hint { display: block; margin-top: 1px; }

/* En un teléfono las dos columnas se apilan. La ficha de Sigma queda debajo de nuestro
   cliente, que es el mismo orden en que se lee en el escritorio. */
@media (max-width: 700px) {
  .vs-fila { grid-template-columns: minmax(0, 1fr); gap: 8px; }
}
