/* ============================================================
   SDPGO · Helpbank Design System (portado desde Helpbank.html)
   Paleta navy corporativa, alta densidad, SaaS minimal.
   ============================================================ */
:root {
  --navy-950: #0a1628;
  --navy-900: #0f1d36;
  --navy-800: #15294d;
  --navy-700: #1d3a6b;
  --navy-600: #2855a3;
  --navy-500: #3d6fc4;
  /* navy-100/50 NO son acento: se usan como superficie (hover de fila clickable).
     Por eso pasan a neutro cálido — un hover azul pálido sobre fondo cálido se ve sucio.
     El nombre se conserva a propósito: renombrar tokens rompe en silencio los 748
     `style=` inline de los .razor. Regla del rediseño: reasignar valores, nunca renombrar. */
  --navy-100: #EBE7DE;
  --navy-50:  #F1EFE9;

  /* ===== Neutros cálidos — variante HÍBRIDA (decidida 2026-08-02) =====
     Del mockup se toma la paleta cálida de superficies y texto; el sidebar se queda
     navy. Así se evita reescribir las 110 líneas de `.sb` (15 rgba(255,255,255,x) y
     3 `color:white` que sobre claro caen a 1,05:1) y desaparece el riesgo de aplanar
     la app: el contraste sidebar/fondo sigue siendo 17,5:1 en vez de bajar a 1,04:1.
     Los neutros se alinean con los tokens de estado ya aplicados (--st-neutro-*),
     que salieron del mismo diseño. */
  --ink-900: #22201C;   /* 15,3:1 sobre blanco */
  --ink-800: #33302B;
  --ink-700: #4A463F;
  --ink-600: #5C584F;   /* = --st-neutro-fg */
  --ink-500: #756F64;   /* 4,98:1 sobre blanco · 4,58:1 sobre --ink-25 → AA en thead */
  --ink-400: #8A857A;   /* = --st-neutro-dot · sólo placeholder y texto decorativo */
  --ink-300: #B0AA9E;
  --ink-200: #D9D4C9;
  --ink-100: #E7E3DA;
  --ink-50:  #F1EFE9;   /* = --st-neutro-bg */
  --ink-25:  #F7F5F1;   /* lienzo cálido del mockup */

  --bg:        #F7F5F1;
  --bg-card:   #ffffff;
  --bg-sidebar:#0a1628;
  --border:    #E3DED4;
  --border-strong:#D0C9BC;

  /* Semánticos alineados al vocabulario de estados: mismo significado, mismo color.
     Antes convivían dos verdes, dos rojos y dos ámbares para lo mismo. */
  --ok:    #2A6440;
  --ok-50: #EAF3ED;
  --warn:  #8A5A0E;
  --warn-50:#FDF4E4;
  --err:   #8E2A22;
  --err-50:#FBEDEB;
  --info:  #14528F;
  --info-50:#EAF1F9;

  /* ===== Los 5 tokens que se usaban sin estar definidos =====
     `--line`, `--surface`, `--brand`, `--card-bg` y `--bg-input` tenían 7 usos en
     .razor y caían a fallbacks azulados (uno, MiPerfil, a un navy #44506b) sin error
     ni warning. Definirlos aquí los alinea con la paleta sin tocar ningún .razor. */
  --line:     #E3DED4;  /* alias semántico de --border */
  --surface:  #ffffff;
  --card-bg:  #ffffff;
  --bg-input: #ffffff;
  --brand:    #2855a3;  /* = --navy-600: en el híbrido el acento sigue siendo el azul */

  --font-sans: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace;

  --sidebar-w: 232px;
  --topbar-h: 56px;
  --subbar-h: 48px;

  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-xl: 12px;

  /* Sombra cálida: la anterior era navy (rgba(15,29,54,x)) y sobre fondo cálido
     tiñe de gris azulado el borde de cada card. */
  --sh-card: 0 1px 0 rgba(60,52,40,0.04), 0 1px 2px rgba(60,52,40,0.05);
  --sh-pop:  0 4px 16px rgba(60,52,40,0.09), 0 1px 2px rgba(60,52,40,0.05);
  --sh-deep: 0 16px 48px rgba(40,34,26,0.20);

  /* ===== Estados de envío — diseño HELPBANK, variante 1d (tratamiento A) =====
     Cada estado es un trío: punto sólido (la señal cromática), fondo tenue y borde,
     más un texto oscuro que mantiene el contraste sobre AA. Como la etiqueta siempre
     va escrita, el color nunca es el único portador de significado (WCAG 1.4.1).

     Fueron los primeros tokens de la paleta nueva; desde F1 el resto de los neutros
     se alinea con ellos (ver el bloque de neutros cálidos más arriba). */
  --st-pend-dot:   #C2801C;  --st-pend-bg:   #FDF4E4;  --st-pend-bd:   #EBD9B4;  --st-pend-fg:   #8A5A0E;
  --st-ruta-dot:   #1B5FA8;  --st-ruta-bg:   #EAF1F9;  --st-ruta-bd:   #C9DCF0;  --st-ruta-fg:   #14528F;
  --st-ok-dot:     #3F8F5F;  --st-ok-bg:     #EAF3ED;  --st-ok-bd:     #C6E0D0;  --st-ok-fg:     #2A6440;
  --st-inc-dot:    #A5322A;  --st-inc-bg:    #FBEDEB;  --st-inc-bd:    #F0CFCA;  --st-inc-fg:    #8E2A22;
  --st-dev-dot:    #6D4AA8;  --st-dev-bg:    #F1ECFA;  --st-dev-bd:    #DACFF0;  --st-dev-fg:    #57388F;
  /* El punto neutro va un tono más oscuro que el #A8A296 del mockup: sobre #F1EFE9 ese
     valor da 2.21:1 y el punto desaparece. #8A857A (también del diseño) da 3.19:1. */
  --st-neutro-dot: #8A857A;  --st-neutro-bg: #F1EFE9;  --st-neutro-bd: #DFDBD1;  --st-neutro-fg: #5C584F;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink-900);
  font-family: var(--font-sans);
  font-size: 13px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button { font-family: inherit; }
a { color: var(--navy-600); text-decoration: none; }
a:hover { color: var(--navy-700); text-decoration: underline; }

/* ===== Acceso (Login · Cambiar contraseña · Acceso denegado) =======
   Las tres pantallas comparten este bloque. F8 del rediseño: el mockup no cubría el
   login, así que se diseñó, no se tradujo.

   Se conserva la partición en dos: a la izquierda la voz oscura de la marca, que es la
   misma del sidebar de la app (en la variante híbrida el navy sigue siendo el color
   corporativo); a la derecha el lienzo cálido donde vive el trabajo. Quien entra ya ve
   los dos mundos que va a usar todo el día. */
.auth-wrap {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--bg);
}

/* Navy plano en vez del gradiente diagonal con halo azul: la retícula de puntos remite
   a la cuadrícula de sectores del ruteo, que es de lo que trata el sistema, y no
   compite con el formulario. */
.auth-aside {
  background-color: var(--navy-950);
  background-image: radial-gradient(rgba(255,255,255,0.055) 1px, transparent 1px);
  background-size: 22px 22px;
  background-position: -1px -1px;
  color: white;
  padding: 56px 64px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 40px;
  position: relative;
  overflow: hidden;
}
/* Una sola veladura, desde abajo, para que el pie no flote sobre la retícula. */
.auth-aside::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 45%;
  background: linear-gradient(to top, rgba(10,22,40,0.85), transparent);
  pointer-events: none;
}
.auth-brand { display: flex; align-items: center; gap: 12px; position: relative; z-index: 1; }
.auth-brand .logo {
  width: 36px; height: 36px;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--navy-500), var(--navy-700));
  color: white;
  display: grid; place-items: center;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.02em;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.20);
}
.auth-brand .name b { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; display: block; }
.auth-brand .name span {
  font-size: 10.5px;
  color: rgba(255,255,255,0.55);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.auth-pitch {
  position: relative; z-index: 1;
  max-width: 30ch;
}
.auth-pitch h1 {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.12;
  margin: 0 0 14px;
  text-wrap: balance;
}
.auth-pitch p {
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255,255,255,0.72);
  margin: 0 0 28px;
  max-width: 42ch;
}
/* Los tres ítems son el ciclo de vida de una expedición, en orden, y cada punto lleva
   el color que ese estado tiene dentro de la app. No es decoración: es el vocabulario
   de color del sistema, presentado antes de entrar. */
