/* =========================================================================
   HD Cargo · sistema de diseño del backoffice
   =========================================================================
   Los tokens vienen del UI kit de Forza Labs. Este archivo es la TRADUCCIÓN de
   ese sistema a lo que el backoffice necesita, no una copia: el kit es para web
   pública y acá se muestran tablas densas de operación.

   Una sola hoja para todas las pantallas. Cambiarla las restyliza a todas.
   Lo específico de cada página sigue en su propio <style>.
   ========================================================================= */

:root{
  /* --- Paleta de marca, tal cual el UI kit ------------------------------- */
  --teal:#00BAC6;        --teal-mid:#00A5B0;    --teal-deep:#00838C;
  --teal-dark:#00565C;   --teal-pale:#E3F7F8;   --teal-2:#BFE9EC;
  --navy-black:#0D1520;  --navy:#233043;        --navy-pale:#EEF1F5;
  --blue-4:#22598C;      --blue-1:#BFDCF2;
  --pink:#E10098;        --pink-deep:#AB0074;   --pink-pale:#FCE6F3;
  --cool-gray-2:#D0D0CE; --cool-gray-4:#BBBCBC; --cool-gray-9:#75787B;
  --cool-gray-11:#53565A;
  --gray-light:#E6E6E6;  --surface-subtle:#F5F6F7;  --white:#FFFFFF;
  --functional-orange:#ED8B00; --functional-red:#DA291C; --functional-yellow:#FFCD00;

  /* --- Roles ------------------------------------------------------------
     El kit pinta la página en blanco (`--surface-page: white`). Acá el fondo es
     el gris sutil y las tarjetas blancas: en una pantalla llena de tablas hace
     falta que la tarjeta se despegue del fondo para poder recorrerla. */
  --bg:var(--surface-subtle); --surface:var(--white);
  --surface-2:var(--navy-pale); --surface-3:var(--gray-light);

  --ink:var(--navy-black);      /* texto principal */
  --ink-2:var(--cool-gray-11);  /* secundario */
  /* Apagado. Era cool-gray-9 (#75787B): 4.4:1 sobre blanco y 3.9:1 sobre el gris de
     las columnas, debajo de WCAG AA. Un punto más oscuro de la misma familia pasa en
     las tres superficies (5.4 / 4.7 / 5.0) sin cambiar el carácter. */
  --ink-3:#686B6F;

  --line:var(--gray-light);     /* borde sutil, el de las tablas */
  --line-2:var(--cool-gray-4);  /* borde marcado */
  /* Contorno de un CONTROL (campo, select, chip de filtro): WCAG 1.4.11 pide 3:1 contra
     el fondo. --line-2 da 1.9:1, bien para separar, no para decir "aquí se escribe". */
  --line-ctl:#8A939C;

  --accent:var(--teal-deep); --accent-ink:var(--teal-dark);
  --accent-soft:var(--teal-pale); --on-accent:var(--white);

  /* Lo que escribe el OPERADOR a mano se muestra en rosa de marca, y no en un
     tono del acento: tiene que leerse como "esto es de otra fuente y no se usa
     para calcular". El acento ya significa "acción del sistema". */
  --oper:var(--pink); --oper-ink:var(--pink-deep); --oper-soft:var(--pink-pale);

  /* --- Estados ----------------------------------------------------------
     El kit define success = teal, o sea el MISMO color del acento. En una web
     eso funciona; en una tabla con una columna de estado, no: los botones y los
     "ok" quedarían del mismo color y se pierde el barrido vertical.
     Se resuelve por TRATAMIENTO, no cambiando el color: el acento se usa lleno
     (botones) y el éxito en versión suave (chips). Mismo color de marca, dos
     pesos visuales distintos. */
  --ok:var(--teal-deep);        --ok-soft:var(--teal-pale);
  --warn:var(--functional-orange); --warn-soft:#FDF0DC;
  --err:var(--functional-red);  --err-soft:#FBE7E5;
  /* Texto sobre los fondos pálidos de estado: el rojo y el teal de marca bajan de 4.5:1
     sobre su propio pálido. Estos son el mismo tono, más hondo. */
  --err-ink:#B42318; --warn-ink:#8A5100; --ok-ink:var(--teal-dark);
  --info:var(--blue-4);         --info-soft:var(--blue-1);

  /* SIN DATOS: el cuarto estado, el que el kit no trae y este producto necesita.
     "Todavía no se pudo verificar" NO puede verse como "está bien": si se
     confunden, alguien cree que un envío está revisado cuando nadie lo miró.
     Va en gris neutro a propósito: es ausencia de información, no un veredicto. */
  --gutter:clamp(22px,2.2vw,56px);
  --nodata:#686B6F;  --nodata-soft:var(--cool-gray-2);

  /* --- Escala tipográfica -------------------------------------------------
     Texto operativo a 14, metadatos nunca debajo de 12. Antes convivían 9.5, 10, 10.5,
     11, 11.5 y 12.5 en la misma pantalla y los folios se leían con esfuerzo. */
  --fs-xs:12px; --fs-sm:13px; --fs-md:14px; --fs-lg:16px; --fs-xl:20px; --fs-2xl:24px;

  /* --- Superficie oscura ------------------------------------------------
     El kit la define aparte (`--surface-inverse`, `--text-on-dark`), y los teales
     brillantes están pensados justamente para eso: sobre claro se lavan, sobre
     oscuro son la marca. Se usa en la portada, donde la plataforma se presenta.
     Las pantallas de trabajo siguen claras: son tablas densas que se leen durante
     horas, y ahí el fondo oscuro cansa. */
  --dark:var(--navy-black); --dark-2:var(--navy); --dark-3:#16222F;
  --on-dark:var(--white); --on-dark-muted:var(--cool-gray-4);
  --accent-on-dark:var(--teal); --accent-bright:#3DF2E2;
  --line-on-dark:rgba(255,255,255,.14);

  /* --- Tipografía -------------------------------------------------------
     Aptos es la del kit; Open Sans es el respaldo que sí se puede cargar de
     Google Fonts, así que se ve igual en una máquina sin Aptos.
     La serif es la de énfasis del kit: se usa SOLO en el título de portada. */
  --font:"Aptos","Open Sans","Segoe UI",system-ui,sans-serif;
  --font-mono:"Aptos Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --font-serif:"STIX Two Text",Georgia,"Times New Roman",serif;

  /* --- Forma ------------------------------------------------------------
     El kit es CUADRADO: radios de 2 y 4 px. Se respeta, aunque las tarjetas
     queden menos redondeadas que antes: es la señal más visible de la marca. */
  --radius-sm:2px; --radius-md:4px; --radius-pill:999px;
  --shadow:0 1px 2px rgba(13,21,32,.08);
  --shadow-2:0 2px 8px rgba(13,21,32,.10);

  /* --- Alias de compatibilidad ---
     /programaciones, /envios y /envio se escribieron con su propio juego de
     nombres sobre un tema oscuro. Mapearlos hace que TODO su CSS existente tome
     la paleta nueva sin tocar sus cientos de líneas, que es donde estaría el
     riesgo de romper algo. Al reescribir esas páginas se pueden borrar. */
  --bg-elev:var(--surface); --bg-card:var(--surface); --bg-input:var(--surface-2);
  --border:var(--line); --text:var(--ink); --muted:var(--ink-3);
  --blue:var(--info); --yellow:var(--warn); --red:var(--err);
}

