/* ==========================================================================
   DESIGN SYSTEM PQG — sistema visual único de la aplicación.

   Una sola hoja para toda PQG: **ningún módulo trae CSS propio** (encargo §2).
   Los componentes se nombran por lo que SON, no por dónde se usan, de modo que
   la misma tarjeta sirve en el Dashboard, en CxC y en Compras.

   Esta pasada es VISUAL. No cambia ninguna regla de negocio, ningún cálculo,
   ningún estado y ningún Permiso: sólo cómo se ve lo que la vista ya entrega.

   Compatibilidad: **todas las clases anteriores siguen existiendo**. La pasada
   redefine su aspecto, no su nombre, así que las 163 plantillas adoptan el
   sistema sin reescribirse una a una.

   Índice
     1. Tokens (color, tipografía, espacio, radio, sombra)
     2. Base y accesibilidad
     3. Layout: barra lateral, barra superior, área de trabajo
     4. Encabezado de pantalla
     5. Iconos
     6. Tarjeta de sección (panel) y rejillas
     7. Franja de indicadores (KPI) y tendencia
     8. Tarjetas de acción y accesos rápidos
     9. Botones
    10. Estados: badges, avisos, marcas
    11. Tablas
    12. Pestañas y barra de filtros
    13. Formularios
    14. Progreso, listas de comprobación y listas compactas
    15. Gráficas
    16. Calendario
    17. Panel de detalle, ficha y rejilla de Permisos
    18. Estado vacío y utilidades
    19. Responsive
   ========================================================================== */

/* ------------------------------------------------------------- 1. TOKENS */

/* La letra de la casa, guardada en el proyecto (D-806). Una sola fuente
   variable cubre los pesos 300–900; el navegador que no la cargue sigue con
   la del sistema. Licencia OFL en `static/fonts/OFL-source-sans-3.txt`. */
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("../fonts/source-sans-3-latin.6e4bd172ce22.woff2") format("woff2");
}

:root {
  /* Superficies y texto -------------------------------------------------- */
  /* 2026-10-06 — primera prioridad de la propuesta de diseño (D-801): el
     fondo deja el azul de ERP por un gris mineral con un punto de verde —el de
     Gamma— y los bordes lo acompañan. Los grises de apoyo se oscurecen: el
     texto de ayuda medía 3.85:1 sobre blanco, por debajo del 4.5:1 que hace
     falta para leerlo sin esfuerzo. `tests/unit/test_contraste_de_la_hoja.py`
     impide que vuelva a bajar.

     El fondo va un punto más gris que las tarjetas, para que las blancas se
     despeguen — Agustín, 22/sep/2026: *«está algo desabrido con tanto blanco;
     tal vez fondo tantito gris, tarjetas sí blancas con color»*. Esa medida se
     conserva; lo que cambia es el matiz. Hasta hoy el valor efectivo lo fijaba
     una segunda regla `:root` al final de la sección 20; ahora vive aquí, una
     sola vez. */
  /* 2026-10-06 — **Matraz** (D-806): la identidad que Agustín eligió entre
     tres. Papel cálido en vez de blanco frío, verde de Gamma como color de la
     casa, y ningún azul de ERP. Un punto más gris el fondo que las tarjetas,
     como pidió el 22/sep. */
  --c-bg:            #eceae0;
  --c-surface:       #fffdf7;
  --c-surface-alt:   #f6f4ec;
  --c-surface-sunk:  #ebe8dd;
  --c-border:        #e2ded2;
  --c-border-strong: #cfc9b9;
  --c-border-soft:   #ece9df;
  --c-text:          #14201b;
  --c-text-2:        #3e4b45;
  --c-text-3:        #596a62;

  /* Primario — el verde de Gamma, en dos tonos -------------------------- */
  /* 2026-10-06 (D-806) — Agustín: *«me gustó la dirección A»*, y sí al verde
     en los botones. El verde VIVO del matraz (`--c-gamma`) es el fondo del
     botón principal, con texto oscuro encima: blanco sobre él no se lee
     (2.4:1). El verde TINTA (`--c-accent`) es el de enlaces, iconos de acción
     y «hecho»: 5.4:1 sobre blanco. El azul deja de ser el color de actuar y
     queda sólo como franja informativa y serie de gráfica. */
  --c-accent:        #1a7340;
  --c-accent-dark:   #145c33;
  --c-accent-soft:   #e3f6ec;
  --c-accent-line:   #b9e4cb;
  --c-sobre-gamma:   #06281a;

  /* Paleta de SERIES — sólo para gráficas de varias series (`Progreso de
     comisiones`). NO son estados y no significan nada por sí mismos: sirven
     para distinguir una serie de otra, y **siempre** van acompañadas de una
     leyenda con el nombre. Ocho matices con contraste suficiente entre sí y
     sobre `--c-surface`; a partir del noveno se repiten, y quien identifica la
     barra es el globo, no el color. */
  --c-serie-0: #1c7a44;  --c-serie-1: #0e8f9c;  --c-serie-2: #96660c;
  --c-serie-3: #5b41ab;  --c-serie-4: #2d6a9f;  --c-serie-5: #b03028;
  --c-serie-6: #2b6a86;  --c-serie-7: #8a4a86;

  /* Turquesa — categoría secundaria, nunca un estado --------------------- */
  --c-teal:          #0e8f9c;
  --c-teal-soft:     #e2f4f6;
  --c-teal-line:     #b4dfe4;

  /* Navegación ----------------------------------------------------------- */
  /* D-806 — verde profundo de laboratorio, no azul marino. */
  --c-nav-bg:        #0d2b21;
  --c-nav-bg-2:      #143a2d;
  --c-nav-text:      #d2e6db;
  --c-nav-text-2:    #9cc0ae;
  --c-nav-active:    #1a4a38;
  /* 2026-09-21 — **el verde del matraz de Gamma, muestreado del logotipo**
     (`img/pqg-logo.png`: #2bb673 es su color dominante). Agustín, 21/sep/2026:
     *«que se vea como tu empresa, no como un ERP»*. Hasta hoy la marca de la
     sección activa era azul —el mismo azul de los enlaces y los botones— y el
     verde de su logotipo **no aparecía en ninguna pantalla**.

     El azul **no se retira**: sigue siendo el color de lo que se pulsa y de lo
     que navega. El verde entra donde dice **identidad y «hecho»**, que es el
     único sitio donde un color puede significar algo sin leerse. */
  --c-gamma:         #2bb673;
  --c-nav-mark:      #2bb673;
  --c-nav-line:      #1f5040;

  /* Estados — el significado del color es el MISMO en toda PQG ----------- */
  --s-info-bg:  #ecebe3;  --s-info-fg:  #44506380;  --s-info-bd:  #d8d5c9;
  --s-ok-bg:    #e3f6ec;  --s-ok-fg:    #1c7a44;    --s-ok-bd:    #b9e4cb;
  --s-aten-bg:  #fdf4e3;  --s-aten-fg:  #96660c;    --s-aten-bd:  #ecd5a4;
  --s-revi-bg:  #f1ecfb;  --s-revi-fg:  #5b41ab;    --s-revi-bd:  #d5c9f0;
  --s-bloq-bg:  #fdecea;  --s-bloq-fg:  #b03028;    --s-bloq-bd:  #f2c3bf;

  /* --- Las FRANJAS de color: la raya de una tarjeta, el canto de un panel ---
     2026-09-22, Agustín viendo el Dashboard en su monitor: *«ese dorado
     cámbialo por amarillo; a los amarillo, azul y verde dales tantita
     transparencia»*.

     **Son tokens aparte de los de estado, y tiene que ser así.** `--s-aten-fg`
     es el color del TEXTO de «atención» y de su icono: un amarillo claro ahí
     no se leería sobre blanco. Lo que cambia es la franja, que no lleva texto
     encima y sólo tiene que distinguirse; y la transparencia la ablanda un
     punto para que acompañe a la tarjeta en vez de gritar. */
  --c-franja-acento: rgba(45, 106, 159, .8);    /* azul informativo (D-806: ya no es «acción») */
  --c-franja-ok:     rgba(43, 182, 115, .78);   /* verde de Gamma  */
  --c-franja-aten:   rgba(242, 191, 15, .85);   /* amarillo, ya no dorado */
  --c-franja-bloq:   #b03028;                   /* vencido: sin ablandar */

  /* Tipografía ----------------------------------------------------------- */
  /* 2026-10-06 (D-801) — un punto más grande en lo que se lee a diario: el
     texto operativo pasa de 13 a 14 px y las ayudas de 12 a 13. Las tablas se
     quedan en 13 (`--fs-sm`): son compactas por su tarea. Los campos siguen en
     16 px en el teléfono, que es lo que impide el zoom de iOS al enfocar. */
  /* D-806 — Source Sans 3, guardada en `static/fonts` (sin descargas de
     terceros, como htmx). Tiene la x más baja que la letra del sistema, así
     que cada medida sube un punto para leerse igual de grande: el texto
     operativo a 15, las ayudas y tablas a 14. Agustín descartó la letra
     condensada para títulos y cifras («muy ancha y alta»): van en la misma
     Source Sans 3, en negrita. */
  --fs-xs:  12px;
  --fs-sm:  14px;
  --fs:     15px;
  --fs-md:  16px;
  --fs-lg:  17px;
  --fs-xl:  22px;
  --fs-2xl: 28px;
  --ff: "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --ff-num: "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Espacio, radio, sombra ----------------------------------------------- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;

  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  /* 2026-10-06 (D-801) — la sombra queda para lo que SE ELEVA: la ficha
     acoplada, el cajón, un menú, una tarjeta al pasar el ratón. Las tarjetas
     planas —panel, indicador, formulario, cabecera— van con su borde de 1 px
     y sin sombra: la pantalla deja de parecer una colección de cajas iguales. */
  --shadow-xs: 0 1px 2px rgba(16, 24, 40, .04);
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .04);
  --shadow:    0 1px 3px rgba(16, 24, 40, .06), 0 4px 10px -4px rgba(16, 24, 40, .06);
  --shadow-md: 0 2px 6px rgba(16, 24, 40, .07), 0 12px 24px -12px rgba(16, 24, 40, .12);

  --nav-w: 236px;
  --wa-max: 1500px;
  /* Alto de la barra superior: la cabecera fija de una tabla se detiene justo
     debajo, en vez de deslizarse por detrás. */
  --topbar-h: 72px;
}

/* Corrección del token de texto informativo (se escribe entero, sin alfa). */
:root { --s-info-fg: #43524a; }

/* --------------------------------------------- 2. BASE Y ACCESIBILIDAD */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--ff);
  font-size: var(--fs);
  color: var(--c-text);
  background: var(--c-bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--c-accent); text-underline-offset: 2px; }
a:hover { color: var(--c-accent-dark); }

h1, h2, h3, h4 { font-weight: 700; letter-spacing: -.015em; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-sm);
  background: var(--c-surface-sunk);
  padding: 1px 5px;
  border-radius: var(--radius-sm);
}

/* Un foco visible SIEMPRE, con el mismo anillo en toda la aplicación. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.skip-link { position: absolute; left: -9999px; }
.skip-link:focus {
  left: var(--sp-2); top: var(--sp-2); z-index: 60;
  background: #fff; padding: 10px 14px; border: 1px solid var(--c-border);
  border-radius: var(--radius); box-shadow: var(--shadow-md);
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ------------------------------------------------------------ 3. LAYOUT */

/* --- Anclas internas y la barra superior fija -----------------------------
   La `.topbar` es `sticky` en lo alto del documento, así que al pulsar un
   ancla del menú de secciones de una ficha 360° el navegador dejaba el título
   **debajo** de ella, cortado. `scroll-padding-top` en el contenedor que
   scrollea —que es el documento— lo resuelve **de una vez para toda PQG**: no
   hace falta una regla por plantilla ni un `scroll-margin-top` repetido en
   cada `id`, y cualquier ancla futura nace ya corregida.

   El valor es la altura de la barra más un respiro, para que el título quede
   visible **completo** y no pegado al borde. */
html { scroll-padding-top: calc(var(--topbar-h) + var(--sp-4)); }

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

/* --- LA BARRA SE PUEDE ENCOGER (2026-09-21) -------------------------------
   Agustín, 21/sep/2026: la aplicación se usa mucho en escritorio, y ahí la
   barra son 236 px fijos delante de tablas de doce columnas. Encogerla a
   iconos devuelve ese ancho al contenido sin perder un solo destino: los
   nombres siguen ahí, en el `title` y para el lector de pantalla.

   **Es CSS y un checkbox, sin JavaScript**: el mismo mecanismo que el menú
   móvil ya usaba. El guion sólo recuerda la preferencia de cada quien.

   Sólo aplica en pantallas anchas: en un teléfono la barra ya colapsa a
   «Menú», y encogerla a iconos ahí sería resolver dos veces el mismo problema
   con dos respuestas distintas. */
/* Texto sólo para lector de pantalla. Existía como `.dots__sr` para un caso
   concreto; aquí se nombra de forma general porque ya lo usan tres sitios. */
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.nav-estrecha { position: absolute; opacity: 0; pointer-events: none; }
.nav__encoger {
  display: none; cursor: pointer; border: 0; background: none;
  color: var(--c-nav-text-2); padding: 4px; border-radius: var(--radius-sm);
  align-self: flex-start;
}
.nav__encoger:hover { color: #fff; background: var(--c-nav-active); }
.nav__encoger:focus-visible { outline: 2px solid var(--c-nav-mark); outline-offset: 2px; }

@media (min-width: 981px) {
  .nav__encoger { display: inline-flex; }
  /* Encogida: sólo iconos. `--nav-w` se redefine en el propio `.app`, así que
     el área de trabajo gana el ancho sin una sola regla más. */
  .nav-estrecha:checked ~ .nav { --nav-w: 62px; width: 62px; flex-basis: 62px; padding-inline: 8px; }
  .nav-estrecha:checked ~ .nav .nav__brand-logo,
  .nav-estrecha:checked ~ .nav .nav__grupo,
  .nav-estrecha:checked ~ .nav .nav__group,
  .nav-estrecha:checked ~ .nav .nav__pie-texto,
  .nav-estrecha:checked ~ .nav .nav__boton span,
  .nav-estrecha:checked ~ .nav summary.nav__boton::after { display: none; }
  .nav-estrecha:checked ~ .nav .nav__boton { justify-content: center; padding-inline: 0; }
  .nav-estrecha:checked ~ .nav .nav__boton .ic { margin: 0; }
}


/* --- Barra lateral oscura ---------------------------------------------- */

/* La barra ocupa **la pantalla completa, siempre**, y sus tres piezas —marca,
   navegación y pie— tienen altura independiente (§25, D-572).

   Antes era una sola columna con `align-self: flex-start` y `max-height`, así
   que su altura era **la de su contenido**: con dos o tres destinos —el caso
   normal, no la excepción: casi nadie tiene las quince secciones— la barra
   oscura terminaba a media pantalla, el pie quedaba flotando bajo el último
   enlace y debajo asomaba el fondo claro del documento. Con la lista completa
   pasaba lo contrario: el `scroll` se comía la barra entera, marca y pie
   incluidos.

   Nada aquí está calculado para un número concreto de elementos. */
.nav {
  width: var(--nav-w);
  flex: 0 0 var(--nav-w);
  background: var(--c-nav-bg);
  color: var(--c-nav-text);
  padding: 14px 12px 20px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  /* D-880 — por encima de la barra superior (20): la lista emergente vive
     dentro de la barra y sólo sube tan alto como ella. Debajo de los menús y
     diálogos (60 y más). */
  z-index: 30;
  height: 100vh;
  /* `dvh` donde exista: en un móvil la barra del navegador aparece y
     desaparece, y `100vh` deja el pie fuera de la pantalla mientras está. */
  height: 100dvh;
  overflow: hidden;
}

/* La lista de destinos: **ocupa lo que necesita y ni un píxel más**, y es la
   ÚNICA pieza que scrollea, sólo cuando de verdad no cabe. `min-height: 0` es
   lo que permite que se encoja dentro del flex; sin él el `overflow` no llega
   a activarse nunca y el pie se sale por abajo. */
.nav__scroll {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
}

.nav__brand {
  display: flex; align-items: center; justify-content: center;
  /* No cede altura cuando la lista es larga: es lo primero que se ve. */
  flex: 0 0 auto;
  min-height: var(--topbar-h);
  margin: -14px -12px 8px;
  padding: 14px 18px 13px;
  border-bottom: 1px solid var(--c-border);
  background: var(--c-surface);
}
.nav__brand-logo {
  display: block;
  width: 100%; max-width: 114px; height: auto;
}

.nav__group {
  padding: 14px 10px 5px;
  font-size: 10px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; color: var(--c-nav-text-2);
}

/* D-880 — **áreas de trabajo con su lista emergente.** Agustín, 16/oct/2026:
   *«quiero cero scroll»* y *«no está muy legible»*. Cada área es una fila
   grande (letra de 15.5 px, icono de 20); su lista sale **encima de la
   pantalla**, pegada a la barra, así que la barra mide siempre lo mismo. */
.nav .nav__boton {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 44px; padding: 10px 12px; margin-bottom: 2px;
  border-radius: var(--radius-sm);
  font-size: 15.5px; font-weight: 550; line-height: 1.2;
  color: var(--c-nav-text); text-decoration: none;
  list-style: none; cursor: pointer; user-select: none;
  transition: background .12s ease, color .12s ease;
}
.nav .nav__boton .ic { width: 20px; height: 20px; flex: 0 0 20px; opacity: .85; }
.nav summary.nav__boton::-webkit-details-marker { display: none; }
.nav summary.nav__boton::after {
  content: ""; margin-left: auto; width: 7px; height: 7px; flex: 0 0 7px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); opacity: .6;
}
.nav .nav__boton:hover { background: var(--c-nav-bg-2); color: #fff; }
.nav .nav__boton:hover .ic { opacity: 1; }
.nav .nav__boton:focus-visible { outline: 2px solid var(--c-nav-mark); outline-offset: -2px; }
/* El área de la pantalla actual se marca igual que un enlace actual. */
.nav .nav__boton--actual,
.nav .nav__area[open] > .nav__boton {
  background: var(--c-nav-active); color: #fff;
  box-shadow: inset 3px 0 0 var(--c-nav-mark);
}
.nav .nav__boton--actual .ic,
.nav .nav__area[open] > .nav__boton .ic { color: var(--c-nav-mark); opacity: 1; }

.nav__fly { display: none; }
.nav__area[open] > .nav__fly {
  display: block;
  position: fixed; z-index: 55;
  top: 0; bottom: 0; left: var(--nav-w);
  width: 300px;
  padding: 22px 14px;
  background: var(--c-surface);
  border-right: 1px solid var(--c-border-strong);
  box-shadow: 10px 0 30px rgb(20 32 27 / .14);
  overflow-y: auto; overscroll-behavior: contain;
  animation: fly-entra .14s ease-out;
}
@keyframes fly-entra { from { opacity: 0; transform: translateX(-8px); } }
.nav__fly-titulo {
  padding: 0 12px 14px; margin-bottom: 6px;
  border-bottom: 1px solid var(--c-border);
  font-size: 20px; font-weight: 650; color: var(--c-text);
}
.nav .nav__fly a {
  min-height: 46px; padding: 11px 12px; gap: 12px;
  font-size: 16px; color: var(--c-text);
}
.nav .nav__fly a .ic { width: 20px; height: 20px; flex-basis: 20px; color: var(--c-accent); opacity: 1; }
.nav .nav__fly a:hover { background: var(--c-surface-alt); color: var(--c-text); }
.nav .nav__fly a[aria-current="page"] {
  background: var(--c-accent-soft); color: var(--c-accent-dark);
  box-shadow: inset 3px 0 0 var(--c-accent);
}
.nav .nav__fly a[aria-current="page"] .ic { color: var(--c-accent); }

.nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; margin-bottom: 1px;
  color: var(--c-nav-text); text-decoration: none;
  font-size: var(--fs); min-height: 34px;
  border-radius: var(--radius-sm);
  transition: background .12s ease, color .12s ease;
}
.nav a .ic { width: 16px; height: 16px; flex: 0 0 16px; opacity: .8; }
.nav a:hover { background: var(--c-nav-bg-2); color: #fff; }
.nav a:hover .ic { opacity: 1; }
.nav a[aria-current="page"] {
  background: var(--c-nav-active); color: #fff; font-weight: 550;
  box-shadow: inset 2px 0 0 var(--c-nav-mark);
}
.nav a[aria-current="page"] .ic { color: var(--c-nav-mark); opacity: 1; }

/* Pie de la barra: quién soy y cómo salgo. **Siempre abajo, con dos destinos
   igual que con quince** — `margin-top: auto` empuja, y como la barra mide toda
   la pantalla, ese empuje ahora tiene contra qué apoyarse. `flex-shrink: 0`
   para que no sea él quien ceda cuando la lista es larga. */
.nav__foot {
  margin-top: auto; flex: 0 0 auto; padding: 12px 10px 0;
  border-top: 1px solid var(--c-nav-line);
  font-size: var(--fs-sm); color: var(--c-nav-text);
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 10px;
}
.nav__avatar {
  width: 30px; height: 30px; flex: 0 0 30px;
  border-radius: var(--radius-pill);
  background: var(--c-nav-active); color: #fff;
  display: grid; place-items: center;
  font-size: var(--fs-sm); font-weight: 650;
}
/* Nombre y correo se recortan con puntos suspensivos en vez de partirse: el
   pie mide **lo mismo** con cualquier nombre y cualquier correo, y eso es lo
   que lo mantiene estable (§25). */
/* `flex-basis: 0` y no `auto`: con la base en el contenido, el nombre
   completo empujaba el botón de salir al renglón siguiente antes de
   encogerse. Así la columna toma lo que sobra y se recorta ella. */
.nav__who, .nav__who b {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav__who { flex: 1 1 0; }
.nav__who b { display: block; color: #fff; font-weight: 550; }
/* `Mi contraseña`, en su propio renglón y a todo el ancho de la barra. */
.nav__yo {
  flex: 1 0 100%; margin-top: 8px;
  color: var(--c-nav-text-2); font-size: var(--fs-sm);
}
.nav__yo:hover { color: #fff; }
.nav__foot form { margin: 0; flex: 0 0 auto; }
.nav__foot button {
  background: none; border: 0; color: var(--c-nav-text-2);
  padding: 6px; cursor: pointer; min-height: 30px;
  border-radius: var(--radius-sm); display: grid; place-items: center;
}
.nav__foot button:hover { color: #fff; background: var(--c-nav-bg-2); }
.nav__foot button .ic { width: 16px; height: 16px; }

/* --- Área principal ----------------------------------------------------- */

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

.topbar {
  background: var(--c-surface);
  border-bottom: 1px solid var(--c-border);
  padding: 11px 26px;
  font-size: var(--fs-sm); color: var(--c-text-2);
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  position: sticky; top: 0; z-index: 20;
  /* 2026-10-20 — la barra mide `--topbar-h` de verdad. El token decía 43 px y
     la barra medía 67 (el botón `Atrás` mide 44): la cabecera fija de una
     tabla, la ficha acoplada y la barra de selección se detenían 24 px por
     debajo de donde empieza la barra, es decir, debajo de ella. Y la franja
     blanca de la marca, en la barra lateral, terminaba 5 px más abajo que esta
     barra: un escalón en la línea que cruza toda la pantalla. */
  min-height: var(--topbar-h);
}
.topbar a { color: var(--c-text-2); text-decoration: none; }

/* 2026-09-25 — **la barra de arriba, en dos bloques.** `Atrás` y la miga a la
   izquierda; buscar y la campana juntos a la derecha. El hueco lo abre este
   `margin-left:auto` y **sólo éste**: antes lo ponían el buscador y la campana
   por separado, y eso dejaba el buscador flotando a media barra.

   `nowrap` + la miga recortable es lo que hace que en un teléfono la barra
   siga siendo UNA franja: el título largo se corta con puntos suspensivos en
   vez de empujar la campana a un segundo renglón. */
.topbar__fin { margin-left: auto; display: flex; align-items: center; gap: 8px; flex: none; }
.crumb {
  min-width: 0; flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* `Atrás` — D-715. Es un control, no un enlace de texto: caja propia, borde y
   un blanco de 44 px de alto para que se pueda picar con el pulgar. */
.atras {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  min-height: 44px; padding: 0 12px; margin-right: var(--sp-2);
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); font-size: var(--fs-sm); font-weight: 550;
  transition: border-color .12s ease, color .12s ease;
}
.atras .ic { transform: rotate(180deg); }
.atras:hover { border-color: var(--c-accent-line); color: var(--c-accent); text-decoration: none; }

/* El calendario de cupo — D-716. Botones grandes, cómodos para el pulgar: la
   fecha se pica, no se teclea. */
.cupo {
  display: grid; gap: 6px; margin: var(--sp-2) 0;
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
}
.cupo__dia {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 62px; padding: 8px 10px;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-text);
  font: inherit; text-align: left; cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.cupo__dia:hover:not(:disabled) {
  border-color: var(--c-accent-line); box-shadow: var(--shadow); transform: translateY(-1px);
}
.cupo__dia--on { border-color: var(--c-accent); box-shadow: var(--shadow); }
.cupo__dia--no { background: var(--c-surface-sunk); color: var(--c-text-2); cursor: not-allowed; }
.cupo__dow { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em; color: var(--c-text-2); }
.cupo__num { font-size: var(--fs-lg); font-weight: 650; line-height: 1; }
.cupo__kg { font-size: var(--fs-xs); font-weight: 550; color: var(--s-ok-fg); }
.cupo__kg--no { color: var(--c-text-2); font-weight: 500; display: flex; align-items: center; gap: 3px; }
.cupo__kg--no .ic { width: 12px; height: 12px; }

/* Escribir para encontrar, en los desplegables largos — D-740, sobre D-730.
   Era una caja de texto ENCIMA del desplegable: dos cajas, y la lista de
   resultados escondida dentro de un `select` cerrado. Ahora es **una** caja con
   su lista debajo, y el `select` original se queda en el formulario —es el que
   se envía— apartado de la vista en cuanto `filtrar.js` marca el envoltorio.
   Sin JavaScript no hay marca, así que el desplegable se ve como siempre. */
.combo { position: relative; }
.combo--armado > select {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); border: 0;
}
.combo__campo {
  display: block; width: 100%;
  padding: 10px 12px; min-height: 44px;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-text);
  /* 16 px: por debajo de eso, iOS hace zoom al enfocar. */
  font: inherit; font-size: 16px;
}
.combo__campo:focus { border-color: var(--c-accent-line); outline: none; }
.combo__lista {
  position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 2px);
  margin: 0; padding: 4px; list-style: none;
  max-height: 46vh; overflow-y: auto;
  background: var(--c-surface); color: var(--c-text);
  border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: 0 10px 26px rgb(0 0 0 / .18);
}
.combo__lista[hidden] { display: none; }
.combo__op {
  padding: 11px 12px; min-height: 44px; border-radius: var(--radius);
  font-size: 16px; line-height: 1.3; cursor: pointer;
}
.combo__op--on, .combo__op:hover { background: var(--c-accent-soft); }
.combo__nada { padding: 11px 12px; color: var(--c-text-3); font-size: 15px; }

/* El margen que se está ofreciendo — D-741. Rojo por debajo del 12 %, ámbar
   hasta el 18 % y verde desde el 18 %, que es el objetivo de margen bruto que
   el negocio confirmó el 2026-08-19. **No bloquea nada**: informa. */
.margen { margin-top: 6px; display: flex; flex-direction: column; gap: 1px; }
.margen__cifra { font-size: var(--fs-lg); font-weight: 700; line-height: 1.1; }
.margen__pie { font-size: 12px; color: var(--c-text-3); }
.margen--bajo  .margen__cifra { color: var(--s-bloq-fg); }
.margen--medio .margen__cifra { color: var(--s-aten-fg); }
.margen--bueno .margen__cifra { color: var(--s-ok-fg); }
@media (max-width: 720px) {
  /* En un teléfono `Atrás` es sólo la flecha, y la barra se aprieta: caben la
     flecha, dónde estoy, buscar y la campana en UNA franja. */
  :root { --topbar-h: 60px; }
  .topbar { padding: 8px 12px; gap: 6px; }
  .atras { padding: 0 10px; margin-right: 4px; }
  .atras span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .topbar__fin { gap: 4px; }
  .campana { width: 34px; height: 34px; }
}
.topbar a:hover { color: var(--c-accent); text-decoration: underline; }
.topbar b { color: var(--c-text); font-weight: 600; }

.workarea { padding: 22px 26px 72px; max-width: var(--wa-max); width: 100%; min-width: 0; }

/* ------------------------------------------ 4. ENCABEZADO DE PANTALLA */

/* Título + descripción breve + acciones principales. Los indicadores van
   debajo, en `.stats`, sólo cuando ayudan a operar la pantalla (encargo §5). */
.screen__head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--sp-5); flex-wrap: wrap; margin-bottom: var(--sp-4);
}
.screen__title {
  font-size: var(--fs-2xl); margin: 0 0 3px; line-height: 1.2;
  letter-spacing: -.02em;
}
.screen__eyebrow {
  display: block; font-size: var(--fs-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--c-accent); margin-bottom: 5px;
}
.screen__sub { margin: 0 0 var(--sp-3); color: var(--c-text-2); max-width: 86ch; }

/* D-627 — lo que falta para preparar, un renglón por requisito. Antes era un
   párrafo con los tres pegados y no se leía. */
.faltantes { margin: var(--sp-1) 0 0; padding-left: var(--sp-4); }
.faltantes li { margin-bottom: var(--sp-2); }

/* D-621 — la navegación por mes del panel. Una fila, con la flecha atrás, el
   mes que se está mirando y la flecha adelante cuando ese mes ya pasó. */
.mes-nav {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap; margin: 0 0 var(--sp-3);
}
/* La misma punta de flecha, girada: no se añade un icono al sprite para
   dibujar el mismo trazo al revés. */
.icon--flip { transform: rotate(180deg); }
.screen__head .screen__sub { margin-bottom: 0; }
.screen__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin: var(--sp-3) 0; }
/* Acciones ADMINISTRATIVAS de una ficha: **dentro de la cabecera**, alineadas
   a la derecha del nombre y por encima del menú de secciones (encargo §3). Son
   pocas y sensibles —deshabilitar, inactivar— y se separan así de la edición,
   que vive dentro de cada sección.

   Ya no llevan franja ni rótulo propios: los botones dicen lo que hacen, y el
   rótulo «Acciones administrativas» sólo repetía la categoría. */
.screen__actions--admin {
  justify-content: flex-end; align-items: center; gap: var(--sp-2);
  margin: 0; flex-shrink: 0;
}
.screen__head .screen__actions { margin: 0; }

/* 2026-10-05 — **en el teléfono las acciones de la ficha no se salen.**
   La revisión de uso del 4/oct: en la ficha del Cliente a 390 px, `Inactivar
   Cliente` quedaba fuera de la pantalla y la página no daba arrastre lateral
   para alcanzarlo — la acción existía y no se podía pulsar.

   La causa era `flex-shrink: 0` de arriba. Es correcto en escritorio: evita que
   el título empuje los botones y los parta. Pero con el ancho de un teléfono
   obliga al bloque a conservar su ancho de contenido —los tres botones en una
   fila—, y lo que sobra se va por el borde derecho de un `.screen__head` que ya
   no puede desplazarse.

   Aquí el bloque ocupa el ancho entero y sus botones se reparten en renglones:
   es lo que `.screen__actions` ya hacía con `flex-wrap`, sólo que no podía.
   **No se esconde ni se mueve ninguna acción**, y los Permisos que cada una
   exige siguen siendo los mismos. */
@media (max-width: 720px) {
  .screen__actions--admin {
    width: 100%; flex-shrink: 1; min-width: 0; justify-content: flex-start;
  }
  /* Un botón por renglón cabe entero y se pulsa con el pulgar; la regla de la
     casa pide 44 px de alto, que `.btn` ya da en pantalla táctil. */
  .screen__actions--admin > form { flex: 1 1 auto; }
  .screen__actions--admin > form > .btn { width: 100%; justify-content: center; }
}

/* 2026-09-25 — **los botones de la cabecera van juntos, siempre.** Agustín, al
   ver Consultas: *«el botón de Nueva Consulta y el de Material nuevo están mal
   acomodados»*.

   La causa era del molde, no de esa pantalla: `.screen__head` es un `flex` con
   `space-between`, así que reparte el hueco entre TODOS sus hijos. Con el
   título y UN bloque de acciones sale bien; con el título y DOS —que es lo que
   pasa en cuanto una pantalla ofrece una segunda acción— el primer botón queda
   flotando a media cabecera.

   El `margin-right:auto` sobre el primer hijo pone el hueco **una sola vez**,
   justo después del título: los bloques de acciones que vengan detrás, sean
   uno o tres, se agrupan pegados a la derecha. Se corrige aquí y no pantalla
   por pantalla para que la siguiente que añada un botón nazca bien. */
.screen__head > :first-child { margin-right: auto; }

/* ------------------------------------------------------------ 5. ICONOS */

/* Iconografía vendorizada: un sprite SVG en línea, sin CDN y sin emojis como
   iconografía de producto (encargo §4). El icono es SIEMPRE decorativo: el
   significado lo lleva el texto que lo acompaña. */
.ic {
  width: 16px; height: 16px;
  display: inline-block; vertical-align: -3px;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  flex: 0 0 auto;
}
.ic--sm { width: 14px; height: 14px; }
.ic--lg { width: 20px; height: 20px; }
.ic--xl { width: 24px; height: 24px; }

/* Icono dentro de un cuadro suave de color — el patrón de la referencia. */
.icobox {
  width: 34px; height: 34px; flex: 0 0 34px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: var(--c-accent-soft); color: var(--c-accent-dark);
}
.icobox .ic { width: 17px; height: 17px; }
.icobox--ok   { background: var(--s-ok-bg);   color: var(--s-ok-fg); }
.icobox--aten { background: var(--s-aten-bg); color: var(--s-aten-fg); }
.icobox--bloq { background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.icobox--revi { background: var(--s-revi-bg); color: var(--s-revi-fg); }
.icobox--teal { background: var(--c-teal-soft); color: var(--c-teal); }
.icobox--info { background: var(--c-surface-sunk); color: var(--c-text-2); }
.icobox--lg { width: 40px; height: 40px; flex-basis: 40px; border-radius: 11px; }
.icobox--lg .ic { width: 20px; height: 20px; }

/* ---------------------------------------- 6. TARJETA DE SECCIÓN Y REJILLAS */

.panel {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  margin: 0 0 var(--sp-4);
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}
.panel__head {
  padding: 13px 18px;
  border-bottom: 1px solid var(--c-border-soft);
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-3); flex-wrap: wrap;
}
.panel__title {
  margin: 0; font-size: var(--fs-md); font-weight: 650;
  display: flex; align-items: center; gap: 9px; color: var(--c-text);
}
.panel__title .ic { color: var(--c-text-3); }
.panel__sub { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--c-text-3); }
.panel__actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.panel__body { padding: 16px 18px; min-width: 0; overflow-x: auto; }
.panel__body > * + * { margin-top: var(--sp-3); }
.panel__body > .table:first-child, .panel__body > .tabla:first-child { margin-top: 0; }
.panel__foot {
  padding: 11px 18px; border-top: 1px solid var(--c-border-soft);
  background: var(--c-surface-alt); font-size: var(--fs-sm);
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
  flex-wrap: wrap;
}
/* Una tabla ocupa el ancho completo de su tarjeta, sin doble margen. */
.panel__body--flush { padding: 0; }
.panel__body--flush > * + * { margin-top: 0; }

.panel--aten { box-shadow: inset 3px 0 0 var(--c-franja-aten); }
.panel--bloq { box-shadow: inset 3px 0 0 var(--s-bloq-fg); }
.panel--ok   { box-shadow: inset 3px 0 0 var(--c-franja-ok); }
.panel--acc  { box-shadow: inset 3px 0 0 var(--c-franja-acento); }

/* Rejilla de paneles (Dashboard y pantallas de resumen). */
.board { display: grid; gap: var(--sp-4); grid-template-columns: 1fr 1fr; align-items: start; }
.board__full { grid-column: 1 / -1; }
.board--2 { grid-template-columns: 1fr 1fr; }
.board--3 { grid-template-columns: repeat(3, 1fr); }

/* Bloque inferior del Dashboard (encargo §2.4): `Abastecimiento` a la
   izquierda, alto; a la derecha `Cuentas` arriba e `Inventario en riesgo`
   debajo. La suma de las dos derechas se aproxima a la altura de la izquierda
   **sin fijar ninguna altura absoluta**: `align-items: stretch` deja que la
   columna alta marque el alto y el apilado lo reparta.

   En pantalla angosta las tres caen en una sola columna por la regla de
   `.board` que ya existe, y el apilado se disuelve solo — ninguna tarjeta
   queda aislada ni deja un hueco al lado. */
.board--bottom { align-items: stretch; }
/* El panel de la izquierda llevaba el margen inferior de `.panel`, que queda
   FUERA de su caja: `stretch` estiraba la caja de margen, así que la tarjeta
   acababa `--sp-4` más baja que el apilado de la derecha. Sin ese margen las
   dos columnas terminan exactamente a la misma altura. */
.board--bottom > .panel { margin-bottom: 0; }
.board__stack { display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }
.board__stack > .panel { margin-bottom: 0; }

/* Primer bloque operativo del Dashboard: lo urgente conserva mayor peso y los
   accesos permanecen visibles sin empujar el Calendario fuera del primer
   recorrido. Es composición de componentes existentes, no otra tarjeta. */
/* §F6 — `Lo urgente hoy` **no lleva scroll interno**.

   La causa medida, no deducida: `.panel__body` declara `overflow-x: auto`, y
   por la propia especificación de CSS un eje `visible` junto a un eje que no lo
   es **computa a `auto`**. Es decir, el cuerpo ya tenía `overflow-y: auto`
   latente; sólo le faltaba una altura que lo activara. Se la daba
   `height: calc(100% - 51px)`, puesta para que las dos tarjetas de la franja
   quedaran a la misma altura: con ocho tarjetas urgentes el contenido no cabía
   en esa altura prestada y aparecía la barra de desplazamiento **dentro** de la
   tarjeta, justo donde el Usuario no la busca.

   Se retira la altura impuesta y la franja pasa a `align-items: start`: cada
   tarjeta mide lo que su contenido necesita y la única navegación vertical es
   la de la página, que es la natural. La simetría de altura era una preferencia
   estética; el scroll interno era un defecto de uso. */
.dashboard-priority {
  display: grid; gap: var(--sp-4); margin: 0 0 var(--sp-4);
  grid-template-columns: minmax(0, 1.25fr) minmax(24rem, 1fr);
  /* **`stretch`, no `start`** — 2026-09-22, Agustín viendo el Dashboard en su
     monitor: *«arregla esos dos espacios en pantalla completa»*.

     Con `start` cada tarjeta medía lo que pedía su contenido, y en pantalla
     ancha la columna corta dejaba un hueco del tamaño de media pantalla al
     lado de la larga. Estiradas, las dos acaban a la misma altura.

     **No vuelve el scroll interno**, que era lo que `start` evitaba y sí era
     un defecto de uso: la tarjeta crece, su contenido se queda arriba y no se
     fija ninguna altura ni ningún `overflow`. */
  align-items: stretch;
}
.dashboard-priority > .panel { margin-bottom: 0; display: flex; flex-direction: column; }
.dashboard-priority .panel__body { height: auto; }
/* Las ocho tarjetas del encargo §F7 en una rejilla que las acomoda en dos
   filas de cuatro a 1440 px y en dos de tres a 1280 px, sin recortar ninguna. */