.auth-pitch ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 14px;
}
.auth-pitch li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  font-size: 13px;
  color: rgba(255,255,255,0.85);
}
.auth-pitch li::before {
  content: "";
  flex: 0 0 7px;
  width: 7px; height: 7px;
  border-radius: 50%;
  transform: translateY(1px);
}
/* Los --st-*-dot están calibrados para fondos CLAROS; sobre el navy quedan apagados,
   así que acá van sus equivalentes luminosos. Mismo significado, distinto sustrato. */
.auth-pitch li.ciclo-1::before { background: #E0A03A; box-shadow: 0 0 0 4px rgba(224,160,58,0.16); }
.auth-pitch li.ciclo-2::before { background: #6FA0E8; box-shadow: 0 0 0 4px rgba(111,160,232,0.16); }
.auth-pitch li.ciclo-3::before { background: #6FBF8C; box-shadow: 0 0 0 4px rgba(111,191,140,0.16); }

/* 0.55 y no 0.45: con 0.45 el pie daba 3,9:1 sobre el navy y no llegaba a AA. */
.auth-foot { font-size: 11.5px; color: rgba(255,255,255,0.55); position: relative; z-index: 1; }

.auth-main {
  display: grid;
  place-items: center;
  padding: 32px;
}
/* Antes el formulario flotaba suelto sobre el fondo. Sobre el lienzo cálido necesita
   cuerpo: tarjeta blanca, para que el punto de entrada tenga un borde donde apoyarse. */
.auth-card {
  width: 100%;
  max-width: 396px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-pop);
  padding: 32px 30px;
}
.auth-card h2 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 6px;
  color: var(--ink-900);
}
.auth-card .lead {
  font-size: 13px;
  color: var(--ink-500);
  margin: 0 0 24px;
  line-height: 1.5;
}
.auth-form .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}
.auth-form label {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-700);
}
.auth-form input {
  height: 42px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-family: inherit;
  font-size: 13.5px;
  color: var(--ink-900);
  background: white;
  outline: none;
  transition: border-color 120ms, box-shadow 120ms;
}
.auth-form input:focus {
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.15);
}
.auth-form input[aria-invalid="true"] {
  border-color: var(--err);
  box-shadow: 0 0 0 3px rgba(142,42,34,0.14);   /* halo del --err nuevo */
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 44px;
  padding: 0 18px;
  border-radius: var(--r-md);
  font-size: 13.5px;
  font-weight: 600;
  border: 1px solid var(--border);
  background: white;
  color: var(--ink-800);
  white-space: nowrap;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.btn:hover { background: var(--ink-25); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-primary {
  background: var(--navy-800);
  color: white;
  border-color: var(--navy-800);
}
.btn-primary:hover { background: var(--navy-700); border-color: var(--navy-700); }
.btn-block { width: 100%; }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--ink-100); }

.alert {
  font-size: 12.5px;
  border-radius: var(--r-md);
  padding: 10px 12px;
  margin-bottom: 14px;
  border: 1px solid transparent;
  display: flex;
  gap: 8px;
  align-items: flex-start;
}
/* Los bordes son los mismos que los de los chips: un aviso y un estado que dicen lo
   mismo se ven igual. Antes eran rgba() de la paleta vieja y quedaban fríos. */
.alert.err   { background: var(--err-50);  color: var(--err);  border-color: var(--st-inc-bd); }
.alert.warn  { background: var(--warn-50); color: var(--warn); border-color: var(--st-pend-bd); }
.alert.info  { background: var(--info-50); color: var(--info); border-color: var(--st-ruta-bd); }
.alert.ok    { background: var(--ok-50);   color: var(--ok);   border-color: var(--st-ok-bd); }

@media (max-width: 900px) {
  .auth-wrap { grid-template-columns: 1fr; }
  .auth-aside { padding: 28px 24px; min-height: auto; gap: 20px; }
  .auth-aside::after { display: none; }
  .auth-pitch { max-width: none; }
  .auth-pitch h1 { font-size: 23px; margin-bottom: 10px; }
  /* En una pantalla chica el argumento de venta estorba: se entra a trabajar. */
  .auth-pitch p, .auth-pitch ul, .auth-foot { display: none; }
  .auth-main { padding: 24px 20px 40px; }
  .auth-card { padding: 26px 22px; box-shadow: var(--sh-card); }
}

/* ===== Shell autenticado (Sidebar + Topbar + Page) ================ */
.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  height: 100vh;
  overflow: hidden;
  transition: grid-template-columns .18s ease;
}
/* Menú colapsado por la hamburguesa.
   OJO: NO usar display:none en .sb — al quitarlo del grid, main cae en la
   primera columna (0px) y la página queda en blanco. En vez de eso dejamos
   el sidebar como ítem del grid y colapsamos su columna a 0 recortándolo. */
.app.sb-collapsed { grid-template-columns: 0 1fr; }
.app.sb-collapsed .sb {
  overflow: hidden;
  min-width: 0;
  padding-left: 0;
  padding-right: 0;
  border: 0;
}

/* Botón hamburguesa (topbar) */
.tb-burger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 34px;
  height: 30px;
  padding: 0 8px;
  margin-right: 12px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  flex: 0 0 auto;
}
.tb-burger span {
  display: block;
  height: 2px;
  width: 18px;
  background: var(--ink-700);
  border-radius: 2px;
}
.tb-burger:hover { background: var(--ink-50); border-color: var(--navy-500); }

.sb {
  background: var(--bg-sidebar);
  color: #c9d2e3;
  display: flex;
  flex-direction: column;
  border-right: 1px solid #0a1628;
  min-height: 0;      /* permite que .sb-nav se contraiga y habilite el scroll */
  overflow: hidden;
}
.sb-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--topbar-h);
  padding: 0 16px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.sb-logo {
  width: 28px; height: 28px;
  border-radius: 6px;
  background: linear-gradient(135deg, #3d6fc4 0%, #1d3a6b 100%);
  display: grid; place-items: center;
  color: white;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: -0.02em;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18);
}
.sb-brand-txt { display: flex; flex-direction: column; line-height: 1.1; }
.sb-brand-txt b {
  color: white;
  font-size: 13.5px;
  letter-spacing: -0.01em;
  font-weight: 600;
}
.sb-brand-txt span {
  color: var(--ink-400);
  font-size: 10.5px;
  letter-spacing: 0.02em;
}

.sb-section {
  padding: 14px 12px 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.36);
}

.sb-nav {
  flex: 1;
  min-height: 0;            /* clave: sin esto el flex-item no scrollea y el menú se corta */
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: 12px;
  scrollbar-width: thin;    /* Firefox */
  scrollbar-color: rgba(255,255,255,0.20) transparent;
}
/* Scrollbar del sidebar oscuro (WebKit/Chromium/Edge) */
.sb-nav::-webkit-scrollbar { width: 8px; }
.sb-nav::-webkit-scrollbar-track { background: transparent; }
.sb-nav::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.16);
  border-radius: 4px;
}
.sb-nav::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.30); }
.sb-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  margin: 1px 8px;
  border-radius: var(--r-md);
  color: #c9d2e3;
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 450;
  user-select: none;
  text-decoration: none;
}
.sb-item:hover { background: rgba(255,255,255,0.05); color: white; }
.sb-item.active {
  background: rgba(61,111,196,0.18);
  color: white;
  box-shadow: inset 2px 0 0 var(--navy-500);
}
.sb-item.disabled { opacity: 0.45; cursor: not-allowed; }
.sb-group {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px 4px;
  margin: 4px 8px 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: rgba(255,255,255,0.55);
  text-transform: uppercase;
  user-select: none;
}
.sb-tag {
  background: rgba(255,255,255,0.08);
  color: rgba(255,255,255,0.55);
  font-size: 9.5px;
  padding: 1px 6px;
  border-radius: 999px;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.tb {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 16px;
  border-bottom: 1px solid var(--border);
  background: white;
  flex-shrink: 0;
}
.tb-crumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-500);
}
.tb-crumb b { color: var(--ink-900); font-weight: 600; }
.tb-crumb .sep { color: var(--ink-300); }
.tb-spacer { flex: 1; }
.tb-meta {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 12px;
  color: var(--ink-600);
}
.tb-meta .pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--ok-50);
  color: var(--ok);
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
}
.tb-meta .pill::before {
  content: "";
  width: 6px; height: 6px;
  background: currentColor;
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(63,143,95,0.16);   /* halo del --st-ok-dot */
}
.tb-icon-btn {
  width: 32px; height: 32px;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: white;
  display: grid; place-items: center;
  color: var(--ink-600);
  cursor: pointer;
}
.tb-icon-btn:hover { background: var(--ink-25); color: var(--ink-900); }