*{box-sizing:border-box;margin:0;padding:0}
/* La página ocupa la ventana entera y el contenido crece para llenarla: antes
   quedaba una franja de fondo vacía debajo en pantallas altas. */
body{
  background:var(--bg); color:var(--ink);
  font-family:var(--font); font-size:15px; line-height:1.45;
  -webkit-font-smoothing:antialiased;
  min-height:100vh; display:flex; flex-direction:column;
}
main{flex:1;display:flex;flex-direction:column}
.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
/* Etiquetas de sección: mayúsculas espaciadas, como el kit */
.lbl{font-family:var(--font);font-weight:700;font-size:var(--fs-xs);
     letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3)}

/* Foco visible en todo lo que se opera con teclado. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.top :focus-visible{outline-color:var(--accent-on-dark)}

/* Iconos de trazo (iconos.js): una familia, del tamaño del texto que acompañan. */
.ico{width:1.15em;height:1.15em;flex:none;vertical-align:-.2em}
[data-ico]{display:inline-flex;align-items:center}

/* --- Estado ----------------------------------------------------------------
   UNA forma de decir cómo va algo, en todas las pantallas. Siempre icono + texto:
   el color refuerza, nunca es la única señal.
     crit  problema que hay que atender (estancado)
     warn  advertencia (falta confirmar algo)
     pend  pendiente normal (espera al cliente, empaque)
     info  en camino (en tránsito, en ruta)
     ok    terminado (entregada)
   El turquesa de marca queda para selección y acciones, no para estados. */
.estado{display:inline-flex;align-items:flex-start;gap:6px;font-size:var(--fs-sm);font-weight:600;
  line-height:1.35;border-radius:var(--radius-sm);padding:3px 8px;max-width:100%}