.dashboard-priority .urgent {
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}
.dashboard-priority .urgent__item { padding: 10px 11px; }
.dashboard-priority .quick {
  grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 0;
  gap: var(--sp-2);
  /* Nueve accesos = tres filas de tres. La cuadrícula queda cerrada y no
     deja el hueco que dejaba el octavo. */
  grid-auto-rows: 1fr;
}
.dashboard-priority .quick a {
  display: grid; grid-template-columns: 30px minmax(0, 1fr);
  align-items: center; min-height: 58px; padding: 8px 9px;
}

/* --- EL DASHBOARD CON CUERPO (2026-09-21 · D-693) --------------------------
   Agustín, al ver el Dashboard de D-691 en producción: «se le quitó demasiado,
   quedó muy vacío; sí me gusta entrar y poder ver ciertas gráficas y acceso e
   información general útil». Vuelven la silueta de Ventas con su margen, la
   semana de Logística, Cuentas como dos barras por moneda, lo que viene de
   Proveedores y seis accesos. Lo que no vuelve: las 26 tarjetas de antes. */

/* La primera fila: la gráfica a la izquierda y «Lo urgente hoy» a la derecha.
   Si sólo se produce uno de los dos —sin casilla de Ventas, o sin nada
   urgente—, ocupa la fila entera en vez de dejar media pantalla vacía. */
.dashboard-priority > .panel:only-child { grid-column: 1 / -1; }

/* La línea de arriba de la gráfica: el mes en curso con su variación, para
   que la última barra —siempre la más corta, porque el mes no termina— se
   lea con su contexto y no como una caída. */
.chart__lead {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  margin: 0 0 4px; font-size: var(--fs-sm); color: var(--c-text-2);
}
.chart__lead > b { font-size: var(--fs-xl); font-weight: 700; color: var(--c-text); font-variant-numeric: tabular-nums; }
.chart__lead-label { text-transform: uppercase; letter-spacing: .07em; font-size: var(--fs-xs); font-weight: 600; }
.chart__lead-margen { margin-left: auto; }
.chart__lead-margen b { color: var(--c-text); font-variant-numeric: tabular-nums; }
.chart--tablero .chart__cols { height: 176px; }
/* En el tablero los meses pasados no se apagan a gris: son la misma serie,
   en el mismo azul y más tenue; el mes en curso, a tono entero. */
.chart--tablero .chart__col--off .chart__bar { background: var(--c-accent); opacity: .42; }
.chart--tablero .chart__col--off:hover .chart__bar { opacity: .7; }
/* El margen de cada mes, debajo de su rótulo: una segunda fila alineada con
   las columnas. Es texto, no color, así que se lee igual en cualquier tono. */
.chart__labels--sub { padding-top: 2px; }
.chart__labels--sub span { color: var(--c-text-2); font-weight: 600; font-variant-numeric: tabular-nums; }
@media (max-width: 1200px) {
  /* Seis meses caben siempre: la regla de «uno de cada dos» es para doce. */
  .chart--tablero .chart__labels span:nth-child(even) { visibility: visible; }
}

/* La leyenda del semáforo, separada de los renglones de la semana. */
.dashboard-week .legend { margin-top: var(--sp-2); }

/* Abajo y a ancho completo, la gráfica gana alto: las barras se leen mejor y
   el panel no queda como una franja aplastada de lado a lado. */
.dashboard-chart--ancha .chart--tablero .chart__cols { height: 208px; }

/* Cuentas: por cada moneda, «Por cobrar» y «Por pagar» como dos barras sobre
   la misma escala, con el importe a la derecha. Cada barra es un enlace a su
   cartera. La escala es la mayor de las dos cifras de ESA moneda; las monedas
   nunca comparten escala ni se suman. */
.saldos { display: flex; flex-direction: column; gap: var(--sp-3); }
.saldos__moneda { display: flex; flex-direction: column; gap: 5px; }
.saldos__titulo {
  font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--c-text-2);
}
.saldos__fila {
  display: grid; grid-template-columns: 5.2rem minmax(0, 1fr) auto;
  align-items: center; gap: 10px; text-decoration: none; color: inherit;
  font-size: var(--fs-sm); border-radius: var(--radius-sm); padding: 2px 0;
}
.saldos__fila:hover { color: inherit; }
.saldos__fila:hover .saldos__monto { text-decoration: underline; }
.saldos__rotulo { color: var(--c-text-2); }
.saldos__barra {
  display: block; height: 12px; border-radius: var(--radius-pill);
  background: var(--c-surface-sunk); overflow: hidden;
}
.saldos__barra i { display: block; height: 100%; border-radius: var(--radius-pill); min-width: 2px; }
/* Las dos barras usan las FRANJAS, no los colores de texto: es la misma
   familia de la tarjeta y con su mismo punto de transparencia. El «Por pagar»
   era el dorado que Agustín señaló el 22/sep — ahora amarillo. */
.saldos__barra--cobrar i { background: var(--c-franja-acento); }
.saldos__barra--pagar i { background: var(--c-franja-aten); }
.saldos__monto { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 650; }
.saldos__nota { font-size: var(--fs-xs); color: var(--c-text-3); cursor: help; }
/* 2026-09-25 — **el vencido, del mismo rango que las barras de arriba.**
   Agustín: *«el cuadro amarillo parece alerta temporal»*. El fondo ámbar y el
   icono de reloj son el lenguaje de *«esto acaba de pasar»*, y el vencido no es
   eso: es una cifra permanente de la cartera. Lo separa una línea, no un color,
   y el importe se lee con el mismo peso y la misma tipografía tabular que los
   de las barras. El ámbar se queda **sólo en la nota de los días**, que es lo
   único que de verdad empeora con el tiempo. */
.saldos__vencido {
  display: flex; flex-direction: column; gap: 2px; margin: 0;
  padding-top: var(--sp-3); border-top: 1px solid var(--c-border-soft);
}
.saldos__vencido-et {
  font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--c-text-2);
}
.saldos__vencido-cifras {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  font-size: var(--fs-md);
}
.saldos__vencido-cifras b { font-weight: 650; color: var(--c-text); font-variant-numeric: tabular-nums; }
.saldos__vencido-sep { color: var(--c-text-3); }
.saldos__vencido-pie { font-size: var(--fs-xs); color: var(--s-aten-fg); font-weight: 600; }

/* La fila de abajo: Cuentas, lo que viene de Proveedores y los accesos.
   Mismo criterio que arriba: las tres acaban a la misma altura, porque la de
   los accesos es mucho más corta que la de Cuentas y dejaba el otro hueco que
   Agustín señaló. */
.dashboard-bottom { align-items: stretch; }
.dashboard-bottom > .panel { margin-bottom: 0; display: flex; flex-direction: column; }
/* D-808 — al subir los accesos arriba, el bloque de abajo pasó de tres paneles a
   dos; quien no ve Cuentas se quedaba con «Lo que viene de Proveedores» a media
   pantalla y un hueco al lado. Solo, ocupa el ancho entero. */
.dashboard-bottom > .panel:only-child { grid-column: 1 / -1; }
/* Seis accesos en dos columnas, cada uno con su icono a la izquierda. */
.quick--tablero {
  grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 0; gap: var(--sp-2);
}
.quick--tablero a {
  display: grid; grid-template-columns: 30px minmax(0, 1fr);
  align-items: center; min-height: 58px; padding: 8px 10px;
}

/* -------------------------------- 7. FRANJA DE INDICADORES Y TENDENCIA */

/* 3–6 indicadores clave, compactos y visuales. Nunca «KPIs porque sí»: cada
   uno tiene que ayudar a operar la pantalla en la que está (encargo §5). */
.stats {
  display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.stats--4 { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
/* Una sola tarjeta que RESUME la población y ocupa la fila entera, con sus
   desgloses debajo en su propia rejilla (`Pedidos activos`). Compartir rejilla
   con ellos dejaba a la tarjeta dominante del mismo tamaño que sus partes. */
.stats--1 { grid-template-columns: minmax(0, 1fr); margin-bottom: var(--sp-3); }
/* §F38 — `Ventas del mes` **domina la primera fila** de Mi panel.

   Con cinco o seis tarjetas del mismo tamaño la cabecera se leía como una lista
   sin jerarquía: la cifra que resume el mes competía con un conteo de
   Cotizaciones. Aquí ocupa la fila entera y las demás se reparten la siguiente
   en `.stats--4`, que ya se apila sola en pantalla angosta.

   No es una tarjeta distinta: es **la misma** `.stat--kpi`, en una rejilla de
   una sola columna y con el hueco inferior reducido para que las dos filas se
   lean como una sola cabecera. */
.stats--panel-lead {
  grid-template-columns: minmax(0, 1fr);
  margin-bottom: var(--sp-3);
}
/* La SEGUNDA fila de esa cabecera — §F38.

   Medido en el navegador: con `.stats--4` (`minmax(13rem, 1fr)`) las cinco
   tarjetas restantes caben en una fila a 1440 px pero **se parten en 4 + 1** a
   1280, porque a ese ancho el hueco disponible da 12.9 rem por tarjeta y el
   mínimo pedía 13. Una fila de cuatro y otra de una no es «las otras cuatro
   debajo»: es una tarjeta huérfana.

   Con `11.5rem` las cinco entran en una sola fila a 1280 y a 1440, y en
   pantalla más angosta se siguen apilando solas — no se fija ningún número de
   columnas, que es lo que dejaría una rejilla rota en un ancho no previsto. */
.stats--panel-rest { grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr)); }
.stats--dashboard { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.stats--fit { grid-template-columns: repeat(auto-fit, minmax(11rem, max-content)); }

.stat {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 3px;
  min-width: 0;
  position: relative;
}
.stat__top { display: flex; align-items: center; gap: 10px; margin-bottom: 3px; }
.stat__top .stat__label { margin: 0; }
.stat__label {
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-2);
  text-transform: uppercase; letter-spacing: .07em;
  overflow: hidden; text-overflow: ellipsis;
}
.stat__value {
  font-size: var(--fs-xl); font-weight: 680; line-height: 1.2;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.stat__value--sm { font-size: var(--fs-lg); }
.stat__value--xl { font-size: var(--fs-2xl); }
.stat__meta { font-size: var(--fs-sm); color: var(--c-text-3); }
.stat__foot { margin-top: auto; padding-top: var(--sp-2); }
.stat a.stat__link { font-size: var(--fs-sm); text-decoration: none; }
.stat a.stat__link:hover { text-decoration: underline; }

/* El tono de una tarjeta refuerza al texto; nunca lo sustituye. */
.stat--aten { border-color: var(--s-aten-bd); }
.stat--bloq { border-color: var(--s-bloq-bd); }
.stat--ok   { border-color: var(--s-ok-bd); }
.stat--acc  { border-color: var(--c-accent-line); }
.stat--aten .stat__value { color: var(--s-aten-fg); }
.stat--bloq .stat__value { color: var(--s-bloq-fg); }
.stat--ok   .stat__value { color: var(--s-ok-fg); }

/* --- Tarjeta KPI de cabecera (componente compartido) ---------------------
   Una sola definición para TODAS las cabeceras (Dashboard, Clientes, y
   cualquier pantalla futura): la cifra manda, va CENTRADA y la lectura baja
   en una jerarquía fija — **cifra → título → contexto**. El contexto
   secundario se estructura en pares etiqueta/valor alineados; nunca en texto
   corrido, que es lo que descuadraba las tarjetas cuando una frase era larga
   y otra corta. Mejorar aquí evita copiar CSS pantalla por pantalla. */
.stat--kpi {
  align-items: center; text-align: center; gap: 2px; padding: 15px 16px 14px;
}
.stat--kpi .icobox { margin-bottom: 5px; }
.stat--kpi .stat__value { font-size: var(--fs-2xl); }
.stat--kpi .stat__value--sm { font-size: var(--fs-xl); }
/* El título NO se recorta con elipsis: envuelve. Una cifra sin su nombre
   completo no se puede interpretar, y la altura la iguala la rejilla. */
.stat--kpi .stat__label {
  overflow: visible; text-overflow: clip; white-space: normal; max-width: 100%;
}
.stat--kpi .stat__meta { text-align: center; }
.stat--kpi .delta { align-self: center; }
.stat--kpi .stat__foot {
  width: 100%; text-align: center;
  border-top: 1px solid var(--c-border-soft); margin-top: auto;
}

/* Contexto secundario de un KPI: pares etiqueta/valor en columnas alineadas.
   Sustituye a la frase corrida — dos datos distintos se leen de un vistazo y
   dos tarjetas contiguas quedan a la misma altura. */
.kpi-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 4px var(--sp-3); width: 100%;
  margin-top: var(--sp-2); padding-top: var(--sp-2);
  border-top: 1px solid var(--c-border-soft);
}
.kpi-facts--1 { grid-template-columns: minmax(0, 1fr); }
/* Variante en FILAS para un contexto de tres cifras cortas cuyo rótulo es una
   palabra larga (`Pedidos activos`). En columnas, `Programados` no cabía en un
   tercio de la tarjeta y se partía a media palabra o se salía; en filas cada
   rótulo tiene el ancho entero, así que **los tres caben en una sola línea**,
   comparten exactamente la misma composición —rótulo a la izquierda, cifra a
   la derecha— y quedan alineados entre sí por construcción.

   `display: contents` en el par deja que rótulo y cifra participen
   directamente en la rejilla: sin él, cada par formaría su propia caja y las
   cifras dejarían de compartir columna. */
.kpi-facts--rows {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 3px var(--sp-3); text-align: left;
}
.kpi-facts--rows .kpi-fact { display: contents; }
.kpi-facts--rows .kpi-fact__label {
  letter-spacing: .04em; line-height: 1.3; align-self: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kpi-facts--rows .kpi-fact__value { text-align: right; }
.kpi-fact { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.kpi-fact__label {
  font-size: var(--fs-xs); color: var(--c-text-3);
  text-transform: uppercase; letter-spacing: .06em;
}
.kpi-fact__value {
  font-size: var(--fs-sm); font-weight: 650;
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.kpi-fact__value--aten { color: var(--s-aten-fg); }
.kpi-fact__value--muted { color: var(--c-text-3); font-weight: 550; }

/* --- Tarjeta KPI de un SUBENCABEZADO (*refinement 6* §B4.4) ---------------
   Misma tarjeta, misma composición y mismo comportamiento; **menos peso
   visual**. Una franja secundaria —la de revisión de `Cuentas por cobrar`—
   tenía exactamente la altura y el tamaño de cifra del encabezado principal, y
   por eso se leía como un segundo encabezado en vez de como contexto.

   Lo que se reduce es **altura, relleno y tamaño de la cifra**; lo que NO se
   reduce es el título, ni el contraste, ni el área pulsable: sigue siendo
   legible y sigue llevando a su conjunto exacto. Achicar el texto hasta
   volverlo decorativo habría cambiado el problema, no resuelto. */
.stats--sub { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: var(--sp-2); }
.stat--mini { padding: 9px 12px 8px; gap: 1px; }
.stat--mini .icobox { width: 24px; height: 24px; flex: 0 0 24px; margin-bottom: 2px; }
.stat--mini .icobox .ic { width: 13px; height: 13px; }
.stat--mini .stat__value { font-size: var(--fs-lg); }
.stat--mini .stat__value--sm { font-size: var(--fs-md); }
.stat--mini .stat__label { font-size: 10px; letter-spacing: .05em; }
.stat--mini .stat__meta { font-size: var(--fs-xs); }
.stat--mini .stat__foot { padding-top: 5px; }

/* --- Tarjeta KPI CLICKABLE (regla global §1 del refinement 2) -------------
   Una cifra que representa un conjunto de hechos lleva a esos hechos, y el
   destino llega **ya filtrado** al mismo subconjunto. La tarjeta entera es un
   `<a>`: sin JavaScript, así que el teclado, el botón central del ratón y
   «abrir en pestaña nueva» funcionan solos.

   El texto NO se pinta de color de enlace —la cifra manda y el subrayado la
   ensuciaría—; lo que indica que es pulsable es el estado al pasar por encima
   y un anillo de foco visible, que es lo que el teclado necesita. */
.stat--link {
  text-decoration: none; color: inherit; cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.stat--link:hover { border-color: var(--c-accent-line); box-shadow: var(--shadow-md); }
.stat--link:focus-visible { outline: 2px solid var(--c-accent-line); outline-offset: 2px; }
.stat--link .stat__label { text-decoration: none; }
@media (prefers-reduced-motion: no-preference) {
  .stat--link:hover { transform: translateY(-1px); }
}

/* --- Tarjeta de VENDEDOR de `Mi panel` (*refinement 6* §B1.1) ------------
   La entrada del Administrador: una tarjeta por Vendedor con su nombre y las
   tres cifras que permiten decidir a quién abrir. **No es un KPI**: el KPI
   tiene UNA cifra dominante y centrada, y aquí las tres pesan lo mismo, así
   que reutilizar `.stat--kpi` habría obligado a deshacer justo lo que ese
   componente define. Lo que sí se reutiliza es `.kpi-facts--rows`, que ya
   resuelve los pares rótulo/cifra alineados.

   La tarjeta entera es un `<a>`, con el mismo estado de hover y el mismo
   anillo de foco que `.stat--link`: sin JavaScript. */
.sellercards {
  display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.sellercard {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0; text-decoration: none; color: inherit; cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.sellercard:hover { border-color: var(--c-accent-line); box-shadow: var(--shadow-md); }
.sellercard:focus-visible { outline: 2px solid var(--c-accent-line); outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .sellercard:hover { transform: translateY(-1px); }
}
.sellercard__head { display: flex; align-items: center; gap: 10px; min-width: 0; }
.sellercard__name {
  font-size: var(--fs-lg); font-weight: 650; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sellercard__foot {
  margin-top: auto; padding-top: var(--sp-2);
  font-size: var(--fs-xs); color: var(--c-text-3);
}

/* La tarjeta DOMINANTE de una cabecera —`Pedidos activos` sobre sus cuatro
   estados operativos— ocupa dos columnas de la rejilla cuando hay sitio. En
   una pantalla angosta vuelve a una sola: `auto-fit` ya reparte, y forzar dos
   columnas donde no caben dejaría justo los huecos que el encargo prohíbe. */
.stat--wide { grid-column: span 2; }
@media (max-width: 720px) {
  .stat--wide { grid-column: span 1; }
}

/* --- Cifra BIMONEDA de una tarjeta KPI (encargo §2.1) --------------------
   CxC y CxP son la excepción al KPI de un solo número, porque manejan dos
   monedas y **nunca se suman entre sí** (RN-138). El orden de lectura que el
   negocio pidió es *importe MXN → importe USD → título → contexto*, así que
   los importes se apilan **encima** del título, centrados y con cifras
   tabulares para que las dos líneas queden alineadas. */
.stat__money {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  width: 100%;
}
.stat__money-line {
  font-size: var(--fs-xl); line-height: 1.2;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
  color: var(--c-text-2); overflow-wrap: anywhere;
}
/* El importe manda; el código de moneda lo acompaña sin competir con él. Las
   dos líneas son igual de importantes —una NO es el total y la otra un
   detalle—, así que van al mismo tamaño: sumarlas está prohibido (RN-138). */
.stat__money-line b { font-weight: 680; color: var(--c-text); }
.stat__money-line--none { color: var(--c-text-3); font-weight: 600; }

/* --- Comparación CxC / CxP por moneda (encargo §2.5) ---------------------
   Tabla compacta de tres cifras. El signo se refuerza con color **y** con el
   propio signo escrito: el color nunca es el único canal, y el `title` de
   cada celda repite que esto es una COMPARACIÓN — las dos carteras siguen
   separadas y no existe ninguna función que las netee (RN-213). */
.ledger { margin-bottom: var(--sp-2); }
.ledger th[scope="row"] { font-weight: 650; }
.ledger td, .ledger th { padding-top: 6px; padding-bottom: 6px; }
.ledger__pos { color: var(--s-ok-fg); font-weight: 650; cursor: help; }
.ledger__neg { color: var(--s-bloq-fg); font-weight: 650; cursor: help; }

/* Indicador compacto de alerta en una tabla: un punto con su descripción.
   **El color nunca es el único canal** — el punto SIEMPRE viaja con su
   `title` y su `aria-label`, que dicen exactamente qué falta. Sustituye a los
   globos de texto largo, que hacían saltar el alto de la fila según cuántas
   palabras llevara cada Cliente. */
.alerts { white-space: nowrap; }
.alerts > * + * { margin-left: 6px; }

/* Una señal de la columna `Alertas` — §F13.

   ## El defecto que se corrige, medido y no deducido

   Los puntos se veían **huecos**, sin su color. La causa era una **colisión de
   nombres en el propio CSS**: `.dot` estaba declarado DOS veces, aquí para la
   alerta y mucho más abajo para el checklist compacto de Próximas salidas, que
   declara `background: transparent` y un borde gris. Con la misma
   especificidad gana la última, así que la regla del checklist **borraba el
   relleno de `.dot--aten` y `.dot--bloq`** en una pantalla que no tiene nada
   que ver con ella. Por eso la alerta pasa a llamarse `.alerta__dot`: pertenece
   a este componente, y así ninguna de las dos puede volver a pisar a la otra.

   ## La forma que el negocio pidió

   Agustín prefiere el patrón anterior —**punto de color**, color según la
   gravedad, y el globo explicando exactamente qué significa— y pidió que el
   texto no viva permanentemente al lado, porque tres etiquetas por fila
   volvían pesada la tabla.

   **El color no es el único portador del significado**, y eso no se negocia:
   cada punto es `tabindex="0"`, así que se alcanza con el teclado; lleva su
   globo instantáneo dibujado por la página (mismo mecanismo que `.dot__tip`,
   por el mismo motivo: el `title` nativo tarda y sólo enseña el cursor `?`); y
   lleva **texto completo para lector de pantalla**, que dice qué falta. Lo que
   se retira es la etiqueta *visible* permanente, no la información. */
.alerta {
  position: relative; display: inline-flex; align-items: center;
  font-size: var(--fs-sm); white-space: nowrap;
}
.alerta:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; border-radius: 50%; }
.alerta__dot {
  display: inline-block; width: 11px; height: 11px; border-radius: 50%;
  vertical-align: middle; border: 1px solid rgba(0, 0, 0, .18); flex: none;
}
.alerta__dot--aten { background: var(--s-aten-fg); border-color: var(--s-aten-fg); }
.alerta__dot--bloq { background: var(--s-bloq-fg); border-color: var(--s-bloq-fg); }
.alerta__dot--ok   { background: var(--s-ok-fg);   border-color: var(--s-ok-fg); }
/* El globo: sale **al instante**, con el ratón y con el teclado. */
.alerta__tip {
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text);
  white-space: normal; width: max-content; max-width: 22rem;
  text-transform: none; letter-spacing: 0; text-align: left;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  padding: 4px 9px; z-index: 5;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .08s ease;
}
.alerta:hover .alerta__tip, .alerta:focus-visible .alerta__tip { opacity: 1; visibility: visible; }
/* Dentro de la celda, el globo del primero y del último no puede desbordarla. */
.alerts .alerta:first-child .alerta__tip { left: 0; transform: none; }
.alerts .alerta:last-child .alerta__tip { left: auto; right: 0; transform: none; }
/* La etiqueta VISIBLE de una señal, cuando la columna es suya y no comparte
   sitio con otras: en `Solicitudes de precio` cada fila tiene **una** señal, así
   que el texto cabe al lado y ahorra el globo para el detalle. En la columna
   `Alertas` de Clientes, donde conviven hasta tres, la etiqueta no se dibuja y
   el texto vive en el globo y en el lector de pantalla (§F13, §F72). */
.alerta__label { margin-left: 5px; }
.alerta__sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Tendencia — la dirección NUNCA es sólo color: lleva su flecha y su texto. */
.delta {
  font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 3px;
}
.delta--up::before   { content: "▲"; font-size: 8px; }
.delta--down::before { content: "▼"; font-size: 8px; }
.delta--up.delta--good, .delta--down.delta--good { color: var(--s-ok-fg); }
.delta--up.delta--bad, .delta--down.delta--bad { color: var(--s-bloq-fg); }
.delta--flat { color: var(--c-text-3); font-weight: 500; }
.delta__ref { color: var(--c-text-3); font-weight: 400; }

/* Micrográfica: la silueta de los últimos meses bajo la cifra. Es
   ORIENTACIÓN, no lectura de valores: las cifras exactas viven en la gráfica
   completa y en su tabla accesible. */
.spark {
  display: flex; align-items: flex-end; gap: 2px;
  height: 30px; margin-top: 8px;
}
.spark__b {
  flex: 1 1 0; min-height: 2px; border-radius: 2px 2px 0 0;
  background: var(--c-accent-line);
}
.spark__b--now { background: var(--c-franja-acento); }
.spark__b--none { background: var(--c-border); }
.spark--ok .spark__b { background: #b6e0c6; }
.spark--ok .spark__b--now { background: var(--s-ok-fg); }
.spark--aten .spark__b { background: #ecd5a4; }
.spark--aten .spark__b--now { background: var(--c-franja-aten); }
.spark--teal .spark__b { background: var(--c-teal-line); }
.spark--teal .spark__b--now { background: var(--c-teal); }

/* Toda micrográfica lleva su equivalente en cifras, plegado: el dato exacto
   nunca vive sólo en un píxel. */
.spark__data { margin-top: 6px; }
.spark__data summary { font-size: var(--fs-xs); color: var(--c-text-3); }
.spark__data .tabla { margin-top: 6px; }
.spark__data .tabla th, .spark__data .tabla td { padding: 4px 8px; font-size: var(--fs-sm); }

/* ------------------------- 8. TARJETAS DE ACCIÓN Y ACCESOS RÁPIDOS */

.cards {
  display: grid; gap: var(--sp-3); margin-bottom: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
}
.card {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 16px; display: flex; flex-direction: column; gap: 6px;
}
.card__head { display: flex; align-items: center; gap: 10px; }
.card__title {
  margin: 0; font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-2);
  text-transform: uppercase; letter-spacing: .07em;
}
.card__value {
  margin: 0; font-size: var(--fs-xl); font-weight: 680; line-height: 1.25;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.card__meta { margin: 0; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.card__detail { margin: 0; color: var(--c-text-2); font-size: var(--fs-sm); }
.card__action { margin: auto 0 0; padding-top: var(--sp-2); }

/* La tarjeta que AGREGA una tarjeta — D-714. Es la misma caja, con el borde
   punteado que dice «aquí todavía no hay nada, pero puede haberlo»: así se lee
   como parte de la fila y no como un botón suelto encima de ella. */
.card--nuevo {
  border-style: dashed; box-shadow: none; text-decoration: none; color: var(--c-text);
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.card--nuevo:hover {
  border-color: var(--c-accent-line); border-style: solid;
  box-shadow: var(--shadow); transform: translateY(-1px); color: var(--c-text);
}
/* --- Los DOCUMENTOS de la empresa (2026-09-25, sobre D-714) ---------------
   Agustín: *«se puede hacer más bonita toda esta sección, sólo más claro qué
   documento es y los botones relevantes»*.

   Usaban `.card`, cuyo título es un rótulo en versalitas de 11 px pensado para
   ir ENCIMA de una cifra grande —`.card__value`—. Aquí la cifra grande era la
   vigencia, o sea el dato que sobraba, y el nombre del documento —lo único que
   se viene a buscar— quedaba en letra chica. Molde propio: el nombre es el
   titular, la tarjeta entera se puede picar y los botones van abajo, con
   `Descargar` de primero. */
.docs {
  display: grid; gap: var(--sp-3); margin-bottom: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
}
.doc {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 16px; display: flex; flex-direction: column; gap: 10px;
}
/* Sin archivo la tarjeta no grita: un borde ámbar y su distintivo bastan. */
.doc--falta { border-color: var(--s-aten-bd); }
.doc__head { display: flex; align-items: flex-start; gap: 11px; }
.doc__head .icobox { flex: 0 0 auto; width: 34px; height: 34px; flex-basis: 34px; }
.doc__id { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }
/* `.panel__body h3` pinta los subtítulos de sección en versalitas grises de
   11 px, y gana por especificidad: el nombre del documento salía como un
   rótulo en vez de como el titular de la tarjeta. Se declara con la clase de
   la tarjeta delante para que este molde mande dentro de él. */
.doc .doc__titulo {
  margin: 0; padding: 0; border: 0;
  font-size: var(--fs-lg); font-weight: 650; letter-spacing: -.01em;
  text-transform: none; color: var(--c-text); line-height: 1.25;
}
.doc__pie { margin: 0; margin-top: auto; font-size: var(--fs-sm); color: var(--c-text-3); }
.doc__botones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.doc--nuevo {
  border-style: dashed; box-shadow: none; text-decoration: none; color: var(--c-text);
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.doc--nuevo:hover {
  border-color: var(--c-accent-line); border-style: solid;
  box-shadow: var(--shadow); transform: translateY(-1px); color: var(--c-text);
}

.card__diag {
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px dashed var(--c-border);
  grid-template-columns: 12rem 1fr; font-size: var(--fs-sm);
}

/* Accesos rápidos: acciones reales — icono + color + etiqueta corta. */
.quick {
  display: grid; gap: 10px; margin: 0 0 var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}
.quick a {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 13px 14px;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-text);
  text-decoration: none; font-size: var(--fs); font-weight: 550;
  box-shadow: var(--shadow-xs);
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
  min-height: 76px;
}
.quick a:hover {
  border-color: var(--c-accent-line); box-shadow: var(--shadow);
  transform: translateY(-1px); color: var(--c-text);
}
.quick a .icobox { width: 30px; height: 30px; flex-basis: 30px; border-radius: 8px; }
.quick a .icobox .ic { width: 16px; height: 16px; }
.quick__label { line-height: 1.3; }

/* D-808 — la franja de «lo que más haces», arriba del Panel general y a todo
   lo ancho: una sola fila cuando caben los seis, y se parte sola cuando no. */
.accesos { padding: var(--sp-3); }
.quick--franja {
  grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr)); margin: 0; gap: var(--sp-2);
}
.quick--franja a {
  flex-direction: row; align-items: center; min-height: 52px; padding: 9px 12px;
}

/* Fila compacta de accesos, cuando el bloque no es protagonista. */
.quick--row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.quick--row a { flex-direction: row; align-items: center; min-height: 38px; padding: 7px 12px; }

/* ----------------------------------------------------------- 9. BOTONES */

/* Cuatro niveles y ni uno más: primario (la acción de la pantalla),
   secundario (complementaria), fantasma (navegación o acción menor) y
   excepcional (sólo lo realmente excepcional) — encargo §17. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 14px; min-height: 34px; line-height: 1.3;
  border-radius: var(--radius-sm);
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface); color: var(--c-text);
  font-family: inherit; font-size: var(--fs); font-weight: 550;
  cursor: pointer; text-decoration: none;
  box-shadow: var(--shadow-xs);
  transition: background .12s ease, border-color .12s ease, box-shadow .12s ease;
  white-space: nowrap;
}
.btn:hover { background: var(--c-surface-alt); border-color: var(--c-text-3); color: var(--c-text); }
.btn:active { box-shadow: none; }
.btn .ic { width: 15px; height: 15px; }

/* D-806 — el botón principal es del verde vivo de Gamma, con texto oscuro:
   el blanco sobre ese verde no se lee. Al pasar el ratón se aclara, no se
   oscurece, para que siga siendo el mismo verde. */
.btn--primary {
  background: var(--c-gamma); border-color: var(--c-gamma); color: var(--c-sobre-gamma);
  box-shadow: 0 1px 2px rgba(13, 43, 33, .14);
}
.btn--primary:hover { background: #3cc482; border-color: #3cc482; color: var(--c-sobre-gamma); }
.btn--primary .ic { color: var(--c-sobre-gamma); }

.btn--secondary {
  background: var(--c-accent-soft); border-color: var(--c-accent-line);
  color: var(--c-accent-dark);
}
.btn--secondary:hover { background: #d4f0e0; border-color: var(--c-accent); color: var(--c-accent-dark); }

.btn--ghost {
  background: transparent; border-color: transparent; color: var(--c-text-2);
  box-shadow: none;
}
.btn--ghost:hover { background: var(--c-surface-sunk); color: var(--c-text); border-color: transparent; }

/* Excepcional: sólo para acciones realmente excepcionales (cancelar, revertir,
   corregir historia). Se ve distinta a propósito. */
.btn--danger {
  background: var(--c-surface); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg);
}
.btn--danger:hover { background: var(--s-bloq-bg); border-color: var(--s-bloq-fg); color: var(--s-bloq-fg); }

.btn--sm { padding: 4px 10px; min-height: 28px; font-size: var(--fs-sm); }
.btn--sm .ic { width: 14px; height: 14px; }
.btn--lg { padding: 10px 18px; min-height: 40px; font-size: var(--fs-md); }
.btn--block { width: 100%; }
.btn--icon { padding: 6px; width: 32px; min-height: 32px; }

.btn:disabled, .btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; box-shadow: none;
}

/* Grupo de botones con jerarquía visible de izquierda a derecha. */
.btns { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }

/* ------------------------------------------------------- 10. ESTADOS */

/* Un estado se lee por su TEXTO; el color sólo lo refuerza (encargo §3, §21). */
.chip, .pill, .badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--radius-pill);
  font-size: var(--fs-xs); font-weight: 600; line-height: 1.6;
  border: 1px solid var(--c-border); background: var(--c-surface-alt);
  color: var(--c-text-2); white-space: nowrap;
}
.chip .ic, .pill .ic, .badge .ic { width: 12px; height: 12px; }
.chip--ok, .badge--ok {
  background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg);
}
.chip--aten, .badge--aten {
  background: var(--s-aten-bg); border-color: var(--s-aten-bd); color: var(--s-aten-fg);
}
.chip--bloq, .chip--off, .chip--n3, .badge--bloq {
  background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg);
}
.chip--revi, .chip--exc, .badge--revi, .badge--exc {
  background: var(--s-revi-bg); border-color: var(--s-revi-bd); color: var(--s-revi-fg);
}
.chip--sens { background: var(--s-aten-bg); border-color: var(--s-aten-bd); color: var(--s-aten-fg); }
.chip--dep, .chip--nat, .chip--acc, .badge--acc {
  background: var(--c-accent-soft); border-color: var(--c-accent-line); color: var(--c-accent-dark);
}
.chip--teal { background: var(--c-teal-soft); border-color: var(--c-teal-line); color: var(--c-teal); }
.chip--lg { font-size: var(--fs-sm); padding: 3px 11px; }

/* Familias de estado operativo — encargo §20 del *Functional refinement 3*.
   Una clase por FAMILIA, no por pantalla: el mismo estado se ve igual en el
   listado de Pedidos, en Mi panel y en la ficha del Cliente, porque las tres
   piden su clase a `commercial.selectors.status_family`.

   **No se inventó ningún estado por tener color** y **el color nunca es el
   único canal**: la etiqueta de texto acompaña siempre al badge. */
.badge--borrador { background: var(--c-surface-alt); border-color: var(--c-border); color: var(--c-text-2); }
.badge--por-preparar { background: var(--s-aten-bg); border-color: var(--s-aten-bd); color: var(--s-aten-fg); }
.badge--esperando-material { background: var(--s-revi-bg); border-color: var(--s-revi-bd); color: var(--s-revi-fg); }
.badge--listo { background: var(--c-teal-soft); border-color: var(--c-teal-line); color: var(--c-teal); }
.badge--programado { background: var(--c-accent-soft); border-color: var(--c-accent-line); color: var(--c-accent-dark); }
.badge--en-ruta { background: var(--c-accent-soft); border-color: var(--c-accent-line); color: var(--c-accent-dark); }
.badge--entregado { background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg); }
.badge--cancelado { background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }
.badge--neutro { background: var(--c-surface-alt); border-color: var(--c-border); color: var(--c-text-2); }

/* Punto de estado: el segundo canal, además del texto. */
.chip::before { content: none; }
.chip--dot::before {
  content: ""; display: inline-block; width: 6px; height: 6px;
  border-radius: 50%; background: currentColor; flex: 0 0 6px;
}

/* Avisos --------------------------------------------------------------- */

.note {
  border: 1px solid var(--s-info-bd); background: var(--s-info-bg); color: var(--s-info-fg);
  padding: 11px 14px; border-radius: var(--radius); font-size: var(--fs);
  display: block;
}
.note--ok   { border-color: var(--s-ok-bd);   background: var(--s-ok-bg);   color: var(--s-ok-fg); }
.note--aten { border-color: var(--s-aten-bd); background: var(--s-aten-bg); color: var(--s-aten-fg); }
.note--revi { border-color: var(--s-revi-bd); background: var(--s-revi-bg); color: var(--s-revi-fg); }
.note--bloq { border-color: var(--s-bloq-bd); background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.note + .note { margin-top: var(--sp-2); }
.note a { color: inherit; font-weight: 600; }

/* La marca no decora: es el canal que NO depende del color. */
.note--ok::before   { content: "✓ "; font-weight: 700; }
.note--aten::before { content: "⚠ "; font-weight: 700; }
.note--bloq::before { content: "✕ "; font-weight: 700; }
.note--revi::before { content: "◆ "; font-weight: 700; }

/* D-806 — **la burbuja del matraz.** Cuando el servidor confirma algo, del
   aviso verde suben tres burbujas y se apagan en menos de un segundo. No
   bloquean nada, no mueven el texto, y con «Reducir movimiento» no existen.
   El marcado (`<i class="burbujas">`) lo pone `base.html` sólo en el aviso de
   éxito. */
.messages .note { position: relative; }
.burbujas, .burbujas::before, .burbujas::after {
  position: absolute; display: block; border-radius: 50%;
  background: var(--c-gamma); opacity: 0; pointer-events: none;
}
.burbujas { left: 12px; bottom: 6px; width: 9px; height: 9px; }
.burbujas::before { content: ""; left: 13px; bottom: 3px; width: 6px; height: 6px; }
.burbujas::after  { content: ""; left: -7px; bottom: 5px; width: 5px; height: 5px; }
@media (prefers-reduced-motion: no-preference) {
  .burbujas         { animation: burbuja .9s ease-out .1s 1 both; }
  .burbujas::before { animation: burbuja .9s ease-out .3s 1 both; }
  .burbujas::after  { animation: burbuja .9s ease-out .45s 1 both; }
}
@keyframes burbuja {
  0%   { transform: translateY(0) scale(1); opacity: .95; }
  100% { transform: translateY(-56px) scale(.5); opacity: 0; }
}

.messages { list-style: none; padding: 0; margin: 0 0 var(--sp-4); }

/* Compatibilidad incremental con las plantillas anteriores a esta pasada.
   `datos` y `cifras` ya expresaban dos patrones estables: pares dato/valor y
   una franja de cifras reconciliables. Se incorporan al sistema común sin
   obligar a reescribir docenas de pantallas ni mantener CSS por módulo. */
.datos {
  display: grid; grid-template-columns: 13rem minmax(0, 1fr);
  gap: 7px var(--sp-4); margin: 0; font-size: var(--fs);
}
.datos dt { color: var(--c-text-2); }
.datos dd { margin: 0; font-weight: 550; min-width: 0; }

.cifras {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.cifras li {
  min-width: 0; padding: 10px 12px;
  border: 1px solid var(--c-border-soft); border-radius: var(--radius);
  background: var(--c-surface-alt); color: var(--c-text-2);
}
.cifras li b { color: var(--c-text); font-variant-numeric: tabular-nums; }

/* Algunas pantallas heredadas ya usaban el título canónico, pero todavía no
   lo envolvían en `panel__head`. Conservarlas es seguro: la tarjeta les da la
   misma cabecera sin duplicar una variante por módulo. */
.panel > .panel__title {
  padding: 13px 18px; border-bottom: 1px solid var(--c-border-soft);
}
.panel > p.help, .panel > p.note { margin: 12px 18px; }
.panel__body > h2 {
  margin: 0 0 var(--sp-3); font-size: var(--fs-md); font-weight: 650;
  color: var(--c-text); letter-spacing: -.01em;
}

/* ------------------------------------------------------------ 11. TABLAS */

.table, .tabla {
  width: 100%; border-collapse: separate; border-spacing: 0;
  /* 13 px: la tabla es compacta por su tarea (D-801). */
  font-size: var(--fs-sm); background: var(--c-surface);
}
.table th, .table td, .tabla th, .tabla td {
  text-align: left; padding: 10px 14px;
  border-bottom: 1px solid var(--c-border-soft);
  vertical-align: top;
}
.table th, .tabla th {
  background: var(--c-surface-alt);
  font-size: var(--fs-xs); font-weight: 650;
  text-transform: uppercase; letter-spacing: .06em; color: var(--c-text-2);
  /* **El encabezado se parte en dos líneas antes que cortarse** — D-707.
     Con `nowrap`, en `Inventario → Existencias` se leía «COMPROMETI…» y
     «BLOQUEAD…»: la tabla tiene nueve columnas y la cabecera no cabía. Un
     rótulo cortado no se puede leer, y dos líneas de cabecera cuestan una vez
     por tabla. Las celdas de datos **no cambian**: lo que no se debe partir
     sigue declarándolo `.nowrap` o `.mid`, columna por columna. */
  white-space: normal; overflow-wrap: break-word;
  border-bottom: 1px solid var(--c-border);
}
.table thead th, .tabla thead th { position: sticky; top: var(--topbar-h); z-index: 1; }
/* Dentro de una tarjeta la cabecera se pega **al borde de la tarjeta**, no bajo
   la barra superior: la tarjeta ya está debajo de ella.

   El selector es de DESCENDENCIA a propósito. Con `>` sólo acertaba a la tabla
   que colgaba directamente de la tarjeta, así que una tabla dentro de un
   `<form>` o de un `<details>` —once plantillas del proyecto— se quedaba con
   `top: var(--topbar-h)` y su cabecera flotaba 43 px hacia abajo, **encima de
   la primera fila**. Se veía como encabezados cortados y contenido superpuesto
   en la parte de arriba de la tabla. Se corrige aquí, una vez, y no plantilla
   por plantilla (mismo criterio que D-424). */
:is(.panel, .panel__body, .tablewrap) :is(.table, .tabla) thead th { top: 0; }

/* La tarjeta ya no recorta —recortar rompería la cabecera fija—, así que las
   esquinas superiores las redondea la propia cabecera de la tabla. */
.panel > .table:first-child thead tr:first-child th:first-child,
.panel > .tabla:first-child thead tr:first-child th:first-child { border-top-left-radius: var(--radius-lg); }
.panel > .table:first-child thead tr:first-child th:last-child,
.panel > .tabla:first-child thead tr:first-child th:last-child { border-top-right-radius: var(--radius-lg); }
.panel > .table:last-child tbody tr:last-child td:first-child,
.panel > .tabla:last-child tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius-lg); }
.panel > .table:last-child tbody tr:last-child td:last-child,
.panel > .tabla:last-child tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius-lg); }
.table tbody tr:hover, .tabla tbody tr:hover { background: var(--c-surface-alt); }
.table tbody tr:last-child td, .tabla tbody tr:last-child td { border-bottom: 0; }
.table tfoot td, .tabla tfoot td {
  background: var(--c-surface-alt); font-weight: 650;
  border-top: 1px solid var(--c-border); border-bottom: 0;
}