.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;             /* truco flexbox: permite que .page haga scroll */
  overflow: hidden;
  background: var(--bg);
}
.page {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 24px;
}

.grid { display: grid; gap: 14px; }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

.kpi {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: var(--sh-card);
}
.kpi-label {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-500);
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.kpi-val {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.kpi-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--ink-500);
}

.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-card);
}
.card-hd {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.card-hd h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink-900);
}
.card-body { padding: 16px; }

.muted { color: var(--ink-500); }

/* ===== Tabla de datos ===== */
.tbl {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.tbl thead th {
  text-align: left;
  padding: 8px 12px;
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-500);
  background: var(--ink-25);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  position: sticky; top: 0; z-index: 1;
}
.tbl tbody td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--ink-100);
  color: var(--ink-800);
  vertical-align: middle;
}
.tbl tbody tr:hover td { background: var(--ink-25); }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl .num { text-align: right; }
.tbl .strong { color: var(--ink-900); font-weight: 500; }
.tbl .mono { font-family: var(--font-mono); font-size: 11.5px; }
.tbl .ellipsis {
  max-width: 220px;
  overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
}

/* Origen pill (Manual / Masivo / Shopify) */
.pill-origen {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: white;
}
.pill-origen.manual  { background: #2855a3; }  /* era #0c77bd, un azul cian que sobre la paleta cálida se ve fuera de sistema */
.pill-origen.masivo  { background: #8d6e63; }
.pill-origen.shopify { background: #96bf48; }

/* El coloreo de fila por origen (tr.origen-* teñía TODO el texto de la fila: #0c77bd,
   #8d6e63, #5a7a20) se retiró en el rediseño: pinta un dato secundario con la misma
   fuerza que el estado, y el azul frío choca con la paleta cálida. El origen sigue
   disponible en el title de la fila y en el chip .pill-origen; la señal vertical de la
   fila ahora la lleva el ESTADO (ver tr.fila-estado más abajo), que es lo que se
   escanea al operar. */

/* ===== Chips de estado (diseño HELPBANK, variante 1d · tratamiento A) =====
   Punto sólido + fondo tenue + borde + texto oscuro. Reemplaza al chip sólido de
   texto blanco, que el diseño descarta porque con 20 filas satura la vista y compite
   con los botones de acción.

   El punto se dibuja con ::before, así ningún .razor necesita markup extra.
   Un solo vocabulario para lo que antes eran .pill-estado y .pill-entrega, que
   duplicaban tres colores idénticos para el mismo significado. */
.chip-estado {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 8px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.35;
  white-space: nowrap;
  width: fit-content;
  border: 1px solid transparent;
  /* Neutro por defecto: un estado sin variante no queda invisible. */
  background: var(--st-neutro-bg);
  border-color: var(--st-neutro-bd);
  color: var(--st-neutro-fg);
}
.chip-estado::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  flex: none;
  background: var(--st-neutro-dot);
}

.chip-estado.st-pendiente  { background: var(--st-pend-bg); border-color: var(--st-pend-bd); color: var(--st-pend-fg); }
.chip-estado.st-pendiente::before  { background: var(--st-pend-dot); }
.chip-estado.st-ruta       { background: var(--st-ruta-bg); border-color: var(--st-ruta-bd); color: var(--st-ruta-fg); }
.chip-estado.st-ruta::before       { background: var(--st-ruta-dot); }
.chip-estado.st-entregado  { background: var(--st-ok-bg);   border-color: var(--st-ok-bd);   color: var(--st-ok-fg); }
.chip-estado.st-entregado::before  { background: var(--st-ok-dot); }
.chip-estado.st-incidencia { background: var(--st-inc-bg);  border-color: var(--st-inc-bd);  color: var(--st-inc-fg); }
.chip-estado.st-incidencia::before { background: var(--st-inc-dot); }
.chip-estado.st-devuelta   { background: var(--st-dev-bg);  border-color: var(--st-dev-bd);  color: var(--st-dev-fg); }
.chip-estado.st-devuelta::before   { background: var(--st-dev-dot); }
.chip-estado.st-neutro     { background: var(--st-neutro-bg); border-color: var(--st-neutro-bd); color: var(--st-neutro-fg); }
.chip-estado.st-neutro::before     { background: var(--st-neutro-dot); }

/* Sin punto: para etiquetas que no son un estado del envío (una marca de la pantalla,
   como «Bloqueada» o el origen de una coordenada). El punto es la señal de estado y
   gastarlo en otra cosa lo devalúa. Viene de la clase `.bg no-dot`, que se usaba en 5
   lugares y NUNCA estuvo definida en ningún CSS: esos badges se veían como texto suelto. */
.chip-estado.no-dot::before { display: none; }

/* ===== Fila teñida por estado =====
   Además de la barra lateral, la fila entera lleva el fondo tenue de su estado, para
   distinguir de un vistazo sin leer la columna. Se usa el MISMO `--st-*-bg` que el chip:
   ya está calibrado para que el texto de la tabla (--ink-800) siga sobre AA, y como es
   muy claro no compite con los chips ni con los botones de acción.

   Especificidad: estas reglas llevan 3 clases, así que ganan al hover genérico
   `.tbl tbody tr:hover td` (2 clases) y el color no se pierde al pasar el mouse. */
.tbl tbody tr.fila-estado.fe-pendiente  > td { background: var(--st-pend-bg); }
.tbl tbody tr.fila-estado.fe-ruta       > td { background: var(--st-ruta-bg); }
.tbl tbody tr.fila-estado.fe-entregado  > td { background: var(--st-ok-bg); }
.tbl tbody tr.fila-estado.fe-incidencia > td { background: var(--st-inc-bg); }
.tbl tbody tr.fila-estado.fe-devuelta   > td { background: var(--st-dev-bg); }

/* Hover sobre fila teñida: en vez de reemplazar el color (que borraría la señal de
   estado), se oscurece lo que haya debajo. Sirve para los 6 estados con una sola regla. */
.tbl tbody tr.fila-estado:hover > td {
  box-shadow: inset 0 0 0 9999px rgba(60,52,40,0.045);
}

/* Fila seleccionada. `tr.sel` se usaba en 4 pantallas (lista de expediciones, despacho,
   detalle de despacho, incidentados) y NUNCA estuvo definida: marcar el check no cambiaba
   nada en la fila. Va con borde izquierdo azul y fondo propio para que se distinga
   incluso encima del color de estado. */
.tbl tbody tr.sel > td {
  background: var(--navy-100);
  box-shadow: inset 0 0 0 9999px rgba(40,85,163,0.05);
}
.tbl tbody tr.sel > td:first-child { box-shadow: inset 3px 0 0 var(--navy-600), inset 0 0 0 9999px rgba(40,85,163,0.05); }
.tbl tbody tr.fila-estado.sel > td { background: var(--navy-100); }

/* Barra lateral de estado en la fila (tratamiento B del diseño): escanea en vertical
   sin colorear la fila entera. Se combina con el chip, no lo reemplaza. */
.tbl tbody tr.fila-estado > td:first-child { position: relative; }
.tbl tbody tr.fila-estado > td:first-child::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--st-neutro-dot);
}
.tbl tbody tr.fe-pendiente  > td:first-child::before { background: var(--st-pend-dot); }
.tbl tbody tr.fe-ruta       > td:first-child::before { background: var(--st-ruta-dot); }
.tbl tbody tr.fe-entregado  > td:first-child::before { background: var(--st-ok-dot); }
.tbl tbody tr.fe-incidencia > td:first-child::before { background: var(--st-inc-dot); }
.tbl tbody tr.fe-devuelta   > td:first-child::before { background: var(--st-dev-dot); }