.estado .ico{margin-top:1px}
.estado.crit{background:var(--err-soft);color:var(--err-ink)}
.estado.warn{background:var(--warn-soft);color:var(--warn-ink)}
.estado.pend{background:var(--surface-2);color:var(--ink-2)}
.estado.info{background:#EAF2FA;color:var(--info)}
.estado.ok{background:var(--ok-soft);color:var(--ok-ink)}
.estado.liso{background:none;padding:0}
/* Sin tope de ancho: es una herramienta de operación, con tablas de muchas
   columnas. Un contenedor centrado dejaba franjas vacías a los costados en
   cualquier monitor grande, justo donde hacía falta ver más columnas.

   Pero "todo el ancho" no es "pegado al borde": el margen lateral crece con la
   pantalla (de 22px en una laptop chica a 56px en un monitor grande) para que
   el logo, la tabla y el pie no queden lamiendo la orilla. Es UNA sola variable
   porque la barra, el contenido y el pie tienen que alinearse entre sí. */
.wrap{width:100%;margin:0;padding-left:var(--gutter);padding-right:var(--gutter)}

/* --- Encabezado y navegación --------------------------------------------
   La barra va OSCURA en todas las pantallas, igual que la portada. Es lo que
   sostiene la sensación de una sola herramienta: entrás a un módulo y el marco
   sigue siendo el mismo, solo cambia el contenido de abajo.
   El contenido de trabajo queda claro: son tablas que se leen durante horas. */
header.top{background:var(--dark);border-bottom:1px solid var(--line-on-dark)}
/* La barra es IDÉNTICA en todas las pantallas: mismo logo, mismo "Trazo /
   HD Cargo", mismo menú, misma esquina derecha. Antes el título cambiaba por
   página y la esquina derecha solo existía en la portada, así que el menú se
   corría de lugar al entrar a un módulo — y un menú que se mueve deja de
   funcionar como menú. Qué módulo estás viendo lo dice la pestaña activa, y el
   nombre de la página vive abajo, en su propio encabezado. */
.top-in{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
        padding-top:13px;padding-bottom:13px}
.ident{min-width:0}
.quien{margin-left:18px;display:flex;align-items:center;gap:11px;text-align:right;flex:none}
/* Ancho fijo para el nombre: si cambia (otra persona, o la fuente que llega después
   del primer pintado), el menú de al lado no se mueve (2026-11-06). */
.quien > div:first-child{width:150px}
.quien .n,.quien .r{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.quien .n{font-size:13px;font-weight:700;line-height:1.25;color:var(--on-dark)}
.quien .r{font-size:11.5px;color:var(--on-dark-muted)}
.quien .av{width:34px;height:34px;border-radius:var(--radius-pill);
  background:var(--accent-on-dark);color:var(--dark);display:grid;place-items:center;
  font-weight:700;font-size:13px;flex:none}
/* En pantallas angostas el nombre del usuario sobra antes que el menú. */
@media(max-width:1120px){.quien > div:first-child{display:none}}
/* El menú de la persona (lo arma sesion.js): perfil, usuarios si es admin, salir. */
.quien.con-menu{position:relative;cursor:pointer;border-radius:var(--radius-md);
  padding:4px 6px;margin-right:-6px}
.quien.con-menu:hover,.quien.con-menu:focus-visible{background:rgba(255,255,255,.07);outline:none}
.quien-menu{position:absolute;right:0;top:calc(100% + 8px);min-width:230px;z-index:60;
  background:var(--surface);color:var(--ink);border:1px solid var(--line);
  border-radius:var(--radius-md);box-shadow:var(--shadow-2);text-align:left;
  display:grid;padding:6px 0;cursor:default}
.quien-menu[hidden]{display:none}
.quien-cab{display:grid;gap:1px;padding:8px 14px 10px;border-bottom:1px solid var(--line);
  margin-bottom:4px}
.quien-cab b{font-size:13.5px}
.quien-cab span{font-size:12px;color:var(--ink-3);overflow-wrap:anywhere}
.quien-menu a,.quien-menu button{display:block;width:100%;text-align:left;font:inherit;
  font-size:13.5px;padding:8px 14px;color:var(--ink);text-decoration:none;
  background:none;border:none;cursor:pointer}
.quien-menu a:hover,.quien-menu button:hover{background:var(--surface-2)}
.quien-menu form{border-top:1px solid var(--line);margin-top:4px;padding-top:4px}
.quien-nota{font-size:12px;color:var(--ink-3);padding:8px 14px 4px;line-height:1.4;max-width:260px}

/* Formularios de cuenta (/perfil, /usuarios). */
.campo{display:grid;gap:6px;font-size:12px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3)}
.campo input,.campo select{font:inherit;font-size:14px;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--ink);padding:9px 11px;border:1px solid var(--line-ctl);
  border-radius:var(--radius-sm);background:var(--surface);min-width:0}