/* Una columna de cifras va **CENTRADA** y tabular — regla transversal de la
   pasada final de aceptación funcional (§F1).

   Hasta esta pasada `.num` alineaba a la derecha, con el argumento contable de
   que una columna de importes se compara unidad contra unidad. Agustín revisó
   las tablas completas del sistema y decidió lo contrario, **a sabiendas de esa
   convención previa**: en PQG un campo compacto —folio, fecha, estado,
   cantidad, kg, conteo, importe— se centra bajo su encabezado, y sólo el campo
   descriptivo largo —Material, Cliente, Proveedor, descripción, notas— queda a
   la izquierda. El motivo es el que se ve en pantalla: con columnas anchas y
   contenidos cortos, unos datos pegados al borde derecho y otros al izquierdo
   hacían que los valores «bailaran» de una columna a otra.

   `tabular-nums` se conserva: aunque ya no se comparen por el borde derecho,
   los dígitos siguen ocupando el mismo ancho y la columna se lee pareja.

   `.mid` sigue existiendo y **no queda duplicado**: añade `nowrap` para el dato
   que además no se debe partir nunca (un folio), que es una garantía distinta
   del centrado. */
.table .num, .tabla .num { text-align: center; font-variant-numeric: tabular-nums; }

/* El vencimiento no estira la tabla — 2026-09-29. «Sin vencimiento calculable»
   es una frase, no una fecha: en una sola línea pedía 300 px de columna y
   empujaba la tabla a apilarse. Se deja envolver en dos renglones. */
.table--tarjetas td[data-rotulo="Vencimiento"] { max-width: 15ch; white-space: normal; }

.table .nowrap, .tabla .nowrap { white-space: nowrap; }
/* 2026-10-06 (D-802) — el folio como CONTEXTO: en las listas que se leen por
   Cliente o Proveedor, el número va en chico y en gris, y su enlace no compite
   con el del nombre, que es el principal. */
.table td.folio, .tabla td.folio { font-size: var(--fs-sm); color: var(--c-text-2); }
.table td.folio a, .tabla td.folio a {
  color: inherit; text-decoration: underline; text-decoration-color: var(--c-border-strong);
}
.table td.folio a:hover, .tabla td.folio a:hover { color: var(--c-accent-dark); text-decoration-color: currentColor; }
.table .state, .tabla .state { text-align: center; }
.table .actions, .tabla .actions { width: 1%; white-space: nowrap; text-align: right; }

/* `.mid` — **dato CORTO y centrado**, encargo del *Functional refinement 8*.
   Es para lo que se lee de un vistazo y **no se compara por magnitud**: un
   folio, una fecha, un conteo pequeño, una etiqueta breve. En una columna más
   ancha que su contenido, ese dato pegado al borde izquierdo es lo que hacía
   que la tabla se viera «desordenada» — no estaba mal alineado, estaba lejos
   de su encabezado.

   **No sustituye a `.num`, y la diferencia sigue importando** aunque desde la
   pasada final ambas centren: `.mid` añade `white-space: nowrap`, la garantía
   de que ese dato **no se parte nunca en dos líneas**. Un importe puede
   ajustarse; un folio no. _(Hasta la pasada final este párrafo decía que la
   diferencia era la alineación —`.num` a la derecha—; **dejó de aplicar** con
   §F1, que centró también las cifras.)_

   Lleva `white-space: nowrap` porque su razón de ser es **caber en una línea**:
   `OC-000007` partido en `OC-` / `000007` estiraba la fila entera a 60 px. */
.table .mid, .tabla .mid {
  text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* Con anchos declarados, `nowrap` no puede imponer un mínimo mayor que el
   porcentaje de su `<col>`: si el dato no cupiera, se recorta con puntos
   suspensivos en vez de sacar la tabla de la pantalla. */
.table--fixed td.mid, .table--fixed th.mid {
  overflow: hidden; text-overflow: ellipsis; word-break: keep-all;
}
.cell-clip {
  display: block; max-width: 24rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.sort-link {
  display: inline-flex; align-items: center; gap: 5px;
  color: inherit; text-decoration: none;
}
.sort-link:hover, .sort-link:focus-visible { color: var(--c-accent-dark); }
.sort-link__arrow { color: var(--c-text-3); font-size: .9em; }
.sort-link--active .sort-link__arrow { color: var(--c-accent); }

/* Acciones dentro de una celda: compactas, y cada una con su propio `form`. */
/* Las acciones de un requisito del checklist: **apiladas, no en una línea**.

   `.actions` fuerza `nowrap`, y aquí conviven hasta tres controles —abrir el
   documento, marcarlo listo y, al retirarlo, su motivo—: en una sola línea la
   columna crecía hasta desbordar la tarjeta y los botones quedaban fuera de la
   vista. Apiladas caben, y el motivo deja de empujar. */
/* Cambiar la modalidad de entrega: el motivo y el botón en una línea, dentro
   de la lista de datos del Pedido. */
.modechange { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0 0; }
.modechange input[type="text"] { max-width: 18rem; }

.checkactions { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; }
.checkactions form { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin: 0; }
.checkactions input[type="text"] { max-width: 13rem; }

/* Quitar / restaurar una fila de un borrador, SIN JavaScript.

   Es una casilla y dos etiquetas: la casilla nace marcada —la Línea entra—, la
   etiqueta visible dice `Quitar`, y al desmarcarla el par se invierte y la fila
   se pinta retirada. Todo el estado vive en el propio formulario, así que
   recargar, volver atrás o navegar con el teclado se comportan como el Usuario
   espera y el `POST` sigue siendo el mismo de siempre. */
.rowdrop { display: inline-flex; }
.rowdrop > input {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  margin: 0; pointer-events: none;
}
.rowdrop > label {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; min-height: 26px; cursor: pointer;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-text-2);
  font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
}
.rowdrop > label:hover { border-color: var(--s-bloq-fg); color: var(--s-bloq-fg); }
.rowdrop > .rowdrop__in { display: none; }
.rowdrop > input:not(:checked) ~ .rowdrop__out { display: none; }
.rowdrop > input:not(:checked) ~ .rowdrop__in { display: inline-flex; }
.rowdrop > input:not(:checked) ~ .rowdrop__in:hover {
  border-color: var(--c-accent); color: var(--c-accent-dark);
}
/* El anillo de foco lo lleva la etiqueta, porque la casilla no se ve. */
.rowdrop > input:focus-visible ~ label { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* La fila retirada **se sigue viendo** —no desaparece— pero deja de parecer
   parte de la Cotización, y su precio deja de pedir atención. */
tr.quotable:has(.rowdrop > input:not(:checked)) { color: var(--c-text-3); }
tr.quotable:has(.rowdrop > input:not(:checked)) th[scope="row"] { text-decoration: line-through; }
tr.quotable:has(.rowdrop > input:not(:checked)) .quotable__price { opacity: .45; }

.table td form, .tabla td form { display: inline-block; margin: 0 4px 0 0; }
.table td .btn, .tabla td .btn { padding: 3px 9px; min-height: 26px; font-size: var(--fs-sm); }

/* Fila desplegable: el detalle vive DENTRO de la fila, no en otra pantalla. */
.table tr.row--sub td, .tabla tr.row--sub td {
  background: var(--c-surface-alt); padding-top: 6px; padding-bottom: 10px;
}
.table tr.row--sub:hover, .tabla tr.row--sub:hover { background: var(--c-surface-alt); }

/* Tabla dentro de una tarjeta a sangre: las esquinas las pone la tarjeta. */
.panel__body--flush .table th:first-child,
.panel__body--flush .tabla th:first-child { padding-left: 18px; }
.panel__body--flush .table td:first-child,
.panel__body--flush .tabla td:first-child { padding-left: 18px; }
.panel__body--flush .table th:last-child,
.panel__body--flush .tabla th:last-child { padding-right: 18px; }
.panel__body--flush .table td:last-child,
.panel__body--flush .tabla td:last-child { padding-right: 18px; }

.tablewrap {
  width: 100%; max-width: 100%; min-width: 0;
  overflow-x: auto; border-radius: var(--radius-lg);
  overscroll-behavior-inline: contain;
  /* 2026-09-21 · D-687 — **la tabla responde a SU columna, no a la ventana.**
     El modo tarjeta de D-667 se disparaba con `@media (max-width: 820px)`, es
     decir con el ancho de la VENTANA. En cuanto la lista comparte el ancho con
     el panel de la ficha, la ventana sigue midiendo 1440 px y la tabla mide
     530: con la media query, doce columnas se metían a empujones en media
     pantalla. Declarando aquí el contenedor, la misma regla —una sola, no dos—
     se dispara por el ancho real de la tabla, y el teléfono entra por el mismo
     camino que antes porque ahí la columna ES la ventana. */
  container-type: inline-size;
  container-name: tabla;
}

/* Anchos DECLARADOS por la tabla, no negociados por el contenido — corrección
   de aceptación del *Functional refinement 6* (§1 de la pasada de corrección).

   El problema medido en el navegador, no deducido de las clases: en Existencias
   a 1440 px la tabla pedía **1257 px** para 1034 disponibles, así que `Bloqueado`
   y `Lotes` quedaban fuera de la pantalla; y como cada columna se dimensionaba
   por su contenido, un nombre de Material largo movía TODAS las demás — los
   valores «bailaban» de una fila a otra y de una página a otra.

   `table-layout: fixed` con un `<colgroup>` resuelve las dos cosas de raíz: los
   anchos los fija la plantilla una vez, el encabezado queda **exactamente**
   sobre su dato y ninguna fila puede reacomodar la rejilla. El texto largo se
   recorta con `.cell-clip`, que ya conserva el valor completo en su `title`. */
.table--fixed { table-layout: fixed; }
/* Con anchos fijos, una celda textual larga tiene que poder partirse en vez de
   ensanchar su columna: `overflow-wrap` es lo que impide que un código sin
   espacios desborde la celda y empuje el borde. */
.table--fixed td { overflow-wrap: anywhere; }
.table--fixed td.num, .table--fixed th.num { overflow-wrap: normal; }
/* `.table th` es `nowrap`, y con anchos fijos eso IMPONE un mínimo mayor que el
   porcentaje declarado: era lo que seguía sacando la tabla del contenedor
   después de fijar la rejilla. En una tabla de anchos declarados el encabezado
   **puede** partirse en dos líneas —los títulos son cortos— y a cambio la
   rejilla cabe entera sin desplazamiento horizontal. */
.table--fixed th { white-space: normal; letter-spacing: .02em; }
/* Una celda de anchos fijos parte las palabras largas para no desbordar, pero
   hay valores que **no se deben partir jamás**: un importe con su moneda y una
   situación de una sola palabra. `Provision\nal` y `USD\n$1.05` eran ilegibles
   y falseaban el dato al leerlo de un vistazo. */
.table--fixed td.num, .table--fixed .nobreak { overflow-wrap: normal; word-break: keep-all; }

/* Subtabla dentro de una fila desplegable. **No es la misma rejilla que la de
   arriba y no debe fingir que lo es**: antes heredaba `.table` completa —mismo
   tamaño, mismo encabezado pegajoso, columnas propias— y el resultado eran dos
   rejillas distintas apiladas cuyos bordes no coincidían, que es justo lo que
   se leía como «desalineado». Aquí se declara como lo que es: un detalle,
   sangrado, más compacto y con su encabezado quieto. */
.table--sub { font-size: var(--fs-sm); background: var(--c-surface); }
.table--sub th, .table--sub td { padding: 7px 10px; }
.table--sub thead th { position: static; text-transform: none; letter-spacing: 0; }
.table--sub tbody tr:last-child td { border-bottom: 1px solid var(--c-border-soft); }
.subtable {
  margin: 6px 0 10px; padding-left: 14px;
  border-left: 2px solid var(--c-border);
}
.subtable + .subtable { margin-top: 10px; }
.subtable__head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 5px; font-size: var(--fs-sm);
}
.subtable__coa { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }

.paginacion {
  display: flex; gap: var(--sp-3); align-items: center; margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm); color: var(--c-text-2);
}

/* ------------------------------------ 12. PESTAÑAS Y BARRA DE FILTROS */

.tabs {
  display: flex; gap: 3px; flex-wrap: wrap; margin: 0 0 var(--sp-4);
  border-bottom: 1px solid var(--c-border);
}
.tabs a {
  padding: 9px 15px; text-decoration: none; color: var(--c-text-2);
  border-bottom: 2px solid transparent; font-size: var(--fs); font-weight: 550;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  display: inline-flex; align-items: center; gap: 7px;
  margin-bottom: -1px;
}
.tabs a:hover { color: var(--c-text); background: var(--c-surface-alt); }
.tabs a[aria-current="page"], .tabs a.tabs__active {
  color: var(--c-accent-dark); border-bottom-color: var(--c-accent); font-weight: 650;
  background: transparent;
}
.tabs .tabs__count {
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-2);
  background: var(--c-surface-sunk); border-radius: var(--radius-pill);
  padding: 1px 7px; margin-left: 2px;
}
.tabs a[aria-current="page"] .tabs__count { background: var(--c-accent-soft); color: var(--c-accent-dark); }

/* 2026-09-25 — **qué trae la cola abierta, debajo de las pestañas.** Una línea
   gris y corta: si fuera un `note` con su franja de color competiría con la
   lista, y esto no es un aviso — es el pie de la pestaña. Se ancla al margen
   que la barra de pestañas ya reservaba, para no añadir un renglón más. */
.tabs__nota {
  margin: calc(var(--sp-4) * -1 + 6px) 0 var(--sp-4);
  font-size: var(--fs-sm); color: var(--c-text-3); max-width: 86ch;
}

/* Barra de filtros: una tarjeta clara, no un montón de campos sueltos.
   `.buscador` es la misma pieza y se define justo debajo; `.filters` existe
   para el caso en el que la barra NO lleva buscador. */
.filters {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
  padding: 12px 16px; margin: 0 0 var(--sp-4);
  display: flex; gap: var(--sp-3); align-items: flex-end; flex-wrap: wrap;
}
.filters .field { margin-bottom: 0; max-width: 18rem; }
.filters__spacer { flex: 1 1 auto; }

/* El buscador es la barra de filtros de PQG y, en un listado de Maestro, la
   acción PRINCIPAL: por eso ocupa una fila propia y no vive plegado. */
.buscador {
  /* `flex-end` y no `center`: con la etiqueta encima del campo, centrar dejaba
     el botón `Buscar` a media altura del bloque y visiblemente por encima de
     la caja de búsqueda. Alineados por abajo, botón y caja comparten línea. */
  display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
  padding: 12px 16px; margin-bottom: var(--sp-4);
}
.buscador .field { margin-bottom: 0; }
.buscador label:not(.buscador__check) {
  font-size: var(--fs-sm); color: var(--c-text-2); white-space: nowrap;
}
/* El campo de búsqueda es el protagonista de la barra: manda el ancho. */
.buscador input[type=search], .buscador input[type=text] { flex: 1 1 17rem; min-width: 13rem; }
.buscador select { min-width: 10rem; }
.buscador__check {
  display: flex; gap: 6px; align-items: center; font-size: var(--fs-sm);
  white-space: nowrap; padding-bottom: 0;
}
/* Dentro de una tarjeta, la barra no dibuja una segunda tarjeta. */
.panel__body > .buscador,
.panel__body .buscador {
  border: 0; box-shadow: none; padding: 0; margin-bottom: 0; background: transparent;
}

/* ------------------------------------------------------- 13. FORMULARIOS */

/* Un control se estiliza por SER un control, no por estar dentro de `.field`.
   Así desaparece de toda PQG la caja gris del navegador, incluidas las barras
   de filtro que no envuelven cada campo en su etiqueta. */
input[type=text], input[type=search], input[type=email], input[type=password],
input[type=number], input[type=date], input[type=datetime-local], input[type=month],
input[type=time], input[type=url], input[type=tel], input[type=file],
select, textarea {
  padding: 8px 11px; min-height: 36px;
  border: 1px solid var(--c-border-strong); border-radius: var(--radius-sm);
  font: inherit; color: var(--c-text); background: #fff;
  transition: border-color .12s ease, box-shadow .12s ease;
  max-width: 100%;
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
  border-color: var(--c-text-3);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-soft); outline: none;
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--c-surface-sunk); color: var(--c-text-3); cursor: not-allowed;
}
input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-color: var(--c-accent); }
select {
  appearance: none;
  padding-right: 30px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--c-text-3) 50%),
    linear-gradient(135deg, var(--c-text-3) 50%, transparent 50%);
  background-position: calc(100% - 16px) calc(50% + 1px), calc(100% - 11px) calc(50% + 1px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
select[multiple], select[size] { appearance: auto; background-image: none; padding-right: 11px; }

/* Un `<button>` sin clase sigue siendo un botón de PQG, no del navegador. */
button:not([class]) {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 14px; min-height: 34px;
  border-radius: var(--radius-sm); border: 1px solid var(--c-border-strong);
  background: var(--c-surface); color: var(--c-text);
  font: inherit; font-weight: 550; cursor: pointer; box-shadow: var(--shadow-xs);
}
button:not([class]):hover { background: var(--c-surface-alt); border-color: var(--c-text-3); }

.field { margin-bottom: var(--sp-3); max-width: 46rem; }
.field label {
  display: block; font-weight: 600; font-size: var(--fs-sm);
  margin-bottom: 4px; color: var(--c-text);
}
.field input[type=text], .field input[type=search], .field input[type=email],
.field input[type=password], .field input[type=number], .field input[type=date],
.field input[type=datetime-local], .field input[type=month], .field input[type=time],
.field input[type=url], .field input[type=tel], .field input[type=file],
.field select, .field textarea {
  width: 100%; padding: 8px 11px;
  border: 1px solid var(--c-border-strong); border-radius: var(--radius-sm);
  font: inherit; background: #fff; color: var(--c-text);
  min-height: 36px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--c-text-3); }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-soft); outline: none;
}
.field .help { color: var(--c-text-3); font-size: var(--fs-sm); margin-top: 4px; }
.errorlist { color: var(--s-bloq-fg); font-size: var(--fs-sm); margin: 4px 0; padding-left: 18px; }
.field .errorlist { list-style: none; padding-left: 0; margin: 5px 0 0; font-weight: 550; }
.field .errorlist li::before { content: "⚠ "; }
.field--error input, .field--error select, .field--error textarea {
  border-color: var(--s-bloq-fg); background: #fffafa;
}

label { cursor: pointer; }

/* Formulario en tarjeta, con sus secciones. */
.form-card {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 20px; margin-bottom: var(--sp-4); max-width: 62rem;
}
.form-card h3, .panel__body h3 {
  font-size: var(--fs-xs); margin: var(--sp-5) 0 var(--sp-2);
  text-transform: uppercase; letter-spacing: .07em; color: var(--c-text-3);
  font-weight: 650;
  padding-bottom: 5px; border-bottom: 1px solid var(--c-border-soft);
}
.form-card h3:first-child, .panel__body h3:first-child { margin-top: 0; }
.form-row { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.form-row .field { flex: 1 1 15rem; max-width: none; }
.form-card > form > p,
.panel__body > form:not(.buscador) > p {
  max-width: 46rem; margin: 0 0 var(--sp-3);
}
.form-card > form > p > label,
.panel__body > form:not(.buscador) > p > label {
  display: block; margin-bottom: 4px; color: var(--c-text);
  font-size: var(--fs-sm); font-weight: 600;
}
/* **La casilla y el radio quedan FUERA, y no es un detalle.** `:is()` toma la
   especificidad de su argumento más específico, así que este selector —(0,1,4)—
   le gana a `input[type=checkbox] { width: 16px }` de más arriba —(0,1,1)—: sin
   la exclusión, toda casilla dentro de un formulario `as_p` se estiraba al
   ancho del contenedor y quedaba como una barra de 16 px de alto. Se vio en el
   paso de teléfono de PQG Dirección, que copia esta hoja tal cual, pero el
   defecto nace aquí y afecta a todo formulario de PQG con una casilla. */
.form-card > form > p > :is(input, select, textarea):not([type="checkbox"], [type="radio"]),
.panel__body > form:not(.buscador) > p > :is(input, select, textarea):not([type="checkbox"], [type="radio"]) {
  width: 100%;
}
.helptext {
  display: block; margin-top: 4px; color: var(--c-text-3);
  font-size: var(--fs-sm);
}
.form-card__foot {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--c-border-soft);
  display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center;
}

/* Bloques de un documento formato Gamma (D-589): la pantalla se arma con
   piezas que se agregan y se mueven, así que cada una necesita verse como una
   pieza —separada de la siguiente— y llevar sus dos botones de orden al lado,
   no debajo del formulario entero. */
.bloque {
  padding-top: var(--sp-3); margin-bottom: var(--sp-3);
  border-top: 1px dashed var(--c-border-soft);
  display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: flex-start;
}
.bloque:first-of-type { border-top: 0; padding-top: 0; }
.bloque .field { flex: 1 1 15rem; margin-bottom: 0; }
.bloque__mover {
  flex: 0 0 auto; display: flex; gap: 4px; align-self: center; margin: 0;
}

/* Pantalla de acceso: centrada, sin barra lateral. */
.acceso { max-width: 27rem; margin: 8vh auto 0; }
.acceso .panel { box-shadow: var(--shadow-md); }
.acceso__brand {
  display: flex; align-items: center; gap: 11px; justify-content: center;
  margin-bottom: var(--sp-5); font-size: var(--fs-xl); font-weight: 680;
  letter-spacing: -.02em;
}
.acceso__brand .nav__logo { width: 36px; height: 36px; flex-basis: 36px; border-radius: 10px; }
.acceso__brand .nav__logo .ic { width: 20px; height: 20px; }

/* Segundo factor (D-553): el QR del alta y la tanda de códigos de
   recuperación, que se muestra UNA vez y se copia a mano o se imprime. */
.qr {
  display: flex; justify-content: center; padding: var(--sp-4) 0;
}
.qr svg { background: #fff; border-radius: var(--radius); padding: 8px; }
.codigos {
  list-style: none; margin: 0 0 var(--sp-4); padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--sp-2);
}
.codigos code { font-size: var(--fs-md); letter-spacing: .08em; }

/* ---------------------- 14. PROGRESO, COMPROBACIÓN Y LISTAS COMPACTAS */

.meter {
  height: 8px; border-radius: var(--radius-pill); background: var(--c-surface-sunk);
  overflow: hidden; min-width: 6rem;
}
.meter__fill { height: 100%; background: var(--c-accent); border-radius: var(--radius-pill); }
.meter--ok   .meter__fill { background: var(--c-franja-ok); }
.meter--aten { background: #f7ecd4; }
.meter--aten .meter__fill { background: var(--c-franja-aten); }
.meter--bloq { background: #f7dcda; }
.meter--bloq .meter__fill { background: var(--s-bloq-fg); }
.meter--lg { height: 10px; }
/* La barra de avance NO puede pisar la columna siguiente — corrección de
   aceptación del *Functional refinement 6*.

   Medido en el navegador a 1440 px, no deducido: `.meter` lleva un piso de
   `min-width: 6rem` (96 px) y la cifra `0 / 3,000` va en `nowrap` (52 px), así
   que con el hueco de 10 px la fila pedía **158 px dentro de una celda de 122**.
   Como `.meter-row` es un flex sin `min-width: 0`, los 36 px sobrantes no se
   repartían: se salían de la celda. La cifra terminaba 22 px fuera de su `td` y
   **8 px encima del primer punto del checklist** — el checklist no se encimaba
   solo, se lo encimaba la columna de al lado.

   El reparto correcto es el que respeta qué es dato y qué es adorno: **la cifra
   conserva su ancho** —es el dato— y **la barra se encoge**, porque el piso de
   `6rem` existe para una barra suelta, no para una que comparte una celda de
   ancho declarado. Si aun así no cabe, la cifra **baja a un segundo renglón**
   en vez de salirse: envolver es legible, desbordar es encimar. */
.meter-row { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
.meter-row .meter { flex: 1 1 auto; min-width: 2.5rem; }
.meter-row .meter-row__label {
  font-size: var(--fs-sm); color: var(--c-text-2); white-space: nowrap;
  font-variant-numeric: tabular-nums; flex: 0 0 auto;
}

/* Leyenda de tramos: el color se explica con palabras, siempre. */
.legend { display: flex; gap: var(--sp-4); flex-wrap: wrap; font-size: var(--fs-sm);
  color: var(--c-text-2); margin-top: var(--sp-2); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.legend .legend--ok i   { background: var(--c-franja-ok); }
.legend .legend--aten i { background: var(--c-franja-aten); }
.legend .legend--bloq i { background: var(--s-bloq-fg); }
.legend .legend--acc i  { background: var(--c-accent); }

.check { list-style: none; margin: 0; padding: 0; font-size: var(--fs); }
.check li { padding: 4px 0 4px 24px; position: relative; }
.check li::before { position: absolute; left: 0; font-weight: 700; }
.check li.check--si::before { content: "✓"; color: var(--s-ok-fg); }
.check li.check--no::before { content: "○"; color: var(--c-text-3); font-weight: 500; }
.check li.check--no { color: var(--c-text-2); }
.check li.check--na::before { content: "—"; color: var(--c-text-3); font-weight: 500; }

/* Checklist COMPACTO: un punto por requisito (Functional refinement 6 §B10.3).
   El checklist en renglones hacía ilegible una tabla de veinte Líneas. Cada
   estado tiene FORMA además de color —relleno, hueco, aspa, anillo— porque el
   color no puede ser el único portador del significado; el nombre completo va
   en el `title` de cada punto y en su texto para lector de pantalla. */
.dots { display: inline-flex; gap: 5px; align-items: center; flex-wrap: wrap; }
.dot {
  width: 12px; height: 12px; border-radius: 50%; display: inline-block;
  position: relative; cursor: default;
  border: 1.5px solid var(--c-text-3); background: transparent;
}
.dot:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* El globo del punto — corrección de aceptación §3.
   Con sólo `title` y `cursor: help`, lo que el Usuario veía al pasar por encima
   era **el signo `?` del cursor**, y el texto del navegador tardaba uno o dos
   segundos en aparecer. El globo lo dibuja la página: sale **al instante**, con
   el ratón y con el teclado, y dice el requisito y su estado. El `title` se
   conserva como respaldo, y `cursor: help` se retira porque ese `?` era el
   defecto que había que corregir. Mismo mecanismo que `.chart__tip`. */
.dot__tip {
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text);
  white-space: nowrap; text-transform: none; letter-spacing: 0;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  padding: 3px 8px; z-index: 5;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .08s ease;
}
.dot:hover .dot__tip, .dot:focus-visible .dot__tip { opacity: 1; visibility: visible; }
/* El globo del primer y del último punto no puede salirse de la celda. */
.dots .dot:first-child .dot__tip { left: 0; transform: none; }
.dots .dot:last-child .dot__tip { left: auto; right: 0; transform: none; }
.dot--ok     { background: var(--s-ok-fg);   border-color: var(--s-ok-fg); }
.dot--pend   { background: transparent;      border-color: var(--c-text-3); }
.dot--previa { background: var(--s-revi-bg); border-color: var(--s-revi-fg); box-shadow: inset 0 0 0 2px var(--c-surface); }
.dot--falta  { background: var(--s-bloq-bg); border-color: var(--s-bloq-fg); }
.dot--falta::before,
.dot--falta::after {
  content: ""; position: absolute; left: 1px; top: 4px;
  width: 7px; height: 1.5px; background: var(--s-bloq-fg);
}
.dot--falta::before { transform: rotate(45deg); }
.dot--falta::after  { transform: rotate(-45deg); }
.dots__sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Lista compacta dentro de un panel (entregas de hoy, riesgos, alertas). */
.rows { list-style: none; margin: 0; padding: 0; font-size: var(--fs); }
.rows li {
  display: flex; gap: 10px; align-items: center; padding: 8px 0;
  border-bottom: 1px solid var(--c-border-soft); flex-wrap: wrap;
}
.rows li:first-child { padding-top: 0; }
.rows li:last-child { border-bottom: 0; padding-bottom: 0; }
.rows .rows__main { flex: 1 1 12rem; min-width: 0; }
.rows .rows__num {
  font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 650;
}
.rows a { text-decoration: none; font-weight: 550; }
.rows a:hover { text-decoration: underline; }

/* Fila de urgencia: icono + cifra grande + etiqueta. El bloque «Lo urgente
   hoy» del Dashboard y cualquier bandeja con prioridad visual. */
.urgent {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}
.urgent__item {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid var(--c-border); background: var(--c-surface);
  text-decoration: none; color: inherit;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.urgent__item .icobox { flex: 0 0 auto; }
.urgent__body { display: flex; flex-direction: column; }
.urgent__item:hover { border-color: var(--c-accent-line); box-shadow: var(--shadow-sm); color: inherit; }
.urgent__body { min-width: 0; }
.urgent__value {
  display: block; font-size: var(--fs-xl); font-weight: 680; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.urgent__label { display: block; font-size: var(--fs-sm); color: var(--c-text-2); }
.urgent__note {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; font-size: var(--fs-xs); font-weight: 600; margin-top: auto;
  padding-top: 3px;
}
.urgent__note--aten { color: var(--s-aten-fg); }
.urgent__note--bloq { color: var(--s-bloq-fg); }
.urgent__note--ok   { color: var(--s-ok-fg); }

/* --------------------------------------------------------- 15. GRÁFICAS */

/* Gráfica de columnas en CSS puro: sin librerías y sin CDN. UNA serie = un
   matiz y sin leyenda; el título de la tarjeta dice qué se grafica. El valor
   se rotula SELECTIVAMENTE (último punto / máximo); el resto vive en el
   `title` y en la tabla accesible que acompaña a toda gráfica. */

.chart { margin: 4px 0 0; }
.chart__cols {
  display: flex; align-items: flex-end; gap: 10px; height: 132px;
  border-bottom: 1px solid var(--c-border); padding: 20px 4px 0;
}
.chart__col {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center;
  justify-content: flex-end; height: 100%; min-width: 0; position: relative;
}
.chart__bar {
  width: 100%; max-width: 26px; min-height: 2px;
  background: var(--c-accent); border-radius: 5px 5px 0 0;
  transition: background .12s ease;
}
.chart__col:hover .chart__bar { background: var(--c-accent-dark); }
.chart__col--off .chart__bar { background: var(--c-border-strong); }
.chart__col--neg .chart__bar { background: var(--s-bloq-fg); }
.chart__val {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-2);
  white-space: nowrap; font-variant-numeric: tabular-nums;
  background: var(--c-surface); padding: 0 2px;
  z-index: 1;
}
/* --- El valor, al pasar por encima o al enfocar (*refinement 6* §B1.6) ----
   Antes se escribían dos valores permanentes sobre las barras —el máximo y el
   último— y en columnas contiguas se encimaban entre sí y sobre la gráfica.
   Ahora el valor vive en un globo que aparece **sólo** al señalar la columna,
   con ratón o con teclado.

   `pointer-events: none` evita que el globo se interponga entre el cursor y la
   barra, que produciría un parpadeo; `visibility` acompaña a `opacity` para
   que el globo no sea alcanzable mientras está oculto. Ningún dato depende de
   esto: el `title` nativo y la tabla `Ver tabla` siguen ahí. */
.chart__tip {
  position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 600; color: var(--c-text);
  white-space: nowrap; font-variant-numeric: tabular-nums;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  padding: 2px 7px; z-index: 3;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .1s ease;
}
.chart__col:hover .chart__tip,
.chart__col:focus-visible .chart__tip { opacity: 1; visibility: visible; }
.chart__col:focus-visible { outline: 2px solid var(--c-accent-line); outline-offset: 2px; }
/* El globo del primer y del último mes no puede salirse del panel. */
.chart__col:first-child .chart__tip { left: 0; transform: none; }
.chart__col:last-child .chart__tip { left: auto; right: 0; transform: none; }

.chart__col:nth-child(even) .chart__val { top: 20px; }
.chart__col:first-child .chart__val { left: 0; transform: none; }
.chart__col:last-child .chart__val { left: auto; right: 0; transform: none; }

/* Rótulos del eje — encargo §9 del *Functional refinement 3*.

   Antes se escalonaban en vertical (`translateY`) para que cupieran doce meses.
   El resultado era justo lo que el encargo manda corregir: rótulos encimados y
   una línea base que no existe. Ahora **no se escalona ninguno**; lo que se
   reduce, y sólo cuando hace falta, es la DENSIDAD.

   **Ningún valor se pierde al ocultar un rótulo**: cada columna lleva su
   `title` con mes e importe, y la gráfica trae siempre su tabla `Ver tabla`
   completa. Reducir densidad es una decisión de presentación, no de datos. */
.chart__labels { display: flex; gap: 10px; padding: 8px 4px 0; }
.chart__labels span {
  flex: 1 1 0; text-align: center; font-size: var(--fs-xs); color: var(--c-text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chart details { margin-top: 14px; }

/* En panel angosto —dos o tres gráficas por fila, o móvil— doce rótulos no
   caben legibles. Se muestra uno de cada dos: la serie sigue completa, los
   valores siguen en el `title` de cada columna y en la tabla desplegable. */
@media (max-width: 1200px) {
  .chart__labels span:nth-child(even) { visibility: hidden; }
}
/* --- Barras AGRUPADAS: varias series dentro de cada columna ---------------
   `Progreso de comisiones` (*refinement 6* §B3.4). Un mes = una columna;
   dentro, una barra por Vendedor. Reutiliza `.chart`, `.chart__cols`,
   `.chart__labels`, `.chart__tip` y `details > Ver tabla` — lo único propio es
   cómo se reparte el ancho de la columna entre las series.

   **Ninguna serie se oculta para que quepan las demás**: cuando hay tantas que
   las barras se aplastarían, la columna crece (su `min-width` lo fija la vista
   según cuántas series haya) y la gráfica se desplaza en horizontal. Ocultar
   una serie habría hecho que la gráfica dejara de reconciliar con la tabla. */
/* `overflow-x: auto` obliga al eje vertical a dejar de ser `visible` —lo dice
   la especificación—, así que el globo del valor, que vive ENCIMA de la barra,
   quedaría recortado por el propio contenedor que hace posible el desplazamiento
   horizontal. Se resuelve dándole sitio DENTRO de la caja: el `padding` superior
   de las columnas reserva la altura del globo, y así no hay nada que recortar. */
.chart__scroll { overflow-x: auto; }
.chart--grouped .chart__cols { gap: 8px; height: 178px; padding-top: 30px; }
.chart--grouped .chart__labels { gap: 8px; }
.chart--grouped .chart__labels span { flex: 1 1 auto; }
.chart__col--group { flex: 1 1 auto; }
.chart__group {
  display: flex; align-items: flex-end; justify-content: center;
  gap: 3px; width: 100%; height: 100%;
}
.chart__seg {
  flex: 1 1 0; max-width: 18px; min-height: 2px;
  border-radius: 4px 4px 0 0; position: relative;
  background: var(--c-serie-0);
  transition: filter .12s ease;
}
.chart__seg:hover { filter: brightness(.82); }
.chart__seg:focus-visible { outline: 2px solid var(--c-accent-line); outline-offset: 2px; }
.chart__seg:hover .chart__tip,
.chart__seg:focus-visible .chart__tip { opacity: 1; visibility: visible; }
/* Una comisión vigente NEGATIVA existe —un Ajuste puede restar más que la base—
   y se declara con trama, no sólo con color: el matiz ya está ocupado
   identificando al Vendedor. */
.chart__seg--neg {
  background-image: repeating-linear-gradient(45deg,
    rgba(255,255,255,.55) 0 3px, transparent 3px 6px);
}
/* La columna agrupada NO se apaga en gris: el gris borraría los matices que
   distinguen a los Vendedores. El mes consultado se marca en la tabla. */
.chart--grouped .chart__col--off .chart__seg { opacity: .78; }

.serie { background: var(--c-serie-0); }
.serie--0 { background: var(--c-serie-0); }
.serie--1 { background: var(--c-serie-1); }
.serie--2 { background: var(--c-serie-2); }
.serie--3 { background: var(--c-serie-3); }
.serie--4 { background: var(--c-serie-4); }
.serie--5 { background: var(--c-serie-5); }
.serie--6 { background: var(--c-serie-6); }
.serie--7 { background: var(--c-serie-7); }
.legend i.serie { width: 9px; height: 9px; border-radius: 50%; }

.chart__zero { text-align: center; color: var(--c-text-3); font-size: var(--fs-sm); padding: 24px 0; }
.chart details { margin-top: var(--sp-2); }
.chart details summary { font-size: var(--fs-sm); color: var(--c-text-2); }

/* Barras horizontales — antigüedad de saldo, reparto por categoría. */
.hbars { display: flex; flex-direction: column; gap: 9px; }
.hbar { display: grid; grid-template-columns: 8.5rem 1fr auto; gap: 10px; align-items: center; }
.hbar__label { font-size: var(--fs-sm); color: var(--c-text-2); }
.hbar__track { height: 10px; background: var(--c-surface-sunk); border-radius: var(--radius-pill); overflow: hidden; }
.hbar__fill { height: 100%; background: var(--c-accent); border-radius: var(--radius-pill); }
.hbar__value { font-size: var(--fs-sm); font-weight: 650; font-variant-numeric: tabular-nums; }
.hbar--ok   .hbar__fill { background: var(--s-ok-fg); }
.hbar--aten .hbar__fill { background: var(--c-franja-aten); }
.hbar--bloq .hbar__fill { background: var(--s-bloq-fg); }
.hbar--revi .hbar__fill { background: var(--s-revi-fg); }

/* ------------------------------------------------------- 16. CALENDARIO */

.cal {
  width: 100%; border-collapse: separate; border-spacing: 0; table-layout: fixed;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius-lg); overflow: hidden;
}
.cal th {
  padding: 9px 10px; font-size: var(--fs-xs); font-weight: 650;
  text-transform: uppercase; letter-spacing: .06em; color: var(--c-text-2);
  background: var(--c-surface-alt); border-bottom: 1px solid var(--c-border);
  text-align: left;
}
.cal td {
  vertical-align: top; border-right: 1px solid var(--c-border-soft);
  border-bottom: 1px solid var(--c-border-soft);
  padding: 6px 8px; height: 104px; font-size: var(--fs-sm);
}
.cal td:last-child, .cal th:last-child { border-right: 0; }
.cal td.cal--fuera { background: var(--c-surface-alt); color: var(--c-text-3); }
.cal td.cal--hoy { background: var(--c-accent-soft); }
.cal__dia { font-weight: 650; font-size: var(--fs-sm); color: var(--c-text-2); }
.cal__viaje {
  display: block; margin-top: 4px; padding: 3px 8px; border-radius: var(--radius-sm);
  background: var(--c-accent-soft); border: 1px solid var(--c-accent-line);
  color: var(--c-accent-dark); text-decoration: none;
  font-size: var(--fs-xs); font-weight: 550; line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cal__viaje:hover { filter: brightness(.97); }
.cal__viaje--listo { background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg); }
.cal__viaje--aten  { background: var(--s-aten-bg); border-color: var(--s-aten-bd); color: var(--s-aten-fg); }
.cal__viaje--bloq  { background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }
.cal__mas { display: block; margin-top: 3px; font-size: var(--fs-xs); color: var(--c-text-2); }

/* La semana del Dashboard: **un renglón por día** — D-770, 28/09/2026.

   Siete columnas de tarjeta dejaban cada día a 76 px en un panel que mide
   media rejilla, y el Cliente se partía en cuatro líneas; darle el renglón
   entero al panel arreglaba el ancho pero dejaba media pantalla en blanco al
   lado de «Lo urgente hoy». Un renglón por día resuelve las dos: cada día
   dispone del ancho completo del panel, quepa donde quepa el panel. */
.semana { display: flex; flex-direction: column; gap: 6px; }
.semana__dia {
  display: grid; grid-template-columns: 5.6rem minmax(0, 1fr); gap: 10px;
  align-items: center; padding: 7px 10px;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface);
}
.semana__dia--fuera { background: var(--c-surface-alt); }
/* Un día sin viajes no gasta la altura de uno con trabajo: se encoge a una
   línea tenue. Siete tarjetas vacías eran el hueco que se veía al entrar. */
.semana__dia--vacio { padding: 3px 10px; background: transparent; border-style: dashed; }
.semana__dia--vacio .semana__num { font-size: var(--fs); color: var(--c-text-2); }
.semana__dia--hoy { border-color: var(--c-accent); box-shadow: 0 0 0 2px var(--c-accent-soft); }
.semana__fecha { display: flex; align-items: baseline; gap: 6px; }
.semana__dow {
  font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--c-text-2);
}
.semana__num {
  font-size: var(--fs-lg); font-weight: 680; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.semana__hoy {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--c-accent);
}
.semana__viajes { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.semana__nada { font-size: var(--fs-xs); color: var(--c-text-3); }

/* Un viaje: a quién va, en qué Vehículo y cuánto lleva de su capacidad
   normal. El color del filo izquierdo es el mismo semáforo de siempre y lo
   explica la leyenda del pie. */
.viaje {
  /* `wrap` para que en un panel estrecho —o en el teléfono— el Vehículo y la
     carga bajen a una segunda línea en vez de comerse el nombre del Cliente,
     que es el dato por el que se mira el día. */
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px;
  min-width: 0; max-width: 100%;
  text-decoration: none; color: inherit;
  border: 1px solid var(--c-border); border-left-width: 3px;
  border-radius: var(--radius-sm); padding: 5px 9px;
  background: var(--c-surface-alt); font-size: var(--fs-xs); line-height: 1.3;
}
.viaje:hover { background: var(--c-surface-sunk); color: inherit; }
.viaje b {
  font-weight: 650; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.viaje__veh { display: inline-flex; align-items: center; gap: 4px; color: var(--c-text-2); white-space: nowrap; }
.viaje__veh svg { width: 13px; height: 13px; }
.viaje__cap { font-variant-numeric: tabular-nums; font-weight: 650; color: var(--c-text-2); white-space: nowrap; }
.viaje--ok   { border-left-color: var(--s-ok-fg); }
.viaje--aten { border-left-color: var(--s-aten-fg); }
.viaje--bloq { border-left-color: var(--s-bloq-fg); }
.viaje--acc  { border-left-color: var(--c-accent); }
@media (max-width: 900px) {
  /* En el teléfono el Cliente se queda con su renglón entero y el Vehículo y
     la carga bajan al siguiente: recortado a «DEM…» el dato no sirve. */
  .viaje b { flex: 1 1 100%; }
}

/* ----------------------- 17. PANEL DE DETALLE, FICHA Y REJILLA DE PERMISOS */

.split { display: flex; gap: var(--sp-4); align-items: flex-start; }
.split__main { flex: 1 1 auto; min-width: 0; }
.split__side { flex: 0 0 21rem; position: sticky; top: 60px; }

/* Ficha: pares dato/valor legibles, nunca un muro de texto. */
.kv {
  display: grid; grid-template-columns: 13rem 1fr; gap: 7px var(--sp-4);
  font-size: var(--fs); margin: 0;
}
.kv dt { color: var(--c-text-2); }
.kv dd { margin: 0; font-weight: 550; }
.kv--tight { grid-template-columns: 9rem 1fr; gap: 5px var(--sp-3); }

/* Datos clave de una ficha 360°, en fila. */
.facts {
  display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}
.fact { min-width: 0; }
.fact__label {
  display: block; font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-3);
  text-transform: uppercase; letter-spacing: .06em;
}
.fact__value { display: block; font-size: var(--fs-md); font-weight: 650; margin-top: 2px; }

.diff { margin: 0; padding: 0; list-style: none; font-size: var(--fs); }
.diff li { padding: 3px 0; display: flex; gap: 7px; align-items: baseline; flex-wrap: wrap; }
.diff--add li::before { content: "+"; color: var(--s-ok-fg); font-weight: 700; }
.diff--del li::before { content: "−"; color: var(--s-bloq-fg); font-weight: 700; }
.diff--dep li::before { content: "+"; color: var(--c-accent); font-weight: 700; }

/* Bloque desplegable — módulo de Permisos y cualquier detalle plegado. */
details > summary { cursor: pointer; }

.module {
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); margin-bottom: var(--sp-2);
  box-shadow: var(--shadow-xs); overflow: hidden;
}
.module > summary {
  padding: 11px 14px; cursor: pointer; background: var(--c-surface);
  display: flex; justify-content: space-between; gap: var(--sp-3); align-items: center;
  font-weight: 650; list-style: none;
}
.module > summary:hover { background: var(--c-surface-alt); }
.module > summary::-webkit-details-marker { display: none; }
.module > summary::before { content: "▸"; color: var(--c-text-3); margin-right: 7px; }
.module[open] > summary::before { content: "▾"; }
.module[open] > summary { border-bottom: 1px solid var(--c-border-soft); }
.module__count { font-weight: 500; font-size: var(--fs-sm); color: var(--c-text-2); }
.module__body { padding: 10px 14px 14px; }

.plane { margin-top: var(--sp-3); }
.plane__label {
  font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--c-text-3);
  border-bottom: 1px solid var(--c-border-soft);
  padding-bottom: 4px; margin-bottom: 7px;
}

.perm { display: flex; gap: 10px; padding: 6px 0; align-items: flex-start; flex-wrap: wrap; }
.perm input[type=checkbox] { margin-top: 3px; flex: 0 0 auto; width: 16px; height: 16px;
  accent-color: var(--c-accent); }
.perm__label { flex: 1 1 22rem; min-width: 16rem; }
.perm__name { display: block; font-weight: 550; }
.perm__meta { display: block; color: var(--c-text-3); font-size: var(--fs-sm); margin-top: 1px; }
.perm__scope { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); }
.perm__scope select {
  padding: 4px 8px; border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm); font: inherit; font-size: var(--fs-sm); background: #fff;
}