/* Toolbar página */
.page-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.page-toolbar .field-inline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
}
.page-toolbar select {
  height: 34px;
  padding: 0 28px 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: white;
  font-size: 13px;
  color: var(--ink-900);
  min-width: 220px;
}
.page-toolbar select:focus {
  outline: none;
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.page-toolbar input[type=search] {
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: white;
  font-size: 13px;
  min-width: 240px;
}
.page-toolbar input[type=search]:focus {
  outline: none;
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
/* Fechas / hora / texto / número: mismo estándar que select y search (altura, bordes, radio). */
.page-toolbar input[type=date],
.page-toolbar input[type=time],
.page-toolbar input[type=text],
.page-toolbar input[type=number] {
  box-sizing: border-box;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: white;
  font-size: 13px;
  color: var(--ink-900);
}
.page-toolbar input[type=date],
.page-toolbar input[type=time] {
  font-family: inherit;
}
.page-toolbar input[type=date]:focus,
.page-toolbar input[type=time]:focus,
.page-toolbar input[type=text]:focus,
.page-toolbar input[type=number]:focus {
  outline: none;
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}

/* Fila de totales de GridDinamico: se queda pegada al pie de la tabla con scroll,
   para poder comparar el total con otro informe sin bajar hasta la última fila. */
.tbl tfoot tr.tot-grid td {
  position: sticky;
  bottom: 0;
  background: var(--ink-100);
  border-top: 2px solid var(--border-strong);
  font-weight: 700;
  color: var(--ink-900);
}

/* Selector de 1 o varios (SelectorMultiple.razor): un <details> que imita al
   select del toolbar y despliega un panel con checkboxes. Sin JS. */
.sel-multi {
  position: relative;
}
.sel-multi > summary {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  height: 34px;
  padding: 0 28px 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: white;
  font-size: 13px;
  color: var(--ink-900);
  min-width: 220px;
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sel-multi > summary::-webkit-details-marker { display: none; }
.sel-multi > summary::after {
  content: "▾";
  position: absolute;
  right: 10px;
  top: 8px;
  color: var(--ink-500);
  font-size: 11px;
}
.sel-multi[open] > summary {
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.sel-multi-panel {
  position: absolute;
  z-index: 30;
  top: 38px;
  left: 0;
  min-width: 240px;
  max-height: 320px;
  overflow-y: auto;
  padding: 6px;
  background: white;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(16,24,40,0.12);
}
.sel-multi-op {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: var(--r-sm);
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}
.sel-multi-op:hover { background: var(--ink-25); }
.sel-multi-sep {
  height: 1px;
  margin: 4px 2px;
  background: var(--border);
}

/* Pagination */
.pag {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--ink-500);
}
.pag .right { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.pag-btn {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  background: white;
  border-radius: var(--r-sm);
  color: var(--ink-700);
  cursor: pointer;
}
.pag-btn:hover:not(:disabled) { background: var(--ink-25); }
.pag-btn.active { background: var(--navy-800); color: white; border-color: var(--navy-800); }
.pag-btn:disabled { color: var(--ink-300); cursor: not-allowed; }

/* Empty state */
.empty {
  padding: 40px 20px;
  text-align: center;
  color: var(--ink-500);
  font-size: 12.5px;
}

/* ===== Modal ===== */
.modal-bg {
  position: fixed; inset: 0;
  background: rgba(38,32,24,0.45);   /* velo cálido: el navy de antes enfriaba la página al abrir cualquier modal */
  display: grid; place-items: center;
  z-index: 1000;
  backdrop-filter: blur(2px);
  /* El velo entra solo; el diálogo tiene su propia curva (ver .modal). */
  animation: modalVelo 140ms ease-out;
}
.modal {
  background: var(--bg-card);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-deep);
  width: min(960px, 96vw);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* Sube apenas y crece desde 97%: da sensación de que el panel "llega",
     sin el rebote que en una app operativa se vuelve molesto al décimo uso. */
  animation: modalEntra 180ms cubic-bezier(.16,.84,.44,1);
  transform-origin: center;
}

@keyframes modalVelo {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes modalEntra {
  from { opacity: 0; transform: translateY(8px) scale(.97); }
  to   { opacity: 1; transform: none; }
}

/* Paneles laterales (drawer): entran desde el borde, no desde el centro. */
.modal-bg.drawer { place-items: stretch; justify-items: end; }
.modal-bg.drawer .modal {
  max-height: 100vh;
  height: 100vh;
  border-radius: 0;
  animation: drawerEntra 200ms cubic-bezier(.16,.84,.44,1);
}
@keyframes drawerEntra {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: none; }
}

/* Accesibilidad: quien pidió menos movimiento ve el cambio, no el viaje. */
@media (prefers-reduced-motion: reduce) {
  .modal-bg,
  .modal,
  .modal-bg.drawer .modal { animation-duration: 1ms; }
}
/* Fila de filtros por columna: se aplica con Enter */
.tbl .tbl-filtros th {
  padding: 4px 6px;
  background: var(--ink-25);
  border-top: 1px solid var(--border);
  /* El sticky de .tbl thead th es POR CELDA: sin esto la fila de filtros también se
     pegaría a top:0 y taparía los títulos al scrollear. Scrollea con el contenido. */
  position: static;
  text-transform: none;
  letter-spacing: normal;
}
.tbl .tbl-filtros input {
  width: 100%;
  min-width: 74px;
  height: 24px;
  padding: 0 6px;
  font-size: 11px;
  font-weight: 400;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-card);
  color: var(--ink-900);
}
.tbl .tbl-filtros input:focus {
  outline: none;
  border-color: var(--navy-800);
}
/* Columna con filtro ya aplicado: se distingue de una sólo tecleada. */
.tbl .tbl-filtros input.activo {
  border-color: var(--navy-800);
  background: var(--info-50);
  font-weight: 500;
}
.tbl .tbl-filtros select {
  width: 100%;
  min-width: 74px;
  height: 24px;
  padding: 0 4px;
  font-size: 11px;
  font-weight: 400;
}

/* Modal ancho — drill-down de ~15 columnas: aprovecha todo el viewport.
   Hay que pisar `width` (no `max-width`): .modal fija width: min(960px, 96vw). */
.modal.modal-ancho { width: min(1760px, 97vw); }
.modal.modal-ancho .modal-body { padding: 14px 16px; }

/* Tabla del drill-down: las columnas cortas no se parten en varias líneas;
   sólo los textos libres (destinatario, dirección, observación) hacen wrap. */
.tbl-detalle th,
.tbl-detalle td { white-space: nowrap; }
.tbl-detalle td.wrap,
.tbl-detalle th.wrap { white-space: normal; min-width: 150px; }

.modal-hd {
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
}
.modal-hd h3 { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.modal-hd .x {
  margin-left: auto;
  width: 30px; height: 30px;
  border-radius: var(--r-sm);
  color: var(--ink-500);
  border: 0; background: transparent;
  cursor: pointer;
  font-size: 16px;
  display: grid; place-items: center;
}
.modal-hd .x:hover { background: var(--ink-100); color: var(--ink-900); }
.modal-body { padding: 18px 20px; overflow-y: auto; flex: 1; }
.modal-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 12px 20px; border-top: 1px solid var(--border);
  background: var(--ink-25);
}

/* Form grid */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px 16px; }
.form-grid .full { grid-column: 1 / -1; }
.form-grid .field { display: flex; flex-direction: column; gap: 4px; }
.form-grid label {
  font-size: 11px; font-weight: 600; color: var(--ink-700);
  letter-spacing: 0.01em; text-transform: uppercase;
}
.form-grid input[type=text], .form-grid input[type=tel],
.form-grid input[type=email], .form-grid input[type=number],
.form-grid input[type=date], .form-grid select, .form-grid textarea {
  height: 34px; padding: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: inherit; font-size: 13px;
  color: var(--ink-900); background: white; outline: none;
}
.form-grid textarea { height: auto; padding: 8px 10px; resize: vertical; min-height: 60px; }
.form-grid input:focus, .form-grid select:focus, .form-grid textarea:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.form-grid input:disabled, .form-grid select:disabled, .form-grid textarea:disabled {
  background: var(--ink-50); color: var(--ink-500); cursor: not-allowed;
}

.section-title {
  font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-500);
  margin: 14px 0 8px; padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.section-title:first-child { margin-top: 0; }

.checkbox-inline {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--ink-700); cursor: pointer;
}