.campo input:focus,.campo select:focus{outline:none;border-color:var(--accent)}
.aviso{font-size:13px;padding:10px 13px;border-radius:var(--radius-sm);line-height:1.45}
.aviso.ok{background:var(--ok-soft);color:var(--accent-ink)}
.aviso.err{background:var(--err-soft);color:var(--err)}
.aviso.warn{background:var(--warn-soft);color:#8A5100}
.aviso[hidden]{display:none}
.mark{width:32px;height:32px;border-radius:var(--radius-md);background:var(--accent-on-dark);
      color:var(--dark);display:grid;place-items:center;font-weight:700;
      font-size:14px;flex:none;text-decoration:none}
.top h1{font-size:16px;font-weight:700;letter-spacing:-.01em;line-height:1.2;
        color:var(--on-dark)}
.top .sub{font-size:12px;color:var(--on-dark-muted)}
/* La marca: "trazo" en minúsculas, serif itálica, con la z cursiva dibujada
   (trazo-z.svg) en teal. La z es una máscara, así que toma el color del texto
   que se le ponga y no depende de que la fuente tenga esa forma. TFL-95. */
.trazo{font-family:var(--font-serif);font-style:italic;font-weight:400;
       letter-spacing:0;white-space:nowrap}
.top h1.trazo{font-size:22px;font-weight:400;line-height:1}
.trazo .z{display:inline-block;width:.87em;height:1.45em;vertical-align:-.5em;
          margin:0 -.16em 0 -.07em;background:var(--accent-on-dark);
          -webkit-mask:url(/static/trazo-z.svg) no-repeat center/contain;
          mask:url(/static/trazo-z.svg) no-repeat center/contain}
.nav{margin-left:auto;display:flex;gap:2px;flex-wrap:wrap}
/* Invisible hasta saber qué opciones van (sesion.js pone .menu-listo): así no se ven
   un instante Envíos, Panel o Admin que después desaparecen. Ocupa su lugar igual. */
/* El espacio de la barra de scroll queda siempre reservado: en un Mac con mouse la
   barra ocupa 15 px, y aparecía cuando llegaba el contenido (Inicio, Grupo, Panel),
   corriendo la barra de arriba y el menú al cambiar de página (2026-11-06). */
html{scrollbar-gutter:stable}
header.top .nav{visibility:hidden}
header.top.menu-listo .nav{visibility:visible}
header.top .nav [hidden]{display:none}
.nav a{font-size:13px;font-weight:600;color:var(--on-dark-muted);text-decoration:none;
       padding:9px 13px;border-radius:var(--radius-sm)}
.nav a:hover{color:var(--on-dark);background:rgba(255,255,255,.06)}
/* La pestaña activa se marca con una línea inferior en el teal brillante, como el
   kit: deja el fondo del acento libre para las acciones. */
.nav a.on{color:var(--accent-on-dark);box-shadow:inset 0 -2px 0 var(--accent-on-dark)}

/* El buscador vive DENTRO de la barra oscura. Sin esto queda una caja blanca
   flotando ahí, que rompe la continuidad justo en el elemento que la sostiene.
   (Las páginas lo declaran en su propio <style>; acá se le corrige el contexto.) */
.top .search{background:rgba(255,255,255,.07);border:1px solid var(--line-on-dark);
             border-radius:var(--radius-sm);color:var(--on-dark-muted)}
.top .search input{color:var(--on-dark)}
.top .search input::placeholder{color:var(--on-dark-muted)}

main{padding-top:22px;padding-bottom:40px}

/* --- Componentes base --------------------------------------------------- */
.chip{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;
      border-radius:var(--radius-pill);font-size:var(--fs-xs);font-weight:700;
      white-space:nowrap;letter-spacing:.01em}
.chip.a{background:var(--accent-soft);color:var(--accent-ink)}
.chip.ok{background:var(--ok-soft);color:var(--ok-ink)}
.chip.warn{background:var(--warn-soft);color:#8A5100}     /* naranja legible sobre claro */
.chip.err{background:var(--err-soft);color:var(--err-ink)}
.chip.mut{background:var(--surface-3);color:var(--ink-2)}

.panel{background:var(--surface);border:1px solid var(--line);
       border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow)}
.panel-h{padding:14px 17px;border-bottom:1px solid var(--line);display:flex;gap:12px;
         align-items:center;flex-wrap:wrap}
.panel-h h3{font-size:16px;font-weight:700;letter-spacing:-.01em;margin-right:auto}
.panel-h .sub{font-size:12.5px;color:var(--ink-3);width:100%}

.tblwrap{overflow:auto}
table.tbl{border-collapse:collapse;width:100%}
/* La cabecera queda fija al hacer scroll: con la tabla ocupando toda la ventana
   se ven muchas más filas, y sin esto uno pierde de vista qué columna es cuál. */
table.tbl th{text-align:left;padding:10px 14px;border-bottom:1px solid var(--line-2);
             font-weight:700;font-size:var(--fs-xs);letter-spacing:.04em;
             text-transform:uppercase;color:var(--ink-3);white-space:nowrap;
             position:sticky;top:0;background:var(--surface);z-index:1}
table.tbl td{padding:10px 14px;border-bottom:1px solid var(--line);font-size:var(--fs-md)}
table.tbl tr:last-child td{border-bottom:none}
table.tbl tbody tr{cursor:pointer}
table.tbl tbody tr:hover{background:var(--surface-2)}
tr.bad td{background:var(--warn-soft)}

/* Tres pesos de acción: .btn (la principal, una por pantalla), .btn.ghost (secundaria)
   y .btn.texto (terciaria). .btn.icono es una acción que solo lleva icono y SIEMPRE
   lleva aria-label. */
.btn{font:inherit;font-weight:700;font-size:var(--fs-md);padding:8px 15px;min-height:38px;
     border-radius:var(--radius-md);border:1px solid var(--accent);
     background:var(--accent);color:var(--on-accent);cursor:pointer;
     transition:background .15s;display:inline-flex;align-items:center;justify-content:center;gap:7px}
.btn:hover{background:var(--navy);border-color:var(--navy)}   /* hover del kit */
.btn.ghost{background:none;color:var(--accent-ink);border-color:var(--accent)}
.btn.ghost:hover{background:var(--accent-soft);border-color:var(--accent)}
.btn.texto{background:none;border-color:transparent;color:var(--accent-ink);padding-left:10px;padding-right:10px}
.btn.texto:hover{background:var(--accent-soft);border-color:transparent}
.btn.icono{background:none;border-color:var(--line-ctl);color:var(--ink-2);padding:0;width:38px}
.btn.icono:hover{background:var(--surface-2);border-color:var(--accent);color:var(--accent-ink)}
@media (max-width:720px),(pointer:coarse){
  .btn{min-height:44px}
  .btn.icono{width:44px}
}
.btn:disabled{background:var(--gray-light);border-color:var(--gray-light);
              color:var(--ink-3);cursor:default}
/* Un botón que en realidad navega. Vive acá y no en la página porque el kit no
   traía la variante <a>: sin esto el link sale subrayado y desalineado. */
a.btn{display:inline-flex;align-items:center;text-decoration:none}

.card{background:var(--surface);border:1px solid var(--line);
      border-radius:var(--radius-md);padding:16px;box-shadow:var(--shadow)}
.kv{display:flex;justify-content:space-between;gap:13px;padding:7px 0;
    border-bottom:1px solid var(--line)}
.kv:last-child{border-bottom:none}
.kv dt{font-size:12.5px;color:var(--ink-3);flex:none}
.kv dd{font-size:13px;font-weight:600;text-align:right;overflow-wrap:anywhere}

/* Avisos: barra de color a la izquierda en vez de fondo pleno, para que no
   compitan con los chips de estado de las tablas. */
.note{display:flex;gap:9px;align-items:flex-start;border-radius:var(--radius-md);
      padding:11px 12px;font-size:12.5px;line-height:1.45;margin-bottom:10px;
      border-left:3px solid currentColor}
.note.w{background:var(--warn-soft);color:#8A5100}
.note.a{background:var(--accent-soft);color:var(--accent-ink)}
.note.o{background:var(--ok-soft);color:var(--ok)}
.note.e{background:var(--err-soft);color:var(--err)}

.back{background:none;border:none;font:inherit;color:var(--accent-ink);font-weight:700;
      cursor:pointer;font-size:13px;padding:0;margin-bottom:12px}
.muted{color:var(--ink-3);font-size:13px;padding:26px 17px;text-align:center}
.stack{display:grid;gap:16px}
h2.title{font-size:26px;font-weight:700;letter-spacing:-.02em;margin-bottom:3px}
.sub2{color:var(--ink-3);font-size:13px;margin-bottom:16px}

/* =========================================================================
   HeiDi flotante · el asistente encima de cualquier pantalla
   =========================================================================
   Va superpuesto abajo a la derecha en vez de ser una página aparte, porque las
   preguntas nacen junto al dato: "¿y esta guía?", "¿por qué esta hoja tiene
   hallazgos?". Salir de la pantalla para preguntar rompe justamente eso.
   ========================================================================= */
/* z 75: encima de la carta abierta del tablero (70), para preguntar sin cerrarla;
   debajo de las confirmaciones (80), que siempre mandan. */
.heidi-fab-raiz{position:fixed;right:var(--gutter);bottom:24px;z-index:75;
  display:flex;flex-direction:column;align-items:flex-end;gap:12px}

.heidi-fab{display:flex;align-items:center;gap:11px;background:none;border:none;
  padding:0;cursor:pointer;font:inherit}
/* La pista al lado del botón: dice para qué sirve sin obligar a abrirlo. */
.heidi-pista{background:var(--dark);color:var(--on-dark);font-size:12.5px;font-weight:600;
  padding:8px 13px;border-radius:var(--radius-sm);border:1px solid var(--line-on-dark);
  white-space:nowrap;box-shadow:var(--shadow-2)}
.heidi-ico{width:52px;height:52px;flex:none;border-radius:var(--radius-pill);
  background:var(--accent-on-dark);color:var(--dark);display:grid;place-items:center;
  font-size:22px;box-shadow:0 4px 16px rgba(0,186,198,.32);transition:background .15s}
.heidi-fab:hover .heidi-ico{background:var(--accent-bright)}
/* Con el panel abierto la pista sobra y el botón pasa a ser el cierre. */
.heidi-fab-raiz.abierto .heidi-pista{display:none}

/* `display:flex` gana sobre el atributo `hidden` del navegador, asi que sin esta
   regla el panel arranca ABIERTO en todas las pantallas. */
.heidi-panel[hidden]{display:none}
.heidi-panel{width:380px;max-width:calc(100vw - 44px);height:520px;
  max-height:calc(100vh - 130px);display:flex;flex-direction:column;
  background:var(--surface);border:1px solid var(--line-2);
  border-radius:var(--radius-md);box-shadow:0 12px 40px rgba(13,21,32,.22);overflow:hidden}

/* La cabecera va oscura: es el mismo marco que la barra de arriba, así el
   asistente se lee como parte de la herramienta y no como un chat pegado. */
.heidi-cab{display:flex;align-items:center;gap:10px;padding:12px 14px;
  background:var(--dark);color:var(--on-dark);flex:none}
.heidi-av{width:30px;height:30px;flex:none;border-radius:var(--radius-sm);
  background:var(--accent-on-dark);color:var(--dark);display:grid;place-items:center;
  font-weight:700;font-size:12px}
.heidi-tit{font-size:14px;font-weight:700;line-height:1.2;margin-right:auto}
.heidi-tit small{display:block;font-size:11px;font-weight:400;color:var(--on-dark-muted)}
.heidi-x,.heidi-max{background:none;border:none;color:var(--on-dark-muted);
  line-height:1;cursor:pointer;padding:0;text-decoration:none;min-width:36px;min-height:36px;
  display:grid;place-items:center;border-radius:var(--radius-sm)}
.heidi-x{font-size:22px}
.heidi-max{font-size:15px}
.heidi-x:hover,.heidi-max:hover{color:var(--on-dark)}

.heidi-msgs{flex:1;overflow-y:auto;padding:16px 14px;display:flex;
  flex-direction:column;gap:10px;background:var(--bg)}
.heidi-hola{font-size:13px;line-height:1.55;color:var(--ink-2)}
.heidi-hola b{display:block;font-size:15px;color:var(--ink);margin-bottom:6px}

.heidi-msg{max-width:86%;padding:9px 12px;border-radius:var(--radius-md);
  font-size:13px;line-height:1.5;white-space:normal;overflow-wrap:anywhere}
.heidi-msg.user{align-self:flex-end;background:var(--accent);color:var(--on-accent)}
.heidi-msg.assistant{align-self:flex-start;background:var(--surface);
  border:1px solid var(--line);color:var(--ink)}
.heidi-msg.pensando{color:var(--ink-3);letter-spacing:.15em}
.heidi-msg.error{border-color:var(--err);color:var(--err)}

/* El envío por el que se pregunta: visible y con su × para quitarlo. */
.heidi-ctx[hidden]{display:none}
.heidi-ctx{display:flex;align-items:center;gap:8px;padding:7px 8px 7px 12px;flex:none;
  border-top:1px solid var(--line);background:var(--accent-soft);color:var(--ink);font-size:var(--fs-sm)}
.heidi-ctx-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.heidi-ctx-t b{font-family:var(--font-mono)}
.heidi-ctx-x{flex:none;min-width:32px;min-height:32px;border:none;background:none;cursor:pointer;
  color:var(--ink-2);font-size:18px;border-radius:var(--radius-sm)}
.heidi-ctx-x:hover{background:var(--surface)}

.heidi-form{display:flex;gap:8px;padding:11px;border-top:1px solid var(--line);
  background:var(--surface);flex:none}
.heidi-in{flex:1;min-width:0;font:inherit;font-size:var(--fs-md);padding:10px 12px;
  border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--surface)}
.heidi-in:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-soft)}
.heidi-send{flex:none;width:40px;border:none;border-radius:var(--radius-sm);display:grid;place-items:center;
  background:var(--accent);color:var(--on-accent);font-size:17px;cursor:pointer}