/* --------------------------------------- 18. ESTADO VACÍO Y UTILIDADES */

.empty {
  padding: 34px 20px; text-align: center; color: var(--c-text-2);
  background: var(--c-surface); border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius-lg); font-size: var(--fs);
}
.empty .icobox { margin: 0 auto var(--sp-3); }
.empty b { display: block; color: var(--c-text); font-size: var(--fs-md); margin-bottom: 4px; }
.empty .btn { margin-top: var(--sp-3); }

.muted { color: var(--c-text-3); }
.help { color: var(--c-text-3); font-size: var(--fs-sm); }
.num { font-variant-numeric: tabular-nums; }
/* Una fila que sigue siendo historia pero ya no dirige trabajo —una Línea de
   cotización retirada—: se atenúa, **nunca se esconde**. El color no es el
   único canal: la fila lleva además su globo `Retirada` y su motivo escrito. */
.row--off > td { color: var(--c-text-3); background: var(--c-surface-alt); }
.stack > * + * { margin-top: var(--sp-3); }

/* -------------------------------------------------------- 19. RESPONSIVE */

/* Prioridad: escritorio, portátil y ancho reducido razonable (encargo §20).
   No se persigue el móvil completo, que no forma parte del piloto. */

@media (max-width: 1400px) {
  .board--3 { grid-template-columns: 1fr 1fr; }
  .board--2 { grid-template-columns: 1fr; }
  .dashboard-priority { grid-template-columns: minmax(0, 1.1fr) minmax(22rem, 1fr); }
}

@media (max-width: 1280px) {
  :root { --nav-w: 208px; --fs-2xl: 23px; }
  .workarea { padding: 18px 18px 56px; }
  .topbar { padding: 10px 18px; }
}

@media (max-width: 1100px) {
  .board, .board--2, .board--3 { grid-template-columns: 1fr; }
  .dashboard-priority { grid-template-columns: 1fr; }
  .split { flex-direction: column; }
  .split__side { position: static; flex: 1 1 auto; width: 100%; }
}

/* El interruptor del menú móvil: un checkbox que NUNCA se pinta. En
   escritorio la etiqueta tampoco existe; en móvil vive en la marca. */
.nav-abierto { display: none; }
.nav__burger { display: none; }