/* Fila de KPIs / estadísticas (estimador + base de sectores) — tarjetas en línea. */
.est-kpis { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
.est-kpi {
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 16px; min-width: 112px;
}
.est-kpi span { display: block; font-size: 11px; color: var(--ink-500); margin-bottom: 2px; }
.est-kpi b { font-size: 18px; letter-spacing: -0.02em; color: var(--ink-900); }
.est-kpi.warn b { color: var(--warn); }
.est-singeo td { color: var(--ink-400); }

/* Panel "Procesar período": inputs de fecha con el estándar de .form-grid. */
.panel-proc { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.panel-proc .field { display: flex; flex-direction: column; gap: 4px; }
.panel-proc label {
  font-size: 11px; font-weight: 600; color: var(--ink-700);
  letter-spacing: 0.01em; text-transform: uppercase;
}
.panel-proc input[type=date] {
  height: 34px; padding: 0 10px; box-sizing: border-box;
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: inherit; font-size: 13px; color: var(--ink-900); background: white; outline: none;
}
.panel-proc input[type=date]:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}

/* Fila de filtros por columna en la cabecera de la grilla.
   Mismo estándar visual que los inputs de .page-toolbar / .form-grid. */
.tbl thead tr.col-filtros th { padding: 6px 8px; background: var(--ink-25); border-top: 1px solid var(--border); }
.tbl thead tr.col-filtros input,
.tbl thead tr.col-filtros select {
  width: 100%; height: 32px; padding: 0 10px; box-sizing: border-box;
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: inherit; font-size: 12.5px; font-weight: 400;
  color: var(--ink-900); background: white; outline: none; appearance: auto;
}
.tbl thead tr.col-filtros input::placeholder { color: var(--ink-400); font-weight: 400; }
.tbl thead tr.col-filtros input:focus,
.tbl thead tr.col-filtros select:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}

.tbl-bultos input { height: 26px; padding: 0 6px; font-size: 11.5px; width: 100%; }
.tbl-bultos td { padding: 4px 6px; }
.tbl-bultos .checkbox-cell { text-align: center; }
.tbl-bultos thead th { font-size: 10px; padding: 6px 8px; }

/* Inputs de la tabla de bultos: misma apariencia que los del formulario, en compacto. */
.tbl-bultos input[type=text], .tbl-bultos input[type=number] {
  border: 1px solid var(--border); border-radius: var(--r-sm);
  font-family: inherit; color: var(--ink-900); background: white; outline: none;
}
.tbl-bultos input[type=text]:focus, .tbl-bultos input[type=number]:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.tbl-bultos input:disabled {
  background: var(--ink-50); color: var(--ink-500); cursor: not-allowed;
}
.tbl-bultos input[type=number]::-webkit-outer-spin-button,
.tbl-bultos input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tbl-bultos input[type=number] { -moz-appearance: textfield; }
.tbl-bultos .checkbox-cell input { width: auto; height: auto; accent-color: var(--navy-500); }

/* Fila "Agregar bultos": mismo estándar visual que .form-grid. */
.bultos-add { display: flex; gap: 12px; margin-bottom: 12px; align-items: flex-end; flex-wrap: wrap; }
.bultos-add .field { display: flex; flex-direction: column; gap: 4px; }
.bultos-add label {
  font-size: 11px; font-weight: 600; color: var(--ink-700);
  letter-spacing: 0.01em; text-transform: uppercase;
}
.bultos-add input[type=text], .bultos-add input[type=number] {
  height: 34px; padding: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: inherit; font-size: 13px;
  color: var(--ink-900); background: white; outline: none;
}
.bultos-add input:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.bultos-add .btn { height: 34px; }

/* Listas de doble columna (select multiple) fuera de .page-toolbar: dual-list de
   Hubs (acceso remoto) y CargaMasivaFormato (campos). */
select[multiple] {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: white; font-family: inherit; font-size: 13px; color: var(--ink-900);
  padding: 4px; outline: none;
}
select[multiple]:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
select[multiple] option { padding: 3px 6px; border-radius: 3px; }

/* Textarea base: para las que quedan fuera de .form-grid (p. ej. mailing en
   ClienteDetalle). .form-grid textarea mantiene su regla (mayor especificidad). */
textarea {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px 10px; font-family: inherit; font-size: 13px;
  color: var(--ink-900); background: white; outline: none; resize: vertical;
}
textarea:focus {
  border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}

/* Make table rows clickable */
.tbl tbody tr.clickable { cursor: pointer; }
.tbl tbody tr.clickable:hover td { background: var(--navy-50); }

/* Buscador prominente */
.search-prominent {
  display: flex;
  align-items: center;
  gap: 10px;
  background: white;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 6px 10px 6px 14px;
  margin-bottom: 12px;
  box-shadow: var(--sh-card);
  transition: border-color 120ms, box-shadow 120ms;
}
.search-prominent:focus-within {
  border-color: var(--navy-500);
  box-shadow: 0 0 0 3px rgba(61,111,196,0.12);
}
.search-prominent .icon { font-size: 14px; opacity: 0.6; }
.search-prominent input {
  flex: 1;
  height: 36px;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: inherit;
  font-size: 13.5px;
  color: var(--ink-900);
}
.search-prominent input::placeholder { color: var(--ink-400); }

/* Input numérico de salto de página */
.pag-input {
  width: 60px;
  height: 28px;
  text-align: center;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 12px;
  background: white;
  color: var(--ink-800);
  outline: none;
  -moz-appearance: textfield;
}
.pag-input::-webkit-outer-spin-button,
.pag-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pag-input:focus { border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(61,111,196,0.12); }

.btn-sm { height: 26px; padding: 0 8px; font-size: 11.5px; }

/* ============================================================
   Banner de error de Blazor — GLOBAL (sin scope).
   Debe vivir aquí y no en un *.razor.css de un layout: el div
   #blazor-error-ui se renderiza tanto en MainLayout (login) como
   en AppLayout (autenticado). Si la regla estuviera scopeada a un
   solo layout, el banner quedaría visible siempre en el otro.
   Oculto por defecto; blazor.web.js lo muestra (display:block)
   solo ante un error real del circuito.
   ============================================================ */
#blazor-error-ui {
  color-scheme: light only;
  background: lightyellow;
  bottom: 0;
  box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
  box-sizing: border-box;
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem 1.25rem;
  position: fixed;
  width: 100%;
  z-index: 1000;
}
#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

/* ===== Boletas Enel: contadores del encabezado ===== */
.be-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 14px;
}
.be-stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.be-stat-num { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; }
.be-stat-lbl { font-size: 11.5px; color: var(--ink-500); }
@media (max-width: 760px) { .be-stats { grid-template-columns: repeat(2, 1fr); } }

/* ===== Boletas Enel: resaltado de fila recién llegada (feed en vivo) ===== */
@keyframes filaNuevaFade {
  0%   { background: #fff7cc; }
  100% { background: transparent; }
}
.tbl tbody tr.fila-nueva td { animation: filaNuevaFade 2.5s ease-out; }

/* ===== Evidencia (popup fotos + mapa) ===== */
.col-acc { text-align: center; width: 44px; }
.btn-evidencia {
  background: transparent;
  border: 1px solid var(--ink-200);
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 4px 6px;
}
.btn-evidencia:hover { background: var(--ink-100); }

/* ===== Skeleton de carga =====
   Dibuja la forma del contenido que viene, para que al llegar los datos no salte el
   layout. Todo con tokens: cuando cambie la paleta, el skeleton la sigue solo. */
.sk { width: 100%; }
.sk-bloque {
  display: block;
  height: 12px;
  border-radius: var(--r-sm);
  background: var(--ink-100);
  position: relative;
  overflow: hidden;
}
/* El brillo recorre el bloque; se detiene con prefers-reduced-motion (más abajo). */
.sk-bloque::after {
  content: "";
  position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg,
      transparent 0%,
      rgba(255,255,255,.65) 50%,
      transparent 100%);
  animation: skBrillo 1.4s ease-in-out infinite;
}

.sk-tabla { display: flex; flex-direction: column; }
.sk-fila {
  display: flex; align-items: center; gap: 22px;
  padding: 0 18px; height: 42px;
  border-bottom: 1px solid var(--ink-50);
}
.sk-fila > .sk-bloque { flex: 1; }
.sk-fila-hd {
  height: 38px;
  background: var(--ink-25);
  border-bottom: 1px solid var(--border);
}
.sk-fila-hd > .sk-bloque { height: 9px; }