.heidi-send:hover{background:var(--navy)}

@media(max-width:520px){
  .heidi-fab-raiz{right:14px;bottom:14px}
  /* En el teléfono la pista tapaba las cartas: queda solo el botón (con su nombre accesible). */
  .heidi-pista{display:none}
  .heidi-panel{height:min(72vh,520px);width:calc(100vw - 28px);max-width:none}
  .heidi-in{font-size:16px}   /* menos de 16px hace que iOS acerque la página al escribir */
  .heidi-send{width:44px}
}

/* Guías todavía no tiene pantalla. Se muestra igual para que la barra no mienta
   sobre el proceso, pero sin enlace y diciendo por qué: "pronto". Antes iba a medio
   tono (3:1) y parecía un enlace roto. */
.nav .pendiente{font-size:13px;font-weight:600;color:var(--on-dark-muted);
  padding:9px 13px;cursor:default;display:inline-flex;align-items:center;gap:6px}
.nav .pendiente small{font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  border:1px solid var(--line-on-dark);border-radius:var(--radius-pill);padding:0 6px;line-height:1.6}
/* Envíos va separado: no es una etapa más, es la capa transversal. La barra tiene
   que decir lo mismo que el mapa. */
.nav .sep{width:1px;align-self:stretch;margin:6px 10px;background:var(--line-on-dark)}

