    /* VARIABLES POR DEFECTO: MODO NOCTURNO (DARK PREMIUM) */
    /* ==========================================================
       PALETA — neutros azulados frios (matiz ~215) para bajar la
       sensacion de brillo en jornadas largas. El color es
       estrictamente semantico: azul = foco de teclado / seleccion,
       rojo = error, verde = exito, ambar = advertencia. No hay
       color decorativo de marca dentro de la interfaz.
       ========================================================== */
    :root {
      /* Azul profundo en vez del gris azulado anterior: el fondo se lee como
         sala de control y no como documento. --bg-deep es el borde de la app
         (columna de navegacion), un escalon mas oscuro que el lienzo. */
      --bg-deep: #060e20;
      --bg-color: #0b1326;
      --card-bg: #131b2e;
      --primary-color: #22d3ee;   /* foco de teclado y estado activo */
      --accent-color: #22d3ee;
      --success-color: #10b981;
      --danger-color: #ef4444;
      --warning-color: #f59e0b;
      --text-main: #E3E9F0;
      --text-muted: #98A6B8;
      --border-color: #232f48;
      --table-bg: #0e1626;
      --input-bg: #0e1626;
      --header-bg: #131b2e;
      --header-text: #E3E9F0;
      --header-muted: #98A6B8;

      /* Los controles nativos (icono del calendario, lista desplegable de los
         select, barras de scroll) los dibuja el navegador, no el CSS. Sin esto
         asume tema claro y el icono del calendario sale oscuro sobre fondo
         oscuro: por eso no se veia en los 14 campos de fecha. */
      color-scheme: dark;

      /* Tokens nuevos de densidad y estado */
      /* Derivados del fondo nuevo: si quedaban los viejos, la fila alterna y
         el hover tiraban al gris sobre un lienzo azul. */
      --zebra: #172039;        /* fila alterna: 1,8% de luminancia de diferencia */
      --hover: #1d2745;
      --line-soft: #1b2440;
      --focus-wash: #103042;
      --row-h: 32px;

      --color-titular: #4ADE80;
      --bg-titular: rgba(74, 222, 128, 0.15);
      --color-backup: #FBBF24;
      --bg-backup: rgba(251, 191, 36, 0.15);
      --color-descanso: #6EA8FE;
      --bg-descanso: rgba(110, 168, 254, 0.15);
      --color-licencia: #F87171;
      --bg-licencia: rgba(248, 113, 113, 0.15);

      /* Aclarados para pasar 4,5:1 sobre su propio fondo al 15% en oscuro:
         los valores anteriores daban 4,05 y 3,28. */
      --color-gregorio: #FB7185;
      --color-posesion: #34D399;
      --color-cabonegro: #A5B4FC;
      --color-puntaarenas: #eab308;
      --color-sombrero: #f97316;
      --color-cullen: #38bdf8;

      /* Color propio de cada gestion. Violeta y verde azulado estan lejos uno
         del otro y lejos de los cuatro colores de estado (verde, rojo, ambar y
         el cian del foco), asi que el sector se lee sin confundirse con "esto
         esta bien" ni con "esto esta seleccionado". */
      --color-continente: #a78bfa;
      --bg-continente: rgba(167, 139, 250, 0.16);
      --color-isla: #2dd4bf;
      --bg-isla: rgba(45, 212, 191, 0.16);

      --bg-prod-potable: #028090;
      --bg-prod-vacuum: #7C3AED;   /* #8b5cf6 daba 4,23:1 con texto blanco */
      --bg-prod-crudo: #475569;
      --bg-prod-industrial: #b45309;
      --text-prod-crudo: #ffffff;
    }

    [data-theme="light"] {
      /* El fondo no es blanco puro: ocho horas de blanco a pantalla
         completa es la principal fuente de fatiga visual. */
      --bg-deep: #DFE5EC;
      --bg-color: #E9EDF2;
      --card-bg: #FBFCFD;
      --primary-color: #1D4ED8;
      --accent-color: #1D4ED8;
      --success-color: #146B33;
      --danger-color: #B42318;
      --warning-color: #92400E;
      --text-main: #16202C;
      --text-muted: #55637A;
      --border-color: #D5DCE5;
      --table-bg: #FBFCFD;
      --input-bg: #FFFFFF;
      --header-bg: #FBFCFD;
      --header-text: #16202C;
      --header-muted: #55637A;

      color-scheme: light;

      --zebra: #F1F4F8;
      --hover: #E4EBF3;
      --line-soft: #E2E8EF;
      --focus-wash: #DBE6FE;

      --bg-titular: #E2F8E9; --color-titular: #146B33;
      --bg-backup: #FBEBD4; --color-backup: #92400E;
      --bg-descanso: #DBE6FE; --color-descanso: #1D4ED8;
      --bg-licencia: #FCE8E6; --color-licencia: #B42318;

      /* Los colores de base son categoricos, no decorativos: identifican
         un lugar. En claro necesitan tonos mas oscuros para pasar 4,5:1
         sobre sus fondos al 15% — antes heredaban los del tema oscuro. */
      --color-gregorio: #BE123C;
      --color-posesion: #065F46;
      --color-cabonegro: #4338CA;
      --color-puntaarenas: #854D0E;
      --color-sombrero: #9A3412;
      --color-cullen: #0369A1;
      --color-continente: #6D28D9;
      --bg-continente: #EDE9FE;
      --color-isla: #0F766E;
      --bg-isla: #CCFBF1;

      --bg-prod-crudo: #16202C;
      --text-prod-crudo: #FBFCFD;
    }

    /* El tema se marca en <body>, pero la barra de scroll del documento la
       dibuja <html>: sin esto queda oscura sobre el tema claro. */
    html:has(body[data-theme="light"]) { color-scheme: light; }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: 'Inter', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    }

    body {
      background-color: var(--bg-color);
      color: var(--text-main);
      padding: 12px;
      transition: background-color 0.3s, color 0.3s;
    }

    /* ==========================================================
       ENCABEZADO
       Ocupaba 137px y con los KPI se comia el 21% de la pantalla antes
       del primer dato. Todo en una fila: logo chico, titulo al lado y
       controles a la derecha. Sin subtitulo: era texto de folleto que a
       quien entra todos los dias no le dice nada.
       ========================================================== */
    header {
      /* Fijo arriba: los controles de aqui —la gestion elegida sobre todo—
         valen mientras se lee una tabla larga, y antes se iban con el scroll.
         El z-index lo deja por encima del rail, que tambien es sticky. */
      position: sticky;
      top: 0;
      z-index: 30;
      background: var(--header-bg);
      border: 1px solid var(--border-color);
      padding: 6px 12px;
      border-radius: 6px;
      margin-bottom: 8px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      flex-wrap: wrap;
      gap: 8px;
    }

    header h1 {
      font-size: 0.95rem; font-weight: 700; letter-spacing: -.01em;
      color: var(--header-text); white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis;
    }

    .header-actions { display: flex; gap: 8px; flex-wrap: wrap; }

    /* ==========================================================
       FILTRO "MI GESTION": CONTROL SEGMENTADO
       Son tres opciones fijas y excluyentes. En un select habia que abrirlo
       para saber que otra cosa se podia elegir y hacian falta dos clics para
       cambiar; a la vista se cambia de uno y siempre se ve entre que se esta
       eligiendo. El select sigue existiendo escondido: es donde vive el valor.
       ========================================================== */
    .seg-sector {
      display: inline-flex; align-items: stretch; padding: 2px;
      background: var(--card-bg);
      border: 1px solid var(--border-color); border-radius: 7px;
    }
    .seg-op {
      position: relative;
      display: inline-flex; align-items: center; gap: 5px;
      padding: 3px 10px; border: none; background: none; cursor: pointer;
      border-radius: 5px; white-space: nowrap;
      font: inherit; font-size: 0.7rem; font-weight: 700; letter-spacing: .01em;
      color: var(--text-muted);
    }
    .seg-op:hover { color: var(--text-main); }

    /* Cada gestion trae su color. Antes la activa se pintaba con --input-bg
       sobre --card-bg: en oscuro son dos azules a un punto de luminancia y no
       se distinguia cual estaba elegida. Ahora el color dice ademas CUAL es,
       no solo que hay una puesta. */
    .seg-op[data-sector="continente"], .seg-op[data-enap-sector="continente"] { --seg-color: var(--color-continente); --seg-fondo: var(--bg-continente); }
    .seg-op[data-sector="isla"],       .seg-op[data-enap-sector="isla"]       { --seg-color: var(--color-isla);       --seg-fondo: var(--bg-isla); }
    .seg-op[data-sector=""],           .seg-op[data-enap-sector=""]           { --seg-color: var(--text-main);        --seg-fondo: var(--hover); }

    /* El icono va a color siempre, tambien en las que no estan elegidas: los
       tres se distinguen de un vistazo antes de tocar nada. */
    .seg-icono { width: 13px; height: 13px; flex-shrink: 0; color: var(--seg-color, currentColor); }
    .seg-op.activo {
      background: var(--seg-fondo);
      color: var(--seg-color);
      box-shadow: inset 0 0 0 1px var(--seg-color);
    }

    /* El separador entre opciones. Se apaga a los dos lados de la activa: si
       no, la linea toca el borde de la pastilla y se lee como si le faltara un
       pedazo al recuadro. */
    .seg-op + .seg-op::before {
      content: ''; position: absolute; left: -1px; top: 5px; bottom: 5px;
      width: 1px; background: var(--border-color);
    }
    .seg-op.activo::before,
    .seg-op.activo + .seg-op::before { background: transparent; }


    .theme-toggle-btn, .icon-btn {
      background-color: var(--card-bg);
      color: var(--text-main);
      border: 1px solid var(--border-color);
      padding: 0 9px;
      height: 26px;
      font-size: 0.72rem;
      font-weight: 600;
      border-radius: 5px;
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 5px;
      transition: background-color .1s ease;
      white-space: nowrap;
    }
    .theme-toggle-btn:hover, .icon-btn:hover { border-color: var(--primary-color); color: var(--primary-color); }

    /* BARRA DE ALERTAS */
    /* ESTILOS DE ALERTAS REMOVIDOS */

    /* Pestañas */
    .layout-con-sidebar {
      display: flex;
      align-items: flex-start;
      gap: 16px;
    }

    .tab-container {
      display: flex;
      flex-direction: column;
      gap: 1px;
      flex-shrink: 0;
      width: 186px;              /* era 250px: se comia el 26% del ancho */
      border-bottom: none;
      border-right: 1px solid var(--border-color);
      /* La navegacion se apoya en el escalon mas oscuro: separa el chrome de
         la app del contenido sin necesidad de una linea mas fuerte. */
      background-color: var(--bg-deep);
      border-radius: 8px;
      /* El padding de abajo reserva el hueco del indicador de GPS, que va fijo
         al pie de la ventana: sin el, en pantallas bajas el ultimo item del
         menu quedaba tapado al scrollear el rail. */
      padding: 6px 8px 76px 6px;
      position: sticky;
      /* Debajo del encabezado, que ahora es sticky: con top:12px el rail se le
         metia por abajo al scrollear y le tapaba el menu. El alto del
         encabezado lo mide ajustarAltoEncabezado(), porque cambia cuando se
         parte en dos filas en pantallas angostas. */
      top: calc(var(--alto-encabezado, 46px) + 12px);
      max-height: calc(100vh - var(--alto-encabezado, 46px) - 24px);
      overflow-y: auto;
      overflow-x: hidden;
      transition: width 0.2s ease, padding 0.2s ease;
    }

    .tab-container.colapsado {
      width: 52px;
      padding-right: 6px;
    }
    .tab-container.colapsado .tab-label { display: none; }
    .tab-container.colapsado .tab-button {
      text-align: center;
      padding: 10px 4px;
      white-space: nowrap;
    }
    .tab-container.colapsado .sidebar-toggle { align-self: center; }

    /* Grupos colapsables */
    .tab-group {
      display: flex;
      flex-direction: column;
      margin-bottom: 0;
    }

    .tab-group-button {
      background: none;
      border: none;
      cursor: pointer;
      padding: 7px 6px 4px;
      font-size: 0.64rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.07em;
      color: var(--text-muted);
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      border-top: 1px solid var(--border-color);
      transition: all 0.2s ease;
      border-radius: 0;
    }

    .tab-group:first-of-type .tab-group-button {
      border-top: none;
    }

    .tab-group-button:hover {
      background-color: var(--card-bg);
      color: var(--text-main);
    }

    .group-toggle-icon {
      display: inline-block;
      transition: transform 0.2s ease;
      font-size: 0.7rem;
    }

    .tab-group-button.collapsed .group-toggle-icon {
      transform: rotate(-90deg);
    }

    .tab-group-items {
      display: flex;
      flex-direction: column;
      max-height: 1000px;
      overflow: hidden;
      transition: max-height 0.3s ease, opacity 0.3s ease;
      opacity: 1;
    }

    .tab-group-items.collapsed {
      max-height: 0;
      opacity: 0;
    }

    /* Cuando el sidebar está colapsado */
    .tab-container.colapsado .tab-group-button {
      padding: 8px 4px;
      white-space: nowrap;
      font-size: 0;
      text-indent: -9999px;
    }

    .tab-container.colapsado .tab-group-button .group-toggle-icon {
      display: none;
    }

    .tab-container.colapsado .tab-group-items {
      display: none;
    }


    .sidebar-toggle {
      align-self: flex-end;
      background: none;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      cursor: pointer;
      color: var(--text-muted);
      font-size: 0.85rem;
      padding: 5px 9px;
      margin-bottom: 6px;
      transition: color 0.2s ease;
    }
    .sidebar-toggle:hover { color: var(--primary-color); border-color: var(--primary-color); }

    /* ---- Gestion elegida, al medio del encabezado ---- */
    /* Leyendo una tabla larga hay que seguir sabiendo si los numeros son de un
       sector o de los dos: eso se malinterpreta callado. Va al medio de la
       barra de arriba, que es sticky, asi que acompana hasta el final. El
       margen automatico lo centra en el hueco que dejan el titulo y los
       controles, sin sacarlo del flujo ni arriesgar que los pise. */
    .sector-activo {
      display: flex;
      align-items: center;
      gap: 6px;
      margin: 0 auto;
      padding: 4px 10px;
      border: 1px solid var(--border-color);
      border-left: 3px solid var(--text-muted);
      border-radius: 6px;
      background-color: var(--card-bg);
    }
    /* Ver todo queda en gris a proposito: es el estado sin recorte y no tiene
       por que competir con el aviso de que hay un filtro puesto. */
    .sector-activo[data-sector="continente"] {
      border-left-color: var(--color-continente);
      background-color: var(--bg-continente);
    }
    .sector-activo[data-sector="isla"] {
      border-left-color: var(--color-isla);
      background-color: var(--bg-isla);
    }
    .sector-activo-icono { display: flex; }
    .sector-activo-icono svg { width: 14px; height: 14px; }
    /* Con margin:auto el chip queda centrado en el hueco que dejan el titulo y
       los controles, y como los controles son el doble de anchos, eso lo corre
       125px a la izquierda del centro real de la barra. Desde 1280px sobra
       lugar para centrarlo de verdad sin que toque ninguno de los dos lados
       (los controles miden ~507px y arrancan recien en el 68% del ancho). Por
       debajo se queda en el flujo, que nunca se solapa. */
    @media (min-width: 1280px) {
      .sector-activo {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        margin: 0;
      }
    }

    .sector-activo-rotulo {
      font-size: 0.5rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: .07em;
      color: var(--text-muted);
    }
    .sector-activo-valor {
      font-size: 0.74rem;
      font-weight: 700;
      color: var(--text-main);
    }
    .sector-activo[data-sector="continente"] .sector-activo-valor,
    .sector-activo[data-sector="continente"] .sector-activo-icono { color: var(--color-continente); }
    .sector-activo[data-sector="isla"] .sector-activo-valor,
    .sector-activo[data-sector="isla"] .sector-activo-icono { color: var(--color-isla); }

    /* ---- Pie del menu lateral: estado del enlace GPS ---- */
    /* Fijo al pie de la ventana, dentro de la columna del rail. Se probo
       estirando el rail hasta abajo con margin-top:auto, pero el rail arranca
       debajo del encabezado y es sticky: cualquier alto en vh dejaba el bloque
       cortado o flotando lejos del borde segun el scroll. Las medidas salen del
       rail: 12px de padding del body + 6px de padding izquierdo del rail. */
    .gps-status {
      position: fixed;
      left: 18px;
      bottom: 12px;
      width: 172px;              /* 186px del rail menos su padding lateral */
      box-sizing: border-box;
      z-index: 5;
      display: flex;
      align-items: flex-start;
      gap: 8px;
      text-align: left;
      font-family: inherit;
      color: var(--text-main);
      background-color: var(--card-bg);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 8px 9px;
      cursor: pointer;
      transition: border-color 0.2s ease;
    }
    .gps-status:hover { border-color: var(--primary-color); }
    .gps-status:focus-visible {
      outline: 2px solid var(--primary-color);
      outline-offset: 2px;
    }

    .gps-status-body {
      display: flex;
      flex-direction: column;
      gap: 1px;
      min-width: 0;
    }

    .gps-status-label {
      font-size: 0.55rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      color: var(--text-muted);
    }

    .gps-status-texto { font-size: 0.72rem; font-weight: 700; }
    .gps-status-detalle { font-size: 0.64rem; color: var(--text-muted); }

    .gps-status-dot {
      width: 9px;
      height: 9px;
      border-radius: 50%;
      flex-shrink: 0;
      margin-left: auto;
      margin-top: 3px;
      background-color: var(--text-muted);
    }

    .gps-status[data-estado="conectado"] .gps-status-dot { background-color: var(--success-color); }
    .gps-status[data-estado="conectando"] .gps-status-dot { background-color: var(--warning-color); }
    .gps-status[data-estado="error"] .gps-status-dot { background-color: var(--danger-color); }
    .gps-status[data-estado="error"] .gps-status-texto { color: var(--color-licencia); }

    /* Plegado: queda solo el punto de color, centrado. El texto completo sigue
       disponible en el title del boton. */
    .tab-container.colapsado .gps-status {
      width: 40px;               /* 52px del rail plegado menos su padding */
      justify-content: center;
      padding: 10px 4px;
    }
    .tab-container.colapsado .gps-status-body { display: none; }
    .tab-container.colapsado .gps-status-dot {
      margin: 0;
      width: 11px;
      height: 11px;
    }

    .contenido-principal {
      flex: 1;
      min-width: 0;
    }

    /* La barra medía 842px de alto sobre un viewport de 910: entraba
       justo y "Resumen por Transportista" ya se partía en dos líneas.
       Entradas de 38 a 27px. */
    .tab-button {
      padding: 5px 9px;
      font-size: 0.72rem;
      font-weight: 600;
      border: 1px solid transparent;
      border-left: 3px solid transparent;
      border-radius: 5px;
      cursor: pointer;
      background-color: transparent;
      color: var(--text-muted);
      transition: background-color .1s ease, color .1s ease;
      text-align: left;
      white-space: nowrap;        /* una línea por entrada, siempre */
      overflow: hidden;
      text-overflow: ellipsis;
      line-height: 1.55;
    }

    .tab-button:hover { color: var(--text-main); background-color: rgba(51, 65, 85, 0.1); }
    .tab-button.active {
      background-color: var(--card-bg);
      color: var(--primary-color);
      border-color: var(--border-color);
      border-left: 3px solid var(--primary-color);
    }

    .tab-content { display: none; }
    .tab-content.active { display: block !important; }

    .sub-tab-selector { display: flex; gap: 8px; margin-bottom: 15px; }
    .sub-tab-button {
      padding: 9px 20px;
      font-size: 0.82rem;
      font-weight: 700;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      cursor: pointer;
      background-color: transparent;
      color: var(--text-muted);
      transition: all 0.2s ease;
    }
    .sub-tab-button:hover { color: var(--text-main); border-color: var(--primary-color); }
    .sub-tab-button.active { background-color: var(--primary-color); color: #fff; border-color: var(--primary-color); }
    .sub-tab-content { display: none; }
    .sub-tab-content.active { display: block; }

    /* Paneles KPI */
    /* ==========================================================
       KPI
       auto-fit colapsa las pistas vacias, asi que cuando sobraba una
       tarjeta se estiraba sola a lo ancho de toda la fila (el "Total a
       Pagar" flotando). auto-fill conserva las pistas y la tarjeta
       mantiene su ancho de columna.
       Ademas se achican: cinco cajas centradas con numeros a 1,5rem se
       comian media pantalla antes del primer dato util.
       ========================================================== */
    .kpi-row {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(138px, 1fr));
      gap: 8px;
      margin-bottom: 10px;
    }

    .kpi-box {
      background: var(--card-bg);
      border: 1px solid var(--border-color);
      border-radius: 5px;
      padding: 7px 10px;
      text-align: left;          /* alineado a la izquierda: se escanea en vertical */
    }

    .kpi-box h3 {
      font-size: 0.6rem; text-transform: uppercase; letter-spacing: .05em;
      color: var(--text-muted); font-weight: 600; margin-bottom: 1px;
      line-height: 1.3;
    }
    .kpi-box p {
      font-size: 1.05rem; font-weight: 700; line-height: 1.15;
      font-variant-numeric: tabular-nums;
    }

    /* El desglose por producto estaba en una banda aparte debajo de los KPI.
       Ahora es una caja mas de la misma banda: ocupa dos columnas porque
       lleva cuatro etiquetas, y si no entran, se van a la fila siguiente. */
    /* Flota por Sector. Los numeros van centrados en su celda, no pegados al
       borde: la tabla se lee como una grilla y el sombreado por cantidad
       necesita que el numero este en el medio del bloque de color. */
    .tabla-sectores th.num-c, .tabla-sectores td.num-c { text-align: center; }
    .tabla-sectores th.th-sector { text-align: center; border-left: 2px solid var(--border-color); }
    .tabla-sectores th.th-sub { background: rgba(148, 163, 184, 0.10); }
    .tabla-sectores td.td-sub { font-weight: 700; background: rgba(148, 163, 184, 0.10); }
    .tabla-sectores td.td-total { border-left: 2px solid var(--border-color); }
    .tabla-sectores th:first-child, .tabla-sectores td:first-child { white-space: nowrap; }
    .tabla-sectores td { transition: none; }

    /* La fila lleva al detalle, asi que se comporta como algo que se toca. */
    .tabla-sectores .fila-producto { cursor: pointer; }
    .tabla-sectores .fila-producto:hover td { background-color: rgba(148, 163, 184, 0.14); }
    .tabla-sectores .fila-producto:hover .badge-product { filter: brightness(1.2); }

    /* Chips de base bajo la tabla de Flota por Sector. */
    .chip-base {
      display: inline-block;
      background: var(--primary-color); color: #fff;
      padding: 2px 7px; border-radius: 3px;
      font-size: 0.7rem; font-weight: 600;
      margin-left: 4px;
    }
    .dash-bases { display: flex; flex-wrap: wrap; gap: 6px 22px; margin-top: 10px; font-size: 0.75rem; }

    .kpi-box-productos { grid-column: span 2; }
    .kpi-box-productos .prod-kpi-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; }
    .kpi-box-productos .prod-kpi-tag { font-size: 0.7rem; padding: 2px 7px; }
    @media (max-width: 620px) { .kpi-box-productos { grid-column: 1 / -1; } }

    .product-kpi-subrow {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 8px;
      margin-bottom: 15px;
      background: var(--card-bg);
      border: 1px solid var(--border-color);
      padding: 6px 12px;
      border-radius: 6px;
      font-size: 0.72rem;
      color: var(--text-muted);
    }
    .prod-kpi-tag { padding: 3px 8px; border-radius: 4px; color: #fff; font-weight: 600; }

    .view-layout { display: grid; grid-template-columns: 1fr; gap: 15px; }
    /* Los items de un grid traen min-width:auto y no se encogen por debajo del
       ancho de su contenido: una tabla ancha empujaba la pagina entera hacia la
       derecha en vez de scrollear dentro de su propio .table-responsive. */
    .view-layout > main, .view-layout > aside { min-width: 0; }

    /* Un <select> se estira hasta el ancho de su opcion mas larga y no se
       encoge por ser item flex: el de "Ver ruta del dia" media 524px dentro de
       una caja de 341 y empujaba la pagina. */
    select { max-width: 100%; }
    @media (min-width: 1024px) {
      .view-layout.split-layout { grid-template-columns: 1fr 340px; }
    }

    /* ==========================================================
       CAMPOS DE FORMULARIO
       El mismo bloque de seis declaraciones estaba copiado en ~30
       campos con style inline. Aca vive una sola vez.
       ========================================================== */
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    select,
    textarea {
      background-color: var(--input-bg);
      color: var(--text-main);
      border: 1px solid var(--border-color);
      border-radius: 5px;
      font-size: 0.78rem;
      padding: 0 8px;
      height: 30px;
    }
    select { cursor: pointer; padding-right: 4px; }
    textarea {
      height: auto; min-height: 70px; padding: 7px 8px;
      line-height: 1.5; resize: vertical;
    }
    input[type="checkbox"], input[type="radio"] { accent-color: var(--primary-color); cursor: pointer; }
    input[type="date"]::-webkit-calendar-picker-indicator,
    input[type="month"]::-webkit-calendar-picker-indicator {
      cursor: pointer; opacity: .75; padding: 2px;
    }
    input[type="date"]::-webkit-calendar-picker-indicator:hover,
    input[type="month"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
    input:disabled, select:disabled, textarea:disabled {
      background-color: var(--zebra); color: var(--text-muted); cursor: not-allowed;
    }
    input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: .75; }

    label { font-size: 0.72rem; color: var(--text-muted); font-weight: 600; }

    /* ==========================================================
       PANELES
       Sin sombra: en tema oscuro no se ve y en claro solo ensucia
       el borde. El borde ya separa la tarjeta del fondo.
       ========================================================== */
    .panel-card {
      background: var(--card-bg);
      border: 1px solid var(--border-color);
      border-radius: 6px;
      padding: 12px;
      margin-bottom: 12px;
    }

    .panel-card h2 {
      color: var(--text-main); font-size: 0.95rem; font-weight: 600;
      margin-bottom: 10px; border-bottom: 1px solid var(--border-color);
      padding-bottom: 6px; letter-spacing: -.01em;
    }

    /* Toolbar de búsqueda / exportar */
    .table-toolbar {
      display: flex;
      gap: 8px;
      margin-bottom: 10px;
      flex-wrap: wrap;
    }
    .table-toolbar input[type="text"] {
      flex: 1;
      min-width: 160px;
      padding: 8px 10px;
      border: 1px solid var(--border-color);
      border-radius: 5px;
      background-color: var(--input-bg);
      color: var(--text-main);
      font-size: 0.8rem;
      outline: none;
    }
    /* ==========================================================
       SISTEMA DE BOTONES
       Habia tres verdes distintos, dos azules y un violeta conviviendo
       en la misma barra para acciones sin relacion entre si. El color
       dejaba de significar algo.
       Ahora: neutro por defecto, relleno solo para la accion principal
       de cada bloque, y rojo unicamente para lo que destruye datos.
       La jerarquia la da el peso visual, no el matiz.
       ========================================================== */
    .btn-export, .btn-clear, .btn-submit {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      background-color: var(--card-bg);
      color: var(--text-main);
      border: 1px solid var(--border-color);
      padding: 0 12px;
      height: 30px;
      border-radius: 5px;
      font-size: 0.75rem;
      font-weight: 600;
      cursor: pointer;
      white-space: nowrap;
      transition: background-color .1s ease;
    }
    .btn-export:hover, .btn-clear:hover, .btn-submit:hover { background-color: var(--hover); }
    .btn-clear { color: var(--text-muted); }

    /* Accion principal: se marca a mano con .btn-primario y casi nunca.
       .btn-success NO entra aca: son los "Guardar" de fila, que se repiten
       92 veces en GPS y 34 en Kilometrajes. Un control que aparece una vez
       por fila es rutina, no la accion principal de la pantalla; rellenarlos
       convertia la vista en una pared azul. */
    .btn-primario {
      background-color: var(--primary-color);
      border-color: var(--primary-color);
      color: var(--bg-color);   /* invierte solo con el tema: legible en ambos */
      font-weight: 700;
    }
    .btn-primario:hover {
      background-color: var(--primary-color);
      filter: brightness(1.08);
    }

    /* Los "Guardar" de formulario son de ancho completo: la jerarquia se la
       da el tamano y la posicion, no el relleno de color. */
    .btn-submit.btn-success { border-color: var(--primary-color); color: var(--primary-color); }
    .btn-submit.btn-success:hover { background-color: var(--focus-wash); }

    /* Destructivo: contorno, no relleno. Un boton rojo macizo pesa mas
       que la accion que representa y compite con las alertas reales. */
    .btn-destructivo, .btn-danger {
      background-color: transparent;
      border-color: var(--danger-color);
      color: var(--danger-color);
      font-weight: 700;
    }
    .btn-destructivo:hover, .btn-danger:hover { background-color: var(--bg-licencia); }
    .btn-export:hover { opacity: 0.9; }
    /* .btn-clear hereda del bloque de arriba; solo cambia el tono del texto. */

    /* max-height habilita el scroll vertical propio, que es lo que hace
       que la cabecera sticky se active. Las tablas cortas no se afectan. */
    .table-responsive {
      overflow: auto; max-height: 62vh;
      border-radius: 6px; border: 1px solid var(--border-color);
      background-color: var(--table-bg);
    }

    /* ==========================================================
       FOCO DE TECLADO — un solo tratamiento en toda la app.
       :focus-visible: aparece al navegar con teclado, no al hacer
       clic con el mouse.
       ========================================================== */
    :where(a, button, input, select, textarea, [tabindex]):focus-visible {
      outline: 2px solid var(--primary-color);
      outline-offset: 1px;
      border-radius: 4px;
    }
    input:focus, select:focus, textarea:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px var(--focus-wash);
    }

    @media (prefers-reduced-motion: reduce) {
      * { transition: none !important; animation: none !important; }
    }
    /* ==========================================================
       TABLA DE ALTA DENSIDAD
       Fila de 32 px con texto de 13 px: es donde entran ~13 filas
       en media pantalla sin que el ojo pierda la linea horizontal.
       ========================================================== */
    table { width: 100%; border-collapse: separate; border-spacing: 0; text-align: left; }

    /* Cabecera fija. Usa box-shadow interior en vez de border-bottom
       porque los bordes de celda no se pintan de forma fiable en
       elementos sticky y dejan una linea que salta al hacer scroll. */
    th {
      position: sticky; top: 0; z-index: 2;
      background-color: var(--table-bg); color: var(--text-muted);
      padding: 0 10px; height: 30px;
      font-weight: 600; font-size: 0.69rem; letter-spacing: .05em;
      text-transform: uppercase; white-space: nowrap;
      box-shadow: inset 0 -1px 0 var(--border-color);
    }

    td {
      padding: 0 10px; height: var(--row-h);
      border-bottom: 1px solid var(--line-soft);
      font-size: 0.8rem; white-space: nowrap;
      font-variant-numeric: tabular-nums;
    }

    /* Cebra: diferencia minima, suficiente para seguir la fila hasta
       la ultima columna e insuficiente para leerse como bloques. */
    tbody tr:nth-child(even) { background-color: var(--zebra); }
    tr:hover { background-color: var(--hover); }

    /* Tipografia por columna, enganchada a data-label: sin tocar el JS.
       Monoespaciada para IDENTIFICADORES — ahi importa distinguir
       caracter por caracter (SDCH-73 de SDCH-74). */
    td[data-label="Patente"], td[data-label="Patente Titular"],
    td[data-label="Patente Real"], td[data-label="Tracto"],
    td[data-label="Semi"], td[data-label="Codigo"], td[data-label="RUT"] {
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
      font-size: 0.75rem; letter-spacing: -.01em;
    }

    /* Alineadas a la derecha para CANTIDADES — ahi importa comparar
       magnitudes: una cifra mas larga tiene que verse mas larga. */
    td[data-label="KM"], td[data-label="KM Real (GPS)"], td[data-label="KM ENAP"],
    td[data-label="Diferencia"], td[data-label="Valor a Pago"],
    td[data-label="Capacidad"], td[data-label="Viajes"],
    th.num, td.num { text-align: right; }

    /* Monoespaciada tambien en las cantidades, no solo en los identificadores:
       kilometrajes, m3 y pesos se leen en columna y comparar magnitudes exige
       que todas las cifras ocupen lo mismo. tabular-nums ya alineaba los
       digitos, pero no el punto ni el separador de miles. */
    td[data-label="KM"], td[data-label="KM Real (GPS)"], td[data-label="KM ENAP"],
    td[data-label="KM TPL"], td[data-label="DIF"], td[data-label="Diferencia"],
    td[data-label="Valor a Pago"], td[data-label="Tarifa"],
    td[data-label="Capacidad"], td[data-label="Viajes"],
    .pg-kms, .pg-valor, .pg-num, td.num {
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
      font-variant-numeric: tabular-nums;
    }
    .tr-group-header { background-color: var(--card-bg) !important; font-size: 0.75rem; font-weight: 700; color: var(--text-main); border-bottom: 2px solid var(--border-color); }
    .sin-resultados td { text-align: center; color: var(--text-muted); font-style: italic; white-space: normal; }
    /* ==========================================================
       FORMULARIO DE CONDUCTOR
       Eran catorce campos identicos apilados: para encontrar uno habia que
       leerlos todos. Agrupados en Conductor / Asignacion / Documentacion, y
       los cortos de a dos por fila, el cuadro entra casi entero en pantalla.
       ========================================================== */
    .form-seccion { margin-bottom: 14px; }
    .form-seccion > h3 {
      font-size: 0.7rem; font-weight: 700; letter-spacing: .08em;
      text-transform: uppercase; color: var(--text-muted);
      margin: 0 0 7px; padding-bottom: 4px;
      border-bottom: 1px solid var(--border-color);
    }
    .form-seccion > h3 .dim { letter-spacing: 0; text-transform: none; font-weight: 500; }
    .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 10px; }
    .form-grid .form-group { min-width: 0; }

    /* Cada documento en una linea: etiqueta, fecha y su estado. El estado al
       lado del campo y no en un resumen aparte, para que se vea cual hay que
       renovar mientras se lo esta editando. */
    .doc-fila {
      display: grid; grid-template-columns: 1fr 132px 74px;
      gap: 8px; align-items: center; margin-bottom: 5px;
    }
    .doc-fila > label { margin: 0; font-size: 0.75rem; color: var(--text-main); }
    .doc-fila > input { margin: 0; }
    .doc-estado { font-size: 0.66rem; font-weight: 700; text-align: right; white-space: nowrap; }

    /* El borde del campo repite el estado: el color y el texto dicen lo mismo,
       asi no depende de distinguir un rojo de un ambar. */
    .doc-fila input.doc-vencido   { border-color: var(--color-licencia); }
    .doc-fila input.doc-porvencer { border-color: var(--color-backup); }
    .doc-fila input.doc-ok        { border-color: var(--color-titular); }

    /* ==========================================================
       LIQUIDACION DEL PERIODO: DESVIOS RECLAMABLES
       El flag no es decorativo: separa lo que se puede mandar a cobrar de lo
       que ya tiene una explicacion operativa cargada y por eso no se manda.
       ========================================================== */
    .conc-desvio {
      font-weight: 800; color: var(--warning-color);
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    }
    .conc-flag {
      display: inline-block; padding: 1px 6px; border-radius: 3px;
      font-size: 0.6rem; font-weight: 700; letter-spacing: .03em; white-space: nowrap;
    }
    .conc-flag-listo {
      background: color-mix(in srgb, var(--success-color) 18%, transparent);
      color: var(--success-color);
    }
    .conc-flag-revision {
      background: color-mix(in srgb, var(--text-muted) 18%, transparent);
      color: var(--text-muted);
    }

    /* ==========================================================
       ACCION DIRECTA EN EL LISTADO OFICIAL
       ========================================================== */
    .lo-acciones { white-space: nowrap; }
    .lo-btn {
      background: none; border: 1px solid var(--border-color); border-radius: 4px;
      color: var(--text-muted); cursor: pointer;
      font-size: 0.62rem; font-weight: 600; padding: 1px 6px; margin-right: 3px;
    }
    .lo-btn:hover:not(:disabled) { border-color: var(--primary-color); color: var(--primary-color); }
    .lo-btn:disabled { opacity: .35; cursor: default; }

    /* Los filtros rapidos de la barra: angostos, que si no se llevan el ancho
       del buscador, que es el control que mas se usa. */
    .table-toolbar select[id^="filtro-base-"],
    .table-toolbar select[id^="filtro-producto-"],
    .table-toolbar select[id^="filtro-categoria-"] { max-width: 168px; }

    /* ==========================================================
       CENTRO DE ALERTAS POR TRANSPORTISTA
       Antes era un acordeon con la cuenta total por empresa. Para saber si una
       empresa tenia algo BLOQUEANTE o solo avisos a treinta dias habia que
       abrirla y leer chofer por chofer. La tarjeta trae el desglose por
       criticidad a la vista y se pinta con el nivel mas grave que tiene:
       lo primero que se busca en el tablero es a quien hay que llamar hoy.
       ========================================================== */
    /* Cabecera del panel: el titulo dice de que es el tablero y las dos
       acciones son las que sirven para TODAS las empresas, no para una. */
    .aud-panel-cab {
      display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
      padding-bottom: 9px; margin-bottom: 11px;
      border-bottom: 1px solid var(--border-color);
    }
    .aud-panel-icono {
      flex: 0 0 auto; display: grid; place-items: center;
      width: 26px; height: 26px; border-radius: 6px;
      background: color-mix(in srgb, var(--danger-color) 18%, transparent);
      color: var(--danger-color); font-size: 0.9rem;
    }
    .aud-panel-tit { flex: 1 1 220px; min-width: 0; }
    .aud-panel-tit h3 { margin: 0; font-size: 0.95rem; letter-spacing: .01em; }
    .aud-panel-tit p {
      margin: 2px 0 0; font-size: 0.68rem; color: var(--text-muted);
    }
    .aud-panel-acciones { flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px; }
    .aud-btn-acento {
      background: color-mix(in srgb, var(--danger-color) 16%, var(--card-bg));
      border-color: color-mix(in srgb, var(--danger-color) 45%, var(--border-color));
      color: var(--danger-color);
    }
    .aud-btn-acento:hover {
      border-color: var(--danger-color); color: var(--danger-color);
    }

    .aud-grid {
      display: grid; gap: 9px;
      grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
    }
    .aud-card {
      background: var(--table-bg);
      border: 1px solid var(--border-color);
      border-left: 3px solid var(--aud-color, var(--border-color));
      border-radius: 7px; padding: 9px 11px; min-width: 0;
    }
    .aud-card-cab {
      display: flex; align-items: center; gap: 8px;
      padding-bottom: 7px; margin-bottom: 7px;
      border-bottom: 1px solid var(--border-color);
    }
    .aud-emp {
      flex: 1 1 auto; min-width: 0;
      font-size: 0.74rem; font-weight: 700; letter-spacing: .02em;
      color: var(--text-main);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* La insignia dice "21 ALERTAS" y no "21": el numero solo no distingue
       una empresa con veintiun papeles vencidos de una con veintiun avisos. */
    .aud-total {
      flex: 0 0 auto; text-align: center; white-space: nowrap;
      border-radius: 11px; padding: 1px 7px;
      font-size: 0.58rem; font-weight: 800; letter-spacing: .04em; color: #0b1326;
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    }

    /* Donde opera la empresa y con cuantas unidades: ubica la tarjeta sin
       tener que abrir nada. */
    .aud-desc {
      margin: -3px 0 7px; font-size: 0.64rem; color: var(--text-muted);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }

    /* Un renglon por documento: nombre a la izquierda, cuenta y unidad a la
       derecha. La unidad va debajo del numero y no al lado para que la columna
       de numeros quede a plomo entre renglones. */
    .aud-niveles { list-style: none; display: flex; flex-direction: column; gap: 4px; }
    .aud-tipo {
      display: grid; grid-template-columns: 8px 1fr auto;
      align-items: center; gap: 7px;
    }
    .aud-punto { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
    .aud-tipo-rot {
      font-size: 0.68rem; color: var(--text-main); min-width: 0;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .aud-tipo-n {
      text-align: right; font-size: 0.8rem; font-weight: 800; line-height: 1.05;
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    }
    .aud-tipo-u {
      display: block; font-family: inherit;
      font-size: 0.52rem; font-weight: 700; letter-spacing: .05em;
      text-transform: uppercase; color: var(--text-muted);
    }
    .aud-ok {
      font-size: 0.62rem; font-weight: 700; white-space: nowrap;
      color: var(--success-color);
    }

    .aud-acciones { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
    .aud-btn {
      background: var(--card-bg); color: var(--text-main);
      border: 1px solid var(--border-color); border-radius: 4px;
      padding: 3px 8px; cursor: pointer;
      font-size: 0.66rem; font-weight: 600; white-space: nowrap;
    }
    .aud-btn:hover { border-color: var(--primary-color); color: var(--primary-color); }
    .aud-btn-ghost { background: none; color: var(--text-muted); }

    /* El detalle reusa .alerta-contenido, que ya tiene el plegado. */
    .aud-detalle { margin-top: 7px; }
    .aud-det-grupo { margin-bottom: 6px; }
    .aud-det-rot {
      display: block; margin-bottom: 2px;
      font-size: 0.58rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
    }
    .aud-det-item {
      display: grid; grid-template-columns: 1fr auto; gap: 2px 8px;
      padding: 3px 6px; margin-bottom: 2px; border-radius: 4px;
      background: var(--card-bg); cursor: pointer;
    }
    .aud-det-item:hover { background: var(--hover); }
    .aud-det-quien { font-size: 0.66rem; font-weight: 700; color: var(--text-main); }
    .aud-det-cuando {
      grid-row: 2; grid-column: 1 / -1;
      font-size: 0.62rem; color: var(--text-muted);
    }
    .aud-det-que { font-size: 0.62rem; color: var(--text-muted); text-align: right; }

    /* ==========================================================
       MATRIZ DE FLOTA POR SECTOR (tarjetas comparativas)
       Era una tabla producto x base con sombreado por cantidad. La tabla
       respondia "cuantos hay de X en Y" pero no la pregunta con la que se
       entra a esta pantalla, que es como esta parada la flota de un sector
       contra la del otro. Dos bloques lado a lado, con la misma escala de
       barras, contestan eso de un vistazo.
       ========================================================== */
    .fs-kpis {
      display: grid; gap: 8px; margin-bottom: 12px;
      grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
    }
    .fs-kpi {
      background: var(--table-bg); border: 1px solid var(--border-color);
      border-top: 2px solid var(--border-color);
      border-radius: 7px; padding: 8px 10px; min-width: 0;
    }
    .fs-kpi-ok { border-top-color: var(--success-color); }
    .fs-kpi-aviso { border-top-color: var(--warning-color); }
    .fs-kpi-critico { border-top-color: var(--danger-color); }
    .fs-kpi-rot {
      display: block; font-size: 0.6rem; font-weight: 700; letter-spacing: .06em;
      text-transform: uppercase; color: var(--text-muted);
    }
    .fs-kpi-val {
      display: block; margin: 1px 0 2px;
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
      font-size: 1.35rem; font-weight: 700; line-height: 1.05; color: var(--text-main);
      font-variant-numeric: tabular-nums;
    }
    .fs-kpi-pie {
      display: block; font-size: 0.64rem; color: var(--text-muted);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }

    /* Los dos sectores lado a lado mientras haya ancho; abajo de 900px se
       apilan, que es cuando ponerlos en fila los deja demasiado angostos
       para que las barras signifiquen algo. */
    .fs-sectores {
      display: grid; gap: 10px;
      grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    }
    .fs-sector {
      background: var(--table-bg); border: 1px solid var(--border-color);
      border-radius: 8px; padding: 10px 12px; min-width: 0;
    }
    .fs-sector-cab {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: 8px; flex-wrap: wrap;
      padding-bottom: 7px; margin-bottom: 8px;
      border-bottom: 1px solid var(--border-color);
    }
    .fs-sector-cab h4 {
      font-size: 0.82rem; font-weight: 700; letter-spacing: .03em;
      text-transform: uppercase; color: var(--text-main);
    }
    .fs-sector-tot { font-size: 0.72rem; color: var(--text-muted); white-space: nowrap; }
    .fs-sector-tot strong {
      color: var(--text-main);
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    }

    .fs-bases { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 9px; }
    .fs-chip {
      display: inline-flex; align-items: center; gap: 5px;
      background: color-mix(in srgb, var(--base-color, transparent) 14%, transparent);
      border: 1px solid color-mix(in srgb, var(--base-color, var(--border-color)) 45%, transparent);
      border-left: 3px solid var(--base-color, var(--border-color));
      border-radius: 4px; padding: 2px 7px; cursor: pointer;
      font-size: 0.64rem; font-weight: 700; letter-spacing: .04em;
      color: var(--text-main); white-space: nowrap;
    }
    .fs-chip:hover { background: color-mix(in srgb, var(--base-color, transparent) 26%, transparent); }
    .fs-chip-n {
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
      font-weight: 700; color: var(--base-color, var(--text-main));
    }

    .fs-prods { list-style: none; display: flex; flex-direction: column; gap: 4px; }
    .fs-prod {
      display: grid; grid-template-columns: 104px 1fr 30px;
      align-items: center; gap: 8px;
      padding: 2px 0; border-radius: 4px; cursor: pointer;
    }
    .fs-prod:hover { background: var(--hover); }
    .fs-prod-cero { cursor: default; opacity: .5; }
    .fs-prod-cero:hover { background: transparent; }
    .fs-prod .badge-product { justify-self: start; font-size: 0.58rem; }
    /* El riel se ve siempre, tambien en cero: sin el, una fila vacia no se
       lee como "cero de esto" sino como una fila rota. */
    .fs-barra {
      display: block; height: 8px; border-radius: 4px;
      background: var(--line-soft); overflow: hidden;
    }
    .fs-barra-fill { display: block; height: 100%; border-radius: 4px; }
    .fs-prod-n {
      text-align: right; font-size: 0.74rem; font-weight: 700;
      font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
      color: var(--text-main); font-variant-numeric: tabular-nums;
    }

    .fs-fuera {
      margin-top: 10px; padding: 7px 10px;
      background: color-mix(in srgb, var(--warning-color) 8%, transparent);
      border-left: 3px solid var(--warning-color); border-radius: 4px;
    }

    /* ==========================================================
       CORTE POR TRANSPORTISTA EN LA TABLA DE CHOFERES
       Son 64 conductores repartidos en 8 empresas: sin un corte que se lea
       como division, la tabla es una lista continua y no se sabe donde
       empieza cada transportista. Mismo tratamiento que el corte de base del
       Listado Oficial: banda tenida con el color del grupo y marca en el
       borde. El color sale del nombre de la empresa, asi que es estable.
       ========================================================== */
    tr.tr-grupo-emp { background-color: transparent !important; }
    tr.tr-grupo-emp:hover { background-color: transparent; }
    tr.tr-grupo-emp td {
      height: 30px;
      background-color: color-mix(in srgb, var(--emp-color, transparent) 14%, var(--zebra));
      box-shadow: inset 3px 0 0 var(--emp-color, var(--border-color));
      border-top: 1px solid var(--border-color);
      border-bottom: 1px solid var(--border-color);
      font-size: 0.74rem; font-weight: 700; letter-spacing: .05em;
      text-transform: uppercase; color: var(--text-main);
      text-align: left !important; padding-left: 13px;
    }
    tr.tr-grupo-emp:first-child td { border-top: none; }
    .grupo-emp-detalle {
      margin-left: 10px; font-weight: 500; letter-spacing: .02em;
      text-transform: none; font-size: 0.7rem; color: var(--text-muted);
    }
    .grupo-emp-alerta { color: var(--color-licencia); font-weight: 700; }
    .grupo-emp-aviso { color: var(--color-backup); font-weight: 700; }

    /* ==========================================================
       CORTES DE GRUPO DEL LISTADO OFICIAL
       La base abre bloque con un encabezado tenue; dentro de la base,
       cada tipo de producto entra con una linea fina de su propio color.
       Son separaciones para el ojo, no titulos: si pesaran mas que la
       cabecera de la tabla, la tabla se leeria como varias tablas.
       ========================================================== */
    tr.tr-grupo-base { background-color: transparent !important; }
    tr.tr-grupo-base:hover { background-color: transparent; }
    tr.tr-grupo-base td {
      height: 28px;
      /* La banda entera se tine con el color de su base, apenas un 12% sobre
         el fondo de la fila: alcanza para separar los bloques de un vistazo
         sin competir con los badges de producto ni con el semaforo documental,
         que son los que tienen que destacar. */
      background-color: color-mix(in srgb, var(--base-color, transparent) 12%, var(--zebra));
      box-shadow: inset 3px 0 0 var(--base-color, var(--border-color));
      border-bottom: 1px solid var(--border-color);
      font-size: 0.72rem; font-weight: 700; letter-spacing: .06em;
      text-transform: uppercase; color: var(--text-main);
      /* Unica celda del listado que NO se centra: ver el bloque de
         alineacion mas abajo. */
      text-align: left !important; padding-left: 13px;
    }
    tr.tr-grupo-base:not(:first-child) td { border-top: 1px solid var(--border-color); }
    .grupo-detalle {
      margin-left: 10px; font-weight: 500; letter-spacing: .02em;
      text-transform: none; font-size: 0.68rem; color: var(--text-muted);
    }

    /* La linea de producto va translucida a proposito: marca donde empieza
       el bloque sin dibujar una regla que compita con la fila. */
    tr.sep-producto > td { border-top: 1px solid var(--line-soft); }
    tr.sep-producto > td { border-top-color: color-mix(in srgb, var(--sep-color, var(--line-soft)) 50%, transparent); }

    /* ==========================================================
       LISTADO OFICIAL: INFORMACION CENTRADA
       Lo que lleva esta tabla son valores cortos —patente, capacidad,
       producto, categoria, un badge—, no frases. Alineados a la izquierda
       dejaban el dato lejos del titulo de su columna y un margen derecho
       en zigzag. Centrados, titulo y dato comparten eje y la tabla se lee
       como grilla.
       Se centra tambien el TH: si la cabecera no acompana, el centrado de
       la celda se lee como un error de alineacion.
       ========================================================== */
    #vista-flota table th, #vista-flota table td { text-align: center; }
    #vista-flota table th.num, #vista-flota table td.num { text-align: center; }
    #vista-flota .inline-select { text-align: center; text-align-last: center; }

    /* KILOMETRAJE EDITABLE
       Se escribe a la derecha, como todo numero que se compara de arriba abajo:
       asi las unidades quedan en un mismo eje y un camion con un digito de mas
       salta a la vista. El campo se ve plano hasta que se lo toca —en una tabla
       de 15 columnas, 44 recuadros con borde son 44 llamadas de atencion que no
       significan nada— y recien ahi muestra que es editable. */
    /* EL BOTON DE CAMBIAR LA PATENTE
       Va chico y debajo de la ayuda del campo: es una operacion rara y pesada,
       no algo que se toque todos los dias. */
    .rp-btn { margin-top: 6px; font-size: 0.72rem; padding: 3px 8px; }

    /* BAJA Y BORRADO DE UN CONDUCTOR
       Van separados de Guardar y Cancelar, y debajo: no son parte de editar la
       ficha, son acciones sobre el conductor. El borrado se distingue del resto
       porque es lo unico que no se puede deshacer. */
    .ch-acciones-baja {
      display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
      margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border-color);
    }
    .ch-acciones-baja .btn-clear { font-size: 0.76rem; }
    .ch-acciones-baja .ch-btn-borrar { color: var(--danger-color); }
    .ch-acciones-baja .ch-btn-borrar:hover { border-color: var(--danger-color); }

    /* LOS PASOS DEL CAMBIO DE UNIDAD
       Mover camiones y choferes es lo que mas cuesta deshacer si sale mal, asi
       que el cuadro dice exactamente que va a hacer antes de que el usuario
       apriete guardar. */
    /* ANULAR no es CERRAR y el boton tiene que decirlo solo. Cerrar es la
       operacion normal —la unidad volvio— y va en verde de guardar. Anular borra
       un registro, asi que se pinta como lo que es y se pone al lado, nunca como
       accion principal salvo cuando es la unica que tiene sentido. */
    .cu-btn-anular {
      color: var(--danger-color);
      border-color: var(--danger-color);
    }
    .cu-btn-anular:hover { background: rgba(239, 68, 68, 0.12); }
    /* El atributo hidden lo pone el cuadro, pero .btn-clear trae su propio
       display y le gana: sin esto el boton quedaba a la vista siempre, hasta
       debajo de otro que hacia lo mismo. */
    .cu-btn-anular[hidden] { display: none; }

    .cu-pasos {
      border: 1px solid var(--border-color); border-left: 3px solid var(--warning-color);
      border-radius: 6px; padding: 8px 12px; margin: 10px 0;
      background: var(--hover); font-size: 0.78rem;
    }
    .cu-pasos-si { display: flex; align-items: center; gap: 7px; cursor: pointer; }
    .cu-pasos-si input { width: auto; margin: 0; }
    .cu-pasos ul { margin: 6px 0 0; padding-left: 18px; }
    .cu-pasos li { margin: 3px 0; }
    .cu-pasos-ok { color: var(--success-color); font-weight: 600; }

    /* CAMBIO DE UNIDAD EN LA PROGRAMACION
       Cuando un camion baja a mantencion y otro lo cubre, la patente que hay
       que seguir es la del que esta trabajando: es la que va a aparecer en el
       GPS. El titular queda debajo y chico, porque los viajes siguen siendo
       suyos y es lo que explica por que esa fila esta ahi. */
    .pg-camion .pg-unidad-btn {
      border: 1px solid transparent; border-radius: 4px;
      background: transparent; color: var(--text-muted);
      font-size: 0.8rem; line-height: 1; padding: 2px 4px; cursor: pointer;
      vertical-align: middle;
    }
    .pg-camion .pg-unidad-btn:hover { border-color: var(--border-color); color: var(--primary-color); }
    .pg-camion .pg-reemplazo { color: var(--warning-color); }
    .pg-camion .pg-cubre {
      display: block; font-size: 0.62rem; font-weight: 600;
      color: var(--text-muted); letter-spacing: .02em; cursor: help;
    }

    #vista-flota .inline-km {
      width: 100%; min-width: 76px; box-sizing: border-box;
      padding: 3px 6px; border: 1px solid transparent; border-radius: 4px;
      background: transparent; color: inherit;
      font: inherit; font-variant-numeric: tabular-nums;
      text-align: right;
    }
    #vista-flota .inline-km::placeholder { color: var(--text-muted); }
    #vista-flota .inline-km:hover { border-color: var(--border-color); }
    #vista-flota .inline-km:focus {
      outline: none; border-color: var(--primary-color);
      background: var(--input-bg);
      box-shadow: 0 0 0 2px var(--focus-wash);
    }
    #vista-flota table th.th-km, #vista-flota table td.td-km { text-align: right; }

    /* CHOFER Y EMPRESA A LA IZQUIERDA
       Son las dos unicas columnas con texto largo y de ancho muy variable
       ("JOSE LORENZO MUÑOZ ALVAREZ" contra "ZMC"). Centradas dejaban los dos
       margenes en zigzag; contra el borde izquierdo comparten un eje y la
       columna se recorre de arriba abajo sin saltar, ademas de leerse en el
       sentido en que se lee un nombre. */
    /* Por CLASE y no por nth-child. Estas reglas iban por numero de columna y
       cada columna nueva las corria: KM las movio de 8 y 10 a 9 y 11, y al
       agregar PATENTE TITULAR habrian ido a 10 y 12. Las dos veces el numero
       viejo termino apuntando a la columna equivocada —una vez le puso a
       CATEGORIA el ancho del desplegable de choferes— y el desajuste solo se ve
       mirando la tabla. Con una clase en la celda, agregar columnas no las toca. */
    #vista-flota table th.th-chofer, #vista-flota table td.td-chofer,
    #vista-flota table th.th-empresa, #vista-flota table td.td-empresa { text-align: left; }
    #vista-flota table td.td-chofer .inline-select { text-align: left; text-align-last: left; }

    /* El titulo va centrado sobre su columna aunque los nombres sigan a la
       izquierda: el encabezado rotula la columna entera, no el primer nombre. */
    /* Lleva "table" adelante a proposito: la regla de arriba que manda los
       nombres a la izquierda tambien lo lleva, y sin eso le gana a esta. */
    #vista-flota table th.th-chofer { text-align: center; }

    /* El desplegable, encuadrado y del ancho de la columna. Suelto mide lo que
       mide su nombre y las flechas caen en diagonal, una por fila, que es lo
       que hace que la columna se vea desordenada. Con width:100% todas las
       flechas comparten eje. */
    /* min-width y no width: la tabla reparte el ancho que le queda y con un
       width a secas la columna se plancha. Los 215px salen de medir la opcion
       mas ancha con la tipografia del desplegable —"⚠ GUILLERMO RETAMALES",
       153px— mas la flecha y el relleno del select (34px + 8px) y los 20px de
       relleno de la celda. Eran 320px cuando la columna mostraba el nombre
       completo; desde que va "primer nombre + primer apellido" ese ancho
       sobraba y le abria un hueco a CATEGORIA. Las etiquetas de transportista
       del desplegable son mas anchas, pero solo se ven con el menu abierto,
       que se despliega por encima y no lo limita la columna. */
    #tabla-continente td.td-chofer,
    #tabla-isla td.td-chofer { min-width: 215px; }
    #tabla-continente td.td-chofer .inline-select,
    #tabla-isla td.td-chofer .inline-select {
      width: 100%; min-width: 0;
      border-color: var(--border-color);
      background-color: var(--input-bg);
    }
    #tabla-continente td.td-chofer .inline-select:hover,
    #tabla-isla td.td-chofer .inline-select:hover { border-color: var(--primary-color); }

    /* PATENTE TITULAR. Casi todas las filas repiten la patente de al lado
       —un camion es su propio cupo— y con el mismo peso la columna parecia un
       duplicado y escondia las pocas filas que si dicen otra cosa, que son
       justo las que hay que mirar. La propia va apagada; la ajena, marcada. */
    .lo-titular-propia { color: var(--text-muted); }
    .lo-titular-otra {
      color: var(--color-backup, #b45309);
      background: rgba(245, 158, 11, 0.14);
      border-radius: 4px; padding: 1px 6px; white-space: nowrap;
    }

    /* El desplegable de choferes lleva sesenta y cuatro nombres: el grupo del
       transportista tiene que leerse como una division, no como un nombre mas. */
    .inline-select optgroup, select optgroup {
      font-style: normal; font-weight: 700;
      color: var(--text-muted);
      background-color: var(--card-bg);
    }
    .inline-select option, select optgroup option {
      font-weight: 500;
      background-color: var(--input-bg);
    }

    /* El corte de base es la excepcion: ocupa las 13 columnas y la tabla es
       mas ancha que la pantalla, asi que un rotulo centrado caeria fuera de
       la vista hasta scrollear. Se queda pegado al borde, junto a la marca
       de color de la base. */

    /* Los subtitulos de los KPI tienen largos muy distintos ("Camiones
       Continente" contra "En Cullen"): el que saltaba a dos lineas empujaba
       su numero y la fila quedaba escalonada. Con una altura comun para el
       subtitulo, los cinco numeros arrancan a la misma altura. */
    #vista-flota .kpi-box { text-align: center; }
    #vista-flota .kpi-box h3 {
      min-height: 2.6em;
      display: flex; align-items: center; justify-content: center;
    }
    #vista-flota .kpi-box-productos .prod-kpi-tags { justify-content: center; }


    .gps-base-header {
      font-size: 0.72rem;
      font-weight: 700;
      color: var(--text-main);
      text-transform: uppercase;
      background-color: var(--card-bg) !important;
    }
    tr.gps-fila {
      cursor: pointer;
      border-left: 4px solid transparent;
    }
    tr.gps-fila:hover { background-color: rgba(56, 189, 248, 0.08); }
    tr.gps-fila.seleccionado { border-left: 4px solid var(--primary-color); background: rgba(56, 189, 248, 0.1); }
    /* Una fila = un camion. Antes cada uno ocupaba dos o tres lineas
       (el nombre del chofer se partia y la posicion traia un <br> con la
       fecha), asi que en pantalla entraban seis camiones en vez de doce.
       La fecha exacta se movio al title: la insignia ya dice la antiguedad
       en relativo, que es lo que se mira de un vistazo. */
    tr.gps-fila td {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      vertical-align: middle;
      line-height: 1.4;
    }

    .tabla-gps { table-layout: fixed; }
    /* Cuatro columnas: la de velocidad se cambio por "KM hoy". El numero
       instantaneo era 0 km/h en casi todas las filas y el punto verde ya dice
       si el camion se mueve; la velocidad exacta quedo en el title. */
    /* La patente es el identificador: nunca debe recortarse. 106px cubren el
       punto de movimiento mas ocho caracteres en monoespaciada. */
    .tabla-gps th:nth-child(1), .tabla-gps td:nth-child(1) { width: 112px; }
    .tabla-gps th:nth-child(2), .tabla-gps td:nth-child(2) { width: 22%; }
    .tabla-gps th:nth-child(3), .tabla-gps td:nth-child(3) { width: 84px; }

    /* La direccion se recorta, la insignia nunca: es el dato que decide
       si hay que revisar el camion. */

    /* ---- Dialogos ----
       El formulario estaba fijo en la columna derecha ocupando pantalla todo el
       tiempo; ahora se abre solo cuando se lo pide. */
    .modal-app {
      border: 1px solid var(--border-color);
      border-radius: 10px;
      background-color: var(--card-bg);
      color: var(--text-main);
      padding: 0;
      /* El reset de la pagina pisa el margin:auto que trae el dialog, y sin eso
         el cuadro queda pegado al borde izquierdo en vez de centrado. */
      margin: auto;
      width: min(420px, calc(100vw - 24px));
      max-height: calc(100vh - 40px);
      overflow: hidden;
      box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
    }
    .modal-app::backdrop { background: rgba(0, 0, 0, 0.55); }
    .modal-app .modal-cuerpo { padding: 16px; max-height: calc(100vh - 40px); overflow-y: auto; }
    .modal-app h2 { margin-top: 0; }
    /* Sin showModal el dialogo queda en el flujo: al menos se ve centrado. */
    .modal-app:not([open]) { display: none; }

    .modal-app .modal-cuerpo { position: relative; }
    /* La revision documental muestra una tabla: necesita mas ancho. */
    .modal-doc { width: min(760px, calc(100vw - 24px)); }
    .modal-doc table { font-size: 0.72rem; }
    .modal-doc .doc-seccion { margin-top: 14px; }
    .modal-doc .doc-seccion > h3 {
      font-size: 0.78rem; margin: 0 0 6px; display: flex; align-items: center; gap: 6px;
    }
    /* Columna de numero del Listado Oficial: angosta, para no robarle ancho
       a las que tienen datos. */
    #tabla-continente td:first-child, #tabla-isla td:first-child { width: 34px; }

    /* Fichas de la revision documental: una por camion, con su motivo. */
    .doc-ficha {
      border: 1px solid var(--border-color);
      border-left: 3px solid var(--danger-color);
      border-radius: 6px;
      padding: 8px 10px;
      margin-bottom: 6px;
    }
    .doc-ficha-incluida { background: rgba(148, 163, 184, 0.07); border-left-color: var(--warning-color); }
    .doc-ficha-cab { display: flex; align-items: center; gap: 8px; cursor: pointer; margin: 0; }
    .doc-ficha-cab input { width: auto; margin: 0; }
    .doc-ficha-chofer { font-size: 0.72rem; color: var(--text-muted); margin: 2px 0 4px 24px; }
    .doc-ficha-docs { font-size: 0.72rem; color: var(--danger-color); margin-left: 24px; line-height: 1.5; }
    .doc-motivo { width: 100%; margin-top: 6px; }
    .doc-motivo:disabled { opacity: 0.45; }
    .doc-resumen { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
    .doc-chip {
      border: 1px solid var(--border-color); border-radius: 999px;
      padding: 2px 9px; font-size: 0.7rem; font-weight: 700;
    }

    /* ==========================================================
       RESUMEN POR TRANSPORTISTA EN LA ALERTA DOCUMENTAL
       La alerta listaba los camiones sueltos, ordenados por vencimiento. Con
       ocho empresas mezcladas no se ve a quien hay que reclamarle: juntar los
       de un transportista pedia recorrer la lista entera. Un cuadro por
       empresa lo dice de entrada, y al tocarlo filtra la alerta a esa empresa.
       ========================================================== */
    .doc-emp-cards {
      display: grid; gap: 6px; margin: 10px 0 4px;
      grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }
    .doc-emp-card {
      display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
      padding: 6px 8px 6px 10px; cursor: pointer; text-align: left;
      background: var(--input-bg); color: var(--text-main);
      border: 1px solid var(--border-color); border-radius: 6px;
      border-left: 3px solid var(--emp-color, var(--border-color));
      font: inherit; line-height: 1.2;
    }
    .doc-emp-card:hover { border-color: var(--primary-color); }
    /* La elegida se marca con el color de su propia empresa y no con uno
       generico: asi el cuadro activo y las filas que quedan abajo se leen como
       lo mismo. */
    .doc-emp-card.activa {
      border-color: var(--emp-color, var(--primary-color));
      background: color-mix(in srgb, var(--emp-color, transparent) 16%, var(--input-bg));
    }
    .emp-nombre {
      font-size: 0.68rem; font-weight: 700; letter-spacing: .02em;
      overflow-wrap: anywhere;
    }
    .emp-cifras { display: flex; flex-wrap: wrap; gap: 4px; }
    .emp-n {
      font-size: 0.66rem; font-weight: 800;
      padding: 0 4px; border-radius: 3px;
    }
    .emp-n-bloq { color: var(--danger-color); background: color-mix(in srgb, var(--danger-color) 14%, transparent); }
    .emp-n-prox { color: var(--warning-color); background: color-mix(in srgb, var(--warning-color) 14%, transparent); }
    .emp-n-falta { color: var(--text-muted); background: color-mix(in srgb, var(--text-muted) 12%, transparent); }
    .emp-n-ok { color: var(--success-color); background: color-mix(in srgb, var(--success-color) 14%, transparent); }
    .emp-total { font-size: 0.6rem; color: var(--text-muted); }
    .doc-emp-nota { margin: 2px 0 0; }


    /* Los 14 campos no entran en una pantalla: los botones se quedan pegados
       abajo para no tener que buscar "Guardar" scrolleando. */
    .modal-acciones {
      position: sticky;
      bottom: 0;
      display: flex;
      flex-direction: column;
      gap: 5px;
      padding: 10px 0 2px;
      margin-top: 4px;
      background: linear-gradient(to bottom, transparent, var(--card-bg) 35%);
    }

    .modal-cerrar {
      position: absolute; top: 0; right: 0;
      background: none; border: none; cursor: pointer;
      color: var(--text-muted); font-size: 1rem; line-height: 1; padding: 4px 6px;
    }
    .modal-cerrar:hover { color: var(--text-main); }

    /* El formulario para agregar viajes estaba metido en dos columnas de la
       tabla y le comia el ancho a la columna de viajes, que es la que hay que
       leer. Ahora es este boton y un dialogo. */
    .btn-agregar-viaje {
      background: none; border: 1px dashed var(--border-color); border-radius: 4px;
      color: var(--text-muted); cursor: pointer;
      font-size: 0.66rem; font-weight: 600; padding: 2px 7px; line-height: 1.25;
    }
    .btn-agregar-viaje:hover { border-color: var(--primary-color); color: var(--primary-color); }
    #vj-km-wrap { margin: 6px 0 10px; }

    /* El tanque que venia pegado al nombre del lugar en el itinerario de ENAP.
       Se muestra al lado del lugar ya resuelto para poder controlar que se
       leyo bien antes de confirmar la programacion. */
    /* El resumen de la importacion: lo que hay que ver antes de confirmar, y
       no despues. */
    /* El relevo dentro de la revision documental: los dos nombres con su
       mitad del dia, y el que tiene un documento vencido en rojo. */
    .doc-relevo { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
    .doc-relevo-chofer { white-space: nowrap; }
    .doc-relevo-turno {
      font-size: 0.58rem; font-weight: 700; color: var(--text-muted);
      border: 1px solid var(--border-color); border-radius: 4px; padding: 0 4px;
    }
    .doc-relevo-mal { color: var(--danger-color); font-weight: 700; }
    .doc-relevo-flecha { color: var(--text-muted); }

    /* Los titulos de cada seccion de la ventana de validacion: cambios de
       chofer y rol cumplido son dos preguntas distintas y conviene que se vea. */
    .val-titulo {
      font-size: 0.86rem; margin: 14px 0 6px;
      padding-bottom: 5px; border-bottom: 1px solid var(--border-color);
    }
    .val-titulo:first-child { margin-top: 0; }
    /* Cuantos dias de mas lleva: es el dato que decide, va destacado. */
    .val-exceso {
      font-size: 0.68rem; font-weight: 700; color: var(--warning-color);
      border: 1px solid var(--warning-color); border-radius: 4px; padding: 1px 6px;
    }
    /* Cuando ni la extension explica el caso: no es una opcion, es un aviso. */
    .val-aviso { border-left-color: var(--danger-color); margin: 4px 0 8px; }

    /* La ventana de cambios de chofer: una ficha por camion, para que cada
       decision se vea separada de la de al lado. Con seis camiones cambiados en
       una lista corrida es facil contestar la del vecino. */
    .modal-cambios { width: min(620px, 94vw); }
    .cambio-ficha {
      border: 1px solid var(--border-color); border-radius: 8px;
      padding: 10px 12px; margin-bottom: 10px;
    }
    .cambio-cab {
      display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
      font-size: 0.82rem; margin-bottom: 8px;
      padding-bottom: 6px; border-bottom: 1px solid var(--border-color);
    }
    .cambio-flecha { font-size: 0.75rem; color: var(--text-main); }
    .cambio-op {
      display: flex; align-items: flex-start; gap: 7px;
      font-size: 0.76rem; padding: 3px 0; cursor: pointer;
    }
    .cambio-op input { margin: 2px 0 0; }
    /* Las mitades del dia solo tienen sentido si es un relevo: con la otra
       opcion marcada se esconden en vez de quedar preguntando al vacio. */
    .cambio-turnos { display: flex; gap: 12px; margin: 4px 0 8px 22px; }
    .cambio-turnos label {
      flex: 1; display: flex; flex-direction: column; gap: 3px;
      font-size: 0.68rem; color: var(--text-muted);
    }
    .cambio-turnos select { width: 100%; }

    /* El cuadro del relevo: las dos mitades del dia, una al lado de la otra,
       porque la pregunta es una sola y partirla en dos filas la alarga. */
    .modal-relevo { width: min(480px, 94vw); }
    .relevo-turnos { display: flex; gap: 12px; }
    .relevo-turnos label {
      flex: 1; display: flex; flex-direction: column; gap: 4px;
      font-size: 0.72rem; color: var(--text-muted);
    }
    .relevo-turnos select { width: 100%; }
    /* Las dos salidas del cuadro llevan su explicacion debajo. La diferencia
       entre ellas es si al que sube se le reinicia el ciclo, y eso no se
       adivina del rotulo de un boton: guardar como relevo un cambio de camion
       a mitad de turno le borra los dias que lleva arriba. */
    .relevo-opcion { display: flex; flex-direction: column; gap: 3px; }
    .relevo-opcion-ayuda {
      padding: 0 2px 4px;
      font-size: 0.7rem;
      line-height: 1.35;
      color: var(--text-muted);
    }

    /* ============ QUIEN ESTA CONECTADO ============ */
    /* El chip decia cuantos; el panel dice quienes. Se abre al pasar el mouse y
       tambien con el teclado, que el chip es enfocable. */
    .conectados-chip { position: relative; cursor: default; }
    .conectados-lista {
      display: none; position: absolute; top: calc(100% + 8px); right: 0;
      min-width: 230px; max-width: 320px; z-index: 200;
      padding: 8px 10px; border-radius: 8px;
      background: var(--bg-card, #111827); border: 1px solid var(--border-color);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
      text-align: left; cursor: default;
    }
    .conectados-chip:hover .conectados-lista,
    .conectados-chip:focus-within .conectados-lista { display: block; }
    .conectados-titulo {
      font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.04em;
      color: var(--text-muted); margin-bottom: 6px;
    }
    .conectados-fila {
      display: flex; align-items: center; gap: 7px;
      font-size: 0.74rem; padding: 3px 0; white-space: nowrap;
    }
    .conectados-punto {
      width: 6px; height: 6px; border-radius: 50%; flex: none;
      background: var(--success-color);
    }
    .conectados-anon .conectados-punto { background: var(--warning-color); }
    .conectados-nombre { flex: 1; overflow: hidden; text-overflow: ellipsis; }
    /* La hora de entrada al margen: es un dato de respaldo, no lo que se lee
       primero. */
    .conectados-hora { font-variant-numeric: tabular-nums; }
    .conectados-pie {
      margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border-color);
      font-size: 0.62rem; color: var(--text-muted); white-space: normal;
    }

    /* ============ SESION Y USUARIOS ============ */
    /* El chip del encabezado: quien esta usando la pagina. Con cuenta va en
       verde y con el nombre; sin cuenta, en ambar, porque es un estado que
       conviene que moleste un poco hasta que todos tengan la suya. */
    .sesion-chip { display: flex; align-items: center; gap: 7px; cursor: default; }
    .sesion-punto { width: 7px; height: 7px; border-radius: 50%; flex: none; }
    .sesion-ok { background: var(--success-color); }
    .sesion-anon { background: var(--warning-color); }
    .sesion-nombre {
      max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      font-size: 0.72rem;
    }
    .sesion-btn {
      background: none; border: 1px solid var(--border-color); border-radius: 5px;
      padding: 2px 8px; cursor: pointer;
      font-size: 0.68rem; color: var(--text-muted);
    }
    .sesion-btn:hover { border-color: var(--primary-color); color: var(--text-main); }

    .modal-login { width: min(420px, 94vw); }

    /* El login obligatorio es la puerta, no un cuadro mas: detras no hay datos
       cargados, asi que ofrecer cerrarlo solo sirve para dejar a la vista una
       pagina vacia que parece rota. Se sacan las salidas y se tapa el fondo. */
    .modal-login.login-puerta .modal-cerrar,
    .modal-login.login-puerta .modal-acciones .btn-submit:not(.btn-success) { display: none; }
    .modal-login.login-puerta::backdrop { background: rgba(8, 12, 20, 0.92); }
    /* El error del formulario: rojo y visible, porque es lo que hay que leer
       para saber que hacer. */
    .login-error {
      border-left-color: var(--danger-color);
      color: var(--danger-color); font-weight: 600;
    }
    /* La cuenta desactivada sigue en la lista pero apagada: borrarla de la
       vista esconderia que existe y que puede reactivarse. */
    .usr-inactivo > td { opacity: 0.55; }

    .enap-cargando { color: var(--primary-color); font-weight: 700; }
    /* La capacidad del renglon, al lado de la categoria. Va visible porque es
       lo que decide que camiones se ofrecen, y el archivo la contradice: un
       bloque "CONTINENTE 30M3" puede traer un renglon de 15. */
    .enap-cap {
      display: block; font-size: 0.58rem; font-weight: 700;
      color: var(--color-titular); letter-spacing: 0.02em;
    }
    /* Los tramos que no tienen kilometraje. Va pegado al resumen porque es la
       explicacion de por que los totales de arriba salen cortos. */
    .enap-faltan {
      font-size: 0.72rem; margin: 6px 0 10px;
      padding: 8px 10px; border-radius: 6px;
      border: 1px solid var(--warning-color);
      background: color-mix(in srgb, var(--warning-color) 10%, transparent);
    }
    .enap-faltan-lista {
      list-style: none; margin: 6px 0 0; padding: 0;
      display: flex; flex-wrap: wrap; gap: 4px 14px;
    }
    .enap-faltan-lista li { white-space: nowrap; }
    .enap-faltan-tramo {
      background: none; border: none; padding: 0; cursor: pointer;
      font-size: 0.72rem; font-weight: 700; color: var(--text-main);
      border-bottom: 1px dotted var(--warning-color);
    }
    .enap-faltan-tramo:hover { color: var(--warning-color); }
    .enap-resumen {
      margin: 6px 0 8px; padding: 6px 9px;
      background: var(--input-bg); border: 1px solid var(--border-color);
      border-radius: 5px; font-size: 0.72rem; color: var(--text-muted);
    }
    .enap-aviso { color: var(--color-backup); font-weight: 700; }
    .enap-carga { font-size: 0.7rem; white-space: nowrap; }
    .enap-carga-alerta { color: var(--color-backup); font-weight: 700; }

    /* La tabla de importacion copia la forma del formulario de ENAP: los
       viajes de un renglon van al lado, no abajo, y por eso es ancha y
       scrollea. Letra chica para que entren tres o cuatro viajes por renglon
       sin que el nombre del lugar se parta. */
    /* Letra chica y celdas apretadas a proposito: son once columnas por
       renglon y cuatro viajes posibles, asi que cada pixel de mas se multiplica
       por diez. El tamano va en td y th y no solo en la tabla: la regla global
       de td fija 0.8rem y le gana a lo que se herede del contenedor. */
    .tabla-enap td, .tabla-enap th {
      font-size: 0.62rem; padding: 0 5px; height: 26px;
    }
    .tabla-enap th.enap-grupo { background: var(--card-bg); }
    .tabla-enap td { white-space: nowrap; }
    .tabla-enap .enap-lugar { font-weight: 600; }
    .tabla-enap .enap-vacia { background: repeating-linear-gradient(45deg, transparent 0 6px, var(--zebra) 6px 7px); }
    .tabla-enap .enap-cat { font-size: 0.55rem; color: var(--text-muted); }
    .tabla-enap .enap-obs { font-size: 0.55rem; color: var(--text-muted); white-space: normal; max-width: 170px; }
    .tabla-enap .enap-tk { font-size: 0.5rem; padding: 0 2px; }
    .tabla-enap .enap-carga { font-size: 0.58rem; }
    /* Km y plata: a la derecha y con cifras de ancho fijo, para poder
       compararlas de arriba abajo sin leer cada una. */
    /* El km de posicionamiento, al lado del total y en gris: es parte del
       numero pero no es lo que ENAP pidio. */
    .tabla-enap .enap-vacio-km { font-weight: 500; color: var(--text-muted); }
    .tabla-enap .enap-num {
      text-align: right; white-space: nowrap;
      font-variant-numeric: tabular-nums; font-weight: 700;
    }
    /* Estos dos van con el id adelante y no con la clase sola. La regla global
       de campos —input:not([type=checkbox]):not(...):not(...), select— suma tres
       pseudoclases y le gana a cualquier selector de dos clases: sin el id, el
       relleno de 8px y la letra de 0.78rem se imponian igual y la cantidad
       quedaba tapada dentro de una caja de 34px. */
    .tabla-enap .enap-cant-col { width: 1%; text-align: center; }
    #enap-tabla-wrap .enap-cant-col input[type="number"] {
      width: 40px; padding: 1px 2px; text-align: center; font-size: 0.66rem;
      border: 1px solid var(--border-color); border-radius: 4px;
      background-color: var(--input-bg); color: var(--text-main);
      /* Sin las flechitas: se comen la mitad de una caja de 40px y el numero
         —que es el dato— queda afuera. Se escribe a mano, que es como se usa. */
      appearance: textfield; -moz-appearance: textfield;
    }
    #enap-tabla-wrap .enap-cant-col input[type="number"]::-webkit-outer-spin-button,
    #enap-tabla-wrap .enap-cant-col input[type="number"]::-webkit-inner-spin-button {
      -webkit-appearance: none; margin: 0;
    }
    /* El camion repetido en dos renglones: el color de la opcion no se ve con
       la lista cerrada, asi que se marca el desplegable entero. No se bloquea
       —un camion PUEDE hacer dos renglones— pero tiene que verse. */
    /* Con "select" adelante y no solo la clase: la regla de abajo que fija el
       ancho tiene la misma cuenta de especificidad y, por venir despues, le
       ganaba el empate y la marca no se veia. */
    #enap-tabla-wrap select.enap-patente-repetida {
      border-color: var(--color-backup);
      color: var(--color-backup);
      font-weight: 700;
    }
    /* Ancho FIJO: un select toma el ancho de su opcion mas larga —"SKST-34 ·
       PATRICIO GALINDO · 1 viaje ya"— y esa sola columna se llevaba 313px. */
    #enap-tabla-wrap .enap-patente {
      width: 145px; padding: 2px; font-size: 0.6rem;
      border: 1px solid var(--border-color); border-radius: 4px;
      background-color: var(--input-bg); color: var(--text-main);
    }

    .enap-tk {
      font-size: 0.6rem; font-weight: 700; color: var(--text-muted);
      border: 1px solid var(--border-color); border-radius: 3px; padding: 0 3px;
    }

    /* ==========================================================
       PROGRAMACION: UN TRAMO POR FILA
       Origen y destino son columnas de la tabla y no texto dentro de una
       celda, asi se leen derecho hacia abajo bajo su encabezado. Patente,
       chofer y producto ocupan las tres primeras columnas con rowspan sobre
       los tramos de ese camion.
       ========================================================== */
    /* A media altura siempre: con rowspan de por medio, alinear arriba dejaba
       la patente pegada al techo de su bloque. Los numeros y los botones van
       centrados; lo que es texto —patente, chofer, producto y los dos
       lugares— va a la izquierda, que es como se lee una lista de nombres. */
    #tabla-programacion-continente td,
    #tabla-programacion-isla td {
      text-align: left; vertical-align: middle;
      /* Mas chica que el resto de las tablas: son once columnas y lo que se
         gana de ancho se lo llevan los nombres de lugar. */
      font-size: 0.72rem; padding: 0 7px;
    }
    /* Las columnas de numeros y de botones, centradas. El :is() no es adorno:
       las reglas de arriba llevan un id y una clase sola no les gana, asi que
       el texto quedaba centrado igual. */
    :is(#tabla-programacion-continente, #tabla-programacion-isla)
    :is(.pg-viajes, .pg-kms, .pg-valor, .pg-recorrido, .pg-estado, .pg-agregar,
        .pg-nada, .sin-resultados td) { text-align: center; }
    #subvista-programacion-continente thead th,
    #subvista-programacion-isla thead th { text-align: center; }
    #subvista-programacion-continente thead th.th-txt,
    #subvista-programacion-isla thead th.th-txt { text-align: left; }

    .pg-num-camion {
      text-align: center !important; white-space: nowrap;
      font-size: 0.6rem; font-weight: 700; color: var(--text-muted);
      font-variant-numeric: tabular-nums;
    }
    /* Lo programado contra lo que midio el GPS. Angosta y sin cortar: es una
       comparacion que se recorre de arriba abajo, no una frase. */
    .pg-kmgps { white-space: nowrap; font-size: 0.62rem; }
    .km-falta { font-weight: 700; color: var(--color-backup); }
    .pg-camion { white-space: nowrap; }
    .pg-camion strong { font-size: 0.8rem; letter-spacing: .02em; }
    /* Producto, capacidad y categoria en una linea. Apilados ahorraban 100px
       de ancho, pero estiraban a 64px la fila de los camiones con un solo
       viaje y la tabla dejaba de tener el paso parejo del Listado Oficial. */
    .pg-producto { font-size: 0.7rem; }
    .pg-producto > * { margin-right: 3px; }
    /* Los badges de esta tabla, mas chicos que en el resto: son tres en una
       celda y en tamano normal la columna se llevaba 198px. */
    .pg-producto .badge, .pg-producto .badge-product { font-size: 0.54rem; padding: 1px 4px; }
    /* Las dos columnas de botones se quedan con lo minimo: su texto parte en
       dos renglones antes que robarle ancho a los nombres de lugar. */
    .pg-recorrido, .pg-agregar { width: 1%; }
    .pg-recorrido .btn-recorrido, .pg-agregar .btn-agregar-viaje { white-space: nowrap; }
    .pg-cap { font-size: 0.66rem; font-weight: 700; color: var(--text-muted); }

    /* Separar las unidades. Con rowspan no se ve donde termina un camion y
       empieza el siguiente, asi que cada uno abre con una linea mas marcada y
       va sobre una banda propia: uno de cada dos apenas tenido. La cebra por
       fila se apaga porque rayaba DENTRO de un mismo camion, que es justo lo
       contrario de lo que hace falta. */
    /* El corte de base es el mismo del Listado Oficial: la banda entera tenida
       con el color de la base. Aca ademas hay que separar unidades DENTRO de
       la base, asi que se reparte la jerarquia: la base es la banda de color y
       el camion apenas una linea mas la banda de uno de cada dos. Si el corte
       de camion pesara como el de base, la tabla se leeria como si cada camion
       fuera un bloque aparte. */
    #tabla-programacion-continente tr.tr-grupo-base td,
    #tabla-programacion-isla tr.tr-grupo-base td {
      padding: 0 13px; text-align: left; font-size: 0.72rem;
    }
    tr[data-inicio] > td { border-top: 1px solid var(--border-color); }
    #tabla-programacion-continente tr:nth-child(even),
    #tabla-programacion-isla tr:nth-child(even) { background-color: transparent; }
    #tabla-programacion-continente tr.pg-banda,
    #tabla-programacion-isla tr.pg-banda { background-color: var(--zebra); }
    /* El hover se vuelve a declarar con el id adelante: la regla global tr:hover
       ya no le gana a las dos de arriba. */
    #tabla-programacion-continente tr.pg-unidad:hover,
    #tabla-programacion-isla tr.pg-unidad:hover { background-color: var(--hover); }

    /* El total del dia, plegado: destacado y arriba de su bloque, para poder
       recorrer los totales de un camion al otro sin leer el resto. */
    .pg-total { font-weight: 800; color: var(--text-main) !important; vertical-align: middle; }

    /* Los nombres de lugar son largos y, sueltos, se llevaban 320px cada
       columna y empujaban la tabla fuera de su caja. Con tope parten en dos
       renglones, que es mas barato que perder las columnas de la derecha. */
    /* Una linea por fila, como en el Listado Oficial: se deja el nowrap que ya
       traen los td y se achica la letra hasta que el nombre mas largo entre.
       "TERMINAL GREGORIO DESCARGADERO" mide 247px a 12,8px y 216 a 11,2. Si la
       tabla no entra en su caja, scrollea, que es lo que hace el Listado
       Oficial (mide 1407 en un contenedor de 1330). */
    /* Ancho fijo y el mismo en los dos sectores. Sin esto cada tabla se acomoda
       al nombre mas largo que le toco ese dia —Continente daba 237px de origen
       contra 161 de Isla— y las dos planillas no se parecen entre si ni de un
       dia para el otro. En 240px entra el nombre mas largo que hay,
       "TERMINAL GREGORIO DESCARGADERO", y en 150 el chofer mas largo.
       Va como min-width y no width: con width la tabla, que ya es mas ancha
       que su caja, lo ignora y sigue repartiendo por contenido. */
    .pg-desde, .pg-hasta { font-size: 0.68rem; min-width: 240px; }
    .pg-chofer { min-width: 150px; }
    .pg-nada { text-align: left !important; }
    .pg-obs { font-size: 0.62rem; font-style: italic; color: var(--text-muted); }
    /* La nota del estado: en la planilla es un boton con lo que dice la nota,
       y el texto se escribe en su propio cuadro. Un campo por fila con veinte
       camiones en pantalla es una columna de cajas vacias; el boton ocupa lo
       que ocupa el texto y se lee de un vistazo cual tiene nota y cual no. */
    .pg-obs-celda { padding: 0 4px !important; }
    .pg-nota-btn {
      max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      display: block; text-align: left;
      background: none; border: 1px dashed var(--border-color); border-radius: 4px;
      padding: 2px 6px; cursor: pointer;
      font-size: 0.62rem; font-style: italic; color: var(--text-muted);
    }
    .pg-nota-btn:hover { border-style: solid; border-color: var(--primary-color); color: var(--text-main); }
    /* Con nota puesta deja de ser un hueco por llenar y pasa a ser un dato. */
    .pg-nota-puesta {
      border-style: solid; border-color: var(--primary-color);
      background: color-mix(in srgb, var(--primary-color) 12%, transparent);
      color: var(--text-main); font-style: normal; font-weight: 600;
    }
    .pg-nota-mezcla { border-color: var(--warning-color); color: var(--warning-color); }

    /* El cuadro: los casos frecuentes arriba, el texto libre abajo. */
    .modal-nota { width: min(560px, 94vw); }
    .notas-chips { display: flex; flex-wrap: wrap; gap: 6px; }
    /* El cuadro de texto ocupa el ancho del modal: la regla generica de
       textarea le deja el ancho por defecto del navegador, unos 200px, y la
       nota se escribe en una columna angosta al lado de un hueco. */
    #nota-estado-texto { width: 100%; box-sizing: border-box; resize: vertical; }
    .nota-chip {
      background: none; border: 1px solid var(--border-color); border-radius: 999px;
      padding: 4px 10px; cursor: pointer;
      font-size: 0.72rem; color: var(--text-muted);
    }
    .nota-chip:hover { border-color: var(--primary-color); color: var(--text-main); }
    .nota-chip.activo {
      border-color: var(--primary-color); color: var(--text-main); font-weight: 700;
      background: color-mix(in srgb, var(--primary-color) 18%, transparent);
    }
}
    .pg-corte { font-weight: 900; color: var(--color-licencia); }
    .pg-lugar { font-weight: 700; color: var(--text-main); }
    .pg-vacio .pg-lugar { font-weight: 500; color: var(--text-muted); }
    .pg-vacio { opacity: .82; }
    .pg-desde .tramo-asa { display: inline-block; width: 12px; margin-right: 2px; }

    /* La cantidad y el estado salieron de la celda del destino a columnas
       propias: apiladas todas ahi, tapaban el nombre del lugar, que es lo que
       se lee al programar. El numero grande deja ver de un vistazo cuantos
       viajes tiene cada tramo; los km y el valor van abajo, chicos. */
    /* Las tres columnas de numeros: angostas, sin cortar y una al lado de la
       otra, para poder recorrerlas de arriba abajo sin leer el resto. */
    .pg-viajes, .pg-kms, .pg-valor { white-space: nowrap; width: 1%; }
    .pg-num { font-size: 0.95rem; font-weight: 800; color: var(--primary-color); line-height: 1; }
    .pg-kms { font-size: 0.68rem; font-weight: 700; }
    .pg-valor { font-size: 0.68rem; color: var(--text-muted); }
    .pg-vacio .pg-num, .pg-vacio .pg-kms { font-weight: 500; color: var(--text-muted); }

    /* El tipo salio de la columna de cantidad: se marca solo el vacio, porque
       el cargado es lo normal y ya se distingue por el asa de arrastre. */
    .pg-tag-vacio {
      display: inline-block; margin-right: 4px;
      font-size: 0.5rem; font-weight: 700; letter-spacing: .04em;
      text-transform: uppercase; color: var(--text-muted);
      border: 1px solid var(--border-color); border-radius: 3px; padding: 0 2px;
    }

    /* Jornada cobrada por tiempo. Va en ambar y no en gris como el vacio: el
       vacio es un tramo de apoyo y este es el servicio que se factura, asi que
       tiene que saltar a la vista en una planilla llena de viajes cargados. */
    .pg-tag-hora {
      display: inline-block; margin-right: 4px;
      font-size: 0.5rem; font-weight: 700; letter-spacing: .04em;
      text-transform: uppercase; color: var(--color-backup);
      border: 1px solid var(--color-backup); border-radius: 3px; padding: 0 3px;
      white-space: nowrap;
    }
    /* La cantidad de horas es un numero, no un rotulo: sin versalitas, que
       dejaban "8,5 H" con la hache gritada. */
    .pg-horas {
      font-weight: 700;
      color: var(--color-backup);
      font-variant-numeric: tabular-nums;
      white-space: nowrap;
    }
    .pg-hora-rango {
      font-size: 0.68rem;
      color: var(--text-muted);
      font-variant-numeric: tabular-nums;
    }
    .pg-fila.pg-hora { background-color: var(--bg-backup); }

    /* La barra de estado a paso fijo: tres huecos del mismo ancho en todas las
       filas —selector, editar, borrar—, asi la columna queda a plomo. En grid
       y no en flex justamente por eso: con flex cada fila se acomodaba a su
       contenido y los iconos bailaban de una a la otra. */
    .pg-acciones {
      display: grid; grid-template-columns: 1fr 14px 14px;
      align-items: center; gap: 4px; justify-content: center;
    }
    .pg-nada { font-size: 0.7rem; }

    /* La casilla de pendiente / realizado. La palabra va al lado y no solo el
       tilde: en una columna de veinte filas, "Pendiente" escrito se cuenta de
       un vistazo y una casilla vacia no. */
    .pg-chk {
      display: inline-flex; align-items: center; gap: 4px;
      cursor: pointer; white-space: nowrap;
      background: none; border: none; padding: 0; font: inherit;
      font-size: 0.6rem; font-weight: 700; letter-spacing: .03em;
      text-transform: uppercase; color: var(--text-muted);
    }
    /* La caja se dibuja a mano y no es un <input type=checkbox>: una casilla
       de verdad tiene dos posiciones y aca son tres —pendiente, realizado,
       cancelado—, que ninguna casilla puede recorrer con un clic. */
    .pg-chk-caja {
      display: inline-flex; align-items: center; justify-content: center;
      width: 13px; height: 13px; border-radius: 3px;
      border: 1px solid var(--border-color); background: var(--input-bg);
      font-size: 0.6rem; line-height: 1;
    }
    .pg-chk:hover .pg-chk-caja { border-color: var(--primary-color); }
    .pg-chk-ok { color: var(--success-color); }
    .pg-chk-ok .pg-chk-caja { border-color: var(--success-color); background: var(--success-color); color: #fff; }
    .pg-chk-no { color: var(--danger-color); }
    .pg-chk-no .pg-chk-caja { border-color: var(--danger-color); background: var(--danger-color); color: #fff; }
    /* Grupo con estados mezclados: ni marcado ni sin marcar, y se dice cuantos
       van en el rotulo de al lado. */
    .pg-chk-parcial .pg-chk-caja { border-color: var(--text-muted); color: var(--text-muted); }
    /* Un cancelado ya no es plan ni es carga: se apaga la fila entera. */
    .pg-fila:has(.pg-chk-no) .pg-lugar { text-decoration: line-through; opacity: .65; }
    /* Un estado que la casilla no puede representar —EN CURSO, CANCELADO, de
       viajes viejos—: se muestra al lado en vez de desaparecer. */
    .pg-chk-otro {
      font-size: 0.52rem; font-weight: 700; color: var(--color-backup);
      border: 1px solid var(--color-backup); border-radius: 3px; padding: 0 3px;
    }

    /* La hora que dejo la validacion contra el GPS: dato de respaldo, no lo
       que se lee primero, asi que va chica y en gris al lado del lugar. */
    /* Verde claro y no gris: la hora es lo unico de la fila que confirmo el
       GPS, y el verde la separa de lo que es plan. Sale de --color-titular, el
       mismo verde de los badges, que ya viene resuelto para los dos temas: en
       claro baja a un tono oscuro para no perder contraste sobre el fondo. */
    .pg-hora {
      font-size: 0.58rem; font-weight: 700; color: var(--color-titular);
      font-variant-numeric: tabular-nums;
      background: none; border: none; padding: 0; cursor: pointer;
      border-bottom: 1px dotted var(--color-titular);
    }
    .pg-hora:hover { color: var(--text-main); border-bottom-color: var(--text-main); }

    /* El ancho va en el <dialog> y no en el cuerpo: .modal-app fija ahi su
       width, y ponerlo en el hijo no mueve nada —el mapa terminaba mas ancho
       que su propio cuadro—. Mismo patron que .modal-doc. */
    .modal-ruta { width: min(900px, calc(100vw - 24px)); }
    /* Alto acotado: dentro de un dialogo no hay de donde sacar el 100% de la
       altura, y un 60vh crudo empujaba el titulo fuera de la pantalla. */
    /* Reproduccion del dia: el boton, el deslizador y el reloj en una linea
       sobre el mapa. */
    .ruta-play { display: flex; align-items: center; gap: 10px; margin: 8px 0 0; }
    .ruta-play input[type="range"] { flex: 1 1 auto; min-width: 0; accent-color: var(--primary-color); }
    .ruta-reloj { font-size: 0.72rem; white-space: nowrap; font-variant-numeric: tabular-nums; }

    /* Las paradas del dia: es la lectura de los horarios sin mirar el mapa. */
    .ruta-paradas { margin-top: 10px; max-height: 170px; overflow-y: auto; }
    .tabla-paradas { font-size: 0.68rem; }
    .tabla-paradas td, .tabla-paradas th { padding: 0 8px; height: 24px; }
    .tabla-paradas tbody tr { cursor: pointer; }
    .ruta-hora-celda { white-space: nowrap; font-variant-numeric: tabular-nums; font-weight: 700; }

    /* El mapa de Puntos Conocidos: alto fijo porque va dentro de una tarjeta
       que crece con la tabla, y un 100% no tendria contra que medirse. */
    .mapa-puntos {
      height: 380px; margin: 8px 0;
      border: 1px solid var(--border-color); border-radius: 6px;
    }
    .pm-aviso {
      border-left-color: var(--primary-color);
      display: flex; align-items: center; gap: 10px;
    }
    /* La fila que se toco en el mapa: se marca para encontrarla entre cien. */
    .pm-fila-activa > td { background-color: color-mix(in srgb, var(--primary-color) 16%, transparent); }

    /* El panel de geocercas dentro del modal de recorrido. */
    .ruta-geocercas { margin-top: 10px; }
    .ruta-geo-cab {
      display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
      font-size: 0.78rem; margin-bottom: 6px;
    }
    .tabla-geocercas td, .tabla-geocercas th { vertical-align: middle; }
    .tabla-geocercas .geo-acciones { white-space: nowrap; text-align: right; }
    .tabla-geocercas .geo-acciones button { padding: 3px 8px; font-size: 0.68rem; margin-left: 4px; }
    .geo-ok { color: var(--success-color); font-weight: 700; }
    /* El radio se edita mientras se ve el circulo: el input va en el aviso. */
    .geo-radio { font-size: 0.72rem; white-space: nowrap; }
    .geo-radio input { width: 70px; padding: 2px 6px !important; font-size: 0.72rem !important; margin: 0 4px; }

    .mapa-ruta-modal {
      height: min(58vh, 440px); min-height: 260px; margin-top: 8px;
      border: 1px solid var(--border-color); border-radius: 6px;
    }

    /* El boton que despliega la cadena con los posicionamientos. */
    .btn-recorrido {
      line-height: 1.25;
      background: none; border: 1px dashed var(--border-color); border-radius: 4px;
      color: var(--text-muted); cursor: pointer;
      font-size: 0.66rem; font-weight: 600; padding: 3px;
    }
    .btn-recorrido:hover { border-color: var(--primary-color); color: var(--primary-color); }

    /* Piezas de cada tramo, ahora dentro de las celdas DESDE / HASTA. */
    .tramo-asa { color: var(--text-muted); user-select: none; line-height: 1; }
    .pg-cargado:hover .tramo-asa { color: var(--primary-color); }
    .tramo-sinkm { color: var(--color-backup); font-weight: 700; }
    .tramo-editar {
      background: none; border: none; cursor: pointer;
      color: var(--text-muted); font-size: 0.68rem; padding: 0;
    }
    .tramo-editar:hover { color: var(--primary-color); }
    .tramo-borrar {
      background: none; border: none; cursor: pointer;
      color: var(--danger-color); font-size: 0.72rem; padding: 0;
    }
    .cadena-avisos {
      margin-top: 4px; font-size: 0.65rem; line-height: 1.5;
      color: var(--color-backup);
    }

    /* ---- Reordenar viajes arrastrando (Programacion) ---- */
    .viaje-fila { border-radius: 4px; }
    .viaje-cargado { cursor: grab; }
    .viaje-cargado:active { cursor: grabbing; }
    .viaje-cargado:hover { background: rgba(148, 163, 184, 0.08); }
    .viaje-arrastrando { opacity: 0.35; }
    /* La linea marca de que lado va a caer el viaje al soltar. */
    tr.viaje-drop-antes > td { box-shadow: inset 0 2px 0 0 var(--primary-color); }
    tr.viaje-drop-despues > td { box-shadow: inset 0 -2px 0 0 var(--primary-color); }
    .viaje-asa { color: var(--text-muted); user-select: none; text-align: center; line-height: 1; }
    .viaje-cargado:hover .viaje-asa { color: var(--primary-color); }

    .gps-pos { display: flex; align-items: center; gap: 6px; min-width: 0; }
    .gps-lugar { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .gps-pos .badge { flex: 0 0 auto; }

    /* Selector dentro de la tabla: 71 cajas con borde en una sola columna
       eran una pared. El control se dibuja al pasar por encima o al recibir
       foco; en reposo se lee como texto y deja respirar a la fila. */
    .inline-select {
      height: 24px; padding: 0 4px;
      font-size: 0.72rem; font-weight: 600;
      border-radius: 4px;
      border: 1px solid transparent;
      background-color: transparent;
      color: var(--text-main);
      cursor: pointer; outline: none;
      transition: background-color .1s ease, border-color .1s ease;
    }
    .inline-select:hover { border-color: var(--border-color); background-color: var(--input-bg); }
    .inline-select:focus { border-color: var(--primary-color); background-color: var(--input-bg); box-shadow: 0 0 0 3px var(--focus-wash); }

    .badge { display: inline-block; padding: 2px 6px; border-radius: 4px; font-size: 0.68rem; font-weight: 700; }
    .badge-base-gregorio { background: rgba(244, 63, 94, 0.15); color: var(--color-gregorio); }
    .badge-base-posesion { background: rgba(16, 185, 129, 0.15); color: var(--color-posesion); }
    .badge-base-cabonegro { background: rgba(99, 102, 241, 0.15); color: var(--color-cabonegro); }
    .badge-base-puntaarenas { background: rgba(234, 179, 8, 0.15); color: var(--color-puntaarenas); }
    .badge-base-sombrero { background: rgba(249, 115, 22, 0.15); color: var(--color-sombrero); }
    .badge-base-cullen { background: rgba(56, 189, 248, 0.15); color: var(--color-cullen); }
    .badge-base-sinbase { background: rgba(148, 163, 184, 0.15); color: var(--text-muted); }

    /* El semaforo documental se puede tocar: que se note. */
    /* Los camiones con papeles vencidos se listan como chips: son pocos y
       cada uno lleva a su ficha. Una tabla para tres filas ocupa mas de lo
       que dice. */
    .alertas-camiones-chips {
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
      margin-bottom: 10px;
    }

    .badge-doc-click { cursor: pointer; }
    .badge-doc-click:hover { filter: brightness(1.25); text-decoration: underline; }
    .badge-doc-click:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 1px; }
    .badge-doc-ok { background-color: var(--bg-titular); color: var(--color-titular); }
    .badge-doc-porvencer { background-color: var(--bg-backup); color: var(--color-backup); }
    .badge-doc-vencido { background-color: var(--bg-licencia); color: var(--color-licencia); }
    .badge-doc-sindatos { background: rgba(148, 163, 184, 0.15); color: var(--text-muted); }

    /* Antigüedad de la última posición GPS: reusa el mismo lenguaje visual que la
       documentación de choferes (verde al día / ámbar por vencer / rojo vencido). */
    .badge-gps-ok { background-color: var(--bg-titular); color: var(--color-titular); }
    .badge-gps-atrasado { background-color: var(--bg-backup); color: var(--color-backup); }
    .badge-gps-viejo { background-color: var(--bg-licencia); color: var(--color-licencia); }
    .badge-gps-sinsenal { background: rgba(148, 163, 184, 0.15); color: var(--text-muted); }

    /* Barra lateral en la fila, para que el camión sin reportar salte a la vista
       incluso sin leer la insignia. */
    tr.gps-fila.gps-frescura-atrasado td:first-child { box-shadow: inset 3px 0 0 var(--color-backup); }
    tr.gps-fila.gps-frescura-viejo td:first-child { box-shadow: inset 3px 0 0 var(--color-licencia); }
    tr.gps-fila.gps-frescura-viejo { opacity: 0.82; }

    .badge-product { font-weight: 700; text-transform: uppercase; padding: 2px 6px; border-radius: 4px; font-size: 0.65rem; }
    .prod-potable { background-color: var(--bg-prod-potable); color: #ffffff; }
    .prod-vacuum { background-color: var(--bg-prod-vacuum); color: #ffffff; }
    .prod-crudo { background-color: var(--bg-prod-crudo); color: var(--text-prod-crudo); }
    .prod-industrial { background-color: var(--bg-prod-industrial); color: #ffffff; }

    .badge-titular { background-color: var(--bg-titular); color: var(--color-titular); }
    .badge-backup { background-color: var(--bg-backup); color: var(--color-backup); }
    .badge-activo { background-color: var(--bg-titular); color: var(--color-titular); }
    .badge-descanso { background-color: var(--bg-descanso); color: var(--color-descanso); }
    .badge-licencia { background-color: var(--bg-licencia); color: var(--color-licencia); }
    .badge-sin-chofer { background-color: var(--bg-licencia); color: var(--color-licencia); }

    .form-group { margin-bottom: 10px; }
    .form-group label { display: block; margin-bottom: 3px; text-transform: uppercase; letter-spacing: .04em; }
    .form-group input, .form-group select { width: 100%; padding: 8px; border: 1px solid var(--border-color); border-radius: 5px; font-size: 0.8rem; background-color: var(--input-bg); color: var(--text-main); outline: none; }
    .form-group input:disabled, .form-group select:disabled { background-color: var(--border-color); color: var(--text-muted); cursor: not-allowed; }

    .btn-submit { width: 100%; height: 34px; font-weight: 700; font-size: 0.78rem; }
    .row-clickable { cursor: pointer; }


    /* ==========================================================
       AVISOS
       Reemplazan a alert(): el nativo congela la pestana entera y se
       dibuja con el estilo del sistema operativo, no con el de la app.
       Este no bloquea, se apila y se va solo.
       ========================================================== */
    #avisos {
      position: fixed; right: 14px; bottom: 14px; z-index: 9999;
      display: flex; flex-direction: column; gap: 6px;
      max-width: min(380px, calc(100vw - 28px));
      pointer-events: none;
    }
    .aviso {
      pointer-events: auto;
      background: var(--card-bg);
      color: var(--text-main);
      border: 1px solid var(--border-color);
      border-left: 3px solid var(--primary-color);
      border-radius: 5px;
      padding: 9px 11px;
      font-size: 0.76rem;
      line-height: 1.5;
      box-shadow: 0 6px 18px rgba(0,0,0,.28);
      cursor: pointer;
      max-height: 42vh;
      overflow-y: auto;
      white-space: pre-wrap;
      opacity: 0;
      transform: translateY(6px);
      transition: opacity .14s ease, transform .14s ease;
    }
    .aviso.visible { opacity: 1; transform: none; }
    .aviso.saliendo { opacity: 0; transform: translateY(6px); }
    /* ---- Foto del conductor (ficha) ---- */
    .foto-chofer {
      display: flex;
      align-items: flex-start;
      gap: 12px;
      margin-bottom: 12px;
    }
    .foto-chofer-marco {
      width: 90px;
      height: 120px;
      flex-shrink: 0;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      background-color: var(--input-bg);
      overflow: hidden;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .foto-chofer-marco img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }
    #ch-foto-vacia {
      font-size: 0.68rem;
      color: var(--text-muted);
    }
    .foto-chofer-acciones {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 6px;
    }
    .foto-chofer-acciones .btn-submit { width: auto; padding: 6px 12px; font-size: 0.75rem; }
    .foto-chofer-elegir { cursor: pointer; }
    .foto-chofer-acciones .nota { margin: 0; }

    .aviso-error { border-left-color: var(--danger-color); }
    .aviso-ok    { border-left-color: var(--success-color); }
    /* Ni error ni exito: la disponibilidad se genero, pero dejando camiones afuera. */
    .aviso-alerta { border-left-color: var(--warning-color); }
    .aviso small { display: block; margin-top: 5px; color: var(--text-muted); font-size: 0.66rem; }

    @media (prefers-reduced-motion: reduce) {
      .aviso { transition: none; transform: none; }
    }

    /* ==========================================================
       NOTAS DE AYUDA
       Eran 23 parrafos con el mismo estilo repetido inline en cuatro
       tamanos distintos. Se leen como ayuda, no como contenido: filete
       lateral y fondo apenas distinto del panel.
       ========================================================== */
    .nota {
      font-size: 0.7rem;
      line-height: 1.55;
      color: var(--text-muted);
      background: var(--zebra);
      border-left: 2px solid var(--border-color);
      border-radius: 0 4px 4px 0;
      padding: 6px 9px;
      margin: 0 0 10px;
      max-width: 92ch;
    }
    .nota strong, .nota b { color: var(--text-main); font-weight: 600; }
    .nota em { font-style: normal; color: var(--text-main); }

    .footer-note { text-align: center; font-size: 0.7rem; color: var(--text-muted); margin-top: 15px; padding: 8px; }

    /* ============ ALERTAS ACCORDION ============ */
    .alerta-transportista {
      border: 1px solid var(--border-color);
      border-radius: 4px;
      margin-bottom: 6px;
      background: var(--card-bg);
      overflow: hidden;
    }

    .alerta-header {
      padding: 8px;
      cursor: pointer;
      display: flex;
      justify-content: space-between;
      align-items: center;
      background: var(--card-bg);
      border-bottom: 1px solid var(--border-color);
      transition: background-color 0.2s ease;
    }

    .alerta-header:hover {
      background-color: rgba(59, 130, 246, 0.08);
    }

    .alerta-header-titulo {
      font-weight: 600;
      font-size: 0.8rem;
      color: var(--text-main);
      flex: 1;
    }

    .alerta-header-count {
      background-color: var(--danger-color);
      color: white;
      padding: 2px 6px;
      border-radius: 10px;
      font-size: 0.7rem;
      font-weight: 700;
      margin-right: 6px;
    }

    .alerta-toggle {
      font-size: 1rem;
      transition: transform 0.2s ease;
    }

    .alerta-toggle.abierto {
      transform: rotate(180deg);
    }

    .alerta-contenido {
      max-height: 0;
      overflow: hidden;
      transition: max-height 0.3s ease;
    }

    .alerta-contenido.abierto {
      max-height: 800px;
      overflow-y: auto;
    }

    .alerta-item {
      padding: 3px 8px;
      border-left: 2px solid var(--warning-color);
      background: rgba(245, 158, 11, 0.04);
      margin: 4px 8px;
      border-radius: 3px;
      font-size: 0.7rem;
    }

    .alerta-item.vencido {
      border-left-color: var(--danger-color);
      background: rgba(239, 68, 68, 0.04);
    }

    .alerta-item.pronto {
      border-left-color: var(--warning-color);
      background: rgba(245, 158, 11, 0.04);
    }

    /* ============ RESPONSIVE MÓVIL / TABLET ============ */
    @media (max-width: 768px) {
      body { padding: 8px; }
      header { padding: 12px 14px; }
      header h1 { font-size: 1.15rem; }
      header p { font-size: 0.75rem; }
      .tab-button { padding: 8px 10px; font-size: 0.72rem; }

      .layout-con-sidebar { flex-direction: column; }
      .sidebar-toggle { display: none; }
      .tab-container.colapsado { width: 100%; }
      .tab-container.colapsado .tab-label { display: inline; }
      .tab-container {
        flex-direction: row;
        flex-wrap: nowrap;
        width: 100%;
        overflow-x: auto;
        border-right: none;
        border-bottom: 2px solid var(--border-color);
        padding-right: 0;
        padding-bottom: 8px;
        margin-bottom: 12px;
        position: static;
        max-height: none;
        padding-bottom: 8px;
      }
      .sector-activo { margin: 0; }
      /* En movil el rail es una tira horizontal que ya scrollea sola: el bloque
         viaja al final de la tira en vez de quedar fijo sobre el contenido. */
      .gps-status {
        position: static;
        width: auto;
        flex-shrink: 0;
        align-self: center;
      }
      .tab-button { flex-shrink: 0; border-left: none; border-bottom: 3px solid transparent; white-space: nowrap; }
      .tab-button.active { border-left: none; border-bottom: 3px solid var(--primary-color); }

      .table-responsive { border: none; background: transparent; overflow-x: visible; }
      table, thead, tbody, th, td, tr { display: block; }
      table thead { display: none; }
      table tr { 
        margin-bottom: 10px; 
        border: 1px solid var(--border-color); 
        border-radius: 8px; 
        padding: 4px 0; 
        background-color: var(--table-bg);
      }
      table td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        text-align: right;
        white-space: normal;
        border-bottom: 1px dashed var(--border-color);
        gap: 8px;
      }
      table td:last-child { border-bottom: none; }
      table td::before {
        content: attr(data-label);
        font-weight: 700;
        color: var(--text-muted);
        text-align: left;
        text-transform: uppercase;
        font-size: 0.65rem;
        flex-shrink: 0;
      }
      .tr-group-header td { display: block; text-align: left; }
      .tr-group-header td::before { content: none; }
      .sin-resultados td { display: block; text-align: center; }
      .sin-resultados td::before { content: none; }

      .table-toolbar { flex-direction: column; }
      .table-toolbar input[type="text"] { width: 100%; }
    }

    .config-warning {
      background: var(--bg-licencia);
      color: var(--color-licencia);
      border: 1px solid var(--color-licencia);
      border-radius: 6px;
      padding: 10px 12px;
      font-size: 0.75rem;
      margin-bottom: 12px;
      line-height: 1.5;
      max-width: 600px;
      margin-left: auto;
      margin-right: auto;
    }
    .config-warning code { background: rgba(0,0,0,0.15); padding: 1px 5px; border-radius: 3px; }

    /* ==========================================================
       CONTROL DE DIAS DE TRABAJO (CAMBIOS DE ROL)
       La agenda es una tabla sola con filas de encabezado por dia:
       una tabla por dia dejaba siete cabeceras repetidas y rompia
       la alineacion de las columnas entre un dia y otro.
       ========================================================== */
    #vista-cambios-rol .dim,
    #dash-cambios-rol .dim { color: var(--text-muted); }

    .rol-toolbar { align-items: center; }
    .rol-semana-rotulo {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 210px;
      font-size: 0.82rem;
      color: var(--text-main);
    }
    .rol-etiqueta-campo {
      font-size: 0.72rem;
      text-transform: uppercase;
      letter-spacing: 0.4px;
      color: var(--text-muted);
    }

    /* Fila que separa un dia del siguiente. Va pegada a la tabla y no como
       titulo suelto para que el scroll horizontal la arrastre con las filas. */
    .rol-dia-cab td {
      background-color: var(--zebra);
      border-top: 1px solid var(--border-color);
      font-size: 0.74rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      color: var(--text-muted);
      padding: 6px 10px;
    }
    .rol-dia-cab.rol-dia-hoy td {
      color: var(--primary-color);
      box-shadow: inset 3px 0 0 var(--primary-color);
    }
    .rol-dia-cab.rol-dia-atraso td {
      color: var(--color-licencia);
      background-color: var(--bg-licencia);
      box-shadow: inset 3px 0 0 var(--color-licencia);
    }
    .rol-dia-cab.rol-dia-viejo td {
      box-shadow: inset 3px 0 0 var(--text-muted);
    }

    /* Marca de bajada cargada a mano: no compite con los badges de estado. */
    .rol-ajustada { color: var(--color-backup); cursor: help; }

    .rol-btn-registrar { padding: 3px 10px; font-size: 0.72rem; }
    .rol-btn-borrar { padding: 3px 8px; font-size: 0.78rem; }

    /* ---- Modal de registro ---- */
    .rol-ficha-cambio {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 8px 14px;
      padding: 10px 12px;
      margin-bottom: 12px;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      background-color: var(--table-bg);
      font-size: 0.82rem;
    }
    .rol-ficha-cambio > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
    .rol-ficha-rotulo {
      font-size: 0.66rem;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      color: var(--text-muted);
    }
    /* El recuento de dias se recalcula al mover la fecha: es el dato que queda
       en el historial y conviene verlo antes de confirmar, no despues. */
    .rol-resumen {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 6px;
      margin: 10px 0 4px;
      min-height: 22px;
      font-size: 0.78rem;
    }

    /* ---- Aviso del dashboard ---- */
    .rol-aviso-resumen { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
    .rol-aviso-lista { list-style: none; margin: 0; padding: 0; }
    .rol-aviso-lista li {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 6px;
      padding: 5px 0;
      border-top: 1px solid var(--line-soft);
      font-size: 0.8rem;
    }
    .rol-aviso-lista li:first-child { border-top: none; }
    .rol-aviso-fecha {
      flex: 0 0 92px;
      font-variant-numeric: tabular-nums;
      font-weight: 700;
      color: var(--text-muted);
    }

    @media (max-width: 620px) {
      .rol-semana-rotulo { min-width: 0; }
      .rol-ficha-cambio { grid-template-columns: 1fr; }
      .rol-aviso-fecha { flex-basis: auto; }
    }