.sk-pag {
  display: flex; align-items: center;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
}

.sk-cards { display: grid; gap: 10px; }
.sk-card {
  display: flex; flex-direction: column; gap: 9px;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-card);
  padding: 14px 16px;
}

.sk-detalle { display: flex; flex-direction: column; gap: 10px; padding: 18px 20px; }
.sk-grid2 {
  display: grid; grid-template-columns: 1fr 1fr; gap: 14px 20px;
  margin-top: 8px;
}
.sk-campo { display: flex; flex-direction: column; gap: 6px; }
.sk-input { height: 32px; border-radius: var(--r-md); }

.sk-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px 18px; padding: 18px 20px;
}

.sk-lineas { display: flex; flex-direction: column; gap: 9px; padding: 16px 18px; }

@keyframes skBrillo {
  100% { transform: translateX(100%); }
}

/* ===== Indicador de carga EN LÍNEA (tres puntos) =====
   Para esperas cortas al lado de un control, donde un skeleton sería desproporcionado.
   Se usa en la carga masiva y en la lista de expediciones, pero NUNCA estuvo definido:
   los tres <i> quedaban sin tamaño ni color, así que el indicador era invisible y la
   pantalla parecía congelada mientras procesaba. */
.dotload {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  vertical-align: middle;
}
.dotload i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--navy-500);
  display: block;
  animation: dotloadPulso 1.1s ease-in-out infinite;
}
.dotload i:nth-child(2) { animation-delay: .16s; }
.dotload i:nth-child(3) { animation-delay: .32s; }

@keyframes dotloadPulso {
  0%, 80%, 100% { opacity: .25; transform: scale(.85); }
  40%           { opacity: 1;   transform: none; }
}
/* Sin movimiento: el punto sigue estando, sólo deja de latir. */
@media (prefers-reduced-motion: reduce) {
  .dotload i { animation: none; opacity: .75; }
}

/* ===== Grilla ocupada: hay una acción de lote corriendo sobre estas filas =====
   Se atenúa y deja de aceptar clics, pero NO se desmonta: reemplazarla por un skeleton
   perdería los filtros de columna y el texto del buscador, y además el usuario necesita
   seguir viendo QUÉ filas está por perder mientras se eliminan. */
.tbl-ocupada {
  opacity: .45;
  pointer-events: none;
  user-select: none;
  transition: opacity 120ms ease-out;
}

/* ===== Pines numerados del estimador de recorrido =====
   Cada parada muestra EL MISMO número que la hoja de ruta: sin eso el mapa no se
   puede seguir. El número va dentro del pin (no en un tooltip aparte), así ocupa lo
   mismo con o sin él y no satura con 150+ paradas.
   Viven acá y no en el .razor porque Leaflet crea los marcadores fuera del scope. */
.est-pin {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  font: 600 11px/1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  color: #fff;
  background: var(--navy-500);
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(40,34,26,.45);
  cursor: pointer;
  transition: transform 120ms ease-out, box-shadow 120ms ease-out;
}
/* Partida y última parada: son las dos que se buscan primero en una hoja de ruta. */
.est-pin-inicio { background: var(--st-ok-dot);  width: 30px; height: 30px; font-size: 12px; }
.est-pin-fin    { background: var(--st-dev-dot); }
.est-pin:hover  { transform: scale(1.18); box-shadow: 0 3px 10px rgba(40,34,26,.5); }

/* Parada enfocada desde la hoja de ruta. */
.est-pin-sel {
  background: var(--st-inc-dot);
  transform: scale(1.35);
  box-shadow: 0 0 0 4px rgba(165,50,42,.28), 0 3px 10px rgba(40,34,26,.5);
}

/* Grupo de paradas apiñadas (Leaflet.markercluster). Reemplaza al icono por
   defecto de la librería (verde/amarillo/rojo), que en un sistema de despacho se
   leería como semáforo de estado. Acá el número es CUÁNTAS paradas hay en ese
   punto, así que va en el mismo azul de los pines, con un halo que sugiere el
   apilamiento. Se abre con un clic. */
.est-cluster {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%; height: 100%;
  border-radius: 50%;
  font: 600 12px/1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  color: #fff;
  background: var(--navy-600);
  border: 2px solid #fff;
  box-shadow: 0 0 0 3px rgba(61,111,196,.30), 0 2px 6px rgba(40,34,26,.40);
  cursor: pointer;
  transition: transform 120ms ease-out, box-shadow 120ms ease-out;
}
.est-cluster-cm { font-size: 13px; }
.est-cluster-cg { font-size: 13px; background: var(--navy-700); box-shadow: 0 0 0 4px rgba(29,58,107,.30), 0 2px 8px rgba(40,34,26,.45); }
.est-cluster:hover { transform: scale(1.12); box-shadow: 0 0 0 5px rgba(61,111,196,.35), 0 3px 10px rgba(40,34,26,.5); }

/* Flecha de sentido del recorrido, en el punto medio de cada tramo. El triángulo
   apunta a la derecha y el JS lo rota con el ángulo del tramo; el contorno blanco
   lo mantiene legible tanto sobre calle como sobre parque o agua. */
.est-flecha {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
}
.est-flecha::before {
  content: '';
  width: 0; height: 0;
  border-left: 9px solid var(--navy-600);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
}

/* Fila de la hoja de ruta: se ve que es clicable y cuál está enfocada. */
.tbl tbody tr.est-fila { cursor: pointer; }
.tbl tbody tr.est-fila-sel > td { background: var(--st-inc-bg); font-weight: 500; }
.tbl tbody tr.est-fila-sel > td:first-child { box-shadow: inset 3px 0 0 var(--st-inc-dot); }

/* Sólo para lectores de pantalla: el skeleton es decorativo, el aviso es el texto. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .sk-bloque::after { animation: none; opacity: 0; }
}

/* Barra de progreso de la carga masiva (worker en segundo plano) */
.cm-barra {
  height: 10px;
  background: var(--ink-100);
  border-radius: 999px;
  overflow: hidden;
}
.cm-barra-fill {
  height: 100%;
  background: var(--navy-800);
  border-radius: 999px;
  transition: width .3s ease;
}

/* Corregir estado de expedición (Entregado ↔ No entregado, sub-privilegio 6) */
.btn-cambiar-estado {
  background: transparent;
  border: 1px solid var(--ink-200);
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  padding: 4px 6px;
  color: var(--ink-700);
}
.btn-cambiar-estado:hover:not(:disabled) { background: var(--navy-800); border-color: var(--navy-800); color: #fff; }
/* Estado no corregible: se ve, pero apagado. El title dice por qué. */
.btn-cambiar-estado:disabled { opacity: .32; cursor: not-allowed; }

.evi-titulo {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 16px 0 8px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--ink-100);
}
.evi-titulo:first-child { margin-top: 0; }

.evi-timeline { list-style: none; margin: 0; padding: 0; }
.evi-timeline li { display: flex; gap: 10px; padding: 6px 0; }
.evi-dot {
  background: var(--brand);
  border-radius: 50%;
  flex: 0 0 auto;
  height: 9px;
  margin-top: 5px;
  width: 9px;
}
.evi-ev { flex: 1; min-width: 0; }
.evi-ev-hd { display: flex; gap: 10px; justify-content: space-between; align-items: baseline; }
.evi-ev-hd .mono { font-size: 11px; white-space: nowrap; }

.evi-fotos { display: flex; flex-wrap: wrap; gap: 10px; }
/* Miniatura clicable: es un <button> (abre el visor interno), no un enlace a
   otra pestaña, así que hay que apagarle el estilo propio del botón. */
.evi-foto {
  background: none;
  border: 1px solid var(--ink-100);
  border-radius: 8px;
  cursor: zoom-in;
  display: block;
  height: 150px;
  overflow: hidden;
  padding: 0;
  position: relative;
  width: 150px;
}
.evi-foto:hover { border-color: var(--navy-500); }
.evi-foto img { height: 100%; object-fit: cover; width: 100%; display: block; }
.evi-foto-msg { display: none; }
/* Lupa: pista de que la foto se amplía acá mismo. */
.evi-foto-lupa {
  align-items: center;
  background: rgba(10,22,40,0.6);
  border-radius: 6px;
  bottom: 6px;
  color: #fff;
  display: flex;
  font-size: 13px;
  height: 24px;
  justify-content: center;
  opacity: 0;
  position: absolute;
  right: 6px;
  transition: opacity 120ms ease-out;
  width: 24px;
}
.evi-foto:hover .evi-foto-lupa { opacity: 1; }
.evi-foto.evi-foto-error { align-items: center; background: var(--ink-100); cursor: default; display: flex; justify-content: center; }
.evi-foto.evi-foto-error img, .evi-foto.evi-foto-error .evi-foto-lupa { display: none; }
.evi-foto.evi-foto-error .evi-foto-msg {
  color: var(--ink-500);
  display: block;
  font-size: 11px;
}