/* --- Barra en el teléfono -------------------------------------------------
   Misma barra en todas las páginas (test_paginas.py compara su HTML), así que lo
   compacto es solo CSS: logo y persona arriba, el menú en una franja que se desliza
   de lado, con objetivos de 44px. Antes se apilaba en tres renglones y medía 480px. */
@media (max-width:720px){
  .top-in{flex-wrap:nowrap;gap:10px;padding-top:8px;padding-bottom:0;display:grid;
    grid-template-columns:auto 1fr auto;align-items:center}
  .top-in > .ident{display:none}
  .top-in > .marca{grid-column:1}
  .top-in > .quien{grid-column:3;margin-left:0}
  .top-in > .nav{grid-column:1 / -1;grid-row:2;margin:0 calc(-1 * var(--gutter));
    padding:0 var(--gutter);flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:0}
  .top-in > .nav::-webkit-scrollbar{display:none}
  .nav a,.nav .pendiente{min-height:44px;display:inline-flex;align-items:center;white-space:nowrap;
    padding:0 12px;flex:none}
  .nav .sep{margin:12px 4px}
}

/* =========================================================================
   Estructura de una PANTALLA DE ETAPA
   =========================================================================
   Las tres etapas (programaciones, hojas de ruta, guías) son partes del mismo
   proceso, así que se miran igual aunque sus columnas difieran. Antes cada una
   resolvía sus controles por su cuenta: una arrancaba directo en la tabla, otra
   tenía filtros, otra un buscador metido en la barra oscura. El resultado era que
   parecían tres herramientas.

   El orden es siempre el mismo, de arriba abajo:

     título del módulo · qué es              [ acciones ]
     [ buscador ]  [ filtros por estado ]
     [ tabla ]

   El buscador sale de la barra oscura: la barra es NAVEGACIÓN (dónde estoy, a
   dónde puedo ir) y es idéntica en todas. Buscar es trabajo sobre ESTA pantalla,
   así que vive con el resto de los controles.
   ========================================================================= */