@media (max-width: 900px) {
  .app { flex-direction: column; }
  /* 2026-08-25 — la barra ya NO es una fila que envuelve (los enlaces
     quedaban revueltos ocupando la pantalla entera): en móvil es una franja
     con la marca y el botón «Menú», y la lista se despliega en COLUMNA con
     sus grupos como encabezados, sólo cuando se pide. */
  .nav {
    width: auto; flex: none; position: static;
    height: auto; max-height: none; overflow: visible;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 0 12px 0;
  }
  .nav__brand {
    width: calc(100% + 24px);
    margin: 0 -12px 0;
    padding: 10px 16px;
    justify-content: space-between;
  }
  .nav__brand-logo { height: 40px; width: auto; }
  .nav__burger {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px; border-radius: 10px; cursor: pointer;
    background: var(--c-nav-bg); color: #fff;
    font-weight: 650; font-size: var(--fs-md);
    user-select: none;
  }
  /* Cerrado por omisión; el checkbox —que va justo ANTES de la barra— lo abre. */
  .nav__scroll, .nav__foot { display: none; }
  .nav-abierto:checked + .nav .nav__scroll { display: block; padding: 6px 0 2px; }
  .nav-abierto:checked + .nav .nav__foot { display: flex; }
  .nav__scroll a { display: flex; padding: 11px 10px; }
  /* D-880 — en el cajón del teléfono la lista se abre DEBAJO de su área. */
  .nav__area[open] > .nav__fly {
    position: static; width: auto; padding: 2px 0 6px 14px;
    background: none; border: 0; box-shadow: none; animation: none;
  }
  .nav__fly-titulo { display: none; }
  .nav .nav__fly a { color: var(--c-nav-text); font-size: 15px; min-height: 42px; }
  .nav .nav__fly a .ic { color: var(--c-nav-text-2); }
  .nav .nav__fly a:hover { background: var(--c-nav-bg-2); color: #fff; }
  .nav .nav__fly a[aria-current="page"] { background: var(--c-nav-active); color: #fff; box-shadow: inset 2px 0 0 var(--c-nav-mark); }
  .nav__group { padding: 12px 10px 4px; }
  .nav__foot { width: 100%; margin: 6px 0 12px; }
  .kv, .kv--tight { grid-template-columns: 1fr; }
  .datos { grid-template-columns: 1fr; }
  .card__diag { grid-template-columns: 1fr; }
  .table, .tabla { display: block; overflow-x: auto; }
  .hbar { grid-template-columns: 7rem 1fr auto; }
}

@media print {
  .nav, .topbar, .screen__actions, .quick, .btn { display: none !important; }
  .panel, .stat { box-shadow: none; border-color: #ccc; }
  .workarea { padding: 0; }
}

/* D-654 — lo que falta de cada Pedido, con su botón, dentro de `Siguiente paso`
   de `Comercial → Pedidos`. Una cosa por renglón: el nombre corto y la acción. */
.faltantes { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.faltantes li { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.faltantes form { display: inline-flex; margin: 0; }

/* ===========================================================================
   D-665 — pantallas de operación: una cosa por renglón, con su botón.

   Agustín, 17/sep/2026: *«formularios grandes y poco reconocibles… quisiera que
   fuera mucho más simple, con botones simples y claros y coloridos»*. El color
   dice el papel del botón y el texto lo repite siempre: azul avanza el proceso,
   ámbar resuelve lo que falta, gris consulta.
   =========================================================================== */
.tarjetas { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.tarjeta {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); padding: 10px 12px;
}
/* --- BUSCAR DESDE CUALQUIER PARTE (2026-09-21) ----------------------------
   Agustín, 21/sep/2026: la aplicación se usa mucho en escritorio y **no tenía
   ningún buscador global**. Vive en la barra superior, así que está en todas
   las pantallas; es un `<details>`, así que funciona sin JavaScript. */
.buscador-g { position: relative; }
.buscador-g__abrir {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  list-style: none; padding: 5px 9px; border-radius: var(--radius-pill);
  border: 1px solid var(--c-border-strong); background: var(--c-surface);
  font-size: var(--fs-sm); color: var(--c-text-2);
}
.buscador-g__abrir::-webkit-details-marker { display: none; }
.buscador-g__abrir:hover { border-color: var(--c-accent-line); color: var(--c-text); }
.buscador-g:not([open]) .buscador-g__abrir:focus-visible,
.buscador-g__abrir:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
/* En una pantalla angosta el rótulo estorba: queda el icono y la tecla se va. */
.buscador-g__rotulo { display: none; }
.buscador-g__tecla {
  font-family: var(--ff-num); font-size: var(--fs-xs); font-weight: 600;
  background: var(--c-surface-sunk); border: 1px solid var(--c-border);
  border-radius: 5px; padding: 2px 5px; color: var(--c-text-3);
}
@media (min-width: 720px) {
  .buscador-g__rotulo { display: inline; }
}
@media (max-width: 719px) { .buscador-g__tecla { display: none; } }

.buscador-g__caja {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 60;
  width: min(520px, calc(100vw - 32px));
  background: var(--c-surface); border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md); overflow: hidden;
}
.buscador-g__forma {
  display: flex; align-items: center; gap: 9px; padding: 11px 13px;
  border-bottom: 1px solid var(--c-border);
}
.buscador-g__forma .ic { flex: none; color: var(--c-text-3); }
.buscador-g__campo {
  flex: 1; min-width: 0; border: 0; outline: 0; background: none;
  font-family: var(--ff); font-size: var(--fs-md); color: var(--c-text);
}
.buscador-g__lista { max-height: min(60vh, 420px); overflow-y: auto; padding: 4px 0 8px; }
.buscador-g__pista { margin: 0; padding: 12px 14px; font-size: var(--fs-sm); color: var(--c-text-3); }
.buscador-g__grupo {
  margin: 0; padding: 9px 14px 3px; font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--c-text-3);
}
.buscador-g__r {
  display: flex; align-items: center; gap: 10px; padding: 8px 14px;
  text-decoration: none; color: inherit;
}
.buscador-g__r:hover, .buscador-g__r:focus-visible {
  background: var(--c-accent-soft); outline: 0;
}
.buscador-g__ic {
  flex: none; width: 24px; height: 24px; border-radius: var(--radius-sm);
  display: grid; place-items: center; font-size: var(--fs-xs); font-weight: 700;
  background: var(--c-surface-sunk); color: var(--c-text-2);
}
.buscador-g__r:hover .buscador-g__ic, .buscador-g__r:focus-visible .buscador-g__ic {
  background: var(--c-accent); color: #fff;
}
.buscador-g__t { min-width: 0; flex: 1; }
.buscador-g__n { display: block; font-weight: 600; font-size: var(--fs-md); }
.buscador-g__d {
  display: block; font-size: var(--fs-sm); color: var(--c-text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.buscador-g__m { flex: none; font-size: var(--fs-xs); color: var(--c-text-3); }

/* --- La ayuda de atajos, con «?» -------------------------------------------
   Se pinta siempre en el HTML y se oculta con `hidden`: así existe para quien
   la abra con el teclado y no depende de que el guion la construya. */
.atajos {
  position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  background: rgba(16, 24, 40, .45); padding: 20px;
}
.atajos__caja {
  background: var(--c-surface); border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  padding: 20px 22px; max-width: 420px; width: 100%;
}
.atajos__caja h2 { font-size: var(--fs-lg); margin: 0 0 4px; }
.atajos__caja p { margin: 0 0 14px; font-size: var(--fs-sm); color: var(--c-text-3); }
.atajos__l { display: grid; gap: 7px; margin: 0; }
.atajos__l div { display: flex; align-items: baseline; gap: 10px; font-size: var(--fs-md); }
.atajos__l kbd {
  font-family: var(--ff-num); font-size: var(--fs-xs); font-weight: 600;
  background: var(--c-surface-sunk); border: 1px solid var(--c-border);
  border-radius: 5px; padding: 3px 6px; min-width: 30px; text-align: center;
}

/* --- CAPTURAR PICANDO (2026-09-21) ----------------------------------------
   Agustín: *«todo dato que tenga que dar se pica»*. Los atajos de fecha y los
   desplegables cortos convertidos en botones. El `select` sigue existiendo y
   sigue siendo el que viaja en el `POST`: se esconde para el ratón, **no se
   deshabilita**, porque un campo deshabilitado no se envía. */
.atajos-fecha { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.atajo-fecha {
  font: 600 var(--fs-sm)/1 var(--ff); cursor: pointer;
  background: var(--c-surface); color: var(--c-text-2);
  border: 1px solid var(--c-border-strong); border-radius: var(--radius-pill);
  padding: 7px 12px;
}
.atajo-fecha:hover { border-color: var(--c-accent); color: var(--c-accent-dark); }
.atajo-fecha:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.select-picable {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.opciones-picables { display: flex; gap: 8px; flex-wrap: wrap; }
.opcion-picable {
  font: 600 var(--fs-md)/1.2 var(--ff); cursor: pointer; text-align: left;
  background: var(--c-surface); color: var(--c-text);
  border: 1.5px solid var(--c-border-strong); border-radius: var(--radius);
  padding: 12px 16px; min-height: 44px;
}
.opcion-picable:hover { border-color: var(--c-accent-line); }
.opcion-picable[aria-pressed="true"] {
  border-color: var(--c-accent); background: var(--c-accent-soft);
  color: var(--c-accent-dark);
}
.opcion-picable:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* --- LA LISTA VACÍA (2026-09-21) -----------------------------------------
   «Sin resultados» en gris tenía el tono de un error. Cuando vacío es **bueno**
   —nada vencido, nada por surtir— la pantalla lo dice en verde y con su marca;
   cuando vacío sólo significa que el filtro no encontró nada, va en neutro: no
   se felicita a nadie por no encontrar lo que buscaba. */
.vacio {
  display: grid; gap: 6px; justify-items: center; text-align: center;
  padding: 28px 18px; border-radius: var(--radius-lg);
  border: 1px solid var(--c-border); background: var(--c-surface-alt);
}
.vacio--ok { background: var(--s-ok-bg); border-color: var(--s-ok-bd); }
.vacio__ic { color: var(--s-ok-fg); }
.vacio__ic .ic { width: 26px; height: 26px; }
.vacio__t { margin: 0; font-size: var(--fs-lg); font-weight: 700; }
.vacio--ok .vacio__t { color: var(--s-ok-fg); }
.vacio__d { margin: 0; font-size: var(--fs-md); color: var(--c-text-2); max-width: 52ch; }
.vacio .btn { margin-top: 6px; }
/* D-802 — «Quitar la búsqueda» y la acción propia de la lista, lado a lado. */
.vacio__botones { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
.vacio__botones .btn { margin-top: 0; }
.vacio__busqueda b { color: var(--c-text); }

/* --- SELECCIÓN MÚLTIPLE EN UNA LISTA (2026-09-21, D-683) ------------------
   Agustín: *«hacer diez a la vez»*. Medido: **ninguna lista de la aplicación
   permitía seleccionar varios renglones**.

   La barra se pega arriba —debajo de la barra superior— porque en una cola de
   veinte Líneas se marca abajo y se envía arriba. Nace con `hidden` y el guion
   se lo quita al marcar la primera; sin JavaScript se ve siempre, que es el
   peor caso y sigue funcionando. */
.selbarra {
  position: sticky; top: var(--topbar-h); z-index: 15;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--c-nav-bg); color: #eaf6ee;
  border-radius: var(--radius); padding: 10px 14px; margin: 0 0 10px;
  box-shadow: var(--shadow);
}
.selbarra b { font-size: var(--fs-md); }
.selbarra .btn { flex: none; }
.selbarra__nota { font-size: var(--fs-sm); color: var(--c-nav-text); margin-left: auto; }
@media (max-width: 720px) { .selbarra__nota { margin-left: 0; } }

/* La columna de la casilla: estrecha, centrada y sin robar ancho al contenido. */
.table .sel, .tabla .sel { width: 3%; text-align: center; padding-inline: 6px; }
.table .sel input, .tabla .sel input { width: 17px; height: 17px; cursor: pointer; }
/* En modo tarjeta la casilla va primera y con su rótulo, o no se entiende qué
   selecciona. */
@container tabla (max-width: 820px) {
  .table--tarjetas td.sel { order: 0; }
  .table--tarjetas td.sel:empty { display: none; }
}

/* --- EL TOTAL, FIJO AL PIE (2026-09-21) ----------------------------------
   **La cabecera fija ya existía** y está bien resuelta arriba (`position:
   sticky` con `top: var(--topbar-h)` y su corrección dentro de una tarjeta).
   Lo que NO existía es el pie: el total de una lista —la cifra por la que se
   abre `Cuentas por cobrar`— quedaba al final de 1,912 renglones.

   `tfoot` pegado abajo lo deja visible mientras se recorre la lista, sin
   contenedor con scroll propio: se pega contra el desplazamiento de la página,
   igual que la cabecera. `background` explícito, o las filas se ven debajo. */
.table tfoot td, .tabla tfoot td {
  position: sticky; bottom: 0; z-index: 1;
  background: var(--c-surface-alt); font-weight: 600;
  box-shadow: inset 0 1px 0 var(--c-border-strong);
}
/* Una tabla dentro de `.tablewrap` que NO está en una tarjeta pegaba su
   cabecera a `top: 0`, es decir **detrás de la barra superior**, que mide 43 px
   y es fija. Dentro de una tarjeta el `top: 0` sí es correcto —la tarjeta ya
   está debajo de la barra—, así que se distingue por el ancestro en vez de
   volver a tocar la regla general. */
.workarea > .tablewrap :is(.table, .tabla) thead th,
.workarea > form > .tablewrap :is(.table, .tabla) thead th { top: var(--topbar-h); }
/* En modo tarjeta no hay columnas que fijar ni total que pegar: la tarjeta ya
   es corta y una cabecera pegada rompería la pila. */
@container tabla (max-width: 820px) {
  .table--tarjetas thead th { position: static; }
  .table--tarjetas tfoot td { position: static; }
}

/* --- El MARCADOR del checklist (2026-09-21) -------------------------------
   Agustín, 21/sep/2026: «más botones, menos texto, menos vueltas de
   pantallas», y de la maqueta de esta pantalla: «era más limpio, menos texto,
   un poco más de diseño… y eso que todavía aguantaba más».

   La pregunta del almacén es una: ¿cuánto me falta para que esto pueda salir?
   Antes se contestaba contando puntos ámbar en seis renglones iguales. Aquí es
   una cifra grande, un segmento por requisito y las palabras que faltan.

   Los segmentos van en `flex: 1` y no con ancho fijo: con cinco requisitos o
   con ocho, la barra mide lo mismo y se reparte. */
.marcador {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--c-surface); border: 1px solid var(--c-border);
  /* El filo dice el estado: ámbar mientras falte algo, verde al completar. Un
     filo verde con «0 de 5» al lado decía lo contrario de lo que pasaba. */
  border-left: 4px solid var(--c-franja-aten);
  border-radius: var(--radius-lg); padding: 14px 16px; margin: 0 0 14px;
  box-shadow: var(--shadow-xs);
}
.marcador__cifra {
  font-size: var(--fs-2xl); font-weight: 700; line-height: 1;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums; flex: none;
}
.marcador__de { font-size: var(--fs-md); font-weight: 600; color: var(--c-text-3); margin-left: 5px; }
.marcador__barra { display: flex; gap: 4px; flex: 1 1 140px; min-width: 120px; }
/* Un segmento por requisito. Hueco el pendiente, relleno el cumplido: el color
   no es el único portador del significado. */
.marcador__seg {
  flex: 1; height: 10px; border-radius: 999px;
  background: var(--c-surface-sunk); border: 1px solid var(--c-border-strong);
}
.marcador__seg--ok { background: var(--s-ok-fg); border-color: var(--s-ok-fg); }
.marcador--ok { border-left-color: var(--s-ok-fg); }

/* 2026-09-21 — **la lista vacía da la buena noticia.** Una cobranza sin nada
   vencido es el mejor estado de esa pantalla, y decirlo con el gris de «sin
   resultados» lo hacía leer como un error. */
.vacio-ok { color: var(--s-ok-fg); font-weight: 700; }
.marcador__falta { font-weight: 600; color: var(--c-text-2); font-size: var(--fs-md); flex: none; }

/* --- La MARCA de un requisito (2026-09-21) --------------------------------
   Sustituye al punto de 11 px de `.tarjeta__punto` en el checklist: lleva
   **forma además de color** —paloma el cumplido, aro hueco el pendiente—, así
   que el estado se lee sin distinguir verde de ámbar. El punto se conserva
   porque lo usan otras pantallas. */
.marca {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--c-border-strong); background: var(--c-surface);
}
.marca .ic { width: 14px; height: 14px; }
.marca--ok { background: var(--s-ok-fg); border-color: var(--s-ok-fg); color: #fff; }
.marca--falta { background: var(--s-aten-bg); border-color: var(--s-aten-bd); }

.tarjeta__punto { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.tarjeta__punto--ok { background: var(--s-ok-fg); }
/* El punto lleva aro para que el amarillo se vea también sobre blanco. */
.tarjeta__punto--falta { background: var(--s-amar-fg); }
.tarjeta__texto { min-width: 12rem; flex: 1 1 14rem; }
.tarjeta__titulo { font-weight: 600; }
.tarjeta__nota { color: var(--c-text-3); font-size: var(--fs-sm); }
.tarjeta__acciones { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.tarjeta__acciones form { margin: 0; }
/* En pantalla angosta la acción baja a su propio renglón, a lo ancho. */
@media (max-width: 560px) {
  .tarjeta__acciones { margin-left: 0; width: 100%; }
  .tarjeta__acciones .btn { flex: 1 1 auto; justify-content: center; }
}

/* El botón que resuelve lo que falta. NO es `--exc`: aquello es excepción
   autorizada, esto es trabajo pendiente normal. */
/* **Amarillo translúcido, del mismo temple que el verde y el rojo del resto del
   sistema.** Agustín, 17/09/2026: *«no me encanta el ámbar, prefiero amarillo»*
   y *«que sea medio transparente igual que el verde y el rojo en otras
   secciones»*. Fondo tenue, letra y borde del mismo tono, como `.chip--ok` y
   `.chip--bloq`; el texto del botón dice siempre lo mismo que el color. */
:root {
  --s-amar-bg: #fdf3d3;  --s-amar-fg: #8a6300;  --s-amar-bd: #f0d78a;
}
.btn--accion {
  background: var(--s-amar-bg); border-color: var(--s-amar-bd); color: var(--s-amar-fg);
  font-weight: 650;
}
.btn--accion:hover {
  background: var(--s-amar-fg); border-color: var(--s-amar-fg); color: var(--s-amar-bg);
}
/* El botón del paso que toca usa `.btn--lg`, que ya existía; en táctil crece a
   44 px, que es el mínimo cómodo para un dedo. */
@media (pointer: coarse) { .btn--lg { min-height: 44px; } }

/* Lo que no se necesita para trabajar, plegado: sigue estando. */
.plegado { border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-surface); }
.plegado + .plegado { margin-top: 8px; }
.plegado > summary {
  cursor: pointer; padding: 10px 14px; font-weight: 600; list-style: none;
  display: flex; align-items: center; gap: 8px;
}
.plegado > summary::-webkit-details-marker { display: none; }
.plegado > summary::before { content: "▸"; color: var(--c-text-3); }
.plegado[open] > summary::before { content: "▾"; }
.plegado > summary:hover { background: var(--c-surface-alt); }
.plegado__cuerpo { padding: 0 14px 14px; }
.plegado__cuerpo > .panel { box-shadow: none; border: 0; }

/* D-667 — **la cantidad, en barra**: «300 de 450 kg preparados» se lee de un
   vistazo; las tres cifras siguen en el plegado de siempre. */
.avance { display: flex; flex-direction: column; gap: 6px; margin: 0 0 14px; }
.avance__texto { font-weight: 600; }
.avance__barra { height: 12px; border-radius: 999px; background: var(--c-surface-alt); border: 1px solid var(--c-border); overflow: hidden; }
.avance__relleno { height: 100%; background: var(--s-ok-fg); }
.avance__falta { color: var(--c-text-3); font-size: var(--fs-sm); }

/* D-667 — **el porqué, detrás de una línea**: el párrafo completo sigue palabra
   por palabra, pero deja de ocupar media pantalla. */
.porque > summary { cursor: pointer; color: var(--c-text-3); font-size: var(--fs-sm); }
.porque > summary::marker { content: ""; }
.porque > summary::after { content: " ¿Por qué?"; text-decoration: underline; }
.porque[open] > summary::after { content: " Ocultar"; }

/* D-667 — **la lista, en tarjetas cuando la pantalla es angosta.**
   En un celular, `Comercial → Pedidos` obligaba a arrastrar la tabla de lado
   para llegar al botón del paso que toca —se vio en la captura del 17/09/2026—.
   La misma tabla, las mismas columnas y el mismo orden: cada renglón se apila
   como tarjeta y cada celda lleva delante el nombre de su columna.

   2026-09-21 · D-687 — **el disparador pasó de la ventana a la columna.** Era
   `@media (max-width: 820px)`; ahora es `@container tabla`, declarado en
   `.tablewrap`. Las reglas son **las mismas, una sola copia**: lo único que
   cambia es qué se mide. En un teléfono no cambia nada —la columna es la
   ventana—, y en escritorio la tabla también se apila cuando comparte el ancho
   con el panel de la ficha, que es el caso que antes no existía. */
@container tabla (max-width: 820px) {
  .table--tarjetas thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .table--tarjetas, .table--tarjetas tbody, .table--tarjetas td { display: block; width: auto; }
  /* 2026-09-21 — **la tarjeta es una columna flex, no un bloque.** Con `block`,
     el orden de la tarjeta era el orden de las columnas de la tabla, así que el
     botón de la primera columna salía **arriba**, antes de saber de qué Pedido
     era. Con flex se puede mandar la acción al final sin mover una sola celda
     del HTML —y por tanto sin cambiar la tabla de escritorio—. */
  .table--tarjetas tr {
    display: flex; flex-direction: column; width: auto;
    border: 1px solid var(--c-border); border-radius: var(--radius);
    background: var(--c-surface); padding: 10px 12px; margin-bottom: 10px;
  }
  .table--tarjetas td[data-titulo] { order: 1; }
  .table--tarjetas td[data-cifra]  { order: 2; }
  .table--tarjetas td             { order: 3; }
  .table--tarjetas td[data-extra]  { order: 4; }
  .table--tarjetas td[data-accion] { order: 5; }
  /* Una celda sin rótulo declarado **no pinta dos puntos huérfanos**. Pasaba en
     los renglones de grupo, que no son datos sino el encabezado de su Pedido:
     la tarjeta abría con «: PED-001914». */
  .table--tarjetas td:not([data-rotulo])::before { content: ""; }
  /* El renglón de grupo es un encabezado, no una tarjeta: sin caja, sin fondo. */
  .table--tarjetas tr.rowgroup {
    border: 0; background: none; padding: 6px 2px 2px; margin-bottom: 4px;
    font-size: var(--fs-md);
  }
  /* 2026-09-21 — **la tarjeta alinea a la izquierda, y gana.** `.table .num`
     centra y `.table .mid` también, con más especificidad que `.table--tarjetas
     td`: dentro de una tarjeta eso dejaba los importes y las fechas centrados
     y el renglón ilegible. Se nombran las dos clases aquí para que la tarjeta
     mande, sin tocar la alineación de la tabla en escritorio. */
  .table--tarjetas td,
  .table--tarjetas td.num,
  .table--tarjetas td.mid,
  .table--tarjetas td.state,
  .table--tarjetas td.actions { border: 0; padding: 3px 0; text-align: left; }
  /* `.table .actions` vale `width: 1%` para que la columna de botones no robe
     ancho en escritorio. Dentro de una tarjeta ese 1% aplastaba el botón hasta
     dejar cuatro letras visibles. */
  .table--tarjetas td.actions { width: auto; white-space: normal; }
  .table--tarjetas td::before {
    content: attr(data-rotulo) ": "; color: var(--c-text-3); font-size: var(--fs-sm);
  }
  /* 2026-09-21 — **el patrón se declara por atributo, no por el nombre de la
     columna.** Hasta hoy el título de la tarjeta y su botón se reconocían por
     `data-rotulo="Folio"` y `="Siguiente paso"`, así que el patrón sólo servía
     en `Comercial → Pedidos`: cualquier otra lista con otras columnas se
     quedaba sin título y sin botón a todo el ancho. Con `data-titulo` y
     `data-accion` sirve en las 195 tablas. **Las dos reglas viejas se
     conservan** para no romper la pantalla que ya las usaba. */
  .table--tarjetas td[data-titulo]::before { content: ""; }
  .table--tarjetas td[data-titulo] { font-size: var(--fs-lg); font-weight: 650; }
  /* 2026-10-06 (D-802) — **la tarjeta se lee por capas**: primero QUIÉN o QUÉ
     (`data-titulo`), después la cifra, y el folio abajo, en chico, como
     contexto. Hasta hoy el folio se pintaba como título por herencia de la
     primera lista que usó el patrón; sólo sigue siéndolo en la tarjeta que no
     declara otro título, para no dejarla sin cabeza. */
  .table--tarjetas tr:not(:has([data-titulo])) td[data-rotulo="Folio"]::before { content: ""; }
  .table--tarjetas tr:not(:has([data-titulo])) td[data-rotulo="Folio"] { font-size: var(--fs-lg); font-weight: 650; }
  .table--tarjetas tr:has([data-titulo]) td[data-rotulo="Folio"]:not([data-titulo]) {
    order: 2; font-size: var(--fs-sm); color: var(--c-text-2); font-weight: 600; padding: 1px 0;
  }
  .table--tarjetas tr:has([data-titulo]) td[data-rotulo="Folio"]:not([data-titulo])::before {
    content: attr(data-rotulo) " "; font-weight: 400;
  }
  .table--tarjetas td[data-rotulo="Siguiente paso"],
  .table--tarjetas td[data-accion] { margin-top: 6px; }
  .table--tarjetas td[data-rotulo="Siguiente paso"] .btn,
  .table--tarjetas td[data-accion] .btn { width: 100%; justify-content: center; }
  /* La celda de la acción **no lleva rótulo**: el botón ya dice qué hace, y el
     rótulo delante lo dejaba a media línea y encimado. */
  .table--tarjetas td[data-accion]::before { content: ""; }
  .table--tarjetas td[data-accion]:empty { display: none; }
  /* La cifra que la persona fue a buscar: grande y con su rótulo delante. */
  .table--tarjetas td[data-cifra] { font-size: var(--fs-xl); font-weight: 700; margin-top: 2px; }
  .table--tarjetas td[data-cifra]::before { font-size: var(--fs-sm); font-weight: 400; }
  /* Lo secundario: más chico y apagado, pero **presente**. No se esconde: en un
     teléfono el renglón ya es una tarjeta y lo que sobra estorba menos abajo
     que a 900 px de scroll lateral. */
  .table--tarjetas td[data-extra] { font-size: var(--fs-sm); color: var(--c-text-3); padding: 1px 0; }
  .table--tarjetas td[data-extra]:empty { display: none; }
  /* Una celda sin dato no gasta un renglón de la tarjeta. */
  .table--tarjetas td[data-vacia] { display: none; }
}

/* D-668 — **los tres pasos, en franja.** Tres casillas del mismo ancho: la
   cumplida en verde, la que toca en azul, la siguiente apagada. Debajo va un
   solo botón grande. Agustín, 17/09/2026, con la ficha del PED-003954 en la
   pantalla: *«siento que sigo sin ver los cambios»* — este bloque seguía siendo
   el párrafo de siempre. */
.pasos3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.paso3 {
  border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 10px 8px; text-align: center; font-size: var(--fs-sm);
  color: var(--c-text-3); background: var(--c-surface);
}
.paso3--ok { background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg); font-weight: 600; }
.paso3--ahora {
  background: var(--c-accent-soft); border-color: var(--c-accent);
  color: var(--c-accent-dark); font-weight: 700;
}
/* 2026-10-06 (D-802) — **el resumen breve**: el paso ya contestado enseña lo
   que se contestó —el Cliente, el importe— debajo de su nombre, para no tener
   que volver atrás a comprobarlo. Lo escribe `captura.js`. */
.paso3__resumen {
  display: block; margin-top: 2px; font-size: var(--fs-xs); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 560px) { .pasos3 { grid-template-columns: 1fr; } }

/* 2026-09-25 — **la banda de la salida, a ancho completo bajo el título.**
   Vivía dentro de `screen__head`, que es *título a la izquierda, botones a la
   derecha*: una tarjeta entera metida ahí se encogía a media pantalla y
   empujaba el título del Pedido. Ahora es la primera banda de la hoja, que es
   el orden en que se lee un Pedido: qué es, y qué le toca. */
.salida .pasos3 { margin-bottom: var(--sp-3); }
.salida__nota { margin: 0 0 var(--sp-3); color: var(--c-text-2); font-size: var(--fs-sm); }
.salida__nota:last-child { margin-bottom: 0; }
/* La acción del paso que toca, y detrás de ella la que de verdad es otra cosa
   —programar lo que falte—, en gris para que no compita con la principal. */
.salida__acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.salida__acciones form { margin: 0; }

/* D-669 — una explicación larga deja de ocupar la pantalla: queda su enlace
   «¿Por qué?» y el texto entero se abre al picarlo. Se aplica a los párrafos de
   ayuda de más de 130 caracteres; los avisos de dinero y de riesgo NO se
   pliegan, siguen a la vista. */
.porque.help > summary { padding: 2px 0; }
.porque.help[open] { color: var(--c-text-3); font-size: var(--fs-sm); margin: 6px 0 10px; }

/* D-670 — capturar en tres preguntas. Sin JavaScript los tres bloques se ven
   seguidos; con él, uno a la vez. */
.captura__paso + .captura__paso { margin-top: var(--sp-3); }
.captura--activa [data-paso] { animation: none; }


/* D-675 — la campana de avisos, a la derecha de la barra de arriba. Amarilla
   cuando hay algo sin leer, con el número encima. */
.campana {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  color: var(--c-text-2);
}
.topbar a.campana:hover { text-decoration: none; background: var(--c-surface-2, rgba(0,0,0,.05)); }
.campana--nuevos { color: var(--s-aten-fg); background: var(--s-aten-bg); }
.campana__n {
  position: absolute; top: -2px; right: -4px;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--s-bloq-fg); color: #fff; font-size: 11px; font-weight: 700; line-height: 18px;
  text-align: center;
}
/* La pantalla de Avisos (D-675). */
.avisos-cabeza { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.avisos-cabeza__acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.celular__fila { display: flex; align-items: center; gap: 12px; padding: 14px 18px; flex-wrap: wrap; }
.celular__icono { display: inline-flex; width: 36px; height: 36px; border-radius: 50%;
  align-items: center; justify-content: center; background: var(--s-ok-bg); color: var(--s-ok-fg); flex: 0 0 36px; }
.celular__estado { flex: 1 1 220px; margin: 0; color: var(--c-text-2); }
.celular__botones { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.celular__botones form { margin: 0; }
.avisos { list-style: none; margin: 0; padding: 0; }
.aviso {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 12px 14px 16px; border-bottom: 1px solid var(--c-border);
}
.aviso:last-child { border-bottom: 0; }
.aviso--nuevo { background: var(--s-aten-bg); }
.aviso__punto { flex: 0 0 10px; height: 10px; margin-top: 7px; border-radius: 50%; background: var(--c-border); }
.aviso--nuevo .aviso__punto { background: var(--s-bloq-fg); }
.aviso__texto { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px;
  text-decoration: none; color: inherit; }
.aviso__texto:hover .aviso__titulo { color: var(--c-accent); }
.aviso__titulo { font-weight: 700; line-height: 1.35; }
.aviso:not(.aviso--nuevo) .aviso__titulo { font-weight: 600; color: var(--c-text-2); }
.aviso__detalle { white-space: pre-line; color: var(--c-text-2); font-size: var(--fs-sm); line-height: 1.45; }
.aviso__cuando { font-size: var(--fs-sm); color: var(--c-text-3, var(--c-text-2)); }
.aviso form { margin: 0; }
.aviso__quitar {
  border: 0; background: transparent; color: var(--c-text-2); cursor: pointer;
  width: 36px; height: 36px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
}
.aviso__quitar:hover { background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.avisos-vacio { padding: 18px; margin: 0; color: var(--c-text-2); }

/* D-675 — elegir a una persona con un toque: un botón grande por opción. */
.opciones-grandes { border: 0; padding: 0; margin: 0 0 var(--sp-3, 12px); }
.opciones-grandes legend { font-weight: 700; margin-bottom: 8px; }
.opcion-grande {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 0 8px 8px 0; padding: 12px 18px; min-height: 48px;
  border: 2px solid var(--c-border); border-radius: 10px;
  background: var(--c-surface); font-size: var(--fs-md); font-weight: 600; cursor: pointer;
}
.opcion-grande input { width: 18px; height: 18px; }
.opcion-grande:has(input:checked) { border-color: var(--c-accent); background: var(--c-accent-soft, #e8f0fe); }

/* --- LISTA Y FICHA JUNTAS EN ESCRITORIO (2026-09-21 · D-687) --------------
   Agustín, 21/sep/2026: *«lista y ficha juntas»*, y el caso que lo motiva es
   cobrar cinco Facturas seguidas en `Cuentas por cobrar` sin volver atrás cinco
   veces. Hasta hoy, abrir una ficha **perdía la lista y el filtro**.

   **El panel es una forma de MIRAR la ficha, no una segunda casa** (regla de
   «una sola casa por entidad»): la ruta de la ficha sigue existiendo igual, el
   enlace del renglón sigue siendo un `href` normal y sin JavaScript lleva a la
   ficha entera como hoy. Aquí sólo está el acomodo.

   **Bajo 980 px no hay dos paneles**: es el mismo corte con el que la barra
   lateral deja de ser lateral, y media ficha en un teléfono no es una ficha. */
.dosp { min-width: 0; }
.dosp__lista { min-width: 0; }

/* Cerrado, el panel no existe y la lista ocupa el ancho entero: `.dosp` no
   declara rejilla hasta que hay algo que acomodar. */
@media (min-width: 980px) {
  .dosp--abierto {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: var(--sp-4);
    align-items: start;
  }
}

/* El panel se queda quieto mientras se recorre la lista —que es justamente lo
   que se fue a hacer— y tiene su propio `scroll` cuando la ficha es larga. */
.ficha {
  min-width: 0;
  position: sticky;
  top: calc(var(--topbar-h) + var(--sp-3));
  max-height: calc(100vh - var(--topbar-h) - var(--sp-6));
  overflow: auto;
  overscroll-behavior: contain;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.ficha__head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: 9px 14px;
  background: var(--c-surface-alt);
  border-bottom: 1px solid var(--c-border);
}
.ficha__rotulo {
  margin-right: auto; min-width: 0;
  font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ficha__cuerpo { padding: var(--sp-4) var(--sp-5) var(--sp-5); }
/* Dentro del panel el título de la ficha es un encabezado de panel, no el
   título de la pantalla: la pantalla sigue siendo la lista. */
.ficha__cuerpo .screen__title { font-size: var(--fs-xl); }
.ficha__cuerpo .screen__head { flex-direction: column; align-items: stretch; gap: var(--sp-2); }
.ficha__cuerpo > :last-child { margin-bottom: 0; }

/* El renglón abierto se señala **por dos canales**: el fondo y la barra de la
   izquierda. Sólo con el fondo, quien no distingue ese azul no sabe cuál de
   los veinte renglones está mirando a la derecha. */
.table tr[aria-selected="true"] > td,
.tabla tr[aria-selected="true"] > td { background: var(--c-accent-soft); }
.table tr[aria-selected="true"] > td:first-child,
.tabla tr[aria-selected="true"] > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
/* En modo tarjeta el renglón ES la caja, así que la marca va en la caja. */
@container tabla (max-width: 820px) {
  .table--tarjetas tr[aria-selected="true"] {
    border-color: var(--c-accent-line);
    box-shadow: inset 3px 0 0 var(--c-accent);
  }
  .table--tarjetas tr[aria-selected="true"] > td { background: transparent; }
  .table--tarjetas tr[aria-selected="true"] > td:first-child { box-shadow: none; }
  /* 2026-09-29 — la cola de Preparación, en tarjeta. La franja de urgencia no
     cabe de canto: pasa a ser el borde izquierdo de la tarjeta entera, que es
     donde el pulgar ya está mirando. */
  .table--tarjetas.table--cola .cola__franja { display: none; }
  .table--tarjetas.table--cola tr:has(.franja--tarde) { border-left: 5px solid var(--c-franja-bloq); }
  .table--tarjetas.table--cola tr:has(.franja--hoy) { border-left: 5px solid var(--c-franja-aten); }
  .table--tarjetas.table--cola .cola__cliente { font-size: var(--fs-sm); }
  /* Y el nombre completo: los topes de ancho existen para que la TABLA quepa;
     dentro de una tarjeta no hay columna que cuidar, y recortar «DEMO Sosa
     cáustica escama…» esconde justo el dato que se fue a buscar. */
  .table--tarjetas.table--cola td[data-rotulo] { max-width: none; }
  .table--tarjetas td[data-rotulo="Vencimiento"] { max-width: none; }
  .table--tarjetas .cell-clip { white-space: normal; overflow: visible; }
  /* 13/oct/2026 — Existencias: el renglón de «Lotes» (`tarjeta-pie`) se pega a
     la tarjeta de su Material, y sus capas son renglones ligeros, no tarjetas
     dentro de tarjetas. Su gemelo apilado está en el bloque «===== P8». */
  tr.tarjeta-pie {
    margin-top: -11px; border-top: 0;
    border-radius: 0 0 var(--radius) var(--radius); padding-top: 0;
  }
  tr:has(+ tr.tarjeta-pie) { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
  tr.tarjeta-pie .table--sub tr {
    border: 0; border-top: 1px solid var(--c-border-soft); border-radius: 0;
    background: none; padding: 6px 0; margin: 0;
  }
  /* Los botones del certificado bajan de renglón en vez de salirse de la tarjeta. */
  tr.tarjeta-pie .subtable__coa { flex-wrap: wrap; margin-left: 0; }
}

/* --- EL MOLDE DE LISTA (2026-09-21 · D-691) --------------------------------
   Agustín: «más sencilla, con menos elementos en la pantalla». Medido el
   21/sep: toda lista abría con cuatro pisos antes de la tabla —tarjetas
   grandes, tarjetas chicas, hasta doce pestañas y el filtro—; en un teléfono,
   cuatro pantallas de tarjetas antes del primer Pedido.

   El molde: la fila de CIFRAS (cada una un filtro), dos o tres pestañas, el
   buscador solo y lo demás plegado en «Más filtros». La tabla, arriba. */
.cifras {
  display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center;
  margin: 0 0 var(--sp-3);
}
.cifra {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 7px 13px; border-radius: var(--radius-pill);
  background: var(--c-surface); border: 1px solid var(--c-border);
  color: var(--c-text-2); font-size: var(--fs-sm); text-decoration: none;
  min-height: 36px; align-items: center;
}
.cifra b { font-size: var(--fs-lg); font-weight: 700; color: var(--c-text); font-variant-numeric: tabular-nums; }
a.cifra:hover { border-color: var(--c-border-strong); color: var(--c-text); }
.cifra--on { background: var(--c-accent-soft); border-color: var(--c-accent-line); color: var(--c-accent-dark); }
.cifra--on b { color: var(--c-accent-dark); }
.cifra--aten { border-color: var(--s-aten-bd); background: var(--s-aten-bg); color: var(--s-aten-fg); }
.cifra--aten b { color: var(--s-aten-fg); }
.cifra--bloq { border-color: var(--s-bloq-bd); background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.cifra--bloq b { color: var(--s-bloq-fg); }
.cifra--ok { border-color: var(--s-ok-bd); background: var(--s-ok-bg); color: var(--s-ok-fg); }
.cifra--ok b { color: var(--s-ok-fg); }
/* Una cifra activa que además pide atención: gana el «estás aquí». */
.cifra--on.cifra--aten, .cifra--on.cifra--bloq, .cifra--on.cifra--ok {
  background: var(--c-accent-soft); border-color: var(--c-accent-line); color: var(--c-accent-dark);
}

/* «Más filtros»: lo que no es el buscador empieza plegado. Vive DENTRO del
   formulario, así que sus campos viajan igual; sólo cambia que no se ven
   hasta que hacen falta. Abierto, se acomoda en la misma fila. */
.filtro-mas { display: contents; }
.filtro-mas > summary {
  cursor: pointer; list-style: none; font-size: var(--fs-sm); color: var(--c-text-2);
  padding: 9px 2px; white-space: nowrap; text-decoration: underline;
  text-underline-offset: 3px;
}
.filtro-mas > summary::-webkit-details-marker { display: none; }
.filtro-mas > summary::after { content: " ▾"; }
.filtro-mas[open] > summary::after { content: " ▴"; }
.filtro-mas__campos { display: contents; }
/* En el molde la descripción larga de la pantalla no ocupa la cabecera: va
   plegada en su «¿Por qué?», como cualquier ayuda (D-669). */
[data-molde="lista"] .screen__sub { display: none; }

/* --- «Más datos» en una captura (D-692) ----------------------------------
   Lo que casi nunca cambia —vigencia, TC provisional, orden de compra,
   observaciones— empieza plegado con su valor propuesto ya puesto. Se abre
   solo cuando trae un error, para que nada mal capturado quede escondido. */
.mas-datos { border: 1px solid var(--c-border); border-radius: var(--radius); padding: 0 14px; margin: 4px 0 12px; background: var(--c-surface-alt); }
.mas-datos > summary { cursor: pointer; padding: 11px 0; font-weight: 600; color: var(--c-text-2); list-style: none; }
.mas-datos > summary::-webkit-details-marker { display: none; }
.mas-datos > summary::after { content: " ▾"; color: var(--c-text-3); }
.mas-datos[open] > summary::after { content: " ▴"; }
.mas-datos[open] > summary { border-bottom: 1px solid var(--c-border-soft); margin-bottom: 10px; }

/* --- Ficha del Cliente con un solo «Editar» (2026-09-22 · D-696) ---------
   La pantalla única reúne las seis ediciones. Lo que ya existe —contactos,
   direcciones, el Vendedor vigente— se enseña en corto encima de «Agregar»,
   y los títulos de «Más datos» se separan como secciones. */
.ficha-editar__hoy { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: 0 0 var(--sp-3); }
.ficha-editar__lista { margin: 0 0 var(--sp-3); padding-left: 1.1em; font-size: var(--fs); }
.ficha-editar__lista li { padding: 2px 0; }
.ficha-editar .mas-datos h3 { margin: var(--sp-3) 0 var(--sp-2); font-size: var(--fs-md); }

/* --- Varios Pedidos en el MISMO viaje (2026-09-22 · D-702) ---------------
   Decisión de Agustín: *«al programar varios pedidos en un viaje se aceptan
   los que caben y se rechazan los demás con su motivo, salvo que quien
   programa sepa que se pasa y dé permiso de pasarse»*.

   El viaje —Vehículo, fecha y hora— se captura UNA vez, encima de la lista, y
   el bloque **no se esconde**: esconderlo sin JavaScript dejaría el botón
   inalcanzable, y la pantalla tiene que seguir sirviendo sin él. Los campos van
   a 16 px y 44 px de alto, que es la medida del pulgar y lo que evita que iOS
   haga zoom al enfocar. */
.lote { border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-surface-alt); padding: 12px 14px; margin: 0 0 12px; }
.lote__head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.lote__nota { font-size: var(--fs-sm); color: var(--c-text-2); }
.lote__campos { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.lote__campos label { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-2); }
.lote__campos input, .lote__campos select { font-size: 16px; min-height: 44px; }
.lote__campos .btn { min-height: 44px; }
.lote > .help { margin: 10px 0 0; }
.lote__confirma { display: flex; align-items: flex-start; gap: 8px; margin: 0 0 12px; font-size: var(--fs); }
.lote__confirma input { width: 20px; height: 20px; flex: none; margin-top: 2px; }
@media (max-width: 720px) {
  .lote__campos { flex-direction: column; align-items: stretch; }
  .lote__campos .btn { width: 100%; justify-content: center; }
}

/* --- Un menú por renglón, en vez de tres botones (2026-09-22 · D-701) -----
   La ficha del Material enseñaba `Redactar`, `Nueva versión` y `Marcar
   desactualizado` en cada renglón de Documentos. Ahora el renglón enseña UN
   control y las tres acciones viven dentro.

   Es un `<details>`: **funciona sin JavaScript**, que es regla de la casa. Y se
   abre HACIA ABAJO dentro de la celda en vez de flotar encima, porque
   `.panel__body` declara `overflow-x: auto` y un menú posicionado se recortaría
   contra el borde del panel justo en la pantalla angosta donde más falta hace.

   El molde es reutilizable a propósito —`menu-fila` no nombra al Material—:
   cualquier tabla con tres acciones por renglón puede pedirlo igual. */
.menu-fila { display: inline-block; position: relative; }
.menu-fila__abrir {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  list-style: none; padding: 6px 11px; border-radius: var(--radius);
  border: 1px solid var(--c-border-strong); background: var(--c-surface);
  font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-2);
  white-space: nowrap;
}
.menu-fila__abrir::-webkit-details-marker { display: none; }
.menu-fila__abrir::after { content: "▾"; color: var(--c-text-3); }
.menu-fila[open] > .menu-fila__abrir::after { content: "▴"; }
.menu-fila__abrir:hover { border-color: var(--c-accent-line); color: var(--c-text); }
.menu-fila__abrir:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.menu-fila__caja {
  margin-top: 6px; min-width: 15rem;
  display: flex; flex-direction: column;
  background: var(--c-surface); border: 1px solid var(--c-border-strong);
  border-radius: var(--radius); overflow: hidden;
}
/* Cada opción es una fila completa y cómoda para un dedo: en táctil crece a los
   44 px que Agustín pidió para toda la flota. */
.menu-fila__opcion {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 12px; text-align: left; white-space: normal;
  background: none; border: 0; border-radius: 0; cursor: pointer;
  font: inherit; font-size: var(--fs-sm); color: var(--c-text);
  text-decoration: none;
}
.menu-fila__opcion + .menu-fila__opcion,
.menu-fila__forma { border-top: 1px solid var(--c-border-soft); }
.menu-fila__opcion:hover { background: var(--c-surface-alt); color: var(--c-accent-dark); }
.menu-fila__opcion:focus-visible { outline: 2px solid var(--c-accent); outline-offset: -2px; }
.menu-fila__opcion .ic { flex: none; color: var(--c-text-3); }
@media (pointer: coarse) { .menu-fila__opcion { min-height: 44px; } }

/* El motivo que «Retirar desactualizado» exige viaja DENTRO del menú, encima de
   su propio botón: la validación y la ruta son las de siempre. */
.menu-fila__forma { display: block; margin: 0; }
.menu-fila__forma input[type="text"] {
  display: block; width: calc(100% - 24px); margin: 10px 12px 0;
  /* 16 px para que iOS no haga zoom al enfocar, como en toda la flota. */
  font-size: 16px; padding: 8px 10px;
  border: 1px solid var(--c-border-strong); border-radius: var(--radius-sm);
  background: var(--c-surface); color: var(--c-text);
}

/* ===================================================================== 20.
   CABECERA OPERATIVA Y TABLERO DE INDICADORES — 2026-09-22, D-707

   Agustín, 22/sep/2026: *«cuando hicimos más simple la aplicación se perdió
   algo de estilo… se siguen calculando los datos pero ahora se ven más feos;
   quisiera mantener cierta estructura para que dé un feeling de dashboard
   operativo aunque no se agreguen datos nuevos»*.

   Lo que se perdió no fueron datos: fue **estructura**. D-691 sustituyó las
   tarjetas por píldoras de texto de ancho desigual y el contexto de la
   pantalla por un párrafo gris. Esta sección devuelve la estructura **sin
   devolver los elementos**: las mismas cifras, el mismo número, el mismo
   comportamiento de filtro.

   Es sólo visual: ninguna cifra cambia de definición, de fuente ni de Permiso.
   ===================================================================== */

/* El fondo «tantito gris» que pidió Agustín el 22/sep/2026 se fija en los
   tokens (sección 1), una sola vez — D-801. */

/* ---------------------------------------------- 20.1 CABECERA OPERATIVA */

/* Módulo · título · acciones, y debajo la cinta con el dato ambiental. La
   MISMA pieza en el Dashboard y en toda pantalla de trabajo. */
/* 2026-10-06 (D-801) — **la cabecera deja de ser una tarjeta.** Agustín aprobó
   la primera prioridad de la propuesta de diseño: *«cabecera más corta,
   identidad presente»*. Título, acciones y cinta siguen siendo la misma pieza;
   lo que se va es la caja blanca que sólo introducía la pantalla y le quitaba
   un renglón a la gráfica y al trabajo. Una raya fina la separa del contenido. */
.jefe {
  padding: 0 0 14px; margin: 0 0 var(--sp-4);
  border-bottom: 1px solid var(--c-border);
}
.jefe--sin-cinta { padding-bottom: 14px; }
.jefe__fila {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--sp-5); flex-wrap: wrap;
}
.jefe__modulo {
  display: block; font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--c-text-3); margin-bottom: 4px;
}
.jefe__titulo { font-size: var(--fs-2xl); margin: 0; line-height: 1.15; letter-spacing: -.02em; }
.jefe__sub { margin: 6px 0 0; color: var(--c-text-2); max-width: 86ch; }
.jefe__acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* La cinta: lo que hoy iba en un párrafo gris —consultado, tipo de cambio—,
   cada dato con su rótulo encima y su valor debajo. */
.cinta {
  display: flex; flex-wrap: wrap;
  margin: 12px 0 0; padding: 10px 0 0;
  border-top: 1px solid var(--c-border-soft);
}
.cinta__dato { padding: 2px 20px 2px 0; margin-right: 20px; border-right: 1px solid var(--c-border); }
.cinta__dato:last-child { border-right: 0; margin-right: 0; }
.cinta__et {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--c-text-3);
}
.cinta__val { font-size: var(--fs-sm); font-weight: 700; color: var(--c-text); font-variant-numeric: tabular-nums; }
.cinta__val small { font-weight: 600; color: var(--c-text-2); }

/* 2026-09-25 — **la cinta al lado del título, no debajo.** Agustín: *«poner el
   tipo de cambio más alineado con "Panel general", a la derecha, ahorrándonos
   ahí unos renglones»*. Es la MISMA cinta con los mismos datos: lo que cambia
   es que deja de ser una franja a sangre bajo el título y se alinea a su
   derecha. En pantalla angosta vuelve a ser una franja, porque al lado del
   título no cabe. */
.cinta--alineada {
  margin: 0; padding: 0; border-top: 0; background: none;
  align-items: flex-start; justify-content: flex-end; row-gap: 8px;
}
.cinta--alineada .cinta__dato:last-child { padding-right: 0; }
@media (max-width: 980px) {
  .cinta--alineada {
    width: 100%; justify-content: flex-start;
    margin-top: 12px; padding-top: 10px;
    border-top: 1px solid var(--c-border-soft);
  }
}

/* ------------------------------------------------- 20.2 TABLERO DE CIFRAS */

/* Sustituye a la fila de píldoras de D-691. Mismo contenido y mismo
   comportamiento —cada tarjeta ES un filtro o un destino—; lo que cambia es
   que todas miden lo mismo y la cifra manda sobre su nombre. */
/* **Cuatro columnas fijas, no `auto-fit`** — corregido el 22/sep/2026 con la
   pantalla ancha de Agustín delante: *«no me encanta ese acomodo de tarjetas
   en la pantalla completa de mi computadora»*.

   Con `auto-fit` el número de columnas lo decidía el ancho disponible, así que
   en su monitor las seis cifras caían **4 + 2**: dos tarjetas sueltas abajo y
   medio renglón vacío a la derecha. Con cuatro columnas el reparto es siempre
   el mismo y siempre cuadra: las dos que resumen el negocio ocupan dos
   columnas cada una y llenan la primera fila; las otras cuatro, una cada una,
   llenan la segunda. Sin tarjetas huérfanas y sin huecos. */
.tablero {
  display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-4);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
/* Una lista trae CUATRO cifras como mucho y ninguna destacada: las cuatro
   columnas le vienen justas. */
.tablero__t {
  display: flex; flex-direction: column; gap: 2px; justify-content: flex-start;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-top: 3px solid var(--c-border-strong);
  border-radius: var(--radius-lg);
  padding: 14px 16px; text-decoration: none; color: inherit;
  min-width: 0; min-height: 116px;
  transition: box-shadow .12s ease, transform .12s ease;
}
a.tablero__t:hover { box-shadow: 0 6px 16px rgba(19, 25, 36, .10); transform: translateY(-1px); }
a.tablero__t:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* **La jerarquía: la cifra que resume el negocio ocupa el doble.** Con todas
   del mismo tamaño la pantalla no dice qué mirar primero, y una venta del mes
   pesaba lo mismo que un conteo de entregas. */
.tablero__t--doble { grid-column: span 2; }

.tablero__t--acento { border-top-color: var(--c-franja-acento); }
.tablero__t--ok     { border-top-color: var(--c-franja-ok); }
.tablero__t--aten   { border-top-color: var(--c-franja-aten); }
.tablero__t--bloq   { border-top-color: var(--c-franja-bloq); }
/* «Estás viendo esto»: el mismo significado que tenía `.cifra--on`. */
.tablero__t--on { border-color: var(--c-accent-line); background: var(--c-accent-soft); }

.tablero__et {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--c-text-2);
  display: flex; gap: 7px;
  /* **El rótulo se parte antes que cortarse.** Con `nowrap` y puntos
     suspensivos, «Cuentas por cobrar · vencido» se leía «Cuentas por cobrar ·
     ·» en la tarjeta compacta, que no dice nada. Dos líneas como mucho, para
     que la tarjeta no crezca por un nombre largo. */
  min-height: 24px; align-items: flex-start; line-height: 1.35;
}
/* La caja del icono no se estira cuando el rótulo ocupa dos líneas. */
.tablero__et .cajita { margin-top: -1px; }
.tablero__cifra {
  font-size: 1.6rem; font-weight: 700; line-height: 1.1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--c-text);
  display: block;
}
/* Dos monedas en la misma tarjeta —`MXN $36,545.80 · USD $51,304.93`— caben
   con el cuerpo un punto más chico, partiendo por el separador. La cifra NO se
   parte en el marcado: RN-138 la quiere entera. */
.tablero__cifra--larga { font-size: 1.15rem; line-height: 1.35; }
.tablero__t--doble .tablero__cifra { font-size: 2rem; }
.tablero__t--doble .tablero__cifra--larga { font-size: 1.35rem; }
/* **El pie, dos líneas como mucho.** El detalle de Ventas trae cuatro datos y
   estiraba su tarjeta hasta descuadrar la fila entera; el texto completo sigue
   en el `title` y, entero, en la pantalla que produce la cifra. */
.tablero__pie {
  font-size: var(--fs-sm); color: var(--c-text-2); margin-top: 3px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow: hidden;
}
.tablero__pie b { color: var(--c-text); font-variant-numeric: tabular-nums; }

/* D-815 — **las tarjetas de cifras, centradas y con peso.** Agustín,
   7/oct/2026: *«se podrían centrar los números de las tarjetas del header… se
   ven muy pobres, bajo construcción»*. Eran rótulo, número y frase pegados a la
   izquierda con mucho aire a la derecha. Ahora todo va al centro, la cifra crece
   y lleva el color de su tarjeta, el icono —donde lo hay— va encima del rótulo,
   y un cero se apaga: «0 por reconciliar» es una buena noticia, no un aviso. */
.tablero__t {
  align-items: center; text-align: center; justify-content: center; gap: 4px;
  padding: 16px 18px 14px; min-height: 124px;
  box-shadow: var(--shadow-xs);
}
.tablero__et { flex-direction: column; align-items: center; justify-content: center; gap: 6px; }
.tablero__et .cajita { width: 30px; height: 30px; border-radius: 9px; margin: 0; }
.tablero__cifra { font-size: 2.1rem; font-weight: 750; margin: 2px 0; }
.tablero__t--acento .tablero__cifra { color: var(--c-accent-dark); }
.tablero__t--ok .tablero__cifra { color: var(--s-ok-fg); }
.tablero__t--aten .tablero__cifra { color: var(--s-aten-fg); }
.tablero__t--bloq .tablero__cifra { color: var(--s-bloq-fg); }
.tablero__t--cero .tablero__cifra { color: var(--c-text-3); }
.tablero__cifra--larga { font-size: 1.25rem; }
.tablero__t--doble .tablero__cifra { font-size: 2.4rem; }
.tablero__pie { max-width: 30ch; }

/* La chispa: la serie que la cifra ya resume, sin ejes y sin números. No es
   una gráfica nueva —los números están en la pantalla de su módulo—: es la
   forma de los últimos meses. */
.chispa { display: block; width: 100%; height: 26px; margin-top: 8px; }

/* El icono, en caja tonal y del mismo tamaño en todas las tarjetas. */
.cajita {
  width: 24px; height: 24px; border-radius: 7px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-accent-soft); color: var(--c-accent-dark);
}
.cajita--ok   { background: var(--s-ok-bg);   color: var(--s-ok-fg); }
.cajita--aten { background: var(--s-aten-bg); color: var(--s-aten-fg); }
.cajita--bloq { background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.cajita .ic { width: 14px; height: 14px; }

/* En pantalla angosta la tarjeta doble deja de serlo: con dos columnas, una
   que ocupa las dos es una fila entera para una sola cifra. */
/* De tableta para abajo, dos columnas: cuatro tarjetas en una fila se quedan
   sin sitio para la cifra, que es lo que hay que leer. La destacada ocupa la
   fila entera. */
@media (max-width: 1100px) {
  .tablero { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .cinta__dato { border-right: 0; margin-right: 14px; }
}

/* --- 20.3 La línea del margen sobre las barras de Ventas — D-707 ---------
   La misma serie que ya se leía como porcentajes bajo cada mes, dibujada
   encima: un mes alto con margen bajo se ve sin comparar dos renglones. Los
   porcentajes se quedan, porque la línea da la forma y ellos la cifra. */
.chart__cols { position: relative; }
.chart__margen {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; overflow: visible;
}
.chart__margen polyline { opacity: .95; }
.chart__leyenda { color: var(--c-gamma); font-weight: 650; }

/* ===================================================================== 21.
   LA MISMA FAMILIA EN TODA LA APLICACIÓN — 2026-09-23, D-708

   Agustín, después de ver el Dashboard con la cabecera y el tablero de D-707:
   *«revisar toda la aplicación con ese criterio y mejorarla»*.

   Lo que había: **dos componentes para lo mismo**. Las listas nuevas usaban el
   tablero —rótulo arriba, cifra grande a la izquierda, franja de color—, y las
   de Maestros y Reportes seguían con la tarjeta KPI centrada, con su icono
   grande en medio. La misma información, dos lenguajes, y la aplicación
   parecía dos aplicaciones.

   Aquí **no se toca ningún marcado**: la tarjeta KPI adopta el lenguaje del
   tablero por CSS, igual que la pasada visual anterior redefinió el aspecto de
   163 plantillas sin reescribirlas. Ninguna cifra cambia de definición, de
   fuente ni de Permiso.
   ===================================================================== */

/* --- 21.1 La tarjeta KPI habla el idioma del tablero -------------------- */
.stat--kpi {
  align-items: flex-start; text-align: left; gap: 3px;
  padding: 14px 16px;
  border-top: 3px solid var(--c-franja-acento);
}
.stat--kpi.stat--ok   { border-top-color: var(--c-franja-ok); }
.stat--kpi.stat--aten { border-top-color: var(--c-franja-aten); }
.stat--kpi.stat--bloq { border-top-color: var(--c-franja-bloq); }
/* **La cifra vuelve a negro y el rótulo a gris**: el color vive en la franja,
   como en el tablero. Teñir la cifra entera de ámbar la hacía competir con la
   de al lado por atención, y con tres tarjetas de tres tonos la fila parecía
   un semáforo. El estado se sigue viendo —en la franja, en el icono y en su
   nota—, pero la cifra se lee primero por ser una cifra. */
.stat--kpi.stat--aten .stat__value,
.stat--kpi.stat--ok   .stat__value,
.stat--kpi.stat--bloq .stat__value { color: var(--c-text); }
.stat--kpi .stat__label { color: var(--c-text-2); }

/* **El rótulo va ARRIBA y la cifra debajo**, como en el tablero. El marcado
   las escribe al revés —`_kpi.html` pinta primero el valor— y se reordena con
   `order`, que es exactamente para esto: cambiar el orden visual sin tocar el
   documento ni el orden de lectura de un lector de pantalla. */
.stat--kpi .icobox { order: 0; margin-bottom: 2px; }
.stat--kpi .stat__label { order: 1; }
.stat--kpi .stat__value { order: 2; font-size: 1.6rem; line-height: 1.1; }
.stat--kpi .stat__value--sm { font-size: 1.25rem; }
.stat--kpi .delta { order: 3; align-self: flex-start; }
.stat--kpi .spark { order: 4; }
.stat--kpi .stat__meta { order: 5; text-align: left; }
.stat--kpi .stat__foot { order: 9; text-align: left; }

/* El icono, en caja pequeña y cuadrada: el círculo grande centrado era lo que
   más separaba a esta tarjeta de la del tablero. */
.stat--kpi .icobox {
  width: 24px; height: 24px; flex: none; border-radius: 7px;
}
.stat--kpi .icobox .ic { width: 14px; height: 14px; }

/* --- 21.2 La cabecera de pantalla, la misma en todas ------------------- */

/* `.jefe` nació en el Dashboard (D-707) y **el resto de la aplicación seguía
   con el título suelto sobre el fondo**. En vez de reescribir la cabecera de
   163 plantillas, `.screen__head` adopta aquí la misma pieza que `.jefe`.

   2026-10-06 (D-801): esa pieza **ya no es una tarjeta**. Título y acciones
   van sobre el fondo, con una raya fina debajo que los separa del contenido:
   la cabecera mide menos y el trabajo empieza antes. Sigue siendo la misma en
   todas las pantallas, y por eso vive aquí y no plantilla por plantilla.

   **Dentro de una ficha no**: ahí la cabecera ya vive dentro de su propia
   tarjeta y meterla en otra la enmarcaría dos veces. */
.workarea > .screen__head,
.workarea > form > .screen__head {
  padding: 0 0 14px;
  border-bottom: 1px solid var(--c-border);
  margin-bottom: var(--sp-4);
  align-items: center;
}
.workarea > .screen__head .screen__title,
.workarea > form > .screen__head .screen__title { margin-bottom: 0; }

/* --- 21.3 Ninguna tarjeta se queda huérfana en la última fila ----------
   `Abastecimiento` abría con seis cifras y en pantalla ancha caían **5 + 1**:
   la sexta sola, ocupando un quinto del renglón y dejando el resto vacío. Es
   el mismo hueco que Agustín señaló en el Dashboard, y sale de `auto-fit`:
   las filas comparten columnas, así que la última se queda con las que sobran.

   El reparto se decide por **cuántas tarjetas hay**, que es lo que `:has()`
   permite preguntar sin tocar el marcado: seis van en dos filas de tres,
   cuatro en una de cuatro, y así. En pantalla angosta manda la media query de
   siempre y todo se apila. */
@media (min-width: 1101px) {
  .stats:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stats:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .stats:has(> :nth-child(5):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .stats:has(> :nth-child(6):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stats:has(> :nth-child(8):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* Nueve o más: cuatro por fila y la última se completa con las que haya.
     Pasado cierto número, una fila incompleta ya no se lee como un olvido. */
}
@media (max-width: 1100px) {
  .stats, .stats--4, .stats--dashboard, .stats--panel-rest {
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  }
}

/* =========================================================================
   LA PANTALLA DEL PRECIO — D-763, 28/09/2026
   =========================================================================
   Agustín, al recorrer el proceso completo: *«los botones de cliente recoge y
   moneda están grandes y aburridas, podría ser algo con iconos con colores
   mejor ordenados; días de vigencia pueden ser botones»*, y sobre el conjunto
   de la aplicación: *«muchas páginas ahorita siento que están muy planas y no
   invitan a leer»*.

   Cada Material deja de ser un renglón de tabla y pasa a ser una tarjeta: el
   precio, sus dos referencias y el importe caben juntos, se leen de un vistazo
   y no hay barra horizontal. Las referencias **se pican**: picar un escalón del
   precio guía escribe ese precio.                                           */

.cotizar { display: flex; flex-direction: column; gap: var(--sp-4, 16px); }
.cotizar__lineas { display: grid; gap: var(--sp-3, 12px); }

.preciocard {
  position: relative;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-left: 3px solid var(--c-franja-acento);
  border-radius: var(--radius);
  padding: 16px 18px;
  display: grid;
  gap: 14px;
  box-shadow: var(--shadow-1, 0 1px 2px rgba(19, 25, 36, .05));
}
/* La casilla es lo que el formulario envía; el botón `Quitar` es su etiqueta. */
.preciocard__incluir {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
}
.preciocard:has(.preciocard__incluir:not(:checked)) {
  border-left-color: var(--c-border-strong);
  background: var(--c-surface-alt);
}
.preciocard:has(.preciocard__incluir:not(:checked)) .preciocard__material {
  text-decoration: line-through; color: var(--c-text-3);
}
.preciocard:has(.preciocard__incluir:not(:checked)) .refs,
.preciocard:has(.preciocard__incluir:not(:checked)) .preciocard__captura { opacity: .4; }

.preciocard__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.preciocard__material { font-size: var(--fs-lg); font-weight: 700; margin: 0; line-height: 1.25; }
.preciocard__volumen { margin: 2px 0 0; color: var(--c-text-2); font-size: var(--fs-sm); }

/* --- Las dos referencias, lado a lado ---------------------------------- */
.refs { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-start; }
.refs__bloque { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.refs__titulo {
  margin: 0; font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--c-text-2); display: flex; align-items: center; gap: 6px;
}
.refs__escalones { display: flex; gap: 6px; flex-wrap: wrap; }

.escalon {
  display: flex; flex-direction: column; gap: 1px; cursor: pointer; text-align: left;
  background: var(--c-surface-alt); border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm, 6px); padding: 7px 11px; min-height: 44px;
  font-family: inherit;
}
.escalon:hover { border-color: var(--c-accent); background: var(--c-accent-soft); }
.escalon:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.escalon__margen {
  font-size: var(--fs-xs); font-weight: 650; color: var(--c-text-2);
  text-transform: uppercase; letter-spacing: .05em;
}
.escalon__precio {
  font-size: var(--fs); font-weight: 700; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* El escalón del objetivo del negocio: es el que se mira primero. */
.escalon--objetivo {
  border-color: var(--s-ok-bd); background: var(--s-ok-bg);
}
.escalon--objetivo .escalon__margen,
.escalon--objetivo .escalon__precio { color: var(--s-ok-fg); }
.escalon--objetivo:hover { border-color: var(--s-ok-fg); }
/* El histórico no es una sugerencia: es un hecho, y va en otro tono. */
.escalon--historico { border-color: var(--c-teal-line); background: var(--c-teal-soft); }
.escalon--historico .escalon__precio { color: var(--c-teal); }

/* --- La captura del precio --------------------------------------------- */
.preciocard__captura {
  display: grid; gap: 4px 16px; align-items: start;
  grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
  grid-template-areas: "label importe" "campo importe" "margen importe";
  padding-top: 12px; border-top: 1px solid var(--c-border-soft);
}
.preciocard__label { grid-area: label; font-weight: 650; font-size: var(--fs-sm); }
.preciocard__captura .quotable__price { grid-area: campo; width: 100%; min-height: 44px; }
.preciocard__captura .margen { grid-area: margen; }
.preciocard__importe {
  grid-area: importe; display: flex; flex-direction: column; gap: 2px;
  align-items: flex-end; text-align: right;
}
.preciocard__importe b {
  font-size: var(--fs-xl, 1.25rem); font-weight: 750; font-variant-numeric: tabular-nums;
}
@media (max-width: 640px) {
  .preciocard__captura {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "label" "campo" "margen" "importe";
  }
  .preciocard__importe { align-items: flex-start; text-align: left; }
}

/* --- El total, que antes sólo existía en el PDF ------------------------- */
.cotizar__total .panel__body { padding-block: 14px; }
.totales { display: flex; flex-direction: column; gap: 6px; margin-left: auto; max-width: 22rem; }
.totales__fila {
  display: flex; justify-content: space-between; gap: 24px;
  font-variant-numeric: tabular-nums; color: var(--c-text-2);
}
.totales__fila b { color: var(--c-text); font-weight: 650; }
.totales__fila--gran {
  border-top: 2px solid var(--c-text); padding-top: 8px; margin-top: 2px;
  font-size: var(--fs-lg); color: var(--c-text);
}
.totales__fila--gran b { font-weight: 800; }

/* --- Las condiciones, en tarjetas con icono ----------------------------- */
.cotizar__condiciones { display: flex; flex-direction: column; gap: var(--sp-4, 16px); }
.opgrid { border: 0; padding: 0; margin: 0; }
.opgrid legend { font-weight: 700; margin-bottom: 8px; padding: 0; }
.opgrid__fila { display: flex; gap: 10px; flex-wrap: wrap; }

.opcard {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  border: 1.5px solid var(--c-border-strong); border-radius: var(--radius);
  background: var(--c-surface); padding: 10px 16px 10px 12px; min-height: 48px;
  font-weight: 650;
}
.opcard input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.opcard__ico {
  display: inline-grid; place-items: center; width: 32px; height: 32px; flex: 0 0 auto;
  border-radius: 8px; background: var(--c-surface-sunk); color: var(--c-text-2);
}
.opcard__ico svg { width: 18px; height: 18px; }
.opcard__ico--sigla { font-size: 12px; font-weight: 800; letter-spacing: .02em; }
.opcard:hover { border-color: var(--c-accent-line); }
.opcard:has(input:checked) {
  border-color: var(--c-accent); background: var(--c-accent-soft); color: var(--c-accent-dark);
}
.opcard:has(input:checked) .opcard__ico { background: var(--c-accent); color: #fff; }
.opcard:has(input:focus-visible) { outline: 2px solid var(--c-accent); outline-offset: 2px; }
/* «Entrega PQG» lleva el verde de la casa cuando se elige: es lo que hacemos
   nosotros. «Cliente recoge» se queda en el azul de producto. */
.opcard--entrega:has(input:checked) {
  border-color: var(--c-gamma); background: #e8f8f0; color: var(--s-ok-fg);
}
.opcard--entrega:has(input:checked) .opcard__ico { background: var(--c-gamma); }

.diaschip {
  cursor: pointer; font-family: inherit; font-size: var(--fs-sm); font-weight: 650;
  border: 1px solid var(--c-border-strong); border-radius: var(--radius-pill);
  background: var(--c-surface); color: var(--c-text-2); padding: 10px 16px; min-height: 44px;
}
.diaschip:hover { border-color: var(--c-accent); color: var(--c-accent-dark); }
.diaschip[aria-pressed="true"] {
  border-color: var(--c-accent); background: var(--c-accent-soft); color: var(--c-accent-dark);
}
.diaschip:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.field--angosto { max-width: 12rem; }

/* El pie de un documento comercial: subtotal, IVA y total — D-763. */
tfoot .tfoot--gran th, tfoot .tfoot--gran td {
  border-top: 2px solid var(--c-text); font-size: var(--fs-lg);
}
tfoot th[scope="row"] { font-weight: 650; color: var(--c-text-2); text-align: right; }
tfoot .tfoot--gran th { color: var(--c-text); font-weight: 800; }

/* =========================================================================
   QUÉ LLEVA ESTE PEDIDO — D-763
   =========================================================================
   La tabla de diez columnas que vivía plegada pasa a tarjetas. Cada Material
   se lee entero sin barra horizontal, con su importe, y el Pedido deja de
   abrir por su checklist.                                                   */

.lineacards { display: grid; gap: 10px; }
.lineacard {
  display: grid; gap: 10px;
  border: 1px solid var(--c-border); border-left: 3px solid var(--c-franja-acento);
  border-radius: var(--radius); background: var(--c-surface-alt); padding: 14px 16px;
}
.lineacard--off { border-left-color: var(--c-border-strong); opacity: .6; }
.lineacard__id { display: flex; flex-direction: column; gap: 6px; }
/* Manda sobre la regla general de `h3` dentro de un panel, que va en
   versalitas: el nombre de un Material se lee, no se grita. */
.panel__body h3.lineacard__material {
  margin: 0; font-size: var(--fs); font-weight: 700; line-height: 1.25;
  text-transform: none; letter-spacing: 0; color: var(--c-text);
  padding-bottom: 0; border-bottom: 0;
}
.lineacard__meta { margin: 0; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.chip--fecha { display: inline-flex; align-items: center; gap: 5px; }
.chip--fecha svg { width: 13px; height: 13px; }

.lineacard__cifras {
  display: grid; gap: 10px 22px;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  padding-top: 10px; border-top: 1px solid var(--c-border-soft);
}
.dato { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.dato__rotulo {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em;
  color: var(--c-text-2); font-weight: 650;
}
.dato__valor { font-size: var(--fs-lg); font-weight: 700; font-variant-numeric: tabular-nums; }
.dato__pie { font-size: var(--fs-xs); color: var(--c-text-3); }
.dato--importe { text-align: right; }
.dato--importe .dato__valor { color: var(--c-accent-dark); }
@media (max-width: 560px) { .dato--importe { text-align: left; } }

.lineacard__cobertura { margin: 0; font-size: var(--fs-sm); color: var(--c-text-2); }
.lineacard__origen {
  display: flex; flex-direction: column; gap: 4px;
  font-size: var(--fs-sm); color: var(--c-text-2);
}
.lineacard__origen p { margin: 0; }
.lineacard__acciones { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.totales--pedido { margin-top: 14px; }

/* El checklist de Preparación, en rejilla y agrupado por Material — D-763.
   Diez requisitos apilados a ancho completo ocupaban dos pantallas y repetían
   el nombre del Material en cada renglón. La rejilla los pone de dos en dos y
   el rótulo del Material dice cuántos faltan, que es lo que se venía a saber. */
/* D-810 — «Imprimir los N documentos», arriba del checklist. */
.imprimir-todo { margin: 0 0 var(--sp-3); }
.tarjetas--checklist {
  display: grid; gap: 8px; list-style: none; padding: 0; margin: 0 0 var(--sp-4, 16px);
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}
.tarjetas--checklist .tarjeta { margin: 0; }
.panel__body h3.checklist__material {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: var(--fs); text-transform: none; letter-spacing: 0;
  color: var(--c-text); font-weight: 700; border-bottom: 0; padding-bottom: 0;
  margin: var(--sp-4, 16px) 0 var(--sp-2, 8px);
}
.panel__body h3.checklist__material:first-child { margin-top: 0; }


/* D-814 — el desglose de «Por mover» en botones: cada paso del día abre su
   parte de la lista. */
.pasos-hoy { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-2); }
.pasos-hoy__paso {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 6px 12px; border: 1px solid var(--c-border); border-radius: var(--radius-pill);
  background: var(--c-surface); color: var(--c-text-2); text-decoration: none; font-size: var(--fs-sm);
}
.pasos-hoy__paso b { color: var(--c-text); font-size: var(--fs); font-variant-numeric: tabular-nums; }
.pasos-hoy__paso:hover { border-color: var(--c-accent); color: var(--c-text); }
.pasos-hoy__paso--on { border-color: var(--c-accent); background: var(--c-accent-soft); color: var(--c-text); }
.tabs__porque { margin: 0 0 var(--sp-3); }

/* D-816 — la barra de avance de la preparación y los requisitos en botones.
   Se rellena con cada requisito cumplido; completa, se pone verde. */
.prep-avance { display: flex; align-items: center; gap: 10px; margin: 8px 0 6px; width: 100%; max-width: 30rem; }
.prep-avance__barra {
  flex: 1 1 auto; height: 8px; border-radius: var(--radius-pill);
  background: var(--c-border-soft); overflow: hidden;
}
.prep-avance__relleno {
  display: block; height: 100%; border-radius: inherit;
  background: var(--c-franja-aten); transition: width .4s ease;
}
.prep-avance__texto { font-size: var(--fs-sm); color: var(--c-text-2); white-space: nowrap; display: inline-flex; align-items: center; gap: 4px; }
.prep-avance__texto b { color: var(--c-text); }
.prep-avance--ok .prep-avance__relleno { background: var(--s-ok-fg); }
.prep-avance--ok .prep-avance__texto { color: var(--s-ok-fg); font-weight: 650; }
.prep-avance--ok .prep-avance__texto svg { width: 15px; height: 15px; }
.req-linea { margin: 6px 0 0; }
.req-linea__material { display: block; font-size: var(--fs-xs); font-weight: 650; color: var(--c-text-2); margin-bottom: 4px; text-transform: uppercase; letter-spacing: .04em; }
.req-linea__botones { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.req-linea__botones form { margin: 0; }
.req {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 4px 3px 10px; border: 1px solid var(--c-border); border-radius: var(--radius-pill);
  background: var(--c-surface); font-size: var(--fs-sm);
}
.req__marca { width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--c-franja-aten); flex: none; }
.req__nombre { color: var(--c-text); white-space: nowrap; }
.req form { margin: 0; }
.req .btn { padding: 2px 9px; min-height: 26px; font-size: var(--fs-xs); }

/* D-817 — «Sugerencia de hoy» en Mi panel: dos columnas de paradas. */
.sugerencia__cols { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
.sugerencia__titulo { font-size: var(--fs-sm); font-weight: 700; color: var(--c-text-2); margin: 0 0 8px; text-transform: uppercase; letter-spacing: .05em; }
.sugerencia__fila {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
  border: 1px solid var(--c-border); border-radius: var(--radius-sm, 6px);
  background: var(--c-surface-alt); padding: 9px 12px; margin-bottom: 6px;
  text-decoration: none; color: inherit;
}
.sugerencia__fila:hover { border-color: var(--c-accent); background: var(--c-accent-soft); }
.sugerencia__quien { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sugerencia__meta { font-size: var(--fs-sm); color: var(--c-text-2); }

/* D-818 — «Sigue: …» debajo del aviso de «listo». */
.siguiente-paso { display: flex; align-items: center; gap: 10px; font-weight: 650; }
.siguiente-paso .btn svg { margin-left: 4px; }

/* D-819 — la bandeja en cero dice lo que se cerró hoy. */
.vacio__hoy { font-weight: 700; color: var(--s-ok-fg); margin: 2px 0 4px; }

/* D-828 — **«Tu registro»**, junto a la campana. Una bitácora, no una meta:
   el ícono siempre está, el número es gris y nada cambia de color según cómo
   vas. Agustín: *«que parezca más como un control automático, no como un
   motivador»*. */
.registro-g { position: relative; }
.registro-g__abrir {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%; cursor: pointer; list-style: none;
  color: var(--c-text-2);
}
.registro-g__abrir::-webkit-details-marker { display: none; }
.registro-g__abrir:hover, .registro-g[open] .registro-g__abrir { background: var(--c-surface-2, rgba(0,0,0,.05)); }
.registro-g__abrir:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.registro-g__n {
  position: absolute; top: -2px; right: -5px;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--c-surface-sunk); border: 1px solid var(--c-border-strong);
  color: var(--c-text-2); font-size: 11px; font-weight: 700; line-height: 16px;
  text-align: center; font-variant-numeric: tabular-nums;
}
.registro-g__caja {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 60;
  width: min(360px, calc(100vw - 32px)); padding: 14px 16px 12px;
  background: var(--c-surface); border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  color: var(--c-text); font-size: var(--fs-sm);
}
.registro-g__titulo { margin: 0; font-weight: 700; font-size: var(--fs-md); }
.registro-g__nota { margin: 0 0 10px; font-size: var(--fs-xs); color: var(--c-text-3); }
.registro-g__dia { margin: 0 0 2px; font-weight: 650; color: var(--c-text-2); }
.registro-g__lista { list-style: none; margin: 0; padding: 0; }
.registro-g__lista li {
  display: flex; align-items: baseline; gap: 10px; padding: 6px 0;
  border-top: 1px solid var(--c-border-soft);
}
.registro-g__hora { flex: none; min-width: 3.2em; color: var(--c-text-3); font-variant-numeric: tabular-nums; }
.registro-g__que { flex: none; }
.registro-g__de {
  flex: 1 1 auto; min-width: 0; text-align: right; color: var(--c-text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.registro-g__lista .registro-g__mas { color: var(--c-text-3); padding-left: calc(3.2em + 10px); }
.registro-g__vacio { margin: 4px 0 0; color: var(--c-text-3); }
.registro-g__semana {
  list-style: none; margin: 10px 0 0; padding: 10px 0 0; border-top: 1px solid var(--c-border);
  display: flex; gap: 6px; justify-content: space-between;
}
.registro-g__semana li { display: flex; flex-direction: column; align-items: center; min-width: 26px; }
.registro-g__semana span { font-size: var(--fs-xs); color: var(--c-text-3); }
.registro-g__semana b { font-weight: 650; font-variant-numeric: tabular-nums; }
.registro-g__hoy span { color: var(--c-text); font-weight: 700; }
.registro-g__semana .registro-g__total { margin-left: auto; align-items: flex-end; }
.registro-g__antes { margin: 8px 0 0; font-size: var(--fs-xs); color: var(--c-text-3); }

/* D-823 — **el color de cada renglón dice lo que significa.** Amarillo lo
   vencido o atrasado, rojo lo muy vencido, y sin color lo que va bien: si todo
   llevara color, nada resaltaría. En tarjeta (teléfono, o tabla que no cabe) es
   el borde izquierdo de la tarjeta; en la tabla de escritorio, la raya de la
   primera celda (ver el bloque de la agenda, abajo). */
.table--tarjetas tr.fila--aten { border-left: 4px solid var(--c-franja-aten); }
.table--tarjetas tr.fila--bloq { border-left: 4px solid var(--c-franja-bloq); }

/* =========================================================================
   MI PANEL — D-824: la cabecera que dice cuánto, y gráficas que destacan
   ========================================================================= */
.logro {
  display: grid; gap: var(--sp-3); grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  margin: 0 0 var(--sp-3);
}
.logro--solo { grid-template-columns: minmax(0, 1fr); }
.logro__venta, .logro__ganado, .logro__margen {
  display: flex; flex-direction: column; gap: 4px; text-decoration: none; color: inherit;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs); padding: 20px 24px;
}
.logro__venta { border-top: 4px solid var(--c-franja-acento); justify-content: center; }
.logro__lado { display: grid; gap: var(--sp-3); }
.logro__ganado { border-top: 4px solid var(--c-franja-ok); }
.logro__ganado:hover, .logro__venta a:hover { box-shadow: var(--shadow); }
.logro__rotulo { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--c-text-2); }
.logro__cifra {
  font-size: 2.9rem; font-weight: 800; line-height: 1.05; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--c-text); text-decoration: none;
}
.logro__cifra--dos { font-size: 2rem; color: var(--s-ok-fg); }
.logro__cifra--tres { font-size: 1.6rem; }
.logro__delta, .logro__delta.delta { font-size: var(--fs); font-weight: 650; background: none; border: 0; padding: 0; }
.logro__delta.delta::before { font-size: 11px; margin-right: 4px; }
.logro__delta--sube { color: var(--s-ok-fg); }
.logro__delta--baja { color: var(--s-bloq-fg); }
.logro__antes { font-size: var(--fs-sm); color: var(--c-text-2); font-weight: 400; }
.logro__meta { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.logro__meta .prep-avance__barra { height: 10px; max-width: 22rem; }
.logro__relleno { background: var(--c-franja-acento); }
.logro__relleno--ok { background: var(--s-ok-fg); }
.logro__meta-texto { font-size: var(--fs-sm); color: var(--c-text-2); }
.logro__meta-texto b { color: var(--c-text); }
.logro__chicos { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.pasos-hoy__paso--alerta { border-color: var(--s-bloq-bd); background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.pasos-hoy__paso--alerta b { color: var(--s-bloq-fg); }
@media (max-width: 760px) {
  .logro { grid-template-columns: minmax(0, 1fr); }
  .logro__cifra { font-size: 2.2rem; }
}
.grafica-logro__lead { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: var(--fs-sm); }
.grafica-logro__este b { color: var(--c-franja-acento); }
.grafica-logro__mejor { color: var(--s-ok-fg); }
.grafica-logro__chart .chart__cols { height: 190px; padding-top: 28px; }
.grafica-logro__chart .chart__bar { max-width: 34px; border-radius: 6px 6px 0 0; }
.grafica-logro__chart .chart__col--off .chart__bar { background: var(--c-accent); opacity: .22; }
.grafica-logro__chart .chart__col--off:hover .chart__bar { opacity: .5; }
.grafica-logro__chart .chart__col--actual .chart__bar { background: var(--c-franja-acento); }
.grafica-logro__chart .chart__col--mejor .chart__bar { background: var(--s-ok-fg); }
.grafica-logro__val {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 750; white-space: nowrap; font-variant-numeric: tabular-nums;
  color: var(--c-text); background: var(--c-surface); padding: 1px 6px; border-radius: var(--radius-pill);
  border: 1px solid var(--c-border); z-index: 2;
}
.chart__col--mejor .grafica-logro__val { color: var(--s-ok-fg); border-color: var(--s-ok-bd); }
.chart__col:first-child .grafica-logro__val { left: 0; transform: none; }
.chart__col:last-child .grafica-logro__val { left: auto; right: 0; transform: none; }
.grafica-logro__hoy { color: var(--c-text); font-weight: 700; }

/* D-825 — **las paradas de Mi panel.** Un renglón que se pica entero: el
   Cliente delante, lo que le pasa en segundo plano, el dato que se busca a la
   derecha y una flecha que dice que lleva a algún lado. La raya de color a la
   izquierda sólo cuando distingue algo (vencida, por vencer, al corriente). */
.renglones { display: grid; gap: 6px; }
.renglon {
  display: flex; align-items: center; gap: 14px; min-width: 0;
  border: 1px solid var(--c-border); border-radius: var(--radius-sm, 6px);
  background: var(--c-surface-alt); padding: 10px 12px 10px 14px;
  text-decoration: none; color: inherit;
  transition: border-color .12s ease, background .12s ease, transform .12s ease;
}
a.renglon:hover, .renglon--plegable > summary:hover { border-color: var(--c-accent); background: var(--c-accent-soft); }
a.renglon:hover { transform: translateX(2px); }
.renglon--bloq { box-shadow: inset 4px 0 0 var(--c-franja-bloq); }
.renglon--aten { box-shadow: inset 4px 0 0 var(--c-franja-aten); }
.renglon--ok   { box-shadow: inset 4px 0 0 var(--c-franja-ok); }
.renglon__principal { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; text-decoration: none; color: inherit; }
.renglon__principal b { font-weight: 700; color: var(--c-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.renglon__meta { font-size: var(--fs-sm); color: var(--c-text-2); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.renglon__meta a { color: inherit; }
.renglon__dato { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; flex: none; text-align: right; }
.renglon__dato b { font-size: var(--fs-md, 1.05rem); font-weight: 750; font-variant-numeric: tabular-nums; color: var(--c-text); }
.renglon__dato--ok b { color: var(--s-ok-fg); }
.renglon__rotulo { font-size: var(--fs-xs); font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--c-text-3); }
.renglon__ir { color: var(--c-text-3); flex: none; display: inline-flex; }
.renglon__ir svg { width: 16px; height: 16px; }
.renglon--plegable { display: block; padding: 0; }
.renglon--plegable > summary { display: flex; align-items: center; gap: 14px; padding: 10px 12px 10px 14px; cursor: pointer; list-style: none; border-radius: inherit; }
.renglon--plegable > summary::-webkit-details-marker { display: none; }
.renglon--plegable[open] .renglon__ir { transform: rotate(180deg); }
.renglon__detalle { padding: 4px 14px 12px; display: grid; gap: 4px; border-top: 1px dashed var(--c-border); }
.renglon__linea { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: var(--fs-sm); }
.renglon__linea > span:first-child { flex: 1 1 14rem; color: var(--c-text); }
.renglon__ok { color: var(--s-ok-fg); font-weight: 650; }
@media (max-width: 640px) {
  .renglon { flex-wrap: wrap; }
  .renglon__principal { flex-basis: 100%; }
}
.puede-entrar { margin: 4px 0 0; font-size: var(--fs-sm); color: var(--c-text-2); }
.puede-entrar b { color: var(--s-ok-fg); font-size: var(--fs); }
.cobranza { display: grid; gap: var(--sp-3); }
.cobranza__titulo {
  display: flex; align-items: center; gap: 8px; margin: 0 0 6px;
  font-size: var(--fs-sm); font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
}
.cobranza__titulo span { font-size: var(--fs-xs); border-radius: var(--radius-pill); padding: 1px 8px; }
.cobranza__grupo--bloq .cobranza__titulo { color: var(--s-bloq-fg); }
.cobranza__grupo--bloq .cobranza__titulo span { background: var(--s-bloq-bg); }
.cobranza__grupo--aten .cobranza__titulo { color: var(--s-aten-fg); }
.cobranza__grupo--aten .cobranza__titulo span { background: var(--s-aten-bg); }
.cobranza__grupo--ok .cobranza__titulo { color: var(--s-ok-fg); cursor: pointer; }
.cobranza__grupo--ok .cobranza__titulo span { background: var(--s-ok-bg); }
.meses { display: grid; gap: var(--sp-2); grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); }
.mes {
  display: flex; flex-direction: column; gap: 4px; text-decoration: none; color: inherit;
  border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-surface-alt);
  padding: 12px 14px; transition: border-color .12s ease, transform .12s ease;
}
.mes:hover { border-color: var(--c-accent); transform: translateY(-1px); }
.mes--actual { border-top: 3px solid var(--c-franja-acento); background: var(--c-surface); }
.mes--mejor { border-top: 3px solid var(--c-franja-ok); background: var(--s-ok-bg); }
.mes__nombre { font-size: var(--fs-sm); font-weight: 700; color: var(--c-text-2); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.mes__venta { font-size: 1.35rem; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--c-text); }
.mes__otros { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: var(--fs-sm); color: var(--c-text-2); }
.mes__otros b { color: var(--c-text); font-variant-numeric: tabular-nums; }
.grafica-logro__prom {
  position: absolute; left: 0; right: 0; border-top: 2px dashed var(--c-text-3); opacity: .55; pointer-events: none; z-index: 1;
}
.grafica-logro__prom span {
  position: absolute; right: 0; top: -18px; font-size: var(--fs-xs); font-weight: 650; color: var(--c-text-2);
  background: var(--c-surface); padding: 0 4px; border-radius: 4px;
}
.grafica-logro__chart .chart__cols { position: relative; }
.grafica-logro__vs { font-weight: 650; }
.grafica-logro__vs--sube { color: var(--s-ok-fg); }
.grafica-logro__vs--baja { color: var(--c-text-2); }

/* =========================================================================
   LAS LISTAS CON LA FORMA DE LA AGENDA — D-813
   =========================================================================
   Agustín, 7/oct/2026, sobre la agenda del Calendario: *«se me hace muy limpia,
   me gusta que incluye información que traen otras listas como fecha, folio,
   información, pero presentado de una manera mucho más atractiva… quiero hacer
   las listas más como ésta… no hacerlas idénticas»*.

   En escritorio cada renglón de una lista (`.table--tarjetas`) pasa a ser una
   **parada**: una caja redondeada sobre el panel, separada de la siguiente, con
   el dato principal (`data-titulo`) en negritas y lo demás en segundo plano.
   **Las columnas y el orden por encabezado se conservan**: en una lista de
   cien Facturas hay que poder comparar y ordenar, que es lo que la agenda no
   necesita. En el teléfono ya eran tarjetas (D-687) y no cambia nada, y una
   tabla que el guion apila por no caber (`.tablewrap--apilada`, D-765) tampoco. */
@container tabla (min-width: 821px) {
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas { border-collapse: separate; border-spacing: 0 6px; margin-top: -6px; }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas thead th { background: transparent; border-bottom: 0; padding-bottom: 2px; }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody td {
    background: var(--c-surface-alt);
    border-top: 1px solid var(--c-border); border-bottom: 1px solid var(--c-border);
    padding-top: 9px; padding-bottom: 9px; vertical-align: middle;
  }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr:last-child td { border-bottom: 1px solid var(--c-border); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody td:first-child {
    border-left: 1px solid var(--c-border);
    border-radius: var(--radius-sm, 6px) 0 0 var(--radius-sm, 6px);
  }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody td:last-child {
    border-right: 1px solid var(--c-border);
    border-radius: 0 var(--radius-sm, 6px) var(--radius-sm, 6px) 0;
  }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr:hover { background: transparent; }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr:hover td { border-color: var(--c-accent); background: var(--c-accent-soft); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas td[data-titulo] { font-weight: 650; color: var(--c-text); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas td:not([data-titulo]):not([data-cifra]):not([data-accion]) { color: var(--c-text-2); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas td[data-cifra] { font-weight: 650; color: var(--c-text); }
  /* Los separadores de grupo (un día, un Cliente) no son paradas: son la
     cabecera del bloque, como el día de la agenda. */
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr.rowgroup td {
    background: transparent; border: 0; border-radius: 0;
    padding: 12px 2px 2px; font-weight: 700; color: var(--c-text);
  }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tfoot td { border-radius: var(--radius-sm, 6px); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr.fila--aten td:first-child { box-shadow: inset 4px 0 0 var(--c-franja-aten); }
  .tablewrap:not(.tablewrap--apilada) .table--tarjetas tbody tr.fila--bloq td:first-child { box-shadow: inset 4px 0 0 var(--c-franja-bloq); }
}


/* =========================================================================
   MODO TARJETA CUANDO LA TABLA NO CABE — D-765, 28/09/2026
   =========================================================================
   El modo tarjeta se encendía **sólo** por ancho del contenedor: a 820 px o
   menos. Entre 820 px y lo que la tabla necesita de verdad queda un hueco, y
   ahí caen las pantallas de la oficina. Medido el 28/09/2026 en una ventana de
   1280 px, con la columna de contenido a 1034 px:

       Consulta comercial      necesita 1 718 px   →  684 px fuera de pantalla
       Cuentas por cobrar      necesita 1 794 px   →  760 px fuera
       Pedidos de venta        necesita 1 401 px   →  367 px fuera
       Próximas salidas        cabe, pero con 74 celdas cortadas

   Se quedaban fuera columnas con acciones —`Solicitar precio`, el botón de la
   Línea— y el renglón medía un tercio de pantalla de alto por el texto largo
   de las últimas columnas.

   `static/js/apilar.js` mide la tabla contra su contenedor y, cuando no cabe,
   marca el contenedor: entonces valen estas reglas, que son **exactamente las
   mismas** del modo tarjeta de siempre. Sin JavaScript no cambia nada: la
   tabla ancha sigue con su barra horizontal, como hasta hoy.

   **Este bloque es un gemelo del de la consulta de contenedor de arriba.**
   Una consulta de contenedor no admite una clase como condición, así que las
   mismas declaraciones tienen que existir dos veces.
   `tests/unit/test_tabla_que_no_cabe.py` compara los dos y falla si se
   separan: nadie tiene que acordarse.                                        */
.tablewrap--apilada { overflow-x: visible; }

  .tablewrap--apilada .table--tarjetas td.sel { order: 0; }
  .tablewrap--apilada .table--tarjetas td.sel:empty { display: none; }


  .tablewrap--apilada .table--tarjetas thead th { position: static; }
  .tablewrap--apilada .table--tarjetas tfoot td { position: static; }


  .tablewrap--apilada .table--tarjetas thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .tablewrap--apilada .table--tarjetas, .tablewrap--apilada .table--tarjetas tbody, .tablewrap--apilada .table--tarjetas td { display: block; width: auto; }
  /* 2026-09-21 — **la tarjeta es una columna flex, no un bloque.** Con `block`,
     el orden de la tarjeta era el orden de las columnas de la tabla, así que el
     botón de la primera columna salía **arriba**, antes de saber de qué Pedido
     era. Con flex se puede mandar la acción al final sin mover una sola celda
     del HTML —y por tanto sin cambiar la tabla de escritorio—. */
  .tablewrap--apilada .table--tarjetas tr {
    display: flex; flex-direction: column; width: auto;
    border: 1px solid var(--c-border); border-radius: var(--radius);
    background: var(--c-surface); padding: 10px 12px; margin-bottom: 10px;
  }
  .tablewrap--apilada .table--tarjetas td[data-titulo] { order: 1; }
  .tablewrap--apilada .table--tarjetas td[data-cifra]  { order: 2; }
  .tablewrap--apilada .table--tarjetas td             { order: 3; }
  .tablewrap--apilada .table--tarjetas td[data-extra]  { order: 4; }
  .tablewrap--apilada .table--tarjetas td[data-accion] { order: 5; }
  /* Una celda sin rótulo declarado **no pinta dos puntos huérfanos**. Pasaba en
     los renglones de grupo, que no son datos sino el encabezado de su Pedido:
     la tarjeta abría con «: PED-001914». */
  .tablewrap--apilada .table--tarjetas td:not([data-rotulo])::before { content: ""; }
  /* El renglón de grupo es un encabezado, no una tarjeta: sin caja, sin fondo. */
  .tablewrap--apilada .table--tarjetas tr.rowgroup {
    border: 0; background: none; padding: 6px 2px 2px; margin-bottom: 4px;
    font-size: var(--fs-md);
  }
  /* 2026-09-21 — **la tarjeta alinea a la izquierda, y gana.** `.table .num`
     centra y `.table .mid` también, con más especificidad que `.tablewrap--apilada .table--tarjetas
     td`: dentro de una tarjeta eso dejaba los importes y las fechas centrados
     y el renglón ilegible. Se nombran las dos clases aquí para que la tarjeta
     mande, sin tocar la alineación de la tabla en escritorio. */
  .tablewrap--apilada .table--tarjetas td,
  .tablewrap--apilada .table--tarjetas td.num,
  .tablewrap--apilada .table--tarjetas td.mid,
  .tablewrap--apilada .table--tarjetas td.state,
  .tablewrap--apilada .table--tarjetas td.actions { border: 0; padding: 3px 0; text-align: left; }
  /* `.table .actions` vale `width: 1%` para que la columna de botones no robe
     ancho en escritorio. Dentro de una tarjeta ese 1% aplastaba el botón hasta
     dejar cuatro letras visibles. */
  .tablewrap--apilada .table--tarjetas td.actions { width: auto; white-space: normal; }
  .tablewrap--apilada .table--tarjetas td::before {
    content: attr(data-rotulo) ": "; color: var(--c-text-3); font-size: var(--fs-sm);
  }
  /* 2026-09-21 — **el patrón se declara por atributo, no por el nombre de la
     columna.** Hasta hoy el título de la tarjeta y su botón se reconocían por
     `data-rotulo="Folio"` y `="Siguiente paso"`, así que el patrón sólo servía
     en `Comercial → Pedidos`: cualquier otra lista con otras columnas se
     quedaba sin título y sin botón a todo el ancho. Con `data-titulo` y
     `data-accion` sirve en las 195 tablas. **Las dos reglas viejas se
     conservan** para no romper la pantalla que ya las usaba. */
  .tablewrap--apilada .table--tarjetas td[data-titulo]::before { content: ""; }
  .tablewrap--apilada .table--tarjetas td[data-titulo] { font-size: var(--fs-lg); font-weight: 650; }
  /* D-802 — el gemelo de «la tarjeta se lee por capas» (ver `@container tabla`). */
  .tablewrap--apilada .table--tarjetas tr:not(:has([data-titulo])) td[data-rotulo="Folio"]::before { content: ""; }
  .tablewrap--apilada .table--tarjetas tr:not(:has([data-titulo])) td[data-rotulo="Folio"] { font-size: var(--fs-lg); font-weight: 650; }
  .tablewrap--apilada .table--tarjetas tr:has([data-titulo]) td[data-rotulo="Folio"]:not([data-titulo]) {
    order: 2; font-size: var(--fs-sm); color: var(--c-text-2); font-weight: 600; padding: 1px 0;
  }
  .tablewrap--apilada .table--tarjetas tr:has([data-titulo]) td[data-rotulo="Folio"]:not([data-titulo])::before {
    content: attr(data-rotulo) " "; font-weight: 400;
  }
  .tablewrap--apilada .table--tarjetas td[data-rotulo="Siguiente paso"],
  .tablewrap--apilada .table--tarjetas td[data-accion] { margin-top: 6px; }
  .tablewrap--apilada .table--tarjetas td[data-rotulo="Siguiente paso"] .btn,
  .tablewrap--apilada .table--tarjetas td[data-accion] .btn { width: 100%; justify-content: center; }
  /* La celda de la acción **no lleva rótulo**: el botón ya dice qué hace, y el
     rótulo delante lo dejaba a media línea y encimado. */
  .tablewrap--apilada .table--tarjetas td[data-accion]::before { content: ""; }
  .tablewrap--apilada .table--tarjetas td[data-accion]:empty { display: none; }
  /* La cifra que la persona fue a buscar: grande y con su rótulo delante. */
  .tablewrap--apilada .table--tarjetas td[data-cifra] { font-size: var(--fs-xl); font-weight: 700; margin-top: 2px; }
  .tablewrap--apilada .table--tarjetas td[data-cifra]::before { font-size: var(--fs-sm); font-weight: 400; }
  /* Lo secundario: más chico y apagado, pero **presente**. No se esconde: en un
     teléfono el renglón ya es una tarjeta y lo que sobra estorba menos abajo
     que a 900 px de scroll lateral. */
  .tablewrap--apilada .table--tarjetas td[data-extra] { font-size: var(--fs-sm); color: var(--c-text-3); padding: 1px 0; }
  .tablewrap--apilada .table--tarjetas td[data-extra]:empty { display: none; }
  /* Una celda sin dato no gasta un renglón de la tarjeta. */
  .tablewrap--apilada .table--tarjetas td[data-vacia] { display: none; }


  .tablewrap--apilada .table--tarjetas tr[aria-selected="true"] {
    border-color: var(--c-accent-line);
    box-shadow: inset 3px 0 0 var(--c-accent);
  }
  .tablewrap--apilada .table--tarjetas tr[aria-selected="true"] > td { background: transparent; }
  .tablewrap--apilada .table--tarjetas tr[aria-selected="true"] > td:first-child { box-shadow: none; }
  /* 2026-09-29 — el gemelo de la cola de Preparación y de los nombres largos. */
  .tablewrap--apilada .table--tarjetas.table--cola .cola__franja { display: none; }
  .tablewrap--apilada .table--tarjetas.table--cola tr:has(.franja--tarde) { border-left: 5px solid var(--c-franja-bloq); }
  .tablewrap--apilada .table--tarjetas.table--cola tr:has(.franja--hoy) { border-left: 5px solid var(--c-franja-aten); }
  .tablewrap--apilada .table--tarjetas.table--cola .cola__cliente { font-size: var(--fs-sm); }
  .tablewrap--apilada .table--tarjetas.table--cola td[data-rotulo] { max-width: none; }
  .tablewrap--apilada .table--tarjetas td[data-rotulo="Vencimiento"] { max-width: none; }
  .tablewrap--apilada .table--tarjetas .cell-clip { white-space: normal; overflow: visible; }


/* Los tres escalones del precio guía dentro de una celda — D-763. */
.guiafila { display: inline-flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.guiafila__paso {
  display: inline-flex; flex-direction: column; align-items: flex-end; gap: 0;
  border: 1px solid var(--c-border); border-radius: var(--radius-sm, 6px);
  padding: 3px 8px; background: var(--c-surface-alt); white-space: nowrap;
}
.guiafila__paso--objetivo { border-color: var(--s-ok-bd); background: var(--s-ok-bg); }
.guiafila__paso--objetivo b { color: var(--s-ok-fg); }
.guiafila__margen {
  font-size: var(--fs-xs); color: var(--c-text-2); font-weight: 650; letter-spacing: .04em;
}
/* En tarjeta, los escalones empiezan por la izquierda como el resto del texto.
   Se nombra la celda y no la tabla, para no confundirse con el gemelo del modo
   tarjeta, que `test_tabla_que_no_cabe` compara declaración por declaración. */
td[data-rotulo="Precio guía"] .guiafila { justify-content: flex-end; }
.tablewrap--apilada td[data-rotulo="Precio guía"] .guiafila { justify-content: flex-start; }

/* El recado de quien pidió algo, con su firma — D-766. */
.recado {
  margin: var(--sp-3, 12px) 0 0; padding: 12px 14px;
  background: var(--s-aten-bg); border-left: 3px solid var(--s-aten-bd);
  border-radius: 0 var(--radius) var(--radius) 0; color: var(--c-text);
}
.recado cite {
  display: block; margin-top: 6px; font-style: normal;
  font-size: var(--fs-sm); color: var(--c-text-2);
}
.recado cite::before { content: "— "; }

/* Los precios ya conseguidos de un Material, en la Necesidad — D-766. */
.precios-conseguidos { list-style: none; padding: 0; margin: 0; display: grid; gap: 8px; }
.precios-conseguidos li {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface-alt); padding: 10px 12px;
}

/* «Hoy hay X y se consumen Y al mes» — la leyenda de D-766. */
.leyenda-material {
  display: flex; align-items: flex-start; gap: 10px; margin: 0 0 var(--sp-3, 12px);
  background: var(--c-accent-soft); border-left: 3px solid var(--c-accent-line);
  border-radius: 0 var(--radius) var(--radius) 0; padding: 10px 14px;
  font-size: var(--fs-sm);
}
.leyenda-material svg { width: 18px; height: 18px; flex: 0 0 auto; color: var(--c-accent); }

/* Lo que hay que saber antes de programar un viaje — D-767. */
.viaje-contexto {
  display: grid; gap: 12px; margin-bottom: var(--sp-4, 16px);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.viaje-dato {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-left: 3px solid var(--c-franja-acento);
  border-radius: 0 var(--radius) var(--radius) 0; padding: 12px 14px;
}
.viaje-dato__rotulo {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em;
  color: var(--c-text-2); font-weight: 650;
}
.viaje-dato__rotulo svg { width: 14px; height: 14px; }
.viaje-dato__valor { font-size: var(--fs-lg); font-weight: 700; }
.viaje-dato__valor--falta { color: var(--s-aten-fg); }
.cupos { list-style: none; padding: 0; margin: 0 0 var(--sp-3, 12px); display: grid; gap: 6px; }
.cupos li { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: var(--fs-sm); }

/* =========================================================================
   LA AGENDA DE LOS PRÓXIMOS DÍAS — D-767
   =========================================================================
   Sustituye a la rejilla del mes como vista por omisión del Calendario. Un
   día por bloque, sólo los que tienen algo, y cada parada dice **el Cliente**
   antes que el Vehículo: es lo que se busca al mirar el día.               */

.agenda { display: grid; gap: 14px; }
.agenda__dia {
  display: grid; gap: 10px;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface); padding: 14px 16px;
}
.agenda__dia--hoy { border-color: var(--c-accent); box-shadow: 0 0 0 2px var(--c-accent-soft); }
.agenda__cabeza {
  grid-row: span 2; display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  border-right: 1px solid var(--c-border-soft); padding-right: 12px;
  /* 2026-10-06 (D-802) — la fecha queda anclada mientras se recorren las
     paradas de un día largo. */
  position: sticky; top: calc(var(--topbar-h) + 8px); align-self: start;
}
.agenda__dow {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .07em;
  color: var(--c-text-2); font-weight: 650;
}
.agenda__num { font-size: 1.9rem; font-weight: 750; line-height: 1; }
.agenda__mes { font-size: var(--fs-sm); color: var(--c-text-3); text-transform: uppercase; }
.agenda__paradas { display: grid; gap: 6px; min-width: 0; }

.parada {
  display: grid; gap: 4px 14px; align-items: center; text-decoration: none; color: inherit;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto auto;
  border: 1px solid var(--c-border); border-radius: var(--radius-sm, 6px);
  background: var(--c-surface-alt); padding: 9px 12px;
}
.parada:hover { border-color: var(--c-accent); background: var(--c-accent-soft); }
.parada__hora { font-variant-numeric: tabular-nums; font-weight: 650; color: var(--c-text-2); }
/* D-802 — el Cliente destacado y la carga en segundo plano. */
.parada__quien { display: flex; flex-direction: column; gap: 1px; min-width: 0; font-weight: 650; }
.parada__que { font-size: var(--fs-sm); color: var(--c-text-2); font-weight: 400; }
.parada__vehiculo { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-sm); color: var(--c-text-2); white-space: nowrap; }
.parada__vehiculo svg { width: 15px; height: 15px; }
.parada__folio { font-size: var(--fs-xs); color: var(--c-text-3); white-space: nowrap; }
@media (max-width: 640px) {
  .agenda__dia { grid-template-columns: minmax(0, 1fr); }
  .agenda__cabeza { grid-row: auto; flex-direction: row; align-items: baseline; gap: 8px;
    border-right: 0; border-bottom: 1px solid var(--c-border-soft); padding: 0 0 8px;
    position: static; }
  .parada { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .parada__vehiculo, .parada__folio { grid-column: 2; }
}

/* D-809 — la agenda en amarillo: lo que ya se pasó de fecha y sigue abierto.
   Misma forma que la de los próximos días; cambia el tono y cada parada trae
   qué le falta y su botón en vez de la camioneta. */
.agenda--aten .agenda__dia { border-color: var(--s-aten-bd); }
.agenda--aten .agenda__num { color: var(--s-aten-fg); }
.parada--accion { grid-template-columns: minmax(0, 1fr) auto auto auto; }
.parada--accion:hover { border-color: var(--s-aten-bd); background: var(--c-surface-alt); }
.parada--accion .parada__quien { text-decoration: none; color: inherit; }
.parada--accion .parada__quien:hover b { text-decoration: underline; }
.parada__accion form { margin: 0; }
@media (max-width: 640px) {
  .parada--accion { grid-template-columns: minmax(0, 1fr) auto; }
  .parada--accion .parada__quien { grid-column: 1 / -1; }
}

.agenda__cargas { grid-column: 2; display: flex; gap: 6px; flex-wrap: wrap; }
.carga {
  font-size: var(--fs-xs); font-weight: 650; border-radius: var(--radius-pill);
  padding: 3px 10px; border: 1px solid var(--c-border-strong); color: var(--c-text-2);
}
.carga--ok { background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg); }
.carga--aten { background: var(--s-aten-bg); border-color: var(--s-aten-bd); color: var(--s-aten-fg); }
.carga--bloq { background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }

/* El checklist, con nombres, cuando la tabla se apila — D-767.
   En tabla son cinco puntos de color con su globo, que es lo que cabe en una
   celda. Apilada hay ancho de sobra y el punto solo no dice nada: se revela el
   rótulo que ya viaja en el marcado para lector de pantalla, y el punto se
   vuelve una marca redonda al inicio del renglón. La cruz que el punto dibuja
   con sus dos pseudoelementos se apaga aquí: dentro de un renglón de texto no
   se lee, y el color ya distingue. */
.tablewrap--apilada .dots { display: grid; gap: 5px; }
.tablewrap--apilada .dot {
  display: flex; align-items: center; gap: 9px; width: auto; height: auto;
  border: 0; background: none; border-radius: 0;
}
.tablewrap--apilada .dot::before,
.tablewrap--apilada .dot--falta::before,
.tablewrap--apilada .dot--falta::after {
  content: ""; position: static; transform: none; inset: auto;
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
  background: var(--c-border-strong);
}
.tablewrap--apilada .dot--falta::after { display: none; }
.tablewrap--apilada .dot--falta::before { background: var(--s-bloq-fg); }
.tablewrap--apilada .dot--ok::before { background: var(--s-ok-fg); }
.tablewrap--apilada .dot--aten::before { background: var(--s-aten-fg); }
.tablewrap--apilada .dot__tip { display: none; }
.tablewrap--apilada .dots__sr {
  position: static; width: auto; height: auto; overflow: visible;
  clip: auto; clip-path: none;
  white-space: normal; font-size: var(--fs-sm); color: var(--c-text-2);
}

/* Las salidas de alta desde Comercial — D-768. Dos enlaces con su icono, no
   dos renglones de texto: se pican y se distinguen de un vistazo. */
.salidas-alta { display: flex; gap: 16px; flex-wrap: wrap; margin: var(--sp-3, 12px) 0 0; }
.salidas-alta a {
  display: inline-flex; align-items: center; gap: 7px; min-height: 44px;
  font-weight: 600; font-size: var(--fs-sm);
}
.salidas-alta svg { width: 16px; height: 16px; }

/* ===========================================================================
   QUE EN EL TELÉFONO SE SIENTA UNA APP, NO UNA PÁGINA — 2026-09-29
   ---------------------------------------------------------------------------
   Agustín, 28/sep/2026, al aprobar los once cambios de la auditoría de uso:
   *«dale una checada a todo como se ve en mobil, se debe de sentir como una app
   no una web app. eso en cuanto al zoom con doble click y los menus y que no se
   rote la pantalla. que se acomode bien la informacion al tamaño de la
   pantalla»*.

   Son cuatro cosas concretas, y cada una tiene su bloque abajo:

   1. **El doble toque no hace zoom.** `touch-action: manipulation` en lo que se
      pica. El pellizco para acercar **se queda**: es accesibilidad y él no pidió
      quitarlo; lo que molesta es que al picar dos veces seguidas un botón la
      pantalla salte.
   2. **La pantalla no gira.** La orientación se fija en `manifest.json` para la
      aplicación instalada, que es donde el sistema hace caso. En el navegador
      ningún sitio puede impedir el giro, así que aquí el diseño **aguanta**
      horizontal en vez de pelearse con él.
   3. **El menú es un cajón.** Tapa la pantalla, se cierra al picar fuera y no
      mueve la página de atrás (eso último lo pone `js/movil.js`).
   4. **La información cabe.** Campos a 16 px —por debajo iOS hace zoom al
      enfocar—, blancos de toque de 44 px, franjas del sistema respetadas y
      ninguna pantalla con barra horizontal.
   =========================================================================== */

/* 1 · El doble toque no hace zoom ------------------------------------------ */
:is(a, button, label, summary, .btn, .chip, .tablero__t, .urgent__item, .quick a,
    input[type=checkbox], input[type=radio], input[type=submit]) {
  touch-action: manipulation;
}
/* El destello gris del navegador al tocar no es el que pinta PQG: se apaga y
   el estado de picado lo da `:active`, que sí es nuestro. */
@media (pointer: coarse) {
  a, button, label, summary, .btn { -webkit-tap-highlight-color: transparent; }
  .btn:active, .tabbar__b:active, .urgent__item:active { filter: brightness(.96); }
}

/* 4 · La información cabe --------------------------------------------------- */
@media (max-width: 900px) {
  /* 16 px exactos: es el umbral de iOS. Con 13 px —lo que heredaba `font:
     inherit`— enfocar un campo daba un salto de zoom del que sólo se sale
     pellizcando, y es lo que más hacía sentir «página web» al capturar. */
  input[type=text], input[type=search], input[type=email], input[type=password],
  input[type=number], input[type=date], input[type=datetime-local], input[type=month],
  input[type=time], input[type=url], input[type=tel], input[type=file],
  select, textarea {
    font-size: 16px; min-height: 44px;
  }
  input[type=checkbox], input[type=radio] { width: 22px; height: 22px; }
  /* Un botón de dedo. `.btn--sm` se exceptúa dentro de una tabla apilada, donde
     son enlaces secundarios y no la acción de la tarjeta. */
  .btn { min-height: 44px; }
  /* Nada de barra horizontal en la página: lo ancho se resuelve dentro de su
     propia caja, que para eso está `.tablewrap`. */
  html, body { overflow-x: hidden; }
  .workarea { padding-left: 14px; padding-right: 14px; }
}

/* 2 · Horizontal: el diseño aguanta ---------------------------------------- */
@media (max-width: 900px) and (orientation: landscape) {
  /* De lado, la altura es lo escaso: la marca se encoge y el cajón ocupa toda
     la pantalla con su propio `scroll` en vez de empujar. */
  .nav__brand { padding-top: 6px; padding-bottom: 6px; }
  .nav__brand-logo { height: 30px; }
  .jefe__titulo { font-size: var(--fs-xl); }
}

/* 3 · El cajón -------------------------------------------------------------- */
.nav__telon { display: none; }

@media (max-width: 900px) {
  /* La franja de la marca se queda arriba siempre: es donde vive «Menú», y
     buscarlo rodando hacia arriba era el otro gesto de página web.
     13/oct/2026 — **ya no se pinta en el teléfono**: «Menú» vive en la barra
     de abajo y la franja repetía lo mismo con 72 px (bloque «P8 · 7»). */
  .nav__brand {
    position: sticky; top: 0; z-index: 60;
    padding-top: calc(10px + env(safe-area-inset-top, 0px));
  }

  /* El cajón: sale de la izquierda, tapa lo que necesita y trae su propio
     `scroll`. Antes se desplegaba dentro del flujo y empujaba la pantalla
     entera hacia abajo. */
  .nav-abierto:checked + .nav-estrecha + .nav .nav__scroll,
  .nav-abierto:checked + .nav .nav__scroll {
    display: block;
    position: fixed; z-index: 70;
    top: 0; left: 0; bottom: 0;
    width: min(86vw, 320px);
    padding: calc(14px + env(safe-area-inset-top, 0px)) 10px 14px;
    background: var(--c-nav-bg);
    overflow-y: auto; overscroll-behavior: contain;
    box-shadow: 0 0 40px rgb(0 0 0 / .45);
    animation: cajon-entra .18s ease-out;
  }
  .nav-abierto:checked + .nav-estrecha + .nav .nav__foot,
  .nav-abierto:checked + .nav .nav__foot {
    display: flex;
    position: fixed; z-index: 71;
    left: 0; bottom: 0; width: min(86vw, 320px);
    margin: 0;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--c-nav-bg-2);
    border-top: 1px solid var(--c-nav-line);
  }
  /* El telón: todo lo que queda visible cierra el cajón al picarlo. */
  .nav-abierto:checked ~ .nav .nav__telon,
  .nav-abierto:checked + .nav .nav__telon {
    display: block;
    position: fixed; inset: 0; z-index: 65;
    background: rgb(6 10 16 / .55);
  }
  .nav__scroll a { min-height: 44px; align-items: center; }
}

@keyframes cajon-entra { from { transform: translateX(-100%); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .nav-abierto:checked + .nav .nav__scroll { animation: none; }
}

/* La barra de abajo — los cinco destinos de todos los días ------------------ */
.tabbar { display: none; }

@media (max-width: 900px) {
  .tabbar {
    /* **No lleva `position: fixed`** (D-784): es el último renglón del armazón
       y la pantalla mide lo que mide, así que ya está abajo sin fijarla. */
    display: flex; flex: none; z-index: 55;
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    background: var(--c-nav-bg);
    border-top: 1px solid var(--c-nav-line);
  }
  .tabbar__b {
    flex: 1 1 0; min-width: 0; min-height: 48px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    padding: 4px 2px; border-radius: 10px;
    color: var(--c-nav-text); text-decoration: none;
    font-size: 11px; font-weight: 600; line-height: 1.1;
    cursor: pointer; user-select: none;
  }
  .tabbar__b span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  .tabbar__b .ic { width: 21px; height: 21px; }
  /* El verde del matraz de Gamma marca dónde estoy, igual que en la barra
     lateral: el color de identidad, no el azul de lo que se pulsa. */
  .tabbar__b--on { color: #fff; }
  .tabbar__b--on .ic { color: var(--c-nav-mark); }
  .tabbar__ic { position: relative; display: inline-flex; }
  .tabbar__punto {
    position: absolute; top: -2px; right: -4px;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--s-bloq-fg); border: 1px solid var(--c-nav-bg);
  }
}

/* 5 · La barra de abajo NO flota al rodar — D-784 -----------------------------
   Agustín, 29/sep/2026, probándolo en el teléfono: *«la nav bar se queda
   flotando un poco cuando scrolleas»*.

   La barra estaba `fixed` al fondo de la ventana, que es lo que se hace en una
   página web. En el teléfono eso se ve mal por dos motivos a la vez: la barra
   de direcciones del navegador crece y se encoge al rodar —y la ventana con
   ella—, y al llegar al final la página rebota. En los dos casos la barra se
   despega del borde un instante y vuelve. **Ninguno se arregla moviendo la
   barra**: se arregla haciendo que la página no ruede.

   Así que en el teléfono la aplicación deja de ser un documento largo y pasa a
   ser lo que Agustín pidió el 22/sep — *«que se sienta app y no página web»*—:
   el armazón mide exactamente la pantalla, **lo único que rueda es el
   contenido**, y la barra de arriba y la de abajo son dos renglones fijos de
   ese armazón. Una barra que no está flotando no puede flotar.

   `100dvh` y no `100vh`: `dvh` es la altura **visible de verdad**, ya
   descontada la barra del navegador. Con `100vh` el último renglón quedaría
   debajo de ella. Se deja `100vh` delante como respaldo para un navegador que
   no entienda `dvh`.

   De regalo se van dos cosas de la lista de «parece un prototipo»: el rebote
   del final —`overscroll-behavior`— y que la cabecera se fuera al rodar.

   **En escritorio no cambia nada**: todo esto vive dentro de la consulta de
   900 px, y ahí la página rueda como siempre. */
@media (max-width: 900px) {
  html, body {
    height: 100%;
    overflow: hidden;
    overscroll-behavior-y: none;
  }
  .app {
    height: 100vh;
    height: 100dvh;
    min-height: 0;
  }
  /* Sin `min-height: 0` un hijo flexible se niega a encoger por debajo de su
     contenido, y el armazón crecería con la lista en vez de darle scroll. */
  .main { min-height: 0; }
  .workarea {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* El rebote se queda DENTRO del contenido: no arrastra la página. */
    overscroll-behavior-y: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 18px;
  }
  /* Ya no se pega a nada: es un renglón del armazón y siempre está a la vista.
     `sticky` dentro de algo que no rueda no hace nada, y confunde al leerlo. */
  .topbar { position: static; }
  .tabbar { position: static; }
}

@media print { .tabbar { display: none !important; } }

/* Los resultados en su propia pantalla — 2026-09-29. La misma lista del cuadro
   de ⌘K, envuelta en la aplicación: aquí hay sitio, así que el renglón respira
   y el grupo se lee como encabezado en vez de como etiqueta de un desplegable. */
.buscador-pantalla .buscador-g__r { padding: 12px 10px; min-height: 52px; border-radius: var(--radius); }
.buscador-pantalla .buscador-g__r + .buscador-g__r { border-top: 1px solid var(--c-border-soft); }
.buscador-pantalla .buscador-g__grupo {
  margin: 14px 0 4px; font-size: var(--fs-sm); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--c-text-3);
}
.buscador-pantalla .buscador-g__grupo:first-child { margin-top: 0; }
.buscador-pantalla .buscador-g__n { font-size: var(--fs-md); font-weight: 650; }
.buscador-pantalla .buscador-g__pista { padding: 10px 2px; color: var(--c-text-2); }

/* El teclado de picar números — 2026-09-29 -----------------------------------
   Agustín, para toda su flota: *«todo dato que tenga que dar se pica, no se
   teclea»*. Lo estrena `Preparación → Registrar avance`, que se captura de pie
   en la bodega. Las teclas son de 56 px: un dedo con guante no acierta a 36.
   El bloque nace `hidden` y lo enciende `js/teclado-numeros.js`. */
.teclado { display: flex; flex-direction: column; gap: 10px; max-width: 340px; }
.teclado[hidden] { display: none; }
.teclado__visor {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 14px 18px; min-height: 76px;
  border: 2px solid var(--c-accent); border-radius: var(--radius);
  background: var(--c-accent-soft);
}
/* 2026-10-06 (D-802) — el importe es el protagonista de la captura: más
   grande que cualquier otra cifra de la pantalla. */
.teclado__cifra { font-size: 40px; font-weight: 750; line-height: 1.1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.teclado__unidad { font-size: var(--fs-md); color: var(--c-text-2); font-weight: 600; }
.teclado__atajos { display: flex; gap: 8px; flex-wrap: wrap; }
.teclado__atajos .chip { cursor: pointer; border-color: var(--c-border-strong); }
.teclado__atajos .chip:hover { border-color: var(--c-accent); color: var(--c-accent-dark); }
.teclado__teclas { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.teclado__tecla {
  min-height: 56px; border: 1px solid var(--c-border-strong); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-text);
  font-size: 22px; font-weight: 650; cursor: pointer;
}
.teclado__tecla:hover { border-color: var(--c-accent); }
.teclado__tecla:active { background: var(--c-accent-soft); }
.teclado__tecla--sec { background: var(--c-surface-alt); font-size: 18px; }
/* El campo sigue ahí y sigue siendo el que se envía; en el teléfono no hace
   falta verlo grande, porque quien captura ya está picando el teclado. */
.teclado + .help { margin-top: 6px; }

/* La franja de urgencia del renglón — 2026-09-29 -----------------------------
   De la auditoría de uso que Agustín aprobó el 28/sep/2026: en una cola de
   trabajo, lo tarde que va algo tiene que verse **sin leer**. El color es el
   mismo de los estados de toda PQG, y siempre va acompañado de un chip con la
   palabra: el color solo no informa a quien no lo distingue. */
.cola__franja { width: 6px; padding: 0 !important; }
.franja { display: block; width: 6px; height: 34px; border-radius: 3px; background: var(--c-border-strong); }
.franja--tarde { background: var(--c-franja-bloq); }
.franja--hoy   { background: var(--c-franja-aten); }
.franja--lejos { background: var(--c-border-strong); }
.cola__cliente { display: block; font-size: var(--fs-sm); color: var(--c-text-2); font-weight: 400; }
.table--cola td { vertical-align: middle; }
.table--cola .meter { display: block; min-width: 110px; margin-bottom: 3px; }


/* «Mi trabajo de hoy» — D-775, 2026-09-29 -----------------------------------
   El renglón de una cola de trabajo: la franja dice la urgencia, el material va
   primero porque es lo que la persona busca con la vista, la cifra es lo que
   falta y el botón lleva a hacerlo. En el teléfono se apila y el botón se va a
   todo lo ancho, que es donde cae el pulgar. */
.trabajo__cuenta { margin: 0 0 10px; color: var(--c-text-2); }
.trabajo__fila {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; margin-bottom: 8px;
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-surface);
}
.trabajo__fila .franja { height: 42px; flex: none; }
.trabajo__que { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.trabajo__material { font-size: var(--fs-md); font-weight: 650; line-height: 1.25; }
.trabajo__meta { font-size: var(--fs-sm); color: var(--c-text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trabajo__cifra { font-size: var(--fs-xl); font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.trabajo__cifra small { font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-3); }
/* Pulido del 13/oct/2026 — «Preparación terminada» de un toque va en su
   formulario: en el teléfono es el formulario el que toma todo el ancho. */
.trabajo__fila form { margin: 0; }

@media (max-width: 720px) {
  .trabajo__fila { flex-wrap: wrap; gap: 8px 10px; }
  .trabajo__fila .franja { height: 100%; align-self: stretch; }
  .trabajo__meta { white-space: normal; }
  .trabajo__fila .btn { flex: 1 0 100%; justify-content: center; }
  .trabajo__fila form { flex: 1 0 100%; display: flex; }
}

/* La tabla esencial: sin sus columnas secundarias — 2026-09-29 ---------------
   El grado intermedio entre la tabla completa y las tarjetas, que `apilar.js`
   enciende cuando la tabla sólo cabe sin lo secundario. Las columnas escondidas
   son las que ya estaban marcadas `data-extra` para el modo tarjeta: una sola
   declaración por tabla sirve para los dos acomodos. */
.tablewrap--esencial td[data-extra],
.tablewrap--esencial th[data-oculta] { display: none; }
/* La columna secundaria la declara la CELDA; el encabezado lo deduce
   `apilar.js` por su posición, para que no haya forma de esconder uno sin el
   otro y correr la tabla entera. */
.tablewrap { position: relative; }
.tablewrap__columnas {
  margin: 8px 0 2px;
  background: none; border-style: dashed; color: var(--c-text-2);
}
.tablewrap__columnas:hover { color: var(--c-accent-dark); border-color: var(--c-accent-line); }

/* La barra de recibido de una Orden de compra — 2026-09-29. */
.oc-avance { display: block; font-size: var(--fs-sm); color: var(--c-text-2); }
.oc-avance b { color: var(--c-text); }
td > .meter { display: block; min-width: 110px; margin-bottom: 3px; }

/* El botón de cada aviso — 2026-09-29. */
.aviso__accion { flex: none; white-space: nowrap; align-self: center; }
@media (max-width: 720px) {
  /* En el teléfono el botón se va a todo lo ancho, debajo del texto: es lo que
     el pulgar busca, y en una fila de tres piezas quedaba de cuatro letras. */
  .aviso { flex-wrap: wrap; }
  .aviso__accion { flex: 1 0 100%; justify-content: center; margin-top: 6px; }
}

/* El tablero de cifras, en el teléfono — 2026-09-29 --------------------------
   De la auditoría de uso que Agustín aprobó el 28/sep/2026: *«en el celular
   cada cifra ocupa una pantalla»*. Eran dos cosas a la vez: la tarjeta
   destacada seguía ocupando las dos columnas —su comentario decía que en
   pantalla angosta debía dejar de hacerlo, y la regla nunca se escribió— y su
   cifra, a 2 rem, partía «Sin Facturas vigentes en el período» en tres
   renglones.

   Ahora en el teléfono las cifras van de dos en dos, con el pie a una línea:
   cuatro cifras en la primera vista en vez de una. **No se quita ninguna** —en
   el teléfono no se apaga lo que da identidad a la pantalla, se adapta— y a
   partir de 561 px todo vuelve a ser exactamente lo de antes. */
@media (max-width: 560px) {
  .tablero { gap: 10px; }
  .tablero__t { min-height: 94px; padding: 11px 12px; }
  .tablero__t--doble { grid-column: span 1; }
  .tablero__cifra { font-size: 1.35rem; }
  .tablero__t--doble .tablero__cifra { font-size: 1.35rem; }
  .tablero__t--doble .tablero__cifra--larga { font-size: 1.05rem; }
  .tablero__pie {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  /* La chispa de la serie se queda —es lo que da forma a la tarjeta—, más baja. */
  .chispa { height: 22px; }
}

/* La cola de Preparación cabe en el monitor de la oficina — 2026-09-29.
   Medido en una ventana de 1 440 px con la barra lateral abierta: la columna de
   contenido son 1 150 px y la tabla pedía 1 264. Siete columnas caben; lo que
   sobraba era holgura. La barra de avance no necesita 110 px para leerse, el
   chip de la fecha cabe debajo de ella en vez de al lado, y esta tabla —que es
   una cola de trabajo, no un reporte— aprieta su celda un punto. */
.table--cola td, .table--cola th { padding-left: 10px; padding-right: 10px; }
.table--cola .meter { min-width: 84px; }
.table--cola .chip { display: inline-block; margin-top: 2px; }
.table--cola td.mid { white-space: nowrap; }

/* Los dos nombres largos de la cola —Cliente y Material— se recortan con sus
   puntos suspensivos y conservan el texto entero en el `title`, que es el trato
   de `.cell-clip` en toda la aplicación. Sin tope pedían 630 px entre los dos y
   tiraban la tabla a tarjetas en un monitor donde cabía. */
.table--cola td[data-rotulo="Pedido"] { max-width: 24ch; }
.table--cola td[data-rotulo="Material"] { max-width: 26ch; }

/* En tarjeta, el nombre completo — 2026-09-29. Los topes de ancho de la cola
   existen para que la TABLA quepa; dentro de una tarjeta no hay columna que
   cuidar y recortar «DEMO Sosa cáustica escama…» sólo esconde el dato que la
   persona fue a buscar. */

/* La cabecera de pantalla, en el teléfono — 2026-09-29. El bloque del título
   con su cinta ocupaba media vista antes del primer dato. Se aprieta y la
   cinta —«Consultado el», «Vencido»— pasa a una línea corrida debajo. */
@media (max-width: 720px) {
  .jefe { padding: 12px 14px; margin-bottom: 10px; }
  .jefe__fila { gap: 8px; }
  .jefe__titulo { font-size: 22px; }
  .jefe__sub { margin-top: 4px; }
  .cinta { gap: 10px 16px; flex-wrap: wrap; }
  .cinta__val { font-size: var(--fs-md); }
  .screen__title { font-size: 22px; }
}

/* De qué está hecho el número de la pestaña — 2026-09-29, D-779. Una línea que
   se lee de corrido y donde cada sumando abre su propio conjunto. */
.tabs__nota--suma { line-height: 1.7; }
.tabs__nota--suma a { text-decoration: none; border-bottom: 1px dotted var(--c-border-strong); }
.tabs__nota--suma a:hover { color: var(--c-accent-dark); border-bottom-color: var(--c-accent); }


/* ===== P8 · Base de la app — revisión del 13/oct/2026 =====================
   Seis arreglos de la revisión completa que Agustín aprobó el 13/oct/2026. Cada
   bloque dice qué estaba mal; las reglas de la casa que los ordenan son las de
   siempre: menos vueltas, botones de dedo, nada cortado en el teléfono.
   Va ANTES de la última regla de la hoja (D-828) y no al final, a propósito: los
   otros paquetes de la misma revisión añaden sus bloques al final, y así los
   dos cambios no caen en las mismas líneas al juntarlos. */

/* 1 · Un toque, un envío (`js/freno.js`). El botón que se picó dice
   «Guardando…» y se apaga con el estilo de siempre (`.btn:disabled`); el cursor
   dice que algo está en camino, no que esté prohibido. */
button[aria-busy="true"], input[aria-busy="true"] { cursor: progress; }

/* 2 · El aviso que confirma se va solo (`js/confirmaciones.js`): se desvanece
   en vez de desaparecer de golpe, que se leería como un parpadeo. */
.messages .note--yendose {
  opacity: 0; transform: translateY(-4px);
  transition: opacity .35s ease, transform .35s ease;
}
@media (prefers-reduced-motion: reduce) {
  .messages .note--yendose { transition: none; }
}

/* 3 · «— sin Material —» arriba de la lista (`js/filtrar.js`): se distingue de
   los Materiales para que no se lea como uno más. */
.combo__op--vacia {
  color: var(--c-text-3); font-style: italic;
  border-bottom: 1px solid var(--c-border-soft); border-radius: var(--radius) var(--radius) 0 0;
}

/* 4 · «Quitar renglón» (`js/renglones.js`). En la tabla del escritorio es una
   cruz en su columna estrecha; el rótulo entero sale en la tarjeta del teléfono.
   Un renglón quitado se va de la vista también cuando el renglón es tarjeta, que
   pinta su propio `display` y ganaría al `hidden` del navegador. */
.renglon__quitar { width: 1%; white-space: nowrap; text-align: center; }
.renglon__quitar .renglon__texto {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
}
.table tr[data-renglon][hidden] { display: none; }

/* 5 · Las rejillas de captura, en tarjetas en el teléfono — Nueva cotización y
   Nuevo Pedido. Antes la tabla se iba de lado: el Material quedaba en «Escri…»
   y el Precio fuera de la pantalla, y en la cotización la cabecera fija caía
   encima del primer renglón. Ahora cada renglón es una tarjeta: el Material a
   todo el ancho arriba, Cantidad y Precio lado a lado debajo, y lo que sigue a
   todo el ancho; cada campo con su rótulo (`data-rotulo` en la plantilla). */
@container tabla (max-width: 640px) {
  .table--captura thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
  }
  .table--captura, .table--captura tbody { display: block; width: auto; overflow: visible; }
  .table--captura tr {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px 10px;
    border: 1px solid var(--c-border); border-radius: var(--radius);
    background: var(--c-surface); padding: 12px; margin-bottom: 10px;
  }
  .table--captura tbody tr:hover { background: var(--c-surface); }
  .table--captura td {
    display: block; min-width: 0; border: 0; padding: 0; text-align: left;
  }
  .table--captura td:first-child,
  .table--captura td:nth-child(n+4) { grid-column: 1 / -1; }
  .table--captura td[data-rotulo]::before {
    content: attr(data-rotulo); display: block; margin-bottom: 4px;
    font-size: var(--fs-sm); color: var(--c-text-3);
  }
  .table--captura td :is(input, select, .combo) { width: 100%; }
  .table--captura td.renglon__quitar { width: auto; text-align: right; }
  .table--captura .renglon__quitar .btn { min-height: 44px; }
  .table--captura .renglon__quitar .renglon__texto {
    position: static; width: auto; height: auto; overflow: visible; clip-path: none;
  }
}
/* La caja de la rejilla de captura NO recorta — revisión final del 13/oct/2026.
   `.tablewrap` declara `overflow-x: auto` y, por especificación, el otro eje
   computa a `auto`: la caja recortaba la lista de coincidencias del Material
   (`.combo__lista`, en absoluto y hasta 46vh), que en el renglón 4 o 5 de Nueva
   cotización casi no se veía y había que rodar la rejilla para elegir. Las
   rejillas de captura caben a lo ancho y en el teléfono ya son tarjetas, así que
   su caja no necesita rodar; sigue siendo el contenedor que mide el ancho para
   volverlas tarjetas (`container-type` no recorta).

   Su cabecera se queda donde está: dentro de la caja que rodaba no se pegaba a
   nada, y sin caja que ruede `sticky` la pegaría a la ventana, detrás de la
   barra de arriba. */
.tablewrap:has(> .table--captura) { overflow: visible; }
.tablewrap:has(> .table--captura) thead th { position: static; }

/* 6 · Existencias en tarjetas — la tabla ya es `table--tarjetas`; aquí sólo el
   renglón de «Lotes», que se pega a la tarjeta de su Material en vez de ser una
   tarjeta suelta, y sus capas como renglones ligeros. Las reglas del teléfono
   viven en la consulta de contenedor del modo tarjeta (busca «tarjeta-pie»):
   no se abre otra. Éstas son su gemelo para la tabla que `apilar.js` apila. No
   llevan `.table--tarjetas` en el selector a propósito: no son reglas del
   molde, que tiene su propio gemelo vigilado (`test_tabla_que_no_cabe`). */
.tablewrap--apilada tr.tarjeta-pie {
  margin-top: -11px; border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius); padding-top: 0;
}
.tablewrap--apilada tr:has(+ tr.tarjeta-pie) {
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
}

/* 7 · El teléfono, arriba y en el cajón ---------------------------------------
   Había dos «Menú», dos «Buscar» y dos «Avisos» —arriba y en la barra de
   abajo—, y las tres franjas fijas se comían casi una cuarta parte de la
   pantalla (72 + 65 + 61 px de 844). La lupa y «Tu registro» abrían su caja
   cortada por la izquierda, y medían 28-36 px, menos que un dedo. Y en el cajón
   el pie con tu nombre tapaba los últimos destinos: al picar «Reportes» se abría
   «Mi contraseña».

   Ahora, en el teléfono: arriba sólo `Atrás`, dónde estoy y «Tu registro» (de
   dedo y con su caja dentro de la pantalla); Buscar, Avisos y Menú viven sólo
   en la barra de abajo, que ya los tenía. La franja del logotipo se queda —es
   la identidad de la aplicación y en el teléfono no se apaga—, sin su «Menú»
   repetido. Y la
   lista del cajón deja abajo el alto de su pie (lo mide `js/movil.js`; sin
   guion queda una holgura que cubre el pie más alto medido), así que el último
   destino siempre se puede picar. */
@media (max-width: 900px) {
  .nav__burger { display: none; }
  .topbar .buscador-g, .topbar .campana { display: none; }
  .topbar { position: relative; }
  .registro-g { position: static; }
  .registro-g__abrir { width: 44px; height: 44px; }
  .atras { min-width: 44px; justify-content: center; }
  .registro-g__caja {
    position: absolute; top: calc(100% + 6px); left: 12px; right: 12px; width: auto;
    max-height: calc(100dvh - 200px); overflow-y: auto;
  }
  .nav-abierto:checked + .nav-estrecha + .nav .nav__scroll,
  .nav-abierto:checked + .nav .nav__scroll {
    padding-bottom: var(--cajon-pie, calc(164px + env(safe-area-inset-bottom, 0px)));
  }
}
.tablewrap--apilada tr.tarjeta-pie .table--sub tr {
  border: 0; border-top: 1px solid var(--c-border-soft); border-radius: 0;
  background: none; padding: 6px 0; margin: 0;
}
.tablewrap--apilada tr.tarjeta-pie .subtable__coa { flex-wrap: wrap; margin-left: 0; }


/* D-828 — «Tu registro» como página (sin JavaScript): la misma lista, a lo ancho
   de un panel angosto. */
.registro-pagina { max-width: 480px; font-size: var(--fs-sm); }

/* ===== P1 · Comercial y Maestros ===== */
/* [3]/[149] — la tarjeta del Material al que le falta el precio, tras un
   rechazo: la franja y el campo en el color del error, para encontrarla sin
   leer el aviso de arriba. */
.preciocard--falta { border-left-color: var(--s-bloq-fg); }
.preciocard--falta .quotable__price { border-color: var(--s-bloq-fg); }
/* [4] — el aviso «¿no es el mismo Pedido?» de Nuevo Pedido se VE arriba, pero
   en el HTML va después de «Capturar Pedido»: Enter en un campo envía con el
   primer botón del formulario, y ése no puede ser «Es otro Pedido». */
form.aviso-arriba { display: flex; flex-direction: column; }
form.aviso-arriba > .aviso-arriba__aviso { order: -1; margin-bottom: var(--sp-4); }

/* ===== P2 · Cuentas por cobrar: ¿es otro Pago?, «Se aplica a» y subir el Complemento ===== */
/* [144] — la pregunta antes de guardar un Pago parecido: los dos botones a la
   mano, uno al lado del otro y, en el teléfono, uno debajo del otro. */
.pregunta-duplicado p { margin: 0 0 var(--sp-2); }
.pregunta-duplicado__botones { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pregunta-duplicado__botones .btn { min-height: 44px; }
/* [143] — las Facturas marcadas en Cuentas por cobrar, una por renglón y
   picables con el pulgar. */
.aplicar-a { border: 0; padding: 0; margin: var(--sp-3) 0 0; }
.aplicar-a legend { font-weight: 600; margin-bottom: var(--sp-1); }
.aplicar-a__factura { display: flex; align-items: center; gap: var(--sp-2); min-height: 44px; }
.aplicar-a__factura input { width: 22px; height: 22px; flex: none; }
/* [80] — subir el Complemento desde la lista «Sin Complemento». */
.subir-complemento { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.subir-complemento input[type="file"] { font-size: 16px; max-width: 100%; }
.subir-complemento .btn { min-height: 44px; }

/* ===== P3 · Cuentas por pagar y Comisiones ===== */
/* [88] «Aplicar ahora a»: cada Factura del Proveedor es una fila que se pica
   entera (44 px en el teléfono), no una casilla diminuta. */
.aplicar-ahora #id_apply_invoice { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.aplicar-ahora #id_apply_invoice label {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 8px 12px;
  border: 1px solid var(--c-border); border-radius: var(--radius-sm);
  background: var(--c-surface); cursor: pointer; font-variant-numeric: tabular-nums;
}
.aplicar-ahora #id_apply_invoice label:has(input:checked) { border-color: var(--c-accent); background: var(--c-surface-alt); }
/* [89] «Saldo completo» en la ficha del Pago: la casilla con su rótulo, del
   tamaño de un dedo. */
.pagar-completo { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; }
/* [93] El plan de pagos: una semana, sus días y cada Factura con su «Pagar». */
.plan-pagos__semana { font-size: var(--fs-md); margin: var(--sp-3) 0 var(--sp-2); }
.plan-pagos__semana:first-child { margin-top: 0; }
.plan-pagos__dia { margin: 0 0 var(--sp-3); }
.plan-pagos__fecha { margin: 0 0 4px; }
.plan-pagos .rows__num { display: inline-flex; align-items: center; gap: 8px; }
/* [84] Un botón por cada mes por cerrar. */
.cierre-meses { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.cierre-meses form { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0; }
@media (max-width: 720px) {
  .plan-pagos .rows__num .btn, .cierre-meses .btn, .accion-pagar .btn { min-height: 44px; }
}

/* ===== P5 · Preparación ===== */
/* Revisión del 13/oct/2026. [23] «Preparación terminada» arriba, como un botón
   verde; quitar la marca, aparte y plegado. [147] los otros materiales del
   Pedido, con su avance. [18] lo que no detiene la salida, aparte, y la Factura
   sin círculo vacío. [24] los dos «Imprimir» juntos. */
.terminar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 0 14px;
}
.terminar__estado { margin: 0; display: inline-flex; align-items: center; gap: 8px; }
.terminar--ok .terminar__estado { color: var(--s-ok-fg); }
.terminar--ok .terminar__estado .ic { width: 20px; height: 20px; }
.terminar__boton { min-height: 44px; }
/* AQR [89] — mientras falte preparar, «Registrar avance» con su teclado ocupa
   el renglón entero; quitar la marca es un botón suelto, sin motivo. */
.terminar__estado + form { margin: 0; }
.terminar__avance { flex: 1 1 100%; max-width: 32rem; }
/* El marcador dice qué cuenta: «Checklist 4 de 4». */
.marcador__rotulo {
  display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-3);
  letter-spacing: 0; margin-bottom: 4px;
}

.otras-lineas { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 8px 0 0; }
.otras-lineas__rotulo { color: var(--c-text-3); font-size: var(--fs-sm); }
.otras-lineas__estado { color: var(--c-text-3); font-weight: 400; margin-left: 4px; }
.otras-lineas__btn--ok { border-color: var(--s-ok-bd); background: var(--s-ok-bg); color: var(--s-ok-fg); }
@media (pointer: coarse) { .otras-lineas .btn { min-height: 44px; } }

.checklist-aparte__titulo {
  font-size: var(--fs-sm); font-weight: 600; color: var(--c-text-3);
  margin: 0 0 8px; text-transform: none; letter-spacing: 0;
}
/* La Factura se registra después (D-811): ni círculo vacío ni ámbar de
   «falta»; un reloj en gris. */
.marca--despues { border-style: dashed; color: var(--c-text-3); }

.imprimir-todo { display: flex; flex-wrap: wrap; gap: 8px; }
.imprimir-todo form { margin: 0; }

/* ===== P6 · Logística — «Entregado» por viaje, con su día ===== */
/* [140] — el cuarto paso del Pedido. En el teléfono los cuatro se apilan,
   igual que los tres. */
.pasos3--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 560px) { .pasos3--4 { grid-template-columns: 1fr; } }
.paso-entregado { margin-top: calc(-1 * var(--sp-2)); margin-bottom: var(--sp-3); }

/* [52] — «Entregado el 28/sep» y «Otro día» uno junto al otro; «Otro día» abre
   el calendario debajo, sin salir de la pantalla. */
.entregado { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; }
.entregado form { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.entregado__otro { position: relative; }
.entregado__otro > summary { list-style: none; cursor: pointer; }
.entregado__otro > summary::-webkit-details-marker { display: none; }
.entregado__otro[open] > form { margin-top: 6px; }
.entregado__otro input[type=date] { max-width: 11rem; }
/* Pulido del 13/oct/2026 — con «Entregado — todos los viajes» a la vista, el
   par del viaje atrasado va plegado en «Sólo el viaje del …»: un solo juego de
   botones grandes en el paso 4. */
.entregado-viaje > summary { list-style: none; cursor: pointer; }
.entregado-viaje > summary::-webkit-details-marker { display: none; }
.entregado-viaje[open] > .entregado { margin-top: 6px; }

/* [51] — la parada de hoy en la agenda: hora, Cliente, camioneta, estado,
   botón y folio. El Cliente sigue siendo el enlace a la ficha. */
.parada--hoy { grid-template-columns: 3.5rem minmax(0, 1fr) auto auto auto auto; }
.parada--hoy:hover { border-color: var(--c-border); background: var(--c-surface-alt); }
.parada--hoy .parada__quien { text-decoration: none; color: inherit; }
.parada--hoy .parada__quien:hover b { text-decoration: underline; }
.parada__estado .chip { white-space: nowrap; }
@media (max-width: 640px) {
  .parada--hoy { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .parada--hoy .parada__vehiculo, .parada--hoy .parada__estado,
  .parada--hoy .parada__accion, .parada--hoy .parada__folio { grid-column: 2; }
  .parada--accion .entregado { justify-content: flex-start; }
}

/* [59] — «Liberar» y «Dejarla como está» con su motivo ahí mismo. */
.acciones-fila { display: flex; flex-wrap: wrap; gap: 6px; align-items: flex-start; }
.accion-motivo > summary { list-style: none; cursor: pointer; }
.accion-motivo > summary::-webkit-details-marker { display: none; }
.accion-motivo[open] > form {
  display: grid; gap: 6px; margin-top: 6px; min-width: 16rem; white-space: normal;
}
.accion-motivo textarea { width: 100%; }

/* [58] — los días que ya no se ofrecen: día y camioneta, motivo, y su botón. */
.bloqueos { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.bloqueo {
  display: grid; grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) auto; gap: 4px 12px;
  align-items: center; border: 1px solid var(--c-border); border-radius: var(--radius-sm, 6px);
  padding: 8px 12px; background: var(--c-surface-alt);
}
.bloqueo__dia { display: inline-flex; align-items: center; gap: 6px; }
.bloqueo__dia svg { width: 15px; height: 15px; }
.bloqueo__motivo { color: var(--c-text-2); font-size: var(--fs-sm); }
.bloqueo form { margin: 0; }
@media (max-width: 640px) { .bloqueo { grid-template-columns: minmax(0, 1fr); } }

/* ===== P6 · Logística — «Entregado» sin cortes (revisión) ===== */
/* La columna «Cerrar» de la lista del Calendario: los dos botones de una
   parada atrasada («Entregado el …» y «Otro día») se apilan dentro de su
   celda; antes se salían de la columna y quedaban cortados. */
td .entregado, td .entregado form { flex-direction: column; align-items: stretch; }
td .entregado .btn { white-space: normal; justify-content: center; }
td .entregado__otro input[type=date] { width: 100%; max-width: 100%; }
@media (max-width: 640px) {
  /* La parada atrasada en el teléfono: Cliente, qué falta y los botones, cada
     uno en su renglón. En dos columnas, los dos botones dejaban sin ancho al
     aviso de qué falta y el calendario de «Otro día» lo tapaba. */
  .parada--accion { grid-template-columns: minmax(0, 1fr); }
  .parada--accion > * { grid-column: 1; }
  .parada--accion > .chip { justify-self: start; }
  /* La carga de la camioneta va debajo de las paradas en una sola columna: con
     `grid-column: 2` creaba una segunda columna y la fecha del día quedaba
     reducida a una letra. */
  .agenda__cargas { grid-column: 1; }
}

/* ===== P7 · Reportes, paneles, avisos e insights ===== */
/* [158] [111] — la Sugerencia de hoy: el Cliente abre su ficha y, a la derecha,
   los días y la Cotización abierta, que se abre aparte (un enlace no puede ir
   dentro de otro). Debajo de cada renglón, si hay con qué surtir y cuánto deja
   ese precio hoy. */
a.sugerencia__quien { text-decoration: none; color: inherit; flex: 1 1 auto; }
.sugerencia__lado { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: none; }
.sugerencia__cotiz { text-decoration: none; white-space: nowrap; }
.sugerencia__datos { display: flex; flex-wrap: wrap; gap: 4px; margin: 2px 0 4px; }
/* [157] — «Sin vendedor»: un botón por Vendedor, que se acomodan solos. */
.sinvendedor__botones { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 100%; justify-content: flex-end; }
.sinvendedor__botones form { margin: 0; }
.renglon.sinvendedor { flex-wrap: wrap; }
@media (max-width: 720px) {
  .sugerencia__fila { flex-wrap: wrap; }
  .sugerencia__lado { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .sugerencia__cotiz, .sinvendedor__botones .btn { min-height: 44px; display: inline-flex; align-items: center; }
  .sinvendedor__botones { justify-content: flex-start; }
}

/* [5095] — Registrar Pago: el Complemento arriba, en un renglón que se pica
   con el pulgar; lo de contado, debajo. */
.desde-complemento__form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.desde-complemento__titulo { flex: 1 1 100%; margin: 0; }
.desde-complemento__form input[type="file"] { flex: 1 1 16rem; min-height: 44px; font-size: 16px; }
.desde-complemento__o { margin: var(--sp-3) 0 var(--sp-2); font-weight: 600; }
/* [5095] — al pagar una Factura en otra moneda, en qué cuenta entró: dos
   botones con su importe, ninguno puesto de antemano. */
.moneda-cuenta { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.moneda-cuenta .btn { min-height: 44px; flex: 1 1 14rem; justify-content: flex-start; }
.moneda-cuenta .btn small { display: block; font-weight: 400; opacity: .8; }

/* D-867 — «Se capturó en MXN: pasar a USD», bajo el subtítulo de la ficha. */
.corrige-moneda { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2, 8px); margin: var(--sp-2, 8px) 0; }

/* D-868 — las tarjetas de Preparación en la ficha del Pedido, **que se
   entienden sin leer**. Agustín, 14/oct/2026: *«que no pese hacerlo leyendo,
   más visuales y fáciles»*. Ícono por tipo de requisito, nombre corto, estado
   en una pastilla de color y el botón del ancho de la tarjeta (46 px: cómodo
   para el pulgar). Ámbar falta, verde con palomita listo, rojo no existe el
   documento, punteada la Factura, que no detiene la salida. Las acciones son
   las del parcial compartido: aquí sólo cambia cómo se ven. */
.preq-avance { display: inline-flex; align-items: center; gap: 10px; flex: 1 1 14rem; font-weight: 400; }
.preq-avance__barra { display: flex; gap: 4px; flex: 1; max-width: 280px; }
.preq-avance__barra i { flex: 1; height: 10px; border-radius: 5px; background: var(--c-surface-sunk); }
.preq-avance__barra i.on { background: var(--s-ok-fg); }
.preq-avance__txt { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; font-size: var(--fs-sm); color: var(--c-text-2); white-space: nowrap; }
.preq-avance--ok .preq-avance__txt { color: var(--s-ok-fg); }
.preqs {
  display: grid; gap: 10px; list-style: none; padding: 0; margin: 0 0 var(--sp-4, 16px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
}
.preq {
  display: flex; flex-direction: column; gap: 10px; margin: 0;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: 12px; padding: 12px;
}
.preq__top { display: flex; align-items: center; gap: 12px; }
.preq__ico {
  position: relative; flex: none; width: 48px; height: 48px; border-radius: 12px;
  display: grid; place-items: center;
}
.preq__ico > .ic { width: 26px; height: 26px; stroke-width: 1.6; }
.preq__palomita {
  position: absolute; right: -5px; bottom: -5px; width: 22px; height: 22px;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--c-surface); border: 2px solid var(--s-ok-fg); color: var(--s-ok-fg);
}
.preq__palomita .ic { width: 13px; height: 13px; stroke-width: 3; }
.preq__nom { flex: 1; min-width: 0; font-weight: 700; font-size: var(--fs-md); line-height: 1.2; }
.preq__nom small {
  display: block; margin-top: 2px; font-weight: 600; font-size: var(--fs-xs);
  color: var(--c-text-3); font-variant-numeric: tabular-nums;
}
.preq__estado { flex: none; font-size: 13px; font-weight: 700; }
.preq__estado .ic { width: 13px; height: 13px; stroke-width: 2.4; }
.preq__acciones { display: flex; flex-wrap: wrap; gap: 6px; }
.preq__acciones:not(:has(*)) { display: none; }
.preq__acciones form { margin: 0; flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 6px; }
.preq__acciones .btn {
  flex: 1 1 100%; min-width: 0; min-height: 46px; justify-content: center;
  font-size: var(--fs-md); font-weight: 700; border-radius: 9px;
  white-space: normal; text-align: center;
}
.preq__acciones .btn .ic { width: 18px; height: 18px; stroke-width: 2; }
.preq__acciones .muted { font-size: var(--fs-sm); }
.preq__porque { font-size: var(--fs-sm); color: var(--c-text-3); }
.preq__porque summary { cursor: pointer; text-align: center; text-decoration: underline dotted; list-style: none; }
.preq__porque summary::-webkit-details-marker { display: none; }
/* Falta: ámbar, y el botón es la acción principal, amarillo lleno. */
.preq--falta { border-color: var(--s-amar-bd); }
.preq--falta .preq__ico { background: var(--s-amar-bg); color: var(--s-amar-fg); }
.preq--falta .preq__estado { background: var(--s-amar-bg); border-color: var(--s-amar-bd); color: var(--s-amar-fg); }
.preq--falta .preq__acciones .btn { background: #f2bf0f; border-color: #dcaa00; color: #2b2100; }
.preq--falta .preq__acciones .btn:hover { background: #f7cd3a; }
/* Sin documento: rojo suave; el botón lleva a crearlo. */
.preq--sin { border-color: var(--s-bloq-bd); }
.preq--sin .preq__ico { background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.preq--sin .preq__estado { background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }
.preq--sin .preq__acciones .btn { background: var(--c-surface); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }
/* Listo: verde con palomita; el botón queda, en segundo plano. */
.preq--ok { background: var(--s-ok-bg); border-color: var(--s-ok-bd); }
.preq--ok .preq__ico { background: var(--s-ok-fg); color: #fff; }
.preq--ok .preq__estado { background: var(--c-surface); border-color: var(--s-ok-bd); color: var(--s-ok-fg); }
.preq--ok .preq__acciones .btn {
  min-height: 44px; background: transparent; border-color: var(--s-ok-bd);
  color: var(--s-ok-fg); font-size: var(--fs); font-weight: 600;
}
/* La Factura no detiene la salida (D-811): punteada y gris. */
.preq--despues { border-style: dashed; border-color: var(--c-border-strong); background: var(--c-surface-alt); }
.preq--despues .preq__ico { background: var(--c-surface-sunk); color: var(--c-text-2); }
.preq--despues .preq__acciones .btn { background: var(--c-surface); border-color: var(--c-border-strong); color: var(--c-text); }

/* D-869 — «Autorizar la salida sin estos documentos» en la ficha del Pedido:
   un botón del ancho de la Línea que abre el motivo a lo ancho. Era un
   `fieldset` sin estilo, con el campo chico y la ayuda corriendo a lo ancho. */
.sindoc { margin: 0 0 var(--sp-4, 16px); }
.sindoc__abrir {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 8px 14px; cursor: pointer; list-style: none;
  border: 1px dashed var(--s-revi-bd); border-radius: 9px;
  background: var(--s-revi-bg); color: var(--s-revi-fg); font-weight: 650;
}
.sindoc__abrir::-webkit-details-marker { display: none; }
.sindoc__abrir .ic { width: 17px; height: 17px; }
.sindoc[open] > .sindoc__abrir { border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-style: solid; }
.sindoc__form {
  display: flex; flex-direction: column; gap: 8px; margin: 0;
  padding: 12px; border: 1px solid var(--s-revi-bd); border-top: 0;
  border-radius: 0 0 9px 9px; background: var(--c-surface);
}
.sindoc__rotulo { font-weight: 650; }
.sindoc__rotulo small { font-weight: 400; color: var(--c-text-3); margin-left: 4px; }
.sindoc__form textarea { width: 100%; min-height: 76px; font-size: 16px; }
.sindoc__boton { min-height: 46px; justify-content: center; background: var(--s-revi-fg); border-color: var(--s-revi-fg); color: #fff; }
.sindoc__boton:hover { filter: brightness(1.1); }

/* D-869 — «Revisar precio»: lo que deja el precio, en tres cifras grandes y,
   debajo, la cuenta renglón por renglón que las suma. */
.deja { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.deja__cifra {
  display: flex; flex-direction: column; gap: 2px; padding: 12px 14px;
  border: 1px solid var(--c-border); border-radius: 12px; background: var(--c-surface-alt);
}
.deja__rotulo { font-size: var(--fs-sm); font-weight: 650; color: var(--c-text-3); }
.deja__valor { font-size: var(--fs-xl); font-weight: 750; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.deja__cifra--ok { background: var(--s-ok-bg); border-color: var(--s-ok-bd); color: var(--s-ok-fg); }
.deja__cifra--aten { background: var(--s-amar-bg); border-color: var(--s-amar-bd); color: var(--s-amar-fg); }
.deja__cifra--bloq { background: var(--s-bloq-bg); border-color: var(--s-bloq-bd); color: var(--s-bloq-fg); }
.deja__cifra--ok .deja__rotulo, .deja__cifra--aten .deja__rotulo, .deja__cifra--bloq .deja__rotulo { color: inherit; }
.deja-cuenta { display: grid; grid-template-columns: max-content 1fr; gap: 10px 16px; margin: var(--sp-4, 16px) 0 0; }
.deja-cuenta dt { font-weight: 700; }
.deja-cuenta dd {
  margin: 0; display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; align-items: baseline;
  padding-bottom: 10px; border-bottom: 1px solid var(--c-border-soft);
}
.deja-cuenta dd > small { grid-column: 1 / -1; color: var(--c-text-3); font-size: var(--fs-xs); }
.deja-cuenta__op { color: var(--c-text-2); font-size: var(--fs-sm); }
.deja-cuenta dd .num { text-align: right; white-space: nowrap; }
.deja-cuenta dd > b.num { grid-column: 2; }
@media (max-width: 560px) {
  .deja { grid-template-columns: 1fr; }
  .deja__cifra { flex-direction: row; justify-content: space-between; align-items: baseline; }
  .deja-cuenta { grid-template-columns: 1fr; gap: 4px; }
}

/* D-878 — los materiales que compra el Cliente, como botones bajo la búsqueda. */
.frecuentes { margin: 4px 0 14px; }
.frecuentes__botones { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.frecuentes__boton { min-height: 36px; }
.frecuentes__boton--puesto { border-color: var(--c-accent); background: var(--c-accent-soft, #e8f0fe); }
@media (max-width: 900px) { .frecuentes__boton { min-height: 44px; } }

/* D-881 — lo que hay que pedir: la frase y el botón que la resuelve. */
.pedir {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px;
  border: 1px solid var(--s-info-bd); background: var(--s-info-bg); color: var(--s-info-fg);
  padding: 11px 14px; border-radius: var(--radius); margin: 0 0 var(--sp-3);
}
.pedir--hoy { border-color: var(--s-aten-bd); background: var(--s-aten-bg); color: var(--s-aten-fg); }
.pedir__texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pedir__texto .muted { color: inherit; opacity: .85; }
.pedir__botones { display: flex; flex-wrap: wrap; gap: 8px; }
.pedir form { margin: 0; }
@media (max-width: 900px) { .pedir .btn { min-height: 44px; } }

/* D-882 — los Pagos sin aplicar de un Proveedor, antes de pagar otra vez. */
.pendientes__lista { margin: 10px 0 12px; padding-left: 18px; }
.pendientes__lista li { margin: 6px 0; line-height: 1.9; }
.pendientes__tc { display: inline-flex; align-items: center; gap: 6px; }
.pendientes__tc input { width: 8.5em; min-height: 36px; padding: 4px 8px; }

/* D-892 — una Solicitud del sitio en la bandeja. */
.sitio-solicitud { padding: 12px 0; border-bottom: 1px solid var(--c-border); }
.sitio-solicitud:last-child { border-bottom: 0; }
.sitio-solicitud ul { margin: 6px 0 8px 18px; }
.sitio-solicitud__acciones { display: flex; gap: 8px; flex-wrap: wrap; }

/* D-893 — lo de cada quien en el Panel del dueño. */
.equipo { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.equipo__persona { display: grid; gap: 8px; align-content: start; min-width: 0; }
.equipo__cabeza { display: grid; gap: 2px; }
.equipo__cuenta { color: var(--c-text-3); font-size: var(--fs-sm); }
.equipo__pendiente { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 8px; padding: 8px 10px; border: 1px solid var(--c-border); border-radius: var(--radius); color: var(--c-text); text-decoration: none; background: var(--c-surface); }
.equipo__pendiente--tarde { border-color: var(--s-bloq-bd, var(--c-border-strong)); }
.equipo__pendiente:hover, .equipo__pendiente:focus-visible { border-color: var(--c-accent); }
.equipo__titulo { font-weight: 600; }
.equipo__n { grid-row: 1; grid-column: 2; font-size: 1.25rem; font-variant-numeric: tabular-nums; line-height: 1.2; }
.equipo__renglon { grid-column: 1 / -1; color: var(--c-text-2); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: none; }
.equipo__mas { color: var(--c-text-3); }
.equipo__hecho { padding: 8px 10px; border-radius: var(--radius); background: var(--s-ok-bg); }
.equipo__hecho-titulo { color: var(--s-ok-fg); font-weight: 600; font-size: var(--fs-sm); }
.equipo__hecho ul { margin: 4px 0 0; padding-left: 0; list-style: none; display: grid; gap: 2px; font-size: var(--fs-sm); }
.equipo__hecho li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.equipo__hora { color: var(--c-text-3); font-variant-numeric: tabular-nums; }
.equipo__al-dia { margin-top: 10px; }

/* D-894 — el panel de quien trabaja: lo siguiente, cifras, pendientes con su
   botón y herramientas al lado. */
.pp { display: grid; gap: 16px; }
.pp-hero { display: flex; gap: 16px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding: 18px 20px; border-radius: 12px; background: var(--c-surface); border: 1px solid var(--c-border); border-left: 6px solid var(--c-accent); }
.pp-hero--bloq { border-left-color: var(--s-bloq-fg); }
.pp-hero--aten { border-left-color: var(--s-aten-fg); }
.pp-hero--info { border-left-color: var(--c-teal); }
.pp-hero__t { display: grid; gap: 4px; min-width: 0; }
.pp-hero__e { font-size: var(--fs-sm); font-weight: 700; color: var(--c-text-3); display: flex; gap: 6px; align-items: center; }
.pp-hero--bloq .pp-hero__e { color: var(--s-bloq-fg); }
.pp-hero__q { font-size: 1.35rem; line-height: 1.25; text-wrap: balance; }
.pp-hero__a { display: flex; gap: 8px; flex-wrap: wrap; }
.pp-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.pp-cifra { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px 12px; align-items: center; padding: 14px 16px; border-radius: 12px; background: var(--c-surface); border: 1px solid var(--c-border); color: var(--c-text); text-decoration: none; }
.pp-cifra:hover, .pp-cifra:focus-visible { border-color: var(--c-accent); }
.pp-cifra__ic { grid-row: span 3; width: 44px; height: 44px; border-radius: 10px; display: grid; place-items: center; background: var(--c-accent-soft); color: var(--c-accent); }
.pp-cifra--bloq .pp-cifra__ic { background: var(--s-bloq-bg); color: var(--s-bloq-fg); }
.pp-cifra--aten .pp-cifra__ic { background: var(--s-aten-bg); color: var(--s-aten-fg); }
.pp-cifra--info .pp-cifra__ic { background: var(--c-teal-soft); color: var(--c-teal); }
.pp-cifra--ok .pp-cifra__ic { background: var(--s-ok-bg); color: var(--s-ok-fg); }
.pp-cifra__n { font-size: 1.9rem; line-height: 1; font-variant-numeric: tabular-nums; }
.pp-cifra__t { font-weight: 600; }
.pp-cifra__s { color: var(--c-text-3); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pp-c { background: var(--c-surface); border: 1px solid var(--c-border); border-radius: 12px; padding: 14px 16px; display: grid; gap: 6px; min-width: 0; }
.pp-c__h { margin: 0 0 4px; font-size: 1rem; display: flex; gap: 8px; align-items: center; }
.pp-c__n { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--c-text-3); font-weight: 600; }
.pp-c__ir { margin-left: auto; font-size: var(--fs-sm); font-weight: 600; display: inline-flex; gap: 4px; align-items: center; }
.pp-flujo { columns: 2 380px; column-gap: 16px; }
.pp-flujo > * { break-inside: avoid; margin: 0 0 16px; }
.pp-flujo > :last-child { margin-bottom: 0; }
.pp-flujo .panel { margin: 0; }
.pp-c { border-top: 4px solid var(--c-border); }
.pp-c--bloq { border-top-color: var(--s-bloq-fg); } .pp-c--aten { border-top-color: var(--s-aten-fg); } .pp-c--info { border-top-color: var(--c-teal); } .pp-c--ok { border-top-color: var(--s-ok-fg); }
.pp-todos { justify-self: start; margin-top: 4px; display: inline-flex; gap: 4px; align-items: center; font-size: var(--fs-sm); font-weight: 600; }
.pp-cifra__n { color: var(--c-text); }
.pp [id^="pendiente-"] { scroll-margin-top: 80px; }
.pp-r { display: grid; grid-template-columns: 5px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 8px 0; border-top: 1px solid var(--c-border-soft); }
.pp-r__f { align-self: stretch; border-radius: 3px; background: var(--c-border); }
.pp-r__f--bloq { background: var(--s-bloq-fg); } .pp-r__f--aten { background: var(--s-aten-fg); } .pp-r__f--info { background: var(--c-teal); } .pp-r__f--ok { background: var(--s-ok-fg); }
.pp-r__t { display: grid; min-width: 0; }
.pp-r__t b, .pp-r__t span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pp-r__t span { color: var(--c-text-3); font-size: var(--fs-sm); }

/* D-895 — el dueño mirando el Panel de otra persona. */
.equipo__ver { display: flex; gap: 6px; flex-wrap: wrap; }
.ver-como { position: sticky; top: var(--topbar-h); z-index: 5; display: flex; gap: 12px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding: 10px 26px; background: var(--s-aten-bg); border-bottom: 1px solid var(--s-aten-bd); color: var(--s-aten-fg); }
.ver-como__t { display: flex; gap: 8px; align-items: center; font-weight: 600; }
.ver-como__a { display: flex; gap: 8px; flex-wrap: wrap; }

/* D-896 (P1) — el día de cada quien, más compacto ---------------------------
   Seis cifras caben en una fila; la cola de preparación cabe en renglones de
   una línea de apoyo, con el botón a la derecha también en el teléfono; la
   semana sin viajes es una línea. */
.pp-cifras { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.trabajo__fila { padding: 8px 12px; margin-bottom: 6px; gap: 10px; }
.trabajo__fila .franja { height: 32px; }
.trabajo__material { font-size: var(--fs); }
.trabajo__cifra { font-size: var(--fs-lg); }
.trabajo__corto { display: none; }
.semana__vacia { margin: 0; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; color: var(--c-text-2); }
@media (max-width: 720px) {
  .trabajo__fila { flex-wrap: nowrap; }
  .trabajo__fila .franja { height: auto; }
  .trabajo__meta { white-space: nowrap; }
  .trabajo__fila .btn { flex: none; }
  .trabajo__fila form { flex: none; }
  .trabajo__largo { display: none; }
  .trabajo__corto { display: inline; }
  .trabajo__cifra { font-size: var(--fs-md); }
}

/* D-896 (P3) — «Lo de cada quien» con título, sin barra; cada pendiente en una
   línea con su número y su «tarde». La cola de preparación del dueño, plegada. */
.equipo-panel .panel__body { padding-top: 4px; }
.equipo__chips { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.equipo__pendiente { grid-template-columns: minmax(0, 1fr) auto; align-items: center; padding: 7px 10px; }
.plegado-cola { margin: 0 0 var(--sp-4); background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius-lg); }
.plegado-cola > summary { cursor: pointer; padding: 12px 16px; font-weight: 650; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.plegado-cola[open] > summary { border-bottom: 1px solid var(--c-border); }
.plegado-cola > .panel { margin: 0; border: 0; box-shadow: none; }
.dueno-arriba { display: flex; flex-direction: column; }

/* D-896 (P5) — en el teléfono, lo de cada quien primero; las cifras del dueño en
   una tira que se desliza de lado y los accesos en una rejilla de 3 × 2. */
@media (max-width: 720px) {
  .dueno-arriba .equipo-panel { order: -1; }
  .dueno-arriba .tablero { display: flex; overflow-x: auto; gap: 10px; padding-bottom: 4px; scroll-snap-type: x proximity; }
  .dueno-arriba .tablero__t { flex: 0 0 156px; min-height: 0; scroll-snap-align: start; }
  .dueno-arriba .tablero__t--doble { flex-basis: 200px; }
  .quick--franja { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .quick--franja a { flex-direction: column; align-items: center; text-align: center; gap: 4px; min-height: 64px; padding: 8px 6px; font-size: var(--fs-sm); }
  .pp-cifra { padding: 10px 12px; }
  .pp-cifra__ic { width: 36px; height: 36px; }
  .pp-cifra__n { font-size: 1.5rem; }
}

/* D-896 (P4) — Mi panel: lo vacío en una línea y una sola lista a todo lo ancho. */
.linea-ok { margin: 0; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; color: var(--s-ok-fg); }
.linea-vacia { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 12px 16px; margin: 0 0 var(--sp-4); color: var(--c-text-2); }
.pp-flujo:has(> :only-child) { columns: 1; }
/* D-896 — la semana en una línea no se estira a la altura de «Lo urgente hoy». */
.dashboard-priority { align-items: start; }

/* D-896 (COMPRAS) — Compras y Abastecimiento en el molde de lista.
   «Entradas sin cerrar» de Facturas de proveedor: un renglón compacto por
   entrada —Material, de quién y cuándo en la misma línea, el costo y su botón
   al lado—. En el teléfono vuelve a partirse en dos líneas y el botón se queda
   a la vista. Y el formulario de «Registrar Importación», plegado detrás de su
   botón, en una línea. */
.renglones--compactos { gap: 3px; }
.renglones--compactos .renglon { padding: 5px 10px 5px 12px; gap: 10px; }
.renglones--compactos .renglon__principal { flex-direction: row; align-items: baseline; gap: 8px; }
.renglones--compactos .renglon__principal b { flex: 0 1 auto; max-width: 45%; }
.renglones--compactos .renglon__meta { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.renglones--compactos .renglon__dato { flex-direction: row; align-items: baseline; gap: 6px; }
.renglones--compactos .renglon__dato b { font-size: var(--fs); }
@media (max-width: 640px) {
  .renglones--compactos .renglon__principal { flex-direction: column; gap: 1px; }
  .renglones--compactos .renglon__principal b { max-width: none; }
  .renglones--compactos .renglon__meta { white-space: normal; }
}
.registrar-importacion { margin: 0 0 var(--sp-4); }
.registrar-importacion__form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 6px; }
.registrar-importacion__form select { flex: 1 1 16rem; min-width: 0; }

/* D-896 (BODEGA) — revisión de uso del 19/oct: listas de Inventario y Logística.
   El desglose de un Apartado enseña sólo lo que no es cero; el separador lo
   pone la hoja para que no quede un «·» huérfano cuando falta un tramo. */
.desglose > span + span::before { content: " · "; }

/* D-896 (COMERCIAL) — Pedidos de venta en un renglón de dos líneas (L1) ---------
   El Cliente arriba y, debajo, folio · OC · modalidad · promesa · origen; el
   estado como pastillas y UN botón. Reutiliza `.renglon__meta` de los renglones
   del panel. Nada aquí toca el modo tarjeta: `apilar.js` sigue decidiendo. */
.pedidos-renglon .pedidos-renglon__cliente { font-weight: 650; max-width: 30rem; }
.pedidos-renglon .renglon__meta { margin-top: 2px; }
.pedidos-renglon .renglon__meta .folio { font-weight: 600; white-space: nowrap; }
.pedidos-renglon .renglon__meta svg { width: 14px; height: 14px; vertical-align: -2px; }
.pedidos-renglon__orden { margin-left: 8px; font-size: var(--fs-xs); font-weight: 400; }
.pedidos-renglon__pastillas { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.pedidos-renglon__pastillas a.badge { text-decoration: none; cursor: pointer; }
.pedidos-renglon__pastillas a.badge:hover { text-decoration: underline; }
.pedidos-renglon td.actions form { margin: 0; }

/* D-896 (DINERO) — fichas, Cuentas y Reportes ------------------------------
   · `.vacio-linea`: una sección sin datos es UNA línea con su botón de agregar
     (Cliente: identificadores, contactos, direcciones; Material: identificadores,
     fabricantes, Proveedores), en vez de una tabla vacía con encabezados. Es la
     `.linea-vacia` de Mi panel sin su relleno propio, porque vive dentro de un
     `.panel__body` que ya lo tiene.
   · `.plan-pagos__vacio`: «Nada por pagar estas dos semanas», una línea.
   · `.quick--reportes`: las tarjetas de Reportes llevan debajo la pregunta que
     contesta, así que piden más ancho y la pregunta en letra chica. */
.vacio-linea { margin: 0 0 var(--sp-2); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; color: var(--c-text-2); }
.plan-pagos__vacio { display: flex; gap: 6px; align-items: center; margin: 0 0 var(--sp-4); }
.quick--reportes { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
.quick--reportes a { min-height: 0; gap: 6px; }
.quick__pregunta { font-size: var(--fs-sm); font-weight: 400; color: var(--c-text-2); line-height: 1.35; }
@media (max-width: 480px) {
  .quick--reportes { grid-template-columns: 1fr; }
}

/* D-896 — Próximas salidas en renglón: en sus celdas el texto se parte en dos
   líneas en vez de recortarse, para que la tabla se lea en una laptop y no se
   apile en fichas (apilar.js apila cuando hay celdas recortadas). */
.table--proximas td .chip,
.table--proximas td .meter-row__label,
.table--proximas td .help,
.table--proximas td .btn { white-space: normal; }
.table--proximas td { overflow-wrap: anywhere; }

/* =========================================================================
   AUDITORÍA DE DISEÑO — 2026-10-20
   =========================================================================
   Agustín, 20/oct/2026: *«una auditoría a la aplicación totalmente en diseño y
   acomodo, nada de agregar o quitar funciones, botones o información… para
   congruencia, simplicidad y atractivo»*. Se recorrieron las 82 pantallas
   (escritorio a 1440 px y teléfono a 375 px). Todo lo de abajo es cómo se ve y
   cómo se acomoda: ninguna cifra, botón, regla ni Permiso cambia. Las
   correcciones de un renglón viven en su sitio (la altura real de la barra
   superior, el campo de búsqueda a lo ancho, el rojo de la paleta); aquí van
   las piezas con cuerpo.
   ========================================================================= */

/* --- A · La fila de cifras no deja huecos ---------------------------------
   `.tablero` son cuatro columnas fijas (D-707), y Clientes, Calendario,
   Materiales y Usuarios traen tres: la cuarta columna quedaba vacía, el mismo
   hueco que `.stats` ya resuelve contando sus tarjetas (§21.3). Mismo criterio:
   con dos o tres cifras sin ninguna destacada, tantas columnas como cifras. La
   destacada sigue ocupando dos y el Panel general no cambia. */
@media (min-width: 1101px) {
  .tablero:not(:has(.tablero__t--doble)):has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tablero:not(:has(.tablero__t--doble)):has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* --- B · La tarjeta KPI de las fichas habla el idioma del tablero ---------
   D-815 centró las cifras del tablero y les dio peso; las tarjetas de las
   fichas (Cliente, Material, Proveedor, Parámetros, Reportes) se quedaron con
   la composición anterior: pegadas a la izquierda, con la cifra chica y el
   icono en caja diminuta. Misma información en dos lenguajes —lo que D-708
   pidió evitar—. Ahora: icono encima, rótulo, la cifra grande y del color de su
   tarjeta, y la nota debajo; la mini conserva su tamaño. */
.stat--kpi {
  align-items: center; text-align: center; gap: 4px;
  padding: 16px 18px 14px;
}
.stat--kpi .stat__label { text-align: center; }
.stat--kpi .stat__value { font-size: 2.1rem; font-weight: 750; line-height: 1.1; margin: 2px 0; }
.stat--kpi .stat__value--sm { font-size: 1.25rem; line-height: 1.25; }
.stat--kpi .stat__meta, .stat--kpi .stat__foot { text-align: center; }
.stat--kpi .delta { align-self: center; }
.stat--kpi .icobox { width: 30px; height: 30px; border-radius: 9px; margin-bottom: 4px; }
.stat--kpi .icobox .ic { width: 15px; height: 15px; }
.stat--kpi .kpi-facts--rows { text-align: left; }
.stat--kpi .stat__value { color: var(--c-accent-dark); }
.stat--kpi.stat--ok   .stat__value { color: var(--s-ok-fg); }
.stat--kpi.stat--aten .stat__value { color: var(--s-aten-fg); }
.stat--kpi.stat--bloq .stat__value { color: var(--s-bloq-fg); }
/* Una cifra que es texto —«Sin ventas», «No declarado»— va en el color del
   texto: no es un dato que pida leerse en color. */
.stat--kpi .stat__value--sm { color: var(--c-text); }
.stat--kpi .stat__money-line b { color: var(--c-text); }
.stat--mini { padding: 10px 12px 9px; gap: 2px; }
.stat--mini .stat__value { font-size: var(--fs-lg); }
.stat--mini .stat__value--sm { font-size: var(--fs-md); }
.stat--mini .icobox { width: 24px; height: 24px; border-radius: 7px; margin-bottom: 2px; }
.stat--mini .icobox .ic { width: 13px; height: 13px; }

/* --- C · La pantalla de acceso tiene la marca ------------------------------
   Era una tarjeta gris sobre fondo gris, sin un solo rasgo de Gamma: la
   primera pantalla que ve cada quien y la única sin identidad. Ahora el
   logotipo va encima de la tarjeta, la tarjeta baja a la altura de la vista y
   detrás hay un halo suave del verde del matraz. Sólo CSS: `.acceso` ya
   existía en las cuatro pantallas de entrada (acceso, código, alta del segundo
   factor y recuperación). */
body:has(.acceso) .workarea {
  min-height: calc(100vh - var(--topbar-h));
  background:
    radial-gradient(60% 50% at 50% 0%, rgba(43, 182, 115, .16), transparent 70%),
    radial-gradient(40% 35% at 85% 100%, rgba(43, 182, 115, .08), transparent 70%);
}
.acceso { margin-top: clamp(24px, 9vh, 96px); }
.acceso::before {
  content: ""; display: block; height: 64px; margin: 0 auto var(--sp-5);
  background: url("../img/pqg-logo.6999bb5b6a31.png") center / contain no-repeat;
}
.acceso .panel { border-color: var(--c-border-strong); }
.acceso .panel__title { font-size: var(--fs-xl); }
.acceso .btn--primary { min-height: 40px; padding-inline: 22px; }

/* --- D · Una bandeja de avisos en cero es buena noticia -------------------
   «No tienes avisos.» salía como un renglón gris, el tono de un error; en
   toda PQG una lista vacía que es buena noticia se dice en verde y con su
   marca (`.vacio--ok`). Misma frase, mismo lenguaje que el resto. */
.avisos-vacio {
  padding: 28px 18px; text-align: center;
  color: var(--s-ok-fg); font-weight: 700; font-size: var(--fs-lg);
}
.avisos-vacio::before { content: "✓ "; }

/* --- E · Movimiento que dice algo -------------------------------------------
   Las gráficas crecen desde el eje al abrir la pantalla y las barras de avance
   se llenan desde la izquierda: el ojo lee la forma antes que la cifra. La
   chispa de una tarjeta se traza. Un botón se hunde un punto al picarlo. Todo
   dura menos de un segundo, no mueve ningún texto y con «Reducir movimiento»
   no existe (la regla general de la sección 2 lo apaga). */
@keyframes barra-crece { from { transform: scaleY(0); } }
@keyframes barra-llena { from { transform: scaleX(0); } }
@keyframes traza        { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes aviso-entra  { from { opacity: 0; transform: translateY(-6px); } }
@media (prefers-reduced-motion: no-preference) {
  .chart__bar, .chart__seg, .spark__b {
    transform-origin: bottom; animation: barra-crece .6s cubic-bezier(.2, .7, .2, 1) both;
  }
  .hbar__fill, .saldos__barra i, .meter__fill, .avance__relleno,
  .prep-avance__relleno, .logro__relleno, .marcador__seg--ok, .preq-avance__barra i.on {
    transform-origin: left; animation: barra-llena .6s cubic-bezier(.2, .7, .2, 1) both;
  }
  .chispa polyline, .chart__margen polyline {
    stroke-dasharray: 1; animation: traza 1s ease-out .15s both;
  }
  .messages .note { animation: aviso-entra .25s ease-out both; }
  .btn { transition: background .12s ease, border-color .12s ease, box-shadow .12s ease, transform .08s ease; }
  .btn:active:not(:disabled) { transform: translateY(1px); }
}

/* --- F · Detalles de la casa ----------------------------------------------- */
/* Lo seleccionado con el ratón se marca del verde de Gamma, no del azul del
   sistema. */
::selection { background: var(--c-accent-line); color: var(--c-text); }
/* Un título largo se parte en dos renglones parejos en vez de dejar una
   palabra sola en el segundo. */
.screen__title, .jefe__titulo, .vacio__t, .pp-hero__q { text-wrap: balance; }