/* ===== Visor de fotos (lightbox) =====
   Ampliar la evidencia sin salir de la pantalla: antes la miniatura abría la
   foto en otra pestaña y se perdía el contexto del popup. */
.evi-visor {
  position: fixed; inset: 0;
  z-index: 1100;                      /* sobre .modal-bg (1000) */
  background: rgba(10,22,40,0.94);
  display: flex;
  flex-direction: column;
  animation: modalVelo 120ms ease-out;
}
.evi-visor:focus { outline: none; }
.evi-visor-hd {
  align-items: center;
  color: #fff;
  display: flex;
  flex: 0 0 auto;
  gap: 12px;
  justify-content: space-between;
  padding: 10px 14px;
}
.evi-visor-tit { font-size: 12.5px; }
.evi-visor-tit .muted { color: rgba(255,255,255,0.6); }
.evi-visor-btns { align-items: center; display: flex; gap: 6px; }
.evi-visor-zoom { color: rgba(255,255,255,0.75); font-size: 11.5px; min-width: 52px; text-align: center; }
.evi-visor-lienzo {
  align-items: center;
  display: flex;
  flex: 1 1 auto;
  justify-content: center;
  /* Con zoom la imagen crece de verdad (width en %), así el scroll del propio
     contenedor sirve para recorrerla; un transform:scale no daría desplazamiento. */
  overflow: auto;
  padding: 0 14px 14px;
}
.evi-visor-img { cursor: zoom-in; display: block; margin: auto; }
.evi-visor-img.ajustada { max-height: 100%; max-width: 100%; object-fit: contain; cursor: zoom-in; }
/* Girada un cuarto de vuelta: la caja de layout NO rota con el transform, así que
   se limita contra la dimensión contraria del lienzo (menos el alto de la barra). */
.evi-visor-img.ajustada.acostada { max-height: 100vw; max-width: calc(100vh - 72px); }
.evi-visor-img:not(.ajustada) { cursor: zoom-out; max-width: none; }
.evi-visor-nav {
  background: rgba(255,255,255,0.12);
  border: 0;
  border-radius: 50%;
  color: #fff;
  cursor: pointer;
  font-size: 26px;
  height: 44px;
  line-height: 1;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
}
.evi-visor-nav:hover { background: rgba(255,255,255,0.24); }
.evi-visor-nav.izq { left: 14px; }
.evi-visor-nav.der { right: 14px; }

.evi-mapa {
  border: 1px solid var(--ink-100);
  border-radius: 8px;
  height: 340px;
  width: 100%;
  /* Es un contenedor de Leaflet: sin esto los tiles se salen del borde redondeado. */
  overflow: hidden;
}
/* Pin del punto de entrega. divIcon propio (como el estimador) en vez del
   marcador por defecto de Leaflet: sus PNG se resuelven relativos a la URL de la
   página (el CSS va inline) y en /reportes/… daban 404, o sea el punto no se veía. */
.evi-pin {
  background: var(--navy-600);
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(10,22,40,0.45);
  display: block;
  height: 18px;
  margin: 4px;
  width: 18px;
}
/* Halo: ubica el punto de un vistazo sobre el mapa. */
.evi-pin::after {
  border: 2px solid rgba(40,85,163,0.35);
  border-radius: 50%;
  content: '';
  display: block;
  height: 32px;
  margin: -9px 0 0 -9px;
  width: 32px;
}
.evi-popup .leaflet-popup-content { font-size: 12px; line-height: 1.5; margin: 10px 12px; }
.evi-popup .leaflet-popup-content-wrapper { border-radius: 8px; }
.evi-popup .evi-popup-sec { color: var(--ink-500); font-size: 11px; }

/* ==========================================================================
   MONITOREO DE CONDUCTORES (mapa en vivo + recorrido del día)
   Los pines y las fichas viven acá, no en los .razor, porque Leaflet crea ese
   HTML fuera del scope de los componentes (mismo criterio que .est-pin).
   ========================================================================== */

/* Cifras de cabecera del mapa en vivo. Misma forma que .est-kpi pero con el
   color del estado: la primera lectura de la página es "cuántos están bien". */
.mon-kpis { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.mon-kpi {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 8px 14px;
  min-width: 108px;
  box-shadow: var(--sh-card);
}
.mon-kpi span { display: block; font-size: 11px; color: var(--ink-500); margin-bottom: 2px; }
.mon-kpi b { font-size: 18px; letter-spacing: -0.02em; color: var(--ink-900); }
.mon-kpi.ok b   { color: var(--ok); }
.mon-kpi.err b  { color: var(--err); }

/* Lista + mapa. En pantallas angostas se apila: el mapa primero, que es el
   contenido principal, y la lista debajo. */
.mon-split {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 12px;
  align-items: start;
}
/* Recorrido del día: el mapa es el contenido principal y la bitácora acompaña,
   al revés que el mapa en vivo (donde la lista de la flota es la que se lee). */
.mon-split.inverso { grid-template-columns: 1fr 420px; }
@media (max-width: 1100px) {
  .mon-split, .mon-split.inverso { grid-template-columns: 1fr; }
  .mon-split .mon-lista { order: 2 !important; }
  .mon-split .mon-mapa-card { order: 1 !important; }
}

.mon-lista { display: flex; flex-direction: column; max-height: 640px; }
/* Dirección del documento en la bitácora: línea propia y recorte por ancho.
   La clase .ellipsis general es inline-block y dejaba la dirección pegada al
   código del documento en la misma línea. */
.mon-dir {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 2px;
}
.mon-lista-body { overflow-y: auto; flex: 1; }
.mon-mapa-card { padding: 0; overflow: hidden; }
.mon-mapa { height: 560px; width: 100%; }
.mon-mapa-alto { height: 620px; }

/* Fila de conductor. Todo el bloque es clickeable (enfoca en el mapa), salvo
   el enlace al recorrido, que navega. */
.mon-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.mon-item:hover { background: var(--ink-25); }
.mon-item.sel { background: var(--info-50); box-shadow: inset 3px 0 0 var(--navy-600); }
.mon-item-txt { flex: 1; min-width: 0; }
.mon-item-txt b { display: block; font-size: 12.5px; font-weight: 500; color: var(--ink-900); }
.mon-item-txt > .muted { display: block; font-size: 11px; }
.mon-item-cifras { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 3px; }
.mon-item-cifras em {
  font-style: normal;
  font-size: 10.5px;
  color: var(--ink-600);
  background: var(--ink-50);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 1px 5px;
}
.mon-item-cifras em.inc     { color: var(--st-inc-fg); background: var(--st-inc-bg); border-color: var(--st-inc-bd); }
.mon-item-cifras em.pend    { color: var(--st-pend-fg); background: var(--st-pend-bg); border-color: var(--st-pend-bd); }
.mon-item-cifras em.bat-baja{ color: var(--err); background: var(--err-50); border-color: var(--st-inc-bd); }
.mon-item-cifras em.alerta  { color: #fff; background: var(--err); border-color: var(--err); }
.mon-item-link { font-size: 11px; color: var(--navy-600); text-decoration: none; white-space: nowrap; }
.mon-item-link:hover { text-decoration: underline; }

/* Semáforo de frescura de la señal. Se repite en la lista y en la leyenda. */
.mon-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  margin-top: 5px;
  flex: 0 0 auto;
  box-shadow: 0 0 0 3px rgba(0,0,0,0.05);
}
.mon-dot.linea, .mon-dot.ok   { background: var(--st-ok-dot); }
.mon-dot.sin, .mon-dot.err    { background: var(--st-inc-dot); }

.mon-leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--ink-500);
  background: var(--ink-25);
}
.mon-leyenda span { display: inline-flex; align-items: center; gap: 5px; }
.mon-leyenda .mon-dot { margin-top: 0; }