.pagina-h{display:flex;align-items:flex-end;justify-content:space-between;
  gap:24px;flex-wrap:wrap;margin-bottom:16px}
.pagina-h h1{font-size:26px;font-weight:700;letter-spacing:-.02em;line-height:1.15}
.pagina-h .sub{color:var(--ink-3);font-size:var(--fs-sm);margin-top:3px}
/* Las páginas de una misma sección (Admin: Usuarios y Grupo de Operaciones). */
.subnav{display:flex;gap:4px;flex-wrap:wrap;border-bottom:1px solid var(--line)}
.subnav a{font-size:var(--fs-md);font-weight:700;color:var(--ink-2);text-decoration:none;padding:8px 12px;
  border-bottom:2px solid transparent;margin-bottom:-1px}
.subnav a:hover{color:var(--ink)}
.subnav a.on{color:var(--accent-ink);border-bottom-color:var(--accent)}
.pagina-h .acciones{display:flex;gap:8px;align-items:center;flex-wrap:wrap}

.controles{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:18px}
.buscador{display:flex;align-items:center;gap:9px;background:var(--surface);
  border:1px solid var(--line-ctl);border-radius:var(--radius-sm);padding:8px 12px;
  min-width:260px;flex:1;max-width:380px}
.buscador .ico{color:var(--ink-3)}
.buscador:focus-within{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.buscador input{flex:1;font:inherit;font-size:var(--fs-md);border:none;background:none;outline:none;
  color:var(--ink)}
.buscador input::placeholder{color:var(--ink-3)}
.filtros{display:flex;gap:6px;flex-wrap:wrap}
/* Los filtros son chips CLICABLES; se distinguen de los chips de estado (que solo
   informan) por el borde y el cursor. */
.filtros .f{background:var(--surface);border:1px solid var(--line-ctl);color:var(--ink-2);
  padding:6px 12px;border-radius:var(--radius-pill);font-size:var(--fs-sm);font-weight:600;
  cursor:pointer;user-select:none;display:inline-flex;align-items:center;gap:6px}
.filtros .f:hover{border-color:var(--accent)}
/* El filtro activo va SÓLIDO, no con un borde teal y fondo pálido.
   En la misma fila conviven botones `.btn.ghost` (Actualizar, Armar ruta del día)
   que ya son borde teal sobre blanco: con el estado activo pintado igual, el borde
   dejaba de significar "seleccionado" y pasaba a significar "esto es clicable".
   Se veía cuál filtro estaba puesto solo si se comparaban los cinco chips entre sí.
   Relleno lleno + contador invertido se lee de un vistazo y no compite con nada. */
.filtros .f.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent);
  font-weight:700}
.filtros .f.on:hover{filter:brightness(1.06)}
.filtros .f .n{background:var(--surface-3);color:var(--ink-2);padding:0 6px;
  border-radius:var(--radius-pill);font-size:var(--fs-xs)}
.filtros .f.on .n{background:rgba(255,255,255,.24);color:var(--on-accent)}

/* --- Logo del cliente ----------------------------------------------------
   Va sobre una PLACA CLARA: el logo de HD Cargo es navy sobre blanco, y la barra
   es navy oscuro, así que sin la placa el "hd" se perdería contra el fondo.
   Es el mismo recurso que usa el referente para la marca del cliente.

   Si el archivo todavía no está, el <img> falla y queda el texto "HD" de respaldo,
   así que la barra nunca se rompe. */
.marca{display:flex;align-items:center;gap:10px;text-decoration:none;flex:none}
.placa{background:var(--white);border-radius:var(--radius-sm);padding:5px 8px;
  display:grid;place-items:center;height:34px}
.placa img{height:24px;width:auto;display:block}


