/* ============================================================================
   Chicken Porcionado · sistema de diseño
   ----------------------------------------------------------------------------
   Una sola hoja, sin build. Reglas que se respetan en toda la app:

   1. UN color de acento, y solo para la acción principal. Los estados
      (verde/rojo/ámbar) son tintes apagados y nunca compiten con el acento.
   2. Tres botones y no más: primario (relleno), secundario (contorno),
      fantasma (texto). Todos con la misma altura y el mismo radio.
   3. Escala de espaciado de 4 px. Nada de márgenes sueltos "a ojo".
   4. La interfaz no explica: los párrafos largos van al LEEME, no a la pantalla.
   ========================================================================== */

/* ============================================================================
   LA TIPOGRAFÍA
   Inter, servida DESDE LA PROPIA APP (src/estaticos/fuentes/, 196 KB en cuatro
   pesos). Antes la hoja decía `font-family: "Inter", ...` pero **nunca se
   cargaba el archivo**: en este PC caía a Segoe UI y la letra que se veía no
   era la que decía el código.
   Va local y no desde Google Fonts a propósito: esto corre en una planta y
   tiene que verse igual sin internet.
   Solo el subconjunto `latin`: cubre á é í ó ú ñ ü, que es todo lo que usa el
   español. El `latin-ext` pesaba 332 KB más y no aporta nada aquí.
   ========================================================================== */
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/estaticos/fuentes/inter-400-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("/estaticos/fuentes/inter-500-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 600;
  font-display: swap; src: url("/estaticos/fuentes/inter-600-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 700;
  font-display: swap; src: url("/estaticos/fuentes/inter-700-latin.woff2") format("woff2");
}

:root {
  /* --- superficie ------------------------------------------------------- */
  --canvas:      #f4f5f7;
  --superficie:  #ffffff;
  --superficie-2:#fafbfc;
  --linea:       #e3e6ea;
  --linea-fuerte:#d2d7dd;

  /* --- texto ------------------------------------------------------------ */
  --tinta:       #14181d;
  --tinta-media: #5b6573;
  /* Auditoría 8 sep 2026: #8b95a3 medía ~3,0:1 sobre blanco. Este tono lo usan
     TOTAL FACTURADO/PESADO/RECIBIDO/DIFERENCIA y la línea de kg de cada fila
     de la lista -- las etiquetas que distinguen números que se firman contra
     una factura. #6b7583 da ~4,6:1, ya en AA. */
  --tinta-suave: #6b7583;

  /* --- chrome (barra superior) ------------------------------------------ */
  /* La barra es BLANCA: la navegación es parte de la misma superficie clara
     de la aplicación, no una franja oscura pegada arriba. */
  --chrome:      #ffffff;
  --chrome-texto:#5b6573;
  --chrome-linea:#1e2a44;   /* filete fino que cierra el encabezado */

  /* --- acento: SOLO para la acción principal ---------------------------- */
  /* Es el ROJO DE LA MARCA, sacado del logo que entregó el cliente
     (`Logo chiken porcionados.jpg`, rojo puro #ff020d). Se oscureció un punto
     para que el texto blanco encima pase contraste AA sobre relleno y para que
     el enlace sea legible sobre blanco (5,3:1). El #ff020d crudo es de
     señalética, no de interfaz: quema y no deja leer.
     ⚠️ El acento y el estado de ALERTA son los dos rojizos, así que NUNCA se
     distinguen por el color: se distinguen por la FORMA. La acción principal
     siempre es un botón RELLENO; el error siempre es un panel con borde e
     icono. Eso ya está así y no se debe romper. */
  --acento:      #d81221;
  --acento-fuerte:#b30d1a;
  --acento-tenue: #fdeaec;

  /* --- estados: tintes apagados ----------------------------------------- */
  --bien:        #0f6b45;   --bien-fondo:  #e9f4ee;
  --alerta:      #a8321f;   --alerta-fondo:#fbeeeb;
  --proceso:     #8a5300;   --proceso-fondo:#fbf2e2;
  --neutro:      #4a5361;   --neutro-fondo:#eef0f3;

  /* --- dato: la ficha azul de la referencia ----------------------------- */
  --dato:        #1c53b3;   --dato-fondo:  #e8f0fe;   --dato-linea: #c5d9f7;

  /* --- geometría -------------------------------------------------------- */
  /* Radios generosos y un marco visible en cada caja: el cliente pidió
     "marcos que limitan", que el contenido se vea contenido y no flotando. */
  --r-caja: 14px;
  --r-control: 8px;
  /* 36 px. Bajó de 38 porque el cliente vio los campos "muy grandes" en el
     teléfono (8 sep 2026). NO baja más: por debajo de 36 se empieza a fallar
     el toque con las manos frías de la planta, y 36 ya está por debajo de los
     44 que recomienda Apple. Es una concesión consciente al cliente, no un
     descuido: si en la planta se quejan de que fallan el toque, esto es lo
     primero que hay que subir. */
  --alto-control: 36px;
  --sombra: 0 1px 2px rgba(20, 24, 29, .03), 0 2px 8px rgba(20, 24, 29, .05);
  --sombra-barra: 0 1px 3px rgba(20, 24, 29, .06);
}

* { box-sizing: border-box; }

/* ⚠️ El atributo `hidden` gana SIEMPRE.
   El navegador lo aplica con `display: none`, pero cualquier regla nuestra que
   ponga `display` lo tumba, porque una clase pesa más que el estilo de agente
   de usuario. Pasó con dos botones que nacen ocultos y los destapa el
   JavaScript: la × de los buscadores (`display: inline-flex`) salía en campos
   obligatorios donde no debe estar, y el ojito de la contraseña se habría
   visto aunque `clave.js` no cargara -- justo lo contrario de lo que se buscó
   al hacerlo mejora progresiva. */
[hidden] { display: none !important; }

/* ============================================================================
   NADA SE DESBORDA A LO ANCHO.
   Regla dura del cliente: no se hace scroll horizontal en ninguna pantalla.
   Lo que pueda empujar el documento (una tabla ancha, un correo largo, una
   dirección) parte de línea en vez de estirarlo. Cada componente que puede
   crecer trae su propia regla de ajuste más abajo.

   ⚠️ AQUÍ NO VA `overflow-x: clip` NI `hidden`. Se probó y fue peor: en vez de
   arreglar el desborde lo ESCONDE — el contenido que sobra se recorta y el
   usuario lo pierde sin enterarse. Y de paso ciega la medición, porque
   `scrollWidth` pasa a ser igual que `clientWidth` y todo parece correcto
   cuando no lo está. El desborde se arregla en el componente que lo causa.
   ========================================================================== */
html { max-width: 100%; }

body {
  margin: 0;
  font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  color: var(--tinta);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

/* ============================================================ barra superior */
/* ⚠️ TRES ZONAS, no un flex corrido: marca a la izquierda, menú CENTRADO en
   la pantalla, sesión a la derecha.
   Con flex el menú quedaba pegado a la marca y se movía cada vez que el
   nombre del usuario o el título cambiaban de largo. Las columnas laterales
   son `1fr` iguales, así que el centro cae en el centro de verdad, pase lo
   que pase a los lados. */
.barra {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 12px 24px;
  padding: 8px 24px;
  background: var(--chrome);
  border-bottom: 2px solid var(--chrome-linea);
  box-shadow: var(--sombra-barra);
  position: sticky; top: 0; z-index: 20;
}
.barra > nav { justify-self: center; }
.barra > .sesion { justify-self: end; }

.marca { display: flex; align-items: center; gap: 11px; flex: 0 0 auto; }
.marca strong { display: block; font-size: 14.5px; color: var(--tinta); letter-spacing: -.015em; }
.marca small  { display: block; font-size: 11px; color: var(--tinta-suave); }

/* El logo de la marca. Va CIRCULAR porque el logo es un sello redondo: con
   esquinas cuadradas se le verían los picos blancos del JPG.
   El archivo no tiene transparencia y la barra también es blanca, así que
   lleva un aro fino: sin él el sello parece flotar recortado. */
.logo {
  width: 40px; height: 40px; border-radius: 50%;
  flex: 0 0 auto; object-fit: cover; overflow: hidden;
  box-shadow: 0 0 0 1px var(--linea);
  background: #fff;
}
/* Respaldo por si algún día no hay imagen y vuelven las dos letras. */
span.logo {
  background: var(--acento); color: #fff;
  display: grid; place-items: center;
  font-weight: 700; font-size: 14px; letter-spacing: .5px;
}

/* La navegación empuja al borde derecho y ocupa lo que sobra. Con 11 enlaces
   tiene que poder partir en dos líneas sin romper nada: por eso wrap. */
nav {
  display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
  margin-left: auto; min-width: 0;
}
/* Icono ARRIBA y etiqueta debajo. Ocupa menos ancho que en línea -- caben más
   secciones sin apretar -- y cada entrada se lee como un botón entero y no
   como un texto con un dibujito al lado. */
nav a {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 14px; min-width: 74px; border-radius: 10px;
  color: var(--chrome-texto); text-decoration: none;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  letter-spacing: -.005em;
  transition: background .12s, color .12s;
}
/* Los SVG traen width/height en el HTML; aquí se unifican para que todos
   midan lo mismo aunque el atributo diga otra cosa. */
nav a svg, nav a .ico { width: 20px; height: 20px; }
/* El icono toma el color del texto del enlace (currentColor): gris normal,
   tinta al pasar el mouse, acento cuando está activo -- sin reglas aparte. */
nav a svg { flex: 0 0 auto; }
nav a:hover { background: var(--neutro-fondo); color: var(--tinta); }

/* El activo es una píldora del color de acento, apagada. Es el único sitio
   donde el acento aparece fuera de la acción principal, y se gana el permiso:
   saber en qué pantalla se está es lo primero que se mira. */
nav a.sel {
  background: var(--acento-tenue); color: var(--acento); font-weight: 700;
}
/* Separa el flujo de planta de los catálogos, que se tocan una vez. */
.nav-sep { width: 1px; height: 22px; background: var(--linea); margin: 0 8px; }

/* La recepción se digita con el camión abajo: se usa toda la pantalla. */
main {
  max-width: 1800px; margin: 0 auto; padding: 24px 24px 56px;
  min-width: 0;
}

/* ================================================================ tipografía */
/* 19px y no 22: el cliente los vio "muy grandes" (8 sep 2026). En una pantalla
   de trabajo el título no compite por atención -- ya se sabe dónde se está por
   la pestaña marcada en la barra; lo que tiene que resaltar son los datos. */
h1 {
  font-size: 19px; font-weight: 600; letter-spacing: -.02em;
  margin: 0 0 18px;
}
h2 {
  font-size: 13px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; color: var(--tinta-media);
  margin: 32px 0 12px;
}
.titulo-fila {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.titulo-fila h1 { margin: 0; }
.titulo-fila .acciones { margin: 0; }

/* Texto de apoyo. Una línea, nunca un párrafo. */
.ayuda, .nota {
  color: var(--tinta-media); font-size: 12.5px;
  margin: 8px 0 0;
}
.suave { color: var(--tinta-media); }

/* ==================================================================== avisos */
.aviso {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 16px; border-radius: var(--r-control);
  margin-bottom: 20px; font-size: 13.5px;
  border: 1px solid;
}
.aviso::before { font-weight: 700; line-height: 1.4; }
/* Un aviso sin modificador es informativo, no una alarma: tinte neutro y no
   compite con .error. Lo usa el recordatorio de datos que exige la norma. */
.aviso:not(.ok):not(.error) {
  background: var(--neutro-fondo); border-color: var(--linea-fuerte);
  color: var(--tinta-media);
}
.aviso:not(.ok):not(.error)::before { content: "i"; font-style: italic; }
.aviso.ok    { background: var(--bien-fondo);   border-color: #c9e5d6; color: #0d5537; }
.aviso.ok::before    { content: "✓"; }
.aviso.error { background: var(--alerta-fondo); border-color: #f0cdc6; color: #8f2718; }
.aviso.error::before { content: "!"; }

/* El porqué de un aviso de norma, plegado. Los avisos legales tienen que
   explicar la ley para que se entiendan, y esa explicación en el teléfono se
   come media pantalla antes de llegar al trabajo. La primera línea dice qué
   falta y dónde se arregla; el artículo y la razón quedan a un toque. */
.porque { margin-top: 2px; }
.porque > summary {
  cursor: pointer; list-style: none; font-weight: 600; font-size: 12.5px;
  opacity: .75; display: inline-flex; align-items: center; gap: 4px;
  min-height: 28px;
}
.porque > summary::-webkit-details-marker { display: none; }
.porque > summary::after { content: "▾"; font-size: 9px; }
.porque[open] > summary::after { content: "▴"; }
.porque > p { margin: 2px 0 0; font-size: 12.5px; line-height: 1.5; }

/* ================================================================== tarjetas */
/* Cada cifra en su propia caja con marco, separadas por aire, como en la
   referencia del WMS. Antes eran una rejilla pegada de 1 px que se leía como
   una sola caja partida. */
.tarjetas {
  display: grid; gap: 12px; margin-bottom: 20px;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}
.tarjeta {
  background: var(--superficie);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra);
  padding: 16px 18px 18px;
  display: flex; flex-direction: column; gap: 6px;
  min-width: 0;
}
.etiqueta {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600;
  overflow-wrap: anywhere;
}
.cifra {
  font-size: 22px; font-weight: 600; letter-spacing: -.025em;
  font-variant-numeric: tabular-nums; line-height: 1.15;
  /* ⚠️ Aquí decía `overflow-wrap: anywhere` y era exactamente lo contrario de
     lo que hace falta: partía "4.606,30" por cualquier sitio y en pantalla
     quedaba "4.606,3" en un renglón y "0" en el siguiente. Un número LEÍDO A
     MEDIAS es peor que un número cortado: 1.258,0 no es 1.258,00. Una cifra
     no se parte nunca; si no cabe, se achica la letra o se ensancha la caja. */
  white-space: nowrap;
}
.cifra.chico { font-size: 14px; font-weight: 500; letter-spacing: 0; }
.cifra em {
  font-size: 11px; font-style: normal; font-weight: 500;
  color: var(--tinta-suave); margin-left: 3px;
}
.tarjeta.merma .cifra { color: var(--alerta); }
.tarjeta.neto  .cifra { color: var(--bien); }
.merma-txt { color: var(--alerta); }
.neto-txt  { color: var(--bien); }

/* ===================================================================== panel */
.panel {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  margin-bottom: 20px; overflow: hidden;
}
.panel-cifras {
  display: grid; gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  padding: 18px 20px;
  border-bottom: 1px solid var(--linea);
  background: var(--superficie-2);
}
.panel-cifras > div { display: flex; flex-direction: column; gap: 4px; }
.panel > .formulario,
.panel > .ayuda,
.panel > .vacio-linea { margin: 0; padding: 18px 20px; }
.panel > .ayuda { padding-top: 0; }
.observaciones { color: var(--tinta-media); margin: 0; padding: 0 20px 16px; }

/* =============================================================== formularios */
.formulario {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  padding: 20px; max-width: 560px;
  display: flex; flex-direction: column; gap: 14px; margin-bottom: 20px;
}
.formulario.en-linea {
  flex-direction: row; align-items: flex-end; gap: 16px;
  flex-wrap: wrap; max-width: none;
}
.formulario.en-linea > div {
  display: flex; flex-direction: column; gap: 6px; flex: 1 1 170px;
}
.panel .formulario { border: 0; border-radius: 0; box-shadow: none; }

label { font-weight: 600; font-size: 12.5px; color: var(--tinta); }
.opcional { font-weight: 400; color: var(--tinta-suave); }

/* ⚠️ La lista de tipos va COMPLETA. Estuvo solo con text/date y las casillas
   de correo y contraseña del login se quedaron con el borde crudo del
   navegador: cuadradas, grises y ajenas al resto de la app. Un tipo que falte
   aquí es una casilla sin diseñar, así que se listan todos los que se usan. */
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], input[type=search], input[type=tel], select, textarea {
  height: var(--alto-control);
  padding: 0 11px; font-size: 14px; font-family: inherit;
  border: 1px solid var(--linea-fuerte); border-radius: var(--r-control);
  background: #fff; color: var(--tinta); width: 100%;
  transition: border-color .15s ease, box-shadow .15s ease;
}
textarea { height: auto; padding: 9px 11px; resize: vertical; }
input::placeholder { color: var(--tinta-suave); }
input:hover, select:hover { border-color: #b9c0c9; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--acento);
  box-shadow: 0 0 0 3px var(--acento-tenue);
}

/* La flecha del desplegable, dibujada por nosotros. La nativa cambia de forma
   en cada navegador y en Windows sale dentro de un botón gris con esquina
   viva: es lo único de la app que no tendría nuestro trazo. Va como SVG
   incrustado (mismo trazo 1.8 del juego de iconos) y no como archivo aparte
   para no gastar una petición en una flecha de 200 bytes. */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 34px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7583' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px 16px;
}
select:disabled {
  background-color: var(--superficie-2); color: var(--tinta-suave);
  cursor: not-allowed;
}

/* Mismo motivo con el calendario: el icono que pinta Chrome es un glifo
   relleno y oscuro, el único elemento de la app fuera del trazo de 1.8.
   Firefox no expone este pseudo-elemento y muestra el suyo; se ve bien igual,
   por eso no se fuerza con `appearance: none` (que dejaría el campo sin
   ninguna forma de abrir el calendario). */
input[type=date]::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .75;
  width: 17px; height: 17px; padding: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7583' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M3 10h18M8 3v4M16 3v4'/%3E%3C/svg%3E");
  background-size: 17px 17px; background-repeat: no-repeat;
}
input[type=date]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
input[readonly] {
  background: var(--superficie-2); color: var(--tinta-suave);
  border-style: dashed; cursor: not-allowed;
}
.acciones { display: flex; align-items: center; gap: 10px; }

/* Rejillas de campos. Un formulario de recepción tiene ocho datos: en una sola
   columna obliga a bajar la vista, y de pie frente a la báscula eso no sirve. */
.rejilla-2, .rejilla-3, .rejilla-4 { display: grid; gap: 14px; }
.rejilla-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rejilla-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rejilla-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rejilla-2 > div, .rejilla-3 > div, .rejilla-4 > div {
  display: flex; flex-direction: column; gap: 6px;
}
.formulario:has(.rejilla-2, .rejilla-3) { max-width: 780px; }
.formulario:has(.rejilla-4) { max-width: 1000px; }
.formulario.en-linea > div.crece { flex: 3 1 240px; }

/* Grupo de campos que se lee como una sola pregunta ("¿cómo llegó?"). */
.bloque {
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  padding: 16px 18px 18px; margin: 0;
  display: flex; flex-direction: column; gap: 14px;
  background: var(--superficie-2);
}
.bloque > legend {
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  font-weight: 600; color: var(--tinta-suave); padding: 0 6px;
}

/* =================================================================== botones */
.boton {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--alto-control); padding: 0 16px;
  border: 1px solid transparent; border-radius: var(--r-control);
  background: var(--acento); color: #fff;
  font-size: 13.5px; font-weight: 600; font-family: inherit;
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.boton:hover { background: var(--acento-fuerte); }
.boton:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

.boton.secundario {
  background: var(--superficie); color: var(--tinta);
  border-color: var(--linea-fuerte);
}
.boton.secundario:hover { background: var(--superficie-2); border-color: #b9c0c9; }

.boton.fantasma {
  background: transparent; color: var(--tinta-media); border-color: transparent;
  padding: 0 10px;
}
.boton.fantasma:hover { background: var(--neutro-fondo); color: var(--tinta); }

.boton.pequeno { height: 32px; padding: 0 12px; font-size: 13px; }
.boton.peligro { background: transparent; color: var(--alerta); border-color: transparent; padding: 0 10px; }
.boton.peligro:hover { background: var(--alerta-fondo); }

/* Botón apagado: se ve que está ahí y que todavía no se puede. Gris y no
   rojo, porque el rojo dice "haz esto" (HANDOFF §7: un solo acento, para la
   acción principal), y un botón que no responde no puede estar diciéndolo. */
.boton:disabled,
.boton:disabled:hover {
  background: var(--superficie-2); color: var(--tinta-suave);
  border-color: var(--linea-fuerte); cursor: not-allowed;
}

.cancelar { color: var(--tinta-media); text-decoration: none; font-size: 13.5px; }
.cancelar:hover { color: var(--tinta); text-decoration: underline; }

/* Campo de escanear/escribir: es la entrada principal de su pantalla, así que
   pesa más que el resto. El lector "teclea" el código y da Enter. */
.buscador-lote {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  padding: 18px 20px; margin-bottom: 16px;
}
.buscador-lote form { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.campo-codigo-caja {
  flex: 1 1 320px; max-width: 420px;
  display: flex; flex-direction: column; gap: 6px;
}
.campo-codigo {
  height: 44px; font-size: 16px; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}
.buscador-lote .boton { height: 44px; }
.buscador-lote code {
  background: var(--neutro-fondo); padding: 1px 5px;
  border-radius: 4px; font-size: 11.5px;
}

/* Barra de filtros: cada control con su etiqueta ENCIMA, no al lado. Con las
   etiquetas en línea, tres filtros seguidos se leen como una frase corrida
   ("Proveedor ... Pedido desde ... Hasta ...") y no se ve dónde empieza uno y
   termina el otro. */
/* ⚠️ `flex-start` y no `flex-end`. Con `flex-end`, en cuanto el filtro de
   proveedor mostraba las fichas de lo elegido, ese bloque crecía hacia abajo
   y arrastraba a "Pedido desde" y "Hasta": las tres etiquetas quedaban a tres
   alturas distintas. Alineados arriba, un bloque puede crecer sin mover a los
   demás. El botón compensa a mano el alto de una etiqueta. */
.filtro {
  display: flex; align-items: flex-start; gap: 10px 14px;
  margin-bottom: 16px; flex-wrap: wrap;
}
.filtro > div { display: flex; flex-direction: column; gap: 4px; }
.filtro > div.crece { flex: 1 1 240px; max-width: 360px; }
.filtro label {
  font-size: 11.5px; color: var(--tinta-suave); font-weight: 500;
}
.filtro select,
.filtro input[type=date] { width: auto; min-width: 190px; height: 34px; font-size: 13px; }
.filtro input[type=date] { min-width: 150px; }
/* El buscador reemplaza el <select> por un <input>, y sin esto salía a todo
   el ancho del formulario y rompía la fila. */
.filtro input.buscador-campo { min-width: 230px; height: 34px; font-size: 13px; }
/* 18 px = el alto de una etiqueta (≈14) más su separación (4). Es lo que baja
   el botón hasta quedar a la altura de los campos, ahora que la fila alinea
   por arriba. */
.filtro .al-final {
  flex-direction: row; align-items: center; gap: 8px; padding-top: 18px;
}


/* ==================================================================== tablas
   NINGUNA tabla hace scroll horizontal. La combinación que lo garantiza es
   `max-width: 100%` + `overflow-wrap: anywhere` en las celdas: como cualquier
   celda puede partir por donde sea, el ancho mínimo de la tabla siempre cabe
   en su contenedor y el navegador nunca tiene que desbordarla.
   Se dejó `table-layout: auto` a propósito: con `fixed` todas las columnas
   salen del mismo ancho y el nombre del proveedor quedaba en tres renglones
   mientras "Lotes" desperdiciaba media columna. Con auto, el reparto lo hace
   el contenido, que es lo que se quiere.
   Antes esto se resolvía con `overflow-x: auto` en móvil, o sea con scroll
   lateral, que es justo lo que el cliente prohibió. */
table {
  width: 100%; max-width: 100%;
  border-collapse: separate; border-spacing: 0;
  background: var(--superficie);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra); overflow: hidden;
}
thead th {
  text-align: left; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--tinta-suave); font-weight: 600;
  background: var(--superficie-2);
  padding: 10px 14px; border-bottom: 1px solid var(--linea);
  /* El encabezado PARTE DE LÍNEA, no se recorta con puntos suspensivos:
     "CUMPLIMIE…" no le dice nada a nadie. Con table-layout fijo la columna no
     se puede ensanchar, así que la única salida honesta es dejarlo en dos
     renglones. Parte SOLO en los espacios (`normal`): con `anywhere` salía
     "RENDIMIENT / O %", que se lee peor que no partir. Si una palabra sola no
     cabe, la recorta la tabla, que ya tiene overflow:hidden — nunca empuja la
     página. */
  white-space: normal; overflow-wrap: normal; word-break: normal;
  vertical-align: bottom; line-height: 1.35;
}
tbody td {
  padding: 12px 14px; border-bottom: 1px solid #eef0f3;
  vertical-align: middle;
  overflow-wrap: anywhere;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--superficie-2); }
tbody td form { margin: 0; display: inline-flex; }
/* Sin `white-space: nowrap`: un código de lote largo tiene que poder partir
   antes que empujar la tabla a lo ancho. */
td a { color: var(--acento); font-weight: 500; text-decoration: none; }
td a:hover { text-decoration: underline; }
td a.suave-enlace { color: var(--tinta-media); font-weight: 400; margin-left: 14px; }
/* Las celdas de números NO parten. Sin esto, "1.258,00" se leía como
   "1.258,0" con un "0" solitario debajo, y el cliente lo marcó como número
   desbordado -- con razón: en un peso, la última cifra es kilos. */
th.num, td.num {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Lo mismo para el código del lote y la fecha: son una sola unidad. */
td.sin-partir, th.sin-partir { white-space: nowrap; }
table.compacta { max-width: 640px; }

/* Fila de totales: cierra la tabla como la cierra el formato en papel. */
tfoot td {
  padding: 12px 16px; background: var(--superficie-2);
  border-top: 1px solid var(--linea-fuerte); font-variant-numeric: tabular-nums;
}

/* Columna de acciones: todo en UNA fila, alineado a la derecha, con el
   primario primero y lo secundario como texto. Nunca apilados. */
td.acciones-col, th.acciones-col { text-align: right; white-space: nowrap; }
td.acciones-col > * { vertical-align: middle; }
/* ⚠️ `stretch` y no `center`: dentro conviven enlaces, botones y formularios,
   y cada uno calcula su alto a su manera. Con `center` quedaban a alturas
   distintas -- se vio en el detalle del pedido, con "Corregir" y "Anular"
   descuadrados uno del otro. Estirados, todos miden lo que mide el más alto y
   la fila queda recta pase lo que pase. */
.grupo-acciones {
  display: inline-flex; align-items: stretch; gap: 6px; justify-content: flex-end;
}
.grupo-acciones > form { display: flex; }
.grupo-acciones .boton { height: auto; min-height: var(--alto-control); }

/* El motivo de la anulación, abierto con `?anular=1`. Fondo de alerta porque
   lo que se va a hacer no se deshace solo. */
.bloque-anular {
  background: var(--alerta-fondo); border-color: var(--alerta);
  margin-bottom: 16px;
}
/* =========================================================== confirmación
   El cartel que tapa la pantalla al guardar. Existe porque la franja verde de
   arriba se perdía: quien pesa mira la tabla, no la cabecera, y después de
   guardar no sabía si había quedado.
   ========================================================================== */
/* ==========================================================================
   EL SELLO
   --------------------------------------------------------------------------
   Esto es una app de TRAZABILIDAD: cada movimiento queda registrado y no se
   borra. La confirmación no debería sentirse como un mensaje del navegador,
   sino como un sello que cae sobre lo que se acaba de hacer.
   Antes era una caja blanca con un ✓ y una frase suelta -- correcta y sin
   ninguna intención. Ahora tiene jerarquía (un titular corto y el detalle
   debajo), un disco que dibuja su marca, y una barra que consume el tiempo
   que le queda: el cartel no desaparece de repente, se ve cuánto le falta.
   ========================================================================== */
.confirmacion {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  /* Un velo con desenfoque: el fondo se aleja de verdad en vez de solo
     oscurecerse. Con `saturate` bajo, el rojo del acento deja de tirar del
     ojo por detrás del cartel. */
  background: rgba(16, 20, 25, .52);
  -webkit-backdrop-filter: blur(4px) saturate(.85);
  backdrop-filter: blur(4px) saturate(.85);
  opacity: 0; transition: opacity .2s ease-out;
}
.confirmacion.visible { opacity: 1; }

.confirmacion-caja {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: center;
  width: min(380px, 100%); padding: 34px 34px 30px;
  background: var(--superficie); border-radius: 20px;
  /* Tres capas: el filo que dibuja el borde, la sombra de contacto y la
     ambiental. Una sola sombra plana se lee como un recorte pegado. */
  box-shadow: 0 0 0 1px rgba(20, 24, 29, .06),
              0 2px 6px rgba(20, 24, 29, .10),
              0 24px 60px rgba(20, 24, 29, .30);
  text-align: center;
  transform: scale(.94) translateY(10px);
  transition: transform .3s cubic-bezier(.16, 1, .3, 1);
}
.confirmacion.visible .confirmacion-caja { transform: none; }

/* El disco. El anillo tenue lo separa del blanco sin dibujar un borde duro. */
.confirmacion-disco {
  width: 62px; height: 62px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 16px;
  background: var(--bien-fondo); color: var(--bien);
  box-shadow: 0 0 0 8px rgba(15, 107, 69, .07);
  /* Salida exponencial, SIN rebote. Un `cubic-bezier` que se pasa de 1 y
     vuelve se lee como juguete; esto es el acuse de un registro que no se
     puede borrar. El disco entra decidido y se planta, como un sello. */
  transform: scale(.72); opacity: 0;
  transition: transform .36s cubic-bezier(.16, 1, .3, 1), opacity .2s ease-out;
}
.confirmacion.visible .confirmacion-disco { transform: none; opacity: 1; }
.confirmacion.es-error .confirmacion-disco {
  background: var(--alerta-fondo); color: var(--alerta);
  box-shadow: 0 0 0 8px rgba(168, 50, 31, .07);
}

/* La marca se DIBUJA. Es el único momento animado de la aplicación, y por eso
   se nota: no hay otros efectos compitiendo con él. */
.confirmacion-marca {
  stroke-dasharray: 40; stroke-dashoffset: 40;
  transition: stroke-dashoffset .4s cubic-bezier(.2, .8, .3, 1) .14s;
}
.confirmacion.visible .confirmacion-marca { stroke-dashoffset: 0; }

.confirmacion-titular {
  margin: 0 0 4px; font-size: 20px; font-weight: 650;
  letter-spacing: -.02em; color: var(--tinta);
}
.confirmacion-texto {
  margin: 0; font-size: 14px; line-height: 1.5; color: var(--tinta-media);
  max-width: 30ch;
}
.confirmacion-cerrar { margin-top: 18px; min-width: 140px; }

/* ---- Preguntas y avisos con el mismo sello (dialogo.js, 11 sep 2026) -----
   Reemplazan el cuadro del navegador ("…descubredata.com dice"), que el
   cliente vio "horrible" al pulsar "Terminar de recibir". Mismo velo, misma
   caja y mismo disco; la pregunta lleva el disco ámbar (atención), y lo
   arriesgado, el rojo del error. */
.confirmacion.es-pregunta .confirmacion-disco {
  background: var(--proceso-fondo); color: var(--proceso);
  box-shadow: 0 0 0 8px rgba(176, 106, 0, .08);
}
.dialogo .confirmacion-texto { max-width: 34ch; }
/* Un aviso que aparece bajo un dedo que sigue apretado (el del dictado) no
   puede seleccionar su propio texto: en Android quedaba "Cancelar" marcado y
   el menú de copiar encima (24 sep 2026). */
.dialogo .confirmacion-caja { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.confirmacion-pasos {
  margin: 4px 0 14px; padding-left: 1.3em; max-width: 36ch; text-align: left;
  font-size: 14px; color: var(--tinta); line-height: 1.45;
}
.confirmacion-pasos li + li { margin-top: 6px; }
/* Las cifras de la pregunta, como las del tablero: etiqueta chica y número. */
.confirmacion-cifras {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 22px;
  width: 100%; margin: 10px 0 12px; padding: 10px 14px;
  background: var(--superficie-2); border-radius: 12px;
}
.confirmacion-cifra { display: flex; flex-direction: column; gap: 1px; }
.confirmacion-cifra > span {
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em;
  font-weight: 600; color: var(--tinta-suave);
}
.confirmacion-cifra > strong {
  font-size: 16px; font-weight: 650; font-variant-numeric: tabular-nums;
  color: var(--tinta);
}
.confirmacion-cifra > strong.merma-txt { color: var(--alerta); }
.confirmacion-cifra > strong.neto-txt { color: var(--bien); }
.confirmacion-botones {
  display: flex; flex-wrap: wrap; gap: 10px; width: 100%; margin-top: 20px;
}
.confirmacion-botones .boton { flex: 1 1 130px; justify-content: center; }

/* El tiempo que le queda, dibujado. Un cartel que se va solo sin avisar deja
   la duda de si se alcanzó a leer; viéndolo consumirse, no. */
.confirmacion-tiempo {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--bien); transform-origin: left center;
  transform: scaleX(1);
}
.confirmacion.visible .confirmacion-tiempo {
  transform: scaleX(0); transition: transform 2s linear;
}

/* Quien pidió menos animación no recibe ninguna: el cartel aparece y ya.
   La marca se dibuja entera de una y la barra se queda quieta. */
@media (prefers-reduced-motion: reduce) {
  .confirmacion, .confirmacion-caja, .confirmacion-disco,
  .confirmacion-marca, .confirmacion.visible .confirmacion-tiempo {
    transition: none;
  }
  .confirmacion-caja, .confirmacion-disco { transform: none; opacity: 1; }
  .confirmacion-marca { stroke-dashoffset: 0; }
  .confirmacion-tiempo { display: none; }
}

@media (max-width: 640px) {
  .confirmacion { padding: 20px; }
  .confirmacion-caja { padding: 30px 24px 26px; }
  .confirmacion-titular { font-size: 18px; }
}

/* ================================ EL CUADRO DE "VER DETALLES" (12 sep 2026)
   El cliente: "un botoncito … 'Ver detalles' … un cuadro flotante" con quién
   creó la orden y quién recibió. Mismo velo y misma caja que los mensajes de
   la app (.confirmacion), pero con el texto a la izquierda: aquí se LEE una
   historia corta, no se confirma nada. Clases propias y no `.confirmacion`,
   para que nada de confirmacion.js lo toque.
   En el celular es una hoja que sube desde abajo, al alcance del pulgar. */
.detalles-capa {
  position: fixed; inset: 0; z-index: 210;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(16, 20, 25, .52);
  -webkit-backdrop-filter: blur(4px) saturate(.85);
  backdrop-filter: blur(4px) saturate(.85);
  opacity: 0; transition: opacity .2s ease-out;
}
.detalles-capa.visible { opacity: 1; }
html.con-detalles { overflow: hidden; }
/* La caja NO se desplaza: se desplaza lo de adentro (.detalles-cuerpo). Así la
   X queda quieta arriba a la derecha, y Novedades puede dejar su título y su
   "Entendido" fijos (13 sep 2026). */
.detalles-caja {
  position: relative;
  display: flex; flex-direction: column;
  width: min(540px, 100%);
  max-height: calc(100vh - 48px); max-height: calc(100dvh - 48px);
  overflow: hidden;
  background: var(--superficie); border-radius: 20px;
  box-shadow: 0 0 0 1px rgba(20, 24, 29, .06),
              0 2px 6px rgba(20, 24, 29, .10),
              0 24px 60px rgba(20, 24, 29, .30);
  transform: scale(.96) translateY(10px);
  transition: transform .3s cubic-bezier(.16, 1, .3, 1);
}
.detalles-capa.visible .detalles-caja { transform: none; }
.detalles-cuerpo {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 22px 24px 20px;
}
.detalles-x {
  position: absolute; top: 12px; right: 12px; z-index: 1;
  width: 40px; height: 40px; border: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  /* Fondo propio (revisión del 13 sep 2026): el cuerpo se desplaza por
     debajo de la X, y con fondo transparente los recibos se le montaban. */
  background: var(--superficie); color: var(--tinta-suave); cursor: pointer;
}
.detalles-x:hover { background: var(--neutro-fondo); color: var(--tinta); }
/* Al abrirse, el foco cae en la X. Cuando el cuadro sale SOLO (Novedades) el
   navegador le pintaba un aro negro grueso: queda visible, pero en voz baja. */
.detalles-x:focus-visible { outline: 2px solid var(--linea-fuerte); outline-offset: 1px; }
.detalles-cargando {
  margin: 30px 8px; text-align: center; font-size: 13.5px; line-height: 1.5;
  color: var(--tinta-media);
}

/* El contenido: el mismo en el cuadro y en su página (sin JavaScript). */
.detalles-cabeza {
  display: flex; align-items: center; gap: 12px;
  padding-right: 40px; margin-bottom: 14px;
}
.detalles-cabeza > div { flex: 1 1 auto; min-width: 0; }
/* `text-transform: none`: los h2 de la app son rótulos de sección en
   mayúscula, y "ORDEN DE COMPRA 10" se leía como un grito. */
.detalles-cabeza h2 {
  margin: 0; padding: 0; border: 0; font-size: 17px; line-height: 1.3; font-weight: 650;
  letter-spacing: -.01em; text-transform: none; color: var(--tinta);
}
.detalles-cabeza p {
  margin: 1px 0 0; font-size: 12.5px; color: var(--tinta-media); overflow-wrap: anywhere;
}
.detalles-cabeza .chip { flex: 0 0 auto; }
.detalles-cifras { margin: 0 0 4px; }
.detalles-titulo {
  display: flex; align-items: center; gap: 6px;
  margin: 18px 0 8px; font-size: 11px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .07em; color: var(--tinta-suave);
}
.detalles-hechos { margin: 0; display: grid; gap: 10px; }
.detalles-hechos > div {
  display: grid; grid-template-columns: 124px minmax(0, 1fr); gap: 12px;
  align-items: baseline;
}
.detalles-hechos dt { font-size: 12.5px; color: var(--tinta-media); }
.detalles-hechos dd { margin: 0; min-width: 0; }
.detalles-hechos dd strong {
  display: block; font-size: 13.5px; font-weight: 600; color: var(--tinta);
  overflow-wrap: anywhere;
}
.detalles-hechos dd small {
  display: block; margin-top: 1px; font-size: 12px; color: var(--tinta-suave);
  font-variant-numeric: tabular-nums;
}
/* "No quedó registrado" y "Todavía no" se leen como ausencia, no como un nombre. */
.detalles-hechos dd .sin-dato { font-weight: 500; font-style: italic; color: var(--tinta-suave); }
.detalles-recibos { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.detalles-recibos > li {
  padding: 12px 14px; border: 1px solid var(--linea); border-radius: 12px;
  background: var(--superficie-2);
}
.detalles-recibo-cabeza {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 10px;
}
.detalles-recibo-cabeza strong { font-size: 13.5px; color: var(--tinta); }
.detalles-recibo-cabeza .suave {
  flex: 1 1 auto; font-size: 12.5px; font-variant-numeric: tabular-nums;
}
.detalles-nota { margin: 14px 0 0; font-size: 12px; line-height: 1.5; color: var(--tinta-suave); }
.detalles-pie { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.detalles-pie .boton { flex: 1 1 150px; }
/* Página completa (sin JavaScript): la misma caja, sobre la página. */
.detalles.en-pagina {
  max-width: 560px; padding: 22px 24px;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
}
.detalles.en-pagina .detalles-cabeza { padding-right: 0; }

@media (max-width: 640px) {
  .detalles-capa { align-items: flex-end; padding: 0; }
  .detalles-caja {
    width: 100%; max-height: 88vh; max-height: 88dvh;
    border-radius: 18px 18px 0 0;
    transform: translateY(48px);
  }
  .detalles-cuerpo { padding: 26px 16px calc(16px + env(safe-area-inset-bottom)); }
  /* La agarradera dice "esto es una hoja", sin palabras. */
  .detalles-caja::before {
    content: ""; position: absolute; top: 8px; left: 50%; z-index: 2;
    width: 40px; height: 4px; border-radius: 2px;
    transform: translateX(-50%); background: var(--linea-fuerte);
  }
  .detalles-x { top: 6px; right: 6px; }
  .detalles-hechos > div { grid-template-columns: 104px minmax(0, 1fr); gap: 10px; }
  .detalles.en-pagina { padding: 18px 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .detalles-capa, .detalles-caja { transition: none; }
  .detalles-caja { transform: none; }
}

/* ======================================== LA VENTANA DE NOVEDADES
   Rehecha el 13 sep 2026. El cliente: "se ve terrible, confuso y muy
   desordenado, está todo mezclado ... tampoco cabe en la pantalla". Ahora:
   título quieto arriba, "Entendido" quieto abajo, y en medio SOLO la
   actualización más reciente, partida en tres bloques con su color --
   Lo nuevo (verde), Mejoras y cambios (azul de los datos), Errores
   corregidos (gris: ya no molesta). Las anteriores, plegadas debajo. */
/* `.es-novedades` la pone detalles.js. Era `:has(> .novedades)`, pero un
   navegador sin `:has` (Chrome antes de la 105, Safari antes de la 15.4)
   descartaba la regla y la cabeza y el pie se iban con el desplazamiento
   (revisión del 13 sep 2026). */
.detalles-cuerpo.es-novedades, .detalles-cuerpo.es-asistente {
  display: flex; flex-direction: column; overflow: hidden; padding: 0;
}
/* El botón por defecto de Notificaciones (notificaciones.html): existe para
   que Enter guarde. Fuera de la vista, no fuera del formulario. */
.formulario > .boton-por-defecto {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.novedades { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.novedades-cabeza {
  flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
  padding: 18px 60px 14px 22px; border-bottom: 1px solid var(--linea);
}
.novedades-cabeza > div { min-width: 0; }
.novedades-cabeza h2 {
  margin: 0; padding: 0; border: 0; font-size: 17px; line-height: 1.3; font-weight: 650;
  letter-spacing: -.01em; text-transform: none; color: var(--tinta);
}
.novedades-cabeza p { margin: 1px 0 0; font-size: 12.5px; color: var(--tinta-media); }
.novedades-disco {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--acento-tenue); color: var(--acento-fuerte);
}
.novedades-cuerpo {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: grid; gap: 22px; align-content: start;
  padding: 18px 22px 22px;
}
.novedades-pie {
  flex: 0 0 auto; display: flex; justify-content: flex-end;
  margin: 0; padding: 12px 22px; border-top: 1px solid var(--linea);
  background: var(--superficie);
}
.novedades-pie .boton { flex: 0 1 180px; }

.novedad-fecha {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 11px; font-weight: 650; line-height: 1.4;
  text-transform: uppercase; letter-spacing: .07em; color: var(--tinta-suave);
}
.novedad-sin-ver {
  display: none; padding: 1px 8px; border-radius: 999px;
  background: var(--acento); color: #fff;
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.novedad.sin-ver .novedad-sin-ver { display: inline-block; }
.novedad-titulo {
  margin: 3px 0 16px; font-size: 19px; font-weight: 700; line-height: 1.25;
  letter-spacing: -.02em; color: var(--tinta); text-wrap: balance;
}

/* Tres columnas, una por tipo (el cliente: "quiero tener en tres columnas,
   una Lo nuevo, en otra las mejoras y en otra los errores corregidos... las
   columnas deben ser claras", 13 sep 2026). Cada una es una tarjeta de su
   color -- no solo el título cambia de color, la tarjeta entera -- para que
   se lean como tres cosas distintas de un vistazo, no como texto corrido.
   Apiladas en el celular (no caben tres columnas en 390px); lado a lado
   desde `--ancho-novedades` (ver la caja del cuadro, más abajo). */
.novedad-grupos { display: grid; gap: 14px; }
.novedad-grupo {
  display: grid; gap: 8px; align-content: start;
  background: var(--grupo-fondo); border-radius: 14px;
  border-top: 3px solid var(--grupo);
  padding: 14px 16px 16px;
}
.novedad-grupo.nuevo     { --grupo: var(--bien);   --grupo-fondo: var(--bien-fondo); }
.novedad-grupo.mejoras   { --grupo: var(--dato);   --grupo-fondo: var(--dato-fondo); }
.novedad-grupo.corregido { --grupo: var(--neutro); --grupo-fondo: var(--neutro-fondo); }
.novedad-grupo-titulo {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 13px; font-weight: 700; line-height: 1.3; color: var(--grupo);
  text-transform: uppercase; letter-spacing: .03em;
}
.novedad-grupo-icono {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--superficie); color: var(--grupo);
}
.novedad-grupo ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.novedad-grupo li {
  position: relative; padding-left: 15px;
  font-size: 13.5px; line-height: 1.5; color: var(--tinta-media);
}
.novedad-grupo li::before {
  content: ""; position: absolute; left: 0; top: .58em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--grupo);
}

/* Desde aquí caben tres columnas lado a lado sin apretarse (medido con la
   entrada más larga que hay hoy: ~230px de columna, cómodo para una frase
   corta). La caja del cuadro se ensancha SOLO para Novedades -- las demás
   ("Ver detalles" de una orden o un recibo) se quedan en 540px. */
@media (min-width: 760px) {
  .detalles-capa.es-novedades .detalles-caja { width: min(880px, 100%); }
  /* `auto-fit` y no `repeat(3, ...)` (revisión del 13 sep 2026): una entrega
     que solo trae "Lo nuevo" -- sin mejoras ni errores que contar -- tiene
     UN grupo, y con 3 columnas fijas se veía como una caja angosta perdida
     a la izquierda, seguida de la lista de entregas anteriores: exactamente
     lo que el cliente describió como "no está en columnas, sigue para
     abajo". Con `auto-fit` las columnas vacías se reparten entre las que sí
     tienen contenido: 1 grupo ocupa TODO el ancho, 2 se reparten a la
     mitad, 3 quedan como antes. */
  .novedad-grupos { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
  .novedad-grupo { padding: 16px 18px 18px; }
}

/* Las anteriores: una fila por actualización, plegada. */
.novedades-anteriores { display: grid; border-top: 1px solid var(--linea); padding-top: 14px; }
.novedades-anteriores-titulo {
  margin: 0 0 4px; font-size: 11px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .07em; color: var(--tinta-suave);
}
.novedad-anterior { border-bottom: 1px solid var(--linea); }
.novedad-anterior:last-child { border-bottom: 0; }
.novedad-anterior > summary {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center;
  gap: 4px 12px; min-height: 46px; padding: 8px 4px; cursor: pointer; list-style: none;
}
.novedad-anterior > summary::-webkit-details-marker { display: none; }
.novedad-anterior > summary::after {
  content: ""; width: 7px; height: 7px; margin: 0 4px 3px;
  border-right: 2px solid var(--tinta-suave); border-bottom: 2px solid var(--tinta-suave);
  transform: rotate(45deg);
}
.novedad-anterior[open] > summary::after { transform: rotate(-135deg); margin-bottom: -3px; }
.novedad-anterior > summary:hover .novedad-anterior-titulo { color: var(--acento-fuerte); }
.novedad-anterior > summary:focus-visible { outline: 2px solid var(--dato); outline-offset: 2px; border-radius: 6px; }
.novedad-anterior-fecha { font-size: 12px; color: var(--tinta-suave); font-variant-numeric: tabular-nums; }
.novedad-anterior-titulo { font-size: 14px; font-weight: 600; color: var(--tinta); }
.novedad-anterior .novedad-grupos { padding: 4px 4px 18px; }

/* Sin JavaScript: la misma ventana como página. */
.detalles.novedades.en-pagina { padding: 0; overflow: hidden; }
.novedades.en-pagina .novedades-cabeza { padding-right: 22px; }
@media (min-width: 760px) {
  .detalles.novedades.en-pagina { max-width: 880px; }
}

/* ======================================== EL ASISTENTE DE DATOS (13 sep 2026)
   "Un icono flotante tipo chatbot para... consultar datos". Botón redondo,
   fijo abajo a la derecha, solo para gerentes y el desarrollador. Es un
   enlace con `data-detalles`: lo abre el mismo cuadro de "Ver detalles",
   ensanchado igual que Novedades (`.es-asistente`, ver más abajo). */
.asistente-flotante {
  position: fixed; right: 20px; bottom: 24px; z-index: 40;
  width: 54px; height: 54px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--acento); color: #fff; text-decoration: none;
  box-shadow: 0 6px 16px rgba(20, 24, 29, .22), 0 2px 4px rgba(20, 24, 29, .12);
  transition: transform .15s ease-out, background-color .15s ease-out;
}
.asistente-flotante:hover { background: var(--acento-fuerte); transform: translateY(-2px); }
.asistente-flotante:focus-visible { outline: 2px solid var(--tinta); outline-offset: 2px; }
.asistente-flotante .ico { width: 23px; height: 23px; }
@media (max-width: 860px) {
  /* Encima de la barra inferior del teléfono, no debajo. */
  .asistente-flotante { right: 16px; bottom: calc(76px + env(safe-area-inset-bottom)); }
}

/* ================================== ORDEN DE COMPRA POR VOZ (14 sep 2026)
   Mismo botón redondo que el asistente, a la IZQUIERDA para no encimarse con
   él -- un gerente puede tener los dos permisos a la vez. Es un <button>, no
   un <a>: no navega al tocarlo, solo mientras se mantiene presionado
   (dictado_orden.js). El aro rojo pulsando es la única señal de "te estoy
   escuchando": sin sonido ni texto no hay forma de saber si el micrófono
   quedó abierto. */
.voz-orden-flotante {
  left: 20px; right: auto;
  border: none; cursor: pointer; font: inherit;
  background: var(--tinta);
  /* SE SOSTIENE, como el de WhatsApp (el cliente, 18 sep 2026: "hay que tocar
     el icono, después dejarlo de tocar [...] eso tiene que ser algo intuitivo,
     como mandar un mensaje por WhatsApp").
     Las tres líneas de abajo son lo que hace que sostener signifique HABLAR:
     sin `touch-action` el celular se lleva el gesto como scroll, sin
     `user-select` sale el menú de copiar, y sin `-webkit-touch-callout` iOS
     abre su propio menú encima. */
  touch-action: none;
  user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.voz-orden-flotante:hover { background: #000; }
.voz-orden-flotante.escuchando {
  background: var(--alerta);
  animation: voz-pulso 1.1s ease-out infinite;
}
/* Arrastrar el dedo fuera del botón cancela, como en WhatsApp. Se avisa
   ANTES de soltar: en gris y sin pulso, para que se note que ya no está
   grabando hacia ninguna parte. */
.voz-orden-flotante.va-a-cancelar,
.boton.va-a-cancelar {
  background: var(--neutro); animation: none; opacity: .75;
}
@keyframes voz-pulso {
  /* rgba fija (no color-mix, por compatibilidad) del mismo rojo de --alerta. */
  0%   { box-shadow: 0 0 0 0 rgba(168, 50, 31, .45); }
  100% { box-shadow: 0 0 0 16px rgba(168, 50, 31, 0); }
}
@media (max-width: 860px) {
  .voz-orden-flotante { left: 16px; right: auto; bottom: calc(76px + env(safe-area-inset-bottom)); }
}

/* Lo que va oyendo, flotando ENCIMA del botón mientras se mantiene
   presionado (14 sep 2026, "¿cómo sé cuál es el texto que le está
   tomando?"). Ancho fijo y no todo el texto en una línea: una orden dictada
   entera no cabe, y una caja que crece de ancho se saldría de la pantalla
   en el celular, que es donde más se va a usar esto. */
.voz-orden-texto {
  position: fixed; left: 20px; bottom: 86px; z-index: 41;
  width: min(280px, calc(100vw - 40px)); padding: 10px 14px;
  border-radius: 12px; background: var(--tinta); color: #fff;
  font-size: 13px; line-height: 1.4; box-shadow: 0 6px 16px rgba(20, 24, 29, .22);
}
.voz-orden-texto::after {
  content: ""; position: absolute; left: 22px; bottom: -6px;
  width: 12px; height: 12px; background: inherit; transform: rotate(45deg);
  border-radius: 0 0 3px 0;
}
@media (max-width: 860px) {
  .voz-orden-texto { left: 16px; bottom: calc(138px + env(safe-area-inset-bottom)); }
}

.asistente { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.asistente-cabeza {
  flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
  padding: 18px 60px 14px 22px; border-bottom: 1px solid var(--linea);
}
.asistente-cabeza > div { min-width: 0; }
.asistente-cabeza h2 {
  margin: 0; padding: 0; border: 0; font-size: 17px; line-height: 1.3; font-weight: 650;
  letter-spacing: -.01em; text-transform: none; color: var(--tinta);
}
.asistente-cabeza p { margin: 1px 0 0; font-size: 12.5px; color: var(--tinta-media); }
.asistente-disco {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--acento-tenue); color: var(--acento-fuerte);
}
.asistente-cuerpo {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  /* `minmax(0, 1fr)` y no una columna implícita "auto" (revisión del 13 sep
     2026, "blowout" de grid visto en el celular): sin decirle que puede
     encogerse, la columna crecía al ancho mínimo del formulario -- la fila
     de la pregunta con su botón -- y empujaba todo el cuadro de lado. */
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; align-content: start;
  padding: 18px 22px 22px;
}
/* ======================= EL ASISTENTE COMO CONVERSACIÓN (14 sep 2026)
   El cliente, viéndolo ya con una llave de IA activa: "parece un
   formulario, no es conversacional... tiene que ser una conversación
   fluida... y no reinicia la conversación". Las preguntas ya escritas y el
   constructor de filtros a mano (asistente-ejemplos, -filtros, -rejilla,
   -campo, -rango-fechas, -entendido, -resumen) eran el diseño de CUANDO NO
   HABÍA IA (13 sep) -- se quitan de aquí. `.asistente-entendido` la sigue
   usando orden_voz.html; no se toca esa regla, solo se dejó de usar aquí.

   `.chat` es un modificador de `.asistente-cuerpo` y no un reemplazo: esa
   clase la comparte orden_voz.html con su propio layout (grid, con scroll
   en el cuerpo entero), así que aquí se sobreescribe a flex column -- los
   mensajes crecen y se desplazan solos, la caja de escribir queda fija
   abajo, como cualquier chat. */
.asistente-cuerpo.chat {
  display: flex; flex-direction: column; overflow: hidden; padding: 0; gap: 0;
}
.asistente-nueva { margin-left: auto; }
.asistente-reiniciar {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--linea-fuerte); background: none; color: var(--tinta-media);
  cursor: pointer; transition: color .12s, border-color .12s, background-color .12s;
}
.asistente-reiniciar:hover { color: var(--acento-fuerte); border-color: var(--acento); background: var(--acento-tenue); }
.asistente-mensajes {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 14px; padding: 18px 22px;
}
/* Discreto y chico a propósito (14 sep 2026, el cliente: "ese texto que
   dice ahí está enorme"): la cabeza YA dice "Pregúntale a tus datos"; esto
   es solo un ejemplo rápido, no una segunda explicación. */
.asistente-vacio { margin: auto; text-align: center; color: var(--tinta-suave); font-size: 12px; max-width: 30ch; }
/* Burbujas grandes, con avatar en las del asistente -- el mismo lenguaje de
   los agentes de chat que ya se han hecho para otros clientes (14 sep 2026,
   el cliente: "como si fuera un chat de WhatsApp... como los que ya hemos
   construido"), con los colores propios de Chicken Porcionados y no los de
   otro producto (el acento de aquí, no el de otro). */
.burbuja-fila { display: flex; align-items: flex-end; gap: 8px; max-width: 92%; }
.burbuja-fila.fila-usuario { align-self: flex-end; flex-direction: row-reverse; }
.burbuja-fila.fila-asistente { align-self: flex-start; }
.burbuja-avatar {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; margin-bottom: 2px;
  display: flex; align-items: center; justify-content: center;
  background: var(--acento); color: #fff;
}
.burbuja-avatar .ico { width: 14px; height: 14px; }
/* Repuesto del avatar (asistente.js) para la burbuja "escribiendo" de la
   PRIMERA pregunta de una conversación nueva, cuando todavía no hay ningún
   ícono ya pintado por el servidor del que copiarlo. */
.burbuja-avatar .ico-punto { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.burbuja {
  min-width: 0; padding: 10px 14px; border-radius: 18px; font-size: 14px; line-height: 1.5;
  box-shadow: 0 1px 2px rgba(20, 24, 29, .06);
}
.burbuja p { margin: 0; }
.burbuja-usuario {
  background: var(--acento); color: #fff; border-bottom-right-radius: 5px;
}
.burbuja-asistente {
  background: var(--superficie-2); color: var(--tinta);
  border: 1px solid var(--linea); border-bottom-left-radius: 5px;
}
.burbuja-asistente .asistente-grafico,
.burbuja-asistente .asistente-tabla-caja { margin-top: 10px; }
.burbuja-asistente .asistente-tabla-caja { background: var(--superficie); }
/* "Escribiendo…" (14 sep 2026): tres puntos que rebotan, mientras se espera
   la respuesta -- asistente.js la pinta apenas se manda la pregunta y la
   quita cuando llega el HTML de verdad. Sin esto, entre mandar la pregunta
   y ver la respuesta la pantalla se quedaba quieta -- se sentía rígido, no
   como una conversación de verdad. */
.burbuja-escribiendo { display: flex; gap: 4px; align-items: center; padding: 13px 14px; }
.burbuja-escribiendo span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--tinta-suave);
  animation: burbuja-rebote 1.2s ease-in-out infinite;
}
.burbuja-escribiendo span:nth-child(2) { animation-delay: .15s; }
.burbuja-escribiendo span:nth-child(3) { animation-delay: .3s; }
@keyframes burbuja-rebote {
  0%, 60%, 100% { transform: translateY(0); opacity: .5; }
  30% { transform: translateY(-4px); opacity: 1; }
}
.asistente-caja-enviar {
  flex: 0 0 auto; padding: 12px 16px; border-top: 1px solid var(--linea); background: var(--superficie);
}
/* Una sola píldora para el campo y el botón (14 sep 2026, el cliente: "eso
   se tiene que ver de forma natural, como en Teams, Telegram, WhatsApp"):
   el campo no lleva borde propio, es la píldora la que lo tiene y la que
   reacciona al foco -- copiado del mismo agente de chat de referencia
   (chatbot-comercial), con los colores propios de Chicken Porcionados. */
.asistente-pregunta {
  display: flex; align-items: center; gap: 6px; padding: 5px 5px 5px 16px;
  border: 1px solid var(--linea-fuerte); border-radius: 24px; background: var(--superficie-2);
  transition: border-color .12s, box-shadow .12s;
}
.asistente-pregunta:focus-within { border-color: var(--acento); box-shadow: 0 0 0 3px var(--acento-tenue); }
.asistente-pregunta input {
  /* `min-width: 0` -- sin esto, un input dentro de un flex no se encoge por
     debajo de su ancho de contenido y empuja el cuadro a un lado (revisión
     del 13 sep 2026, se vio en el celular). */
  flex: 1 1 auto; min-width: 0; padding: 8px 0; border: 0; background: none;
  font: inherit; font-size: 14px; color: var(--tinta);
}
.asistente-pregunta input:focus { outline: none; }
.asistente-pregunta button[type=submit] {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; border: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--acento); color: #fff; cursor: pointer;
  transition: background-color .12s, transform .08s;
}
.asistente-pregunta button[type=submit]:hover { background: var(--acento-fuerte); }
.asistente-pregunta button[type=submit]:active { transform: scale(.93); }
/* La gráfica mínima (el cliente, 13 sep 2026: "tiene que poder hacer unas
   mínimas gráficas"): barras horizontales con los porcentajes ya resueltos
   en Python -- aquí solo se pintan anchos, nada de una librería de
   gráficas. Con "Pedido vs. recibido" la pista entera es el pedido (más
   clara) y el relleno de adentro es lo que ya llegó (el acento de datos). */
.asistente-grafico { display: grid; gap: 9px; margin: 0 0 18px; }
.asistente-grafico-fila {
  display: grid; grid-template-columns: minmax(70px, 130px) 1fr auto;
  align-items: center; gap: 10px;
}
.asistente-grafico-etiqueta {
  font-size: 12px; color: var(--tinta-media); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.asistente-grafico-pista {
  position: relative; display: block; height: 16px; min-width: 8px;
  border-radius: 5px; background: var(--dato-fondo); overflow: hidden;
}
.asistente-grafico-relleno {
  position: absolute; inset: 0 auto 0 0; height: 100%;
  border-radius: 5px; background: var(--dato);
}
.asistente-grafico-valor {
  font-size: 12px; font-variant-numeric: tabular-nums; color: var(--tinta-media);
  white-space: nowrap;
}
.asistente-tabla-caja { overflow-x: auto; border: 1px solid var(--linea); border-radius: 12px; }
.asistente-tabla-caja table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.asistente-tabla-caja th {
  text-align: left; padding: 9px 12px; background: var(--superficie-2);
  border-bottom: 1px solid var(--linea); font-size: 11.5px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .04em; color: var(--tinta-suave);
  white-space: nowrap;
}
.asistente-tabla-caja td { padding: 9px 12px; border-bottom: 1px solid var(--linea); white-space: nowrap; }
.asistente-tabla-caja tr:last-child td { border-bottom: 0; }
.asistente-tabla-caja td:first-child { white-space: normal; }
.asistente-pie { flex: 0 0 auto; display: flex; justify-content: flex-end;
  margin: 0; padding: 12px 22px; border-top: 1px solid var(--linea); background: var(--superficie); }
.asistente-pie .boton { flex: 0 1 180px; }

@media (min-width: 760px) {
  .detalles-capa.es-asistente .detalles-caja { width: min(760px, 100%); }
}
@media (max-width: 640px) {
  .asistente-cabeza { padding: 24px 56px 12px 16px; }
  .asistente-cuerpo { padding: 16px 16px 20px; }
  .asistente-rejilla { grid-template-columns: 1fr; }
  .asistente-rango-fechas.visible { grid-template-columns: 1fr; }
  .asistente-pie { padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); }
  .asistente-pie .boton { flex: 1 1 auto; }
  .asistente-grafico-fila { grid-template-columns: minmax(0, 84px) 1fr auto; gap: 6px; }
  .asistente-grafico-etiqueta, .asistente-grafico-valor { font-size: 11px; }
}

@media (max-width: 640px) {
  .novedades-cabeza { padding: 24px 56px 12px 16px; }
  .novedades-cuerpo { padding: 16px 16px 20px; gap: 20px; }
  .novedades-pie { padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); }
  .novedades-pie .boton { flex: 1 1 auto; }
  .novedad-titulo { font-size: 18px; }
  .novedad-anterior > summary { grid-template-columns: minmax(0, 1fr) auto auto; }
  .novedad-anterior-fecha { grid-column: 1 / -1; }
}

/* ================================ AVISOS EN ESTE EQUIPO (13 sep 2026)
   La franja de "Activar" en las listas. Azul de los datos, no rojo: no es un
   error ni algo que haya que hacer ya, es una invitación. Ámbar cuando hay un
   paso que dar (instalar la app en el iPhone, desbloquear) y verde al quedar
   lista. Nace escondida; la muestra avisos.js. */
.avisos-equipo {
  display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 12px 14px;
  background: var(--dato-fondo); border: 1px solid var(--dato-linea);
  border-radius: var(--r-caja);
}
.avisos-equipo[hidden] { display: none; }
.avisos-equipo-icono {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--superficie); color: var(--dato);
}
.avisos-equipo-texto { flex: 1 1 260px; min-width: 0; }
.avisos-equipo-texto strong { display: block; font-size: 13.5px; font-weight: 650; color: var(--tinta); }
.avisos-equipo-texto span { display: block; font-size: 12.5px; line-height: 1.45; color: var(--tinta-media); }
.avisos-equipo-botones { display: flex; gap: 8px; flex: 0 0 auto; }
.avisos-equipo-botones .boton[hidden] { display: none; }
.avisos-equipo.es-problema { background: var(--proceso-fondo); border-color: transparent; }
.avisos-equipo.es-problema .avisos-equipo-icono { color: var(--proceso); }
.avisos-equipo.es-listo { background: var(--bien-fondo); border-color: transparent; }
.avisos-equipo.es-listo .avisos-equipo-icono { color: var(--bien); }
@media (max-width: 640px) {
  .avisos-equipo-botones { flex: 1 1 100%; }
  .avisos-equipo-botones .boton { flex: 1 1 0; }
}

/* La configuración de Notificaciones: una tarjeta por persona, con sus dos
   avisos y las casillas de correo y equipo. Tarjetas y no tabla: en el
   celular seis columnas no caben sin correrse de lado. */
.avisos-personas {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 430px), 1fr));
}
.aviso-persona {
  min-width: 0; padding: 12px 16px 6px;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja);
}
.aviso-persona-cabeza { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.aviso-persona-cabeza > div { flex: 1 1 auto; min-width: 0; }
.aviso-persona-cabeza strong { display: block; font-size: 13.5px; font-weight: 600; color: var(--tinta); }
.aviso-persona-cabeza small { display: block; font-size: 11.5px; color: var(--tinta-suave); }
.aviso-equipos {
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto;
  font-size: 12px; white-space: nowrap;
}
.aviso-evento {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center;
  gap: 2px 16px; padding: 6px 0; border-top: 1px solid var(--linea);
  font-size: 13px; color: var(--tinta-media);
}
.aviso-evento .casilla {
  display: inline-flex; align-items: center; gap: 7px; min-height: 34px;
  font-size: 13px; color: var(--tinta); cursor: pointer; white-space: nowrap;
}
.aviso-evento input[type=checkbox] { width: 18px; height: 18px; margin: 0; accent-color: var(--acento); }
.aviso-evento .casilla:has(input:disabled) { color: var(--tinta-suave); cursor: default; }
.avisos-ayuda { margin: 0; padding-left: 18px; display: grid; gap: 8px; max-width: 72ch;
  font-size: 13.5px; line-height: 1.5; color: var(--tinta-media); }
@media (max-width: 640px) {
  .aviso-evento { grid-template-columns: 1fr 1fr; }
  .aviso-evento > span { grid-column: 1 / -1; font-weight: 600; color: var(--tinta); padding-top: 2px; }
}

/* La frase que explica qué falta: ocupa la línea completa bajo los tres
   números, en voz baja. Solo aparece mientras el dato falta. */
.cuadre-ayuda {
  flex: 1 1 100%; margin: 8px 0 0;
  font-size: 12.5px; color: var(--tinta-media);
}
.cuadre-tira strong.falta {
  color: var(--proceso); font-size: 15px; font-style: italic; font-weight: 600;
}

/* Dentro de la franja, las acciones ocupan la línea completa debajo. */
.franja-pedido .acciones-pedido { flex: 1 1 100%; margin-top: 10px; }

/* Las acciones sobre el pedido, dentro del recibo: van al pie del bloque y en
   voz baja. No son el trabajo -- el trabajo es pesar. */
.acciones-pedido {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--linea);
}
.acciones-pedido .fila-anular { flex: 1 1 380px; }
.acciones-pedido .fila-anular input[type="text"] {
  height: var(--alto-control); font-size: 13px; flex: 1 1 auto; width: auto;
}

/* Producto del pedido que el camión no trajo. Se apaga, pero NO se esconde:
   el faltante es lo único que permite reclamarle al proveedor. */
.producto.no-llego { opacity: .62; }
.producto.no-llego .arrumes-tabla { display: none; }

/* ------------------------------------------------ la fila de cada producto
   Es el resumen y el disparador a la vez: dice cuánto se pidió, cuánto va y
   cuánto falta, y al abrirla salen SUS arrumes. Antes esos números vivían en
   una tabla arriba y los arrumes 400 px más abajo, con el nombre del producto
   repetido en los dos sitios. */
.prod-fila {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 18px; cursor: pointer; list-style: none;
  border-bottom: 1px solid transparent;
}
.prod-fila::-webkit-details-marker { display: none; }
.prod-fila:hover { background: var(--superficie-2); }
details.producto[open] > .prod-fila {
  border-bottom-color: var(--linea); background: var(--superficie-2);
}
/* El triángulo lo dibujamos nosotros, con el mismo trazo del juego de iconos:
   el nativo cambia de forma en cada navegador. */
.prod-fila::before {
  content: ""; flex: 0 0 14px; height: 14px;
  background: no-repeat center/14px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7583' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18l6-6-6-6'/%3E%3C/svg%3E");
  transition: transform .15s ease;
}
details.producto[open] > .prod-fila::before { transform: rotate(90deg); }

.prod-nombre {
  flex: 1 1 220px; min-width: 0; font-weight: 600; font-size: 13.5px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
/* Ancho fijo: con `auto` cada fila calculaba el suyo según el número que
   tuviera dentro y las columnas no caían en la misma vertical. */
.prod-num { flex: 0 0 108px; text-align: right; }
.prod-num .etiqueta { display: block; font-size: 10.5px; }
.prod-num strong { font-size: 13.5px; font-variant-numeric: tabular-nums; }

/* La franja del pedido: quién y los tres números, en UNA línea.
   Antes eran un <h2> (32 px de margen) más tres tarjetas debajo, y entre lo
   uno y lo otro quedaban dos bandas de aire vacío que no decían nada. Tres
   números no necesitan tres cajas: necesitan una línea con separadores. */
.franja-pedido {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 28px;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  padding: 12px 18px; margin-bottom: 14px;
}
.franja-quien { display: flex; align-items: center; gap: 10px; flex: 1 1 220px; }
.franja-quien strong { display: block; font-size: 13.5px; }
.franja-quien .chip { margin-top: 2px; }

/* Separadores en vez de cajas: el borde de 1 px hace el mismo trabajo que
   tres marcos y ocupa la tercera parte. */
.franja-num {
  flex: 0 0 auto; min-width: 118px; padding-left: 24px;
  border-left: 1px solid var(--linea);
}
.franja-num .etiqueta { display: block; font-size: 10.5px; margin-bottom: 1px; }
.franja-num strong { font-size: 17px; font-variant-numeric: tabular-nums; }
.franja-num small { font-size: 11.5px; color: var(--tinta-suave); font-weight: 500; }

@media (max-width: 720px) {
  /* En el teléfono los separadores verticales no funcionan: se reparten de a
     dos por línea y la franja sigue siendo una sola tarjeta. */
  .franja-quien { flex: 1 1 100%; }
  .franja-num {
    flex: 1 1 calc(33% - 20px); min-width: 0; padding-left: 0; border-left: 0;
  }
}

@media (max-width: 720px) {
  /* En el teléfono los cuatro números no caben en una línea: se reparten de a
     dos y la fila sigue siendo legible sin scroll lateral. */
  .prod-num { flex: 1 1 calc(50% - 8px); text-align: left; }
  .prod-nombre { flex: 1 1 100%; }
}

/* Qué hacer ahora. No es un error ni un aviso: es la señal de que la pantalla
   está bien y falta un paso. */
.vacio.siguiente-paso {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--tinta-media);
}
.vacio.siguiente-paso .ico { color: var(--acento); margin-bottom: 4px; }
.vacio.siguiente-paso p { margin: 0; max-width: 46ch; }
.vacio.siguiente-paso strong { color: var(--tinta); }

.bloque-anular label { display: block; margin-bottom: 6px; }
.bloque-anular .fila-anular { gap: 8px; }
.bloque-anular .fila-anular input[type="text"] {
  height: var(--alto-control); font-size: 14px; flex: 1 1 320px; width: auto;
}
.bloque-anular .subtitulo { margin: 10px 0 0; }
/* Enlazar la orden de un recibo que llegó sin ella (11 sep 2026): se abre a
   pedido desde el subtítulo, en UNA fila. Sin el rojo de anular: es una
   corrección, no una baja. */
.bloque-enlazar { margin-bottom: 14px; padding: 12px 16px; }
.bloque-enlazar label { display: block; margin-bottom: 6px; }
.fila-enlazar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.fila-enlazar > .crece { flex: 1 1 320px; min-width: 0; }

/* Fila en modo edición: se distingue del resto sin gritar. */
tr.editando td { background: var(--acento-tenue); }
tr.editando:hover td { background: var(--acento-tenue); }
tr.editando input[type=text] { height: 32px; font-size: 13px; }
.campo-corto { max-width: 110px; }
tr.inactiva td:not(.acciones-col) { opacity: .55; }

/* Barra de rendimiento detrás del número. */
.rend {
  display: inline-block; padding: 3px 8px; border-radius: 5px;
  white-space: nowrap;   /* "100.0 %" se partía en dos renglones */
  font-variant-numeric: tabular-nums; font-weight: 600; font-size: 13px;
  background: linear-gradient(to right,
              rgba(15, 107, 69, .16) var(--pct), var(--neutro-fondo) var(--pct));
}

/* ===================================================================== chips */
/* El texto ya viene rotulado desde config.ROTULOS ("En proceso"), así que aquí
   no se transforma: solo se evita que parta en dos líneas. */
.chip {
  display: inline-block; padding: 3px 9px; border-radius: 5px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: var(--neutro-fondo); color: var(--neutro);
}
.chip.recibido            { background: var(--bien-fondo);    color: var(--bien); }
.chip.en_proceso          { background: var(--proceso-fondo); color: var(--proceso); }
.chip.agotado             { background: var(--neutro-fondo);  color: var(--neutro); }
.chip.anulado             { background: var(--alerta-fondo);  color: var(--alerta); }
.chip.entrada_produccion  { background: var(--bien-fondo);    color: var(--bien); }
.chip.salida_despacho     { background: var(--alerta-fondo);  color: var(--alerta); }
.chip.ajuste              { background: var(--proceso-fondo); color: var(--proceso); }
.chip.devolucion          { background: var(--neutro-fondo);  color: var(--neutro); }
.chip.hueso, .chip.piel, .chip.viscera, .chip.otro {
  background: var(--neutro-fondo); color: var(--neutro);
}

/* ===================================================================== vacío */
.vacio {
  background: var(--superficie); border: 1px dashed var(--linea-fuerte);
  border-radius: var(--r-caja); padding: 48px 24px; text-align: center;
}
.vacio p { color: var(--tinta-media); margin: 0 0 16px; }
.vacio-linea { color: var(--tinta-media); }

/* ================================================================== totales */
/* Los tres números que se firman contra la factura: facturado, pesado,
   recibido. Van arriba y grandes porque son la respuesta a la única pregunta
   que importa al cerrar un recibo. */
/* Cada cifra en su caja, con marco y aire alrededor. Antes era una rejilla
   pegada por líneas de 1 px, que se leía como una sola caja partida en
   pedazos; el cliente pidió "marcos que limitan". */
.totales {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px; margin-bottom: 12px;
}
.totales > div {
  background: var(--superficie); padding: 16px 18px;
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra);
  display: flex; flex-direction: column; gap: 6px;
  min-width: 0;
}
.totales .etiqueta {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600;
}
.totales .etiqueta small {
  text-transform: none; letter-spacing: 0; font-weight: 500; opacity: .8;
}
.totales .cifra {
  font-size: 26px; font-weight: 600; font-variant-numeric: tabular-nums;
  line-height: 1.1; color: var(--tinta);
}
.totales .cifra em { font-size: 12px; font-style: normal; font-weight: 500;
                     color: var(--tinta-suave); margin-left: 4px; }

/* ================================================= tabla de captura de arrumes */
/* Un renglón por arrume, como el formato en papel: se llena toda y se guarda
   una sola vez. */
/* ====================================================== bloque de producto */
/* Cada producto del pedido es un bloque cerrado: su identificación, su cuadre
   en una línea, y sus arrumes en rejilla. */
/* Todos los productos del recibo viven en UNA tarjeta. El marco y la sombra
   son de la lista, no de cada fila: así los dos productos de un mismo pedido
   se leen como lo que son -- dos renglones de lo mismo, no dos bloques
   sueltos. */
.lista-productos {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  overflow: hidden; overflow: clip; margin-bottom: 14px;
}
.producto {
  background: var(--superficie);
  border: 0; border-radius: 0; box-shadow: none; margin: 0;
}
/* La línea separa fila de fila; la última no la lleva o se duplicaría con el
   borde de la tarjeta. */
.lista-productos > .producto + .producto { border-top: 1px solid var(--linea); }
details.producto > *:not(.prod-fila) { padding-left: 20px; padding-right: 20px; }
details.producto > .prod-cab { padding-top: 14px; }
/* ⚠️ `:not(.oculto)` y NO `:last-child`. Con `:last-child` esto nunca se
   aplicaba: el último hijo del <details> es uno de los ~14 formularios
   ocultos que existen para corregir y anular cada arrume, así que la barra de
   botones quedaba pegada al borde -- medido: 0 px de aire -- y se veía
   encimada con el bloque de abajo. */
details.producto > form:not(.oculto),
details.producto > .arrumes-pie { padding-bottom: 16px; }
.producto-cab {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.producto-cab h2 { margin: 0; font-size: 17px; letter-spacing: -.01em; }
.producto-cab h2 .chip { vertical-align: middle; margin-left: 8px; font-size: 11px; }
.producto-id p {
  margin: 3px 0 0; font-size: 12.5px; color: var(--tinta-media);
}
.producto-id code {
  background: var(--neutro-fondo); padding: 1px 5px;
  border-radius: 4px; font-size: 11.5px;
}

/* El cuadre del producto en UNA línea: pesado − tara = recibido, contra
   facturado. Es la cuenta que se hace en el papel, escrita como se dice. */
.cuadre {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 14px; padding: 10px 14px;
  background: var(--superficie-2); border: 1px solid var(--linea);
  border-radius: var(--r-control);
  font-size: 13.5px; color: var(--tinta-media);
  font-variant-numeric: tabular-nums;
}
.cuadre b { color: var(--tinta); font-weight: 600; font-size: 15px; }
.cuadre .sep { color: var(--tinta-suave); }
.cuadre .resta { color: var(--alerta); }
.cuadre .resta small { color: var(--tinta-suave); }
.cuadre .dif.mal    { color: var(--alerta); }
.cuadre .dif.mal b  { color: var(--alerta); }
.cuadre .dif.bien   { color: var(--bien); }
.cuadre .dif.bien b { color: var(--bien); }
.cuadre .dif.exacto { color: var(--bien); font-weight: 600; }

/* ================================================== rejilla de arrumes ==== */
/* En lista vertical, 30 arrumes son 30 pantallazos. En rejilla caben ~10 por
   línea y se ven todos de un vistazo, que es como se lee el papel. */
/* Un arrume por fila, como el formato en papel. Las filas NO son un número
   fijo: se van agregando (ver estaticos/arrumes.js), porque nadie sabe cuántos
   arrumes trae el camión hasta que se acaba de bajar. */
.arrumes-tabla { margin-bottom: 12px; box-shadow: none; }
.arrumes-tabla tbody td { padding: 6px 14px; }
.arrumes-tabla tbody tr:hover { background: transparent; }
.arrumes-tabla th:first-child, .arrumes-tabla td:first-child { width: 90px; }
.arrumes-tabla th:nth-child(2), .arrumes-tabla td:nth-child(2) { width: 170px; }
.arrumes-tabla th:nth-child(3), .arrumes-tabla td:nth-child(3) { width: 140px; }
.arrumes-tabla input[type=text] {
  height: 34px; font-size: 15px; font-weight: 600; text-align: right;
  font-variant-numeric: tabular-nums;
}
.arrumes-tabla input.izq { text-align: left; font-weight: 400; font-size: 14px; }
.arrumes-tabla tr.fila-nueva td { background: var(--superficie-2); }
.arrumes-tabla tr.fila-nueva td.numeral { color: var(--acento); font-weight: 700; }

/* El guardado solo de cada arrume (11 sep 2026): la fila dice en qué va. */
.arrume-estado { font-size: 12px; font-weight: 600; margin-right: 8px; white-space: nowrap; }
.arrume-estado.guardando  { color: var(--tinta-suave); }
.arrume-estado.guardado   { color: var(--bien); }
.arrume-estado.sin-enviar { color: var(--proceso); }
.arrume-estado.error      { color: var(--alerta); white-space: normal; }
.arrumes-tabla tr[data-estado="error"] td      { background: var(--alerta-fondo); }
.arrumes-tabla tr[data-estado="sin-enviar"] td { background: var(--proceso-fondo); }
.arrumes-tabla tr[data-estado] input[readonly] { color: var(--tinta-media); }
.arrumes-tabla tr[data-estado] [data-agregar]  { display: none; }
/* Recién guardado: la fila se ilumina un momento y vuelve a ser una más. */
.arrumes-tabla tr.recien-guardada,
.arrumes-tabla tr.recien-guardada td { background: var(--bien-fondo); }
@media (max-width: 640px) {
  /* En la tarjeta del celular no cabe el texto junto a Corregir y Anular:
     basta la fila iluminada. */
  .arrumes-tabla tr.fila-guardada .arrume-estado { display: none; }
}

/* Lo que el guardado solo no pudo guardar se dice arriba, junto al total. */
.aviso-guardado {
  margin: 0 0 16px; padding: 12px 16px; border-radius: var(--r-control);
  border: 1px solid var(--linea-fuerte); background: var(--neutro-fondo);
  color: var(--tinta); font-size: 13.5px;
}
.aviso-guardado.error  { background: var(--alerta-fondo); border-color: #f0cdc6; color: #8f2718; }
.aviso-guardado.espera { background: var(--proceso-fondo); }
.aviso-guardado p  { margin: 0 0 8px; }
.aviso-guardado ul { margin: 0 0 10px; padding-left: 18px; }
.aviso-guardado .acciones-fila { display: flex; gap: 8px; flex-wrap: wrap; }
/* Recuperar lo que quedó en el celular (29 oct 2026): un renglón, botones a la derecha. */
.aviso-guardado.recuperar { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }
.aviso-guardado.recuperar p { margin: 0; flex: 1 1 260px; }
.aviso-guardado.recuperar .acciones-fila { flex: 0 0 auto; }
/* El «+» del arrume siguiente, debajo del último, en la columna del número. */
.arrumes-tabla tfoot .arrume-mas-fila td { padding-top: 6px; padding-bottom: 6px; }
.arrume-mas { min-width: 36px; justify-content: center; font-size: 16px; font-weight: 700; }
.insp-plegable .insp-temp { margin-left: 4px; }
.arrumes-tabla tfoot td {
  padding: 9px 14px; background: var(--superficie-2);
  border-top: 2px solid var(--linea-fuerte);
  font-variant-numeric: tabular-nums; font-size: 13px;
}

/* La banda del producto: cifras, ficha y acciones en una sola fila. Cada
   plegable cerrado es un elemento pequeño; el que se abre se lleva la fila
   entera para que su contenido no quede espachurrado en una columna. */
.prod-barra {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px 22px;
  margin-bottom: 6px;
}
.prod-barra > details[open] { flex: 1 1 100%; }
/* Totales del producto FIJOS al bajar por los arrumes (29 oct 2026): "que el
   total sea estático, para siempre tener control visual sobre los totales".
   Se pegan debajo de la barra de arriba (--alto-barra lo mide arrumes.js) y
   se sueltan al terminar el producto. Con «Datos del producto» abierto no se
   pegan: sería media pantalla fija. */
details.producto[open] > .prod-barra {
  position: sticky; top: var(--alto-barra, 0px); z-index: 6;
  background: var(--superficie);
  padding-top: 4px; padding-bottom: 4px; margin-bottom: 2px;
  border-bottom: 1px solid var(--linea);
}
details.producto[open] > .prod-barra:has(> details[open]) { position: static; }
/* En el celular, fija, en tres columnas y más apretada: en dos se llevaba
   casi un cuarto de la pantalla (197 px) encima de los arrumes. */
@media (max-width: 640px) {
  details.producto[open] > .prod-barra > .prod-cuenta {
    grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px 10px; padding: 0;
  }
  details.producto[open] > .prod-barra .prod-cuenta strong { font-size: 14px; }
  details.producto[open] > .prod-barra > .ficha-producto { margin-bottom: 0; }
}
.prod-barra > .prod-acciones.sueltas { margin: 0; }
/* Las cifras de ESTE producto, al final de la barra, detrás de "Editar"
   (el cliente, 11 sep 2026). Van primero en el HTML: `order` las manda a la
   derecha. En el teléfono, su propio renglón en dos columnas. */
.prod-barra > .prod-cuenta {
  order: 3; margin-left: auto;
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 4px 22px;
  padding: 4px 0;
}
.prod-cuenta .prod-num { display: flex; flex-direction: column; gap: 1px; }
/* Producto con "Terminar arrumes" (el cliente, 11 sep 2026): se ve, no se
   toca. Sin fila en blanco ni "+ Agregar arrume", sin Corregir/Anular,
   "Terminar" en gris y sin efecto, y a la vista "Editar arrumes" para
   corregir algo después. La clase la pone arrumes.js. */
.boton[data-editar-arrumes] { display: none; }
.producto.terminado .boton[data-editar-arrumes] { display: inline-flex; }
.producto.terminado tr.fila-nueva,
.producto.terminado [data-agregar],
.producto.terminado .acciones-col .boton,
.producto.terminado [data-ayuda-arrumes] { display: none !important; }
.producto.terminado .boton[data-terminar-producto] {
  background: var(--neutro-fondo); color: var(--tinta-suave);
  border-color: var(--linea); box-shadow: none; pointer-events: none;
}
.prod-cuenta .etiqueta {
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600; white-space: nowrap;
}
.prod-cuenta strong {
  font-size: 15px; font-weight: 650; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 640px) {
  .prod-barra > .prod-cuenta {
    margin-left: 0; flex-basis: 100%;
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 14px;
  }
}

/* Las cifras del producto, plegadas. Mismo criterio que la ficha: en la
   pantalla donde se pesa, lo que manda es el nombre y las casillas del peso.
   Estas cuatro cifras son el detalle de ESTE producto -- el total del recibo
   ya está arriba, en el tablero, a la vista y en grande. */
.prod-cifras { margin: 0 0 8px; }
.prod-cifras > summary {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 34px; cursor: pointer; list-style: none;
  font-size: 12.5px; font-weight: 600; color: var(--tinta-media);
}
.prod-cifras > summary::-webkit-details-marker { display: none; }
.prod-cifras > summary::before {
  content: "+"; font-size: 15px; line-height: 1; font-weight: 700;
  color: var(--acento);
}
.prod-cifras[open] > summary::before { content: "−"; }
.prod-cifras-rejilla {
  display: flex; flex-wrap: wrap; gap: 10px 28px; padding: 2px 0 6px;
}
@media (max-width: 640px) {
  /* En el teléfono el flex les daba un renglón a cada una y cuatro cifras
     cortas se llevaban cuatro líneas. En dos columnas son dos. */
  .prod-cifras-rejilla {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 14px;
  }
}

/* La ficha del producto, plegada. Siete datos de referencia que se consultan
   una vez y estorban las otras veinte: iban justo encima de las casillas donde
   se escribe el peso, y en el teléfono había que pasar de largo ~340 px para
   llegar a escribir. Cerrada ocupa una línea. */
.ficha-producto { margin-bottom: 10px; }
.ficha-producto > summary {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 36px; cursor: pointer; list-style: none;
  font-size: 12.5px; font-weight: 600; color: var(--tinta-media);
}
.ficha-producto > summary::-webkit-details-marker { display: none; }
.ficha-producto > summary::before {
  content: "+"; font-size: 15px; line-height: 1; color: var(--acento);
  font-weight: 700;
}
.ficha-producto[open] > summary::before { content: "−"; }
.ficha-producto[open] > summary { margin-bottom: 2px; }
.ficha-producto > .prod-cab { margin-bottom: 0; }

/* Peso facturado, lote y fechas de cada producto, ANTES de su primer arrume
   (el cliente, 11 sep 2026: "¿por qué no salen al principio?"). Solo existe
   mientras falte alguno de los cuatro; completo, desaparece y los datos
   quedan en la ficha. Con fondo propio: es lo primero que se llena, no una
   referencia más. */
.datos-factura {
  position: relative;
  margin: 0 0 10px; padding: 6px 14px 10px;
  background: var(--superficie-2); border: 1px solid var(--linea);
  border-radius: var(--r-control);
}
.datos-factura > summary {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px;
  min-height: 36px; cursor: pointer; list-style: none;
  font-size: 13px; font-weight: 600; color: var(--tinta);
}
.datos-factura > summary::-webkit-details-marker { display: none; }
.datos-factura > summary::before {
  content: "+"; font-size: 15px; line-height: 1; font-weight: 700;
  color: var(--acento);
}
.datos-factura[open] > summary::before { content: "−"; }
/* «Guardar datos» en el encabezado, arriba a la derecha (29 oct 2026). Vive
   dentro del formulario y se sube al renglón del título. */
.datos-factura[open] > summary { padding-right: 132px; }
.datos-factura-guardar { position: absolute; top: 8px; right: 14px; }
/* Mientras falte el rótulo, en vez de los arrumes. */
.arrumes-bloqueados {
  display: flex; align-items: center; gap: 8px; margin: 4px 0 12px;
  font-size: 13px; color: var(--tinta-media);
}
.datos-factura-campos {
  display: grid; gap: 10px 12px; align-items: end; margin-top: 6px;
  grid-template-columns: repeat(4, minmax(0, 1fr)) auto;
}
.datos-factura-campos > div { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.datos-factura-campos input { width: 100%; min-width: 0; }
@media (max-width: 760px) {
  /* En el teléfono, dos por renglón y el botón a lo ancho. */
  .datos-factura-campos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .datos-factura-campos > .al-final { grid-column: 1 / -1; }
  .datos-factura-campos > .al-final .boton { width: 100%; justify-content: center; }
}

/* Las acciones ya no viven dentro de la rejilla de datos: son trabajo, no
   referencia, y se quedan a la vista aunque la ficha esté plegada. */
.prod-acciones.sueltas {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 12px;
}

/* Encabezado pequeño del producto: sus datos en UNA línea, a todo el ancho. */
.prod-cab {
  display: flex; align-items: flex-end; gap: 20px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 12px;
  background: var(--superficie-2); border: 1px solid var(--linea);
  border-radius: var(--r-control);
}
.prod-dato { display: flex; flex-direction: column; gap: 2px; }
.prod-dato.ancho { min-width: 220px; }
.prod-dato .etiqueta {
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600;
}
.prod-dato strong { font-size: 14px; font-weight: 600; color: var(--tinta); }
.prod-acciones {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
}
.prod-acciones form { display: inline-flex; }

/* Fila de encabezado: todos los campos en una línea, usando toda la pantalla. */
.fila-encabezado {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
}
.fila-encabezado > div {
  display: flex; flex-direction: column; gap: 6px; flex: 1 1 150px;
  min-width: 130px;
}
.fila-encabezado > div.crece { flex: 2 1 220px; }
.fila-encabezado > div.al-final { flex: 0 0 auto; min-width: 0; }
.formulario.ancho-total { max-width: none; }

.acciones .empuja { flex: 1; }

kbd {
  background: var(--neutro-fondo); border: 1px solid var(--linea-fuerte);
  border-bottom-width: 2px; border-radius: 4px;
  padding: 0 5px; font-size: 11px; font-family: inherit; font-weight: 600;
}

/* Fila de "Agregar producto": todo en una línea, sin bajar la vista. */
.fila-producto {
  display: grid; gap: 12px; align-items: end;
  grid-template-columns: minmax(200px, 2fr) repeat(3, minmax(120px, 1fr)) auto;
}
.fila-producto > div { display: flex; flex-direction: column; gap: 6px; }
.fila-producto .al-final { justify-content: flex-end; }
.formulario:has(.fila-producto) { max-width: none; }

.oculto { display: none; }

.plegable-cuerpo {
  display: flex; flex-direction: column; gap: 14px;
  padding: 0 0 4px;
}

/* ================================================================= buscador */
/* Un <select> largo convertido en campo de busqueda por coincidencias.
   Lo monta estaticos/buscador.js; el <select> real sigue debajo, oculto, y es
   el que se envia. Si el JS no corre, .buscador-oculto nunca se aplica y se ve
   la lista desplegable de siempre. */
.buscador { position: relative; display: block; }
/* Lleva la MISMA flecha que un <select>: para quien usa la pantalla los dos
   son "una lista de la que escojo", y no tendría sentido que uno avise que se
   abre y el otro no. Va con `input.` delante porque `input[type=text]` pesa
   más que una clase sola y le borraría el fondo. */
input.buscador-campo {
  width: 100%; padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7583' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px 16px;
}
/* ⚠️ ESTE `display: none` ARREGLA UN DESBORDE REAL, no es cosmético.
   Antes se ocultaba con el truco de `position:absolute; width:1px; clip:...`,
   y NO funcionaba: `.rejilla-insp select { width: 100% }` está más abajo en
   esta misma hoja y con la misma especificidad, así que ganaba. El <select>
   de proveedor quedaba invisible pero midiendo 669 px y **empujaba la página
   283 px a la derecha**: era la causa del scroll horizontal en
   /recepciones/nueva, en TODOS los anchos, incluso en 1440.
   Medido con scrollWidth vs clientWidth, no a ojo.

   Un control con `display:none` SIGUE ENVIÁNDOSE en el formulario (solo
   `disabled` lo excluye), así que la mejora progresiva no se rompe: si el JS
   no corre, la clase nunca se aplica y se ve la lista desplegable de siempre.
   El selector lleva `.buscador >` para ganar por especificidad sin recurrir
   a !important. */
.buscador > select.buscador-oculto { display: none; }
.buscador-caja { position: relative; display: block; }

/* La × de quitar lo elegido. Solo aparece cuando hay algo que quitar: un
   botón permanente que a veces no hace nada enseña a ignorarlo. */
.buscador-borrar {
  position: absolute; right: 28px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 50%; background: var(--neutro-fondo);
  color: var(--tinta-media); cursor: pointer;
}
.buscador-borrar:hover { background: var(--linea-fuerte); color: var(--tinta); }
.buscador-borrar:focus-visible { outline: 2px solid var(--acento); outline-offset: 1px; }

/* Cabecera del panel: cuántas hay. Con 26 proveedores, sin este número no se
   sabe si se está viendo la lista entera o un pedazo. */
.buscador-cuenta {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 6px 10px; position: sticky; top: 0; z-index: 1;
  background: var(--superficie-2); border-bottom: 1px solid var(--linea);
  font-size: 11px; color: var(--tinta-suave);
}
.buscador-cuenta span { color: var(--tinta-suave); }

/* Fichas de lo ya elegido, en la selección múltiple. Van DEBAJO del campo y
   no dentro: dentro, con tres proveedores de nombre largo, el campo crecía
   hasta empujar la fila entera del filtro. */
.buscador-fichas {
  display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px;
}
.ficha {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 6px 3px 9px; border-radius: 999px;
  border: 1px solid var(--acento-tenue); background: var(--acento-tenue);
  color: var(--acento-fuerte); font: inherit; font-size: 11.5px; font-weight: 600;
  cursor: pointer; max-width: 100%;
}
.ficha:hover { border-color: var(--acento); }
.ficha .ico { opacity: .65; flex: 0 0 auto; }
.ficha:hover .ico { opacity: 1; }
.ficha:focus-visible { outline: 2px solid var(--acento); outline-offset: 1px; }

.buscador-panel {
  position: absolute; z-index: 40; top: calc(100% + 4px); left: 0; right: 0;
  /* El panel puede ser más ancho que su campo: "GAM POLLO(GRUPO DE ALIMENTOS
     MUNDIAL)" no cabe en una columna de 200 px, y partirlo en tres renglones
     hace la lista ilegible justo cuando hay que elegir rápido. */
  min-width: 300px; max-width: 480px;
  max-height: 320px; overflow-y: auto;
  background: var(--superficie); border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-control);
  box-shadow: 0 10px 28px rgba(20, 24, 29, .16);
}
/* 13 px y 7 px de aire: antes eran 14 y 9, y con 26 proveedores solo cabían
   seis en pantalla. Ahora caben nueve sin que se sienta apretado, que es lo
   que hace que una lista larga se pueda recorrer con la vista y no a ciegas
   con la rueda del ratón. */
.buscador-opcion {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; font-size: 13px; cursor: pointer; color: var(--tinta);
  border-bottom: 1px solid #f1f3f5; line-height: 1.35;
}
.buscador-opcion:last-child { border-bottom: 0; }
.buscador-opcion.marcada { background: var(--acento-tenue); }
/* Hueco reservado SIEMPRE, tenga chulo o no: si el espacio apareciera solo en
   la elegida, toda la lista se desplazaría al marcar una. */
.buscador-marca {
  flex: 0 0 14px; height: 14px; display: inline-flex;
  align-items: center; justify-content: center; color: var(--acento);
}
.buscador-texto { min-width: 0; overflow-wrap: anywhere; }
.buscador-opcion.elegida { color: var(--acento-fuerte); font-weight: 600; }
.buscador-opcion:hover { background: var(--superficie-2); }
.buscador-opcion.marcada:hover { background: var(--acento-tenue); }
.buscador-opcion mark {
  background: none; color: var(--acento); font-weight: 700; padding: 0;
}
.buscador-vacio {
  padding: 10px 12px; font-size: 13px; color: var(--tinta-suave);
}
/* En una tabla el panel no puede quedar recortado por el overflow. */
td .buscador-panel { min-width: 220px; }

/* Recepciones sin terminar de pesar: lo primero que tiene que ver quien entra,
   porque es trabajo a medias que alguien debe retomar. */
.panel.abiertas { border-color: var(--proceso); margin-bottom: 20px; }
.panel-titulo {
  padding: 10px 20px; border-bottom: 1px solid var(--linea);
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  font-weight: 600; color: var(--proceso); background: var(--proceso-fondo);
}
/* Las líneas divisorias van en cada .tira (borde), no en el fondo del
   contenedor: con `auto-fill` la última fila casi nunca completa todas las
   columnas, y un fondo compartido pintaba esas celdas vacías como una caja
   gris suelta -- se veía como una tarjeta rota. Con el borde en el elemento,
   una celda sin tarjeta simplemente no pinta nada. */
.tiras { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.tira {
  background: var(--superficie); padding: 14px 18px; text-decoration: none;
  display: flex; flex-direction: column; gap: 3px;
  border-right: 1px solid var(--linea); border-bottom: 1px solid var(--linea);
}
.tira:hover { background: var(--superficie-2); }
.tira-titulo  { font-weight: 600; color: var(--tinta); font-size: 15px; }
.tira-detalle { color: var(--tinta-media); font-size: 12.5px; }
.tira-cifra   { color: var(--tinta); font-size: 13px; font-variant-numeric: tabular-nums; }
.tira-accion  { color: var(--acento); font-size: 12.5px; font-weight: 600; margin-top: 4px; }

.titulo-fila h1 .chip { vertical-align: middle; margin-left: 8px; font-size: 11px; }

/* ============================================ el cuadre, en UNA sola línea
   Reemplaza las cuatro tarjetas de totales. Son los tres números que se
   miran mientras se pesa: lo que dice la factura, lo que va entrando y lo
   que falta. Lo demás del cálculo vive en el pie de cada producto, que es
   donde se está trabajando. */
.cuadre-tira {
  display: flex; flex-wrap: wrap; gap: 8px 32px; align-items: baseline;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); padding: 12px 18px; margin-bottom: 12px;
}
.cuadre-tira > div { display: flex; align-items: baseline; gap: 8px; }
.cuadre-tira span {
  font-size: 11.5px; color: var(--tinta-suave); text-transform: uppercase;
  letter-spacing: .05em; font-weight: 600;
}
.cuadre-tira strong { font-size: 19px; font-variant-numeric: tabular-nums; }

/* ⚠️ EL TELÉFONO. Medido a 390 px: la tira de totales se llevaba 167 px y la
   franja del pedido otros 149 -- 316 px, más de un tercio de la primera
   pantalla, para seis cifras. El problema es el reparto de escritorio
   (etiqueta y número en la misma línea, hueco de 32 px): en 375 px cada par
   se iba a su propio renglón. En columnas fijas caben los tres de un vistazo. */
@media (max-width: 640px) {
  .cuadre-tira {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px 10px; padding: 10px 12px; margin-bottom: 10px;
  }
  .cuadre-tira > div { flex-direction: column; align-items: flex-start; gap: 0; }
  .cuadre-tira span { font-size: 10px; letter-spacing: .03em; }
  .cuadre-tira strong { font-size: 16px; }
  .cuadre-tira strong.falta { font-size: 13px; }
  .cuadre-ayuda { grid-column: 1 / -1; margin: 2px 0 0; font-size: 12px; }

  /* La ficha con el número sobra en el teléfono: justo al lado dice
     "Pedido 4" con todas sus letras. Y el estado cabe en esa misma línea en
     vez de bajarse a la suya. */
  .franja-pedido { padding: 10px 12px; gap: 8px 10px; margin-bottom: 10px; }
  .franja-quien > .numero-pedido { display: none; }
  .franja-quien > div { display: flex; align-items: center; gap: 8px; }
  .franja-quien .chip { margin-top: 0; }
  .franja-num .etiqueta { font-size: 10px; }
  .franja-num strong { font-size: 16px; }
}

/* ========================================================================
   EL TABLERO DEL RECIBO
   ------------------------------------------------------------------------
   El único bloque oscuro de toda la aplicación, y es a propósito. Esta es la
   pantalla donde se trabaja de pie, con el celular en una mano y un camión
   bajando: en una pila de tarjetas blancas, esto dice "aquí es".
   Una sola cifra grande -- RECIBIDO, la que cambia cada dos minutos -- y tres
   referencias pequeñas al lado. Antes eran dos tiras con las mismas palabras
   repetidas y 186 px entre ambas.
   Las cifras van en `tabular-nums`: mientras se suman arrumes, los dígitos no
   pueden bailar de sitio a cada guardado.
   ======================================================================== */
.tablero {
  display: flex; align-items: center; flex-wrap: wrap; gap: 18px 32px;
  background: var(--tinta); color: #fff;
  border-radius: var(--r-caja); padding: 16px 22px; margin-bottom: 12px;
  box-shadow: 0 1px 2px rgba(20, 24, 29, .12), 0 8px 24px rgba(20, 24, 29, .16);
}
.tablero-hero { display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto; }
.tablero-etiqueta {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em;
  font-weight: 600;
  /* Sobre superficie oscura el texto secundario se saca del propio color de
     enfrente, nunca un gris genérico. */
  color: rgba(255, 255, 255, .62);
}
.tablero-cifra {
  font-size: 40px; font-weight: 650; line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tablero-cifra small {
  font-size: 15px; font-weight: 500; margin-left: 6px;
  color: rgba(255, 255, 255, .62);
}
/* Las canastas que lleva el recibo, junto a lo recibido (5 nov 2026). */
.tablero-canastas {
  display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto;
  padding-left: 24px; border-left: 1px solid rgba(255, 255, 255, .16);
}

/* Las referencias: fijas, pequeñas, separadas por un filete. */
.tablero-refs {
  display: flex; flex-wrap: wrap; gap: 10px 26px;
  flex: 1 1 auto; min-width: 0;
  /* Dos polos: la cifra que cambia ancla a la izquierda y las referencias
     fijas se van al canto derecho. Repartidas por el medio dejaban medio
     tablero vacío en un portátil y el bloque se leía como una fila de datos
     sueltos en vez de un instrumento. */
  justify-content: flex-end;
}
.tablero-ref {
  display: flex; flex-direction: column; gap: 1px;
  padding-left: 18px; border-left: 1px solid rgba(255, 255, 255, .16);
  min-width: 0;
}
.tablero-ref > span {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  font-weight: 600; color: rgba(255, 255, 255, .62);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tablero-ref > strong {
  font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* El número de la orden, pegado a su etiqueta: dice de dónde sale la cifra. */
.tablero-oc {
  display: inline-block; margin-left: 5px; padding: 1px 6px;
  border-radius: 4px; background: rgba(255, 255, 255, .14);
  color: #fff; font-weight: 700; letter-spacing: .02em;
}
/* Los dos tonos que sí se usan sobre el oscuro: subidos en luminosidad para
   que pasen contraste, porque el verde y el rojo del sistema están calibrados
   contra blanco y sobre negro se apagan. */
.tablero-menos { color: #ff9b8b; }
.tablero-mas   { color: #7ee0b0; }
.tablero-pendiente {
  font-size: 13px; font-weight: 600; font-style: italic;
  color: #ffc46b;
}

@media (max-width: 640px) {
  /* En el teléfono la cifra manda todavía más: es lo que se mira de reojo
     entre arrume y arrume, sin acercarse el aparato a la cara. */
  .tablero { gap: 12px 18px; padding: 14px 16px; }
  .tablero-hero { flex: 1 1 auto; }
  .tablero-canastas { padding-left: 16px; }
  .tablero-cifra { font-size: 34px; }
  .tablero-refs { flex: 1 1 100%; gap: 8px 14px; }
  .tablero-ref { flex: 1 1 0; padding-left: 12px; }
  .tablero-ref > span { font-size: 9.5px; white-space: normal; }
  .tablero-ref > strong { font-size: 15px; }
}

/* La franja de la orden, ya sin números: solo dice contra qué llegó. */
.franja-pedido.escueta { padding: 10px 16px; }
.franja-ir {
  margin-left: auto; font-size: 12.5px; font-weight: 600;
  color: var(--acento); white-space: nowrap;
}

/* La inspección plegada: el veredicto se ve siempre, el resto solo si se
   pide. Es lo que se decidió con el camión en la puerta, no algo que se
   consulte veinte veces mientras se pesa. */
.insp-plegable { margin-top: 0; margin-bottom: 12px; }
.insp-plegable > summary { display: flex; align-items: center; gap: 10px; }
.insp-plegable > summary::before { content: none; }
.insp-plegable .insp-resumen { padding: 0 20px 14px; margin: 0; }

/* ------------------------------------------------------- quién está dentro */
.sesion { display: flex; align-items: center; gap: 10px; margin-left: 16px; }
.sesion-quien { text-align: right; line-height: 1.25; min-width: 0; }
.sesion-quien strong { display: block; font-size: 12.5px; color: var(--tinta); }
.sesion-quien small  { display: block; font-size: 11px; color: var(--tinta-suave); }

@media (max-width: 860px) {
  /* En el teléfono el nombre y el cargo no caben al lado de "Salir" y se
     montaban encima. Se va el texto y queda solo el icono de salir: quién
     entró se ve en el panel de Usuarios, y en un turno lo sabe la persona
     que tiene el teléfono en la mano. */
  .sesion { margin-left: auto; gap: 0; }
  .sesion-quien { display: none; }
  /* Solo el icono: la palabra "Salir" ya no cabe y el icono se entiende. */
  .salir span { display: none; }
  .salir { padding: 0 10px; }
}
.salir { gap: 6px; }

/* El botón "Novedades" de la barra (12 sep 2026). La chispa en el color de la
   marca; el punto dice "hay algo que no has visto" y lo prende novedades.js. */
.novedades-boton { position: relative; gap: 6px; }
.boton.novedades-boton .ico { margin-right: 0; color: var(--acento); }
/* ⚠️ Era un punto de 8 px sin número: el cliente, 18 sep 2026, lo comparó con
   un punto que "pasa desapercibido" frente al globo de WhatsApp. Ahora es un
   globo con el número de entregas sin ver -- 0 lo esconde (novedades.js le
   pone `hidden`). */
.novedades-punto {
  position: absolute; top: -6px; left: 20px;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--acento); box-shadow: 0 0 0 2px var(--chrome);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 10px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 860px) {
  /* Como "Salir": solo el icono, que ya se entiende. */
  .novedades-boton span { display: none; }
  .novedades-boton { padding: 0 10px; }
  .novedades-punto { left: 18px; }
}

/* "Quién más está aquí", en vivo (18 sep 2026, presencia.js). Empieza
   `hidden` en el HTML -- nadie lo escribe, lo pinta el websocket apenas
   alguien más aparece en la misma sala. Tono neutro/proceso para "aquí
   también hay alguien"; `.alerta` (rojo) para el caso que sí importa
   corregir: dos personas recibiendo la MISMA orden en recibos distintos. */
.presencia-aviso {
  margin: 0 0 12px; padding: 8px 14px; border-radius: var(--r-control);
  background: var(--proceso-fondo); color: var(--proceso);
  font-size: 12.5px; font-weight: 600;
}
.presencia-aviso.alerta { background: var(--alerta-fondo); color: var(--alerta); }
/* Dentro de la tarjeta de "Por llegar": `.tarjeta-registro` es flex-wrap, así
   que sin `flex: 1 1 100%` este aviso se metería en la misma fila que
   "Productos"/"Se encargó", peleando el ancho en vez de ir debajo del
   proveedor, en su propia línea. */
.tarjeta-registro .presencia-aviso { flex: 1 1 100%; margin: 2px 0 0; }

/* La clave temporal: se ve una vez y se copia. Monoespaciada y grande porque
   se dicta o se transcribe a mano. */
.clave-temporal {
  background: var(--proceso-fondo); border: 1px solid var(--proceso);
  border-radius: var(--r-caja); padding: 16px 18px; margin-bottom: 20px;
}
.clave-temporal strong {
  display: block; margin-top: 4px;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 24px; letter-spacing: .06em; color: var(--tinta);
  user-select: all;
}
.clave-temporal .campo-etiqueta { color: var(--proceso); }
.clave-temporal p { margin: 10px 0 0; font-size: 12.5px; color: var(--tinta-media); }

.tarjeta-registro.inactiva { opacity: .6; }
.registro-extra { flex: 0 0 auto; }

/* ================================================================== acceso
   Entrar / cambiar contraseña. Tarjeta partida: el formulario a la izquierda
   y la ilustración a la derecha, que se va la primera cuando no hay ancho.
   ========================================================================== */
.acceso {
  min-height: calc(100vh - 120px);
  display: flex; align-items: center; justify-content: center;
  padding: 20px 0;
}
.acceso-tarjeta {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  width: min(920px, 100%); overflow: hidden;
  background: var(--superficie);
  border: 1px solid var(--linea); border-radius: 18px;
  box-shadow: 0 12px 40px rgba(20, 24, 29, .10);
}

/* Cambiar contraseña no lleva foto. `sola` se usaba en la plantilla pero no
   existía aquí, así que la rejilla seguía partida en dos y la mitad derecha
   quedaba en blanco: una tarjeta de 920 px con el formulario arrinconado. */
.acceso-tarjeta.sola {
  grid-template-columns: minmax(0, 1fr);
  width: min(470px, 100%);
}

.acceso-forma { padding: 40px 44px; display: flex; flex-direction: column; }
.acceso-marca { display: flex; align-items: center; gap: 10px; margin-bottom: 32px; }
.acceso-marca img { border-radius: 50%; box-shadow: 0 0 0 1px var(--linea); }
.acceso-marca strong { font-size: 15px; letter-spacing: -.01em; }

.acceso-forma h1 { font-size: 26px; margin: 0; letter-spacing: -.02em; }
.acceso-sub { color: var(--tinta-media); font-size: 14px; margin: 4px 0 24px; }

.acceso-campos { display: flex; flex-direction: column; gap: 16px; }
.acceso-campos label {
  display: block; margin-bottom: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--tinta);
}
.acceso-campos input {
  width: 100%; height: 48px; font-size: 15px; border-radius: 10px;
}
.boton.ancho { width: 100%; justify-content: center; margin-top: 6px; }

/* --- campo con icono adentro ---------------------------------------------
   Solo en las pantallas de acceso. En los formularios de operación NO: allí
   hay ocho campos por pantalla y ocho iconos serían ruido; aquí hay dos y son
   lo que separa una casilla diseñada de un cuadro de texto suelto. */
.campo { position: relative; }
.campo > .ico-campo {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  color: var(--tinta-suave); pointer-events: none;
  transition: color .15s ease;
}
/* El icono se tiñe con el campo enfocado: confirma dónde está el cursor sin
   agregar un segundo elemento que avise. */
.campo:focus-within > .ico-campo { color: var(--acento); }
.campo > input { padding-left: 44px; }
.campo.con-ojo > input { padding-right: 48px; }

/* El ojo. Nace `hidden` en el HTML y lo destapa clave.js: sin JavaScript un
   botón que no hace nada es peor que no tener botón. */
.ojo {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--tinta-suave); cursor: pointer;
  transition: color .15s ease, background-color .15s ease;
}
.ojo:hover { color: var(--tinta); background: var(--neutro-fondo); }
.ojo:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

.acceso-nota {
  margin: 20px 0 0; font-size: 12.5px; color: var(--tinta-suave); text-align: center;
}
/* "¿Olvidaste tu contraseña?" y "Volver a Iniciar sesión": sin esto salían
   en el azul por defecto del navegador. */
.acceso-nota a {
  color: var(--tinta); font-weight: 600; text-underline-offset: 3px;
}
.acceso .aviso { margin: 0 0 16px; }

/* --- la portada: las tres fotos girando --- */
.acceso-arte { position: relative; min-height: 460px; background: var(--acento-fuerte); }
.laminas { position: absolute; inset: 0; }
.lamina {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .8s ease;
}
/* Solo se anima la opacidad: es lo que el compositor puede mover sin
   recalcular el diseño en cada cuadro. */
.lamina.visible { opacity: 1; }

/* Vela al pie: los puntos son blancos y una de las fotos termina en una mesa
   de acero clara, donde desaparecían. Con este degradado se ven sobre
   cualquiera de las tres, ahora y cuando se cambien por otras. */
.acceso-arte::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 90px;
  background: linear-gradient(to bottom, rgba(20, 24, 29, 0), rgba(20, 24, 29, .45));
  z-index: 1; pointer-events: none;
}

.puntos {
  position: absolute; left: 0; right: 0; bottom: 16px; z-index: 2;
  display: flex; justify-content: center; gap: 8px;
}
/* Se anima `transform`, no `width`: cambiar el ancho obliga al navegador a
   recalcular el diseño en cada cuadro, mientras que `scale` lo resuelve el
   compositor. La escala es UNIFORME a propósito -- estirar solo en X un
   círculo con `border-radius` lo deforma en un óvalo con las puntas mal. */
.punto {
  width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .55); cursor: pointer;
  transition: transform .2s ease, background .2s ease;
}
.punto.activo { background: #fff; transform: scale(1.45); }
.punto:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
/* El punto es de 8 px pero el dedo necesita 44: el área se agranda por fuera
   con un pseudo-elemento, sin engordar el punto que se ve. */
.punto { position: relative; }
.punto::after { content: ""; position: absolute; inset: -18px -7px; }

/* En el teléfono la portada NO desaparece: se vuelve una franja arriba del
   formulario y sigue girando. Es la cara de la aplicación y el cliente la
   quiere también ahí. */
@media (max-width: 780px) {
  .acceso { min-height: 0; padding: 0; }
  .acceso-tarjeta { grid-template-columns: 1fr; }
  /* ⚠️ La proporción de la franja es la MISMA de las fotos (3:2), y por eso
     no se recorta nada. Con una altura fija (190 px) quedaba una tira mucho
     más apaisada que la imagen, `cover` recortaba arriba y abajo, y a las
     operarias se les cortaba la cabeza. Mover `object-position` solo cambiaba
     por dónde cortaba: el encuadre no era el problema, la proporción sí.
     Si algún día se cambian las fotos por otras que no sean 3:2, hay que
     cambiar este número al de las nuevas. */
  .acceso-arte { min-height: 0; height: auto; aspect-ratio: 3 / 2; order: -1; }
  .acceso-arte::after { height: 70px; }
  .puntos { bottom: 12px; }
  .acceso-forma { padding: 26px 22px 30px; }
}

/* Sin movimiento para quien lo pidió en su sistema: se queda la primera
   imagen fija y los puntos siguen sirviendo para cambiarla a mano. */
@media (prefers-reduced-motion: reduce) {
  .lamina { transition: none; }
}

/* --- entrar solo con el correo (29 oct 2026) ------------------------------ */
.acceso-volver {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  margin: -8px 0 14px -8px; padding: 6px 8px; border-radius: var(--r-control);
  font-size: 13px; font-weight: 600; color: var(--tinta-media); text-decoration: none;
}
.acceso-volver:hover { color: var(--tinta); background: var(--neutro-fondo); }
.acceso-enviado { margin: 12px 0 20px !important; }
.acceso-enviado b { font-weight: 700; word-break: break-all; }
/* Seis cajas grandes y espaciadas: se copia del correo mirando de a un número. */
.acceso-campos input.campo-codigo {
  height: 56px; text-align: center;
  font-size: 24px; font-weight: 700; letter-spacing: .5em; padding-left: .5em;
  font-variant-numeric: tabular-nums;
}
button.enlace {
  border: 0; background: none; padding: 4px; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--tinta);
  text-decoration: underline; text-underline-offset: 3px;
}
button.enlace:hover { color: var(--acento-fuerte); }
.acceso { flex-direction: column; gap: 18px; }
.acceso-pie { margin: 0; font-size: 12.5px; color: var(--tinta-suave); text-align: center; }
.acceso-pie a { color: var(--tinta-media); font-weight: 600; text-underline-offset: 3px; }
.acceso-pie a:hover { color: var(--tinta); }
@media (max-width: 780px) {
  .acceso-pie { padding: 0 16px 20px; }
}

/* --- aviso de cookies ----------------------------------------------------
   Franja oscura abajo, centrada; en el teléfono sube por encima de la barra
   de secciones para no tapar lo que se toca con el pulgar. */
.aviso-cookies {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 90;
  display: flex; align-items: center; gap: 14px;
  max-width: 620px; margin: 0 auto; padding: 12px 12px 12px 18px;
  background: var(--tinta); color: #fff; border-radius: var(--r-caja);
  box-shadow: 0 18px 44px -16px rgba(20, 24, 29, .55);
}
.aviso-cookies[hidden] { display: none; }
.aviso-cookies p { flex: 1; min-width: 0; margin: 0; font-size: 13px; line-height: 1.45; color: rgba(255, 255, 255, .86); }
.aviso-cookies a { color: #fff; font-weight: 600; text-underline-offset: 3px; white-space: nowrap; }
.aviso-cookies .boton { flex-shrink: 0; background: #fff; color: var(--tinta); }
.aviso-cookies .boton:hover { background: var(--neutro-fondo); }
@media (max-width: 780px) {
  .aviso-cookies { bottom: calc(76px + env(safe-area-inset-bottom)); flex-wrap: wrap; }
  .aviso-cookies .boton { width: 100%; justify-content: center; }
  .aviso-cookies.sin-barra { bottom: calc(12px + env(safe-area-inset-bottom)); }
}

/* --- política de cookies -------------------------------------------------- */
.politica { width: min(760px, 100%); margin: 0 auto; padding: 8px 0 40px; }
.politica-arriba {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 16px;
}
.politica-arriba .acceso-volver { margin: 0 0 0 -8px; }
.politica-arriba .acceso-marca { margin: 0; }
.politica-hoja {
  background: var(--superficie); border: 1px solid var(--linea); border-radius: 18px;
  box-shadow: 0 12px 40px rgba(20, 24, 29, .08);
  padding: 36px 40px 40px;
}
.politica-hoja h1 { font-size: 28px; margin: 0; letter-spacing: -.02em; }
.politica-fecha { margin: 4px 0 0; font-size: 13px; color: var(--tinta-suave); }
.politica-hoja section { margin-top: 28px; }
.politica-hoja h2 { font-size: 16.5px; margin: 0 0 8px; letter-spacing: -.01em; text-transform: none; color: var(--tinta); }
.politica-hoja p { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--tinta-media); max-width: 68ch; }
.politica-hoja code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; font-weight: 600; color: var(--tinta); overflow-wrap: anywhere;
}
.politica-ficha {
  display: grid; grid-template-columns: 130px 1fr; gap: 10px 20px; margin: 4px 0 0;
  padding: 16px 18px; border: 1px solid var(--linea); border-radius: 12px;
  font-size: 14px;
}
.politica-ficha dt { font-weight: 600; color: var(--tinta-suave); }
.politica-ficha dd { margin: 0; color: var(--tinta); }
.politica-lista {
  list-style: none; margin: 4px 0 0; padding: 0;
  border: 1px solid var(--linea); border-radius: 12px;
}
.politica-lista li {
  display: grid; grid-template-columns: minmax(0, 270px) 1fr; gap: 6px 20px;
  padding: 14px 18px; font-size: 14px; color: var(--tinta-media);
}
.politica-lista li + li { border-top: 1px solid var(--linea); }
@media (max-width: 640px) {
  .politica { padding: 4px 0 24px; }
  .politica-hoja { padding: 24px 20px 28px; border-radius: 14px; }
  .politica-hoja h1 { font-size: 24px; }
  .politica-ficha { grid-template-columns: 1fr; gap: 2px; }
  .politica-ficha dd { margin-bottom: 10px; }
  .politica-ficha dd:last-child { margin-bottom: 0; }
  .politica-lista li { grid-template-columns: 1fr; }
}

/* ==================================================================== tabs
   Filtro principal de una lista. Son enlaces, no controles: cada pestaña es
   una URL que se puede compartir y recargar. */
.tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  margin: 0 0 16px; padding-bottom: 2px;
  border-bottom: 1px solid var(--linea);
}
.tabs a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 14px; border-radius: var(--r-control) var(--r-control) 0 0;
  color: var(--tinta-media); text-decoration: none;
  font-size: 13px; font-weight: 600; white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -3px;
}
.tabs a:hover { color: var(--tinta); background: var(--neutro-fondo); }
.tabs a.sel { color: var(--acento-fuerte); border-bottom-color: var(--acento); }
.tab-cuenta {
  display: inline-block; min-width: 17px; padding: 0 5px;
  border-radius: 999px; background: var(--acento); color: #fff;
  font-size: 10.5px; font-weight: 700; text-align: center; line-height: 17px;
  font-variant-numeric: tabular-nums;
}
/* El rojo se guarda para lo que hay que atender HOY. Cuatro pestañas con
   cuatro números rojos no señalan nada: si todo urge, nada urge. Las demás
   informan en gris. */
.tab-cuenta.calma {
  background: var(--neutro-fondo); color: var(--tinta-media);
}
.tabs a.sel .tab-cuenta.calma { background: var(--acento-tenue); color: var(--acento-fuerte); }

/* ================================================ navegación inferior (móvil)
   Al alcance del pulgar y siempre visible: con el menú de hamburguesa no
   había forma de saber en qué sección estabas sin abrirlo. En escritorio no
   se muestra -- la barra de arriba ya lo resuelve. */
.nav-inferior { display: none; }

@media (max-width: 860px) {
  .nav-inferior {
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    /* 45 y no 30: la hoja de "Más" sale de aquí y tiene que quedar por
       ENCIMA del micrófono y del chat flotantes (41), que si no se le
       montan encima. La barra en sí no estorba a ninguno: están arriba
       de ella, no sobre ella. */
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    background: var(--superficie);
    border-top: 1px solid var(--linea);
    box-shadow: 0 -2px 10px rgba(20, 24, 29, .06);
    /* El área segura del indicador de gestos, si el teléfono la tiene. */
    padding: 6px 8px max(6px, env(safe-area-inset-bottom));
  }
  .nav-inferior > a,
  .nav-inferior > .nav-mas > summary {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 6px 2px; min-height: 52px; border-radius: 12px;
    color: var(--tinta-media); text-decoration: none;
    font-size: 11px; font-weight: 600; text-align: center; line-height: 1.2;
    /* ⚠️ ESTAS TRES LÍNEAS SON LAS QUE EVITAN QUE SE SOBREPONGAN LOS TEXTOS.
       Sin `min-width: 0` una casilla de rejilla NO se encoge por debajo de su
       contenido: "Órdenes de compra" empujaba a la de al lado y los rótulos
       se montaban unos sobre otros (el cliente, 18 sep 2026, con la captura:
       "eso es impresentable"). Los rótulos ya son cortos, pero esto lo sostiene
       aunque mañana entre uno largo. */
    min-width: 0;
    list-style: none; cursor: pointer;
  }
  .nav-inferior > a > span,
  .nav-inferior > .nav-mas > summary > span {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .nav-inferior > .nav-mas > summary::-webkit-details-marker { display: none; }
  .nav-inferior a.sel,
  .nav-inferior > .nav-mas > summary.sel { background: var(--acento-tenue); color: var(--acento-fuerte); }
  .nav-inferior .ico { flex: 0 0 auto; }

  /* En un teléfono angosto (360 px) cuatro casillas dan 90 px cada una: la
     letra baja un punto y el icono manda. Nunca se quitan los rótulos: un
     icono solo, sin palabra, se adivina. */
  @media (max-width: 380px) {
    .nav-inferior > a,
    .nav-inferior > .nav-mas > summary { font-size: 10px; padding: 6px 1px; }
  }

  /* "Más": la hoja que sube cuando hay más secciones de las que caben.
     Es un <details>, así que abre y cierra sin JavaScript. */
  .nav-mas { position: relative; }
  .nav-mas-hoja {
    position: absolute; bottom: calc(100% + 10px); right: 0;
    min-width: 200px; padding: 6px;
    background: var(--superficie); border: 1px solid var(--linea);
    border-radius: var(--r-caja); box-shadow: 0 -6px 24px rgba(20, 24, 29, .18);
  }
  .nav-mas-hoja a {
    /* ⚠️ `flex-direction: row` VA EXPLÍCITO. La regla general `nav a` (la del
       menú de arriba, con el icono ARRIBA del rótulo) también alcanza a estos
       enlaces, porque están dentro de un <nav>. Como aquí no se declaraba la
       dirección, ganaba la de allá y la hoja salía en columnas gigantes.
       Se vio mirando el estilo calculado en el navegador, no leyendo el CSS. */
    display: flex; flex-direction: row; align-items: center;
    justify-content: flex-start; gap: 10px;
    padding: 11px 12px; border-radius: 10px; min-height: 44px; min-width: 0;
    color: var(--tinta); text-decoration: none; font-size: 14px; font-weight: 600;
  }
  .nav-mas-hoja a.sel { background: var(--acento-tenue); color: var(--acento-fuerte); }
  .nav-mas-hoja a:active { background: var(--superficie-2); }

  /* Que la barra no tape el final del contenido. */
  main { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
  footer { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }

}

/* ============================================================ volver atrás
   Va ARRIBA y a la IZQUIERDA, solo, antes del título. Antes vivía como
   `.boton.fantasma` dentro del grupo de acciones de la derecha, junto a
   "Cerrar pedido" y "Anular": ahí el ojo lee todo el bloque como acciones
   sobre el registro, no como navegación, y el enlace de volver quedaba
   siendo lo más callado de la pantalla. La salida nunca es lo más callado. */
.volver {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 12px; padding: 6px 10px 6px 6px; border-radius: var(--r-control);
  color: var(--tinta-media); text-decoration: none;
  font-size: 13px; font-weight: 600;
}
.volver:hover { background: var(--neutro-fondo); color: var(--tinta); }
.volver:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }
.volver .ico { flex: 0 0 auto; }

/* En el teléfono NO se fija: quedaba flotando como una píldora suelta encima
   del contenido. La salida siempre disponible es la barra inferior, que
   muestra la sección actual y lleva a su listado de un toque. */

/* ============================================================================
   TARJETA DE REGISTRO
   Un renglón de lista que NO es una fila de tabla. La tabla apretaba nueve
   columnas del mismo tamaño y no dejaba ver qué era importante; aquí cada
   dato es una etiqueta gris pequeña CON ICONO arriba y el valor en negrita
   debajo, que es la jerarquía que hace que una lista se lea de un vistazo.
   ========================================================================== */
.registros { display: flex; flex-direction: column; gap: 12px; }

.tarjeta-registro {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  /* 22 px a la izquierda en TODAS, tengan espina o no: si solo lo llevaran
     las marcadas, el nombre del proveedor arrancaría en dos verticales
     distintas dentro de la misma lista. */
  padding: 12px 18px 12px 22px;
  position: relative; overflow: hidden;
  transition: box-shadow .18s cubic-bezier(.2, .8, .3, 1),
              border-color .18s cubic-bezier(.2, .8, .3, 1);
}

/* ======================= EL ESTADO SE VE ANTES DE LEER =====================
   Quien recorre esta lista con el celular en una mano y una canasta en la
   otra hace UNA pregunta: "¿tengo que hacer algo con esta?". Antes la
   respuesta estaba en un chip de 11 px abajo a la izquierda, y había que
   buscarla tarjeta por tarjeta.
   Ahora la lista tiene DOS PLANOS. Lo que pide trabajo se adelanta:
   superficie blanca, sombra, y una espina de color pegada al canto. Lo que ya
   está hecho retrocede: se apoya en el fondo, pierde la sombra y baja el
   contraste. La lista se ordena sola ante el ojo, sin leer una palabra.

   ⚠️ LA ESPINA VA SOLO EN LAS QUE PIDEN TRABAJO. Una franja de color en cada
   tarjeta es decoración: en cuanto la lleva la lista entera deja de señalar
   nada. Puesta únicamente donde hay que actuar, es lo que el ojo busca.
   ⚠️ El rojo de "atrasado" es el mismo familiar del acento de la marca, y por
   eso aquí NUNCA aparece como relleno: la acción principal es un botón
   relleno, el estado es una espina de 4 px. Se distinguen por la FORMA, que
   es la regla del sistema (HANDOFF §7), no por el tono.
   ⚠️ Y el color nunca va solo: el chip sigue diciéndolo con palabras. */
.tarjeta-registro::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: transparent;
}
.tarjeta-registro.trabajo::before { background: var(--proceso); }
.tarjeta-registro.urgente::before { background: var(--alerta); }

/* Lo terminado retrocede al fondo. No es "gris apagado": es una tarjeta que
   deja de competir por la atención con las que sí piden algo. */
.tarjeta-registro.hecho,
.tarjeta-registro.parcial,
.tarjeta-registro.fuera {
  background: var(--superficie-2); box-shadow: none;
}
.tarjeta-registro.hecho .registro-campos strong,
.tarjeta-registro.parcial .registro-campos strong { color: var(--tinta-media); }
/* Anulada: sigue estando, porque la Res. 242/2013 no deja borrar registros,
   pero se lee como lo que es -- algo que ya no cuenta. */
.tarjeta-registro.fuera { border-style: dashed; }
.tarjeta-registro.fuera .registro-identidad strong,
.tarjeta-registro.fuera .registro-campos strong { color: var(--tinta-suave); }

/* La ficha del número es el primer glifo de la tarjeta: que lleve el estado
   encima ahorra el viaje del ojo hasta el chip de abajo. */
.tarjeta-registro.trabajo .numero-pedido { background: var(--proceso-fondo); color: var(--proceso); }
.tarjeta-registro.urgente .numero-pedido { background: var(--alerta-fondo);  color: var(--alerta); }
.tarjeta-registro.hecho   .numero-pedido { background: var(--bien-fondo);    color: var(--bien); }
.tarjeta-registro.parcial .numero-pedido { background: var(--proceso-fondo); color: var(--proceso); }

/* Solo donde hay ratón: en táctil el resaltado se queda pegado tras el toque. */
@media (hover: hover) {
  .tarjeta-registro.trabajo:hover,
  .tarjeta-registro.urgente:hover {
    box-shadow: 0 1px 2px rgba(20, 24, 29, .04), 0 6px 16px rgba(20, 24, 29, .09);
    border-color: var(--linea-fuerte);
  }
}

/* Quién. Ancla la fila: es lo primero que se busca al barrer la lista.
   ⚠️ ANCHO FIJO, no `min-width`. Con min-width la columna crecía con el
   largo del nombre ("BUCANERO" 210 px vs "MAC POLLO MEDELLIN (AVSA SA)"
   301 px) y los campos de cada tarjeta arrancaban en una x distinta: medido,
   tres posiciones diferentes en seis tarjetas. En una lista, las columnas
   tienen que caer en la misma vertical o se ve rota. */
.registro-identidad {
  display: flex; align-items: center; gap: 10px;
  flex: 0 0 200px; width: 200px; min-width: 0;
}
.avatar {
  width: 32px; height: 32px; flex: 0 0 32px; border-radius: 50%;
  background: var(--acento-tenue); color: var(--acento-fuerte);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px;
}

/* El número del pedido ocupa el sitio del avatar, y no es decoración: es el
   dato con el que se habla del pedido por teléfono. Cuadrado y no redondo
   para que se lea como una ficha numerada y no como la inicial de un nombre;
   ancho mínimo fijo para que el 7 y el 128 no muevan la columna de al lado. */
/* "Recibiendo el pedido 3": un HECHO, no un campo. Se llegó aquí desde ese
   pedido, así que no se vuelve a preguntar cuál es. */
.pedido-fijado {
  display: flex; align-items: center; gap: 12px;
  margin: 0 0 14px; padding: 10px 16px;
  background: var(--dato-fondo); border: 1px solid var(--dato-linea);
  border-radius: var(--r-caja); color: var(--dato);
}
.pedido-fijado > div { flex: 1 1 auto; min-width: 0; }
.pedido-fijado strong { display: block; font-size: 13.5px; color: var(--dato); }
.pedido-fijado span { font-size: 12.5px; color: var(--tinta-media); }
.pedido-fijado a {
  flex: 0 0 auto; font-size: 12.5px; font-weight: 600;
  color: var(--tinta-media); text-decoration: underline;
}
.pedido-fijado a:hover { color: var(--tinta); }

.numero-pedido {
  min-width: 34px; height: 32px; flex: 0 0 auto; padding: 0 7px;
  border-radius: 8px;
  background: var(--neutro-fondo); color: var(--tinta);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; font-variant-numeric: tabular-nums;
}
/* Llegó sin pedido: la ficha se queda (para que la columna no baile) pero en
   voz baja, porque no hay número que leer. */
.numero-pedido.vacio {
  background: none; border: 1px dashed var(--linea-fuerte);
  color: var(--tinta-suave); font-weight: 500;
}
.registro-identidad > div { min-width: 0; }
/* Peso 600 y no el 700 que trae <strong> por defecto. Con ocho tarjetas
   seguidas, todas con el nombre en negrita plena y en mayúsculas, la lista se
   leía como un bloque negro: el cliente lo describió como "muy cargado". El
   nombre sigue siendo lo primero que se ve, por posición y tamaño. */
.registro-identidad strong {
  display: block; font-size: 12.5px; font-weight: 600;
  color: var(--tinta); line-height: 1.3;
  overflow-wrap: anywhere; min-width: 0;
}
.registro-identidad small  { display: block; font-size: 11.5px; color: var(--tinta-suave); margin-top: 1px; }

/* Los datos. `auto-fit` para que se repartan solos según lo que quepa. */
.registro-campos {
  flex: 1 1 320px; min-width: 0;
  display: grid; gap: 8px 20px;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
}
.campo { min-width: 0; }
.campo-etiqueta {
  display: flex; align-items: center; gap: 4px;
  font-size: 11px; color: var(--tinta-suave); margin-bottom: 1px;
}
.campo-etiqueta .ico { flex: 0 0 auto; }
.campo strong {
  display: block; font-size: 12.5px; font-weight: 600; color: var(--tinta);
  font-variant-numeric: tabular-nums;
  /* ⚠️ Aquí decía `overflow-wrap: anywhere` y partía los valores por la
     mitad: la factura MMMMMM025 salía como "MMMMMM0" y "25" debajo, que se
     lee como OTRA factura. Estos cuatro campos son todos piezas indivisibles
     -- una fecha, un código, un conteo, unos kilos. Si no cabe, se recorta
     con puntos suspensivos, que dice "hay más" en vez de mentir, y el valor
     completo queda en el `title` y en la pantalla de detalle. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ⚠️ ANCHO FIJO, igual que la identidad. Con `flex: 0 0 auto` el bloque medía
   187 px con "Continuar" y 160 px con "Abrir", así que cada fila le dejaba
   distinto espacio a la rejilla del medio y las columnas 2 a 5 se corrían
   entre 6 y 22 px. Dos columnas fijas: el chip y el botón caen siempre en la
   misma vertical, midan lo que midan sus textos. */
.registro-acciones {
  display: grid; grid-template-columns: 96px 140px;
  gap: 10px; align-items: center; flex: 0 0 auto;
}
.registro-acciones .chip {
  justify-self: stretch; text-align: center;
  overflow: hidden; text-overflow: ellipsis;
}
.registro-acciones .boton { width: 100%; justify-content: center; }
/* Variante de cuatro columnas (Usuarios): chip · editar · reiniciar ·
   desactivar. Cada <form> es una celda de la rejilla y el botón la llena; no
   hace falta `display: contents`, que sobre un <form> es terreno resbaloso. */
.registro-acciones.cuatro { grid-template-columns: 96px 88px 140px 112px; }
/* Recibo sin terminar: chip · continuar pesaje · editar. */
.registro-acciones.con-editar { grid-template-columns: 96px 168px 96px; }
/* Órdenes de compra (11 sep 2026): el estado dice "Aún sin recibir" y no
   cabía en 96 px; el botón dice "Editar" o "Abrir", que piden menos. */
.registro-acciones.orden { grid-template-columns: 132px 112px; }
/* "Ver detalles" (12 sep 2026): una columna más, justo después del estado.
   Donde no aplica (una orden que aún no recibe nada) queda el hueco, para
   que "Abrir" y "Editar" caigan en la misma vertical en toda la lista. */
.registro-acciones.orden.con-detalles { grid-template-columns: 132px 120px 104px; }
.registro-acciones.con-detalles:not(.orden):not(.con-editar) { grid-template-columns: 96px 120px 140px; }
.registro-acciones.con-editar.con-detalles { grid-template-columns: 96px 120px 168px 96px; }

/* El botón: de contorno suave y más bajo que la acción de la tarjeta, para
   no competir con "Abrir" ni con "Continuar pesaje". La "i" va en el color
   de los datos, que es lo que abre. */
.boton.detalles-boton {
  height: 32px; padding: 0 10px; font-size: 12.5px;
  background: var(--superficie); color: var(--tinta-media);
  border-color: var(--linea);
}
.boton.detalles-boton:hover {
  background: var(--superficie-2); color: var(--tinta); border-color: var(--linea-fuerte);
}
.boton.detalles-boton .ico { margin-right: 5px; color: var(--dato); }
.detalles-boton .corto { display: none; }

/* Los tramos de "Por recibir" y "Por llegar" (12 sep 2026): la lista va por
   cuándo llega y cada tramo lleva su rótulo con su número. Lo atrasado en el
   rojo de alerta y lo de hoy en ámbar: los colores de la espina. */
.grupo-lista {
  display: flex; align-items: center; gap: 8px;
  margin: 12px 0 -4px; font-size: 11.5px; line-height: 1.4; font-weight: 650;
  text-transform: uppercase; letter-spacing: .06em; color: var(--tinta-media);
}
.grupo-lista:first-child { margin-top: 0; }
.grupo-lista.atrasado { color: var(--alerta); }
.grupo-lista.hoy { color: var(--proceso); }

/* "Ver más" (12 sep 2026): el historial se trae de a 30. */
.ver-mas {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin: 16px 0 4px;
}
.ver-mas p { margin: 0; font-size: 12.5px; color: var(--tinta-suave); }
/* "Ver más" baja a la primera tarjeta nueva: que no quede bajo la barra. */
.tarjeta-registro { scroll-margin-top: 84px; }
/* La tarjeta que se está editando se vuelve formulario, en su mismo sitio. */
.registros > .formulario { margin: 0; }
.editar-titulo { margin: 0 0 14px; font-size: 14px; font-weight: 600; color: var(--tinta); }

/* Seguimiento (historial de uso, 11 sep 2026): solo lo ve el desarrollador. */
.seguimiento-tabla { width: 100%; margin-bottom: 20px; }
.seguimiento-tabla td { vertical-align: top; font-size: 13px; }
.seguimiento-vivo { color: var(--bien); }
.seguimiento-fallo { color: var(--alerta); }
.seguimiento-tabla th { white-space: nowrap; }
.seguimiento-tabla .seg-hora { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Seguimiento en celular y tableta (12 sep 2026). El cliente: "el responsivo
   de la sección de seguimiento se ve horrible, mira los títulos". Cuatro y
   cinco columnas en 390 px partían todo a mitad de palabra ("HO RA",
   "PERSO NA", "06: 43: 25"), y como así "cabían", tabla_movil.js nunca las
   pasaba a tarjetas. Aquí cada fila es un bloque: quién y cuándo arriba, lo
   demás debajo con su etiqueta chica. Las tablas llevan data-tarjetas="no". */
@media (max-width: 900px) {
  .seguimiento-tabla thead { display: none; }
  .seguimiento-tabla, .seguimiento-tabla tbody { display: block; width: 100%; }
  .seguimiento-tabla tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    gap: 6px 14px; padding: 12px 16px; border-bottom: 1px solid var(--linea);
  }
  .seguimiento-tabla tr:last-child { border-bottom: 0; }
  .seguimiento-tabla td {
    display: block; min-width: 0; padding: 0; border: 0;
    overflow-wrap: normal; word-break: normal; font-size: 13px;
  }
  .seguimiento-tabla td[data-etiqueta]::before {
    content: attr(data-etiqueta); display: block;
    font-size: 10px; font-weight: 600; letter-spacing: .06em;
    text-transform: uppercase; color: var(--tinta-suave);
  }
  /* Última conexión: nombre y "en línea" arriba; entró y actividad abajo. */
  .seg-conexiones .seg-ahora { grid-column: 2; grid-row: 1; text-align: right; }
  /* Hoy por persona: el nombre arriba y sus cuatro cifras en fila. */
  .seg-resumen tr { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .seg-resumen .seg-persona { grid-column: 1 / -1; }
  .seg-resumen td.num { text-align: left; }
  /* Lo que han hecho: hora y persona en un renglón; qué hizo debajo, en
     grande; dónde y desde, chicos y con la etiqueta al lado. */
  .seg-eventos tr { grid-template-columns: auto minmax(0, 1fr); gap: 3px 10px; }
  .seg-eventos .seg-hora { grid-column: 1; font-weight: 600; color: var(--tinta); }
  .seg-eventos .seg-persona { grid-column: 2; }
  .seg-eventos .seg-que { grid-column: 1 / -1; font-size: 14px; color: var(--tinta); }
  .seg-eventos td[data-etiqueta] { grid-column: 1 / -1; font-size: 12px; }
  .seg-eventos td[data-etiqueta]::before { display: inline; margin-right: 6px; }
}
/* Seguimiento rehecho como el de Blue Len (26 oct 2026): un resumen arriba y una
   ficha por persona. Mismas superficies y tamaños del resto de la app: nada de
   cifras grandes ni barras. */
.seg-resumen-barra {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra); margin: 0 0 16px;
}
.seg-resumen-barra > div { padding: 14px 18px; min-width: 0; display: grid; gap: 2px; align-content: start; }
.seg-resumen-barra > div + div { border-left: 1px solid var(--linea); }
.seg-resumen-barra strong { font-size: 20px; line-height: 1.2; color: var(--tinta); font-variant-numeric: tabular-nums; }
.seg-resumen-barra small { font-size: 12.5px; color: var(--tinta-suave); overflow-wrap: anywhere; }
.seg-rotulo { font-size: 12.5px; color: var(--tinta-media); }
.seg-fichas { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; align-items: start; }
.seg-ficha {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); box-shadow: var(--sombra);
  padding: 14px 18px 16px; display: grid; gap: 12px; min-width: 0;
}
.seg-ficha.sin-entrar { background: transparent; box-shadow: none; border-style: dashed; }
.seg-ficha.sin-entrar .seg-quien strong { color: var(--tinta-media); }
.seg-cabeza { display: flex; align-items: center; gap: 12px; }
.seg-quien { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.seg-nombre { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.seg-nombre strong { font-size: 15px; color: var(--tinta); }
.seg-quien small { font-size: 12.5px; color: var(--tinta-suave); overflow-wrap: anywhere; }
.seg-cabeza .boton { flex: 0 0 auto; }
.seg-viendo {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 8px 12px;
  background: var(--bien-fondo); color: var(--bien); border-radius: var(--r-control);
  font-size: 13.5px;
}
.seg-viendo strong { color: var(--bien); }
.seg-datos {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0;
}
.seg-datos > div {
  background: var(--superficie-2); border: 1px solid var(--linea);
  border-radius: var(--r-control); padding: 8px 10px; min-width: 0;
}
.seg-datos dt { font-size: 12px; color: var(--tinta-suave); }
.seg-datos dd { margin: 2px 0 0; font-size: 14px; font-weight: 600; color: var(--tinta); }
.seg-datos dd small { display: block; font-size: 12px; font-weight: 400; color: var(--tinta-suave); overflow-wrap: anywhere; }
.seg-ultimo { margin: 0; font-size: 13px; color: var(--tinta-suave); }
.seg-ultimo strong { color: var(--tinta-media); font-weight: 600; }
.seg-sub {
  margin: 0; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--tinta-suave);
}
.seg-revisado { list-style: none; margin: -4px 0 0; padding: 0; display: grid; }
.seg-revisado li {
  display: flex; justify-content: space-between; gap: 12px; align-items: baseline;
  padding: 7px 0; border-bottom: 1px solid #eef0f3; font-size: 13.5px;
}
.seg-revisado li:last-child { border-bottom: 0; }
.seg-revisado li span:first-child { min-width: 0; overflow-wrap: anywhere; }
.seg-revisado .suave { flex: 0 0 auto; font-size: 12.5px; text-align: right; }
.seg-fallos {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 8px 12px;
  background: var(--alerta-fondo); color: var(--alerta); border-radius: var(--r-control);
  font-size: 13px;
}
@media (max-width: 900px) {
  .seg-fichas { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .seg-resumen-barra { grid-template-columns: minmax(0, 1fr); }
  .seg-resumen-barra > div + div { border-left: 0; border-top: 1px solid var(--linea); }
  .seg-datos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .seg-cabeza { flex-wrap: wrap; }
  .seg-cabeza .boton { margin-left: 44px; }
}
/* El recorrido de una persona: un cuadro más ancho que el de «Ver detalles»
   (detalles.js le pone `es-recorrido`), conexión por conexión. */
@media (min-width: 760px) {
  .detalles-capa.es-recorrido .detalles-caja { width: min(900px, 100%); }
}
.recorrido .rec-conexion {
  display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline;
  text-transform: none; letter-spacing: normal; font-size: 14px; color: var(--tinta-media);
}
.recorrido .rec-conexion strong { color: var(--tinta); font-size: 15px; }
.recorrido .rec-tabla { margin-bottom: 8px; }
.recorrido .rec-tabla .seg-que { overflow-wrap: anywhere; }
.recorrido .rec-clic .seg-que { color: var(--dato); }
.recorrido .rec-clic .seg-que .suave { color: var(--tinta-suave); }
.recorrido .seguimiento-fallo { color: var(--alerta); font-weight: 600; }
/* En el cuadro de recorrido las filas son un renglón: hora, qué y dónde. */
@media (max-width: 900px) {
  .rec-tabla tr { grid-template-columns: auto minmax(0, 1fr); gap: 3px 10px; }
  .rec-tabla .seg-hora { grid-column: 1; font-weight: 600; color: var(--tinta); }
  .rec-tabla .seg-que { grid-column: 2; font-size: 14px; color: var(--tinta); }
  .rec-tabla td[data-etiqueta] { grid-column: 1 / -1; font-size: 12px; }
  .rec-tabla td[data-etiqueta]::before { display: inline; margin-right: 6px; }
}
/* "Dónde está" es el dato de la tarjeta: no se corta. En el celular, dos
   columnas en vez de cuatro, y el texto parte renglón si hace falta. */
.seguimiento-vivos .campo strong { white-space: normal; overflow: visible; text-overflow: clip; }
@media (max-width: 640px) {
  .seguimiento-vivos .registro-campos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Administración (11 sep 2026): usuarios, roles y permisos, y seguimiento,
   en tres tarjetas. Solo la ve el desarrollador. */
.admin-tarjetas {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.admin-tarjeta {
  display: flex; flex-direction: column; gap: 6px; padding: 18px 20px;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); color: var(--tinta); text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.admin-tarjeta:hover {
  border-color: var(--linea-fuerte);
  box-shadow: 0 4px 16px rgba(20, 24, 29, .08);
}
.admin-tarjeta strong { font-size: 16px; }
.admin-tarjeta > span:last-child { font-size: 13px; line-height: 1.45; color: var(--tinta-media); }
.admin-icono {
  width: 40px; height: 40px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--acento-tenue); color: var(--acento);
}
/* Roles y permisos: una fila por persona, una casilla por módulo. */
.tabla-desplaza { overflow-x: auto; }
.tabla-permisos { width: 100%; }
/* Los nombres se parten por palabras, nunca por la mitad ("Administrad /
   or"): la regla general de tablas angostas deja partir cualquier letra. */
.tabla-permisos th, .tabla-permisos td { overflow-wrap: normal; word-break: normal; }
.tabla-permisos td small { display: block; font-size: 12px; color: var(--tinta-suave); }
.tabla-permisos .centro { text-align: center; width: 104px; }
@media (max-width: 640px) { .tabla-permisos .centro { width: 84px; } }
/* Los tres grupos de columnas: «Puede editar en», «Solo ve» y «Entra a». Una
   línea fina separa cada grupo; el título va un poco más oscuro que el de la
   columna para que se lea primero. */
.tabla-permisos .grupos th { color: var(--tinta-media); padding-bottom: 4px; border-bottom: 0; }
.tabla-permisos .grupos th.centro { border-bottom: 2px solid var(--linea-fuerte); }
.tabla-permisos .grupo-aparte { border-left: 1px solid var(--linea); }
.tabla-permisos input[type=checkbox] {
  width: 20px; height: 20px; accent-color: var(--acento); cursor: pointer;
}
/* Factura o remisión (11 sep 2026): dos opciones cortas, a la altura de los
   campos de al lado. */
fieldset.opciones-documento { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset.opciones-documento legend {
  padding: 0; margin-bottom: 6px;
  font-weight: 600; font-size: 12.5px; color: var(--tinta);
}
.opciones-documento .opciones {
  display: flex; align-items: center; gap: 18px; min-height: var(--alto-control);
}
.opciones-documento label {
  display: inline-flex; align-items: center; gap: 7px;
  font-weight: 500; font-size: 14px; cursor: pointer;
}
.opciones-documento input[type=radio] {
  width: 18px; height: 18px; margin: 0; accent-color: var(--acento);
}

/* El icono dentro de un botón acompaña al texto, nunca lo reemplaza. */
.boton .ico { margin-right: 6px; }

@media (max-width: 860px) {
  .tarjeta-registro { gap: 12px; padding: 14px 16px; }
  .registro-identidad { min-width: 100%; }
  /* ⚠️ CUATRO columnas fijas, no `auto-fit`. Con auto-fit y un mínimo de
     110 px, a 515 px de pantalla solo cabían tres y el cuarto dato se iba a
     un segundo renglón: la tarjeta crecía y la lista obligaba a hacer scroll.
     Con cuatro columnas explícitas siempre es una sola fila. */
  .registro-campos {
    flex-basis: 100%; gap: 8px 10px;
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .registro-acciones { flex-basis: 100%; }
  .registro-acciones .boton { flex: 1 1 auto; justify-content: center; }
  /* ⚠️ Las columnas fijas de Usuarios no caben angostas: con solo tres
     (96+140+112) ya se salían 22 px por la derecha a 375 px. Aquí el chip
     conserva su ancho y los botones se reparten lo que quede. */
  .registro-acciones.cuatro { grid-template-columns: 88px repeat(3, minmax(0, 1fr)); }
  .registro-acciones.con-editar { grid-template-columns: 88px repeat(2, minmax(0, 1fr)); }
}
/* En el teléfono cuatro en fila no caben ("Reiniciar clave" sola pide 120 px):
   dos por renglón, el estado y Editar arriba. */
@media (max-width: 640px) {
  .registro-acciones.cuatro { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Sin terminar: el estado y Editar arriba; "Continuar pesaje", que es lo
     que se pulsa, abajo y a lo ancho. */
  .registro-acciones.con-editar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .registro-acciones.con-editar .continuar { grid-column: 1 / -1; order: 1; }
}
/* "Ver detalles" en pantallas angostas: las columnas se reparten el ancho. */
@media (max-width: 860px) {
  .registro-acciones.orden.con-detalles { grid-template-columns: minmax(0, 1.25fr) repeat(2, minmax(0, 1fr)); }
  .registro-acciones.con-detalles:not(.orden):not(.con-editar) { grid-template-columns: 88px repeat(2, minmax(0, 1fr)); }
  .registro-acciones.con-editar.con-detalles { grid-template-columns: 88px repeat(3, minmax(0, 1fr)); }
}
/* Sin terminar, en el teléfono: estado · detalles · Editar arriba, y
   "Continuar pesaje" abajo y a lo ancho, como antes. */
@media (max-width: 640px) {
  .registro-acciones.con-editar.con-detalles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* A 390 px caben tres botones si se aprietan un poco: "Detalles" a secas,
   y menos relleno a los lados. Medido: "Aún sin recibir" pide 113 px. */
@media (max-width: 460px) {
  .detalles-boton .largo { display: none; }
  .detalles-boton .corto { display: inline; }
  .registro-acciones.con-detalles .boton { padding: 0 8px; }
  .registro-acciones.orden.con-detalles { grid-template-columns: minmax(0, 1.3fr) repeat(2, minmax(0, 1fr)); }
}
/* ⚠️ En el teléfono, LOS CUATRO DATOS EN UNA FILA.
   Antes iba uno por línea "para que las etiquetas no se cortaran", y el
   resultado fue una tarjeta de 180 px de alto: con cuatro recibos había que
   hacer scroll para ver la lista completa. El cliente lo pidió al revés y
   tiene razón — son cuatro valores cortos (una fecha, un código, un número y
   unos kilos) y caben.
   La etiqueta baja a 10 px y el valor a 12,5: se sigue leyendo, y la tarjeta
   pasa de cuatro renglones a uno. */
@media (max-width: 460px) {
  .registro-campos { gap: 6px 8px; }
  .registro-campos .campo-etiqueta { font-size: 9.5px; gap: 2px; }
  /* El icono de cada etiqueta sale: en 85 px de columna se come el espacio
     del texto que sí informa. */
  .registro-campos .campo-etiqueta .ico { display: none; }
  .registro-campos .campo strong { font-size: 12px; line-height: 1.25; }
}

/* Aquí vivía el bloque MAESTRO-DETALLE (lista lateral + panel de detalle,
   con su botón de contraer y su propio scroll). Se eliminó: la lista se
   veía desordenada, al contraerse se montaba sobre el contenido, y no
   coincidía con el diseño de tarjetas del resto. Recepción MP usa ahora
   las mismas .tarjeta-registro que Pedidos, y el recibo es página completa. */

/* Ficha de datos que se leen, no se editan: etiqueta arriba, valor abajo. */
.ficha {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--linea);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  overflow: hidden; margin-bottom: 20px;
}
.ficha > div {
  background: var(--superficie); padding: 12px 16px;
  display: flex; flex-direction: column; gap: 5px;
  font-size: 13.5px; align-items: flex-start;
}
.ficha .etiqueta {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600;
}

/* Línea de contexto bajo el título: quién, qué y cuándo, sin un párrafo. */
.subtitulo {
  color: var(--tinta-media); font-size: 13.5px; margin: -8px 0 20px;
}
.subtitulo code {
  background: var(--neutro-fondo); padding: 1px 5px;
  border-radius: 4px; font-size: 12px;
}

/* Lo que casi nunca se toca va plegado: corregir la etiqueta del proveedor no
   puede competir con el campo de pesar. */
.plegable {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); margin-top: 24px;
}
.plegable > summary {
  padding: 12px 20px; cursor: pointer; font-size: 13px; font-weight: 600;
  color: var(--tinta-media); list-style: none;
}
.plegable > summary::before { content: "＋ "; color: var(--tinta-suave); }
.plegable[open] > summary::before { content: "－ "; }
.plegable > summary:hover { color: var(--tinta); }
.plegable .formulario {
  border: 0; border-top: 1px solid var(--linea);
  border-radius: 0; box-shadow: none; margin: 0; max-width: none;
}

footer {
  max-width: 1800px; margin: 0 auto; padding: 0 24px 40px;
  color: var(--tinta-suave); font-size: 11.5px;
}
footer code {
  background: var(--neutro-fondo); padding: 1px 5px;
  border-radius: 4px; font-size: 11px;
}

/* ==========================================================================
   CUMPLIMIENTO NORMATIVO (Resolución 242 de 2013)
   --------------------------------------------------------------------------
   Los veredictos son ESTADOS, así que usan los tintes apagados de siempre y
   nunca el acento: el acento es solo de la acción principal.
   ========================================================================== */
.chip.conforme       { background: var(--bien-fondo);   color: var(--bien); }
.chip.fuera_de_rango { background: var(--alerta-fondo); color: var(--alerta); }
.chip.sin_dato       { background: var(--neutro-fondo); color: var(--neutro); }

/* Un dato que la norma exige y todavía no está. No grita: informa. */
.falta { color: var(--tinta-suave); font-weight: 500; font-style: italic; }

/* --- anular (nunca borrar): pide el motivo en la misma fila -------------- */
.fila-anular { display: flex; gap: 4px; align-items: center; }
.fila-anular input[type="text"] {
  height: 28px; font-size: 12px; padding: 0 8px; width: 180px;
}
.fila-anulando > td { background: var(--alerta-fondo); }
.fila-anulando input[type="text"] { width: 100%; }
.acciones-fila { display: flex; gap: 8px; align-items: center; padding: 8px 12px; }

.anulada-tabla { opacity: .75; }
.anulada-tabla td:first-child,
.anulada-tabla td:nth-child(2) {
  text-decoration: line-through; text-decoration-color: var(--tinta-suave);
}

.titulo-menor {
  font-size: 13px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--tinta-media); margin: 24px 0 8px;
}

/* ==========================================================================
   TABLERO
   ========================================================================== */
.totales.secundarios { margin-top: -8px; }
.totales.secundarios .cifra-menor {
  display: block; font-size: 20px; font-weight: 600;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}

.tarjetas-kpi { margin: 12px 0 24px; }
.tarjeta-kpi {
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-caja); padding: 16px; box-shadow: var(--sombra);
}
.tarjeta-kpi .cifra-menor {
  display: block; font-size: 28px; font-weight: 700;
  line-height: 1.1; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.tarjeta-kpi .etiqueta { display: block; margin-top: 4px; }
.tarjeta-kpi small { display: block; margin-top: 4px; color: var(--tinta-suave); font-size: 11.5px; }
/* Un contador en cero es una buena noticia: solo se tine el que tiene algo. */
.tarjeta-kpi.mal { border-color: #f0cdc6; background: var(--alerta-fondo); }
.tarjeta-kpi.mal .cifra-menor { color: var(--alerta); }

/* ==========================================================================
   LA PREGUNTA HABLADA (orden de compra por voz)
   El cliente, 18 sep 2026, sobre el bloque rojo que salía cuando faltaba un
   dato: "eso se ve horrible, parece un error, al usuario no le gusta eso".
   Y que falte un dato NO es un error de la persona: es una conversación a
   medias. Así que no va en rojo de alerta sino en el AZUL DE DATO, que en
   esta app significa "información", y con el disco del micrófono delante --
   el mismo del botón de dictar -- para que se lea como "te estoy hablando",
   no como "hiciste algo mal".
   ========================================================================== */
.voz-pregunta {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--dato-fondo); border: 1px solid var(--dato-linea);
  border-radius: var(--r-caja); padding: 14px 16px; margin: 0 0 16px;
}
.voz-pregunta-disco {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--superficie); color: var(--dato);
}
.voz-pregunta > div { min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.voz-pregunta-texto {
  margin: 0; color: var(--tinta); font-size: 15.5px; line-height: 1.4;
  /* Es una frase hablada, no un párrafo: se lee de un vistazo o no sirve. */
  max-width: 46ch; text-wrap: balance;
}
.voz-pregunta-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
/* Cuando `play()` dice que sí pero no se oye nada: en el iPhone el interruptor
   lateral de silencio apaga el audio de la web sin avisar. Callarlo deja a la
   persona esperando un sonido que no va a llegar. */
.voz-mudo {
  margin: 0; font-size: 12.5px; color: var(--ambar); font-weight: 600;
}
.voz-pregunta-acciones .boton { gap: 6px; }
/* "Contestar hablando" se sostiene igual que el botón flotante: si uno se
   sostiene y el otro se toca, vuelve la confusión que el cliente reportó. */
.voz-pregunta-acciones [data-responder-voz] {
  touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.voz-pregunta-acciones [data-responder-voz].escuchando {
  background: var(--alerta); border-color: var(--alerta);
}

@media (max-width: 480px) {
  /* En el teléfono el botón de contestar se lleva la fila entera: es el que
     se toca con guantes y con el celular en una mano. */
  .voz-pregunta { padding: 12px 13px; }
  .voz-pregunta-acciones .boton { flex: 1 1 100%; justify-content: center; }
}

/* ==========================================================================
   DASHBOARD  (reconstruido 18 sep 2026)
   Las reglas de la reconstrucción, en CSS. El razonamiento completo está en
   src/plantillas/dashboard.html; aquí solo lo que obliga la hoja:
   - una sola cosa teñida de rojo por pantalla (lo pendiente) y una sola
     tarjeta teñida (el OTIF, la única con meta). Si se tiñe todo, no resalta
     nada;
   - la FLECHA de la comparación dice para dónde va el número y el COLOR dice
     si eso conviene: en "Comprado", subir es gastar más.
   ========================================================================== */
/* Cuatro cifras y no más (Ley de Miller). `.tarjetas` sola usa `auto-fit`, que
   en pantalla ancha abría cinco o seis columnas y dejaba las tarjetas flacas. */
.tarjetas.cuatro { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.tarjetas.cuatro .cifra { font-size: 26px; font-weight: 700; }
.tarjetas.cuatro small {
  color: var(--tinta-suave); font-size: 11.5px; line-height: 1.35;
}
.tarjetas .var { font-weight: 600; }
.tarjetas .var.bueno { color: var(--bien); }
.tarjetas .var.malo  { color: var(--alerta); }
.tarjeta.meta-bien { border-color: #bfe0cd; }
.tarjeta.meta-mal  { border-color: #f0cdc6; background: var(--alerta-fondo); }
.tarjeta.meta-mal .cifra { color: var(--alerta); }

/* Pendiente ahora. Va primero y es lo único con marco rojo: al abrir, la
   vista tiene que caer aquí. */
.panel.hoy { border-color: #f0cdc6; }
.panel.hoy .panel-cabeza {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 13px 20px; background: var(--alerta-fondo);
  border-bottom: 1px solid #f0cdc6;
}
.panel.hoy .panel-cabeza h2 {
  margin: 0; font-size: 13px; color: var(--alerta);
  text-transform: uppercase; letter-spacing: .05em;
}
.panel.hoy .panel-cabeza .suave { font-size: 12px; }
.hoy-lista { list-style: none; margin: 0; padding: 0; }
.hoy-lista li + li { border-top: 1px solid var(--linea); }
/* Cada línea es un enlace entero, no un "ver" al final: lo urgente se abre
   con un toque, también con guantes. */
.hoy-lista a {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 20px; text-decoration: none; color: var(--tinta);
}
.hoy-lista a:hover { background: var(--superficie-2); }
.hoy-lista .suave { font-size: 12.5px; }

/* Las barras nacieron dentro de la burbuja del asistente, que es angosta: la
   etiqueta se corta a 130 px. A lo ancho del dashboard eso dejaba "PECHUGA
   GRANEL ..." y "PECHUGA CAMPESI..." -- dos productos distintos que se leen
   igual. Aqui la etiqueta puede respirar. */
/* De 641 px para arriba, no siempre: en el telefono la regla de 640 deja la
   etiqueta en 84 px para que la BARRA se vea, y esta (mas especifica) se la
   comia -- quedaba el nombre largo y una barra de dos pixeles. */
@media (min-width: 641px) {
  .asistente-grafico.grafico-ancho .asistente-grafico-fila {
    grid-template-columns: minmax(120px, 260px) 1fr auto;
  }
}

/* "¿De donde salen estos numeros?" -- la prueba de cada cifra, dentro de la
   app. El cliente: "esa mierda, ¿de donde la estas sacando? Eso no dice
   nada". Un porcentaje sin las filas que lo componen hay que creerlo, y en
   una planta no se firma lo que no se puede revisar. */
.de-donde { margin-top: 4px; margin-bottom: 24px; }
.de-donde > summary { font-size: 13.5px; color: var(--dato); }
.de-donde > summary::before { color: var(--dato); }
.de-donde-cuerpo { padding: 4px 20px 20px; border-top: 1px solid var(--linea); }
.de-donde-cuerpo h3 {
  font-size: 13px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--tinta-media); margin: 22px 0 6px;
}
.de-donde-cuerpo > h3:first-child { margin-top: 18px; }
.de-donde-cuerpo .ayuda-bloque { margin: 0 0 10px; }
.de-donde-cuerpo table { margin-bottom: 4px; }
/* El total de la tabla, con el mismo peso que la cifra de la tarjeta: es lo
   que permite comprobar de un vistazo que las dos dicen lo mismo. */
.de-donde-cuerpo tfoot td {
  border-top: 2px solid var(--linea-fuerte); background: var(--superficie-2);
}

.pie-dashboard { margin: 22px 0 0; font-size: 12px; max-width: 86ch; }

@media (max-width: 1100px) {
  .tarjetas.cuatro { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 480px) {
  /* En el teléfono cuatro cifras en dos columnas parten el número; una
     debajo de otra se lee. Una cifra no se parte nunca. */
  .tarjetas.cuatro { grid-template-columns: 1fr; }
  .hoy-lista a { padding: 12px 14px; }
  /* Materia prima (1 oct 2026): aquí lo que importa son los lotes, y cuatro
     tarjetas apiladas ocupaban la pantalla entera antes del primero. Dos por
     fila, con la cifra más chica y sin partirse. */
  .tarjetas.cuatro.compactas { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tarjetas.cuatro.compactas .tarjeta { padding: 12px 12px 14px; gap: 4px; }
  .tarjetas.cuatro.compactas .cifra { font-size: 20px; white-space: nowrap; }
  .tarjetas.cuatro.compactas .etiqueta { font-size: 10px; }
  .tarjetas.cuatro.compactas small { font-size: 11.5px; }
  .tabs.apretadas a { padding: 9px 9px; }
}

.ayuda-bloque {
  margin: -4px 0 12px; color: var(--tinta-media);
  font-size: 12.5px; max-width: 70ch;
}
.linea-filtro { display: flex; gap: 8px; align-items: center; }
.linea-filtro label { margin: 0; font-size: 12px; color: var(--tinta-media); }

/* La tabla de alertas usa todo el ancho: con la clase `compacta` los chips de
   "le falta" se apilaban en columna y cada fila crecia cuatro renglones. */
.alertas-tabla { width: 100%; }
.nowrap { white-space: nowrap; }
.chips-fila { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

/* ==========================================================================
   EL ENCABEZADO COMO INSPECCION DE ENTRADA  (sep 2026)
   --------------------------------------------------------------------------
   13 campos que hay que llenar ANTES de pesar. El reto es de espacio: tienen
   que caber todos en pantalla sin bajar la vista, o la persona que recibe el
   camion no los va a llenar. Se agrupan en tres bloques de una fila cada uno,
   separados por linea y no por tarjeta -- una tarjeta por bloque comeria 3 x
   32 px de padding sin aportar nada.
   ========================================================================== */
.inspeccion { padding: 0; }

.bloque-insp { padding: 16px 20px; border-bottom: 1px solid var(--linea); }
.bloque-insp:first-child { padding-top: 20px; }

.bloque-titulo {
  margin: 0 0 12px; font-size: 11.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .06em; color: var(--tinta-media);
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.bloque-titulo small {
  font-size: 11px; font-weight: 400; text-transform: none;
  letter-spacing: 0; color: var(--tinta-suave);
}
.bloque-titulo .propuesta { color: var(--proceso); font-style: italic; }

/* ⚠️ SEIS columnas FIJAS, no `auto-fit`.
   Con `auto-fit` cada sección calculaba su propio número de columnas según
   cuántos campos tuviera (Orden 7 unidades, frío 5, organoléptico 5), así que
   los campos de una sección no caían en la misma vertical que los de la de
   arriba. Se veía torcido, y lo estaba. Ahora las tres secciones suman
   exactamente 6 unidades y comparten la misma retícula:
     Orden        1 + 2 + 1 + 2
     Frío         2 + 1 + 1 + 1 + 1
     Organoléptico 1 + 1 + 1 + 3
   Añadir un campo obliga a recolocar los tramos: eso es deliberado, es lo que
   impide que la pantalla se vuelva a desalinear sola. */
.rejilla-insp {
  display: grid; gap: 12px;
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
.rejilla-insp .ancho-2 { grid-column: span 2; }
.rejilla-insp .ancho-3 { grid-column: span 3; }
.rejilla-insp label {
  display: block; margin-bottom: 4px;
  font-size: 12px; color: var(--tinta-media);
}
.rejilla-insp .ud { color: var(--tinta-suave); font-weight: 400; }
.rejilla-insp input, .rejilla-insp select { width: 100%; }

/* La decision va sola, sobre fondo tenue: es lo unico que se "firma". */
.bloque-decision {
  display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap;
  padding: 16px 20px; background: var(--superficie-2);
  border-top: 1px solid var(--linea);
}
.decision-campo { min-width: 200px; }
.decision-campo label {
  display: block; margin-bottom: 4px;
  font-size: 12px; font-weight: 600; color: var(--tinta);
}
.decision-nota {
  flex: 1 1 260px; margin: 0 0 8px;
  font-size: 11.5px; color: var(--tinta-suave);
}
.boton.grande { height: 44px; padding: 0 24px; font-size: 14px; }

/* La inspección ya hecha, resumida en una línea sobre los totales. */
.insp-resumen {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  margin: -8px 0 16px; padding: 10px 14px;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--r-control);
  font-size: 12.5px; color: var(--tinta-media);
}
.insp-resumen b { color: var(--tinta); font-weight: 600; }
.insp-resumen .fuera {
  font-style: normal; font-weight: 600; color: var(--alerta);
}
.chip.aceptado     { background: var(--bien-fondo);   color: var(--bien); }
.chip.no_aceptado  { background: var(--alerta-fondo); color: var(--alerta); }

/* --- el bloqueo: no se pesa sin inspeccionar --------------------------- */
.bloqueo-inspeccion {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 20px 24px; margin-bottom: 20px;
  background: var(--proceso-fondo); border: 1px solid #eddcb6;
  border-radius: var(--r-caja); color: #6f4400;
}
.bloqueo-inspeccion strong { font-size: 14px; }
.bloqueo-inspeccion p { margin: 2px 0 0; font-size: 12.5px; }

/* La retícula se parte a la mitad, no se rehace: 6 → 3 → 2 columnas. Así los
   tramos siguen encajando y las secciones siguen alineadas entre sí en
   cualquier ancho. */
@media (max-width: 1100px) {
  .rejilla-insp { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rejilla-insp .ancho-3 { grid-column: span 3; }
}
@media (max-width: 720px) {
  .rejilla-insp { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rejilla-insp .ancho-2,
  .rejilla-insp .ancho-3 { grid-column: span 2; }
}
@media (max-width: 430px) {
  .rejilla-insp { grid-template-columns: minmax(0, 1fr); }
  .rejilla-insp .ancho-2,
  .rejilla-insp .ancho-3 { grid-column: span 1; }
}

@media (max-width: 720px) {
  main { padding: 20px 14px 40px; }
  .barra { padding: 10px 14px; }
  /* Antes aquí la tabla pasaba a `display:block; overflow-x:auto`, o sea a
     scroll lateral. El cliente lo prohibió: ahora la tabla sigue siendo tabla
     y son las celdas las que parten de línea (table-layout: fixed). */
  thead th, tbody td { padding: 10px 10px; font-size: 13px; }
  .rejilla-2, .rejilla-3, .rejilla-4 { grid-template-columns: 1fr; }
  .fila-producto { grid-template-columns: 1fr; }
  .fila-anular { flex-wrap: wrap; }
  .fila-anular input[type="text"] { width: 100%; }
}
@media (min-width: 721px) and (max-width: 1100px) {
  .rejilla-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ============================================================================
   SE TOCA CON EL DEDO, NO CON EL RATÓN
   Va por MÉTODO DE ENTRADA (`pointer: coarse`), no por ancho de pantalla.
   Con `max-width` sola quedaba una banda huérfana entre 641 y 860 px --
   tablet en vertical, que es un aparato plausible en la planta -- con el
   layout ya apilado pero los controles todavía de 38 px de ratón. Y una
   laptop con pantalla táctil nunca recibía nada.
   ========================================================================== */
@media (pointer: coarse) {
  /* 44 px es el mínimo que se acierta sin mirar, con la mano ocupada. */
  .boton, .boton.pequeno, .pildora,
  input[type=text], input[type=date], input[type=number], select, textarea {
    min-height: 44px;
  }
  .lista-tabs a { min-height: 44px; display: flex; align-items: center; }
  .lista-fila { padding-top: 14px; padding-bottom: 14px; }

  /* ⚠️ 16 px NO ES ESTÉTICA: iOS Safari hace ZOOM al enfocar un campo con
     letra más pequeña, y deja la página ampliada. En una pantalla donde se
     digitan veinte pesos por camión, eso es pellizcar para alejar veinte
     veces. Medido: los campos venían en 12,5 / 14 / 15 px. */
  input[type=text], input[type=date], input[type=number], select, textarea {
    font-size: 16px;
  }

  /* Acciones sueltas dentro de tablas y fichas ("Editar", "Quitar",
     "Anular", "corregir"): eran texto de 16-38 px de alto. */
  .acciones-col a, .acciones-col button,
  .prod-acciones a, .prod-acciones button,
  .subtitulo a {
    min-height: 44px; display: inline-flex; align-items: center;
  }
}

/* Sin hover no hay estado hover: en táctil el resaltado se queda pegado
   después de tocar. Los efectos de hover solo para quien puede hacerlo. */
@media (hover: none) {
  .lista-fila:hover, .tira:hover, nav a:hover, .lista-tabs a:hover {
    background: inherit;
  }
}

/* ============================================================ píldoras de filtro
   Filtrar una lista por una categoría corta (la clase de proveedor). Es un
   enlace, no un control: cada una es una URL y se puede compartir o recargar.
   Sale de la referencia del WMS: contorno gris, y el activo relleno. */
.filtros {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0 0 16px;
}

.pildora {
  display: inline-flex; align-items: center; height: 32px;
  padding: 0 14px;
  border: 1px solid var(--linea-fuerte); border-radius: 999px;
  background: var(--superficie);
  font-size: 12.5px; font-weight: 500; color: var(--tinta-media);
  text-decoration: none; white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s;
}
.pildora:hover { border-color: var(--tinta-suave); color: var(--tinta); }

/* Las cuatro se reparten el ancho. Alineadas a la izquierda dejaban un hueco
   muerto a la derecha y no se leían como un grupo de opciones excluyentes. */
.filtros.reparte { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.filtros.reparte .pildora { justify-content: center; padding: 0 10px; gap: 6px; }

.pildora-cuenta {
  display: inline-block; min-width: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--neutro-fondo); color: var(--tinta-media);
  font-size: 10.5px; font-weight: 700; line-height: 16px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.pildora.activa .pildora-cuenta { background: rgba(255, 255, 255, .25); color: #fff; }

/* ⚠️ SIEMPRE cuatro en una fila, también en el teléfono.
   Se probó a dos por renglón "para que se leyeran enteras" y el resultado fue
   ocupar el doble de alto — lo contrario de lo que se busca. En 390 px caben
   las cuatro: la letra baja a 11,5 px, el aire lateral a 6 y la etiqueta larga
   dice "Semana" en vez de "Esta semana". */
@media (max-width: 560px) {
  .filtros.reparte { gap: 6px; }
  .filtros.reparte .pildora {
    padding: 0 6px; gap: 4px; font-size: 11.5px; height: 34px;
  }
  .filtros.reparte .pildora-cuenta { min-width: 14px; font-size: 10px; }
}

/* Solo el activo se rellena, y con el acento: sigue siendo un color de acento
   por pantalla porque el filtro ES la acción principal de la lista. */
.pildora.activa {
  background: var(--acento); border-color: var(--acento); color: #fff;
}
.pildora.activa:hover { background: var(--acento-fuerte); color: #fff; }

/* ---------------------------------------------------- segunda línea de celda
   El dato de apoyo va debajo del principal, no en otra columna: con 32
   proveedores y 8 datos cada uno, una columna por dato deja la tabla
   impracticable en un portátil. */
.sub {
  display: block;
  font-size: 12px; color: var(--tinta-suave);
  margin-top: 2px;
  overflow-wrap: anywhere;
}
tr.inactiva .sub { color: var(--linea-fuerte); }

/* En la fila abierta para editar, los dos campos se apilan igual que el texto
   plano al que reemplazan. */
tr.editando td > input + input,
tr.editando td > select + input { margin-top: 4px; }

/* ============================================================================
   REDISEÑO v2 · ajustes finales
   Referencia: el WMS del propio cliente (barra blanca, píldora de acento en el
   activo, cajas con marco y esquinas generosas, fichas azules de dato).
   Referencia, no copia: la paleta, el vocabulario y los componentes siguen
   siendo los de Chicken Porcionado.
   ========================================================================== */

/* --------------------------------------------------- nada empuja a lo ancho */
/* Los sospechosos de siempre: correos, direcciones, códigos de lote y
   observaciones que el usuario pega desde WhatsApp. */
main, .panel, .tarjeta, .formulario, .bloque,
.tarjeta-registro, .registro-campos, .campo { min-width: 0; }
code, .observaciones, .nota, .ayuda { overflow-wrap: anywhere; }

/* Una rejilla de grid con contenido largo se estira si no se le dice que puede
   encogerse. `minmax(0, 1fr)` es lo que se lo dice. */
.rejilla-2 > *, .rejilla-3 > *, .rejilla-4 > *, .tarjetas > * { min-width: 0; }

/* Las acciones van en UNA línea mientras quepan (regla 2 del sistema: nunca
   apiladas). Solo se les permite partir en pantalla angosta, abajo. */

/* ------------------------------------------------------------- marcos y aire */
.panel { border-radius: var(--r-caja); }
.formulario { border-radius: var(--r-caja); }

/* Título de sección con su línea de apoyo debajo, como el "Bodega 106 /
   Layout detalle del Nivel" de la referencia. */
.titulo-fila { align-items: flex-start; gap: 12px 20px; flex-wrap: wrap; }
h1 { letter-spacing: -.025em; }

/* ------------------------------------------------------------- ficha de dato */
/* El equivalente de los cuadritos azules M1, M2… de la referencia: un valor
   corto que se lee de un golpe. No es un botón y no se pulsa. */
.ficha {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 28px; padding: 0 9px;
  background: var(--dato-fondo); border: 1px solid var(--dato-linea);
  border-radius: 7px;
  color: var(--dato); font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------- chips */
/* Más redondos, para que hagan juego con las píldoras de la navegación. */
.chip { border-radius: 999px; }

/* ------------------------------------------- pantallas angostas (tablet/móvil)
   Debajo de 900 px las tablas de 7 y 8 columnas ya no caben partiendo solo por
   los espacios. Aquí SÍ se deja partir por cualquier letra: un encabezado feo
   se lee; una tabla que se sale de la pantalla, no. Medido a 768 px: sin esto,
   /recepciones se desbordaba 83 px y /lotes 133 px. */
@media (max-width: 900px) {
  thead th { overflow-wrap: anywhere; letter-spacing: .04em; }
  td.acciones-col, th.acciones-col { white-space: normal; }
  .grupo-acciones { flex-wrap: wrap; }
  thead th, tbody td { padding-left: 10px; padding-right: 10px; }
  .grupo-acciones .boton { padding: 0 8px; }
}

/* ============================================================================
   CELULAR
   ----------------------------------------------------------------------------
   El cliente lo pidió mirando el historial de pedidos en su teléfono: "se ve
   terrible". Tres cosas lo arreglan, en este orden de importancia:

     1. En celular una TABLA NO ES UNA TABLA: es una lista de tarjetas. Siete
        columnas en 390 px no se salvan con CSS — el problema no es que se
        desborde, es que no se puede leer.
     2. La navegación se recoge. Once píldoras ocupaban CUATRO renglones, más
        alto que el propio contenido.
     3. Los objetivos táctiles suben a 44 px y el aire se aprieta, para que no
        ocupe más espacio del necesario.
   ========================================================================== */

/* ------------------------------------------------------------- el menú
   Aquí vivía el menú de hamburguesa (casilla oculta + `:checked ~ nav`).
   Se eliminó: en el teléfono ahora manda `.nav-inferior`, que deja las dos
   secciones siempre visibles y señala en cuál estás. Un menú que esconde
   dos enlaces no ahorra espacio, y quitaba la única pista de ubicación. */
/* Ya no lleva `margin-left: auto`: eso era del flex viejo y con la rejilla de
   tres zonas empujaba el menú fuera del centro. */
nav { display: flex; align-items: center; gap: 2px; }

@media (max-width: 860px) {
  /* `position: relative` vivía aquí para anclar el desplegable de la
     hamburguesa. Sin hamburguesa, la barra vuelve a ser `sticky` (regla
     base) y el encabezado se queda a la vista al bajar. */
  /* Arriba solo queda la marca; navegar es cosa de la barra de abajo. */
  .barra > nav { display: none; }
  /* ...y por eso la rejilla pasa a DOS zonas. Seguía siendo `1fr auto 1fr`
     con la del medio vacía, así que la marca vivía en un tercio del ancho:
     medido a 390 px, "Chicken Porcionados" se partía en dos renglones y al
     lado quedaba medio encabezado en blanco. */
  .barra { grid-template-columns: 1fr auto; }
}

/* Paso intermedio antes de rendirse y volverla tarjetas: la misma tabla, con
   menos aire. Lo pone tabla_movil.js despues de medir, nunca a mano. */
table.tabla-etiquetada.apretada thead th,
table.tabla-etiquetada.apretada tbody td,
table.tabla-etiquetada.apretada tfoot td { padding: 8px 9px; font-size: 12.5px; }
table.tabla-etiquetada.apretada thead th { font-size: 9.5px; }

/* --------------------------------------------- la tabla se vuelve tarjetas
   `.tabla-etiquetada` la pone tabla_movil.js cuando ya copió el título de cada
   columna a su celda. Si el JS no corrió, la clase no está y la tabla se queda
   como tabla: no se muestran tarjetas sin etiqueta, que sería peor.

   ⚠️ ANTES ESTO COLGABA DE `@media (max-width: 640px)`, y la pregunta que se
   estaba haciendo era la equivocada. Lo que decide si una tabla se puede leer
   NO es el ancho de la pantalla: es si la tabla CABE. La de lotes tiene once
   columnas y a 768 y a 1100 px no cabía -- se salía de la pantalla o, peor,
   partía los números ("1.258,0" y un "0" solo debajo). Ahora la clase
   `.no-cabe` la pone el propio JS después de medir, y vale a cualquier ancho:
   una tabla de tres columnas sigue siendo tabla en el teléfono, y una de once
   se vuelve tarjetas en un portátil. El cliente prohibió el scroll lateral, y
   así no hace falta. */
table.tabla-etiquetada.no-cabe {
  display: block; border: 0; background: none; box-shadow: none;
  border-radius: 0;
}
table.tabla-etiquetada.no-cabe thead { display: none; }
table.tabla-etiquetada.no-cabe tbody { display: block; }

table.tabla-etiquetada.no-cabe tbody tr {
  display: block; margin-bottom: 10px; padding: 12px 14px;
  background: var(--superficie);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra);
}
table.tabla-etiquetada.no-cabe tbody tr:hover { background: var(--superficie); }
table.tabla-etiquetada.no-cabe tbody tr:last-child { margin-bottom: 0; }

/* Cada dato: etiqueta a la izquierda, valor a la derecha.
   La etiqueta va FLOTADA, no en un flex. Con flex, una celda con dos partes
   (correo + dirección, contacto + teléfono) las convertía en dos columnas
   pegadas y la etiqueta se partía en "CORR / EO". Flotada, la etiqueta ocupa
   su sitio a la izquierda y TODO el valor —tenga las partes que tenga— fluye
   a la derecha y baja de línea con normalidad. */
table.tabla-etiquetada.no-cabe tbody td {
  display: block; padding: 6px 0; border: 0; text-align: right;
  line-height: 1.45;
}
table.tabla-etiquetada.no-cabe tbody td::before {
  content: attr(data-etiqueta);
  float: left; margin-right: 14px; max-width: 42%;
  text-align: left;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--tinta-suave); font-weight: 600; line-height: 1.9;
}
/* Contiene el flotado para que no se derrame a la celda siguiente. */
table.tabla-etiquetada.no-cabe tbody td::after { content: ""; display: block; clear: both; }
table.tabla-etiquetada.no-cabe tbody td .sub { text-align: right; }

/* Sin etiqueta no hay dos columnas: ocupa todo el ancho. */
table.tabla-etiquetada.no-cabe tbody td:not([data-etiqueta]) { text-align: left; }
table.tabla-etiquetada.no-cabe tbody td:not([data-etiqueta])::before { content: none; }

/* La primera celda es el TÍTULO de la tarjeta, no un dato más. */
table.tabla-etiquetada.no-cabe tbody td:first-child {
  display: block; text-align: left;
  padding: 0 0 8px; margin-bottom: 6px;
  border-bottom: 1px solid var(--linea);
  font-size: 15px;
}
table.tabla-etiquetada.no-cabe tbody td:first-child::before { content: none; }
table.tabla-etiquetada.no-cabe tbody td:first-child .sub { text-align: left; }
table.tabla-etiquetada.no-cabe tbody td.num { font-variant-numeric: tabular-nums; }

/* Las acciones, al pie de la tarjeta y a lo ancho. */
table.tabla-etiquetada.no-cabe tbody td.acciones-col {
  display: block; text-align: left;
  padding: 10px 0 0; margin-top: 6px;
  border-top: 1px solid var(--linea);
}
table.tabla-etiquetada.no-cabe .grupo-acciones { justify-content: flex-start; gap: 8px; }
table.tabla-etiquetada.no-cabe .grupo-acciones .boton { height: 38px; }

/* El pie de totales queda como una tarjeta más, marcada. */
table.tabla-etiquetada.no-cabe tfoot { display: block; }
table.tabla-etiquetada.no-cabe tfoot tr { display: block; }
table.tabla-etiquetada.no-cabe tfoot td {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 10px 14px; border: 0;
  background: var(--superficie-2);
  border-radius: var(--r-control); margin-top: 4px;
}

/* --------------------------------------------------------- aire y dedos */
@media (max-width: 640px) {
  /* Los env(safe-area-inset-*) valen 0 en un navegador sin notch, así que
     el max() deja el valor de siempre y solo crece donde hace falta. */
  main {
    padding: 16px max(12px, env(safe-area-inset-right)) 40px max(12px, env(safe-area-inset-left));
  }
  footer { padding-bottom: max(40px, env(safe-area-inset-bottom)); }
  .barra { padding: 8px 12px; gap: 8px 12px; }
  .marca small { display: none; }          /* en 390 px el subtítulo es ruido */
  .marca strong { font-size: 15px; }

  h1 { font-size: 19px; }
  h2 { margin: 24px 0 10px; }
  .titulo-fila { margin-bottom: 14px; gap: 10px; }

  .pildora { padding: 0 16px; }

  /* Los formularios en una sola columna: dos campos en 390 px no caben. */
  .formulario.en-linea { flex-direction: column; align-items: stretch; }
  .formulario.en-linea > div { flex: 1 1 auto; width: 100%; }
  .formulario.en-linea .boton { width: 100%; justify-content: center; }

  .tarjetas, .totales { gap: 8px; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .tarjeta, .totales > div { padding: 12px 14px; }
  .cifra { font-size: 22px; }

  .panel-cifras { gap: 14px; padding: 14px 16px; }
  .aviso { padding: 11px 13px; }
}

/* ------------------------------------------- el formulario de alta se pliega
   En los catálogos (proveedores, productos, presentaciones) el formulario de
   "agregar" ocupaba la pantalla entera del teléfono ANTES de la lista, que es
   a lo que uno entra. Se pliega tras un botón. Lo envuelve tabla_movil.js;
   si el JS no corre, el formulario se queda abierto como siempre. */
@media (max-width: 640px) {
  details.plegable { margin-bottom: 16px; }
  details.plegable > summary {
    display: flex; align-items: center; gap: 8px;
    min-height: 44px; padding: 0 16px; border-radius: var(--r-control);
    background: var(--superficie); border: 1px solid var(--linea-fuerte);
    font-size: 14px; font-weight: 500; color: var(--tinta);
    cursor: pointer; list-style: none;
  }
  details.plegable > summary::-webkit-details-marker { display: none; }
  details.plegable > summary::before { content: "+"; font-size: 17px; font-weight: 600;
                                       color: var(--acento); line-height: 1; }
  details.plegable[open] > summary { margin-bottom: 8px; }
  details.plegable[open] > summary::before { content: "−"; }
}

/* En portátiles de 1280-1440 los 11 enlaces no caben junto a la marca y la
   barra se partía en dos renglones: el doble de alto para nada. Se aprieta la
   navegación lo justo para que quepa en una sola línea. */
@media (min-width: 861px) and (max-width: 1460px) {
  .barra { padding-left: 16px; padding-right: 16px; }
  .barra > nav a { padding: 6px 10px; min-width: 66px; font-size: 11px; }
  .nav-sep { margin: 0 5px; }
}

/* Los cuatro KPI de cumplimiento son cifras cortas: en celular caben de a dos.
   `.rejilla-4` pasa a una sola columna porque también la usan formularios,
   donde un campo por renglón sí es lo correcto. */
@media (max-width: 720px) {
  .rejilla-4.tarjetas-kpi { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tarjeta-kpi { padding: 12px 14px; }
}

/* --------------------------------------------------- las barras de filtro
   `.filtro` es un flex plano de pares etiqueta+campo, sin un contenedor por
   pareja. En escritorio va todo en una línea y se lee bien; en celular el
   wrap los desparejaba y la etiqueta "Presentación" quedaba pegada al campo
   ANTERIOR. En una sola columna el orden del HTML ya es el correcto:
   etiqueta, su campo, etiqueta, su campo. */
@media (max-width: 640px) {
  .filtro, .linea-filtro {
    display: grid; grid-template-columns: 1fr; gap: 10px; align-items: stretch;
  }
  /* `> label` a propósito: en `.filtro` las etiquetas ya viven dentro de su
     propio <div> y no necesitan separación extra; en `.linea-filtro`, que
     sigue siendo una fila plana de etiqueta+campo, sí. */
  .filtro > label, .linea-filtro > label { margin-top: 10px; font-weight: 600; }
  .filtro > *:first-child, .linea-filtro > *:first-child { margin-top: 0; }
  .filtro > div { width: 100%; }
  .filtro select, .filtro input, .filtro .buscador, .filtro .buscador-campo,
  .linea-filtro select, .linea-filtro input {
    width: 100%; min-width: 0; height: 40px; font-size: 14px;
  }
  .filtro .al-final { flex-direction: column; align-items: stretch; }
  .filtro .boton, .linea-filtro .boton { width: 100%; justify-content: center; }
}

/* El número de lote propio de un arrume: se resalta porque es la EXCEPCIÓN
   (ese arrume vino con otro lote que el resto del producto). Cuando no la hay,
   se muestra en gris el del producto, para que la columna nunca esté vacía. */
.lote-otro {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  background: var(--dato-fondo); border: 1px solid var(--dato-linea);
  color: var(--dato); font-size: 12.5px; font-weight: 600;
}

/* ============================================================================
   LOS ARRUMES EN CELULAR
   ----------------------------------------------------------------------------
   Un arrume son cuatro números cortos: numeral, peso, canastas y lote. La
   conversión genérica a tarjetas lo volvía una ficha de diez renglones —
   media pantalla por arrume, con "CANASTA/S" partido a la mitad y el renglón
   de OBSERVACIÓN ocupando sitio aunque estuviera vacío. Por eso esta tabla
   lleva `data-tarjetas="no"` y se maqueta aquí, con una rejilla explícita:

        1 │ 117,10 kg          │ Anular
          │ 5 canastas · B0012 │

   El peso manda porque es el dato que se verifica contra la báscula; canastas
   y lote van debajo, en gris. La observación solo aparece si existe.
   ========================================================================== */
@media (max-width: 640px) {
  .arrumes-tabla { display: block; border: 0; background: none; box-shadow: none; }
  .arrumes-tabla thead { display: none; }
  .arrumes-tabla tbody, .arrumes-tabla tfoot { display: block; }

  /* Rejilla explícita: cada celda sabe dónde va. Sin esto el `text-align:
     right` que traen las celdas numéricas dejaba el numeral y el peso
     flotando en mitad del renglón. */
  .arrumes-tabla tbody tr:not(.fila-nueva) {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: 10px; row-gap: 1px;
    padding: 9px 10px;
    border-bottom: 1px solid var(--linea);
  }
  .arrumes-tabla tbody tr:hover { background: none; }
  .arrumes-tabla tbody td { padding: 0; border: 0; text-align: left; }
  .arrumes-tabla tbody td:empty { display: none; }

  .arrumes-tabla tbody tr:not(.fila-nueva) .a-numeral {
    grid-area: 1 / 1 / 3 / 2;
    font-size: 15px; font-weight: 700; color: var(--tinta-suave);
  }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-peso      { grid-area: 1 / 2 / 2 / 3; font-size: 17px; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .acciones-col{ grid-area: 1 / 3 / 3 / 4; align-self: center; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-canastas  { grid-area: 2 / 2 / 3 / 3; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-obs       { grid-area: 3 / 2 / 4 / 4; }

  /* ⚠️ El lote NO comparte renglón con las canastas. Lo compartía, alineado
     a la derecha, y desde que el arrume lleva Corregir Y Anular al lado la
     columna quedó de ~110 px: "5 canastas" y "2026252" se montaban uno sobre
     otro (visto el 11 sep 2026). El lote del producto ya está en su
     encabezado ("N° de lote"), así que aquí solo aparece el que es DISTINTO
     -- el que de verdad informa --, y en su propio renglón. */
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-lote {
    grid-area: 3 / 2 / 4 / 3; justify-self: start;
  }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-lote .suave { display: none; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-obs { grid-area: 4 / 2 / 5 / 4; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-canastas::after { content: " canastas"; }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-peso::after {
    content: " kg"; font-size: 12px; font-weight: 500; color: var(--tinta-suave);
  }
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-canastas,
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-lote,
  .arrumes-tabla tbody tr:not(.fila-nueva) .a-obs {
    font-size: 12.5px; color: var(--tinta-suave);
  }
  .arrumes-tabla .a-lote .lote-otro { padding: 1px 7px; font-size: 11.5px; }

  /* La fila de captura sí necesita espacio: se digita de pie y con guantes.
     Los dos números cortos comparten renglón; lote y observación a lo ancho. */
  .arrumes-tabla tbody tr.fila-nueva {
    display: flex; flex-wrap: wrap; gap: 8px;
    padding: 12px 10px; background: var(--superficie-2);
  }
  .arrumes-tabla tr.fila-nueva td { display: block; flex: 1 1 100%; min-width: 0; }
  .arrumes-tabla tr.fila-nueva .a-numeral {
    flex: 0 0 100%; font-size: 12px; font-weight: 600; color: var(--acento);
  }
  .arrumes-tabla tr.fila-nueva .a-numeral::before { content: "Arrume "; color: var(--tinta-suave); }
  /* Cuatro campos en DOS renglones, no en cuatro. Peso y canastas comparten
     el primero; lote y observación el segundo. Antes cada uno se llevaba su
     renglón y un solo arrume ocupaba media pantalla del teléfono.

     ⚠️ Los cuatro con la MISMA base de 50%: con `flex: 1 1 0` los tres
     primeros cabían en una sola línea y el peso quedaba de 55 px mostrando
     "188," -- el dato que se verifica contra la báscula, cortado. Con base
     50% caben exactamente dos por renglón y el reparto no depende de cuánto
     texto tenga cada uno. */
  /* PESO · CANASTAS · LOTE en el MISMO renglón, y la observación debajo a lo
     ancho. Lo pidió así el cliente y tiene sentido: los tres son el arrume, y
     la observación casi siempre va vacía.
     Los anchos no son iguales a propósito: canastas es un número de un dígito
     y el lote un código de siete. */
  .arrumes-tabla tr.fila-nueva .a-peso     { flex: 1 1 30%; }
  .arrumes-tabla tr.fila-nueva .a-canastas { flex: 1 1 20%; }
  .arrumes-tabla tr.fila-nueva .a-lote     { flex: 1 1 calc(50% - 16px); }
  .arrumes-tabla tr.fila-nueva .a-obs      { flex: 1 1 100%; }
  /* Los cuatro se alinean por ARRIBA: el de observación no lleva etiqueta, y
     con `align-items` por defecto quedaba descuadrado contra los que sí. */
  .arrumes-tabla tbody tr.fila-nueva { align-items: flex-start; }
  .arrumes-tabla tr.fila-nueva input { width: 100%; height: 44px; }
  .arrumes-tabla tr.fila-nueva .acciones-col .boton { width: 100%; }

  /* El botón de agregar otro arrume, SOLO en la última fila en blanco. Salía
     en todas, así que entre un arrume y el siguiente había un "+ Otro arrume"
     que no hacía falta: el siguiente ya estaba ahí abajo. */
  .arrumes-tabla tr.fila-nueva:not(:last-of-type) .acciones-col { display: none; }
  /* …salvo la que se está guardando: su estado ("Guardando…", "Sin señal")
     tiene que verse. */
  .arrumes-tabla tr.fila-nueva[data-estado]:not(:last-of-type) .acciones-col { display: block; }

  /* El pie: las tres cifras sueltas no se entienden sin su columna, así que en
     celular se ocultan y queda solo la frase, que ya las dice en palabras. */
  /* Desde el 29 oct 2026 el pie solo lleva el «+» del arrume siguiente: en
     celular, a lo ancho, debajo de la última tarjeta. */
  .arrumes-tabla tfoot tr { display: block; padding: 0 12px 12px; }
  .arrumes-tabla tfoot td { display: none; border: 0; padding: 0; }
  .arrumes-tabla tfoot td:first-child:has(.arrume-mas) { display: block; width: 100%; max-width: none; }
  .arrumes-tabla tfoot .arrume-mas { width: 100%; height: 44px; }
}

/* La etiqueta de una tarjeta nunca se parte a la mitad: "CANASTA / S" no se
   lee. Prefiere no caber a partirse. */
table.tabla-etiquetada tbody td::before { overflow-wrap: normal; word-break: keep-all; }

/* La botonera de cada producto: en celular no cabe en una línea. Se apila, con
   la acción principal primero y a lo ancho — es la que se pulsa con guantes.
   Sin esto los tres botones empujaban la página 161 px a la derecha. */
@media (max-width: 640px) {
  .acciones { flex-direction: column; align-items: stretch; gap: 8px; }
  .acciones .boton { width: 100%; justify-content: center; }
  .acciones .ayuda { text-align: center; margin: 0; }
  .acciones .empuja { display: none; }
}

/* El encabezado del producto en celular: rejilla de dos columnas apretada.
   Con el flex de escritorio (gap 20 px, `ancho` de 220 px mínimo) cada dato se
   comía un renglón entero y el bloque ocupaba una pantalla completa para ocho
   valores cortos. El nombre del producto y la planta van a lo ancho porque son
   los dos textos largos. */
@media (max-width: 640px) {
  .prod-cab {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px 14px; padding: 12px 14px; align-items: start;
  }
  .prod-dato { min-width: 0; }
  .prod-dato.ancho { grid-column: 1 / -1; min-width: 0; }
  .prod-dato .etiqueta { font-size: 9.5px; }
  .prod-dato strong { font-size: 13.5px; overflow-wrap: anywhere; }
  /* "Editar" al pie del bloque, a lo ancho: es una acción, no un dato más. */
  .prod-cab > .acciones-col,
  .prod-cab > a.boton, .prod-cab > .prod-editar { grid-column: 1 / -1; }
  /* ⚠️ DESBORDE MEDIDO. `.prod-acciones` conservaba el `margin-left: auto` de
     escritorio y caía en UNA columna de la rejilla; su contenido (los chips,
     "Editar" y "No llegó") no cabe en media pantalla. A 375 px la fila llegaba
     a 402 px y toda la pantalla se iba de lado. Va a lo ancho, como el resto
     de las acciones, y sus piezas pueden bajar de línea. */
  .prod-cab > .prod-acciones {
    grid-column: 1 / -1; margin-left: 0; flex-wrap: wrap; gap: 8px;
  }
}

@media (max-width: 640px) {
  /* Los dos campos numéricos se quedaban SIN NOMBRE al ocultar el encabezado
     de la tabla: dos cajas iguales con "152,4" y "5" dentro. Quien pesa tiene
     que ver cuál es kilos y cuál canastas sin adivinar. */
  .arrumes-tabla tr.fila-nueva .a-peso,
  .arrumes-tabla tr.fila-nueva .a-canastas,
  .arrumes-tabla tr.fila-nueva .a-lote { position: relative; }
  .arrumes-tabla tr.fila-nueva .a-peso::before,
  .arrumes-tabla tr.fila-nueva .a-canastas::before,
  .arrumes-tabla tr.fila-nueva .a-lote::before {
    display: block; margin-bottom: 3px;
    font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
    color: var(--tinta-suave); font-weight: 600;
    /* "CANASTA / S" partido en dos renglones no se lee, y encima descuadraba
       la altura de ese campo contra la del de al lado. */
    white-space: nowrap;
  }
  /* La observación también lleva etiqueta: sin ella, su caja arrancaba 17 px
     más arriba que las otras tres y la fila se veía torcida. */
  .arrumes-tabla tr.fila-nueva .a-obs { position: relative; }
  .arrumes-tabla tr.fila-nueva .a-obs::before {
    content: "Observación"; display: block; margin-bottom: 3px;
    font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
    color: var(--tinta-suave); font-weight: 600; white-space: nowrap;
  }
  .arrumes-tabla tr.fila-nueva .a-peso::before     { content: "Peso (kg)"; }
  .arrumes-tabla tr.fila-nueva .a-canastas::before { content: "Canastas"; }
  .arrumes-tabla tr.fila-nueva .a-lote::before     { content: "N° de lote"; }
  /* El número se lee mejor pegado a la izquierda en una caja ancha. */
  .arrumes-tabla tr.fila-nueva input { text-align: left; }

  /* Un "+" solo no dice qué agrega. */
  .arrumes-tabla tr.fila-nueva .acciones-col .boton::after { content: " Otro arrume"; }
  /* Había DOS botones para lo mismo: el de la fila y el de la botonera de
     abajo. En celular se queda el de la fila, que está donde se está
     digitando; el de abajo desaparece y con él un renglón entero. */
  .acciones > [data-agregar] { display: none; }

  /* El encabezado del producto, un punto más apretado. */
  .prod-cab { gap: 8px 14px; }
}

/* Cuánto se va a guardar. Existe porque "1,200" en notación colombiana son
   1,2 kg y mucha gente lo escribe esperando 1.200 -- un error de mil veces que
   la app aceptaba en silencio. En vez de adivinar, se muestra la lectura y
   quien digita ve el error antes de guardar.

   ⚠️ Va AL LADO del título del campo, no debajo de la casilla. Debajo era un
   bloque que nacía al escribir, y al nacer empujaba la fila entera: la
   pantalla se descuadraba justo mientras alguien digita kilos. */
.eco-numero {
  display: block; margin-top: 3px;
  font-size: 11.5px; color: var(--tinta-media);
  font-variant-numeric: tabular-nums;
}
label > .eco-numero {
  display: inline; margin: 0 0 0 8px;
  font-weight: 400; color: var(--acento-fuerte);
  white-space: nowrap;
}
/* Con `:has` la etiqueta se vuelve una fila y el eco se recorta antes que
   partir en dos renglones -- porque un renglón de más descuadraría igual que
   el bloque de antes. Donde no haya `:has`, el eco sigue siendo texto en
   línea, que es lo de arriba y también sirve. */
label:has(> .eco-numero) {
  display: flex; align-items: baseline; gap: 8px;
}
label:has(> .eco-numero) > .eco-numero {
  margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

/* Fila abierta para corregir: mismo tratamiento que la de anular, pero en
   ámbar (enmienda) y no en rojo (descarte). */
.fila-corrigiendo td { background: var(--proceso-fondo); }
.chip.corregido { background: var(--proceso-fondo); color: var(--proceso); font-size: 10px; margin-left: 6px; }

/* El tablero avisa cuando su cifra incluye arrumes que todavía no se han
   guardado: arrumes.js suma en vivo lo que se va digitando. */
.tablero-sin-guardar {
  font-size: 11.5px; font-weight: 500; margin-top: 4px;
  color: rgba(255, 255, 255, .62);
}

/* Los botones de corregir o anular un arrume pueden bajar de renglón en una
   pantalla angosta, en vez de apretar la ayuda hasta dejarla letra por letra. */
.acciones-fila { flex-wrap: wrap; }

/* Corregir o anular un arrume en el TELÉFONO. La rejilla de las filas
   guardadas solo sabe dónde van las celdas con clase (numeral, peso,
   canastas...); estas filas traen casillas y botones sin esas clases, y en la
   rejilla caían en cualquier parte. Se apilan como la fila de captura. */
@media (max-width: 640px) {
  .arrumes-tabla tbody tr.fila-corrigiendo,
  .arrumes-tabla tbody tr.fila-anulando {
    display: flex; flex-wrap: wrap; gap: 8px; padding: 10px;
  }
  .arrumes-tabla tr.fila-corrigiendo td,
  .arrumes-tabla tr.fila-anulando td { display: block; flex: 1 1 100%; min-width: 0; }
  .arrumes-tabla tr.fila-corrigiendo td:nth-child(2),
  .arrumes-tabla tr.fila-corrigiendo td:nth-child(3) { flex: 1 1 calc(50% - 4px); }
  .arrumes-tabla tr.fila-corrigiendo input { width: 100%; height: 44px; text-align: left; }
  .arrumes-tabla tr.fila-corrigiendo td:empty { display: none; }
}

/* ============================================================================
   DASHBOARD (15 sep 2026)
   Analítica de compras y recepción. Las tarjetas (.tarjetas/.tarjeta),
   la rejilla de KPI chicos (.tarjeta-kpi) y las barras (.asistente-grafico*)
   ya existían -- se reutilizan tal cual, sin duplicar reglas. Lo único
   nuevo es la frase-resumen de arriba, que necesitaba más aire y un color
   más firme que `.suave` para leerse como el titular de la página. */
.panorama {
  font-size: 15.5px; line-height: 1.5; color: var(--tinta);
  margin: 4px 0 20px; max-width: 70ch;
}
@media (max-width: 720px) {
  .panorama { font-size: 14.5px; }
}

/* ============================ LISTAS AGRUPADAS POR DÍA (24 sep 2026) ======
   Órdenes de compra y Recepción MP. El cliente: "luego serán 100, luego serán
   200 [...] agruparlas por día"; y al verlo con barras sueltas: "la
   presentación se ve muy pobre [...] no es lo suficientemente estética,
   limpia y profesional".

   Un día es UNA tarjeta, como una agenda: ficha de calendario, el nombre del
   día y sus cifras. Abierta, sus registros son FILAS de esa misma tarjeta,
   separadas por un filete -- no tarjetas sueltas con sombra cada una, que era
   lo que hacía ver la lista como un montón de cajas apiladas. */
.dia-grupo {
  margin: 0 0 12px;
  background: var(--superficie);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra);
  overflow: hidden;
}
.dia-cabecera {
  display: grid; grid-template-columns: auto 1fr auto auto;
  align-items: center; gap: 16px;
  padding: 12px 16px 12px 14px;
  cursor: pointer; list-style: none;
  -webkit-user-select: none; user-select: none;
  transition: background-color .15s ease;
}
.dia-cabecera::-webkit-details-marker { display: none; }
@media (hover: hover) { .dia-cabecera:hover { background: var(--superficie-2); } }
.dia-cabecera:focus-visible { outline: 2px solid var(--acento); outline-offset: -2px; }
.dia-grupo[open] > .dia-cabecera { border-bottom: 1px solid var(--linea); }

/* La ficha de calendario: el mes arriba, el día grande. Hoy va en el color
   de la marca -- es el único día que se destaca. */
.dia-ficha {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 46px; height: 50px; border-radius: 10px;
  background: var(--superficie-2); border: 1px solid var(--linea);
  font-variant-numeric: tabular-nums; line-height: 1;
}
.dia-mes { font-size: 9.5px; font-weight: 700; letter-spacing: .08em; color: var(--acento); }
.dia-num { margin-top: 4px; font-size: 19px; font-weight: 700; color: var(--tinta); letter-spacing: -.02em; }
.dia-ficha.es-hoy { background: var(--acento); border-color: var(--acento); }
.dia-ficha.es-hoy .dia-mes { color: rgba(255, 255, 255, .82); }
.dia-ficha.es-hoy .dia-num { color: #fff; }
/* Materia prima (1 oct 2026): la ficha es la fecha en que vence el primer
   lote del proveedor. Si vence pronto, en el tinte de alerta -- apagado, no
   el rojo de la marca, que es de la acción principal. Sin fecha, en gris:
   falta un dato que la norma exige. */
.dia-ficha.urge { background: var(--alerta-fondo); border-color: #f0c9c1; }
.dia-ficha.urge .dia-mes,
.dia-ficha.urge .dia-num { color: var(--alerta); }
.dia-ficha.sin-fecha .dia-mes { color: var(--tinta-suave); }
.dia-ficha.sin-fecha .dia-num { margin-top: 2px; font-size: 11px; font-weight: 600; color: var(--tinta-suave); }

.dia-texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dia-titulo { font-size: 15px; font-weight: 650; color: var(--tinta); letter-spacing: -.01em; }
.dia-sub { font-size: 12.5px; color: var(--tinta-suave); }
.dia-sub::first-letter { text-transform: uppercase; }
.dia-sub-movil { display: none; }

/* Las cifras del día: número arriba, qué es abajo. Alineadas a la derecha y
   con números tabulares, para que al bajar por los días se lean en columna. */
.dia-cifras { display: flex; align-items: center; }
.dia-cifra {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  min-width: 84px; padding: 0 16px;
}
.dia-cifra + .dia-cifra { border-left: 1px solid var(--linea); }
.dia-cifra strong {
  font-size: 15px; font-weight: 650; color: var(--tinta);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.dia-cifra span { font-size: 11px; color: var(--tinta-suave); }

.dia-flecha {
  position: relative; width: 30px; height: 30px; border-radius: 50%;
  background: var(--superficie-2); border: 1px solid var(--linea);
}
.dia-flecha::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 7px; height: 7px; margin: -5px 0 0 -3.5px;
  border-right: 1.8px solid var(--tinta-media); border-bottom: 1.8px solid var(--tinta-media);
  transform: rotate(45deg); transition: transform .2s cubic-bezier(.2, .8, .3, 1);
}
.dia-grupo[open] .dia-flecha::after { transform: translateY(3px) rotate(-135deg); }

/* ---- Lo de adentro: filas de la tarjeta del día, no tarjetas sueltas ---- */
.dia-cuerpo.registros { gap: 0; }
.dia-cuerpo .tarjeta-registro {
  border: 0; border-radius: 0; box-shadow: none; background: transparent;
  border-top: 1px solid var(--linea);
}
.dia-cuerpo .tarjeta-registro:first-child { border-top: 0; }
@media (hover: hover) {
  .dia-cuerpo .tarjeta-registro:hover,
  .dia-cuerpo .tarjeta-registro.trabajo:hover,
  .dia-cuerpo .tarjeta-registro.urgente:hover {
    background: var(--superficie-2); box-shadow: none;
  }
}
/* Lo terminado ya no retrocede con un fondo gris propio -- dentro de la
   tarjeta del día sería una franja gris por fila --; retrocede con el texto. */
.dia-cuerpo .tarjeta-registro.hecho,
.dia-cuerpo .tarjeta-registro.parcial,
.dia-cuerpo .tarjeta-registro.fuera { background: transparent; }

/* La tabla de recepciones, dentro de la tarjeta del día: sin su propio marco. */
.dia-cuerpo > table { border: 0; border-radius: 0; box-shadow: none; }
.dia-cuerpo > table.tabla-etiquetada.no-cabe tbody tr {
  margin: 0; border: 0; border-radius: 0; box-shadow: none;
  border-top: 1px solid var(--linea);
}
.dia-cuerpo > table.tabla-etiquetada.no-cabe tbody tr:first-child { border-top: 0; }

@media (max-width: 640px) {
  .dia-cabecera { grid-template-columns: auto 1fr auto; gap: 12px; padding: 11px 12px; }
  .dia-cifras { display: none; }
  .dia-sub-movil { display: block; color: var(--tinta-media); font-variant-numeric: tabular-nums; }
  .dia-ficha { width: 42px; height: 46px; }
  .dia-num { font-size: 17px; }
}
@media (prefers-reduced-motion: reduce) {
  .dia-flecha::after, .dia-cabecera { transition: none; }
}

/* ============================================================================
   La franja de la COPIA LOCAL (1 oct 2026). Solo sale con COPIA_LOCAL=1, que
   nunca se pone en el dominio: dice que lo que se ve es una copia de prueba
   en este PC y que nada de lo que se haga aquí llega a la planta.
   ========================================================================== */
.franja-local {
  padding: 6px 16px;
  background: var(--dato-fondo); color: var(--dato);
  border-bottom: 1px solid var(--dato-linea);
  font-size: 12.5px; font-weight: 600; text-align: center;
}

/* ============================================================================
   Producción: materia prima, entregas y conteo (1 oct 2026, sql/39)
   ========================================================================== */
.filtro-producto { margin: -8px 0 16px; }
table input.entrada-kg, .entrada-kg { width: 130px; max-width: 100%; text-align: right; font-variant-numeric: tabular-nums; }
/* Lo que propuso la app (FEFO) se distingue de lo que escribió la persona. */
.entrada-kg.sugerido { background: var(--dato-fondo); border-color: var(--dato-linea); }
.enlace-lote { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--linea-fuerte); }
.enlace-lote:hover { color: var(--acento-fuerte); border-bottom-color: var(--acento); }
/* Anulado: queda a la vista (la norma no deja borrarlo), pero no suma. */
tr.anulada-fila td { color: var(--tinta-suave); }
tr.anulada-fila td.num { text-decoration: line-through; }
.otros-lotes { margin: 8px 12px 12px; padding: 10px 12px; border: 1px solid var(--dato-linea);
  border-radius: var(--r-control); background: var(--dato-fondo); }
.otros-lotes form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.otros-lotes form + form { margin-top: 8px; }
.otros-lotes .falta { color: var(--alerta); font-weight: 600; }
/* Los datos del lote en su ficha. Nombre propio: `.ficha` ya es la pastilla
   del buscador y las dos reglas se pisaban (la franja salía recortada). */
.datos-lote {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1px; background: var(--linea);
  border: 1px solid var(--linea); border-radius: var(--r-caja);
  overflow: hidden; margin-bottom: 20px;
}
.datos-lote > div {
  background: var(--superficie); padding: 12px 16px;
  display: flex; flex-direction: column; gap: 5px; align-items: flex-start;
  font-size: 13.5px; min-width: 0;
}
.datos-lote .etiqueta {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--tinta-suave); font-weight: 600;
}
.otros-lotes label { margin: 0; font-style: normal; font-size: 13px; font-weight: 600; color: var(--tinta-media); }
.otros-lotes input[type="date"] { width: 170px; }
/* Conteo y entrega: una tabla por producto, y todas con las mismas columnas.
   Con el ancho automático cada tabla se medía sola y las columnas bailaban de
   un producto al siguiente. (En el celular tabla_movil.js las vuelve fichas.) */
@media (min-width: 761px) {
  table.tabla-alineada { table-layout: fixed; }
  table.tabla-alineada th:nth-child(1) { width: 16%; }
  table.tabla-alineada th:nth-child(2) { width: 30%; }
  table.tabla-alineada th:nth-child(3) { width: 24%; }
  table.tabla-alineada th:nth-child(4) { width: 15%; }
  table.tabla-alineada th:nth-child(5) { width: 15%; }
}

/* ----------------------------------------------------------------------------
   Columnas ALINEADAS entre tablas hermanas (el cliente, 1 oct 2026: "los
   encabezados tienen que estar alineados, no se pueden correr"). Cada
   proveedor es su propia tabla; con el ancho automático cada una medía sus
   columnas sola y "Lote" quedaba en un sitio distinto en cada una. Con
   `table-layout: fixed` y anchos fijos en el <colgroup>, todas son iguales;
   producto y proveedor se reparten lo que sobra.
   Solo en pantallas anchas: por debajo, tabla_movil.js tiene que poder medir
   que la tabla no cabe y volverla fichas, y con ancho fijo nunca "no cabe".
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  table.tabla-mp { table-layout: fixed; width: 100%; }
  table.tabla-mp col.c-lote   { width: 112px; }
  table.tabla-mp col.c-fecha  { width: 104px; }
  table.tabla-mp col.c-vence  { width: 236px; }
  table.tabla-mp col.c-cadena { width: 112px; }
  table.tabla-mp col.c-kg     { width: 116px; }
  table.tabla-mp col.c-accion { width: 104px; }
  table.tabla-mp col.c-accion-ancha { width: 210px; }
  table.tabla-mp td, table.tabla-mp th { overflow-wrap: anywhere; }
}

/* Una cifra que lleva a su detalle (Reservado -> órdenes reservadas). */
a.tarjeta-enlace { color: inherit; text-decoration: none; transition: border-color .15s ease; }
a.tarjeta-enlace:hover { border-color: var(--linea-fuerte); }
a.tarjeta-enlace:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

/* Orden de producción: los tres pasos, y en cuál va (1 oct 2026). */
.chip.dato { background: var(--dato-fondo); color: var(--dato); }
.pasos {
  list-style: none; margin: 0 0 20px; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
}
.pasos li {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  background: var(--superficie); border: 1px solid var(--linea); border-radius: var(--r-caja);
  color: var(--tinta-suave); min-width: 0;
}
.pasos li > span:last-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pasos small { font-size: 12px; color: var(--tinta-suave); }
.pasos-num {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--neutro-fondo); color: var(--tinta-media); font-weight: 700; font-size: 13px;
}
.pasos li.actual { border-color: var(--dato-linea); background: var(--dato-fondo); color: var(--tinta); }
.pasos li.actual .pasos-num { background: var(--dato); color: #fff; }
.pasos li.hecho { color: var(--tinta); }
.pasos li.hecho .pasos-num { background: var(--bien-fondo); color: var(--bien); }
.acciones-paso { padding: 14px 16px; border-top: 1px solid var(--linea); flex-wrap: wrap; }
@media (max-width: 760px) {
  .pasos { grid-template-columns: 1fr; }
}
@media (min-width: 1024px) { table.tabla-mp col.c-acabo { width: 130px; } }
table.tabla-mp input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--dato); }
table.tabla-mp .centro { text-align: center; }
/* Las tablas de Producción NO parten palabras por cualquier letra debajo de
   1024 px: con `overflow-wrap: anywhere` (la regla general de tbody td) una
   tabla de seis columnas "cabía" a 390 px partiendo "PERNIL" en "PE/RNI/L", y
   tabla_movil.js, que mide si cabe, nunca la volvía tarjetas. Partiendo solo
   en los espacios, la que no cabe se vuelve tarjetas como debe. */
@media (max-width: 1023px) {
  table.tabla-mp tbody td, table.tabla-mp tfoot td { overflow-wrap: normal; word-break: normal; }
}

/* ----------------------------------------------------------------------------
   Nueva orden de producción, un paso a la vez (1 oct 2026)
   -------------------------------------------------------------------------- */
/* `.panel` recorta lo que sobresale (overflow: hidden, para las esquinas
   redondeadas de sus tablas). Un panel con un buscador adentro NO puede
   recortar: la lista de opciones se abre hacia abajo y quedaba escondida. */
.panel.con-listas { overflow: visible; }
.panel-aviso { border-color: #f0c9c1; background: var(--alerta-fondo); }

.paso-titulo {
  display: flex; align-items: center; gap: 10px;
  margin: 24px 0 12px; font-size: 16px; font-weight: 650; color: var(--tinta);
  text-transform: none; letter-spacing: -.01em;
}
.paso-orden > .paso-titulo:first-child { margin-top: 4px; }
.paso-titulo .pasos-num { background: var(--dato); color: #fff; }
.paso-titulo .suave { font-weight: 500; font-size: 14px; }
.paso-ayuda { margin: -4px 0 12px; font-size: 13px; color: var(--tinta-media); }

/* La materia prima, en tarjetas a la vista: son pocas y así se ven todas,
   con su nombre entero. Es un radio de verdad debajo (teclado y lector de
   pantalla funcionan); la tarjeta es solo cómo se ve. */
.opciones-mp {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.opcion-mp {
  position: relative; display: flex; flex-direction: column; gap: 4px;
  padding: 14px 16px; min-height: 92px; cursor: pointer;
  background: var(--superficie); border: 1px solid var(--linea); border-radius: var(--r-caja);
  box-shadow: var(--sombra); transition: border-color .15s ease, background-color .15s ease;
}
.opcion-mp input { position: absolute; opacity: 0; pointer-events: none; }
.opcion-mp strong { font-size: 14px; line-height: 1.3; color: var(--tinta); }
.opcion-mp-kg { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--tinta); }
.opcion-mp-sub { font-size: 12px; color: var(--tinta-suave); }
.opcion-mp-sub.urge { color: var(--alerta); font-weight: 600; }
@media (hover: hover) { .opcion-mp:hover { border-color: var(--linea-fuerte); } }
.opcion-mp:focus-within { outline: 2px solid var(--dato); outline-offset: 2px; }
.opcion-mp.sel, .opcion-mp:has(input:checked) {
  border-color: var(--dato); background: var(--dato-fondo); box-shadow: 0 0 0 1px var(--dato) inset;
}

.fila-kilos { display: flex; gap: 10px; align-items: stretch; max-width: 420px; }
.fila-kilos input { flex: 1 1 auto; min-width: 0; font-size: 16px; text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
  .opciones-mp { grid-template-columns: 1fr; }
  .opcion-mp { min-height: 0; }
  .fila-kilos { max-width: none; }
}

/* La lista abierta del buscador va POR ENCIMA de los botones flotantes
   (micrófono y asistente, z-index 40): tapaban las primeras opciones cuando
   el campo quedaba abajo de la pantalla (1 oct 2026). */
.buscador-panel { z-index: 45; }

/* "Transformable: sí o no" en el recibo (el cliente, 1 oct 2026; sql/40).
   Las dos opciones van en cajas del alto de un campo: en el muelle se tocan
   con el dedo, sin apuntarle al círculo. Debajo es un radio de verdad
   (teclado y lector de pantalla funcionan); marcada, se ve como la tarjeta
   elegida de "Nueva orden de producción" (.opcion-mp). */
.si-no .opciones { gap: 8px; }
.si-no .opciones label {
  flex: 1 1 0; justify-content: center; min-width: 68px;
  height: var(--alto-control); padding: 0 14px;
  border: 1px solid var(--linea-fuerte); border-radius: var(--r-control);
  background: #fff; transition: border-color .15s ease, background-color .15s ease;
}
@media (hover: hover) { .si-no .opciones label:hover { border-color: #b9c0c9; } }
.si-no .opciones label:has(input:checked) {
  border-color: var(--dato); background: var(--dato-fondo); box-shadow: 0 0 0 1px var(--dato) inset;
}
/* El aro de foco, solo con teclado: al tocar con el dedo ya se ve marcada. */
.si-no .opciones label:has(input:focus-visible) { outline: 2px solid var(--dato); outline-offset: 2px; }
.si-no input[type=radio] { accent-color: var(--dato); flex: 0 0 auto; }
.si-no input[type=radio]:focus { box-shadow: none; }
@media (pointer: coarse) {
  .si-no .opciones label { height: auto; min-height: 44px; font-size: 16px; }
}
/* El aviso de lo que falta en el producto puede ser largo ("Falta peso que
   llegó, producción, planta, transformable"): en el celular se parte en dos
   renglones en vez de salirse de la pantalla. */
.datos-factura > summary .chip { white-space: normal; }

/* El formulario de "Agregar producto" del recibo, en pantallas anchas (1 oct
   2026). Con nueve campos en un renglón se repartían el ancho por igual y el
   nombre del producto quedaba cortado ("PECHUGA A GRANEL (BLA") y los rótulos
   largos partidos en dos ("Peso que llegó (kg, / opcional)"). El producto
   lleva ancho para el nombre más largo del catálogo, y los demás, el de su
   rótulo; lo que no quepa baja al renglón siguiente. Solo aquí: las otras
   `fila-encabezado` tienen pocos campos. En el celular ya van de a dos. */
@media (min-width: 900px) {
  .producto-nuevo .fila-encabezado > div { flex-basis: 184px; min-width: 184px; }
  .producto-nuevo .fila-encabezado > div.campo-producto { flex: 3 1 360px; min-width: 340px; }
  .producto-nuevo .fila-encabezado > div.al-final { flex: 0 0 auto; min-width: 0; }
  .producto-nuevo .fila-encabezado > div > label { white-space: nowrap; }
}

/* En el celular los campos van a 16 px (iOS hace zoom con menos) y el nombre
   más largo del catálogo, "PECHUGA GRANEL TIPO MAC POLLO", no cabía por 9 px
   en el buscador de productos. Medido con scrollWidth contra clientWidth. La
   letra un pelo más junta y la flecha más cerca del borde le dan 13 px. Y si
   algún día un nombre no cabe, que se note con puntos suspensivos. */
.buscador-caja input { text-overflow: ellipsis; }
@media (pointer: coarse) {
  .buscador-caja input { letter-spacing: -0.02em; padding-right: 30px; background-position: right 8px center; }
}

/* ==========================================================================
   PRODUCCIÓN · CUATRO TARJETAS Y SU LISTA (1 oct 2026)
   --------------------------------------------------------------------------
   La versión que el cliente aprobó en boceto. Antes hubo aquí un tablero de
   columnas con una banda negra y cifras de 44 px: "no tiene nada que ver con
   la aplicación [...] recargando de manera exagerada con los números
   grandes". Esta usa lo que la app ya tiene: tarjetas blancas, letra de
   tamaño normal, tablas en panel y los iconos de la casa.
   Todo lleva `pt-` para no chocar con clases de otras pantallas.
   ========================================================================== */
.pt-tarjetas { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin: 0 0 20px; }
/* Lo disponible (29 oct 2026, sql/54): el total pequeño, la PECHUGA PARA
   PRODUCCIÓN ancha -- la protagonista -- y las PRESAS. */
.pt-disponible {
  display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 2.3fr) minmax(0, 1fr);
  gap: 14px; margin: 0 0 14px;
}
.pt-disponible .pt-tarjeta.sel::after { display: none; }
.pt-total { background: transparent; box-shadow: none; cursor: default; }
.pt-total:active { transform: none; }
.pt-total .pt-nombre { color: var(--tinta-media); font-weight: 600; }
.pt-partes { display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; color: var(--tinta-media); }
.pt-partes b, .pt-productos b { font-weight: 650; color: var(--tinta); font-variant-numeric: tabular-nums; margin-right: 4px; }
.pt-pechuga { border-color: var(--acento); }
.pt-pechuga .pt-nombre { font-size: 15px; color: var(--acento-fuerte); }
.pt-pechuga .pt-icono { background: var(--acento-tenue); color: var(--acento-fuerte); }
.pt-pechuga .pt-kg { font-size: 26px; }
.pt-cuerpo { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }
.pt-productos {
  display: grid; grid-template-columns: repeat(3, minmax(0, auto)); gap: 4px 24px;
  font-size: 12.5px; color: var(--tinta-media);
}
.pt-tarjeta {
  position: relative; display: flex; flex-direction: column; gap: 10px; padding: 16px 18px 14px;
  background: var(--superficie); border: 1px solid var(--linea-fuerte); border-radius: var(--r-caja);
  box-shadow: var(--sombra); color: inherit; text-decoration: none; cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, transform .14s ease-out;
}
@media (hover: hover) and (pointer: fine) { .pt-tarjeta:hover { border-color: var(--tinta-suave); } }
.pt-tarjeta:active { transform: scale(.985); }
.pt-tarjeta:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }
.pt-cab { display: flex; align-items: center; gap: 10px; min-width: 0; }
.pt-icono {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--neutro-fondo); color: var(--tinta-media);
}
.pt-nombre { font-size: 14px; font-weight: 650; color: var(--tinta); }
.pt-kg { font-size: 22px; font-weight: 650; letter-spacing: -.02em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pt-kg em { font-size: 12px; font-style: normal; font-weight: 500; color: var(--tinta-suave); margin-left: 4px; }
.pt-pie { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12.5px; color: var(--tinta-media); }
.pt-donde { display: block; margin-top: -4px; font-size: 12px; line-height: 1.35; color: var(--tinta-suave); }
.pt-ver { display: inline-flex; align-items: center; gap: 4px; font-weight: 600; color: var(--acento-fuerte); white-space: nowrap; }
/* LA ELEGIDA: el mismo rojo suave de la opción marcada en el menú de arriba,
   borde rojo, "Viendo" con su visto, y una punta que señala la lista de
   abajo. El cliente: "algo tiene que pasar en la tarjeta para que el usuario
   sepa en cuál está". */
.pt-tarjeta.sel { background: var(--acento-tenue); border-color: var(--acento); box-shadow: 0 0 0 1px var(--acento) inset; }
.pt-tarjeta.sel .pt-icono { background: #fff; color: var(--acento-fuerte); }
.pt-tarjeta.sel .pt-nombre { color: var(--acento-fuerte); }
.pt-tarjeta.sel::after {
  content: ""; position: absolute; left: 50%; bottom: -9px; width: 14px; height: 14px;
  margin-left: -7px; transform: rotate(45deg);
  background: var(--acento-tenue); border-right: 2px solid var(--acento); border-bottom: 2px solid var(--acento);
}

/* Lo que está en la cava pero NO es disponible (vencido, recibiéndose, no
   aceptado): un renglón, y solo si hay alguno. */
.fuera-total { margin: -6px 0 16px; font-size: 13px; color: var(--tinta-suave); }
.fuera-total a { color: var(--tinta-media); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--linea-fuerte); }
.fuera-total a.alerta { color: var(--alerta); font-weight: 600; }
.fuera-total a.sel { color: var(--tinta); font-weight: 650; text-decoration-color: currentColor; }

/* La lista de la tarjeta elegida. */
.pt-lista { margin-top: 6px; }
.pt-titulo { display: flex; align-items: baseline; justify-content: space-between; gap: 6px 16px; flex-wrap: wrap; margin: 0 0 10px; }
.pt-titulo h2 { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -.01em; text-transform: none; color: var(--tinta); }
.pt-titulo span { font-size: 13px; color: var(--tinta-media); }
.pt-titulo.pt-segundo { margin-top: 26px; }
.pt-tabla td, .pt-tabla th { vertical-align: middle; }
.pt-tabla .acciones-col { text-align: right; white-space: nowrap; }
/* Suprema lista en el celular (5 nov 2026): partiendo por cualquier letra la
   tabla de siete columnas "cabía" a 390 px con una letra por renglón, y
   tabla_movil.js nunca la volvía fichas. Igual que en tabla-mp: solo en los
   espacios, y la que no cabe se vuelve fichas. */
@media (max-width: 1023px) {
  table.pt-tabla thead th, table.pt-tabla tbody td { overflow-wrap: normal; word-break: normal; }
}
/* ---- la lista por proveedor, desplegable -----------------------------------
   Cada proveedor es un <details>: un renglón con su "+" y, adentro, sus
   lotes. El cliente: "no veo la jerarquía [...] debería haber un 'más' para
   desplegar y, dentro, ver los productos". La jerarquía se marca con TRES
   cosas a la vez: el icono (camión = proveedor, caja = producto), el peso de
   la letra (el proveedor en negrilla, el producto normal) y la sangría.
   Las columnas se alinean con la misma rejilla en el encabezado, en el
   renglón del proveedor y en cada lote. */
.pt-acordeon { --pt-cols: minmax(0, 1fr) 130px 290px 150px; }
.pt-acordeon.con-destino { --pt-cols: minmax(0, 1fr) 130px 290px 150px 130px; }
.pt-acordeon.con-botones { --pt-cols: minmax(0, 1fr) 130px 290px 150px 190px; }
/* Con el reparto del lote: Llegó · En producción · Para venta · Disponible. */
.pt-acordeon.con-reparto.con-destino { --pt-cols: minmax(0, 1fr) 100px 240px 120px 120px 120px 130px 120px; }
.pt-acordeon.con-reparto.con-botones { --pt-cols: minmax(0, 1fr) 100px 240px 120px 120px 120px 130px 180px; }
/* Disponible (sql/44): Llegó · Transformar · Reempacar · Para venta ·
   Disponible y "Repartir". Los tres destinos van bajo un mismo "Va para". */
.pt-acordeon.con-va { --pt-cols: minmax(0, 1fr) 92px 200px 104px 104px 104px 104px 112px 104px; }
.pt-acordeon.con-va .pt-rejilla { column-gap: 14px; }
.pt-acordeon.con-va .pt-prov-nombre strong { white-space: nowrap; }
.pt-enc.pt-enc-va { min-height: 0; padding-top: 10px; border-bottom: 0; }
.pt-va-sobre { grid-column: 5 / span 3; text-align: center; padding-bottom: 6px; border-bottom: 1px solid var(--linea); }
.pt-otro { font-variant-numeric: tabular-nums; color: var(--tinta-media); white-space: nowrap; }
.pt-otro.cero { color: var(--tinta-suave); }
.pt-prov > summary .pt-otro { font-weight: 600; }
.pt-rejilla { display: grid; grid-template-columns: var(--pt-cols); align-items: center; column-gap: 16px; padding: 0 16px; }
.pt-rejilla > .num { text-align: right; }
.pt-enc {
  min-height: 38px; background: var(--superficie-2); border-bottom: 1px solid var(--linea);
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .07em; color: var(--tinta-suave);
}
.pt-prov + .pt-prov { border-top: 1px solid var(--linea); }
.pt-prov > summary {
  min-height: 52px; cursor: pointer; list-style: none; user-select: none;
  transition: background-color .15s ease;
}
.pt-prov > summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) { .pt-prov > summary:hover { background: var(--superficie-2); } }
.pt-prov > summary:focus-visible { outline: 2px solid var(--acento); outline-offset: -2px; }
.pt-prov[open] > summary { background: var(--superficie-2); border-bottom: 1px solid var(--linea); }
.pt-prov-nombre { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--tinta-media); }
.pt-prov-nombre strong { font-size: 14px; font-weight: 650; color: var(--tinta); }
.pt-prov-meta { font-size: 12.5px; color: var(--tinta-suave); white-space: nowrap; }
/* El "+": un cuadro con el signo, que pasa a "−" al desplegar. */
.pt-mas {
  position: relative; flex: 0 0 auto; width: 22px; height: 22px; border-radius: 6px;
  border: 1px solid var(--linea-fuerte); background: var(--superficie); color: var(--tinta);
}
.pt-mas::before, .pt-mas::after {
  content: ""; position: absolute; left: 50%; top: 50%; background: currentColor; border-radius: 1px;
}
.pt-mas::before { width: 10px; height: 2px; margin: -1px 0 0 -5px; }
.pt-mas::after  { width: 2px; height: 10px; margin: -5px 0 0 -1px; transition: transform .15s ease-out; }
.pt-prov[open] > summary .pt-mas::after { transform: scaleY(0); }
.pt-prov[open] > summary .pt-mas { border-color: var(--acento); color: var(--acento-fuerte); }
.pt-prov-kg { font-weight: 650; color: var(--tinta); font-variant-numeric: tabular-nums; }
/* Abierto, la urgencia ya se lee en el lote: no se dice dos veces. */
.pt-prov[open] > summary .pt-prov-vence { visibility: hidden; }
/* Los lotes del proveedor: con sangría, la caja delante y letra normal. */
.pt-lote { min-height: 56px; padding-top: 8px; padding-bottom: 8px; }
.pt-lote + .pt-lote, .pt-reparto + .pt-lote { border-top: 1px solid var(--linea); }
.pt-prod { display: flex; align-items: center; gap: 10px; min-width: 0; padding-left: 42px; color: var(--tinta-suave); }
.pt-prod > span { font-size: 14px; font-weight: 500; color: var(--tinta); }
.pt-kilos strong { font-variant-numeric: tabular-nums; }
.pt-accion { text-align: right; white-space: nowrap; }
.pt-todos {
  padding: 0; border: 0; background: none; cursor: pointer; font: inherit; font-size: 13px;
  color: var(--tinta-media); text-decoration: underline; text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) { .pt-todos:hover { color: var(--tinta); } }
.pt-bajo { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 400; color: var(--tinta-suave); }
/* El reparto, pegado al renglón del lote. */
.pt-reparto { background: var(--dato-fondo); padding: 14px 16px 16px; }
.pt-campos { display: flex; align-items: flex-end; gap: 14px 16px; flex-wrap: wrap; padding-left: 42px; }
.pt-campos > div { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.pt-campos .entrada-kg { width: 150px; }
.pt-campos label { white-space: nowrap; }
/* El eco de numeros.js ("Se guarda: 1.800 kg (miles)") se cuelga de la
   etiqueta: aquí no cabe sin mover los campos, y la cuenta de al lado
   ("Quedan disponibles") ya dice lo mismo con todos sus ceros. */
.pt-campos label > .eco-numero { display: none; }
/* El reparto con "Va para" (sql/44): las tres opciones arriba y, debajo, la
   rejilla del destino marcado. Transformar: los dos turnos en columnas, con
   la fecha y los kilos de cada uno; reempacar y venta: solo los kilos. */
.pt-va { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; padding-left: 42px; }
.pt-va-opciones { padding-bottom: 10px !important; border-bottom: 1px dashed var(--linea) !important;
                  width: 100%; max-width: 560px; }
.pt-va-opciones .opciones { gap: 22px; flex-wrap: wrap; }
.pt-va-rejilla { display: grid; grid-template-columns: 70px 200px 200px; gap: 8px 12px; align-items: center; }
.pt-va-rejilla[hidden] { display: none; }
.pt-va-rejilla input { width: 100%; }
.pt-va-col { font-size: 13px; font-weight: 600; color: var(--tinta); }
.pt-va-col span { display: block; margin-top: 2px; font-size: 12.5px; font-weight: 400; color: var(--tinta-media); }
.pt-va-fila { font-size: 13px; font-weight: 500; color: var(--tinta-media); }
.pt-va .pt-queda { padding-bottom: 0; }
.pt-va .pt-motivo { width: 100%; }
/* Un turno: su fecha y sus kilos, bajo el nombre y el horario (8 oct 2026). */
.pt-turno-campos { display: flex; gap: 8px; }
.pt-turno-campos input[type=date] { width: 170px; }
/* Una cifra que se está restando mientras se reparte: en azul, para que se
   note que es un avance y todavía no está guardado. */
.restando, .pt-acordeon .restando, .pt-tarjeta .restando { color: var(--dato); transition: color .15s ease; }
.pt-queda { font-size: 13px; color: var(--tinta-media); padding-bottom: 9px; margin: 0; }
.pt-queda strong { color: var(--tinta); font-variant-numeric: tabular-nums; }
.pt-queda.de-mas, .pt-queda.de-mas strong { color: var(--alerta); font-weight: 600; }
.pt-motivo { flex: 1 1 100%; max-width: 620px; }
.pt-entro { margin: 0; font-size: 14px; color: var(--tinta-media); }
.pt-entro strong { color: var(--tinta); }
.formulario > .pt-queda { padding-bottom: 0; font-size: 14px; }
.panel-cifras.sin-borde { border-bottom: 0; }
.pt-conteo { margin: 28px 0 96px; font-size: 13px; color: var(--tinta-suave); }
.pt-conteo a { color: var(--tinta-media); text-decoration: underline; text-underline-offset: 3px; }

/* El porcentaje de pérdida aceptado, al pie del historial: un renglón. */
.perdida-aceptada { margin: 18px 0 96px; font-size: 13px; color: var(--tinta-media); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.perdida-aceptada strong { color: var(--tinta); }
.perdida-aceptada a:not(.boton) { color: var(--tinta-media); text-decoration: underline; text-underline-offset: 3px; }
.perdida-aceptada form { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.perdida-aceptada input { width: 96px; text-align: right; }

@media (max-width: 1500px) {
  /* Con cinco tarjetas y siete columnas, en un portátil el vencimiento va
     más angosto para que quepa todo sin partir las cifras. */
  .pt-acordeon.con-reparto.con-destino { --pt-cols: minmax(0, 1fr) 84px 190px 104px 104px 104px 112px 110px; }
  .pt-acordeon.con-reparto.con-botones { --pt-cols: minmax(0, 1fr) 84px 190px 104px 104px 104px 112px 168px; }
  .pt-acordeon.con-reparto .pt-rejilla { column-gap: 12px; }
  .pt-acordeon.con-va { --pt-cols: minmax(0, 1fr) 84px 180px 100px 100px 100px 100px 104px 100px; }
  .pt-acordeon.con-va .pt-rejilla { column-gap: 10px; }
}
@media (max-width: 1280px) {
  .pt-tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pt-disponible { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .pt-disponible .pt-total { grid-column: 1 / -1; flex-direction: row; align-items: baseline; flex-wrap: wrap; gap: 6px 18px; }
  .pt-disponible .pt-total .pt-partes { flex-direction: row; gap: 16px; }
  .pt-productos { grid-template-columns: repeat(2, minmax(0, auto)); }
}
@media (max-width: 1100px) {
  .pt-tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .pt-tarjetas { gap: 10px; }
  .pt-disponible { grid-template-columns: 1fr; gap: 10px; margin-bottom: 10px; }
  .pt-productos { grid-template-columns: 1fr; }
  .pt-pechuga .pt-kg { font-size: 22px; }
  .pt-cuerpo { gap: 10px; }
  .pt-tarjeta { padding: 14px 12px 12px; gap: 8px; }
  .pt-icono { width: 32px; height: 32px; }
  .pt-nombre { font-size: 13px; }
  .pt-kg { font-size: 19px; }
  .pt-pie { flex-direction: column; align-items: flex-start; gap: 4px; font-size: 12px; }
  /* La lista por proveedor, en el celular: el proveedor es un renglón con su
     "+" y su total; cada lote, un bloque con el producto y los kilos arriba y
     sus datos debajo, cada uno con su rótulo. */
  .pt-enc { display: none; }
  .pt-rejilla { grid-template-columns: minmax(0, 1fr) auto; row-gap: 4px; padding: 12px 14px; }
  .pt-prov > summary { align-items: start; }
  .pt-prov > summary > span:empty { display: none; }
  .pt-prov-nombre { flex-wrap: wrap; row-gap: 2px; }
  .pt-prov-nombre .pt-prov-meta { flex: 1 1 100%; padding-left: 32px; }
  .pt-prov-vence { grid-column: 1 / -1; padding-left: 32px; }
  .pt-prov[open] > summary .pt-prov-vence { display: none; }
  .pt-prov-vence:empty { display: none; }
  .pt-prov-kg { grid-column: 2; grid-row: 1; }
  .pt-prod { padding-left: 0; grid-column: 1; }
  .pt-lote .pt-kilos { grid-column: 2; grid-row: 1; }
  .pt-lote .pt-dato { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; padding-left: 25px; }
  .pt-lote .pt-otro.pt-dato { justify-content: flex-start; text-align: left; }
  .pt-lote .pt-otro.pt-dato::before { min-width: 104px; }
  .pt-prov > summary .pt-otro { display: none; }
  .pt-lote .pt-dato::before { content: attr(data-rotulo); min-width: 56px; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--tinta-suave); }
  .pt-lote .pt-accion { grid-column: 1 / -1; margin-top: 6px; }
  .pt-lote .pt-accion .boton { width: 100%; justify-content: center; }
  .pt-lote .pt-accion:empty { display: none; }
  .pt-campos { padding-left: 0; }
  .pt-campos > div { flex: 1 1 44%; }
  .pt-campos .entrada-kg { width: 100%; }
  .pt-campos > .pt-turno { flex: 1 1 100%; }
  .pt-turno-campos input[type=date] { flex: 1 1 55%; width: auto; min-width: 0; }
  .pt-turno-campos .entrada-kg { flex: 1 1 45%; min-width: 0; }
  .pt-campos .pt-queda, .pt-campos .pt-guardar { flex: 1 1 100%; padding-bottom: 0; }
  .pt-campos .pt-guardar .boton { width: 100%; justify-content: center; }
  .pt-acordeon.con-va .pt-prov-nombre strong { white-space: normal; }
  .pt-va { padding-left: 0; align-items: stretch; }
  .pt-va-opciones { max-width: none; }
  .pt-va-rejilla { grid-template-columns: 64px minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
  .pt-va-rejilla input { min-width: 0; }
  .pt-va-rejilla input[type=date] { font-size: 14px; padding-left: 8px; padding-right: 4px; }
  .pt-va-rejilla input[type=date]::-webkit-calendar-picker-indicator { margin-left: 0; }
  .pt-va .pt-guardar .boton { width: 100%; justify-content: center; }
}

/* El filtro de producto de Materia prima: ancho para el nombre más largo del
   catálogo con la × de quitar al lado. Con los 230 px de los demás filtros,
   "PECHUGA A GRANEL (BLANCA)" quedaba en "PECHUGA A GRANEL (BLA…" (1 oct
   2026, medido al usar el filtro). En el celular ya va a todo lo ancho. */
.filtro-producto input.buscador-campo, .filtro-producto select { min-width: 330px; }

/* "Nueva orden de compra": un renglón de producto a la vista y los demás
   ocultos hasta que se pidan (renglones.js). `display: flex` de la fila le
   ganaba al atributo `hidden`, así que hay que decirlo. */
.fila-encabezado[hidden] { display: none; }
.otro-renglon { margin: -4px 0 0; }

/* ===================================================== operarios y empaque
   sql/45, 12 oct 2026: la tabla de operarios de una tanda de transformar, la
   pantalla de empaque y el catálogo de referencias. */
.pasos.pasos-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.tabla-operarios .entrada-kg { width: 110px; text-align: right; }
.tabla-operarios tfoot td { font-weight: 650; border-top: 2px solid var(--linea-fuerte); background: var(--superficie-2); }
.tabla-operarios tr.fila-escribe td { background: var(--dato-fondo); }
.sangre-calc { color: var(--dato); font-weight: 600; font-variant-numeric: tabular-nums; }
.sangre-calc.de-mas { color: var(--alerta); }
.operarios-vacio { margin: 0; padding: 16px; font-size: 14px; color: var(--tinta-media); }
.operarios-pie { display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap; padding: 14px 16px; border-top: 1px solid var(--linea); }
.operarios-pie input[name=operario] { width: 220px; }
.operarios-pie .entrada-kg { width: 150px; text-align: right; }
.operarios-nota { margin: 0; font-size: 13px; color: var(--tinta-media); }
.operarios-nota strong { color: var(--tinta); }
/* Lo que falta por repartir en una tanda (16 oct 2026, sql/49): merma de
   proceso, o pasa a reempacar o a venta. Las filas de abajo de la tabla dicen
   a dónde fue lo que ningún operario recibió. */
.operarios-sobra { background: var(--superficie-2); }
.operarios-sobra { flex-direction: column; align-items: flex-start; }
.operarios-sobra .pt-va-opciones { max-width: 560px; }
.operarios-sobra .pt-queda { padding-bottom: 0; font-size: 14px; }
.operarios-sobra .pt-queda[hidden] { display: none; }
/* «Sale para» de una orden por sacar: las opciones arriba de la tabla y, abajo,
   los campos de reempacar o venta (igual que «Repartir»). */
.sale-para { padding: 14px 16px 0; }
.sale-para .pt-va-opciones { max-width: 560px; }
.sale-bloques { padding: 14px 16px 0; }
.sale-bloques .pt-va-rejilla[hidden] { display: none; }
.tabla-operarios tr.fila-sobra td { background: var(--superficie-2); }
.tabla-operarios tr.fila-sobra td.num { font-variant-numeric: tabular-nums; }
table.tabla-mp td small { white-space: normal; }
/* En el celular la tabla son tarjetas: la casilla de lo que sale se va entera cuando se marca otro destino. */
@media (max-width: 1023px) { table.tabla-mp td:has(> [data-destino][hidden]) { display: none; } }

.empaque-cab { display: flex; align-items: flex-end; gap: 14px 28px; flex-wrap: wrap; padding: 14px 16px; border-bottom: 1px solid var(--linea); }
.empaque-cab > div { display: flex; flex-direction: column; gap: 6px; }
.empaque-cab input[type=date] { width: 180px; }
.empaque-dato span { font-size: 12.5px; color: var(--tinta-media); }
.empaque-dato strong { font-size: 14px; }
.empaque-buscar { margin-left: auto; }
.empaque-buscar input { width: 220px; }
.empaque-grupo td { background: var(--superficie-2); font-size: 11px; font-weight: 650; letter-spacing: .06em;
                    text-transform: uppercase; color: var(--tinta-media); }
.tabla-empaque td label { font-weight: 500; cursor: pointer; }
.tabla-empaque .entrada-paquetes { width: 96px; text-align: right; }
/* Por peso (sql/55): «kg» dentro de la casilla, para que todas queden alineadas. */
.empaque-cantidad { position: relative; display: inline-block; }
.empaque-cantidad > .suave { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); pointer-events: none; font-size: 13px; }
[data-por-peso] .entrada-paquetes { padding-right: 32px; }
.tabla-empaque [data-empaque-kg] { font-variant-numeric: tabular-nums; color: var(--tinta-suave); }
.tabla-empaque [data-empaque-kg].restando { color: var(--dato); font-weight: 600; }
.tabla-empaque tr[hidden], .tabla-empaque tbody[hidden] { display: none; }
.empaque-nota { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border-top: 1px solid var(--linea); max-width: 620px; }
.empaque-total { position: sticky; bottom: 0; z-index: 2; display: flex; justify-content: space-between; align-items: center;
                 gap: 12px 16px; flex-wrap: wrap; padding: 14px 16px; background: var(--superficie);
                 border-top: 1px solid var(--linea-fuerte); border-radius: 0 0 var(--r-caja) var(--r-caja); }
.empaque-total p { margin: 0; font-size: 14px; color: var(--tinta-media); }
.empaque-total p strong { color: var(--tinta); font-variant-numeric: tabular-nums; }
.empaque-total p.de-mas, .empaque-total p.de-mas strong { color: var(--alerta); }

.referencias-nueva { display: flex; align-items: flex-end; gap: 12px 14px; flex-wrap: wrap; padding: 16px; margin-bottom: 8px; }
.referencias-nueva > div { display: flex; flex-direction: column; gap: 6px; }
.referencias-nueva .referencias-nombre { flex: 1 1 320px; }
.referencias-nueva input[name=grupo] { width: 240px; }
.referencias-nueva .entrada-kg { width: 150px; text-align: right; }
.referencias-editar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.referencias-editar input[name=grupo] { width: 220px; }
.referencias-editar input[name=nombre] { flex: 1 1 280px; }
.referencias-editar .entrada-kg { width: 110px; text-align: right; }
.tabla-referencias tr.fila-escribe td { background: var(--dato-fondo); }
.tabla-referencias tr.inactiva td:first-child { color: var(--tinta-suave); text-decoration: line-through; }

@media (max-width: 760px) {
  .pasos.pasos-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .operarios-pie { align-items: stretch; }
  .operarios-pie input[name=operario], .operarios-pie .entrada-kg, .operarios-sobra .sobra-recibe { width: 100%; }
  .operarios-sobra { align-items: stretch; }
  .sale-para .pt-va-opciones { max-width: none; }
  .operarios-pie .boton { width: 100%; justify-content: center; }
  .tabla-operarios .entrada-kg { width: 120px; }
  .empaque-cab { align-items: stretch; }
  .empaque-cab input[type=date], .empaque-buscar input { width: 100%; }
  .empaque-buscar { margin-left: 0; }
  /* En el celular la hoja queda en tres columnas: referencia, paquetes y
     suprema; lo que lleva un paquete se ve al escribir. */
  .tabla-empaque th:nth-child(2), .tabla-empaque td:nth-child(2) { display: none; }
  .tabla-empaque .entrada-paquetes { width: 76px; }
  .empaque-total .boton { width: 100%; justify-content: center; }
  .referencias-nueva > div, .referencias-nueva input[name=grupo], .referencias-nueva .entrada-kg { width: 100%; }
  .referencias-nueva .boton { width: 100%; justify-content: center; }
  .referencias-editar input { width: 100% !important; flex: 1 1 100%; }
}

/* La fila de operario que acaba de cambiar se ilumina un momento: es la
   confirmación de lo de todos los días, en vez del cartel que tapa la
   pantalla (el cliente, 12 oct 2026: "debería ser para procesos más
   críticos"). */
@keyframes fila-recien { 0%, 35% { background-color: var(--bien-fondo); } }
@keyframes fila-recien-borde { 0%, 35% { background-color: var(--bien-fondo); box-shadow: inset 4px 0 0 var(--bien); } }
.tabla-operarios tr.recien td { animation: fila-recien 1.8s ease-out; }
.tabla-operarios tr.recien td:first-child { animation-name: fila-recien-borde; }

/* Quién recibe lo de venta y lo de reempacar (sql/47), y el cierre de la
   venta del día. */
.pt-va-rejilla .pt-va-nombre { grid-column: span 2; }
.venta-cierre { display: flex; align-items: flex-end; gap: 10px 16px; flex-wrap: wrap; }
.venta-cierre > div { display: flex; flex-direction: column; gap: 6px; }
.venta-cierre .entrada-kg { width: 150px; text-align: right; }
.venta-cierre .pt-queda strong { color: var(--dato); }
@media (max-width: 760px) {
  .venta-cierre { align-items: stretch; }
  .venta-cierre .entrada-kg, .venta-cierre .boton { width: 100%; justify-content: center; }
}

/* «Vendido hoy» (3 nov 2026): los títulos no se parten letra por letra; si
   no caben, la tabla pasa a tarjetas en el celular (tabla_movil.js). */
.tabla-vendido th { white-space: nowrap; }

/* ===========================================================================
   SEGUIMIENTO COMO LOS LOGS DE DUMA (3 nov 2026)
   A la izquierda las personas, a la derecha el historial: hora, quién y qué
   hizo, por día. El período y el tipo son enlaces (sin JavaScript).
   =========================================================================== */
.seg-periodo, .seg-tipos { display: inline-flex; gap: 2px; padding: 3px; border-radius: 12px; background: var(--neutro-fondo); flex-wrap: wrap; }
.seg-periodo a, .seg-tipos a {
  padding: 6px 12px; border-radius: 9px; font-size: 13px; font-weight: 600;
  color: var(--tinta-media); text-decoration: none; white-space: nowrap;
}
.seg-periodo a:hover, .seg-tipos a:hover { color: var(--tinta); }
.seg-periodo a.sel { background: var(--tinta); color: #fff; }
.seg-tipos a.sel { background: var(--superficie); color: var(--tinta); box-shadow: 0 1px 2px rgb(20 24 29 / .12); }

.seg-reg { display: grid; grid-template-columns: 340px minmax(0, 1fr); gap: 16px; align-items: start; }
.seg-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 14px 16px 10px; }
.seg-cab h2 { margin: 0; font-size: 15px; }
.seg-cab small { display: block; margin-top: 2px; font-size: 12.5px; color: var(--tinta-suave); }
.seg-activas { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--bien); }
.seg-activas i { width: 8px; height: 8px; border-radius: 50%; background: var(--bien); }

.seg-personas ul { list-style: none; margin: 0; padding: 0 8px 8px; }
.seg-persona {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 12px;
  color: var(--tinta); text-decoration: none;
}
.seg-persona:hover { background: var(--superficie-2); }
.seg-persona.sel { background: var(--tinta); color: #fff; }
.seg-persona.quieta { opacity: .6; }
.seg-persona.sel.quieta { opacity: 1; }
.seg-ini {
  position: relative; flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
  background: var(--acento-tenue); color: var(--acento-fuerte);
}
.seg-persona.sel .seg-ini { background: rgb(255 255 255 / .16); color: #fff; }
.seg-vivo { position: absolute; right: -1px; bottom: -1px; width: 11px; height: 11px; border-radius: 50%; background: var(--bien); box-shadow: 0 0 0 2px var(--superficie); }
.seg-pnombre { flex: 1; min-width: 0; }
.seg-pnombre strong, .seg-pnombre small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seg-pnombre strong { font-size: 13.5px; }
.seg-pnombre small { font-size: 12px; color: var(--tinta-suave); }
.seg-persona.sel small, .seg-persona.sel .seg-cifras { color: rgb(255 255 255 / .75); }
.seg-cifras { flex: 0 0 auto; text-align: right; font-size: 11.5px; line-height: 1.35; color: var(--tinta-suave); font-variant-numeric: tabular-nums; }

.seg-registro { padding-bottom: 12px; }
.seg-dia {
  position: sticky; top: var(--alto-barra, 64px); z-index: 2; padding: 8px 16px;
  font-size: 12.5px; font-weight: 700; color: var(--tinta-suave);
  background: rgb(255 255 255 / .96); border-top: 1px solid var(--linea);
}
.seg-linea { list-style: none; margin: 0 16px 0 96px; padding: 0; border-left: 1px solid var(--linea); }
.seg-ev { position: relative; display: flex; align-items: flex-start; padding: 7px 0 7px 22px; }
.seg-hora {
  position: absolute; left: -88px; top: 9px; width: 70px; text-align: right;
  font-size: 12px; color: var(--tinta-suave); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.seg-punto {
  position: absolute; left: -13px; top: 5px; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; box-shadow: 0 0 0 4px var(--superficie);
  background: var(--neutro-fondo); color: var(--neutro);
}
.t-entrada .seg-punto { background: var(--bien-fondo); color: var(--bien); }
.t-clic .seg-punto { background: var(--proceso-fondo); color: var(--proceso); }
.t-guardo .seg-punto { background: var(--dato-fondo); color: var(--dato); }
.seg-ev.fallo .seg-punto { background: var(--alerta-fondo); color: var(--alerta); }
.seg-texto { margin: 0; padding-top: 3px; font-size: 13.5px; line-height: 1.45; color: var(--tinta); min-width: 0; overflow-wrap: anywhere; }
.seg-texto b { font-weight: 600; }
.seg-fallo { display: block; margin-top: 2px; font-size: 12.5px; color: var(--alerta); }
.seg-cel { margin-left: 6px; padding: 1px 6px; border-radius: 6px; font-size: 11px; background: var(--neutro-fondo); color: var(--tinta-media); }
.seg-mas { text-align: center; padding: 14px 0 4px; }

@media (max-width: 980px) {
  .seg-reg { grid-template-columns: 1fr; }
  .seg-personas ul { max-height: 300px; overflow-y: auto; }
}
@media (max-width: 560px) {
  .seg-linea { margin-left: 84px; margin-right: 12px; }
  .seg-hora { left: -80px; width: 60px; font-size: 11.5px; }
  .titulo-fila .seg-periodo { margin-top: 6px; }
}

/* ============================================================================
   DASHBOARD OSCURO · 9 nov 2026
   El cliente: «moderno, limpio, organizado, futurista», con referencias de
   paneles oscuros. Solo esta página es oscura (body.pagina-oscura): continúa
   la barra lateral y separa "mirar" de "operar", que sigue en claro.
   El rojo de la marca es la luz de la escena: el resplandor del fondo, las
   barras y el anillo. Los estados (verde/ámbar) van apagados para no competir.
   Una sola animación de autor: al llegar, las cifras suben, las barras crecen
   en cascada y el anillo se dibuja. Nada se mueve después.
   ========================================================================== */
.sr-solo {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

body.pagina-oscura {
  --db-fondo:   #0c0f14;
  --db-carta:   rgba(255, 255, 255, .035);
  --db-carta-2: rgba(255, 255, 255, .055);
  --db-borde:   rgba(255, 255, 255, .08);
  --db-texto:   #f2f4f7;
  --db-medio:   rgba(242, 244, 247, .70);
  --db-suave:   rgba(242, 244, 247, .54);
  --db-rojo:    #ff3343;
  --db-verde:   #4ade80;
  --db-ambar:   #fbbf24;
  --db-curva:   cubic-bezier(.22, .9, .24, 1);
  background:
    radial-gradient(900px 520px at 85% -10%, rgba(216, 18, 33, .22), transparent 65%),
    radial-gradient(700px 480px at 10% 110%, rgba(216, 18, 33, .10), transparent 65%),
    var(--db-fondo);
  background-attachment: fixed;
  color: var(--db-texto);
  color-scheme: dark;
}
body.pagina-oscura footer { color: var(--db-suave); }
body.pagina-oscura .franja-local {
  background: rgba(28, 83, 179, .18); color: #a9c4f5; border-bottom-color: rgba(28, 83, 179, .35);
}

.db { display: flex; flex-direction: column; gap: 18px; container-type: inline-size; }

/* --- cabecera -------------------------------------------------------------- */
.db-cabeza { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.db-cabeza h1 { margin: 0; font-size: 26px; font-weight: 700; letter-spacing: -.03em; color: var(--db-texto); }
.db-rango { margin: 4px 0 0; color: var(--db-suave); font-size: 13px; font-variant-numeric: tabular-nums; }
.db-filtro { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.db-periodo {
  display: inline-flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 6px 0 14px; border-radius: 999px;
  background: var(--db-carta-2); border: 1px solid var(--db-borde); color: var(--db-medio);
}
.db-periodo select {
  height: 36px; border: 0; background: transparent; color: var(--db-texto);
  font: inherit; font-size: 13px; font-weight: 600; padding-right: 8px; cursor: pointer;
}
.db-periodo select:focus-visible { outline: none; }
.db-periodo:focus-within { border-color: rgba(255, 255, 255, .35); }
.db-periodo option { background: #1a1f27; color: var(--db-texto); }
.db-filtro input[type="date"] {
  height: 38px; border-radius: 10px; border: 1px solid var(--db-borde);
  background: var(--db-carta-2); color: var(--db-texto); padding: 0 10px; font: inherit;
}

/* --- tarjeta base ---------------------------------------------------------- */
.db-tarjeta {
  position: relative;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02));
  border: 1px solid var(--db-borde);
  border-radius: 18px;
  padding: 18px 20px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .05) inset, 0 12px 30px rgba(0, 0, 0, .28);
}
.db-tarjeta-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.db-tarjeta-cab h2, .db-alertas h2 {
  margin: 0; padding: 0; border: 0; text-transform: none; letter-spacing: -.01em;
  font-size: 14.5px; font-weight: 650; color: var(--db-texto);
}
.db-nota { display: block; color: var(--db-suave); font-size: 12.5px; line-height: 1.45; }
.db-var { display: block; font-size: 12.5px; font-weight: 600; }
.db-var.bueno { color: var(--db-verde); }
.db-var.malo  { color: #ff6b77; }

.db-chip {
  display: inline-flex; align-items: center; padding: 3px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: rgba(255, 255, 255, .07); color: var(--db-medio);
}
.db-chip.rojo  { background: rgba(255, 51, 67, .14); color: #ff8a93; }
.db-chip.ambar { background: rgba(251, 191, 36, .13); color: #fcd34d; }
.db-chip.verde { background: rgba(74, 222, 128, .12); color: #86efac; }

/* --- alertas --------------------------------------------------------------- */
.db-alertas {
  border-radius: 18px; padding: 14px 8px 8px;
  background: linear-gradient(180deg, rgba(255, 51, 67, .12), rgba(255, 51, 67, .04));
  border: 1px solid rgba(255, 51, 67, .28);
}
.db-alertas h2 { display: flex; align-items: center; gap: 8px; padding: 0 12px 8px; color: #ff9aa2; }
.db-alertas ul { list-style: none; margin: 0; padding: 0; }
.db-alertas a {
  display: flex; align-items: center; gap: 14px; padding: 10px 12px; border-radius: 12px;
  color: var(--db-texto); text-decoration: none; transition: background-color .15s ease;
}
.db-alertas a:hover { background: rgba(255, 255, 255, .05); }
.db-alertas a:focus-visible { outline: 2px solid rgba(255, 255, 255, .6); outline-offset: -2px; }
.db-alerta-texto { flex: 1 1 auto; min-width: 0; }
.db-alerta-texto strong { display: block; font-size: 13.5px; font-weight: 600; }
.db-alerta-texto small { display: block; color: var(--db-suave); font-size: 12.5px; }
.db-ir { color: var(--db-suave); flex: 0 0 auto; transition: transform .2s var(--db-curva); }
.db-alertas a:hover .db-ir { transform: translateX(3px); color: var(--db-texto); }

/* --- las cuatro cifras ----------------------------------------------------- */
.db-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.db-kpi { display: flex; flex-direction: column; gap: 6px; }
.db-kpi-cab { display: flex; align-items: center; gap: 10px; color: var(--db-medio); font-size: 12.5px; font-weight: 600; margin-bottom: 4px; }
.db-icono {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px; flex: 0 0 auto;
  background: rgba(255, 51, 67, .14); color: #ff8a93;
}
.db-cifra {
  display: block; font-size: clamp(22px, 2.5cqi, 30px); font-weight: 700; letter-spacing: -.03em; line-height: 1.1;
  color: var(--db-texto); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.db-cifra em { font-style: normal; font-size: 14px; font-weight: 600; color: var(--db-suave); margin-left: 3px; letter-spacing: 0; }
.db-anillo-fila { display: flex; align-items: center; gap: 14px; }
.db-anillo { width: 74px; height: 74px; flex: 0 0 auto; transform: rotate(-90deg); }
.db-anillo circle { fill: none; stroke-width: 8; }
.db-anillo-pista { stroke: rgba(255, 255, 255, .08); }
.db-anillo-valor {
  stroke: var(--db-rojo); stroke-linecap: round;
  stroke-dasharray: calc(var(--p) * 1) 100;
  filter: drop-shadow(0 0 6px rgba(255, 51, 67, .55));
}
.db-kpi-anillo.bien .db-anillo-valor { stroke: var(--db-verde); filter: drop-shadow(0 0 6px rgba(74, 222, 128, .45)); }

/* --- rejilla: barras por día + qué entra ----------------------------------- */
.db-rejilla { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 14px; }

.db-barras {
  display: flex; align-items: stretch; gap: 10px;
  height: 250px; padding-top: 8px;
  background-image: repeating-linear-gradient(to top, rgba(255, 255, 255, .05) 0 1px, transparent 1px 25%);
  background-size: 100% calc(100% - 26px); background-repeat: no-repeat;
}
.db-barra { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.db-barra-pista { flex: 1 1 auto; width: 100%; max-width: 64px; display: flex; align-items: flex-end; }
.db-barra-relleno {
  display: block; width: 100%; height: calc(var(--h) * 1%); min-height: 3px;
  border-radius: 10px 10px 4px 4px;
  background: linear-gradient(180deg, rgba(255, 51, 67, .85), rgba(179, 13, 26, .55));
  transform-origin: bottom;
}
.db-barra.mayor .db-barra-relleno {
  background: linear-gradient(180deg, #ffe1e4 0%, #ff3343 35%, #b30d1a 100%);
  box-shadow: 0 0 24px rgba(255, 51, 67, .55);
}
.db-barra-valor { font-size: 11px; color: var(--db-suave); white-space: nowrap; font-variant-numeric: tabular-nums; opacity: 0; transition: opacity .2s ease; }
.db-barra:hover .db-barra-valor, .db-barra.mayor .db-barra-valor { opacity: 1; color: var(--db-texto); }
.db-barra-dia { font-size: 11.5px; color: var(--db-suave); font-variant-numeric: tabular-nums; }
.db-sin-grafico { padding: 40px 0; text-align: center; }

.db-lista-barras { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.db-lista-barras li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 12px; }
.db-lb-nombre { font-size: 13px; font-weight: 600; color: var(--db-texto); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-lb-valor { font-size: 12.5px; color: var(--db-medio); font-variant-numeric: tabular-nums; white-space: nowrap; }
.db-lb-valor small { color: var(--db-suave); font-size: 12px; }
.db-lb-pista { grid-column: 1 / -1; height: 8px; border-radius: 999px; background: rgba(255, 255, 255, .06); overflow: hidden; }
.db-lb-pista span {
  display: block; height: 100%; width: calc(var(--w) * 1%); border-radius: inherit;
  background: linear-gradient(90deg, #b30d1a, #ff3343);
  transform-origin: left;
}

/* --- tablas dentro del dashboard ------------------------------------------- */
.db-tabla { background: transparent; border: 0; box-shadow: none; border-radius: 0; }
.db-tabla thead th { background: transparent; color: var(--db-suave); border-bottom: 1px solid var(--db-borde); padding: 8px 12px; }
.db-tabla tbody td { border-bottom: 1px solid rgba(255, 255, 255, .05); color: var(--db-medio); padding: 12px; }
.db-tabla tbody td strong { color: var(--db-texto); font-weight: 600; }
.db-tabla tbody tr:hover { background: rgba(255, 255, 255, .03); }
.db-tabla tfoot td { padding: 12px; color: var(--db-texto); border-top: 1px solid var(--db-borde); }
.db-enlace { color: #ff8a93; font-weight: 600; text-decoration: none; }
.db-enlace:hover { text-decoration: underline; }

/* --- ¿de dónde salen? ------------------------------------------------------ */
.db-de-donde { padding: 0; }
.db-de-donde > summary {
  display: flex; align-items: center; gap: 10px; padding: 16px 20px; cursor: pointer; list-style: none;
  color: var(--db-medio); font-weight: 600; font-size: 13.5px;
}
.db-de-donde > summary::-webkit-details-marker { display: none; }
.db-de-donde > summary:hover { color: var(--db-texto); }
.db-de-donde > summary .db-flecha { margin-left: auto; transition: transform .25s var(--db-curva); }
.db-de-donde[open] > summary .db-flecha { transform: rotate(180deg); }
.db-de-donde-cuerpo { padding: 0 20px 18px; }
.db-de-donde-cuerpo h3 { margin: 18px 0 4px; font-size: 13.5px; color: var(--db-texto); }
.db-de-donde-cuerpo .db-nota { margin-bottom: 10px; }

.db-vacio { text-align: center; padding: 48px 20px; }
.db-vacio p { color: var(--db-medio); margin: 0 0 16px; }

/* --- la llegada: una sola animación ---------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .db-kpi, .db-rejilla > *, .db-alertas {
    animation: db-sube .6s var(--db-curva) both;
    animation-delay: calc(var(--i, 0) * 70ms);
  }
  .db-rejilla > :nth-child(1) { --i: 4; }
  .db-rejilla > :nth-child(2) { --i: 5; }
  .db-barra-relleno { animation: db-crece .9s var(--db-curva) both; animation-delay: calc(300ms + var(--i, 0) * 60ms); }
  .db-lb-pista span { animation: db-estira .9s var(--db-curva) both; animation-delay: calc(400ms + var(--i, 0) * 70ms); }
  .db-anillo-valor { animation: db-anillo 1.1s var(--db-curva) both; animation-delay: .25s; }
  @keyframes db-sube   { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  @keyframes db-crece  { from { transform: scaleY(0); } to { transform: scaleY(1); } }
  @keyframes db-estira { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  @keyframes db-anillo { from { stroke-dasharray: 0 100; } }
}

/* --- pantallas medianas y celular ------------------------------------------ */
/* Se acomoda al ANCHO QUE LE QUEDA (barra lateral abierta u oculta), no al
   de la pantalla. */
@container (max-width: 1000px) {
  .db-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (max-width: 860px) {
  .db-rejilla { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .db-kpis { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .db-cabeza h1 { font-size: 22px; }
  .db-cifra { font-size: 26px; white-space: normal; }
  .db-tarjeta { padding: 16px; border-radius: 16px; }
  .db-barras { height: 200px; gap: 6px; }
  .db-barra-valor { display: none; }
}
@media (max-width: 860px) {
  body.pagina-oscura .barra { background: #12161c; border-bottom-color: rgba(255, 255, 255, .08); }
  body.pagina-oscura .barra .marca strong { color: #fff; }
  body.pagina-oscura .nav-inferior { background: #12161c; border-top-color: rgba(255, 255, 255, .08); }
  body.pagina-oscura .nav-inferior > a,
  body.pagina-oscura .nav-inferior > .nav-mas > summary { color: rgba(255, 255, 255, .62); }
  body.pagina-oscura .nav-inferior a.sel { background: rgba(255, 51, 67, .16); color: #ff8a93; }
}

@media (max-width: 640px) {
  .db-alertas a { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 10px; align-items: center; }
  .db-alertas a > .db-chip { grid-column: 1; justify-self: start; }
  .db-alertas a > .db-alerta-texto { grid-column: 1; }
  .db-alertas a > .db-ir { grid-column: 2; grid-row: 1 / 3; }
}

/* ============================================================================
   TEMA Y MENÚ FLOTANTE · 9 nov 2026 (boceto aprobado:
   bocetos-chicken/menu-profesional/boceto-chicken.html)

   Lo que se investigó y se aplicó:
   - Menú flotante de vidrio, separado del borde (Apple, materiales 2025).
   - Se oculta en un riel de íconos; en celular, barra flotante abajo (Vercel).
   - Calma: el menú queda tenue y solo brilla el lugar activo (Linear 2026).
   - El rojo de la marca en menos del 5 % de la pantalla: acción principal y
     lo urgente (Stripe).
   - Profundidad por capas de luz, no por cajas con borde grueso.

   TODA la app pasa a oscuro cambiando las variables de arriba: casi todo el
   CSS ya las usa. Lo que tenía colores fijos se corrige aquí mismo.
   ========================================================================== */
html:not([data-tema="claro"]) {
  color-scheme: dark;
  --canvas:       #0b0d11;
  --superficie:   #15181d;
  --superficie-2: #1b1f25;
  --linea:        rgba(255, 255, 255, .08);
  --linea-fuerte: rgba(255, 255, 255, .14);
  --tinta:        #f4f5f7;
  --tinta-media:  rgba(244, 245, 247, .72);
  --tinta-suave:  rgba(244, 245, 247, .52);
  --chrome:       #0b0d11;
  --chrome-texto: rgba(244, 245, 247, .72);
  --chrome-linea: rgba(255, 255, 255, .08);
  --acento:       #e11d2e;
  --acento-fuerte:#ff6b78;
  --acento-tenue: rgba(225, 29, 46, .15);
  --bien:    #34d399;  --bien-fondo:    rgba(52, 211, 153, .12);
  --alerta:  #ff7d7d;  --alerta-fondo:  rgba(255, 107, 107, .12);
  --proceso: #f5b84b;  --proceso-fondo: rgba(245, 184, 75, .12);
  --neutro:  rgba(244, 245, 247, .75); --neutro-fondo: rgba(255, 255, 255, .07);
  --dato:    #8ab4ff;  --dato-fondo:    rgba(138, 180, 255, .12); --dato-linea: rgba(138, 180, 255, .30);
  --sombra: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 10px 28px rgba(0, 0, 0, .28);
  --sombra-barra: none;
  --curva: cubic-bezier(.32, .72, 0, 1);
  --salida: cubic-bezier(.22, .9, .24, 1);
}
html:not([data-tema="claro"]) body {
  background:
    radial-gradient(560px 460px at 0% 0%, rgba(225, 29, 46, .22), transparent 70%),
    radial-gradient(700px 560px at 100% 100%, rgba(225, 29, 46, .07), transparent 70%),
    var(--canvas);
  background-attachment: fixed;
}
/* Lo que tenía blanco o tinta fijos. */
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], input[type=search], input[type=tel], select, textarea,
.si-no .opciones label { background: var(--superficie-2); }
html:not([data-tema="claro"]) tbody td { border-bottom-color: rgba(255, 255, 255, .05); }
.boton:hover, .asistente-flotante:hover,
.asistente-pregunta button[type=submit]:hover { background: #c8101f; }
html:not([data-tema="claro"]) :is(.voz-orden-flotante, .voz-orden-texto, .tablero, .aviso-cookies) { background: #262b33; color: #fff; }
html:not([data-tema="claro"]) :is(.seg-periodo a.sel, .seg-persona.sel) { background: rgba(255, 255, 255, .14); color: #fff; }
html:not([data-tema="claro"]) .franja-local { background: rgba(138, 180, 255, .10); color: #a9c4f5; border-bottom-color: rgba(138, 180, 255, .25); }
.boton { background: linear-gradient(180deg, #f0283a, #c8101f); box-shadow: 0 6px 18px rgba(225, 29, 46, .28), 0 1px 0 rgba(255, 255, 255, .18) inset; }
html:not([data-tema="claro"]) :is(.boton.secundario, .boton.fantasma) { background: rgba(255, 255, 255, .05); box-shadow: none; }
html:not([data-tema="claro"]) :is(.boton.secundario:hover, .boton.fantasma:hover) { background: rgba(255, 255, 255, .10); }

/* ============================ el menú flotante ============================= */
.menu { display: none; }

@media (min-width: 861px) {
  :root { --ancho-menu: 256px; --hueco-menu: 280px; }
  html[data-menu="oculto"] { --ancho-menu: 64px; --hueco-menu: 88px; }
  .barra { display: none; }
  body:has(> .menu) { padding-left: var(--hueco-menu); }
  html.menu-listo body:has(> .menu) { transition: padding-left .55s var(--curva); }

  .menu {
    position: fixed; top: 12px; bottom: 12px; left: 12px; z-index: 30;
    width: var(--ancho-menu);
    display: flex; flex-direction: column;
    background: rgba(24, 27, 33, .60);
    -webkit-backdrop-filter: blur(22px) saturate(150%); backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid rgba(255, 255, 255, .08); border-radius: 20px;
    box-shadow: 0 1px 0 rgba(255, 255, 255, .06) inset, 0 24px 60px rgba(0, 0, 0, .40);
    color: var(--tinta);
  }
  html.menu-listo .menu { transition: width .55s var(--curva); }

  .menu-cab { position: relative; display: flex; align-items: center; height: 64px; padding: 0 10px 0 14px; flex: 0 0 auto; }
  .menu-marca { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--tinta); text-decoration: none; }
  .menu-marca img { width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto; box-shadow: 0 0 0 1px rgba(255, 255, 255, .15); }
  .menu-marca strong { font-size: 14px; font-weight: 650; letter-spacing: -.01em; white-space: nowrap; }
  .menu-plegar {
    margin-left: auto; width: 30px; height: 30px; padding: 0; border: 0; border-radius: 8px; flex: 0 0 auto;
    display: grid; place-items: center; cursor: pointer; background: transparent; color: var(--tinta-suave);
    transition: background-color .15s, color .15s;
  }
  .menu-plegar:hover { background: rgba(255, 255, 255, .07); color: var(--tinta); }
  .menu-plegar:focus-visible, .menu-nav a:focus-visible, .menu-salir:focus-visible,
  .menu-novedades:focus-visible, .menu-marca:focus-visible { outline: 2px solid rgba(255, 255, 255, .7); outline-offset: 1px; }

  .menu-nav { position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 4px 10px 10px; scrollbar-width: none; }
  .menu-sec { margin: 18px 10px 6px; font-size: 11px; font-weight: 600; color: var(--tinta-suave); white-space: nowrap; }
  .menu-nav a {
    position: relative; z-index: 1;
    display: flex; align-items: center; gap: 11px; height: 36px; padding: 0 10px; border-radius: 10px;
    color: var(--tinta-media); text-decoration: none; font-size: 13.5px; font-weight: 500; white-space: nowrap;
    transition: color .2s;
  }
  .menu-nav a .ico { color: var(--tinta-suave); flex: 0 0 auto; transition: color .2s; }
  .menu-nav a:hover { color: var(--tinta); }
  .menu-nav a:hover .ico { color: var(--tinta-media); }
  .menu-nav a.sel { color: var(--tinta); font-weight: 600; }
  .menu-nav a.sel .ico { color: var(--acento); }
  .menu-pildora {
    position: absolute; top: 0; left: 10px; right: 10px; height: 36px; z-index: 0; border-radius: 10px; opacity: 0;
    background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, .06));
    box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset, 0 6px 16px rgba(0, 0, 0, .25);
  }
  html.menu-listo .menu-pildora { transition: transform .5s var(--curva); }

  .menu-pie { margin: 8px; flex: 0 0 auto; }
  .menu-novedades {
    position: relative; display: flex; align-items: center; gap: 11px; height: 36px; padding: 0 10px; margin-bottom: 6px;
    border-radius: 10px; color: var(--tinta-media); text-decoration: none; font-size: 13px; font-weight: 600; white-space: nowrap;
  }
  .menu-novedades:hover { background: rgba(255, 255, 255, .06); color: var(--tinta); }
  .menu-novedades .ico { flex: 0 0 auto; }
  .menu-novedades .novedades-punto { position: static; margin-left: auto; box-shadow: none; }
  .menu-quien { display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 14px; background: rgba(255, 255, 255, .04); }
  .menu-avatar { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; flex: 0 0 auto; background: linear-gradient(135deg, #f43f4f, #b40f1d); color: #fff; font-size: 12px; font-weight: 700; }
  .menu-quien-texto { min-width: 0; flex: 1 1 auto; line-height: 1.25; }
  .menu-quien-texto strong, .menu-quien-texto small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .menu-quien-texto strong { font-size: 13px; font-weight: 600; color: var(--tinta); }
  .menu-quien-texto small { font-size: 11.5px; color: var(--tinta-suave); }
  .menu-salir { width: 30px; height: 30px; display: grid; place-items: center; flex: 0 0 auto; border-radius: 8px; color: var(--tinta-suave); }
  .menu-salir:hover { background: rgba(255, 255, 255, .07); color: var(--tinta); }

  /* --- oculto: riel de íconos; los nombres se van con un desenfoque ------- */
  .menu-marca strong, .menu-nav a span, .menu-sec, .menu-novedades span, .menu-quien-texto, .menu-salir {
    transition: opacity .3s var(--salida), filter .3s var(--salida), transform .4s var(--salida);
    transition-delay: calc(var(--n, 0) * 18ms + 120ms);
  }
  html[data-menu="oculto"] :is(.menu-marca strong, .menu-nav a span, .menu-novedades span, .menu-quien-texto, .menu-salir) {
    opacity: 0; filter: blur(4px); transform: translateX(-6px); pointer-events: none; transition-delay: 0s;
  }
  html[data-menu="oculto"] .menu-sec { opacity: 0; transition-delay: 0s; }
  html[data-menu="oculto"] .menu-cab { padding-left: 16px; }
  html[data-menu="oculto"] .menu-plegar {
    position: absolute; top: 18px; right: -14px; width: 28px; height: 28px; border-radius: 50%;
    background: #20242b; border: 1px solid rgba(255, 255, 255, .12); color: var(--tinta);
  }
  html[data-menu="oculto"] .menu-plegar .ico { transform: rotate(180deg); }
  html[data-menu="oculto"] .menu-nav { overflow: visible; }
  html[data-menu="oculto"] .menu-nav a,
  html[data-menu="oculto"] .menu-novedades { padding-left: 12px; }
  html[data-menu="oculto"] .menu-quien { background: transparent; padding: 10px 7px; }
  html[data-menu="oculto"] .menu-novedades .novedades-punto { position: absolute; left: 26px; top: 2px; }
  html[data-menu="oculto"] .menu-nav a:hover::after,
  html[data-menu="oculto"] .menu-novedades:hover::after {
    content: attr(data-nombre); position: absolute; left: calc(100% + 14px); top: 50%; transform: translateY(-50%);
    padding: 6px 10px; border-radius: 8px; background: #1d2127; border: 1px solid rgba(255, 255, 255, .08);
    color: var(--tinta); font-size: 12.5px; font-weight: 600; white-space: nowrap; box-shadow: 0 10px 24px rgba(0, 0, 0, .35);
  }

  /* Lo que flota abajo a la izquierda arranca después del menú. */
  body:has(> .menu) .voz-orden-flotante,
  body:has(> .menu) .voz-orden-texto { left: calc(var(--hueco-menu) + 8px); }
  body:has(> .menu) .aviso-cookies { left: calc(var(--hueco-menu) + 8px); }
}

/* ======================= celular: barra flotante =========================== */
@media (max-width: 860px) {
  .barra {
    background: rgba(11, 13, 17, .72);
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--linea);
  }
  .nav-inferior {
    left: 12px; right: 12px; bottom: max(12px, env(safe-area-inset-bottom));
    padding: 6px; gap: 2px; border-radius: 22px;
    grid-auto-columns: minmax(0, 1fr);
    background: rgba(28, 31, 38, .74);
    -webkit-backdrop-filter: blur(22px) saturate(150%); backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid rgba(255, 255, 255, .09); border-top-color: rgba(255, 255, 255, .09);
    box-shadow: 0 18px 40px rgba(0, 0, 0, .5);
  }
  .nav-inferior > a, .nav-inferior > .nav-mas > summary {
    min-height: 54px; border-radius: 16px; color: var(--tinta-suave);
    font-size: 10.5px; line-height: 1.15; padding: 6px 2px;
  }
  .nav-inferior > a > span, .nav-inferior > .nav-mas > summary > span {
    white-space: normal; overflow: visible; text-overflow: clip; text-align: center;
  }
  .nav-inferior a.sel, .nav-inferior > .nav-mas > summary.sel { background: rgba(255, 255, 255, .09); color: var(--tinta); }
  .nav-inferior a.sel .ico, .nav-inferior > .nav-mas > summary.sel .ico { color: var(--acento); }
  .nav-mas-hoja {
    bottom: calc(100% + 12px); border-radius: 20px; padding: 8px;
    background: rgba(28, 31, 38, .92);
    -webkit-backdrop-filter: blur(22px); backdrop-filter: blur(22px);
    border: 1px solid rgba(255, 255, 255, .09); box-shadow: 0 18px 40px rgba(0, 0, 0, .5);
  }
  .nav-mas-hoja a { color: var(--tinta); }
  .nav-mas-hoja a.sel { background: rgba(255, 255, 255, .09); color: var(--tinta); }
  main { padding-bottom: calc(100px + env(safe-area-inset-bottom)); }
}

@media (prefers-reduced-motion: reduce) {
  html.menu-listo .menu, html.menu-listo body:has(> .menu), html.menu-listo .menu-pildora,
  .menu-marca strong, .menu-nav a span, .menu-sec, .menu-novedades span, .menu-quien-texto, .menu-salir { transition: none; }
}

/* El rojo, solo para la acción principal y lo urgente (Stripe: menos del
   5 % de la pantalla). Filtrar, la píldora elegida y la pestaña activa son
   navegación, no acción principal: van en claro. */
form.filtro .boton, .al-final > .boton {
  background: rgba(255, 255, 255, .07); box-shadow: none; color: var(--tinta);
  border: 1px solid var(--linea-fuerte);
}
form.filtro .boton:hover, .al-final > .boton:hover { background: rgba(255, 255, 255, .12); }
.pildora.activa { background: rgba(255, 255, 255, .14); color: var(--tinta); border-color: transparent; box-shadow: none; }
.tabs a.sel, .tabs button.sel { border-bottom-color: var(--tinta); color: var(--tinta); }

/* ===================== Producción: cabecera del boceto ===================== */
.pt-cabeza { align-items: center; margin-bottom: 18px; }
.pt-cabeza h1 { font-size: 26px; font-weight: 700; letter-spacing: -.035em; margin: 0; }
.pt-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.pt-acciones .boton .ico { margin-right: 2px; }

.pt-pestanas {
  display: flex; flex-wrap: wrap; gap: 2px; padding: 4px; margin: 0 0 26px;
  width: max-content; max-width: 100%;
  border-radius: 13px; background: rgba(255, 255, 255, .04); border: 1px solid var(--linea);
}
.pt-pestanas a {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 8px 14px; border-radius: 9px;
  color: var(--tinta-media); text-decoration: none; font-size: 13px; font-weight: 600; white-space: nowrap;
  transition: background-color .2s, color .2s;
}
.pt-pestanas a span { font-weight: 500; color: var(--tinta-suave); font-variant-numeric: tabular-nums; }
.pt-pestanas a:hover { color: var(--tinta); }
.pt-pestanas a.sel { background: rgba(255, 255, 255, .10); color: var(--tinta); box-shadow: 0 1px 0 rgba(255, 255, 255, .07) inset; }

.pt-cifras { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 0 0 28px; }
.pt-cifra { display: flex; flex-direction: column; gap: 6px; padding: 4px 24px 4px 0; color: inherit; text-decoration: none; border-radius: 0; }
.pt-cifra + .pt-cifra { padding-left: 24px; border-left: 1px solid var(--linea); }
a.pt-cifra:hover .pt-cifra-nombre { color: var(--tinta); }
.pt-cifra-nombre { font-size: 12.5px; font-weight: 500; color: var(--tinta-suave); }
.pt-cifra.sel .pt-cifra-nombre { color: var(--tinta); font-weight: 600; }
.pt-cifra-kg { font-size: 30px; font-weight: 650; letter-spacing: -.035em; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pt-cifra-kg em { font-style: normal; font-size: 14px; font-weight: 500; letter-spacing: 0; color: var(--tinta-suave); margin-left: 4px; }
.pt-cifra-pie { font-size: 12.5px; color: var(--tinta-suave); }
.pt-cifra-otras { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; }
.pt-cifra-otras a { color: var(--tinta-media); font-size: 13.5px; font-weight: 600; text-decoration: none; }
.pt-cifra-otras a:hover { color: var(--tinta); }
.pt-cifra-otras a.alerta { color: var(--proceso); }
.pt-cifra-otras a.sel { text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 640px) {
  .pt-cabeza h1 { font-size: 22px; }
  .pt-acciones .boton.secundario { display: none; }
  .pt-pestanas { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
  .pt-pestanas a { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; white-space: normal; padding: 8px 12px; }
  .pt-cifras { grid-template-columns: 1fr 1fr; row-gap: 16px; }
  .pt-cifra:nth-child(3) { grid-column: 1 / -1; padding: 14px 0 0; border-left: 0; border-top: 1px solid var(--linea); }
  .pt-cifra-kg { font-size: 24px; }
}
/* Las pestañas viven en un <nav>: la regla general `nav a` (icono arriba del
   rótulo) las partía en dos renglones. Aquí se dice explícito. */
.pt-pestanas a { flex-direction: row; min-width: 0; letter-spacing: 0; }
@media (max-width: 640px) { .pt-pestanas a { flex-direction: column; } }
/* Con el menú al lado la primera columna de la lista se angosta: el nombre
   del proveedor baja de renglón en vez de montarse sobre «Vence». */
.pt-acordeon.con-va .pt-prov-nombre strong { white-space: normal; }
.pt-prov-nombre { flex-wrap: wrap; row-gap: 2px; }
.pt-acordeon.con-va { --pt-cols: minmax(0, 1fr) 92px 172px 96px 96px 96px 96px 104px 96px; }
.pt-acordeon .pt-prov-nombre { display: grid; grid-template-columns: auto auto minmax(0, 1fr); column-gap: 10px; align-items: center; }
.pt-acordeon .pt-prov-nombre > strong { grid-column: 3; }
.pt-acordeon .pt-prov-nombre > .pt-prov-meta { grid-column: 3; }

/* ===================== Dashboard del boceto (9 nov) ======================== */
.db-cabeza h1 { font-size: 26px; }
.db-cifras { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 6px 0 8px; }
.db-cifra { display: flex; flex-direction: column; gap: 6px; padding: 4px 24px 4px 0; }
.db-cifra + .db-cifra { padding-left: 24px; border-left: 1px solid var(--linea); }
.db-cifra dt { font-size: 12.5px; font-weight: 500; color: var(--tinta-suave); }
.db-cifra dd { margin: 0; font-size: clamp(22px, 2.6cqi, 32px); font-weight: 650; letter-spacing: -.035em; line-height: 1.05; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--tinta); }
.db-cifra dd em { font-style: normal; font-size: 14px; font-weight: 500; letter-spacing: 0; color: var(--tinta-suave); margin-left: 4px; }

.db-tarjeta { background: rgba(255, 255, 255, .035); box-shadow: 0 1px 0 rgba(255, 255, 255, .04) inset; border-radius: 18px; }
.db-rejilla { grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); align-items: start; }

/* Barras: grises; solo el mejor día en rojo con luz. */
.db-barra-relleno { background: linear-gradient(180deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, .07)); border-radius: 12px 12px 6px 6px; }
.db-barra.mayor .db-barra-relleno { background: linear-gradient(180deg, #ff8792 0%, #e11d2e 45%, #8f0b16 100%); box-shadow: 0 0 34px rgba(225, 29, 46, .45); }
.db-barra-valor { opacity: 1; }
.db-barra:not(.mayor) .db-barra-valor { color: var(--tinta-suave); }

/* Anillo grande. */
.db-anillo-caja { display: flex; flex-direction: column; align-items: center; }
.db-anillo-caja .db-tarjeta-cab { align-self: stretch; }
.db-anillo-grande { position: relative; width: 168px; height: 168px; margin: 4px auto 14px; }
.db-anillo-grande svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.db-anillo-grande circle { fill: none; stroke-width: 12; }
.db-anillo-grande .db-anillo-pista { stroke: rgba(255, 255, 255, .06); }
.db-anillo-grande .db-anillo-valor { stroke: var(--db-verde, #34d399); stroke-linecap: round; stroke-dasharray: calc(var(--p) * 1) 100; filter: none; }
.db-anillo-caja.mal .db-anillo-valor { stroke: #e11d2e; }
.db-anillo-centro { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.db-anillo-centro strong { font-size: 34px; font-weight: 700; letter-spacing: -.04em; line-height: 1; }
.db-anillo-centro small { color: var(--tinta-suave); font-size: 12px; margin-top: 4px; }
.db-anillo-texto { margin: 0; text-align: center; font-size: 13px; color: var(--tinta-media); }
.db-anillo-texto .db-var { display: inline; }
@media (prefers-reduced-motion: no-preference) {
  .db-anillo-grande .db-anillo-valor { animation: db-anillo 1.4s cubic-bezier(.32, .72, 0, 1) .3s both; }
  .db-cifra { animation: db-sube .6s cubic-bezier(.22, .9, .24, 1) both; }
}
@container (max-width: 1000px) {
  .db-rejilla { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .db-cifras { grid-template-columns: 1fr 1fr; row-gap: 16px; }
  .db-cifra:nth-child(3) { grid-column: 1 / -1; padding: 14px 0 0; border-left: 0; border-top: 1px solid var(--linea); }
  .db-cifra dd { white-space: normal; }
}

.db-cifra dt, .db-cifra small, .db-cifra .db-nota, .db-cifra .db-var { letter-spacing: 0; font-stretch: normal; }
.db-cifras .db-cifra { display: flex; font-size: 14px; font-weight: 400; letter-spacing: 0; line-height: 1.45; white-space: normal; color: var(--tinta); }


/* Con el menú al lado, la lista de Producción puede quedarse sin ancho (en un
   portátil de 1280 px con el menú abierto no caben sus 9 columnas): entonces
   toma el mismo acomodo del celular, cada lote como bloque, en vez de montar
   textos. Se mide el ancho que le queda al contenido, no el de la pantalla. */
.pt-acordeon { container-type: inline-size; container-name: lista; }
@container lista (max-width: 1100px) {
  .pt-acordeon .pt-prov-nombre { display: flex; }
  .pt-enc { display: none; }
  .pt-rejilla { grid-template-columns: minmax(0, 1fr) auto; row-gap: 4px; padding: 12px 14px; }
  .pt-prov > summary { align-items: start; }
  .pt-prov > summary > span:empty { display: none; }
  .pt-prov-nombre { flex-wrap: wrap; row-gap: 2px; }
  .pt-prov-nombre .pt-prov-meta { flex: 1 1 100%; padding-left: 32px; }
  .pt-prov-vence { grid-column: 1 / -1; padding-left: 32px; }
  .pt-prov[open] > summary .pt-prov-vence { display: none; }
  .pt-prov-vence:empty { display: none; }
  .pt-prov-kg { grid-column: 2; grid-row: 1; }
  .pt-prod { padding-left: 0; grid-column: 1; }
  .pt-lote .pt-kilos { grid-column: 2; grid-row: 1; }
  .pt-lote .pt-dato { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; padding-left: 25px; }
  .pt-lote .pt-otro.pt-dato { justify-content: flex-start; text-align: left; }
  .pt-lote .pt-otro.pt-dato::before { min-width: 104px; }
  .pt-prov > summary .pt-otro { display: none; }
  .pt-lote .pt-dato::before { content: attr(data-rotulo); min-width: 56px; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--tinta-suave); }
  .pt-lote .pt-accion { grid-column: 1 / -1; margin-top: 6px; }
  .pt-lote .pt-accion .boton { width: 100%; justify-content: center; }
  .pt-lote .pt-accion:empty { display: none; }
  .pt-acordeon.con-va .pt-prov-nombre strong { white-space: normal; }
}

@media (max-width: 860px) {
  .asistente-flotante { bottom: calc(96px + env(safe-area-inset-bottom)); }
  .voz-orden-texto { bottom: calc(160px + env(safe-area-inset-bottom)); }
}

/* ============================================================================
   MODO CLARO Y ESCENA DE PRODUCCIÓN · 10 nov 2026
   El cliente: «pásalo a docker, pero debes ponerle también modo claro».
   El oscuro es el de siempre desde el boceto; el claro vuelve a las
   variables originales de arriba (blanco, gris claro, rojo de la marca) y
   aquí solo se ajusta lo que se había hecho para fondo oscuro.
   El botón vive en el menú (sol/luna) y en la barra del celular; lateral.js
   lo guarda en este navegador.
   ========================================================================== */

/* --- piezas que solo se muestran en un modo ------------------------------- */
html:not([data-tema="claro"]) .si-claro { display: none !important; }
html[data-tema="claro"] .si-oscuro { display: none !important; }
.menu-tema { width: 100%; border: 0; background: transparent; cursor: pointer; font: inherit; text-align: left; }
.menu-tema > .si-oscuro, .menu-tema > .si-claro { display: inline-flex; }
html[data-menu="oculto"] .menu-tema > .si-oscuro,
html[data-menu="oculto"] .menu-tema > .si-claro { opacity: 1; filter: none; transform: none; pointer-events: auto; }
html[data-tema="claro"][data-menu="oculto"] .menu-tema > .si-oscuro { display: none !important; }
.tema-barra { padding: 0 10px; }

/* --- variables de superficies flotantes por modo --------------------------- */
html:not([data-tema="claro"]) {
  --vidrio: rgba(22, 24, 30, .62); --vidrio-borde: rgba(255, 255, 255, .08);
  --capa: rgba(255, 255, 255, .04); --capa-2: rgba(255, 255, 255, .07); --resalte: rgba(255, 255, 255, .10);
  --sombra-flota: 0 1px 0 rgba(255, 255, 255, .05) inset, 0 18px 40px rgba(0, 0, 0, .35);
  --texto-vidrio: #f5f6f8;
}
html[data-tema="claro"] {
  --vidrio: rgba(255, 255, 255, .78); --vidrio-borde: rgba(17, 20, 24, .08);
  --capa: rgba(17, 20, 24, .03); --capa-2: rgba(17, 20, 24, .05); --resalte: rgba(17, 20, 24, .06);
  --sombra-flota: 0 1px 0 rgba(255, 255, 255, .9) inset, 0 16px 40px rgba(17, 20, 24, .10);
  --texto-vidrio: #14181d;
  --curva: cubic-bezier(.32, .72, 0, 1); --salida: cubic-bezier(.22, .9, .24, 1);
  color-scheme: light;
}

/* --- modo claro: lo que se había hecho para fondo oscuro ------------------- */
html[data-tema="claro"] body {
  background: radial-gradient(560px 460px at 0% 0%, rgba(225, 29, 46, .07), transparent 70%), var(--canvas);
  background-attachment: fixed;
}
html[data-tema="claro"] .menu { background: var(--vidrio); border-color: var(--vidrio-borde); box-shadow: var(--sombra-flota); }
html[data-tema="claro"] .menu-pildora { background: rgba(17, 20, 24, .06); box-shadow: none; }
html[data-tema="claro"] :is(.menu-plegar:hover, .menu-novedades:hover, .menu-salir:hover) { background: rgba(17, 20, 24, .06); }
html[data-tema="claro"] .menu-quien { background: rgba(17, 20, 24, .04); }
html[data-tema="claro"] .menu-marca img { box-shadow: 0 0 0 1px rgba(17, 20, 24, .12); }
html[data-tema="claro"][data-menu="oculto"] .menu-plegar { background: #fff; border-color: rgba(17, 20, 24, .12); }
html[data-tema="claro"][data-menu="oculto"] :is(.menu-nav a:hover, .menu-novedades:hover)::after {
  background: #fff; border-color: rgba(17, 20, 24, .10); box-shadow: 0 10px 24px rgba(17, 20, 24, .15);
}
html[data-tema="claro"] :is(form.filtro .boton, .al-final > .boton) { background: #fff; }
html[data-tema="claro"] .pildora.activa { background: var(--tinta); color: #fff; }
html[data-tema="claro"] .pt-pestanas { background: rgba(17, 20, 24, .04); }
html[data-tema="claro"] .pt-pestanas a.sel { background: #fff; box-shadow: 0 1px 3px rgba(17, 20, 24, .12); }
@media (max-width: 860px) {
  html[data-tema="claro"] .barra { background: rgba(255, 255, 255, .82); }
  html[data-tema="claro"] .nav-inferior { background: rgba(255, 255, 255, .82); border-color: rgba(17, 20, 24, .08); box-shadow: 0 18px 40px rgba(17, 20, 24, .16); }
  html[data-tema="claro"] :is(.nav-inferior a.sel, .nav-inferior > .nav-mas > summary.sel) { background: rgba(17, 20, 24, .06); }
  html[data-tema="claro"] .nav-mas-hoja { background: rgba(255, 255, 255, .97); border-color: rgba(17, 20, 24, .08); box-shadow: 0 18px 40px rgba(17, 20, 24, .16); }
  html[data-tema="claro"] .nav-mas-hoja a.sel { background: rgba(17, 20, 24, .06); }
}

/* Dashboard en claro: sus variables propias pasan a las claras. */
html[data-tema="claro"] body.pagina-oscura {
  --db-fondo: var(--canvas); --db-borde: rgba(17, 20, 24, .08);
  --db-texto: var(--tinta); --db-medio: var(--tinta-media); --db-suave: var(--tinta-suave);
  --db-verde: #0f7a4a; --db-ambar: #92560a;
  background: radial-gradient(560px 460px at 0% 0%, rgba(225, 29, 46, .07), transparent 70%), var(--canvas);
  color: var(--tinta); color-scheme: light;
}
html[data-tema="claro"] .db-tarjeta { background: #fff; box-shadow: 0 1px 2px rgba(17, 20, 24, .05), 0 10px 28px rgba(17, 20, 24, .06); }
html[data-tema="claro"] .db-periodo { background: #fff; }
html[data-tema="claro"] .db-periodo option { background: #fff; color: var(--tinta); }
html[data-tema="claro"] .db-alertas { background: linear-gradient(180deg, rgba(225, 29, 46, .07), rgba(225, 29, 46, .02)); }
html[data-tema="claro"] .db-alertas h2 { color: #b30d1a; }
html[data-tema="claro"] .db-alertas a:hover { background: rgba(17, 20, 24, .04); }
html[data-tema="claro"] .db-chip { background: rgba(17, 20, 24, .06); color: var(--tinta-media); }
html[data-tema="claro"] .db-chip.rojo { background: #fdecee; color: #b30d1a; }
html[data-tema="claro"] .db-chip.ambar { background: #fdf3e2; color: #92560a; }
html[data-tema="claro"] .db-chip.verde { background: #e8f5ee; color: #0f7a4a; }
html[data-tema="claro"] .db-var.malo { color: #b30d1a; }
html[data-tema="claro"] .db-icono { background: #fdecee; color: #c3111d; }
html[data-tema="claro"] .db-barra-relleno { background: linear-gradient(180deg, rgba(17, 20, 24, .16), rgba(17, 20, 24, .06)); }
html[data-tema="claro"] .db-barras { background-image: repeating-linear-gradient(to top, rgba(17, 20, 24, .06) 0 1px, transparent 1px 25%); }
html[data-tema="claro"] .db-anillo-grande .db-anillo-pista { stroke: rgba(17, 20, 24, .07); }
html[data-tema="claro"] .db-lb-pista { background: rgba(17, 20, 24, .07); }
html[data-tema="claro"] .db-tabla tbody td { border-bottom-color: rgba(17, 20, 24, .06); }
html[data-tema="claro"] .db-tabla tbody tr:hover { background: rgba(17, 20, 24, .025); }

/* ============================================================================
   PRODUCCIÓN · LA ESCENA (boceto 10 nov, referencias 6, 8 y 9)
   ========================================================================== */
.pd-barra { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.pd-titulo { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.pd-titulo h1 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -.035em; }
.pd-titulo span { color: var(--tinta-suave); font-size: 13px; }
.pd-acciones { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.pd-acciones .boton .ico { margin-right: 2px; }

.pd-rejilla { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 16px; }
.pd-panel { position: relative; border-radius: 20px; background: var(--vidrio); border: 1px solid var(--vidrio-borde);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); box-shadow: var(--sombra-flota); }
.pd-panel-cab { display: flex; align-items: center; gap: 10px; padding: 16px 18px 6px; }
.pd-panel-cab h2 { margin: 0; padding: 0; border: 0; font-size: 14px; font-weight: 650; letter-spacing: -.01em; text-transform: none; color: var(--tinta); }
.pd-der { margin-left: auto; color: var(--tinta-suave); font-size: 12px; }
.pd-ic { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; flex: 0 0 auto;
  background: var(--acento-tenue); color: var(--acento-fuerte); }
html[data-tema="claro"] .pd-ic { color: #c3111d; }

/* la escena: la planta de Chicken con las cifras encima (igual en los dos modos:
   es una foto) */
.pd-escena { position: relative; height: 420px; border-radius: 22px; overflow: hidden; isolation: isolate;
  border: 1px solid var(--vidrio-borde); box-shadow: 0 24px 60px rgba(0, 0, 0, .35); background: #111; }
.pd-escena img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; transform: scale(1.04); }
.pd-escena::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; background:
  linear-gradient(90deg, rgba(10, 11, 14, .92) 0%, rgba(10, 11, 14, .55) 38%, rgba(10, 11, 14, .15) 70%, rgba(10, 11, 14, .35) 100%),
  linear-gradient(0deg, rgba(10, 11, 14, .85) 0%, transparent 45%); }
.pd-escena-titulo { position: absolute; z-index: 2; left: 26px; top: 24px; max-width: 380px; color: #fff; }
.pd-escena-titulo small { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, .78);
  padding: 5px 10px; border-radius: 999px; background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .12); }
.pd-escena-titulo small i { width: 6px; height: 6px; border-radius: 50%; background: #ff1f2d; box-shadow: 0 0 10px #ff1f2d; }
.pd-escena-titulo strong { display: block; margin-top: 14px; font-size: 54px; font-weight: 700; letter-spacing: -.045em; line-height: 1; font-variant-numeric: tabular-nums; }
.pd-escena-titulo strong em { font-style: normal; font-size: 22px; font-weight: 600; letter-spacing: -.01em; color: rgba(255, 255, 255, .7); margin-left: 6px; }
.pd-escena-titulo p { margin: 8px 0 0; color: rgba(255, 255, 255, .72); font-size: 14px; }

.pd-pin { position: absolute; z-index: 3; left: var(--x); top: var(--y); text-decoration: none; color: #fff; }
.pd-p-mesa { --x: 49%; --y: 82%; }
.pd-p-canastas { --x: 88%; --y: 76%; }
.pd-p-bascula { --x: 66%; --y: 42%; }
.pd-pin-punto { position: absolute; left: -7px; top: -7px; width: 14px; height: 14px; border-radius: 50%; background: #ff1f2d;
  box-shadow: 0 0 0 4px rgba(255, 31, 45, .25), 0 0 18px #ff1f2d; }
.pd-pin-punto::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid #ff1f2d; animation: pd-late 2.2s var(--salida) infinite; }
@keyframes pd-late { from { transform: scale(.6); opacity: .9; } to { transform: scale(2.4); opacity: 0; } }
.pd-pin-linea { position: absolute; left: 0; bottom: 7px; width: 1px; height: 46px; background: linear-gradient(0deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0)); }
.pd-pin-tarjeta { position: absolute; left: -18px; bottom: 54px; min-width: 178px; padding: 10px 12px; border-radius: 14px;
  background: rgba(14, 15, 19, .74); border: 1px solid rgba(255, 255, 255, .12); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .45); white-space: nowrap; transition: transform .25s var(--salida), border-color .2s;
  animation: pd-aparece .7s var(--salida) both; animation-delay: var(--d, 0s); }
.pd-p-canastas .pd-pin-tarjeta { left: auto; right: -18px; }
.pd-pin:hover .pd-pin-tarjeta { transform: translateY(-3px); border-color: rgba(255, 31, 45, .55); }
@keyframes pd-aparece { from { opacity: 0; transform: translateY(8px) scale(.97); } }
.pd-pin-tarjeta small { display: block; font-size: 11.5px; color: rgba(255, 255, 255, .55); font-weight: 600; }
.pd-pin-tarjeta b { display: block; margin-top: 2px; font-size: 18px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.pd-pin-tarjeta b em { font-style: normal; font-size: 12px; font-weight: 500; color: rgba(255, 255, 255, .55); margin-left: 3px; }
.pd-pin-tarjeta > span { display: block; font-size: 12px; color: rgba(255, 255, 255, .72); }
.pd-pin-tarjeta > span::first-letter { text-transform: uppercase; }

/* el medidor */
.pd-medidor { display: flex; flex-direction: column; }
.pd-dial { position: relative; width: 250px; height: 150px; margin: 10px auto 0; }
.pd-dial svg { width: 100%; height: 100%; overflow: visible; }
.pd-marcas line { stroke: var(--linea-fuerte); stroke-width: 2; stroke-linecap: round; }
.pd-marcas line.on { stroke: #ff1f2d; filter: drop-shadow(0 0 4px rgba(255, 31, 45, .45)); }
html[data-tema="claro"] .pd-marcas line.on { stroke: var(--acento); filter: none; }
.pd-dial-centro { position: absolute; left: 0; right: 0; bottom: 4px; text-align: center; }
.pd-dial-centro strong { display: block; font-size: 38px; font-weight: 700; letter-spacing: -.04em; line-height: 1; color: var(--tinta); }
.pd-dial-centro small { color: var(--tinta-suave); font-size: 12px; }
.pd-dos { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 14px 16px 16px; }
.pd-mini { display: block; padding: 12px 14px; border-radius: 14px; background: var(--capa); border: 1px solid var(--vidrio-borde); color: var(--tinta); text-decoration: none; transition: border-color .2s, transform .2s var(--salida); }
.pd-mini:hover { transform: translateY(-2px); }
.pd-mini small { display: block; font-size: 12px; color: var(--tinta-suave); font-weight: 600; }
.pd-mini b { display: block; margin-top: 4px; font-size: 20px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.pd-mini b em { font-style: normal; font-size: 12px; font-weight: 500; color: var(--tinta-suave); margin-left: 3px; }
.pd-mini > span { display: block; margin-top: 2px; font-size: 11.5px; color: var(--tinta-suave); }
.pd-mini.rojo { background: linear-gradient(160deg, rgba(255, 31, 45, .20), rgba(255, 31, 45, .05)); border-color: rgba(255, 31, 45, .30); }
.pd-mini.sel { border-color: var(--acento); box-shadow: 0 0 0 1px var(--acento) inset; }
.pd-aviso { display: flex; align-items: flex-start; gap: 10px; margin: 0 16px 16px; padding: 10px 12px; border-radius: 12px;
  background: var(--proceso-fondo); border: 1px solid rgba(245, 184, 75, .25); font-size: 12.5px; color: var(--tinta-media); }
.pd-aviso .ico { color: var(--proceso); flex: 0 0 auto; margin-top: 1px; }
.pd-aviso a { color: var(--tinta); font-weight: 600; text-decoration: none; }
.pd-aviso a.alerta { color: var(--proceso); }
.pd-aviso a.sel { text-decoration: underline; text-underline-offset: 3px; }

/* abajo: a dónde va y qué vence */
.pd-abajo { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 16px; margin: 16px 0 26px; }
.pd-flujo { padding: 6px 18px 18px; display: flex; flex-direction: column; gap: 12px; }
.pd-etapa { display: block; text-decoration: none; color: inherit; }
.pd-etapa-cab { display: flex; justify-content: space-between; align-items: baseline; font-size: 13px; }
.pd-etapa-cab > span { color: var(--tinta-media); font-weight: 600; }
.pd-etapa:hover .pd-etapa-cab > span { color: var(--tinta); }
.pd-etapa-cab b { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--tinta); }
.pd-etapa-cab b em { font-style: normal; font-size: 11.5px; color: var(--tinta-suave); font-weight: 500; margin-left: 2px; }
.pd-segmentos { display: grid; grid-template-columns: repeat(32, 1fr); gap: 3px; height: 18px; margin-top: 6px; }
.pd-segmentos i { border-radius: 3px; background: var(--capa-2); }
.pd-segmentos i.on { background: linear-gradient(180deg, #ff5a65, #c3111d); box-shadow: 0 0 8px rgba(255, 31, 45, .3); }

.pd-vence { list-style: none; margin: 0; padding: 8px 18px 18px; display: flex; flex-direction: column; }
.pd-vence li { position: relative; display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; column-gap: 12px; padding: 8px 0 8px; }
.pd-vence li::before { content: ""; position: absolute; left: 7px; top: 22px; bottom: -8px; width: 2px; background: var(--linea); }
.pd-vence li:last-child::before { display: none; }
.pd-vence li > i { grid-row: 1 / 3; width: 16px; height: 16px; margin-top: 2px; border-radius: 50%; background: var(--superficie); border: 2px solid var(--linea-fuerte); position: relative; z-index: 1; }
.pd-vence li.urge > i { background: #ff1f2d; border-color: #ff1f2d; box-shadow: 0 0 12px rgba(255, 31, 45, .7); }
.pd-vence li.pronto > i { background: var(--proceso); border-color: var(--proceso); }
.pd-vence b { font-size: 13.5px; font-weight: 650; color: var(--tinta); font-variant-numeric: tabular-nums; }
.pd-vence li > span { grid-column: 3; grid-row: 1; text-align: right; font-size: 13px; font-weight: 600; color: var(--tinta-media); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pd-vence li.urge > span { color: var(--acento-fuerte); }
html[data-tema="claro"] .pd-vence li.urge > span { color: #c3111d; }
.pd-vence small { grid-column: 2 / 4; font-size: 12px; color: var(--tinta-suave); }
.pd-vacio { padding: 8px 18px 18px; margin: 0; color: var(--tinta-suave); }

/* la llegada: una sola animación */
@media (prefers-reduced-motion: no-preference) {
  .pd-escena img { animation: pd-respira 18s ease-in-out infinite alternate; }
  @keyframes pd-respira { to { transform: scale(1.09) translateY(-6px); } }
  .pd-marcas line.on { animation: pd-enciende .3s var(--salida) both; animation-delay: calc(250ms + var(--k, 0) * 26ms); }
  .pd-segmentos i.on { animation: pd-enciende .35s var(--salida) both; animation-delay: calc(var(--s, 0) * 16ms); }
  @keyframes pd-enciende { from { opacity: 0; } }
}
@media (prefers-reduced-motion: reduce) {
  .pd-pin-punto::after { animation: none; }
  .pd-pin-tarjeta { animation: none; }
}

/* --- tablet y portátil angosto: se mide el ancho que le queda ---------------- */
main { container-type: inline-size; container-name: pagina; }
@container pagina (max-width: 1100px) {
  .pd-rejilla { grid-template-columns: minmax(0, 1fr); }
  .pd-medidor { display: grid; grid-template-columns: 260px minmax(0, 1fr); align-items: center; }
  .pd-medidor .pd-panel-cab { grid-column: 1 / -1; }
  .pd-medidor .pd-aviso { grid-column: 1 / -1; }
  .pd-escena-titulo strong { font-size: 44px; }
}
@container pagina (max-width: 720px) {
  .pd-abajo { grid-template-columns: minmax(0, 1fr); }
}
@container pagina (max-width: 520px) {
  .pd-escena { height: 340px; }
  .pd-escena::after { background: linear-gradient(0deg, rgba(10, 11, 14, .95) 0%, rgba(10, 11, 14, .4) 55%, rgba(10, 11, 14, .55) 100%); }
  .pd-escena-titulo { left: 18px; top: auto; bottom: 18px; }
  .pd-escena-titulo strong { font-size: 38px; }
  .pd-pin-tarjeta { min-width: 0; padding: 8px 10px; }
  .pd-pin-tarjeta b { font-size: 15px; }
  .pd-pin-tarjeta > span { display: none; }
  .pd-medidor { display: flex; }
  .pd-acciones .boton.secundario { display: none; }
}

/* Las etiquetas se ubican según el ancho REAL de la escena (con el menú
   abierto la escena es más angosta que en el boceto). */
.pd-escena { container-type: inline-size; container-name: escena; }
@container escena (max-width: 960px) {
  .pd-p-mesa { --x: 26%; --y: 84%; }
  .pd-p-canastas { --x: 93%; --y: 80%; }
  .pd-p-bascula { --x: 60%; --y: 44%; }
}
@container escena (max-width: 520px) {
  .pd-p-bascula { display: none; }
  .pd-p-mesa { --x: 24%; --y: 52%; }
  .pd-p-canastas { --x: 94%; --y: 44%; }
  .pd-pin-tarjeta { min-width: 0; padding: 8px 10px; }
  .pd-pin-tarjeta b { font-size: 15px; }
  .pd-pin-tarjeta > span { display: none; }
}
.pd-aviso a { white-space: nowrap; }

/* ============================================================================
   PRODUCCIÓN · LA RUTA DE LA PECHUGA (10 nov 2026, boceto-ruta.html)
   Cuatro estaciones en el orden de la planta, el carril de presas y «Lo que
   toca ahora». Cada estación es un enlace entero a su lista (.rt-ir cubre la
   tarjeta) y su botón queda por encima, para que se pueda tocar aparte.
   ========================================================================== */
.rt-titulo { margin: 4px 0 12px; padding: 0; border: 0; font-size: 15px; font-weight: 650; letter-spacing: -.01em; text-transform: none; color: var(--tinta); }
.rt-ruta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 12px; }
.rt-estacion, .rt-otro { position: relative; background: var(--superficie); border: 1px solid var(--linea); transition: background-color .15s, border-color .15s; }
.rt-estacion { display: flex; flex-direction: column; padding: 16px 18px; }
.rt-estacion:first-child { border-radius: 16px 0 0 16px; }
.rt-estacion:last-child { border-radius: 0 16px 16px 0; }
.rt-estacion + .rt-estacion { border-left: 0; }
.rt-estacion:hover, .rt-otro:hover { background: var(--superficie-2); }
.rt-estacion.sel, .rt-otro.sel { background: linear-gradient(180deg, var(--acento-tenue), transparent 140%); border-color: rgba(225, 29, 46, .45); }
.rt-estacion:not(:last-child)::after {
  content: ""; position: absolute; right: -9px; top: 50%; z-index: 2; width: 16px; height: 16px;
  transform: translateY(-50%) rotate(45deg); background: var(--superficie);
  border-top: 1px solid var(--linea); border-right: 1px solid var(--linea);
}
.rt-estacion.sel:not(:last-child)::after { border-color: rgba(225, 29, 46, .45); }
.rt-ir { position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.rt-ir:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }
.rt-estacion .boton, .rt-otro .boton { position: relative; z-index: 3; }
.rt-estacion .boton { margin-top: auto; width: 100%; justify-content: center; }
.rt-paso { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: var(--tinta-suave); }
.rt-paso b { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: var(--neutro-fondo); color: var(--tinta-media); font-size: 11px; }
.rt-estacion.sel .rt-paso b { background: var(--acento); color: #fff; }
.rt-estacion h3, .rt-otro h3 { margin: 8px 0 2px; padding: 0; border: 0; font-size: 14px; font-weight: 650; text-transform: none; letter-spacing: 0; color: var(--tinta); }
.rt-kg { font-size: 26px; font-weight: 700; letter-spacing: -.03em; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--tinta); white-space: nowrap; }
.rt-kg em { font-style: normal; font-size: 13px; font-weight: 500; letter-spacing: 0; color: var(--tinta-suave); margin-left: 3px; }
.rt-estacion small { display: block; margin: 2px 0 12px; font-size: 12px; color: var(--tinta-suave); }

.rt-carril { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr); gap: 10px; margin-bottom: 10px; }
.rt-otro { display: flex; align-items: center; gap: 14px; padding: 12px 14px; border-radius: 14px; }
.rt-otro-tx { flex: 1 1 auto; min-width: 0; }
.rt-otro h3 { margin: 0; font-size: 13px; font-weight: 600; color: var(--tinta-media); }
.rt-otro .rt-kg { font-size: 18px; }
.rt-otras { margin: 0 0 22px; font-size: 13px; color: var(--tinta-suave); }
.rt-otras a { color: var(--tinta-media); font-weight: 600; text-decoration: none; white-space: nowrap; }
.rt-otras a.alerta { color: var(--proceso); }
.rt-otras a.sel { text-decoration: underline; text-underline-offset: 3px; }

.rt-tareas { list-style: none; margin: 0 0 28px; padding: 0; border-radius: 16px; background: var(--superficie); border: 1px solid var(--linea); overflow: hidden; }
.rt-tarea { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 12px 16px; }
.rt-tarea + .rt-tarea { border-top: 1px solid var(--linea); }
.rt-ic { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; background: var(--neutro-fondo); color: var(--tinta-media); }
.rt-tarea.urge .rt-ic { background: var(--acento-tenue); color: var(--acento-fuerte); }
.rt-tarea.pronto .rt-ic { background: var(--proceso-fondo); color: var(--proceso); }
html[data-tema="claro"] .rt-tarea.urge .rt-ic { color: #c3111d; }
.rt-tarea strong { display: block; font-size: 14px; font-weight: 600; color: var(--tinta); }
.rt-tarea small { display: block; font-size: 12.5px; color: var(--tinta-suave); }
.rt-chip { display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; vertical-align: 1px; white-space: nowrap; background: var(--neutro-fondo); color: var(--tinta-media); }
.rt-chip.urge { background: var(--acento-tenue); color: var(--acento-fuerte); }
.rt-chip.pronto { background: var(--proceso-fondo); color: var(--proceso); }
html[data-tema="claro"] .rt-chip.urge { color: #b30d1a; }
.rt-acc { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

@container pagina (max-width: 900px) {
  .rt-ruta { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
  .rt-estacion, .rt-estacion:first-child, .rt-estacion:last-child { border-radius: 16px; }
  .rt-estacion + .rt-estacion { border-left: 1px solid var(--linea); }
  .rt-estacion.sel { border-left-color: rgba(225, 29, 46, .45); }
  .rt-estacion::after { display: none; }
  .rt-carril { grid-template-columns: minmax(0, 1fr); }
}
@container pagina (max-width: 560px) {
  .rt-tarea { grid-template-columns: 34px minmax(0, 1fr); }
  .rt-acc { grid-column: 1 / -1; justify-content: flex-start; }
  .rt-kg { font-size: 22px; }
}

/* Botones blancos con letra oscura fija: en modo oscuro --tinta es clara y
   el texto quedaba blanco sobre blanco (aviso de cookies, 10 nov 2026). */
.aviso-cookies .boton { color: #14181d; }