/* Pestañas de la bitácora del recorrido. */
.mon-tab {
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 4px 8px;
  font: 500 12px/1.4 var(--font-sans);
  color: var(--ink-500);
  cursor: pointer;
}
.mon-tab:hover { color: var(--ink-800); }
.mon-tab.on { color: var(--navy-600); border-bottom-color: var(--navy-600); }

.mon-fila { cursor: pointer; }
.mon-fila.sel td { background: var(--info-50); }

/* ── Pin del conductor en el mapa en vivo ─────────────────────────────────
   Iniciales dentro del pin y color por estado de la señal: con 45 equipos en
   pantalla, el color dice a quién hay que mirar y las iniciales quién es sin
   tener que abrir la ficha. */
.mon-pin {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 34px; height: 34px;
  border-radius: 50%;
  font: 600 11.5px/1 var(--font-sans);
  color: #fff;
  background: var(--st-ok-dot);
  border: 2.5px solid #fff;
  box-shadow: 0 2px 6px rgba(40,34,26,.45);
  cursor: pointer;
  transition: transform 120ms ease-out, box-shadow 120ms ease-out;
}
.mon-pin i { font-style: normal; }
.mon-pin-linea    { background: var(--st-ok-dot); }
.mon-pin-sin      { background: var(--ink-400); }
.mon-pin:hover    { transform: scale(1.12); box-shadow: 0 3px 10px rgba(40,34,26,.5); }
.mon-pin-sel {
  transform: scale(1.2);
  box-shadow: 0 0 0 4px rgba(40,85,163,.30), 0 3px 10px rgba(40,34,26,.5);
}
/* El equipo declaró "ubicación simulada" (mock location): es lo primero que hay
   que ver, porque invalida el punto sin importar qué tan reciente sea. */
.mon-pin-alerta {
  position: absolute;
  top: -5px; right: -5px;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--err);
  border: 2px solid #fff;
  font: 700 9px/11px var(--font-sans);
  font-style: normal;
  text-align: center;
}
/* Nombre bajo el pin: en el zoom de una comuna hay que distinguirlos sin pinchar. */
.mon-pin-nombre {
  position: absolute;
  top: 34px; left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font: 500 10.5px/1.4 var(--font-sans);
  color: var(--ink-800);
  background: rgba(255,255,255,0.86);
  border-radius: var(--r-sm);
  padding: 0 4px;
  pointer-events: none;
}

/* Ficha del pin (Leaflet popup). Tabla de dos columnas: etiqueta a la izquierda,
   dato a la derecha; se lee más rápido que un párrafo. */
.mon-popup-wrap .leaflet-popup-content { margin: 10px 12px; font-size: 12px; }
.mon-popup-wrap .leaflet-popup-content-wrapper { border-radius: 8px; }
.mon-popup b { font-size: 12.5px; color: var(--ink-900); }
.mon-popup table { border-collapse: collapse; margin-top: 6px; width: 100%; }
.mon-popup th {
  text-align: left;
  font-weight: 400;
  color: var(--ink-500);
  padding: 1px 10px 1px 0;
  white-space: nowrap;
  vertical-align: top;
}
.mon-popup td { color: var(--ink-800); padding: 1px 0; }
.mon-popup-alerta {
  margin-top: 5px;
  color: var(--err);
  background: var(--err-50);
  border-radius: var(--r-sm);
  padding: 2px 6px;
  font-size: 11px;
}
.mon-popup-link { display: inline-block; margin-top: 8px; font-size: 11.5px; color: var(--navy-600); }

/* ── Inventario de dispositivos ──────────────────────────────────────────── */

.disp-graficos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 12px;
}
@media (max-width: 1100px) { .disp-graficos { grid-template-columns: 1fr; } }

/* Barra de distribución (versiones, plataformas, marcas). Etiqueta, pista y
   valor en tres columnas fijas para que todas las barras arranquen alineadas
   por más que los nombres midan distinto. */
.disp-barra {
  display: grid;
  grid-template-columns: 130px 1fr 82px;
  align-items: center;
  gap: 10px;
  padding: 3px 0;
  font-size: 11.5px;
  color: var(--ink-700);
}
.disp-barra-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.disp-barra-pista {
  display: block;
  height: 8px;
  background: var(--ink-100);
  border-radius: 4px;
  overflow: hidden;
}
.disp-barra-pista i {
  display: block;
  height: 100%;
  min-width: 2px;
  background: var(--navy-500);
  border-radius: 4px;
}
/* La versión vigente se distingue del resto: es la referencia contra la que se
   mide el rezago de los demás equipos. */
.disp-barra.vigente { color: var(--ink-900); font-weight: 500; }
.disp-barra.vigente .disp-barra-pista i { background: var(--st-ok-dot); }
.disp-barra-val { text-align: right; color: var(--ink-500); font-variant-numeric: tabular-nums; }

/* Ficha del equipo en el modal: etiqueta a la izquierda, dato a la derecha. */
.disp-ficha th {
  text-align: left;
  font-weight: 400;
  color: var(--ink-500);
  white-space: nowrap;
  width: 190px;
  padding: 5px 12px 5px 0;
  vertical-align: top;
}
.disp-ficha td { padding: 5px 0; color: var(--ink-800); }
.disp-ficha tbody tr:hover td { background: transparent; }

/* ── Recorrido del día ───────────────────────────────────────────────────── */

/* Primera y última marca del trayecto. */
.rec-extremo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  font: 700 12px/1 var(--font-sans);
  color: #fff;
  border: 2.5px solid #fff;
  box-shadow: 0 2px 6px rgba(40,34,26,.45);
}
.rec-extremo-inicio { background: var(--st-ok-dot); }
.rec-extremo-fin    { background: var(--st-dev-dot); }

/* Certificación en terreno. Punto chico: son cientos por jornada y no deben
   competir con la traza; el anillo ámbar marca las que no calzan con el GPS. */
.rec-hito {
  display: block;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(40,34,26,.45);
}
.rec-hito-ok  { background: var(--st-ok-dot); }
.rec-hito-inc { background: var(--st-inc-dot); }
.rec-hito-alerta { box-shadow: 0 0 0 3px rgba(194,128,28,.55), 0 1px 3px rgba(40,34,26,.45); }

/* Marcador que avanza durante la reproducción de la jornada. */
.rec-vehiculo {
  display: block;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--navy-800);
  border: 3px solid #fff;
  box-shadow: 0 0 0 4px rgba(21,41,77,.25), 0 2px 6px rgba(40,34,26,.5);
}

/* Barra de reproducción: es un control de Leaflet, va dentro del mapa. */
.rec-player {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255,255,255,0.95);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-pop);
  padding: 6px 10px;
  font: 500 11.5px/1 var(--font-sans);
}
.rec-player .rec-play {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--navy-600);
  background: var(--navy-600);
  color: #fff;
  cursor: pointer;
  font-size: 11px;
}
.rec-player .rec-slider { width: 230px; accent-color: var(--navy-600); }
.rec-player .rec-hora {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-800);
  min-width: 42px;
}
.rec-player .rec-factor { font-size: 11px; padding: 2px 4px; }

/* Muestras de color de la leyenda del recorrido. */
.rec-l { display: inline-block; width: 16px; height: 3px; border-radius: 2px; }
.rec-l-lento  { background: #7FA3DC; }
.rec-l-medio  { background: #3d6fc4; }
.rec-l-rapido { background: #2855a3; }
.rec-l-alto   { background: #A5322A; }
.rec-l-desvio { background: repeating-linear-gradient(90deg, #C2801C 0 4px, transparent 4px 7px); height: 3px; }

/* ===== Impresión global =====
   Al imprimir cualquier página ocultamos el cromo (topbar .tb, sidebar .sb y
   todo lo marcado .no-print), colapsamos el grid del layout a una sola columna
   y soltamos los overflow/altura fija de .main/.page para que el contenido
   fluya por varias hojas en vez de recortarse a la primera. */
@media print {
  .no-print, .tb, .sb { display: none !important; }
  .app, .app.sb-collapsed { grid-template-columns: 1fr !important; }
  .main { overflow: visible !important; }
  .page { overflow: visible !important; padding: 0 !important; }
  html, body, #appRoot, .app, .main { height: auto !important; min-height: 0 !important; }
}