/* =========================================================================
   La etapa ocupa la ventana
   =========================================================================
   Las pantallas de trabajo (programaciones, hojas de ruta, envíos) son una
   tabla larga. Con altura natural la tabla terminaba donde terminaban sus filas
   y debajo quedaba fondo vacío: en un monitor alto se desperdiciaba media
   pantalla justo donde cabían más filas. Y al bajar se perdían de vista el
   buscador y los filtros, que es lo que uno usa para acotar la tabla.

   Ahora la ventana entera es el marco y la tabla hace scroll DENTRO del panel,
   con la cabecera de columnas pegada arriba.

   Los dos `:has()` acotan esto a la LISTA (un único panel). El detalle de una
   hoja de ruta apila varios bloques y puede ser más alto que la ventana: ahí no
   se toca nada y la página scrollea como siempre, porque encerrarla en 100vh
   recortaría lo de abajo.

   El `min-height` del media query es la otra red: en una ventana muy baja no
   entran barra + título + filtros + tabla, así que preferimos scroll normal
   antes que recortar los controles. */
@media (min-height:560px){
  body:has(#view > .panel:only-child),
  body:has(#content > .panel:only-child){height:100vh;overflow:hidden}

  /* min-height:0 en toda la cadena: sin esto un contenedor flex se niega a
     encogerse por debajo de su contenido y la tabla vuelve a empujar la página. */
  body:has(#view > .panel:only-child) main,
  body:has(#content > .panel:only-child) main,
  body:has(#content > .panel:only-child) > .wrap{min-height:0}

  #view,#content{flex:1;min-height:0}
  #view:has(> .panel:only-child),
  #content:has(> .panel:only-child){display:flex;flex-direction:column}
  #view > .panel:only-child,
  #content > .panel:only-child{flex:1;min-height:0;display:flex;flex-direction:column}
  #view > .panel:only-child > .tblwrap,
  #content > .panel:only-child > .tblwrap{flex:1;min-height:0}

  /* Cuando lo único que hay es un aviso — cargando, sin datos, error — se centra
     en el espacio libre. Pegado arriba de un rectángulo vacío parece que la
     página se cortó a la mitad. */
  #view:has(> .muted:only-child),   #content:has(> .muted:only-child),
  #view:has(> .empty:only-child),   #content:has(> .empty:only-child),
  #view:has(> .loading:only-child), #content:has(> .loading:only-child),
  #view:has(> .err:only-child),     #content:has(> .err:only-child),
  #view:has(> .note:only-child),    #content:has(> .note:only-child){
    display:flex;flex-direction:column;justify-content:center;align-items:center}
  #view > .panel:only-child > .muted,
  #content > .panel:only-child > .muted{margin:auto}
}


/* =========================================================================
   Borrado con confirmación — compartido
   =========================================================================
   Lo usan /programaciones y /hojas-ruta. Vive acá y no en cada página porque es
   el mismo gesto destructivo en las dos: si en una se ve distinto, deja de
   leerse como "esto no se deshace". */
/* El borrado va al FINAL de la fila y en gris, no a la mano izquierda ni en rojo:
   es la única acción de la tabla que destruye datos, y una que se dispara con un
   clic distraído no se arregla con un undo que no existe. Se pinta en rojo solo al
   pasar por encima, cuando ya hay intención. */
.col-acciones{width:34px;text-align:center;padding-left:0;padding-right:8px}
.borrar{background:none;border:none;cursor:pointer;color:var(--ink-3);font-size:14px;
  line-height:1;padding:4px 6px;border-radius:var(--radius-sm);opacity:.45;transition:.14s}
tr:hover .borrar{opacity:1}
.borrar:hover{color:var(--err);background:var(--err-soft)}

/* El diálogo de confirmación: muestra QUÉ se borra, no un "¿estás seguro?" */
.confirma-fondo{position:fixed;inset:0;background:rgba(13,21,32,.55);z-index:80;
  display:grid;place-items:center;padding:24px}
.confirma-fondo[hidden]{display:none}
.confirma{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md);
  max-width:430px;width:100%;padding:22px 24px;box-shadow:0 18px 50px rgba(0,0,0,.24)}
.confirma h3{font-size:17px;font-weight:700;letter-spacing:-.01em;margin-bottom:8px}
.confirma p{font-size:13.5px;color:var(--ink-2);line-height:1.5;margin-bottom:14px}
.confirma dl{border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 13px;
  margin-bottom:16px;background:var(--surface-2)}
.confirma .aviso{background:var(--warn-soft);color:#8A5100;border-radius:var(--radius-sm);
  padding:10px 13px;font-size:13px;line-height:1.45;margin-bottom:16px}
.confirma .acc{display:flex;gap:9px;justify-content:flex-end}
.btn.peligro{background:var(--err);border-color:var(--err);color:#fff}
.btn.peligro:hover{background:#B31F14;border-color:#B31F14}

/* Filas que se deslizan de lado (menú, estados y fases en el teléfono): el borde se
   desvanece del lado donde hay más. El JS de cada página pone .izq / .der solo si
   la fila realmente desborda. */
.desliza.der{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 36px),transparent);
  mask-image:linear-gradient(90deg,#000 calc(100% - 36px),transparent)}
.desliza.izq{-webkit-mask-image:linear-gradient(90deg,transparent,#000 36px);
  mask-image:linear-gradient(90deg,transparent,#000 36px)}
.desliza.izq.der{-webkit-mask-image:linear-gradient(90deg,transparent,#000 36px,#000 calc(100% - 36px),transparent);
  mask-image:linear-gradient(90deg,transparent,#000 36px,#000 calc(100% - 36px),transparent)}
