/* =====================================================================
   Estaciones de piso · capa industrial del design system

   Se carga DESPUÉS de twenty-theme.css y **no inventa colores**: usa sus
   tokens. Lo único que cambia respecto al panel es la escala, y por una
   razón concreta: el panel se mira sentado a 50 cm y la estación de pie,
   a un metro, con guantes y a veces con la mano ocupada.

   Tres decisiones que sostienen el resto:

     · **Superficies planas.** Nada de sombras ni de tarjetas que se
       levantan al pasar el cursor: en una terminal táctil no hay cursor
       que pasar, y el relieve solo añade ruido.
     · **Una jerarquía, no cinco.** Título grande, dato grande, todo lo
       demás en secundario. Si todo destaca, no destaca nada.
     · **El color dice estado, no decora.** El acento es del paso activo;
       los estados usan los tags del sistema. Un icono de color por
       tarjeta es adorno, y en piso el adorno se lee como información.
   ===================================================================== */

:root {
    /* Escala propia de la estación, un escalón por encima del panel. */
    --st-text-sm: 0.875rem; /* 14px · apoyo */
    --st-text-md: 1rem; /* 16px · cuerpo */
    --st-text-lg: 1.25rem; /* 20px · título de fila */
    --st-text-xl: 1.75rem; /* 28px · título de pantalla */
    --st-text-data: 1.5rem; /* 24px · códigos y cantidades */

    /* Alturas mínimas pensadas para dedo con guante. */
    --st-hit: 56px;
    --st-hit-bar: 48px; /* los mandos de la cabecera del puesto */
    --st-row: 76px;
    /* El aire del lienzo: 16 en el teléfono, 24–26 en la tablet, hasta 40 en
       un monitor grande, donde el contenido ya no tiene tope (9-oct-2026). */
    --st-gutter: clamp(16px, 2.2vw, 40px);
    /* El ancho máximo del contenido y de la cabecera (9-oct-2026). */
    --st-ancho: 1680px;
}

/* ── Armazón ──────────────────────────────────────────────────────────── */

/* ── EL ALTO DEL ARMAZÓN ES LA PANTALLA, NO EL CONTENIDO ──────────────────

   `.st-body` se declara como la zona que se desplaza —`flex-grow`,
   `min-height: 0`, `overflow-y: auto`— y con `min-height` no lo era nunca: si
   el contenido pasaba del alto de la pantalla, el armazón crecía con él, el
   cuerpo crecía dentro y quien acababa desplazándose era la página. El
   `overflow` se quedaba sin usar, la cabecera del puesto se iba hacia arriba
   con el resto, y cualquier cosa pegada al borde de abajo —la barra de la caja
   en «Terminar y guardar»— no tenía a qué pegarse: el navegador la ata al
   marco que dice desplazarse, y ése no se movía.

   Con `height` el cuerpo es lo único que se desplaza, que es lo que la hoja ya
   decía. La cabecera del puesto —qué estación, qué turno, la hora, los avisos—
   se queda a la vista, que en una terminal de piso es lo que se quiere. */
.st-shell {
    height: 100dvh;
    display: flex;
    flex-direction: column;
    background-color: var(--tw-bg-secondary);
    color: var(--tw-font-primary);
    font-size: var(--st-text-md);
}

/* ── La cabecera del puesto: tres zonas (9-oct-2026) ──────────────────────

   Salvador, con seis botones en fila: «en el header hay demasiados y
   amontonados botones… sé creativo y ordenado». Cada zona contesta una
   pregunta y va en su columna de la rejilla:

     · izquierda — ¿dónde estoy y a nombre de quién? Un solo botón, la
       terminal, que abre lo que se toca de vez en cuando (cambiar de
       estación, escáner, impresora, apariencia, practicar y Salir);
     · centro — ¿cómo la estoy viendo? «Normal | 3D», centrado de verdad
       aunque los lados midan distinto (`1fr auto 1fr`);
     · derecha — lo que pide atención: la hora, los avisos y la ayuda.

   Los mandos de la cabecera miden `--st-hit-bar` (48): siguen siendo de dedo
   con guante, pero la cabecera es la barra del puesto y no compite en peso con
   los botones del trabajo, que miden 56. */
.st-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 12px 16px;
    /* A los mismos bordes que `.st-container`: en un monitor más ancho que
       `--st-ancho` el nombre de la estación cae encima del título de la
       pantalla y la ayuda encima de su botón, no en las esquinas. */
    padding: 10px max(var(--st-gutter), (100% - var(--st-ancho)) / 2);
    background-color: var(--tw-bg-primary);
    border-bottom: 1px solid var(--tw-border-strong);
    flex-shrink: 0;
}

.st-header-lado {
    grid-column: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.st-header-vista {
    grid-column: 2;
}

.st-header-lado--fin {
    grid-column: 3;
    justify-content: flex-end;
}

.st-header .st-btn {
    min-height: var(--st-hit-bar);
    padding: 0 16px;
    white-space: nowrap;
}

/* La terminal · las iniciales, la estación y quién opera, en un solo botón
   plano. El galón dice que se abre; el fondo sólo aparece al tocarlo. */
/* El margen negativo alinea las iniciales con el borde del contenido. Va en la
   envoltura y no en el botón: en el botón restaba 8 px a su propio ancho
   máximo y cortaba «Empaque y ensam…» con sitio de sobra. */
.st-terminal {
    min-width: 0;
    margin-left: -8px;
}

.st-terminal-boton {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    max-width: 100%;
    min-height: var(--st-hit-bar);
    padding: 4px 12px 4px 8px;
    border: 1px solid transparent;
    border-radius: var(--tw-radius-md);
    background: transparent;
    color: var(--tw-font-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--tw-transition);
}

.st-terminal-boton:hover,
.st-terminal-boton[aria-expanded='true'] {
    background-color: var(--tw-bg-tertiary);
}

.st-terminal-boton:focus-visible {
    outline: 2px solid var(--tw-accent);
    outline-offset: 2px;
}

.st-terminal-texto {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.st-terminal-texto > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.st-terminal-galon {
    flex: 0 0 auto;
    font-size: 18px;
    color: var(--tw-font-secondary);
    transition: transform var(--tw-transition);
}

.st-terminal-boton[aria-expanded='true'] .st-terminal-galon {
    transform: rotate(180deg);
}

/* El menú de la terminal: por grupos, a escala de estación. */
.st-terminal-menu {
    min-width: 300px;
    padding: 6px 0;
}

.st-terminal-menu .dropdown-header {
    padding: 10px 14px 4px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-tertiary, var(--tw-font-secondary));
}

.st-menu-mas .st-mas-item.is-actual {
    font-weight: var(--tw-weight-semibold);
}

/* En la terminal el color dice estado y no decora: los iconos de lo que se
   hace van en secundario, la palomita de la estación en la que se está en
   acento, y «Salir» en rojo. Con la clase repetida porque
   `.st-menu-mas .st-mas-item` y `.dropdown-menu .dropdown-item .ti` fijan el
   color más abajo en esta hoja. */
.st-terminal-menu.dropdown-menu .st-mas-item .ti {
    color: var(--tw-font-secondary);
}

.st-terminal-menu.dropdown-menu .st-mas-item .ti-check {
    color: var(--tw-accent);
}

.st-terminal-menu.dropdown-menu .st-mas-item.st-mas-item--salir,
.st-terminal-menu.dropdown-menu .st-mas-item.st-mas-item--salir .ti {
    color: var(--tw-tag-red-fg);
}

/* La apariencia, con el control del panel a escala de dedo. */
.st-terminal-tema {
    padding: 8px 14px 10px;
}

.st-terminal-tema .tw-theme-switch__label {
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary, var(--tw-font-secondary));
}

.st-terminal-tema .tw-theme-option {
    min-height: 40px;
    gap: 6px;
    font-size: var(--st-text-sm);
}

/* «Normal | 3D» · el segmentado de la casa al alto de la barra. La vista en
   la que se está no es un enlace: se marca como la elegida. */
.st-header-vista .st-seg-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: calc(var(--st-hit-bar) - 10px);
    padding: 0 16px;
    text-decoration: none;
}

.st-seg-btn[aria-current='page'] {
    background-color: var(--tw-bg-primary);
    border-color: var(--tw-border-strong);
    color: var(--tw-font-primary);
    cursor: default;
}

.st-header-hora {
    text-align: right;
}

/* La hora se va antes que cualquier mando: en la tablet vertical estorba. */
@media (max-width: 767.98px) {
    .st-header-hora {
        display: none;
    }
}

/* ── La cabecera en un teléfono ───────────────────────────────────────────
 *
 * Medido a 375 px antes de las zonas: con los botones en fila, «Salir» quedaba
 * fuera de la pantalla, y dejarlos envolver gastaba un tercio del teléfono en
 * mandos. Aquí no se envuelve: se encoge. Los mandos se quedan en su icono
 * —que es lo que se reconoce de un vistazo con guantes— y el ancho se lo lleva
 * el nombre del puesto, cortado con puntos suspensivos. El rótulo sigue
 * existiendo para el lector de pantalla y en el `title`. */
@media (max-width: 575.98px) {
    .st-header {
        grid-template-columns: minmax(0, 1fr) auto auto;
        gap: 8px;
        padding: 8px var(--st-gutter);
    }

    .st-header-lado {
        gap: 8px;
    }

    .st-header .st-btn-label {
        display: none;
    }

    .st-header .st-btn {
        padding: 0 12px;
        flex: 0 0 auto;
    }

    .st-header-vista .st-seg-btn {
        padding: 0 12px;
    }

    /* En el teléfono el segmentado se queda en la puerta al 3D: la vista en la
       que ya se está no cabe y no dice nada que la pantalla no diga. Y las
       iniciales ceden su sitio al nombre del puesto, que con ellas se leía «E». */
    .st-header-vista .st-seg-btn[aria-current='page'],
    .st-terminal-boton .brand-initials {
        display: none;
    }

    .st-terminal-galon {
        display: none;
    }

    /* El configurador del lector elige el puerto serie de una pistola, y un
       teléfono no tiene ni puerto ni pistola: ahí el lector es la cámara. */
    .st-header #scanner-button {
        display: none;
    }
}

.st-header-station {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.1;
}

.st-header-meta {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* El reloj con cifras de ancho fijo: sin esto la hora “baila” cada minuto. */
.st-clock {
    font-variant-numeric: tabular-nums;
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
    line-height: 1.1;
    text-align: right;
}

/* ── Avisos del puesto ────────────────────────────────────────────────────
   Lo que le está esperando a esta estación: programas por surtir, cajas que
   recoger, láminas que Almacén ya bajó. Va pegada bajo la cabecera y **sin
   scroll**: es lo primero que se ve al levantar la vista, y si se fuera con el
   contenido dejaría de avisar en cuanto el operador bajara media pantalla.

   Sin nada que decir no existe: el `hidden` del elemento la quita entera y no
   deja ni el hueco. */

.st-alerts {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px var(--st-gutter);
    background-color: var(--tw-bg-secondary);
    flex-shrink: 0;
}

.st-alerts[hidden] {
    display: none;
}

.st-alert {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: var(--st-hit);
    padding: 10px 14px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-primary);
}

/* El tono va en el borde entero y el fondo, nunca en una barra a la izquierda. */
.st-alert--info {
    border-color: var(--tw-tag-blue-fg);
    background-color: var(--tw-tag-blue-bg);
}

.st-alert--warning {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-alert-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-primary);
    font-size: 20px;
}

.st-alert-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex-grow: 1;
    min-width: 0;
}

.st-alert-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.2;
}

.st-alert-detail {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* La campana de la cabecera (7-oct-2026) · los avisos del puesto ya no van en
   franjas encima del trabajo: «esos avisos estorban mucho». El botón sólo sale
   con algo que decir; su número toma el tono del peor y late cuando sube. */
.st-campana {
    position: relative;
}

.st-campana-n {
    min-width: 22px;
    padding: 1px 7px;
    border-radius: 999px;
    text-align: center;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    background-color: var(--tw-tag-blue-bg);
    color: var(--tw-tag-blue-fg);
}

.st-campana-n[data-tono='naranja'] {
    background-color: var(--tw-tag-orange-bg);
    color: var(--tw-tag-orange-fg);
}

.st-campana-n[data-tono='roja'] {
    background-color: var(--tw-tag-red-bg);
    color: var(--tw-tag-red-fg);
}

.st-campana--nueva .ti-bell {
    animation: st-campana-late 0.9s ease-in-out 2;
}

@keyframes st-campana-late {
    0%, 100% { transform: rotate(0); }
    20% { transform: rotate(-16deg); }
    40% { transform: rotate(14deg); }
    60% { transform: rotate(-10deg); }
    80% { transform: rotate(6deg); }
}

@media (prefers-reduced-motion: reduce) {
    .st-campana--nueva .ti-bell {
        animation: none;
    }
}

/* El panel · encima del trabajo, sin empujarlo; ancho de tablet y con su propio
   scroll cuando hay mucho. */
.st-avisos-panel {
    width: min(460px, calc(100vw - 24px));
    max-height: min(70vh, 640px);
    overflow-y: auto;
    padding: 6px 10px 10px;
}

.st-avisos-seccion[hidden] {
    display: none;
}

.st-avisos-seccion + .st-avisos-seccion {
    margin-top: 6px;
    border-top: 1px solid var(--tw-border-light);
}

.st-avisos-titulo {
    margin: 10px 2px 6px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tw-font-tertiary);
}

.st-avisos-panel .st-alert {
    min-height: 0;
    gap: 10px;
    padding: 8px 10px;
}

.st-avisos-panel .st-alert + .st-alert {
    margin-top: 6px;
}

.st-avisos-panel .st-alert-icon {
    width: 30px;
    height: 30px;
    font-size: 17px;
}

.st-avisos-panel .st-alert-title {
    font-size: var(--st-text-md);
}

/* En el panel el botón se queda a la derecha en cualquier ancho: el panel ya es
   angosto, y bajarlo a un renglón entero duplicaba el alto de cada aviso. */
.st-avisos-panel .st-alert {
    flex-wrap: nowrap;
}

.st-avisos-panel .st-alert-text {
    flex-basis: auto;
}

.st-avisos-panel .st-alert .st-btn {
    flex-shrink: 0;
    width: auto;
    min-height: 40px;
    padding: 0 12px;
}

.st-avisos-lista {
    display: grid;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Cada aviso de la estación dentro de la campana (5-oct-2026). Su pliegue
   `.st-avisos-area` y su cuenta se retiraron el 9-oct-2026: desde el 7-oct los
   avisos viven en la campana de la cabecera y nadie los pintaba. */
.st-aviso-area {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 100%;
    min-height: var(--st-hit);
    padding: 8px 12px;
    border: 1px solid;
    border-radius: var(--tw-radius-sm);
    color: inherit;
    text-decoration: none;
}

.st-aviso-area--roja { border-color: var(--tw-tag-red-fg); background-color: var(--tw-tag-red-bg); }
.st-aviso-area--naranja { border-color: var(--tw-tag-orange-fg); background-color: var(--tw-tag-orange-bg); }
.st-aviso-area--azul { border-color: var(--tw-tag-blue-fg); background-color: var(--tw-tag-blue-bg); }

.st-aviso-area-ic {
    display: inline-grid;
    place-items: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border-radius: 50%;
    color: var(--tw-bg-primary);
    font-size: 16px;
}

.st-aviso-area--roja .st-aviso-area-ic { background-color: var(--tw-tag-red-fg); }
.st-aviso-area--naranja .st-aviso-area-ic { background-color: var(--tw-tag-orange-fg); }
.st-aviso-area--azul .st-aviso-area-ic { background-color: var(--tw-tag-blue-fg); }

.st-aviso-area .st-alert-title {
    font-size: var(--st-text-sm);
}

/* En el teléfono el botón no cabe al lado: baja y se hace ancho, que es como se
   toca con guante. El icono y el texto se quedan juntos —el texto reclama el
   ancho que queda— porque un icono solo en su renglón parece otro aviso. */
@media (max-width: 575.98px) {
    .st-alert {
        flex-wrap: wrap;
    }

    .st-alert-text {
        flex-basis: calc(100% - 50px);
    }

    .st-alert .st-btn {
        width: 100%;
        justify-content: center;
    }
}

.st-body {
    flex-grow: 1;
    min-height: 0;
    overflow-y: auto;
    padding: var(--st-gutter);
}

/* El contenido usa la pantalla (9-oct-2026). Salvador, con la portada de
   Empaque en un monitor de 1440: «usa toda la pantalla». Tenía un tope de
   1180 px —el ancho de la tablet del kiosco— y en cualquier monitor dejaba dos
   franjas vacías a los lados mientras la lista de abajo se desplazaba.

   Y con tope, pero otro (Salvador, el mismo día: «pero sí deberían tener un
   max width, ¿no?»): `--st-ancho`, 1680 px. Hasta ahí —la laptop de 1440, el
   monitor de 1680— la pantalla se usa entera; en uno de 1920 o de 2560 el
   renglón dejaría la acción a un metro de lo que nombra, así que se centra.
   La cabecera del puesto se alinea a los mismos bordes (ver `.st-header`). Lo
   que no debe estirarse ni a 1680 —un campo de cantidad, un párrafo— se acota
   en su componente, no en el lienzo. */
.st-container {
    max-width: var(--st-ancho);
    margin: 0 auto;
}

/* Y Rafa, el asistente, vive fijo en la esquina de abajo a la derecha (96 px).
   Con el tope de 1180 se quedaba en el margen; con la pantalla entera cae
   encima de lo que va pegado a la derecha —«Recibir ›», «Imprimir 400 ›» en
   «Lo que sigue»— (Salvador, 9-oct-2026, en la portada de Almacén). Un hueco al
   final deja desplazar lo último por encima de él. No en las pantallas con barra
   de acción pegada abajo: ahí Rafa ya se sube sobre la barra (`rafa.js`), y el
   hueco dejaría la barra flotando a media pantalla al final del desplazamiento. */
body:has(> #rafa:not([hidden])) .st-container:not(:has(.st-wizard-foot, .st-loadbar, .st-signbar))::after {
    content: '';
    display: block;
    height: 112px;
}

/* ── Encabezado de pantalla ───────────────────────────────────────────── */

.st-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
}

/* En un teléfono, el título y sus botones no caben en la misma línea.
 *
 * Sin esto el encabezado no parte: el título se estrecha hasta quedar en una
 * columna de ocho renglones y los botones se salen por la derecha, fuera de la
 * pantalla y sin forma de alcanzarlos. Se nota desde que la estación se abre
 * desde el teléfono de quien entra con gafete y no sólo desde la tablet.
 *
 * El título ocupa la fila entera y los botones bajan a la suya. Sólo en
 * pantallas estrechas: en la tablet siguen uno al lado del otro. */
@media (max-width: 575.98px) {
    .st-page-head {
        flex-wrap: wrap;
    }

    .st-page-head > :first-child {
        flex: 1 1 100%;
    }
}

.st-title {
    font-size: var(--st-text-xl);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.15;
    margin: 0;
}

.st-subtitle {
    font-size: var(--st-text-md);
    color: var(--tw-font-secondary);
    margin: 4px 0 0;
}

/* ── Botones de estación ──────────────────────────────────────────────── */

.st-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: var(--st-hit);
    padding: 0 20px;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    cursor: pointer;
    transition: background-color var(--tw-transition);
}

.st-btn:hover {
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-primary);
}

.st-btn--primary {
    background-color: var(--tw-accent);
    border-color: var(--tw-accent);
    color: var(--tw-font-inverted);
}

.st-btn--primary:hover {
    background-color: var(--tw-accent-hover);
    color: var(--tw-font-inverted);
}

.st-btn--danger {
    color: var(--tw-tag-red-fg);
    border-color: var(--tw-border-strong);
}

.st-btn:disabled,
.st-btn[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
}

/* ── La escala de alturas (9-oct-2026) ───────────────────────────────────

   «Homologa… tamaños»: había botones de 32, 36, 38, 40, 44, 48, 54, 56, 64 y
   72, trece escritos a mano con `style="min-height…"`. Quedan cuatro escalones
   y cada uno dice dónde va, no cuánto mide:

     64 · `--lg`   la acción que cierra un paso grande, el campo de escaneo;
     56 · base     botones, campos y el renglón que se pliega (`--st-hit`);
     48 · `--md`   dentro de un renglón o de una barra: la cabecera, los menús,
                   los filtros de una lista, la cabecera de un grupo
                   (`--st-hit-bar`);
     40 · `--sm`   el que acompaña a un título, el icono (`--icon`) y el plano
                   (`--plain`).

   Un tamaño nuevo se pide aquí y no en el `style` de un botón. */
.st-btn--lg {
    min-height: 64px;
    font-size: var(--st-text-lg);
    padding: 0 28px;
}

.st-btn--md {
    min-height: var(--st-hit-bar);
    padding: 0 14px;
}

/* A lo ancho de su columna: las acciones de un lote, una debajo de otra. Se
   usaba en `batches.js` sin estar definida. */
.st-btn--wide {
    width: 100%;
}

/* ── El botón de al lado ──────────────────────────────────────────────────
 *
 * «Quitar todas» junto al título de un bloque, «Agregar» en la cabecera de
 * una lista: acompañan a otra cosa y no son la acción del paso, así que a 56
 * pesan más que el título que llevan al lado. Bajan a 40, que es lo que ya
 * miden el de icono y el `--plain`, y siguen siendo del tamaño del dedo.
 *
 * Existe porque si no se escribe a mano. Antes esto eran cuatro plantillas
 * con `style="min-height: 40px; padding: 0 14px"` puesto a ojo —y cinco
 * guiones con la misma frase y otros dos números—, que es de donde salen los
 * tamaños que no cuadran: nadie compara un atributo `style` con el de otra
 * pantalla. Los de icono solo van con `--icon`, que ya era cuadrado. */
.st-btn--sm {
    min-height: 40px;
    padding: 0 12px;
    font-size: var(--st-text-sm);
}

/* Botón de estación trabajando.
   En la terminal el operador está de pie y a un metro de la pantalla: no
   percibe un cambio de opacidad ni un rótulo que cambia de texto, y si no ve
   nada vuelve a picarle. Por eso el botón conserva su color y su tamaño
   —moverlo sería peor— y gira un aro grande encima del rótulo apagado.
   Los keyframes `tw-spin` los pone twenty-theme.css, que esta pantalla
   también carga. */
.st-btn.is-busy {
    position: relative;
    color: transparent !important;
    pointer-events: none;
    opacity: 1;
}

.st-btn.is-busy::after {
    content: '';
    position: absolute;
    inset: 0;
    margin: auto;
    width: 22px;
    height: 22px;
    border: 3px solid var(--st-btn-spinner, var(--tw-font-secondary));
    border-top-color: transparent;
    border-radius: 50%;
    animation: tw-spin 0.6s linear infinite;
}

.st-btn--lg.is-busy::after {
    width: 28px;
    height: 28px;
}

.st-btn--primary {
    --st-btn-spinner: var(--tw-font-inverted);
}

.st-btn--danger {
    --st-btn-spinner: var(--tw-tag-red-fg);
}

@media (prefers-reduced-motion: reduce) {
    .st-btn.is-busy::after {
        animation-duration: 2.4s;
    }
}

/* Punto del botón del lector: gris si nunca se configuró, verde si hay un
   puerto guardado en esta terminal. */
.st-scanner-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--tw-font-extra-light);
    display: inline-block;
}

.st-scanner-dot--on {
    background-color: var(--tw-tag-green-fg);
}

/* ── Bandeja de tareas · la pantalla de inicio de cada estación ───────── */

/* Un flujo: las tareas que se hacen por el mismo motivo.
   Separar por flujo es lo que devuelve al número su significado. Una lista
   corrida numerada 01…04 promete que se hace 01, luego 02, luego 03; en Almacén
   eso era falso —recibir y etiquetar son una cadena, entregar es la otra puerta
   y consultar no es un paso—, y una promesa falsa de orden se paga en piso. */
.st-flow + .st-flow {
    margin-top: 28px;
}

.st-flow-title {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    /* El `h2` de Tabler trae 28 px de interlínea: un rótulo que parte renglón
       quedaba con un hueco de párrafo entre sus dos líneas. */
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--tw-font-light);
    margin: 0 0 10px 2px;
}

.st-tasks {
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    overflow: hidden;
}

.st-task {
    --st-task-pad: 18px;
    /* El fondo de la fila lo hereda la pastilla del número para tapar la línea
       que la cruza; sin esta variable el hover abre un hueco en la cadena. */
    --st-task-bg: var(--tw-bg-primary);

    display: flex;
    align-items: center;
    gap: 20px;
    width: 100%;
    min-height: var(--st-row);
    padding: var(--st-task-pad) 20px;
    border: 0;
    border-bottom: 1px solid var(--tw-border-light);
    background: transparent;
    color: inherit;
    text-align: left;
    text-decoration: none;
    transition: background-color var(--tw-transition);
}

.st-task:last-child {
    border-bottom: 0;
}

.st-task:hover {
    --st-task-bg: var(--tw-bg-tertiary);
    background-color: var(--tw-bg-tertiary);
    color: inherit;
}

/* La marca de la fila: número si el flujo tiene orden, icono si no.
   Es la única señal que distingue «paso 2 de esta cadena» de «tarea que se hace
   cuando toca», y por eso ocupan la misma columna: se comparan de un vistazo. */
.st-task-mark {
    position: relative;
    flex-shrink: 0;
    align-self: stretch;
    width: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    color: var(--tw-font-light);
}

.st-task-num {
    position: relative; /* encima de la línea de la cadena */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--tw-border-strong);
    border-radius: 50%;
    background-color: var(--st-task-bg);
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-secondary);
}

/* La línea que encadena los pasos. Se sale del relleno de la fila por arriba y
   por abajo para tocar la del vecino, y se recorta en el primero y en el último
   para que la cadena empiece y termine en un número, no en el aire.

   Va en el contenedor y no en las filas —`.st-chain`— porque también encadena
   la lista de «Aquí se trabaja así» de la pantalla de proceso, que es un
   `.st-list`: donde haya orden real, la misma línea. */
.st-chain .st-task-mark::before {
    content: '';
    position: absolute;
    left: 50%;
    top: calc(var(--st-task-pad) * -1);
    bottom: calc(var(--st-task-pad) * -1);
    width: 1px;
    margin-left: -0.5px;
    background-color: var(--tw-border-strong);
}

.st-chain > :first-child .st-task-mark::before {
    top: 50%;
}

.st-chain > :last-child .st-task-mark::before {
    bottom: 50%;
}

.st-task-title {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
    line-height: 1.2;
}

.st-task-desc {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    margin-top: 4px;
    max-width: 78ch;
}

.st-task-rule {
    font-size: var(--st-text-sm);
    color: var(--tw-tag-orange-fg);
    margin-top: 6px;
}

/* ── Lo que lleva esperando, dicho desde fuera ─────────────────────────────
 *
 * LA ESPERA ESTABA DETRÁS DE LA PUERTA. El renglón de la bandeja decía «9 h 20
 * min esperando» y lo decía en rojo, pero para leerlo hay que entrar, y se entra
 * cuando uno ya sospecha que hay algo. Desde fuera sólo había un número, y un
 * «3» no distingue tres cajas que el proceso anterior acaba de cerrar de una que
 * lleva ahí desde el turno de la noche.
 *
 * Ahora la puerta dice lo que toca —ir por ellas— y se tiñe entera. El tono va en
 * el fondo y en el filo de toda la fila —mismo criterio que `.st-note`— porque a
 * un metro de la terminal una barra de 3 px en un costado no se ve, y ésta es
 * justo la señal que tiene que verse sin ir a mirarla.
 *
 * Los umbrales son los del renglón —2 h avisa, 8 h alarma—: la puerta y lo que
 * hay detrás tienen que decir lo mismo, o una de las dos miente. */
.st-task-espera {
    display: block;
    margin-top: 6px;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
    color: var(--tw-tag-orange-fg);
}

.st-task-espera:empty {
    display: none;
}

.st-task--aviso {
    background-color: var(--tw-tag-orange-bg);
}

.st-task--aviso:hover {
    --st-task-bg: var(--tw-tag-orange-bg);
    background-color: var(--tw-tag-orange-bg);
}

.st-task--alarma {
    background-color: var(--tw-tag-red-bg);
    box-shadow: inset 0 0 0 2px var(--tw-tag-red-fg);
}

.st-task--alarma:hover {
    --st-task-bg: var(--tw-tag-red-bg);
    background-color: var(--tw-tag-red-bg);
}

.st-task--alarma .st-task-espera,
.st-task--alarma .st-task-mark,
.st-task--aviso .st-task-mark {
    color: var(--tw-tag-red-fg);
}

.st-task--aviso .st-task-mark {
    color: var(--tw-tag-orange-fg);
}

/* El número, del color de la fila y con latido cuando alarma: es lo que se mira
   primero de las tres puertas, y en una pantalla que se ve de reojo el
   movimiento es lo único que gana a la costumbre. */
.st-task--aviso .st-block-count {
    color: var(--tw-tag-orange-fg);
    font-weight: var(--tw-weight-semibold);
}

.st-task--alarma .st-block-count {
    color: var(--tw-tag-red-fg);
    font-weight: var(--tw-weight-semibold);
    animation: st-espera-latido 1.6s ease-in-out infinite;
}

@keyframes st-espera-latido {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.35;
    }
}

/* Quien pidió menos movimiento no se queda sin la señal: el latido baja a un
   pulso lento, igual que el del lector. */
@media (prefers-reduced-motion: reduce) {
    .st-task--alarma .st-block-count {
        animation-duration: 5s;
    }
}

/* ── La bandeja en un teléfono ────────────────────────────────────────────
 *
 * ELEGIR ES COMPARAR, y no se puede comparar lo que no cabe junto. Medido a
 * 375 px con la escala de kiosco: **260 px por tarjeta**, o sea una tarea y
 * media en pantalla. Para saber si lo tuyo era «Etiquetar placas» o «Guardar en
 * su lugar» había que desplazar, leerlas por turnos y acordarse de la primera.
 *
 * Lo que sobra no es la explicación: es **la regla**. La descripción dice qué es
 * la tarea y eso es lo que se compara; la regla dice por qué se hace así, que es
 * doctrina —se lee aprendiendo, en la tablet, junto a quien te enseña— y no lo
 * que se necesita para decidir a dónde ir. Ocupaba 84 px de los 260.
 *
 * No se recorta ni una frase: lo que se enseña se enseña entero. Se enseña
 * menos.
 *
 * En la tablet no cambia nada, que es donde la regla está en su sitio. */
@media (max-width: 575.98px) {
    .st-task {
        --st-task-pad: 14px;
        gap: 14px;
    }

    .st-task-title {
        font-size: var(--st-text-md);
    }

    .st-task-rule {
        display: none;
    }
}

/* La misma línea cuando lo que dice es que la cuenta cuadra. Es el único sitio
   del kiosco donde el verde significa «sigue», y por eso se distingue del
   naranja de la regla que todavía no se cumple. */
.st-task-rule--ok {
    color: var(--tw-tag-green-fg);
}

.st-task-go {
    flex-shrink: 0;
    color: var(--tw-font-light);
}

/* Pendiente: se ve, no se toca, y se distingue de un tirón por el fondo. */
.st-task--soon {
    --st-task-bg: var(--tw-bg-tertiary);
    background-color: var(--tw-bg-tertiary);
    pointer-events: none;
}

.st-task--soon .st-task-title,
.st-task--soon .st-task-num,
.st-task--soon .st-task-mark {
    color: var(--tw-font-light);
}

/* ── Bloques de trabajo ───────────────────────────────────────────────── */

.st-block {
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    overflow: hidden;
    /* `clip` recorta igual que `hidden` -las esquinas redondas- pero no convierte
       el bloque en contenedor de desplazamiento, y eso es lo que deja al pie del
       asistente pegarse al fondo de `.st-body`. Con `hidden` se pegaba al bloque,
       que no se desplaza, y quedaba donde acabara el contenido. */
    overflow: clip;
}

/* Un paso del asistente que no es un formulario sino la portada del puesto
   —«a qué vino» en Procesos—: sin caja, sobre el lienzo, como el inicio de
   Almacén y Empaque (9-oct-2026). Sigue siendo `.st-block` para el asistente,
   que enseña y esconde paneles; sólo pierde el marco y el relleno. */
.st-block.st-block--lienzo {
    border: 0;
    border-radius: 0;
    background-color: transparent;
    overflow: visible;
}

.st-block--lienzo > .st-block-body {
    padding: 0;
}

.st-block--lienzo > .st-block-body + .st-block-body {
    margin-top: 22px;
}

/* El aire lo pone la rejilla de las puertas: los márgenes propios de «Lo que
   sigue» y de «Más» se le sumaban y dejaban 46 px donde Almacén deja 22. */
.st-puertas > .st-que-sigue--abajo,
.st-puertas > .st-inicio-mas {
    margin-top: 0;
}

/* «Aquí se trabaja así» debajo de «Más»: los dos pliegues como uno solo de
   Almacén —el galón al borde del contenido y una línea entre ellos—, no dos
   cajas con dos sangrías y la línea doble. */
.st-block--lienzo > .st-fold {
    margin-top: 0;
    border-top: 0;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-block--lienzo > .st-fold > summary {
    padding-left: 2px;
    padding-right: 2px;
}

.st-block + .st-block {
    margin-top: 16px;
}

/* Una rejilla de bloques necesita el mismo aire que un bloque.

   `.st-block + .st-block` no llegaba: una `.st-cols` no es un bloque, así que
   en cuanto una pantalla mezcla las dos formas —una tarjeta ancha arriba y dos
   columnas debajo, que es como quedó «Terminar y guardar»— las tarjetas se
   tocaban borde con borde y parecían una encima de la otra. */
.st-block + .st-cols,
.st-cols + .st-block,
.st-cols + .st-cols {
    margin-top: 16px;
}

/* ── Y el aire tampoco puede depender de que sean hermanas ────────────────

   La pareja `.st-block + .st-block` sólo llega entre hermanos adyacentes, y
   estas pantallas envuelven sus tarjetas en cuanto una lista la pinta el
   guion: «un bloque por nesteo», «lo que está por recibir», los dos pasos de
   una pantalla que se turnan. Ese `div` de por medio rompe la pareja y las
   tarjetas quedan borde con borde: dos cajas seguidas se leen como una sola
   partida por una raya, y a un metro de una terminal eso es un amontonamiento.

   Se arregla donde está el problema —el contenedor— y no tarjeta por tarjeta:
   todo lo que cuelga del cuerpo de la estación, del asistente o de una pila
   declarada se separa de lo que tiene encima, sea una tarjeta o el envoltorio
   de varias. Es la medida de siempre, así que nada se mueve de sitio; lo que
   cambia es que ya no se pierde metiendo un `div` por medio.

   El modal se queda fuera: no está en la columna, está encima de ella. Es
   `position: fixed` con `top: 0`, así que un margen no lo separa de nada —lo
   baja 16 px y le saca esa misma altura por debajo de la pantalla.

   ── Y EL AIRE LO DA LA ÚLTIMA QUE SE VE, NO LA DE AL LADO ─────────────────

   Hasta el 15 de septiembre de 2026 era `* + *`, y una tarjeta escondida
   entre dos visibles hacía de hermana: la regla de abajo le quitaba el margen
   a la siguiente para que la escondida no empujara, y las dos visibles
   quedaban pegadas. Lo reportó Salvador en «Cajas de EMB-2026-0016»: la
   cabecera del embarque y la lista de cajas, borde con borde, con «Sin
   asignar» escondida en medio.

   Ahora el margen lo lleva quien tiene **alguna hermana visible antes**, esté
   pegada o no. Eso cubre los tres casos con una regla: la escondida en medio
   ya no separa de más ni de menos, la escondida primera no empuja, y en un
   asistente el paso visible —todos los anteriores escondidos— arranca arriba.
   El `:where` deja la especificidad donde estaba (una clase y el `:not`). */
.st-container > :where(:not(.d-none, [hidden], .modal, script, style, template)) ~ *:not(.modal),
.st-wizard > :where(:not(.d-none, [hidden], .modal, script, style, template)) ~ *:not(.modal),
.st-stack > :where(:not(.d-none, [hidden], .modal, script, style, template)) ~ *:not(.modal) {
    margin-top: 16px;
}

/* ── Y un bloque escondido no deja su hueco ───────────────────────────────

   La pareja `bloque + bloque` no mira si el de delante se está viendo: sigue
   siendo el hermano anterior aunque lleve `d-none`. Media estación tiene
   tarjetas que nacen escondidas y aparecen cuando hay algo que decir —«lo que
   acaba de salir» al terminar una corrida, el detalle de un paso— y todas
   empujaban 16 px a la de debajo desde el primer pintado.

   En una sola columna no se nota. En dos, sí: la tarjeta de la izquierda
   empieza 16 px más abajo que la de la derecha, los títulos de las dos
   cabeceras no coinciden y se lee como si una estuviera mal puesta.

   La especificidad iguala a la de las reglas de arriba y va después, que es lo
   que la deja ganar.

   ── Y SÓLO CUANDO LA ESCONDIDA VA LA PRIMERA ─────────────────────────────

   La regla nació sin esa condición y se llevó por delante el caso contrario, que
   es más común: una tarjeta escondida **en medio** —el recorrido del contenedor
   en la mesa de Empaque, que sólo aparece al escanear— dejaba pegadas a las dos
   visibles de arriba y de abajo. El hueco que quitaba no era el suyo: era el que
   separa dos tarjetas que sí se están viendo.

   Lo que la escondida no debe empujar es el aire de arriba de la columna, y eso
   sólo ocurre cuando no hay nada antes que ella. En los tres contenedores
   (`st-container`, `st-wizard`, `st-stack`) eso ya lo resuelve la regla de
   arriba, que sólo separa de lo que se ve; esto queda para la pareja suelta
   `bloque + bloque` fuera de ellos. */
.d-none:first-child + .st-block,
.d-none:first-child + .st-cols,
[hidden]:first-child + .st-block,
[hidden]:first-child + .st-cols {
    margin-top: 0;
}

/* Dentro de una rejilla el aire lo pone `gap`. El margen de la pareja se le
   sumaría —32 px donde el resto de la pantalla lleva 16— y, en dos columnas,
   bajaría la tarjeta de la derecha respecto de la de la izquierda: dos
   columnas que empiezan a distinta altura sin que nada lo justifique. */
.st-cols > .st-block + .st-block {
    margin-top: 0;
}

/* Y todas miden lo mismo · una cabecera con botón y otra sin él no se alinean.

   El alto de la cabecera lo decidía su contenido: la que lleva el botón de
   actualizar mide 40 px de botón más el relleno, y la que sólo lleva título mide
   la línea de texto. En dos tarjetas puestas una al lado de la otra —que es como
   está media estación— eso deja los dos títulos a distinta altura y el cuerpo de
   una empezando 16 px más abajo que el de la otra: se lee como si una de las dos
   estuviera mal puesta.

   Los 64 px son los que ya medía la que lleva botón, así que nada de lo que
   estaba bien se mueve; lo que cambia es que la de al lado la alcanza. */
.st-block-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 64px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-block-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
    margin: 0;
}

/* El título empuja al resto a la derecha.

   Con dos hijos —título y cuenta— `space-between` ya los separaba, pero desde
   que la cabecera lleva además el botón de actualizar son tres, y entonces
   `space-between` deja la cuenta flotando en mitad de la fila, lejos de los dos
   sitios donde significa algo. Con el margen automático, el título se queda a la
   izquierda y lo demás viaja junto a la derecha. */
.st-block-head > .st-block-title {
    margin-right: auto;
}

/* Un título que lleva una marca colgando · la prisa del nesteo en Corte.

   La marca es del título y tiene que quedarse con él. Suelta como hermana en la
   cabecera, `space-between` se la llevaba al borde derecho y quedaba pegada al
   contador: «Prioridad alta 2 láminas» se lee como si calificara al contador.
   Dentro del título va donde tiene que ir, y el título deja de estar en
   versalitas apretadas sólo para ella: la marca conserva su propia caja. */
.st-block-title--con-marca {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
}

/* El título va en versalitas y espaciado; la marca, no. Sin esto la prisa se
   escribiría «PRIORIDAD ALTA» con el mismo espaciado del rótulo y dejaría de
   parecerse a la que lleva cada renglón dos centímetros más abajo, que es todo
   lo que tiene que hacer: parecerse. */
.st-block-title--con-marca > .st-tag {
    text-transform: none;
    letter-spacing: normal;
}

/* Botón de sólo icono para la cabecera de una tabla.

   Cuadrado y sin rótulo porque el título ya ocupa la fila y en una tablet el
   ancho es lo que falta. Los 40 px son el mismo tamaño que ya usaban a mano los
   botones de cabecera —«Quitar todos»— y siguen siendo un blanco de dedo con
   guante; el alto de golpe completo, `--st-hit`, se reserva para lo que se pulsa
   sin mirar. */
.st-btn--icon {
    min-height: 40px;
    width: 40px;
    padding: 0;
    flex-shrink: 0;
}

.st-btn--icon.is-busy::after {
    width: 18px;
    height: 18px;
    border-width: 2px;
}

.st-block-body {
    padding: 16px;
}

/* ── La tarjeta que se trabaja · con su acción pegada al borde de abajo ───

   UNA TARJETA NORMAL CRECE HACIA ABAJO Y SE LLEVA SU BOTÓN CON ELLA. En
   «Terminar y guardar», el panel de la caja lleva dentro la lista de lo que
   falta, lo que ya metió, los avisos y un pliegue: con seis renglones
   pendientes, «Cerrar y enviar» quedaba dos pantallas más abajo. El operador
   tiene la caja llena delante y lo que hace con ella es cerrarla, así que ese
   botón no puede depender de cuánto haya que desplazarse para encontrarlo.

   La barra se queda pegada al borde de abajo de la pantalla mientras la tarjeta
   esté a la vista, y baja a su sitio cuando se llega al final. No se acota el
   alto de la tarjeta —eso deja dos desplazamientos, uno dentro de otro, y con
   un dedo con guante el de dentro se pierde— ni se fija la columna entera, que
   con una lista larga esconde justo el final.

   La tarjeta tiene que dejar de recortar para que esto funcione: `overflow:
   hidden` convierte a la tarjeta en el marco al que se pega la barra, y
   entonces vuelve al fondo. El redondeo de abajo lo pone la propia barra. */
.st-block--panel {
    overflow: visible;
}

/* ── La barra de la caja · lo que se firma, escrito al lado del botón ─────

   No es una fila de botones: es el resumen de la carga. Cerrar un contenedor se
   firma, y lo que hay que tener delante para firmarlo es cuántas piezas lleva,
   de qué números de parte, de qué colada y a dónde va. Eso vivía repartido
   entre la cabecera del panel, los renglones de dentro y un campo suelto de
   «siguiente proceso»; aquí va junto, en la única parte de la tarjeta que no se
   va de la pantalla. */
.st-loadbar,
.st-signbar {
    position: sticky;
    /* Al borde de la pantalla, como `.st-wizard-foot`: con 0 dejaba ver pasar lo de abajo. */
    bottom: calc(-1 * var(--st-gutter));
    z-index: 2;
    box-shadow: 0 -10px 16px -12px rgb(0 0 0 / 0.45);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px 16px;
    padding: 12px 16px;
    border-top: 1px solid var(--tw-border-medium);
    border-radius: 0 0 var(--tw-radius-md) var(--tw-radius-md);
    background-color: var(--tw-bg-secondary);
}

/* `display: flex` gana al `[hidden]` de la hoja del navegador, así que la barra
   vacía se seguía viendo como una franja gris debajo del panel. */
.st-loadbar[hidden],
.st-signbar[hidden] {
    display: none;
}

/* ── La barra de firma · lo mismo, donde lo que se firma no es una carga ──

   Empaque tenía el problema que la barra de Corte resolvió y no la barra: con
   seis contenedores por vaciar, «Marcar armada y firmar» quedaba una pantalla
   más abajo, y el operador que acaba de meter la última pieza tiene la caja
   cerrada delante. El botón de firmar no puede depender de cuánto haya que
   desplazarse para encontrarlo.

   Es `.st-loadbar` por dentro —el mismo sticky, el mismo borde, el mismo
   fondo— y se separa sólo por lo que lleva escrito: aquélla resume una carga
   (piezas, colada, destino) y ésta acompaña una frase corta con su acción. Dos
   nombres para que ninguna de las dos tenga que aguantar el maquetado de la
   otra.

   Va con el bloque que la contiene en `overflow: visible`: si el bloque recorta,
   se convierte en el marco al que la barra se pega y vuelve al fondo. */
.st-signbar {
    justify-content: space-between;
    background-color: var(--tw-bg-secondary);
    border-radius: var(--tw-radius-md);
}

/* El texto se encoge, el botón no: «Faltan 3 pieza(s) por registrar en su caja»
   no puede partir «Marcar armada y firmar» en tres renglones. */
.st-signbar-what {
    flex: 1 1 220px;
    min-width: 0;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-signbar-go {
    flex-shrink: 0;
}

/* El bloque que la lleva dentro no puede recortar. Mismo motivo que
   `.st-block--panel`. */
.st-block--signable {
    overflow: visible;
}

/* El resumen se encoge; el botón no. Al revés, un número de parte largo dejaba
   «Cerrar y enviar a Doblado» partido en tres renglones. */
.st-loadbar-what {
    flex: 1 1 240px;
    min-width: 0;
}

.st-loadbar-count {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
}

/* Los números de parte de dentro, en una línea. Son la comprobación de que la
   caja es la que se cree: si dice uno que no se metió, el error está aquí y no
   tres procesos más tarde. */
.st-loadbar-parts {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    overflow-wrap: anywhere;
}

/* Lo que las láminas de esta caja siguen sin tener guardado. Va en el color del
   aviso y no en el del resto del resumen: es lo único de la barra que puede
   estar diciendo que la caja no lleva lo que dice llevar. Ver `pintarBarra`. */
.st-loadbar-pending {
    margin-top: 4px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-tag-orange-fg);
    overflow-wrap: anywhere;
}

.st-loadbar-go {
    flex: 0 0 auto;
}

/* ── Campo de escaneo ─────────────────────────────────────────────────── */

.st-scan-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
    margin-bottom: 8px;
}

/* Punto vivo: dice que el campo está escuchando al lector. */
.st-scan-label::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--tw-tag-green-fg);
    flex-shrink: 0;
}

.st-scan-label--off::before {
    background-color: var(--tw-font-extra-light);
}

.st-scan {
    width: 100%;
    min-height: 64px;
    padding: 0 16px;
    font-size: var(--st-text-data);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
}

/* La condición de la acción, encima del lector.
 *
 * Abrir la caja pide gafete o PIN, y eso hay que saberlo **antes** de ir por la
 * caja: una petición de credencial que aparece cuando ya se pasó por el lector
 * obliga a hacer el viaje dos veces. No es un cartel explicativo —de ésos ya se
 * quitaron— sino la condición de lo que hay justo debajo, dicha donde se
 * ejecuta y en una línea.
 *
 * En el gris secundario y no en un recuadro de aviso: no ha pasado nada malo, y
 * un recuadro ámbar sobre el lector se lee como un problema del puesto. */
.st-scan-nota {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
    color: var(--tw-font-secondary);
    font-size: var(--st-text-sm);
    line-height: 1.35;
}

.st-scan-nota > .ti {
    flex: none;
    font-size: 1.15em;
    color: var(--tw-font-light);
}

.st-scan:focus {
    outline: none;
    border-color: var(--tw-accent);
    box-shadow: 0 0 0 3px var(--tw-accent-secondary);
}

.st-scan:disabled {
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-light);
}

/* ── Espera del lector · escanear no es rellenar un formulario ─────────
 *
 * El lector —por puerto serie o de los que teclean— no necesita foco ni cursor,
 * así que un paso de escaneo no lleva campo: lleva una espera que dice qué hay
 * que pasar, enseña lo que se leyó y **se mueve mientras valida**. El borde
 * punteado es la señal de que ahí no se teclea; se vuelve sólido —y de color— en
 * cuanto hay una respuesta que dar.
 *
 * Lo montan `station.js` (los pasos de las estaciones) y el modal del gafete,
 * con el mismo armazón a propósito: es el mismo gesto y tiene que verse igual.
 */

.st-scan-wait {
    display: flex;
    align-items: center;
    gap: 20px;
    min-height: 112px;
    padding: 20px 24px;
    border: 2px dashed var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-secondary);
    color: var(--tw-font-primary);
    transition:
        border-color var(--tw-transition),
        background-color var(--tw-transition);
}

/* El disco del lector · lo que dice «te estoy escuchando».
   El aro late despacio mientras espera y gira mientras valida: a un metro de la
   pantalla y de pie, un cambio de color no se percibe y un icono quieto se lee
   como una pantalla congelada. */
.st-scan-orb {
    position: relative;
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-secondary);
}

.st-scan-orb i {
    font-size: 28px;
    line-height: 1;
}

/* El latido: un aro que crece y se apaga. Va en `::before` para que el `::after`
   quede libre para el giro de la validación. */
.st-scan-orb::before {
    content: '';
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    border: 2px solid currentColor;
    opacity: 0;
    animation: st-scan-latido 2s ease-out infinite;
}

@keyframes st-scan-latido {
    0% {
        transform: scale(0.86);
        opacity: 0.35;
    }
    70% {
        transform: scale(1.12);
        opacity: 0;
    }
    100% {
        opacity: 0;
    }
}

.st-scan-wait-title {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    /* `anywhere` y no `break-all`, que es lo que había.
     *
     * Este rótulo es dos cosas: una frase —«Escanea cada placa»— y, cuando ya se
     * leyó algo, el código leído, que es una tira sin espacios y más ancha que la
     * columna. `break-all` resolvía la segunda partiendo también la primera:
     * en un teléfono salía «Escanea cada pl / aca que estás gu / ardando».
     *
     * `anywhere` sólo parte cuando la palabra no cabe de ninguna manera, así que
     * el código sigue partiéndose y la frase vuelve a partirse por los espacios.
     * Se nota desde que la estación se abre en un teléfono. */
    overflow-wrap: anywhere;
}

.st-scan-wait[data-estado='validando'] {
    border-style: solid;
    border-color: var(--tw-accent);
}

.st-scan-wait[data-estado='validando'] .st-scan-orb {
    color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

/* Validando: el latido se apaga y en su lugar gira un aro. Es el mismo aro del
   botón trabajando —`tw-spin`, de twenty-theme.css— para que «estoy en eso» se
   vea igual se haya tocado un botón o pasado una etiqueta. */
.st-scan-wait[data-estado='validando'] .st-scan-orb::before {
    animation: none;
    opacity: 0;
}

.st-scan-wait[data-estado='validando'] .st-scan-orb::after {
    content: '';
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    border: 3px solid currentColor;
    border-top-color: transparent;
    animation: tw-spin 0.7s linear infinite;
}

.st-scan-wait[data-estado='ok'] {
    border-style: solid;
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

.st-scan-wait[data-estado='ok'] .st-scan-orb {
    color: var(--tw-tag-green-fg);
    background-color: transparent;
}

.st-scan-wait[data-estado='error'] {
    border-style: solid;
    border-color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

.st-scan-wait[data-estado='error'] .st-scan-orb {
    color: var(--tw-tag-red-fg);
    background-color: transparent;
}

/* Resuelto ya no late: el aro sólo dice «sigo esperando algo». */
.st-scan-wait[data-estado='ok'] .st-scan-orb::before,
.st-scan-wait[data-estado='error'] .st-scan-orb::before {
    animation: none;
    opacity: 0;
}

/* El texto de un estado resuelto va con el estado y no con un color fijo.
   Aquí había un `#1b1b1b` para todo, pensando que el fondo del estado era claro
   en los dos temas; en el oscuro `--tw-tag-red-bg` es casi negro y «No se pudo
   identificar» o «PIN incorrecto» no se leían (9 de octubre, en la puerta del
   asistente). El rótulo toma el color del estado y la pista el del texto
   principal: el gris de `.st-muted` sobre el rojo o el verde se apaga. */
.st-scan-wait[data-estado='ok'] .st-scan-wait-title {
    color: var(--tw-tag-green-fg);
}

.st-scan-wait[data-estado='error'] .st-scan-wait-title {
    color: var(--tw-tag-red-fg);
}

.st-scan-wait[data-estado='ok'] .st-muted,
.st-scan-wait[data-estado='error'] .st-muted {
    color: var(--tw-font-primary);
}

/* El PIN se ve como puntos sin ser `type="password"`: ese tipo es lo que hace
   que Chrome le meta la contraseña guardada de la cuenta de la terminal y que
   ofrezca guardar el PIN como si fuera ella (9 de octubre). */
.st-pin {
    -webkit-text-security: disc;
    text-security: disc;
    letter-spacing: 0.3em;
    font-variant-numeric: tabular-nums;
}

.st-pin:placeholder-shown {
    letter-spacing: normal;
}

/* ── El paso de escaneo entero · espera, respaldo y turno ─────────────── */

.st-scan-step {
    display: block;
}

/* Fuera de turno se apaga entero y deja de latir. El operador tiene que poder
   ver de un vistazo cuál de los dos pasos de la pantalla le toca, sin leer. */
.st-scan-step[data-turno='off'] {
    opacity: 0.55;
}

.st-scan-step[data-turno='off'] .st-scan-wait {
    background-color: transparent;
}

.st-scan-step[data-turno='off'] .st-scan-orb::before {
    animation: none;
    opacity: 0;
}

.st-scan-step[data-turno='off'] .st-scan-alt {
    display: none;
}

/* Los respaldos, en línea y envolviendo: en un teléfono son tres —cámara, foto
   y teclado— y en fila obligarían a desplazar la pantalla a lo ancho. */
.st-scan-alt {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}

/* ── El visor de la cámara ─────────────────────────────────────────────
 *
 * Proporción fija: sin ella el hueco mide cero hasta que la cámara entrega el
 * primer cuadro, y el paso entero salta justo cuando el operador ya está
 * apuntando a la etiqueta. */
.st-scan-cam {
    margin-top: 12px;
}

.st-scan-video {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--tw-radius-md);
    /* Negro fijo y no un token: la escala de grises se invierte con el tema
       —`--tw-gray-90` es casi blanco en oscuro— y un visor de vídeo tiene que
       ser oscuro en los dos. El vídeo nunca llena el marco exacto, y lo que se
       ve alrededor es esto. */
    background: #101010;
}

/* En un teléfono el visor se come la pantalla si se le deja: se acota a la
   mitad del alto para que la lista de lo ya escaneado siga a la vista. */
@media (max-width: 767px) {
    .st-scan-video {
        max-height: 45vh;
    }
}

.st-scan-manual {
    margin-top: 12px;
}

/* El campo y su confirmación en la misma línea: teclear un código termina en
   pulsar algo, y ese algo no puede estar a media pantalla de distancia. */
.st-scan-manual-row {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.st-scan-manual-row .st-scan {
    flex: 1 1 auto;
    min-width: 0;
}

.st-scan-manual-row .st-btn {
    flex-shrink: 0;
    min-height: 64px;
    padding: 0 24px;
}

/* Quien pidió menos movimiento no se queda sin la señal: el latido y el giro
   bajan a un pulso lento en vez de desaparecer. */
@media (prefers-reduced-motion: reduce) {
    .st-scan-orb::before {
        animation-duration: 6s;
    }

    .st-scan-wait[data-estado='validando'] .st-scan-orb::after {
        animation-duration: 2.4s;
    }
}

/* El respaldo tecleado se ofrece, no se anuncia: no compite con el escaneo. */
.st-btn--plain {
    min-height: 40px;
    padding: 0 12px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    background-color: transparent;
    border-color: transparent;
}

.st-btn--plain:hover {
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-primary);
}

/* ── Campos normales, en tamaño de estación ───────────────────────────── */

.st-field-label {
    display: block;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-secondary);
    margin-bottom: 6px;
}

/* El campo que no se puede dejar vacío, marcado como en el panel: mismo
   asterisco y mismo rojo, para que quien pasa del uno al otro no tenga que
   aprender dos señales. */
.st-field-label.required::after,
.st-scan-label.required::after {
    content: '*';
    margin-left: 0.25rem;
    color: var(--tw-tag-red-fg);
}

.st-input,
.st-select {
    width: 100%;
    min-height: var(--st-hit);
    padding: 0 12px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-sm);
}

.st-input:focus,
.st-select:focus {
    outline: none;
    border-color: var(--tw-accent);
}

/* ── Datos ────────────────────────────────────────────────────────────── */

/* Códigos: cifras de ancho fijo y algo de aire entre caracteres. Es lo que
   permite leer un serial de un vistazo y detectar un dígito cambiado. */
.st-code {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.03em;
    font-weight: var(--tw-weight-medium);
}

.st-data {
    font-size: var(--st-text-data);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.st-muted {
    color: var(--tw-font-secondary);
    font-size: var(--st-text-sm);
}

/* En la estación nada se escribe por debajo de 14: el `small` de Bootstrap
   (0.875em, 12 px sobre un texto de 14) llegaba en guiones que comparte el
   panel —el emplayado del scrap, quién asignó una existencia— (9-oct-2026). */
.st-shell .small,
.st-shell small,
.modal .small {
    font-size: var(--st-text-sm);
}

.st-table {
    width: 100%;
    border-collapse: collapse;
}

.st-table th {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
    text-align: left;
    padding: 8px 12px;
    border-bottom: 1px solid var(--tw-border-medium);
    white-space: nowrap;
}

.st-table td {
    font-size: var(--st-text-md);
    padding: 12px;
    border-bottom: 1px solid var(--tw-border-light);
    vertical-align: middle;
}

.st-table tr:last-child td {
    border-bottom: 0;
}

/* ── Lista seleccionable (solicitudes, renglones, estaciones) ─────────── */

.st-list {
    border-top: 1px solid var(--tw-border-light);
}

/* El renglón de 48 · lo que se lee de corrido dentro de una tarjeta (las cajas de
   una tarima, lo que lleva un bulto). Iba con `style="min-height: 48px"`. */
.st-list-item.st-list-item--md {
    min-height: var(--st-hit-bar);
}

.st-list-item {
    /* Las dos que lee `.st-chain` y la pastilla del número: el renglón de lista
       es más apretado que el de la bandeja, y la línea tiene que salirse
       justo su relleno para tocar la del vecino. */
    --st-task-pad: 14px;
    --st-task-bg: var(--tw-bg-primary);

    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    min-height: 64px;
    padding: var(--st-task-pad) 16px;
    border: 0;
    border-bottom: 1px solid var(--tw-border-light);
    background: transparent;
    text-align: left;
    color: inherit;
    text-decoration: none;
    transition: background-color var(--tw-transition);
}

.st-list-item:last-child {
    border-bottom: 0;
}

/* El bloque de texto se come el sitio que sobra · lo demás queda a la derecha.

   El renglón es `space-between` con tres hijos —texto, distintivo y flecha—, y
   sin esto el espacio libre se repartía **entre** ellos: el distintivo caía
   donde lo dejara el largo del texto de su izquierda, así que en una lista de
   seis órdenes los seis terminaban en seis sitios distintos y la columna que el
   ojo busca no existía. Con el texto creciendo ya no hay hueco que repartir: el
   distintivo se pega a la flecha y todos acaban en la misma vertical.

   Sólo el primer `div`: hay renglones cuyo primer hijo es una casilla o un
   icono, y ésos no deben estirarse. El renglón de piezas ya lo resolvía por su
   cuenta con `.st-pick-main`, que es esta misma regla con nombre propio. */
.st-list-item > div:first-child {
    flex: 1 1 auto;
    min-width: 0;
}

/* La cabecera de un grupo de renglones · la lámina de la que salen las piezas.

   Es un renglón más y a la vez no lo es: no se pulsa, no lleva cantidad y lo que
   dice vale para todos los de debajo. Sin un fondo que lo separe, la lista se
   lee como cinco renglones del mismo rango y el primero parece una pieza más. */
.st-list-item--head {
    background-color: var(--tw-bg-secondary);
}

.st-list-item--head:hover {
    background-color: var(--tw-bg-secondary);
}

/* En un teléfono el renglón no cabe en una línea · y lo que se parte es el dato.

   El renglón es «lo que es» a la izquierda y «lo que se hace con ello» a la
   derecha, y a 390 px los dos botones se quedan con el ancho: el código de la
   placa se parte en tres líneas de cuatro caracteres y el último botón se sale
   de la pantalla, arrastrando el desplazamiento horizontal de la página entera.
   Envuelto, las acciones bajan a su propia línea y el dato se lee. */
@media (max-width: 575.98px) {
    .st-list-item {
        flex-wrap: wrap;
    }
}

.st-list-item:hover {
    background-color: var(--tw-bg-tertiary);
}

/* El renglón que no se puede elegir pero sí consultar: va apagado con
   `aria-disabled`, no con `disabled`, para que el plano y el historial que
   lleva dentro sigan recibiendo el clic. */
.st-list-item[aria-disabled='true'] {
    cursor: default;
}

.st-list-item[aria-disabled='true']:hover {
    background-color: transparent;
}

.st-list-item[aria-disabled='true'] > div:first-child,
.st-list-item[aria-disabled='true'] .st-tag {
    opacity: 0.55;
}

/* El renglón elegido se dice con el fondo, como el resto del sistema marca la
   fila activa (`.tw-item-row.is-selected`, `.plano-lista-zona.is-selected`).
   Llevaba además una barra de acento a la izquierda que el tema no usa para
   «elegido» —la reserva para un destino entre dos o para lo que espera un
   escaneo— (paridad, 10-oct-2026). */
.st-list-item--active {
    background-color: var(--tw-accent-secondary);
}

.st-list-item--active:hover {
    background-color: var(--tw-accent-secondary);
}

.st-list-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
}

/* El «#» de la hoja impresa de Lantek · la primera columna del renglón.

   EN EL PAPEL ES UNA COLUMNA, y aquí también. El reporte de Lantek trae una
   tabla cuya primera columna es el «#», y ese número va además rotulado sobre
   cada pieza del dibujo del acomodo: el operador baja por esa columna buscando
   la línea que está contando. Puesto en línea con el nombre se leía como una
   palabra más del título —y peor, con un número de parte largo se llevaba un
   renglón entero de los tres que le caben al nombre en la tablet—.

   Ancho fijo para que los números formen columna: es lo que hace que se recorran
   con la vista en vez de leerse uno a uno. Monoespaciada por lo mismo.

   `:first-child` en el selector, y no sólo la clase, porque la regla de al lado
   —`.st-list-item > div:first-child`— le daría el `flex: 1 1 auto` del nombre y
   la columna se estiraría con el renglón. */
.st-list-item > .st-pos:first-child {
    flex: none;
    width: 3.25rem;
    color: var(--tw-text-tertiary);
    font-family: var(--tw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    /* Arriba y no al centro: el renglón crece hacia abajo con el trabajo y el
       aviso de cuadre, y el número pertenece a la primera línea. */
    align-self: flex-start;
    padding-top: 0.125rem;
}

/* El mismo número en la ficha de Empezar, que es una lista más apretada y sin
   columnas: ahí va en línea, delante del nombre. */
.st-pos-inline {
    display: inline-block;
    min-width: 2.5rem;
    color: var(--tw-text-tertiary);
    font-family: var(--tw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: var(--st-text-sm);
}

/* El título de un renglón que lleva una marca al lado · la prisa del cliente.

   Envuelve y alinea por el centro para que la marca no empuje la línea del
   nombre hacia arriba cuando el nombre es largo y la marca baja a un segundo
   renglón. `align-items: center` y no `baseline` porque lo que hay al lado es
   una píldora con caja propia, no otra palabra. */
.st-list-title--con-marca {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
}

/* ── Listas y tablas largas ───────────────────────────────────────────────

   Una lista crece: hoy hay una orden abierta y en agosto habrá cuarenta. Sin
   un tope, el bloque empuja el resto de la pantalla fuera de la vista y el
   operador pierde el campo de escaneo, que es lo único que no puede perder.

   El tope va en `vh` y no en píxeles porque las terminales de piso y el
   escritorio del supervisor no miden lo mismo. */
.st-list--scroll {
    max-height: 42vh;
    overflow-y: auto;
}

/* Cuántos hay. Un contador evita tener que desplazarse para saber si la
   lista tiene tres cosas o trescientas. */
.st-block-count {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
}

/* Tabla con encabezado fijo: al desplazar cien placas, saber qué columna se
   está leyendo importa más que ganar 30 px de alto. */
.st-table-wrap {
    max-height: 52vh;
    overflow: auto;
}

.st-table-wrap .st-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--tw-bg-primary);
}

/* Filtro de lista: aparece cuando la lista es larga de verdad. */
/* El filtro de una lista, al escalón de la barra (48): con 40 y letra de 14 era
   el control más chico de pantallas cuyos renglones miden 64 (9-oct-2026). */
.st-filter {
    width: 100%;
    min-height: var(--st-hit-bar);
    padding: 0 14px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-sm);
}

.st-filter:focus {
    outline: none;
    border-color: var(--tw-accent);
}

/* ── Estado vacío y avisos ────────────────────────────────────────────── */

.st-empty {
    padding: 32px 16px;
    text-align: center;
    color: var(--tw-font-light);
    font-size: var(--st-text-md);
}

/* Mismo criterio que `.tw-note`: el tono va en el fondo y en el borde entero, no
   en un filo de color a la izquierda. A un metro de la terminal, además, un
   borde de 3 px en un solo lado no se ve; la caja teñida sí. */
.st-note {
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-primary);
    padding: 12px 14px;
    font-size: var(--st-text-md);
}

.st-note--info {
    border-color: var(--tw-tag-blue-fg);
    background-color: var(--tw-tag-blue-bg);
}

.st-note--warning {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-note--danger {
    border-color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

/* ── La diferencia, partida por número de parte ────────────────────────────

   Va dentro del aviso del conteo, debajo del total. Dos columnas y no una
   frase: el número de parte a la izquierda y cuántas sobran o faltan a la
   derecha, alineadas, para que se lean de un vistazo cuando son cuatro o cinco
   renglones. `tabular-nums` porque son cantidades que se comparan entre sí. */
.st-diff-parts {
    margin-top: 8px;
    border-top: 1px solid var(--tw-border-medium);
    padding-top: 6px;
    font-size: var(--st-text-sm);
}

.st-diff-part {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 2px 0;
}

.st-diff-name {
    overflow-wrap: anywhere;
}

.st-diff-qty {
    flex: 0 0 auto;
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.st-note--success {
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

/* ── Etiquetas de estado ──────────────────────────────────────────────── */

.st-tag {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 10px;
    border-radius: var(--tw-radius-pill);
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    white-space: nowrap;
    background-color: var(--tw-tag-gray-bg);
    color: var(--tw-tag-gray-fg);
}

.st-tag--green {
    background-color: var(--tw-tag-green-bg);
    color: var(--tw-tag-green-fg);
}

.st-tag--blue {
    background-color: var(--tw-tag-blue-bg);
    color: var(--tw-tag-blue-fg);
}

.st-tag--orange {
    background-color: var(--tw-tag-orange-bg);
    color: var(--tw-tag-orange-fg);
}

.st-tag--red {
    background-color: var(--tw-tag-red-bg);
    color: var(--tw-tag-red-fg);
}

/* El retal: morado en todas partes, como su etiqueta de tipo en el panel. */
.st-tag--purple {
    background-color: var(--tw-tag-purple-bg);
    color: var(--tw-tag-purple-fg);
}

/* ── La misma marca, dicha en voz baja ─────────────────────────────────────

   UNA MARCA QUE SE REPITE DEJA DE SER UNA MARCA. La prisa del cliente sale en
   la cabecera de un grupo y otra vez en cada renglón de ese grupo, y las dos
   veces hacen falta: arriba se lee al entrar, abajo con la lámina delante y el
   código en la mano. Lo que no puede es salir idéntica las dos veces —en un
   nesteo de dos láminas eso son tres píldoras rojas iguales en un palmo de
   pantalla— porque entonces el ojo deja de contar cuántas hay y sólo ve rojo.

   Así que la de arriba se pinta en plano: el mismo rótulo y el mismo tono, sin
   relleno. Es lo que el panel ya hace con `tw-flag` en sus listados, donde la
   única píldora con fondo es la del estado.

   El tono se hereda de `--red` o `--orange`, que ya lo pusieron en `color`: lo
   único que hace falta es quitar el fondo y el relleno lateral. Lo neutro
   —`normal`, sin modificador de tono— cae al gris de `.st-tag` y aquí queda en
   el color del texto secundario, que es lo que le toca a lo que no corre. */
.st-tag--plano {
    height: auto;
    padding: 0;
    background-color: transparent;
}

.st-tag--plano:not(.st-tag--red):not(.st-tag--orange):not(.st-tag--blue):not(.st-tag--green):not(.st-tag--purple) {
    color: var(--tw-font-secondary);
}

/* ── Asistente · una decisión a la vez ────────────────────────────────────

   El operador de piso no compara: decide. Enseñarle la orden, los renglones,
   los datos del embarque y el resumen a la vez es pedirle que sostenga cuatro
   cosas en la cabeza con las manos ocupadas y una fila de placas detrás.

   Así que la pantalla enseña **un paso**, con lo que hace falta para tomar esa
   decisión y nada más. La barra de arriba dice dónde está y cuánto queda —sin
   eso, un paso aislado se siente como un callejón—, y el pie tiene siempre las
   dos únicas salidas: volver y seguir.

   Los pasos ya recorridos son pulsables: corregir la orden elegida no debe
   costar cancelar y empezar de nuevo. Los que vienen, no: no se puede confirmar
   una recepción de la que aún no se ha elegido la orden. */

.st-wizard {
    /*
       Más ancho que el panel a propósito. Con 940 px, en el monitor de un
       puesto de corte —que es grande y está a un metro— quedaban dos tercios
       de pantalla en negro y la lista de opciones se leía como una columna
       estrecha en medio de la nada. La escala de la estación es grande; el
       lienzo también tiene que serlo.
    */
    margin: 0 auto;
}

.st-steps {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin-bottom: 20px;
}

.st-step {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    row-gap: 2px;
    min-width: 0;
    padding: 12px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: var(--tw-font-light);
    text-align: left;
    font: inherit;
    cursor: default;
}

/* El número, no un icono: dice cuántos son y en cuál va sin leer nada. */
.st-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--tw-border-strong);
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.st-step-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Qué significa ese paso, debajo de su nombre.

   El rótulo solo nombra —«Contenedor», «Recepción», «Cuántas»— y eso basta para
   quien ya sabe de qué va. Nadie sabe todavía: esto se está implementando y el
   operador llega a una barra de cuatro palabras sueltas sin ninguna forma de
   averiguar qué se le está pidiendo en cada una ni qué pasa al terminarla.

   Va **dentro del paso** y no en un cartel aparte, que es la diferencia: se lee
   donde se decide, se ve el camino entero de un vistazo y desaparece con la
   barra cuando no hay camino que enseñar.

   Se sangra 42 px —los 32 del número más los 10 de hueco— para que caiga
   debajo del rótulo y no debajo del círculo. */
.st-step-what {
    flex: 1 0 100%;
    padding-left: 42px;
    font-size: var(--st-text-sm);
    line-height: 1.25;
    color: var(--tw-font-light);
}

.st-step--now .st-step-what,
.st-step--done .st-step-what {
    color: var(--tw-font-secondary);
}

.st-step--done {
    color: var(--tw-font-secondary);
    cursor: pointer;
}

.st-step--done .st-step-num {
    background-color: var(--tw-tag-green-bg);
    border-color: var(--tw-tag-green-fg);
    color: var(--tw-tag-green-fg);
}

.st-step--now {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
    color: var(--tw-font-primary);
}

.st-step--now .st-step-num {
    background-color: var(--tw-accent);
    border-color: var(--tw-accent);
    color: #fff;
}

/* Un paso que no aplica —«Sin carrito» no tiene código que registrar— no se
   pinta como hecho ni se puede tocar: el círculo punteado dice que se saltó. */
.st-step:disabled {
    color: var(--tw-font-light);
    cursor: default;
}

.st-step:disabled .st-step-num {
    background-color: transparent;
    border-style: dashed;
    border-color: var(--tw-border-strong);
    color: var(--tw-font-light);
}

/* ── La barra apretada · sólo el paso de ahora se explica ──────────────────

   Con seis pasos en el iPad viejo —1024 de ancho— cada caja mide 160 px, la
   explicación se parte en cinco renglones y un rótulo se corta con puntos
   suspensivos: la barra se lleva 156 px, un tercio de la pantalla, antes de
   empezar el trabajo. Con cuatro pasos a 1180 cabe holgada y no se toca.

   Apretada, el paso queda en número y rótulo, y la explicación la enseña
   **sólo el paso de ahora**. La regla se conserva —donde se está decidiendo se
   sigue leyendo qué significa— y lo que se va es lo que nadie está leyendo:
   los cinco renglones de los pasos que no tocan.

   Quién la pone, en `wizard.js`: se decide midiendo, porque lo que no cabe no
   es el ancho a secas sino los pasos que haya, lo largo de sus rótulos y lo
   que la pantalla les reescriba al entrar. */
.st-steps--compacta {
    position: relative;
    /*
       El hueco del renglón de abajo, que va fuera del flujo. Fuera y no dentro
       del paso porque dentro no cabe: a seis pasos son 160 px de ancho, y eso
       es lo que partía la explicación en cinco renglones. Abajo la tiene
       entera, del ancho de la barra.

       Cuánto mide lo dice `wizard.js` al medir —casi siempre un renglón; dos,
       con una explicación larga en una tablet en vertical—. Los 22 px son ese
       renglón, por si la medida no ha llegado.
    */
    padding-bottom: var(--st-steps-que, 22px);
}

.st-steps--compacta .st-step {
    padding: 10px 12px;
}

/* El rótulo parte en dos renglones antes que recortarse: «¿Qué vas a ar…» no
   dice nada, y apretada es el único texto que le queda al paso.

   `flex` y `min-width: 0` para que parta **dentro del renglón del número**. Sin
   eso pide su ancho entero, no cabe al lado del círculo y el envoltorio lo baja
   a una línea propia: el paso crecía 21 px justo cuando se estaba apretando. */
.st-steps--compacta .st-step-title {
    flex: 1 1 0;
    min-width: 0;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.2;
}

.st-steps--compacta .st-step-what {
    display: none;
}

.st-steps--compacta .st-step--now .st-step-what {
    display: block;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding-left: 0;
    /* Se dibuja fuera de su caja, así que un toque ahí no es un toque en el
       paso: el renglón explica, no navega. */
    pointer-events: none;
}

/* Con cuatro pasos en un teléfono no cabe el rótulo. El número sí, y basta:
   la pregunta del paso ya está escrita en grande dentro del panel, y debajo de
   ella va lo que significa. */
@media (max-width: 767px) {
    .st-steps {
        gap: 6px;
    }

    .st-step {
        justify-content: center;
        padding: 10px 8px;
    }

    /* Y el renglón del paso de ahora tampoco: apretada o no, en el teléfono la
       barra es la fila de números. La pregunta y su explicación ya están en
       grande dentro del panel. */
    .st-step-title,
    .st-step-what,
    .st-steps--compacta .st-step--now .st-step-what {
        display: none;
    }

    .st-steps--compacta {
        padding-bottom: 0;
    }
}

/* La pregunta del paso. Va dentro del panel y en grande porque es lo único
   que el operador tiene que responder ahora mismo. */
/* La fila de la pregunta de un paso, cuando además lleva algo a la derecha.

   Es la cabecera de arriba del bloque —«¿Qué orden llegó?» y su explicación— y
   ahí es donde va el botón de actualizar en las pantallas de asistente: la
   tabla que refresca cuelga de esa pregunta, y no todas tienen una cabecera de
   tabla propia debajo. `flex-start` y no `center` para que el botón quede en el
   renglón del título y no flotando a media explicación. */
.st-step-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.st-step-ask {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.2;
    margin: 0;
}

.st-step-hint {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    margin: 4px 0 0;
}

/* La pregunta y el lector que la contesta. Pegados, el recuadro punteado se
   leía como el borde de la pregunta: «¿Qué salida volvió?» encima de la raya.
   Va en el componente y no en cada vista porque el lector lo arma `armarPaso`
   justo detrás de lo que la plantilla ponga antes del campo. */
:is(.st-step-ask, .st-step-hint) + .st-scan-step {
    margin-top: 16px;
}

/* El folio con el que hay que ir al mostrador. Grande porque se dicta de
   memoria en el camino: quien cierra Etiquetar se levanta de la mesa y lo lee
   de un vistazo, no lo copia. */
/* El código de lo que se acaba de hacer, en grande: el mismo escalón que el
   folio del paso final. Iba con `style="font-size: 2rem"` en seis pantallas. */
.st-data.st-data--folio {
    font-size: var(--st-text-xl);
}

.st-step-folio {
    margin: 12px 0 0;
    font-size: var(--st-text-xl);
    font-weight: var(--tw-weight-semibold);
    color: var(--tw-font-primary);
    letter-spacing: 0.02em;
}

/* Pie fijo al fondo del panel: en una pantalla táctil la salida no se busca,
   está siempre en el mismo sitio. */
/* El pie del asistente, pegado abajo. Salvador, 12 de septiembre de 2026: «en
   las estaciones maneja todo sticky abajo con botón, para que no tengan que
   scrollear para verlo». Con tres números de parte que contar, «Registrar conteo»
   quedaba una pantalla más abajo en el iPad. Es el trato que ya tenían la barra
   de la caja y la de firma. */
/* Pegado al borde de la pantalla, no al relleno de `.st-body`. Salvador, 8 de
   octubre de 2026: *«en todos los sticky footers no me gusta como deja pasar lo
   de abajo»*. Con `bottom: 0` el pie se quedaba a `--st-gutter` del borde, porque
   lo pegajoso se mide contra la caja de desplazamiento menos su relleno, y en esa
   franja se veía pasar el contenido del paso. La sombra de arriba dice que lo de
   detrás sigue. */
.st-wizard-foot {
    position: sticky;
    bottom: calc(-1 * var(--st-gutter));
    z-index: 2;
    box-shadow: 0 -10px 16px -12px rgb(0 0 0 / 0.45);
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Envuelve en cuanto no cabe. Sin esto, en un teléfono el botón que cierra
       el paso se salía de la pantalla por la derecha y con él toda la página:
       el ancho del pie arrastraba el `body` entero. */
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px;
    border-top: 1px solid var(--tw-border-light);
    background-color: var(--tw-bg-primary);
}

.st-wizard-foot .st-btn {
    /* El rótulo puede partirse en dos líneas antes que empujar el pie. */
    min-width: 0;
    white-space: normal;
}

@media (min-width: 768px) {
    .st-wizard-foot .st-btn--primary {
        min-width: 220px;
    }
}

/* En un teléfono los botones del pie ocupan el ancho, en el orden en que se
   usan: la acción principal abajo, donde llega el pulgar. */
@media (max-width: 767px) {
    .st-wizard-foot,
    .st-wizard-foot > div {
        flex-direction: column-reverse;
        align-items: stretch;
        width: 100%;
    }

    .st-wizard-sum {
        text-align: center;
    }
}

/* Lo que se lleva decidido, al lado del botón que cierra el paso. */
.st-wizard-sum {
    font-size: var(--st-text-md);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
}

/* ── Fila con casilla · marcar y desmarcar con guante ─────────────────────

   La casilla nativa mide 13 px. Con guante no se acierta, así que lo pulsable
   es la fila entera y la casilla solo dibuja el estado. */

.st-pick {
    display: flex;
    align-items: center;
    gap: 16px;
    width: 100%;
    min-height: var(--st-row);
    padding: 14px 16px;
    border: 0;
    border-bottom: 1px solid var(--tw-border-light);
    background: transparent;
    text-align: left;
    color: inherit;
    cursor: pointer;
    transition: background-color var(--tw-transition);
}

.st-pick:last-child {
    border-bottom: 0;
}

.st-pick:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-pick-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border: 2px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-primary);
    color: transparent;
    font-size: 20px;
}

.st-pick--on .st-pick-box {
    background-color: var(--tw-accent);
    border-color: var(--tw-accent);
    color: #fff;
}

/* Marcada, la fila entera se tiñe: a un metro, un cuadrito de 32 px no se ve
   desde el otro lado del pasillo y la lista se lee como si no hubiera nada
   elegido. */
.st-pick--on {
    background-color: var(--tw-accent-secondary);
}

.st-pick-main {
    flex: 1 1 auto;
    min-width: 0;
}

.st-pick-side {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 12px;
}

/* La etiqueta dibujada dentro de la fila que se marca.

   Dice CUÁL es el papel. «CHICA · SERIAL» y «CHICA · NÚMERO DE PARTE» se
   parecen escritas y son dos papeles distintos sobre la mesa; el dibujo los
   separa de un vistazo, que es lo que hace falta antes de decidir cuál sale
   hoy.

   No es una prueba de impresión: el símbolo va como marca de posición y el de
   verdad lo genera la Zebra. Fondo blanco siempre —la etiqueta es papel— y por
   eso no sigue al tema oscuro. */
.st-label-thumb {
    width: 200px;
    padding: 6px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-sm);
    background-color: #fff;
}

/* En el iPad vertical la fila tiene menos ancho, pero el dibujo no baja de
   aquí: por debajo el texto de la etiqueta deja de leerse y entonces las dos
   del juego vuelven a parecerse, que es lo que este dibujo viene a evitar. El
   que cede es el nombre, que se recorta y se sigue entendiendo. */
@media (max-width: 820px) {
    .st-label-thumb {
        width: 168px;
    }
}

/* Ya impresa: la fila sigue ahí —reimprimir es legítimo— pero apagada, para
   que no compita con lo que falta por hacer. */
.st-pick--spent {
    opacity: 0.55;
}

/* Y la que no se puede marcar en absoluto: en Guardar, la placa sin etiqueta.
   Se enseña —esconderla haría que alguien se la llevara al rack igual— pero el
   cursor dice, antes de pulsar, que ahí no hay nada que decidir. */
.st-pick--locked {
    cursor: not-allowed;
}

/* La que queda fuera de una selección, con su porqué a la vista (Cancelar
   etiquetas, 10 de octubre de 2026). Se apagan el código y la casilla, no la
   razón: es lo único que hay que leer en esa fila, y a 0.55 de opacidad en el
   tema oscuro ya no se leía. */
.st-pick--fuera {
    cursor: not-allowed;
}

.st-pick--fuera:hover {
    background-color: transparent;
}

.st-pick--fuera .st-pick-box,
.st-pick--fuera .st-list-title,
.st-pick--fuera .st-muted {
    opacity: 0.5;
}

.st-pick-porque {
    margin-top: 2px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* Cantidad editable dentro de la fila: lo normal es no tocarla, así que no
   se lleva el tamaño de un campo de captura. */
.st-pick-qty {
    width: 7rem;
    min-height: 48px;
    padding: 0 10px;
    font-size: var(--st-text-lg);
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-sm);
}

.st-pick-qty:focus {
    outline: none;
    border-color: var(--tw-accent);
}

/* La que falta por teclear: borde del tono de aviso entero, no una raya. */
.st-pick-qty--falta {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

/* Ancho × largo del sobrante: cada campo con su nombre encima, porque cada
   fila es su propio grupo y no hay cabecera común que los nombre. */
.st-retal-medidas {
    align-items: flex-end;
    gap: 8px;
    cursor: default;
}

.st-retal-medida {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
}

.st-retal-por {
    padding-bottom: 12px;
}

/* Encabezado de grupo dentro de una lista de piezas: el renglón al que
   pertenecen, con su colada. */
.st-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: var(--st-hit-bar);
    padding: 6px 16px;
    background-color: var(--tw-bg-secondary);
    border-bottom: 1px solid var(--tw-border-light);
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
}

/* ── La partida que se abre y se cierra ───────────────────────────────────

   Una recepción de seis renglones son doscientas placas apiladas: abierta
   entera no se recorre con el dedo. Cerrada, el encabezado tiene que decir lo
   que hay dentro —cuántas trae y cuántas van marcadas—, porque si no, cerrar
   sería esconder la decisión que se está tomando.

   Se pulsa el encabezado entero y no un triangulito: es la misma razón por la
   que la fila con casilla es pulsable de lado a lado. */

.st-group-head--toggle {
    cursor: pointer;
    min-height: var(--st-hit);
    /* A la letra de todo lo que se pliega (`.st-fold`): 16 y no los 14 de la
       cabecera de grupo que sólo rotula (9-oct-2026). */
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
}

.st-group-head--toggle:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-group-title {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

/* Apunta hacia abajo cuando está abierta y hacia el renglón cuando está
   cerrada. Bootstrap escribe `aria-expanded` en el disparador, así que el
   estado se lee de ahí y no hay que sincronizar una clase propia. */
.st-group-caret {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    font-size: 18px;
    line-height: 1;
    color: var(--tw-font-secondary);
    transition: transform var(--tw-transition);
}

.st-group-head--toggle[aria-expanded='false'] .st-group-caret {
    transform: rotate(-90deg);
}

/* La cuenta de la partida: normal y en cifras de ancho fijo, para que no baile
   al pasar de 9 a 10 marcadas. */
.st-group-count {
    display: block;
    font-weight: var(--tw-weight-normal);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
}

/* ── El papel del certificado ─────────────────────────────────────────────

   Dos entradas sobre el mismo dato, porque son dos situaciones distintas: en
   una tablet de piso el sobre se fotografía, y en la computadora del almacén el
   PDF ya está en el disco. Ofrecer solo una obliga a la otra mitad a resolverlo
   fuera del sistema, que es como el certificado acaba en un cajón.

   `capture="environment"` es lo que hace que el teléfono abra la cámara
   trasera directamente en vez del selector de archivos. */

.st-capture {
    display: flex;
    gap: 8px;
}

.st-capture > label {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: var(--st-hit);
    padding: 0 16px;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px dashed var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    cursor: pointer;
    text-align: center;
}

.st-capture > label:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-capture input[type='file'] {
    /* Fuera de la vista pero **no** `display: none`: escondido así, el campo
       sigue siendo enfocable y el `label` lo sigue abriendo en los navegadores
       de las tablets viejas del piso. */
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* Lo que ya se adjuntó. Con el nombre delante: en un lote de doce renglones,
   «archivo cargado» no dice cuál. */
.st-file {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: var(--st-hit);
    padding: 8px 12px;
    border: 1px solid var(--tw-tag-green-fg);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-tag-green-bg);
}

.st-file-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--st-text-sm);
}

.st-file-thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    object-fit: cover;
    border-radius: var(--tw-radius-sm);
}

/* ── Plegar y desplegar · un solo aspecto en todo el piso (9-oct-2026) ─────

   Salvador: «termina de homologar el diseño de todas las estaciones en cuanto
   a la manera de ocultar y mostrar, tamaños». Había seis maneras: «+/−» en los
   datos opcionales, un galón que giraba en los nesteos, el triángulo de las
   partidas de Almacén, iconos que se cambiaban sin girar en Verificar, un galón
   quieto en las procedencias y un botón sin galón en «Ver los sobrantes»; con
   alturas de 36 a 64 para el mismo gesto.

   Ahora todo lo que se pliega se dice igual:

     · el galón va a la izquierda del rótulo: cerrado apunta al rótulo y
       abierto hacia abajo, y gira (`--tw-transition`), no salta;
     · se toca el renglón entero, de `--st-hit` de alto;
     · el rótulo nombra lo que hay dentro —«Datos del embarque», «Las 3 láminas
       que no entran»— sin «Ver» ni «Ocultar»: eso ya lo dice el galón;
     · la cuenta, si la hay, a la derecha en `.st-fold-n`.

   Tres maneras de montarlo, un solo aspecto:
     · `<details class="st-fold">` con su `<summary>`: no necesita guion y no
       se queda a medias si el módulo falla. La de siempre;
     · `.st-fold-head[aria-expanded]`: un botón que repinta su lista (lo que
       no entra en la caja);
     · `.st-fold-galon`: sólo el galón, para un renglón que ya tiene su forma
       (`.st-list-item`, la tarjeta de una procedencia). Gira con el `[open]`
       de su `<details>` o con el `aria-expanded="true"` del renglón que lo
       lleva como hijo directo. */
.st-fold {
    border-top: 1px solid var(--tw-border-light);
}

.st-fold > summary,
.st-nesteo > summary,
.st-fold-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: var(--st-hit);
    padding: 0 16px;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--tw-font-primary);
    font: inherit;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    text-align: left;
    list-style: none;
    cursor: pointer;
    transition: background-color var(--tw-transition);
}

.st-fold > summary::-webkit-details-marker,
.st-nesteo > summary::-webkit-details-marker,
.st-desglose > summary::-webkit-details-marker {
    display: none;
}

.st-fold > summary:hover,
.st-nesteo > summary:hover,
.st-fold-head:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-fold > summary:focus-visible,
.st-nesteo > summary:focus-visible,
.st-fold-head:focus-visible {
    outline: 2px solid var(--tw-accent);
    outline-offset: -2px;
}

/* El galón · `ti-chevron-right` desde la hoja, para que el marcado no tenga que
   traerlo: un `<summary>` escrito a mano sale igual que uno del guion. */
.st-fold > summary::before,
.st-nesteo > summary::before,
.st-desglose > summary::before,
.st-fold-head::before,
.st-fold-galon::before {
    content: '\ea61';
    font-family: 'tabler-icons';
    font-size: 18px;
    font-weight: normal;
    line-height: 1;
}

.st-fold > summary::before,
.st-nesteo > summary::before,
.st-desglose > summary::before,
.st-fold-head::before,
.st-fold-galon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    color: var(--tw-font-secondary);
    transition: transform var(--tw-transition);
}

.st-fold[open] > summary::before,
.st-nesteo[open] > summary::before,
.st-desglose[open] > summary::before,
.st-fold-head[aria-expanded='true']::before,
details[open] > summary > .st-fold-galon,
[aria-expanded='true'] > .st-fold-galon,
.st-fold-galon.is-abierto {
    transform: rotate(90deg);
}

/* El galón dentro de una tarjeta que ya tiene su forma (las procedencias): en
   línea con el rótulo, y lo de abajo sangrado a la altura del texto. */
.st-fold-linea {
    display: flex;
    align-items: center;
    gap: 10px;
}

.st-fold-sangria {
    padding-left: 30px;
}

/* Dentro de un dato · el mismo pliegue sin línea ni renglón a lo ancho, para lo
   que se abre en medio de un bloque —«Ver los sobrantes» bajo «Lámina que
   usa»—: el galón y el rótulo a 40 de alto, alineados con el texto de arriba. */
.st-fold--dentro {
    border-top: 0;
}

.st-fold--dentro > summary {
    width: auto;
    min-height: 40px;
    margin-left: -8px;
    padding: 0 8px;
    border-radius: var(--tw-radius-sm);
}

.st-fold--dentro > summary .st-fold-n {
    margin-left: 4px;
}

/* La cuenta de lo plegado: a la derecha, en cifras de ancho fijo. */
.st-fold-n {
    margin-left: auto;
    font-weight: var(--tw-weight-normal);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .st-fold > summary::before,
    .st-nesteo > summary::before,
    .st-desglose > summary::before,
    .st-fold-head::before,
    .st-fold-galon {
        transition: none;
    }
}

/* ── Todo lo que se abre encima, a escala de estación ─────────────────────

   Esta hoja solo se carga en el kiosco, así que aquí se puede hablar de
   `.modal` a secas sin tocar el panel. Y hay que hacerlo: los diálogos del
   sistema —`components/dialogo.js`— y los modales de las plantillas usan las
   clases de Bootstrap, que están calibradas para mirarse sentado a 50 cm. En
   una terminal de piso salían con letra de 14 px y botones de 31 px de alto en
   medio de una pantalla cuyo cuerpo es de 16 y cuyos botones miden 56.

   El resultado era que el aviso más importante —el que pregunta si de verdad
   se registra sin colada— era el texto más pequeño de la pantalla.

   No se cambia ni la paleta ni la forma: solo la escala y la altura de golpeo.
   Los colores siguen saliendo de twenty-theme.css. */

.modal-content {
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
}

.modal-header,
.modal-body,
.modal-footer {
    padding: 20px;
}

.modal-header {
    border-bottom: 1px solid var(--tw-border-light);
}

.modal-footer {
    border-top: 1px solid var(--tw-border-light);
    gap: 12px;
}

.modal-title {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.2;
}

.modal-body,
.modal-body p,
.modal-body label,
.modal-body .form-label,
.modal-body .form-hint {
    font-size: var(--st-text-md);
}

.modal-body p:last-child {
    margin-bottom: 0;
}

/**
 * La cruz de cerrar · un botón, no un carácter suelto.
 *
 * Bootstrap la dibuja con un SVG negro de fondo, y sobre el kiosco oscuro había
 * que darle la vuelta con `invert(1) grayscale(1) brightness(2)`. Eso la dejaba
 * en un gris lavado, fina y sin caja: parecía una equis perdida en la esquina
 * más que algo que se toca —y con guante, «parece» decide si se toca o no—.
 *
 * Con `mask` el color sale del token en vez de un filtro, así que contrasta lo
 * mismo en claro y en oscuro, y encima va la caja de `.st-btn`: mismo borde,
 * mismo radio, mismo alto de toque que el resto de la pantalla.
 */
/*
 * La equis no tapa el final de un título largo («Parece que hubo un error al
 * imprimir», 11-oct). Tabler la pone `position: absolute` arriba a la derecha
 * (`.modal-content .btn-close`) y le reservaba su lugar con el relleno derecho
 * de la cabecera, que aquí se cambió a 20 px: se le devuelve su hueco para que
 * el título parta renglón antes de llegar a ella.
 */
.modal .modal-header:has(.btn-close) {
    padding-right: 76px;
}

.modal .btn-close {
    flex: none;
    /*
       48 y no `--st-hit`: el alto de toque completo deja una caja enorme
       alrededor de una equis de 20, y en el encabezado pesa más que el título.
       Sigue siendo un blanco cómodo con guante.
    */
    width: 48px;
    height: 48px;
    padding: 0;
    /* Se apaga todo lo de Bootstrap: el SVG de fondo y el filtro que lo salvaba. */
    background-image: none;
    filter: none;
    opacity: 1;
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    transition: background-color var(--tw-transition);
}

.modal .btn-close::before {
    content: '';
    display: block;
    width: 20px;
    height: 20px;
    margin: auto;
    background-color: var(--tw-font-secondary);
    -webkit-mask: var(--st-cruz) center / 20px no-repeat;
    mask: var(--st-cruz) center / 20px no-repeat;
}

.modal .btn-close:hover {
    background-color: var(--tw-bg-tertiary);
}

.modal .btn-close:hover::before {
    background-color: var(--tw-font-primary);
}

:root {
    /* La equis, en un trazo del grosor del resto de los iconos. */
    --st-cruz: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3e%3cpath d='M18 6 6 18M6 6l12 12'/%3e%3c/svg%3e");
}

/**
 * Los botones de un modal son botones de estación.
 *
 * Se igualan a `.st-btn` en vez de reescribir cada plantilla porque los
 * diálogos los genera `dialogo.js`, que es común al panel y al kiosco: cambiar
 * su marcado allí rompería el panel, y duplicar el módulo garantiza que dentro
 * de un mes digan cosas distintas.
 */
.modal .btn,
.modal .st-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: var(--st-hit);
    padding: 0 20px;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    border-radius: var(--tw-radius-md);
}

/* Y los escalones de la escala siguen siéndolo dentro de un modal. La regla de
   arriba pesa más que `.st-btn--sm` y los inflaba a 56 sin que nadie lo pidiera:
   «Sin gafete a mano» en la firma, «Siguiente pendiente» en las procedencias,
   la «X» de una cabecera de modal (9-oct-2026). */
.modal .st-btn.st-btn--sm,
.modal .st-btn.st-btn--plain {
    min-height: 40px;
    padding: 0 12px;
    font-size: var(--st-text-sm);
}

.modal .st-btn.st-btn--icon {
    min-height: 40px;
    width: 40px;
    padding: 0;
}

.modal .st-btn.st-btn--md {
    min-height: var(--st-hit-bar);
    padding: 0 14px;
}

.modal .st-btn.st-btn--lg {
    min-height: 64px;
    padding: 0 28px;
    font-size: var(--st-text-lg);
}

/* Neutra: cancelar, cerrar, volver. */
.modal .btn:not([class*='btn-']) {
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
}

/**
 * La que cierra el modal, en el azul de la estación.
 *
 * `success` y `warning` caen aquí a propósito: en el kiosco la primaria es el
 * azul —a un metro, el negro del panel no se separa del fondo— y un botón
 * amarillo de «continuar» se lee como una advertencia sobre sí mismo. El tono
 * de lo que pasa ya lo dice el título y el texto del aviso.
 */
.modal .btn-primary,
.modal .btn-success,
.modal .btn-warning {
    color: #fff;
    background-color: var(--tw-accent);
    border: 1px solid var(--tw-accent);
}

/* La segunda línea de una opción, a la escala del kiosco: los 12 px del panel
   se leen a medio metro y aquí se lee a uno, de pie. */
.modal .tw-choice-hint {
    font-size: var(--st-text-sm);
}

/* Rojo solo lo que destruye, igual que en el panel. */
.modal .btn-danger {
    color: #fff;
    background-color: var(--tw-tag-red-fg);
    border: 1px solid var(--tw-tag-red-fg);
}

/* Campos dentro de un modal: la misma altura que los de la pantalla. */
.modal .form-control,
.modal .form-select {
    min-height: var(--st-hit);
    font-size: var(--st-text-md);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-sm);
    color: var(--tw-font-primary);
}

/* Las opciones apiladas de `elegir()`: una decisión por botón, a lo ancho. */
.modal .tw-dialogo-opcion {
    width: 100%;
    justify-content: flex-start;
    text-align: left;
}

/**
 * Un interruptor apagado · la barra del visor del programa.
 *
 * El visor —`nesting/lxd-visor.js`— apaga y enciende capas, entradas y
 * recorrido. En el panel eso lo dibuja el `.active` de Bootstrap, que sobre un
 * `.st-btn` no pinta nada; el estado viaja además en el atributo, y de ahí sale
 * aquí.
 *
 * Apagado no es deshabilitado: se vuelve a encender tocando en el mismo sitio,
 * así que conserva su caja y su alto de golpeo y sólo baja de tono.
 */
.modal .st-btn[data-encendido='0'] {
    color: var(--tw-font-tertiary);
    background-color: transparent;
    border-color: var(--tw-border-light);
}

/* ── Los menús de la cabecera, también a escala ───────────────────────────

   Mismo caso que los modales y con la misma causa: «Cambiar estación» abre un
   `.dropdown-menu` de Bootstrap, calibrado para el panel. Debajo de un botón de
   56 px salía una lista de 14 px con renglones de 24, y elegir entre Almacén,
   Procesos y Empaque —que es un cambio de puesto, no un ajuste menor— quedaba
   como el control más pequeño de la pantalla, justo el que se toca con guante.

   Sólo la escala y la altura de golpeo; la paleta sigue saliendo del tema. */

.st-header .dropdown-menu,
.dropdown-menu {
    padding: 6px;
    font-size: var(--st-text-md);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    box-shadow: var(--tw-shadow-lg, 0 12px 32px rgb(0 0 0 / 45%));
}

/* La letra va con `!important` porque el tema del panel la fija así —13 px para
   todos los menús—, y sin repetir la fuerza el renglón quedaba de 56 px de alto
   con el texto del panel dentro. */
/* Los renglones de un menú, al escalón de la barra (48) desde el 9-oct-2026:
   el «Más» de la cabecera de pantalla medía 44 y el de la estación 56. */
.dropdown-menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--st-hit-bar);
    padding: 0 14px;
    font-size: var(--st-text-md) !important;
    border-radius: var(--tw-radius-sm);
    color: var(--tw-font-primary);
}

.dropdown-menu .dropdown-item:hover,
.dropdown-menu .dropdown-item:focus {
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-primary);
}

/* El icono de la que ya está abierta: se lee de un vistazo cuál es la actual,
   que en una terminal compartida importa más que el adorno. */
.dropdown-menu .dropdown-item .ti {
    font-size: var(--st-text-lg) !important;
    color: var(--tw-accent);
}

/* Y la caja del icono, del tamaño de su letra. El tema del panel la deja en
   16 × 16 para su letra de 16; aquí la letra sube a 20 y sin esto el dibujo se
   salía por abajo de su caja: el renglón lo centraba bien y el icono se veía
   caído respecto al texto (Salvador, 9-oct-2026: «centra bien verticalmente
   iconos»). */
.dropdown-menu .dropdown-item .ti,
.st-menu-mas .st-mas-item .ti {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    line-height: 1;
}

.dropdown-menu .dropdown-divider {
    border-color: var(--tw-border-light);
}

/* ── Desplegable con buscador · TomSelect a escala de estación ────────────

   Las estaciones no llevaban buscador por norma —se usan con guante y lector,
   no con teclado— y la norma se quedó corta: la lista de ubicaciones pasó de
   tres a catorce y elegir «el almacén que no era» dejó de ser improbable. Donde
   la lista es un catálogo abierto, el buscador entra también aquí.

   Lo que no entra es la escala del panel. TomSelect trae 14 px y un control de
   36 px de alto; esto lo lleva a la altura de golpeo del kiosco y a sus
   tokens, para que el desplegable no se vea pegado de otra aplicación. */

.ts-wrapper {
    width: 100%;
}

.ts-wrapper .ts-control {
    min-height: var(--st-hit);
    padding: 0 12px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-sm);
    box-shadow: none;
}

.ts-wrapper.focus .ts-control,
.ts-wrapper .ts-control:focus-within {
    border-color: var(--tw-accent);
    box-shadow: 0 0 0 3px var(--tw-accent-secondary);
}

.ts-wrapper .ts-control > input,
.ts-wrapper .ts-control > .item {
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
}

.ts-wrapper.single .ts-control::after {
    border-color: var(--tw-font-secondary) transparent transparent;
}

/* La sangría, a escala de kiosco.

   El tema del panel la fija con `!important` —viene de igualar `.form-control`,
   `.form-select` y `.ts-control` en un solo renglón—, así que aquí hay que
   repetirla con la misma fuerza o el campo de 56 px se queda con la sangría del
   de 28. A la derecha va más hueco que a la izquierda: es el sitio de la
   flecha, que en esta escala también es más grande. */
.ts-wrapper .ts-control {
    padding: 0 12px !important;
}

.ts-wrapper.single .ts-control {
    padding-right: 36px !important;
}

.ts-dropdown {
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    box-shadow: var(--tw-shadow-md, 0 8px 24px rgb(0 0 0 / 35%));
    margin-top: 4px;
}

/* Renglones altos: se eligen con el dedo, no con el ratón. */
.ts-dropdown .option {
    min-height: var(--st-hit);
    display: flex;
    align-items: center;
    padding: 10px 14px;
    border-bottom: 1px solid var(--tw-border-light);
}

.ts-dropdown .option:last-child {
    border-bottom: 0;
}

.ts-dropdown .active {
    background-color: var(--tw-accent-secondary);
    color: var(--tw-font-primary);
}

.ts-dropdown .no-results {
    padding: 16px 14px;
    color: var(--tw-font-light);
}

/* El campo de búsqueda del desplegable, cuando TomSelect lo separa. */
.ts-dropdown .dropdown-input-wrap .dropdown-input {
    min-height: 48px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border-bottom: 1px solid var(--tw-border-light);
}

/* ── Rejilla simple, sin depender de Bootstrap ────────────────────────── */

.st-cols {
    display: grid;
    gap: 16px;
}

/* Y las columnas se encogen · el mínimo de un hijo de rejilla es su contenido.

   Un código de placa largo, un renglón con dos botones al lado o una lista
   apretada empujan la columna entera más allá del ancho de la pantalla, y lo
   que se desplaza entonces es la página en horizontal: es lo mismo que ya
   arreglaba la cabecera con `flex-wrap`, en el otro sitio donde pasa. Con el
   mínimo en cero la columna se encoge y el contenido reparte. */
.st-cols > * {
    min-width: 0;
}

@media (min-width: 992px) {
    .st-cols--5-7 {
        grid-template-columns: 5fr 7fr;
    }

    .st-cols--2 {
        grid-template-columns: 1fr 1fr;
    }

    /* Tres datos del mismo peso en un renglón: cuántas piezas, cuántas cajas y
       cuánto queda. La clase se pone y se quita desde el guion porque el mismo
       renglón lleva dos o tres campos según el número de parte sea a granel. */
    .st-cols--3 {
        grid-template-columns: 1fr 1fr 1fr;
    }

    .st-cols--4-8 {
        grid-template-columns: 4fr 8fr;
    }

    /* Dos filtros y el buscador: los filtros comparten lo que antes era la
       columna de uno solo. */
    .st-cols--3-3-6 {
        grid-template-columns: 3fr 3fr 6fr;
    }

    /* Al revés que `5-7`: para cuando lo ancho es lo que se está tocando —la
       caja que se llena— y lo estrecho es el contexto que se mira de reojo. */
    .st-cols--7-5 {
        grid-template-columns: 7fr 5fr;
    }
}

/* ── Filtros en el renglón del escaneo ────────────────────────────────

   Cuando un select comparte renglón con el campo de escanear se iguala a su
   altura y a su radio: dos alturas en la misma fila se leen como dos
   aplicaciones distintas. Cubre también el control envuelto de TomSelect,
   que es como el select se dibuja de verdad. */
.st-scan-row .st-select,
.st-scan-row .st-input,
.st-scan-row .ts-wrapper .ts-control {
    min-height: 64px;
    border-radius: var(--tw-radius-md);
}

/* La fila-grupo de existencias abre entera, como toda tabla de la casa:
   el cursor y el fondo al pasar son el único aviso que hace falta. */
.st-table tbody tr[data-grupo] {
    cursor: pointer;
}

.st-table tbody tr[data-grupo]:hover td {
    background-color: var(--tw-bg-secondary);
}

/* «¿Quién puede firmar?» en el modal de firma; abierto, los nombres son lo que hay
   que leer, así que no van apagados */
.st-signature-who {
    margin-top: 8px;
}

.st-aviso-quien {
    margin-top: 12px;
}

.st-signature-who .quien-firma-lista,
.st-aviso-quien .quien-firma-lista {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium, 500);
    color: var(--tw-font-primary);
}

/* La lámina de Existencias se marca tocando el renglón: la casilla es la de
   `.st-pick`, y marcado se tiñe entero igual que allá. */
.st-table tbody tr[data-lamina] {
    cursor: pointer;
}

.st-table .st-stock-pick {
    width: 56px;
    padding-right: 0;
}

/* ── Esqueleto de carga ───────────────────────────────────────────────

   Mismo alto y mismos márgenes que `.st-list-item`: mientras la lista se
   trae, el bloque ya ocupa su sitio y nada se mueve cuando llegan los
   datos. En una terminal de piso eso no es estética: el operador tiene el
   dedo sobre la pantalla y una lista que empuja botones hace pulsar el
   renglón equivocado. */
.st-skeleton-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 64px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-skeleton-item:last-child {
    border-bottom: 0;
}

.st-skeleton-main {
    display: flex;
    flex-direction: column;
    gap: 9px;
    flex: 1 1 auto;
    min-width: 0;
}

.st-skeleton-item:nth-child(2) .tw-skeleton {
    animation-delay: 0.07s;
}

.st-skeleton-item:nth-child(n + 3) .tw-skeleton {
    animation-delay: 0.14s;
}

/* ── Avisos flotantes ─────────────────────────────────────────────────────

   Misma caja que en el panel, un escalón más grande: el aviso de la estación
   se lee de pie y a un metro, y en 13 px un «pieza ya escaneada» no se ve
   hasta que uno se acerca. Solo cambia la escala; el color y la forma salen
   de twenty-theme.css. */

#toast-container > div.toast {
    width: 26em !important;
    padding: 16px 20px 16px 52px !important;
    font-size: var(--st-text-md);
}

#toast-container > div.toast::before {
    left: 18px;
    top: 17px;
    width: 22px;
    height: 22px;
    -webkit-mask-size: 22px 22px;
    mask-size: 22px 22px;
}

#toast-container > div.toast .toast-title {
    font-size: var(--st-text-lg);
}

#toast-container > div.toast .toast-message {
    font-size: var(--st-text-md);
}

#toast-container > div.toast .toast-progress {
    height: 3px;
}

/* ── Teléfono · la página que se abre escaneando un código ─────────────
   Una sola tarea, sin sesión y sin menú. Vive aquí y no en su propio
   archivo porque es la misma escala de estación: quien la abre lleva
   guantes y mira a un palmo. Lo único que cambia es que la pantalla es
   estrecha y la mano tapa la mitad de abajo, así que la acción va arriba
   y la lista debajo, no al revés. */

/**
 * El reset que este layout no hereda.
 *
 * La superficie del teléfono NO carga Tabler —medio mega para una página que
 * hace una cosa— y con él se quedó fuera su `box-sizing: border-box`. Sin eso,
 * un `.st-input` con `width: 100%` mide el 100% **más** su relleno y su borde, y
 * se sale de la pantalla por la derecha: el campo del código y el botón de
 * adjuntar quedaban cortados.
 *
 * Se acota a `.mv-body` en vez de ponerlo global porque el resto de la
 * aplicación sí trae el suyo, y dos resets discutiendo es peor que ninguno.
 */
.mv-body,
.mv-body *,
.mv-body *::before,
.mv-body *::after {
    box-sizing: border-box;
}

.mv-body {
    margin: 0;
    background-color: var(--tw-bg-secondary);
    color: var(--tw-font-primary);
    font-family: var(--tw-font-family);
    font-size: var(--st-text-md);
}

.mv-shell {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 20px 16px calc(24px + env(safe-area-inset-bottom));
    max-width: 640px;
    margin-inline: auto;
}

.mv-title {
    font-size: var(--st-text-xl);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.2;
}

.mv-sub {
    color: var(--tw-font-secondary);
    font-size: var(--st-text-sm);
}

/* La zona de captura. Es un `label` sobre un input de archivo: se toca
   entera, que es lo único que funciona con guantes. */
.mv-capture {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 168px;
    padding: 24px;
    text-align: center;
    cursor: pointer;
    border: 2px dashed var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: var(--tw-font-primary);
}

.mv-capture:active {
    background-color: var(--tw-bg-tertiary);
}

.mv-capture i {
    font-size: 2.5rem;
    color: var(--tw-font-secondary);
}

.mv-capture-title {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
}

/* Una fila por archivo, con su estado. El estado va en texto y no sólo en
   color: en una pantalla al sol, el color no llega. */
.mv-file {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
}

.mv-file-thumb {
    width: 48px;
    height: 48px;
    flex: 0 0 48px;
    object-fit: cover;
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-tertiary);
}

.mv-file-name {
    font-size: var(--st-text-sm);
    word-break: break-all;
}

.mv-file-state {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.mv-file-state--ok {
    color: var(--tw-tag-green-fg);
}

.mv-file-state--bad {
    color: var(--tw-tag-red-fg);
}

/* Las cuatro utilidades que esta pantalla necesita.
   Se escriben aquí porque el layout del teléfono NO carga Bootstrap: usar
   `d-none` o `w-100` ahí sería escribir una clase que no existe, y el fallo
   no se ve —el elemento simplemente sale cuando no debía—. */

.mv-oculto {
    display: none !important;
}

/* Lo que salió mal, en rojo y en su sitio. Mismo tono que el estado de una
   fila fallida: en esta pantalla el rojo significa siempre lo mismo. */
.mv-error {
    color: var(--tw-tag-red-fg);
}

.mv-ancho {
    width: 100%;
    justify-content: center;
}

.mv-sep {
    margin-top: 16px;
}

.mv-lista {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/*
   La lista mientras carga lo que se tocó.

   `conCarga` gira el botón, y en un renglón de lista ancho ese giro pasa
   desapercibido: la pantalla se ve quieta y se toca otro programa. Aquí se apaga
   la lista entera —lo que se tocó sigue legible, lo demás se atenúa— y sobre
   todo deja de recibir clics, que es lo que impedía el segundo.
*/
.st-list--cargando {
    pointer-events: none;
}

.st-list--cargando .st-list-item:not(.is-busy) {
    opacity: 0.45;
}

.st-list-item.is-busy {
    position: relative;
}

.st-list-item.is-busy::after {
    content: '';
    position: absolute;
    right: 18px;
    top: 50%;
    width: 22px;
    height: 22px;
    margin-top: -11px;
    border: 3px solid var(--tw-font-secondary);
    border-top-color: transparent;
    border-radius: 50%;
    animation: tw-spin 0.6s linear infinite;
}

/*
   El croquis del recorrido · ayuda visual, no una ruta.

   No hay pasillos modelados y no los va a haber. Lo que hace falta con el
   montacargas cargado no es un GPS, es saber hacia dónde caminar. Por eso la
   línea va **punteada y curva**: recta y sólida se leería como «por aquí», y
   por ahí hay racks.
*/
.st-croquis {
    background: var(--tw-bg-secondary);
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-md);
    padding: 12px;
}

/*
   El recuadro: el dibujo debajo y las marcas encima, apilados y del mismo
   tamaño. La proporción la fija aquí el CSS y la respeta el recorte que calcula
   el guion; si dejaran de coincidir, el punto del destino caería al lado de la
   máquina en vez de encima.
*/
.st-croquis-marco {
    position: relative;
    aspect-ratio: 16 / 10;
    inline-size: 100%;
    max-block-size: 320px;
    margin-inline: auto;
    overflow: hidden;
    border-radius: var(--tw-radius-sm);
    background: var(--tw-bg-tertiary);
}

/*
   El plano. Aparece cuando termina de pintarse —el PDF tarda— y no antes: un
   lienzo en blanco encendiéndose de golpe parece un fallo de la pantalla.
*/
.st-croquis-fondo {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    opacity: 0;
    transition: opacity var(--tw-transition, 0.15s ease);
}

.st-croquis-fondo.is-listo {
    opacity: 1;
}

/*
   En oscuro se invierte el dibujo, igual que en el constructor: el plano es
   tinta negra sobre papel blanco y aquí no hay hoja. `hue-rotate` devuelve a su
   tono las anotaciones de color, que la inversión sola manda a su complementario
   —el rojo del área de limpieza saldría cian—.
*/
[data-bs-theme='dark'] .st-croquis-fondo {
    filter: invert(1) hue-rotate(180deg);
}

.st-croquis-svg {
    position: absolute;
    inset: 0;
    display: block;
    inline-size: 100%;
    block-size: 100%;
}

.st-croquis-linea {
    fill: none;
    stroke: var(--st-acento, #4a9eff);
    stroke-linecap: round;
    /* El grosor y el guion los pone el guion en unidades del recorte: fijos
       aquí, un plano recortado los pinta como una manguera. */
    stroke-width: 6;
    stroke-dasharray: 14 18;
    /* Camina hacia el destino: dice el sentido sin necesidad de una flecha. */
    animation: st-croquis-avanza 1.4s linear infinite;
    /* Sobre el plano hace falta despegarse del dibujo. */
    paint-order: stroke;
}

/* El paso lo pone el guion junto con el guion de la línea: uno fijo se arrastra
   o se atropella según cuánto se haya recortado el plano. */
@keyframes st-croquis-avanza {
    to {
        stroke-dashoffset: calc(var(--st-croquis-paso, 32) * -1);
    }
}

/* De dónde sales: hueco, porque ahí ya estás. */
.st-croquis-origen {
    fill: none;
    stroke: var(--tw-font-secondary);
    stroke-width: 4;
}

/* A dónde vas: lleno, que es lo que el ojo tiene que encontrar primero. Con el
   plano detrás, un punto de color se pierde entre las líneas de la celda: el
   halo del color de la tarjeta lo despega del dibujo. */
.st-croquis-destino {
    fill: var(--st-acento, #4a9eff);
    stroke: var(--tw-bg-secondary);
    stroke-width: 3;
    paint-order: stroke;
}

/* ══════════════════════════════════════════════════════════════════════════
   El papel · packing list
   ══════════════════════════════════════════════════════════════════════════

   El packing list se imprime desde la propia pantalla, y eso es deliberado: el
   papel sale del sistema, con los rangos de serial que se escanearon, y no de
   una hoja que alguien rellena aparte. Lo que faltaba era decirle al navegador
   qué es documento y qué es kiosco.

   Sin estas reglas salían dos páginas con la barra de la estación, las listas
   de la izquierda, los botones y el aviso flotante encima de la tabla; y en
   tema oscuro, con fondos que se comen el tóner. Aquí se apaga todo lo que no
   es el documento y se le devuelve la forma de un papel: fondo blanco, tipo
   serio, cabecera de tabla repetida en cada página y firmas al pie.
   ══════════════════════════════════════════════════════════════════════════ */

/* En pantalla, el membrete y las firmas no existen: son cosa del papel. */
.doc-membrete,
.doc-firmas,
.doc-qr {
    display: none;
}

/* ── El visor de archivos, con la escala del piso ─────────────────────────

   `components/visor.js` sirve a las dos superficies y marca cuál es: el panel
   se mira sentado, con ratón, y usa `.btn`; esto se mira de pie, a un metro y
   con guantes. Sin esta capa el plano se abría dentro de un marco de escritorio
   —cabecera de 8 px, botón de cerrar de 24— sobre una pantalla cuyo resto mide
   64: se leía como si fuera de otra aplicación. */

.tw-visor--kiosco {
    padding: 0;
    background-color: rgba(0, 0, 0, 0.8);
}

/* A pantalla completa: el plano es lo que se vino a ver, y en una tablet los
   márgenes de escritorio le quitan un tercio del alto. */
.tw-visor--kiosco .tw-visor-marco {
    width: 100%;
    max-width: none;
    border-radius: 0;
    background-color: var(--tw-bg-primary);
}

.tw-visor--kiosco .tw-visor-cabecera {
    gap: 16px;
    padding: 12px 16px;
    min-height: 72px;
    background-color: var(--tw-bg-secondary);
    border-bottom: 1px solid var(--tw-border-light);
}

.tw-visor--kiosco .tw-visor-titulo {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
}

.tw-visor--kiosco .tw-visor-acciones {
    gap: 8px;
}

/* El cuerpo hereda el fondo de la superficie, no el gris del panel: un plano en
   blanco sobre gris claro dentro de un kiosco en oscuro es la costura que
   delata que esto viene de otro sitio. */
.tw-visor--kiosco .tw-visor-cuerpo {
    background-color: var(--tw-bg-secondary);
}

/* ── Y fslightbox, que es quien abre las fotos ────────────────────────────

   No acepta clases propias —se pinta al final del `body`— así que la marca va
   en el `body` y esto cuelga de ahí. Lo único que se toca es el tamaño de lo
   que hay que acertar con el dedo: cerrar y pasar de foto venían a 24 px. */

body.tw-visor-kiosco .fslightbox-toolbar-button {
    width: 56px;
    height: 56px;
}

body.tw-visor-kiosco .fslightbox-toolbar-button svg {
    width: 24px;
    height: 24px;
}

body.tw-visor-kiosco .fslightbox-slide-btn {
    padding: 20px 22px;
}

body.tw-visor-kiosco .fslightbox-slide-btn svg {
    width: 24px;
    height: 24px;
}

/* ── La lista del catálogo ────────────────────────────────────────────────

   Más alta que la lista de una estación: aquí la lista **es** la pantalla, no
   un bloque debajo del campo de escaneo, y el tope de 42vh dejaba ver cuatro
   renglones de trescientos. */
#catalogo-lista.st-list--scroll {
    max-height: 68vh;
}

/* El pie que trae la siguiente tanda. Va dentro de la lista para que se alcance
   desplazándose, que es como se llega a él. */
.st-cat-mas {
    display: flex;
    justify-content: center;
    padding: 12px 16px;
    border-top: 1px solid var(--tw-border-light);
}

/* ── La ficha del número de parte · consulta ──────────────────────────────

   Se abre encima de lo que se está haciendo, en cualquier pantalla del piso.
   Todo lo de aquí es de lectura: no hay un solo control que escriba, y por eso
   nada tiene el tamaño de un campo de captura. Lo único pulsable de verdad son
   las revisiones y los archivos. */

.st-cat-head {
    background-color: var(--tw-bg-secondary);
    border-bottom: 1px solid var(--tw-border-light);
}

.st-cat-desc {
    margin: 0 0 12px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
}

/* Los datos de identidad en rejilla y no en renglones: son cuatro etiquetas
   cortas y en columna ocupaban media pantalla del modal antes de llegar al
   plano, que es a lo que se vino. */
.st-cat-datos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px 20px;
}

.st-cat-dato {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.st-cat-dato-rotulo {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-cat-dato-valor {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-primary);
    overflow-wrap: anywhere;
}

/* ── Las revisiones ───────────────────────────────────────────────────────

   Botones y no un desplegable. Cuál se está mirando es el dato más importante
   de esta ficha —el plano equivocado es una pieza mal fabricada— y dentro de un
   desplegable cerrado eso se lee sólo si se abre. Con dos o tres revisiones,
   que es lo normal, caben todas a la vista. */
.st-cat-revs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.st-cat-rev {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: var(--st-hit);
    padding: 0 14px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    cursor: pointer;
}

.st-cat-rev:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-cat-rev--on {
    background-color: var(--tw-accent-secondary);
    border-color: var(--tw-accent);
}

.st-cat-rev-nombre {
    font-weight: var(--tw-weight-semibold);
}

/* Trabajando: mismo estado que el resto de la casa —el rótulo se apaga y gira
   el indicador encima—, porque cambiar de revisión va al servidor. */
.st-cat-rev.is-busy {
    color: transparent !important;
    pointer-events: none;
}

.st-cat-rev.is-busy > * {
    visibility: hidden;
}

.st-cat-rev.is-busy::after {
    content: '';
    position: absolute;
    inset: 0;
    margin: auto;
    width: 20px;
    height: 20px;
    border: 3px solid var(--tw-font-secondary);
    border-top-color: transparent;
    border-radius: 50%;
    animation: tw-spin 0.6s linear infinite;
}

/* El número de parte convertido en puerta, para donde un botón de 44 px no
   cabe: la línea de resumen del asistente, la cabecera de un grupo. Se subraya
   con puntos en vez de con línea entera —no es un enlace de navegación, no
   lleva a ninguna pantalla— y el icono dice qué hay detrás. */
.st-cat-link {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 0;
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    border-bottom: 1px dotted var(--tw-font-secondary);
    cursor: pointer;
}

.st-cat-link.is-busy {
    pointer-events: none;
    opacity: 0.5;
}

.st-cat-link:hover {
    color: var(--tw-accent);
    border-bottom-color: var(--tw-accent);
}

.st-cat-link .ti {
    font-size: 0.9em;
    color: var(--tw-font-secondary);
}

/* Qué números de parte trae una caja, dentro de su renglón.

   En pastillas y no en una lista debajo: un contenedor trae uno o dos números
   de parte, rara vez cinco, y una lista de dos renglones por cada caja de la
   bandeja convierte una pantalla de ocho cajas en una de veinticuatro líneas.
   La pastilla agrupa el número con su cantidad —que es como se lee, «este y
   tantos»— y deja que la fila envuelva cuando de verdad son muchos.

   El número sigue siendo la puerta de su ficha: `.st-cat-link` va dentro. */
.st-parts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    margin-top: 4px;
}

.st-part {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    padding: 3px 10px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-pill);
    background-color: var(--tw-bg-secondary);
    font-size: var(--st-text-sm);
}

/* La cantidad, apagada respecto del número: lo que identifica la pieza es el
   número de parte, y el operador busca ése primero. */
.st-part > .st-code {
    color: var(--tw-font-secondary);
}

/* El número de parte que corre prisa · dentro de la misma lista.

   Una caja no corre prisa: la corre uno de los seis números de parte que trae,
   y hasta el 20 de septiembre de 2026 la etiqueta iba pegada al código de la
   caja, donde no señalaba a ninguno. Ahora la lleva la pastilla de su pieza.

   El tono va en el borde entero y en el fondo, nunca en una barra al costado, y
   el texto no cambia de color: lo que distingue la pastilla es su marco, y el
   número de parte tiene que seguir leyéndose igual de negro que los otros
   cinco. La llama la pone `marcaDePrisa` y se pinta con `.tw-prisa-marca`. */
.st-part--prisa {
    border-color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

/* ── Planos y especificaciones ────────────────────────────────────────────

   En rejilla de tarjetas y no en lista: la miniatura es lo que deja reconocer
   el plano sin abrirlo, y en un renglón de lista no cabe a un tamaño que sirva
   a un metro de distancia. */
.st-cat-files {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
}

/* Es un `<button>` y no un enlace: el plano se abre **dentro** de la pantalla
   —el velo del visor, o fslightbox si es foto—. En una tablet en modo
   aplicación no hay barra de direcciones ni botón de volver, así que una
   pestaña nueva se traga al operador con el trabajo a medias detrás. */
.st-cat-file {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    padding: 10px;
    font: inherit;
    text-align: left;
    color: inherit;
    text-decoration: none;
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-md);
    cursor: pointer;
}

.st-cat-file:hover {
    background-color: var(--tw-bg-tertiary);
    border-color: var(--tw-border-strong);
}

.st-cat-file-cara {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 120px;
    overflow: hidden;
    background-color: var(--tw-bg-secondary);
    border-radius: var(--tw-radius-sm);
    font-size: 32px;
    color: var(--tw-font-secondary);
}

.st-cat-file-cara img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.st-cat-file-nombre {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El archivo cuya fila sigue y cuyo objeto ya no está. Se lista apagado en vez
   de esconderse: sin él, el número de parte parecería no tener plano cuando lo
   que tiene es un archivo roto, y eso manda a buscar el problema al sitio
   equivocado. */
.st-cat-file--roto {
    opacity: 0.6;
    cursor: not-allowed;
}

/* ── El historial del contenedor · consulta ───────────────────────────────

   La otra pregunta que se hace con la caja delante, después de «¿cómo tiene que
   ser esta pieza?»: «¿de dónde viene lo que hay aquí dentro?». Se abre en el
   mismo sitio y con la misma regla: todo es de lectura y nada tiene tamaño de
   campo, porque aquí no se registra nada.

   La lista es una línea de tiempo y no una tabla. Lo que se busca al abrirla es
   el orden —qué pasó antes de qué— y una tabla obliga a leer la columna de la
   hora para reconstruirlo. */

.st-hist-head {
    padding: 0 0 16px;
    border-bottom: 1px solid var(--tw-border-light);
    margin-bottom: 8px;
}

.st-hist {
    display: flex;
    flex-direction: column;
}

.st-hist-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-hist-row:last-child {
    border-bottom: 0;
}

/* Lo que vino de otra caja se sangra y se apoya en una franja.

   No es una barra de color a la izquierda de las que se retiraron: es la
   sangría misma, que es lo que dice «esto no le pasó a esta caja, le pasó a la
   que se vació en ella». Sin ella, las dos historias se leen como una y las
   cuentas dejan de cuadrar. */
.st-hist-row--heredada {
    padding-left: 16px;
    background-color: var(--tw-bg-secondary);
}

.st-hist-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 32px;
    width: 32px;
    height: 32px;
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-secondary);
    font-size: 18px;
}

.st-hist-main {
    flex: 1 1 auto;
    min-width: 0;
}

@media print {
    @page {
        size: letter portrait;
        margin: 14mm 12mm;
    }

    /* El armazón de kiosco se recorta al alto de la pantalla y desplaza el
       cuerpo por dentro; en papel eso imprime una hoja y se come el resto. */
    .st-shell {
        height: auto;
    }

    .st-body {
        overflow: visible;
    }

    /* Nada del kiosco viaja al papel. */
    .st-header,
    .st-page-head,
    .pl-controles,
    #toast-container,
    .toast,
    /* El encabezado del panel —«Documento»— es del kiosco. Los de dentro del
       resultado son los títulos de cada pedido y sí van al papel, de ahí que
       esto sea hijo directo y no descendiente: sin el `>`, ocultar y volver a
       enseñar dependía de cuál de las dos reglas quedara escrita después. */
    #doc-imprimible > .st-block-head,
    #doc-imprimible .st-actions,
    #doc-imprimible .st-btn,
    #doc-imprimible .st-empty {
        display: none !important;
    }

    /* Papel: blanco, negro y sin sombras que el tóner convierte en gris sucio. */
    html,
    body,
    .st-shell,
    .st-body,
    .st-container,
    #doc-imprimible,
    #doc-imprimible .st-block-body {
        background: #fff !important;
        color: #000 !important;
        box-shadow: none !important;
        border: 0 !important;
    }

    /**
     * Sans y no serif, y con las cifras alineadas.
     *
     * Esto no es una carta: son códigos, cantidades y rangos de serial que se
     * cotejan columna contra columna con el dedo. Una serif de texto corrido
     * junta los caracteres justo donde importa distinguirlos —el 1 del l, el 0
     * del O— y desalinea los números al no ser tabulares, que es lo que obliga
     * a contar dos veces la misma fila.
     *
     * La pila es de fuentes del sistema: el papel se imprime desde tablets y
     * equipos distintos, y una tipografía descargada que no esté instalada sale
     * sustituida por otra cualquiera, con otro ancho y otro salto de página.
     */
    body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
        font-size: 9.5pt;
        line-height: 1.35;
        font-variant-numeric: tabular-nums;
        -webkit-font-smoothing: antialiased;
    }

    /* El documento ocupa la hoja: las dos columnas del kiosco no son del papel. */
    .st-cols,
    .st-cols--5-7 {
        display: block !important;
    }

    .st-shell,
    .st-body,
    .st-container,
    #doc-imprimible {
        display: block !important;
        margin: 0 !important;
        padding: 0 !important;
        width: 100% !important;
        max-width: none !important;
        overflow: visible !important;
    }

    /* Y no se corta el alto: con la lista dentro de un panel con scroll, el
       navegador imprime lo que se ve y da por terminada la página. */
    .st-list,
    .st-list--scroll,
    .st-table-wrap,
    #packing-result {
        max-height: none !important;
        overflow: visible !important;
    }

    /* ── Membrete ──────────────────────────────────────────────────────── */

    .doc-membrete {
        display: flex !important;
        justify-content: space-between;
        align-items: flex-start;
        gap: 1rem;
        border-bottom: 2px solid #000;
        padding-bottom: 6pt;
        margin-bottom: 10pt;
    }

    .doc-empresa {
        font-size: 10.5pt;
        font-weight: 600;
        letter-spacing: 0.01em;
    }

    /* El nombre del documento manda en la hoja: es lo primero que alguien busca
       en un fajo de papeles sobre la mesa del andén. */
    .doc-tipo {
        font-size: 19pt;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.12em;
        line-height: 1.1;
        margin-top: 3pt;
    }

    .doc-membrete-derecha {
        display: flex;
        align-items: flex-start;
        gap: 10pt;
    }

    .doc-meta {
        text-align: right;
        font-size: 9pt;
        line-height: 1.55;
        color: #222 !important;
    }

    /* El folio, en monoespaciada y grande: es el dato que se dicta por teléfono
       y el que se teclea para buscar el embarque. */
    .doc-meta .doc-folio {
        font-family: 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace;
        font-size: 14pt;
        font-weight: 700;
        letter-spacing: -0.01em;
        color: #000 !important;
        margin-bottom: 2pt;
    }

    /* ── El código escaneable ──────────────────────────────────────────── */

    .doc-qr {
        display: block !important;
        width: 23mm !important;
        height: 23mm !important;
        /* El QR es una imagen de dos tonos: sin esto el navegador puede
           «ahorrar tinta» y devolver un gris que el lector no distingue. */
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* ── El cuerpo ─────────────────────────────────────────────────────── */

    /* El resumen que en pantalla va arriba del todo ya lo dice el membrete. */
    #packing-result > .st-block-body:first-child {
        display: none !important;
    }

    /* Cada pedido abre su bloque, y no se parte del título a su tabla. */
    #packing-result .st-block-head {
        display: flex !important;
        justify-content: space-between;
        align-items: baseline;
        background: none !important;
        border: 0 !important;
        border-bottom: 1px solid #000 !important;
        padding: 8pt 0 3pt !important;
        break-after: avoid;
        page-break-after: avoid;
    }

    #packing-result .st-block-title {
        font-size: 11pt;
        font-weight: 700;
        letter-spacing: 0.01em;
    }

    #packing-result .st-muted {
        color: #333 !important;
        font-size: 9pt;
    }

    .st-table {
        width: 100% !important;
        border-collapse: collapse !important;
        margin-bottom: 6pt;
    }

    .st-table th,
    .st-table td {
        border: 0.5pt solid #999 !important;
        padding: 3.5pt 5pt !important;
        font-size: 9pt !important;
        color: #000 !important;
        background: none !important;
        text-align: left;
        vertical-align: top;
    }

    .st-table th {
        background: #ececec !important;
        font-weight: 700;
        text-transform: uppercase;
        font-size: 7.5pt !important;
        letter-spacing: 0.06em;
        color: #111 !important;
        /* Que se sepa qué es cada columna también en la página tres. */
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Las cantidades a la derecha: en columna, un 4 y un 40 mal alineados se
       leen como el mismo número de un vistazo. */
    .st-table td:nth-child(4),
    .st-table th:nth-child(4) {
        text-align: right;
        white-space: nowrap;
    }

    /* La cabecera se repite en cada hoja y ninguna fila se parte por la mitad. */
    .st-table thead {
        display: table-header-group;
    }

    .st-table tr {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    /* Códigos y seriales en monoespaciada: es lo que se compara carácter a
       carácter contra la etiqueta pegada en la caja. */
    .st-code {
        font-family: 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace;
        font-size: 8.5pt !important;
        letter-spacing: -0.01em;
    }

    /* ── Firmas ────────────────────────────────────────────────────────── */

    .doc-firmas {
        display: flex !important;
        gap: 2cm;
        margin-top: 18pt;
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .doc-firma {
        flex: 1;
        font-size: 8.5pt;
        text-align: center;
        color: #333;
    }

    .doc-firma-linea {
        border-top: 1px solid #000;
        margin-bottom: 4pt;
        /* Sitio para firmar de verdad, no una raya pegada al texto. */
        padding-top: 34pt;
    }
}

/* ── El inicio en mosaicos · elegir es comparar, y se compara en horizontal ──
 *
 * Salvador, 8 de septiembre de 2026, sobre Almacén y Empaque: «todas las
 * instrucciones en vertical es difícil de entender y elegir y buscar». Diez
 * renglones seguidos, cada uno con título, descripción y regla apiladas, eran
 * tres pantallas de tablet para decidir a dónde ir.
 *
 * Cada flujo sigue siendo una sección —el número sigue significando orden y la
 * cadena sigue dibujándose— pero sus tareas van en mosaicos, lado a lado: el
 * título grande, la descripción en dos líneas, y la regla fuera. La regla es
 * doctrina —se lee aprendiendo— y vuelve entera con «Ver las reglas», que se
 * recuerda por terminal. Y arriba un buscador: se escribe lo que se quiere
 * hacer y quedan sólo los mosaicos que lo dicen.
 *
 * El ancho del mosaico es fijo entre flujos (auto-fill, no auto-fit): un flujo
 * de una sola tarea no la estira a toda la pantalla, y la vista se recorre
 * comparando cajas del mismo tamaño. */
.st-inicio-herramientas {
    display: flex;
    align-items: center;
    gap: 10px;
    /* El buscador toma su ancho primero y el subtítulo parte renglón: al revés,
       la frase del subtítulo no cedía nada y el campo se estrangulaba hasta
       cortar la indicación a media palabra. */
    flex: 0 1 440px;
    min-width: 0;
}

.st-page-head--inicio > :first-child {
    flex: 1 1 0;
    min-width: 240px;
}

.st-inicio-herramientas .st-scan {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    /* Aquí se teclean tres letras, no se apunta una pistola: la altura del
       botón de al lado y la letra de cuerpo. Con la de escaneo la indicación
       se cortaba a media palabra. */
    min-height: var(--st-hit);
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-regular);
    letter-spacing: 0;
    text-overflow: ellipsis;
}

.st-inicio-herramientas .st-btn {
    flex: none;
    white-space: nowrap;
}

.st-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(236px, 1fr));
    gap: 12px;
}

.st-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 136px;
    padding: 16px 16px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: inherit;
    text-decoration: none;
    transition:
        background-color var(--tw-transition),
        border-color var(--tw-transition);
}

.st-tile:hover {
    background-color: var(--tw-bg-tertiary);
    border-color: var(--tw-border-strong);
    color: inherit;
}

.st-tile--soon {
    opacity: 0.6;
}

.st-tile-mark {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 34px;
    font-size: 28px;
    color: var(--tw-font-light);
}

.st-tile-mark .st-task-num {
    --st-task-bg: var(--tw-bg-primary);
}

.st-tile-title {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
    line-height: 1.2;
    padding-right: 20px;
}

.st-tile-desc {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.st-tile-rule {
    display: none;
    margin-top: auto;
    font-size: var(--st-text-sm);
    color: var(--tw-tag-orange-fg);
}

html[data-reglas] .st-tile-rule {
    display: block;
}

html[data-reglas] .st-tile-desc {
    -webkit-line-clamp: unset;
}

.st-tile-go {
    /* Abajo a la derecha: arriba chocaba con la cuenta de la marca. */
    position: absolute;
    right: 12px;
    bottom: 12px;
    color: var(--tw-font-light);
}

.st-tile .st-tag {
    align-self: flex-start;
    margin-top: auto;
}

/* Sitio para la flecha de abajo: el último renglón no se le mete debajo. */
.st-tile {
    padding-bottom: 30px;
}

/* La cadena entre mosaicos: una punta de flecha en el hueco, del mismo trazo
   que la línea vertical de antes. Sólo donde hay orden real. */
.st-tiles--chain .st-tile:not(:last-child)::after {
    content: '';
    position: absolute;
    right: -10px;
    top: 50%;
    width: 10px;
    height: 10px;
    border-top: 1px solid var(--tw-border-strong);
    border-right: 1px solid var(--tw-border-strong);
    transform: translateY(-50%) rotate(45deg);
}

/*
 * ── LOS FLUJOS COMPARTEN UNA SOLA REJILLA ───────────────────────────────
 *
 * Desde el 14 de septiembre de 2026. Antes, desde tablet, el rótulo iba a la
 * izquierda de cada flujo (172 px) y dos flujos seguidos de un solo mosaico
 * compartían renglón. Juntas, las dos reglas dejaban el segundo rótulo flotando
 * a media pantalla, los mosaicos de un flujo solo casi el doble de anchos que
 * los de la cadena, y rótulos partidos en dos líneas dentro de su columna.
 *
 * Ahora la bandeja es una rejilla de columnas iguales —cuatro en pantalla
 * ancha, tres en tablet vertical— y cada flujo ocupa tantas columnas como
 * mosaicos tiene, con su nombre encima. Los flujos se acomodan uno tras otro en
 * el orden declarado (sin `dense`: el orden de lectura no se toca), así que
 * varios flujos cortos comparten renglón sin que ninguno cambie de tamaño.
 *
 * El nombre encima cuesta un renglón por fila de mosaicos, no por flujo, y en
 * Almacén son tres filas donde antes eran cuatro. Los mosaicos de cada flujo
 * heredan las columnas con `subgrid`: miden lo mismo en toda la pantalla, y un
 * flujo con más mosaicos que columnas parte renglón dentro de su propio hueco.
 *
 * Debajo de 768 px cada flujo vuelve a su bloque, con el nombre arriba.
 */
@media (min-width: 768px) {
    .st-flujos {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 22px 12px;
    }

    .st-flujos > .st-flow {
        display: grid;
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
        grid-template-rows: auto 1fr;
    }

    .st-flujos > .st-flow--de-1 {
        grid-column: span 1;
    }

    .st-flujos > .st-flow--de-2 {
        grid-column: span 2;
    }

    /* El aire lo pone la rejilla: el margen entre flujos se le sumaría. */
    .st-flujos > .st-flow + .st-flow {
        margin-top: 0;
    }

    /*
     * El nombre abarca el ancho de su flujo y lo subraya una línea fina hasta
     * el último mosaico: así se lee de dónde a dónde llega cada flujo cuando
     * tres comparten renglón.
     */
    .st-flujos > .st-flow .st-flow-title,
    .st-turno .st-flow .st-flow-title {
        grid-column: 1 / -1;
        display: flex;
        align-items: center;
        gap: 10px;
        min-width: 0;
        white-space: nowrap;
        overflow: hidden;
    }

    .st-flujos > .st-flow .st-flow-title::after,
    .st-turno .st-flow .st-flow-title::after {
        content: '';
        flex: 1 1 auto;
        height: 1px;
        background-color: var(--tw-border-light);
    }

    .st-flujos > .st-flow .st-tiles {
        grid-column: 1 / -1;
        grid-row: 2;
        grid-template-columns: subgrid;
        grid-auto-rows: 1fr;
    }
}

@media (min-width: 1100px) {
    .st-flujos {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .st-flujos > .st-flow--de-3 {
        grid-column: span 3;
    }
}

@media (min-width: 768px) {
    .st-flow--lookup {
        margin-top: 18px;
    }
}

.st-flow[hidden],
.st-tile[hidden],
.st-lookup[hidden] {
    display: none;
}

/*
 * Las consultas · lo que se mira y se vuelve.
 *
 * No son mosaicos a propósito: pesan menos que una tarea del turno y tienen
 * que costar menos alto. En la tablet del piso —iPad horizontal— la fila de
 * mosaicos que ocupaban empujaba «Empacar el embarque» fuera de la pantalla.
 *
 * Van al pie y sobre una línea, que es lo que separa el trabajo de lo que se
 * consulta sin decirlo con un rótulo más.
 */
.st-flow--lookup {
    margin-top: 24px;
    padding-top: 14px;
    border-top: 1px solid var(--tw-border-medium);
}

.st-lookups {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}

.st-lookups-title {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--tw-font-light);
    margin-right: 4px;
}

/* Alto de dedo aunque sea un enlace: en el piso se toca con guante. */
.st-lookup {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: inherit;
    font-size: var(--st-text-sm);
    text-decoration: none;
    transition:
        background-color var(--tw-transition),
        border-color var(--tw-transition);
}

.st-lookup:hover {
    background-color: var(--tw-bg-tertiary);
    border-color: var(--tw-border-strong);
    color: inherit;
}

.st-lookup--soon {
    opacity: 0.6;
}

.st-inicio-vacio {
    margin-top: 12px;
}

/* Los avisos del inicio · lo que ya pasó una fecha, arriba de los mosaicos.
   Todo el aviso es el enlace a donde se atiende: se lee como una nota, no
   como un enlace azul. */
.st-avisos {
    display: grid;
    gap: 8px;
    margin-bottom: 16px;
}

.st-inicio-aviso {
    display: block;
    color: inherit;
    text-decoration: none;
}

.st-inicio-aviso:hover {
    color: inherit;
    border-color: var(--tw-tag-red-fg);
}

/* En un teléfono: dos por fila, sin descripción y sin flecha. El título y el
   icono bastan para elegir; la descripción se lee al entrar. */
@media (max-width: 575.98px) {
    .st-tiles {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
    }

    .st-tile {
        min-height: 108px;
        padding: 12px;
    }

    .st-tile-title {
        font-size: var(--st-text-md);
    }

    .st-tile-desc,
    .st-tiles--chain .st-tile:not(:last-child)::after {
        display: none;
    }
}

/* Las puertas del puesto de proceso, en mosaico. Son botones y enlaces con la
   misma caja; la cuenta va en la esquina de la marca y el aviso de espera —las
   clases `.st-task--aviso` / `.st-task--alarma` que `proceso.js` ya pone— tiñe
   el mosaico entero y gana al puntero. */
button.st-tile {
    width: 100%;
    text-align: left;
    font: inherit;
    cursor: pointer;
}

.st-tile > .flex-grow-1 {
    display: block;
}

.st-tiles--puertas .st-tile {
    min-height: 150px;
}

.st-tile-mark .st-block-count {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-primary);
}

.st-tile-mark .st-block-count:empty {
    display: none;
}

.st-tile .st-task-espera {
    margin-top: 8px;
}

.st-tile.st-task--aviso,
.st-tile.st-task--aviso:hover {
    background-color: var(--tw-tag-orange-bg);
    border-color: var(--tw-tag-orange-fg);
}

.st-tile.st-task--alarma,
.st-tile.st-task--alarma:hover {
    background-color: var(--tw-tag-red-bg);
    border-color: var(--tw-tag-red-fg);
}

/* ── La portada del puesto en tres alturas ───────────────────────────────

   14 de septiembre de 2026. Las seis puertas de Corte eran del mismo tamaño y
   del mismo gris, así que elegir entre «Empezar» y «Adelantar trabajo» costaba
   lo mismo que elegir entre «Empezar» y «Terminar». Ahora pesan lo que pesan:

   · `.st-tiles--turno` · lo que se hace todo el turno. Más alto, levantado del
     fondo con el velo del tema —más claro en oscuro, más oscuro en claro— y la
     marca en una pastilla del acento, que es el azul de la primaria de estación.
   · `.st-tiles--ligeras` · revisar y los casos especiales. Más bajos, título a
     letra de cuerpo y la marca sin pastilla.

   Los tintes de espera (`.st-task--aviso` / `.st-task--alarma`) ganan en las
   dos alturas: por eso el fondo del turno se pone con `:not()`. */
.st-puertas {
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.st-tiles--turno {
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.st-tiles--turno .st-tile {
    min-height: 172px;
    padding: 20px 20px 34px;
    gap: 10px;
    border-color: var(--tw-border-strong);
}

.st-tiles--turno .st-tile:not(.st-task--aviso):not(.st-task--alarma) {
    background-color: var(--tw-bg-transparent-light);
}

.st-tiles--turno .st-tile:not(.st-task--aviso):not(.st-task--alarma):hover {
    background-color: var(--tw-accent-tertiary);
    border-color: var(--tw-accent);
}

.st-tiles--turno .st-tile-mark {
    height: 44px;
}

.st-tiles--turno .st-tile-mark > .ti {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-accent);
    color: var(--tw-font-inverted);
    font-size: 24px;
}

.st-tiles--turno .st-tile-title {
    font-size: var(--st-text-data);
    font-weight: var(--tw-weight-semibold);
}

.st-tiles--turno .st-tile-desc {
    font-size: var(--st-text-md);
}

/* En la cadena del turno el número hace de pastilla: es la misma marca que el
   icono de las demás puertas del turno, y el orden sigue leyéndose. */
.st-tiles--turno .st-tile-mark .st-task-num {
    width: 44px;
    height: 44px;
    border-color: var(--tw-accent);
    background-color: var(--tw-accent);
    color: var(--tw-font-inverted);
    font-size: var(--st-text-lg);
}

/* La franja del turno en el inicio de estación: renglones que se llenan, con
   el nombre de cada flujo encima de sus mosaicos. Debajo, la rejilla del resto.

   Desde 1100 px cada renglón es una rejilla de tantas columnas como mosaicos
   lleva (`--st-turno-columnas`, la calcula la plantilla) y cada flujo ocupa las
   suyas (`--st-flujo-ancho`) con `subgrid`: los mosaicos de un renglón miden lo
   mismo aunque sean de dos flujos. Por debajo, cada flujo va en su renglón. */
.st-turno,
.st-turno-fila {
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.st-turno .st-flow + .st-flow {
    margin-top: 0;
}

@media (min-width: 1100px) {
    .st-turno-fila {
        display: grid;
        grid-template-columns: repeat(var(--st-turno-columnas, 4), minmax(0, 1fr));
        gap: 0 12px;
    }

    .st-turno-fila > .st-flow {
        display: grid;
        grid-column: span var(--st-flujo-ancho, 1);
        grid-template-columns: subgrid;
        grid-template-rows: auto 1fr;
    }

    .st-turno-fila > .st-flow .st-tiles {
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
        grid-auto-rows: 1fr;
    }
}

.st-turno + .st-flujos {
    margin-top: 22px;
}

.st-tiles--turno .st-tile-mark .st-block-count {
    font-size: var(--st-text-xl);
}

.st-tiles--turno .st-tile-go {
    color: var(--tw-font-secondary);
}

/* Cómo trabaja un proceso, en la elección de proceso: dato de su configuración
   —«cuenta al recibir · registra salida»—, no una instrucción. */
.st-tile-como {
    font-size: var(--st-text-sm);
    color: var(--tw-font-light);
}

.st-tiles--puertas.st-tiles--ligeras .st-tile {
    min-height: 124px;
    padding: 14px 16px 30px;
    gap: 6px;
}

.st-tiles--ligeras .st-tile-mark {
    height: 26px;
    font-size: 22px;
}

.st-tiles--ligeras .st-tile-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
}

@media (max-width: 575.98px) {
    .st-tiles--turno {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .st-tiles--turno .st-tile {
        min-height: 132px;
        padding: 14px 14px 30px;
    }

    .st-tiles--turno .st-tile-title {
        font-size: var(--st-text-lg);
    }

    .st-tiles--puertas.st-tiles--ligeras .st-tile {
        min-height: 96px;
        padding: 12px 12px 28px;
    }

    .st-tile-como {
        display: none;
    }
}

/* ── El contador de armar ─────────────────────────────────────────────────
   Un toque, un ensamble: el número grande y el botón grande, para iPad
   horizontal a un metro. Se recorta por alto, nunca encogiendo la letra. */
.st-counter {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
    padding-top: 12px;
    padding-bottom: 12px;
}

.st-counter-num {
    font-size: 64px;
    line-height: 1;
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
}

.st-counter-what {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-counter-btn {
    min-height: 72px;
    min-width: 260px;
    font-size: var(--st-text-lg);
    margin-top: 8px;
}

.st-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
}

/* ── Las cajas del puesto, en tarjetas ────────────────────────────────────

   POR QUÉ TARJETA Y NO RENGLÓN. Un renglón dice una cosa por caja: su código.
   Lo que hay que comparar de una canastilla son cuatro —qué lleva dentro, de
   qué colada, cuánto le queda y a dónde va—, y en un renglón eso es una línea
   de texto corrida que se lee entera para saber si es la que se busca. En
   tarjeta cada dato tiene su sitio, siempre el mismo, y la mezcla de números de
   parte cabe sin recortarse: la caja se reconoce de un vistazo desde un metro,
   que es la distancia a la que se mira la tablet con las piezas en la mano.

   TRES ESTADOS Y SE VEN. La que está eligiéndose, la que sirve para las piezas
   que se van a guardar y la que no sirve. Apagar la que no sirve —no
   esconderla— es lo que evita el paseo: la caja existe, está ahí, y lo que dice
   la tarjeta es por qué no es ésta. */
.st-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 12px;
}

.st-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
}

/* La que sirve para lo que se está guardando: se enciende el borde entero, no
   una barra al lado. Ver `otv-sin-bordes-ia`. */
.st-card--sirve {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

/* La que no sirve sigue a la vista y apagada: el porqué está en su pie. */
.st-card--no {
    opacity: 0.5;
}

/* La cabecera de una tarjeta del plano: el código y lo que le cuelga.

   Envuelve porque desde que la caja dice además con qué prisa corre son dos
   etiquetas detrás del código, y en una columna de 228 px eso no cabe en una
   línea: sin envolver, la segunda se sale de la tarjeta y se corta contra el
   borde. Envuelta baja a un segundo renglón, que es el mismo remedio que ya
   lleva la cabecera de subpanel. El alto de la tarjeta sólo crece en las que
   llevan prisa, y en el plano son las menos. */
.st-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
}

/* ── Y cuando envolver no basta · el plano de cajas del puesto ─────────────

   ENVOLVER EVITA QUE SE SALGA; NO EVITA QUE SE DESNIVELE. En una columna de
   320 px, con el código corto las dos etiquetas caben en la línea del código y
   con uno más largo bajan a un segundo renglón. Como el largo del código lo
   decide cada caja, dos tarjetas vecinas acaban con el número de piezas, la
   barra, la mezcla y la firma a una línea de diferencia, y se lee como si una
   de las dos estuviera mal puesta.

   La cura no es más ancho: es no depender del ancho. El código ocupa su propia
   línea y las marcas van siempre debajo, lleve la caja prisa o no. Todas las
   tarjetas miden lo mismo porque todas tienen las mismas dos líneas.

   Va como modificador y no dentro de `.st-card-head` porque esa regla la
   comparte el plano de cajas de Empaque, que es otra pantalla y otra decisión. */
.st-card-head--apilada {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
}

/* Las marcas de la tarjeta, en su renglón · el estado primero, que es la
   píldora principal, y detrás lo que la matiza. Envuelven entre ellas: dos
   marcas largas en 320 px siguen sin caber, y ahí sí crece la tarjeta, pero
   crece por lo que lleva y no por cómo se llama. */
.st-card-marcas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    min-height: 26px;
}

.st-card-code {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

.st-card-num {
    margin-left: auto;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.st-card-senas {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* Cuánto le queda · la barra va debajo del número y no en su lugar: el número
   es el dato y la barra es para el vistazo. Sin capacidad capturada no se
   dibuja, que es distinto de dibujarla vacía. */
.st-card-cap {
    height: 6px;
    border-radius: var(--tw-radius-pill);
    background-color: var(--tw-bg-tertiary);
    overflow: hidden;
}

.st-card-cap-fill {
    height: 100%;
    background-color: var(--tw-accent);
}

.st-card-cap-fill--full {
    background-color: var(--tw-tag-orange-fg);
}

/* La mezcla · un renglón por número de parte, con su cantidad a la derecha y
   la ✕ de quitarlo cuando la caja sigue abierta. */
.st-card-mix {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.st-card-mix-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--st-text-sm);
}

.st-card-mix-row > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.st-card-mix-qty {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-secondary);
}

.st-card-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: auto;
    padding-top: 4px;
}

/* El campo de cuántas se meten, dentro de la tarjeta: el tope va pegado al
   campo, y el campo pegado a la caja en la que se van a meter. */
.st-card-meter {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}

.st-card-meter .st-scan {
    min-height: 48px;
    width: 6.5rem;
    text-align: center;
}

/* ── Lo que falta por guardar · las fichas de arriba ──────────────────────

   Se elige una y las tarjetas de abajo contestan. Es el orden que pidió el
   piso —«primero el nesteo, y luego dime en qué caja cabe»— con las dos cosas
   en la misma pantalla en vez de en dos pasos de un asistente. */
.st-pend {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.st-pend-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.st-pend-item:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-pend-item.is-active,
.st-pend-item.is-active:hover {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

.st-pend-qty {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
}

.st-pend-what {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

@media (max-width: 575.98px) {
    .st-cards {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ── La caja elegida, en grande ───────────────────────────────────────────

   Al tocar una tarjeta la pantalla cambia de modo: la caja se pone en grande a
   la izquierda con lo que lleva dentro, y a la derecha todo lo que se le puede
   meter. Es una decisión a la vez —la caja ya está elegida, lo que queda es qué
   entra— y la transición existe para que se vea de dónde salió lo que ahora
   ocupa la pantalla: sin ella, tocar una tarjeta parece cargar otra página. */
.st-detalle {
    animation: st-detalle-in 180ms ease-out;
}

@keyframes st-detalle-in {
    from {
        opacity: 0;
        transform: scale(0.985);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* Quien prefiere no ver movimiento no lo ve: la pantalla es la misma. */
@media (prefers-reduced-motion: reduce) {
    .st-detalle {
        animation: none;
    }
}

.st-detalle-code {
    font-size: var(--st-text-xl);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

/* El renglón de un nesteo dentro de la caja · se pulsa para ver el desglose.
   Va cerrado porque lo que se pregunta primero es «de qué programa es lo que
   lleva», no cuántas piezas de cada número de parte. */
.st-nesteo {
    border-bottom: 1px solid var(--tw-border-light);
}

.st-nesteo:last-child {
    border-bottom: 0;
}

/* El renglón, el galón y el alto son los de `.st-fold` (9-oct-2026). */

.st-nesteo-title {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
}

.st-nesteo-qty {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-secondary);
}

/* El número de parte y su distribución · el segundo pliegue.

   Dentro del nesteo, lo que se lee es el número de parte con su total: es la
   cuenta que el puesto dice en voz alta. De qué lámina salió cada pieza y de qué
   orden de compra es —cuarenta renglones repitiendo el mismo código— va debajo,
   plegado.

   El renglón se abre entero, que es la regla de las listas del sistema, y el
   rótulo de la derecha está para que se vea que hay algo que abrir: un renglón
   que sólo se distingue de los demás por el cursor no invita a nadie. */
.st-desglose > summary {
    cursor: pointer;
    list-style: none;
}

.st-desglose > summary:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-desglose-qty {
    font-size: var(--st-text-md);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Lo que se abría lo decía una píldora «Ver distribución» a la derecha, con su
   propio galón. Desde el 9-oct-2026 lo dice el galón de la izquierda, el mismo
   de todo lo que se pliega (ver `.st-fold`). */

/* Y el desglose, hundido: lo de dentro se lee como lo de dentro, no como cinco
   renglones más de la lista de arriba. */
.st-desglose-body {
    background-color: var(--tw-bg-secondary);
    border-top: 1px solid var(--tw-border-light);
}

.st-desglose-body .st-list-item {
    padding-left: 28px;
}

/* La cabecera de la lámina, dentro del desglose, no puede llevar el mismo fondo
   que el desglose entero: se leería como un renglón más. */
.st-desglose-body .st-list-item--head,
.st-desglose-body .st-list-item--head:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-desglose-body .st-list-item:last-child {
    border-bottom: 0;
}

.st-desglose:last-child:not([open]) > summary {
    border-bottom: 0;
}

/* ── El renglón de conteo · buenas y de scrap ─────────────────────────────

   Las dos cifras que el operador conoce de una lámina, en el mismo par de campos
   con el que las declaró al cerrar la corrida. Van en una retícula de anchos
   fijos —no en un `flex` que reparte lo que sobra— para que los campos de todos
   los renglones caigan en la misma vertical y la cabecera de arriba los nombre
   una vez: ver `otv-cada-renglon-es-su-propia-reticula`.

   Y por eso el segundo campo es más estrecho que el primero: el scrap de una
   lámina son unidades y las buenas son ciento veinte. Un campo del mismo tamaño
   para los dos números dice que se esperan del mismo orden. */
.st-conteo-campos {
    display: grid;
    grid-template-columns: 6.5rem 5.5rem 5.5rem auto auto;
    align-items: center;
    gap: 8px;
}

.st-conteo-campos .st-input,
.st-conteo-campos .st-scan {
    width: 100%;
    min-height: 48px;
    text-align: center;
}

/* La cabecera lleva los dos botones del renglón, invisibles: son los que dan
   ancho a las dos últimas pistas de la retícula. Sin ellos el bloque se encoge,
   se pega al borde derecho y los rótulos dejan de caer sobre sus campos. */
/* El renglón de la lámina que se vino a guardar · se llega a él desde la
   sugerencia de «Falta guardar», y es donde se reparte lo que falta. */
.st-list-item.st-conteo.is-active {
    background-color: var(--tw-bg-secondary);
}

.st-conteo-hueco {
    visibility: hidden;
}

/* Lo que falta o sobra para cuadrar · en naranja mientras no cuadre. No es un
   error todavía: es lo que queda por decidir con las piezas en la mano. */
.conteo-cuadre--falta {
    color: var(--tw-tag-orange-fg);
}

.st-conteo-head .st-field-label {
    margin-bottom: 0;
    text-align: center;
    white-space: nowrap;
}

.st-conteo-head {
    min-height: 0;
    padding-top: 8px;
    padding-bottom: 8px;
}

/* En un teléfono los dos campos y los dos botones no caben en la misma línea que
   el número de parte: bajan enteros, con su retícula puesta, y el dato se lee. */
@media (max-width: 767.98px) {
    .st-list-item.st-conteo,
    .st-list-item.st-conteo-head {
        flex-wrap: wrap;
    }
}

/* ── El mapa de cajas · como un plano de mesas ────────────────────────────

   Salvador, 12 de septiembre de 2026: *«quiero algo así como los softwares de
   distribución de mesas en restaurantes»*. Y la comparación es exacta: una caja
   es una mesa —tiene un nombre corto que se dice en voz alta, un estado que se
   reconoce por color desde la puerta, una ocupación que se lee de un número y
   una acción que empieza tocándola—. Lo que hace legible un plano de mesas no es
   el dibujo: es que las tres preguntas —cuál, cómo está, cuánto lleva— se
   contesten sin leer una sola frase.

   Así que la tarjeta pesa lo justo: código grande arriba, ocupación en número
   grande al centro con su barra, y abajo de qué programa es lo que lleva. El
   estado tiñe la tarjeta entera —no una barra al lado, ver `otv-sin-bordes-ia`—
   y la elegida se levanta. */
.st-cards {
    grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
}

.st-card {
    gap: 8px;
    transition:
        transform var(--tw-transition),
        border-color var(--tw-transition),
        background-color var(--tw-transition);
}

.st-card[role='button'] {
    cursor: pointer;
}

.st-card[role='button']:hover {
    transform: translateY(-2px);
    border-color: var(--tw-border-strong);
}

/* El estado, teñido · verde se está llenando, azul cerrada y esperando,
   apagada la que ya contó el proceso siguiente y aquí ya no se toca. */
.st-card--llenando {
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

.st-card--cerrada {
    border-color: var(--tw-tag-blue-fg);
    background-color: var(--tw-tag-blue-bg);
}

.st-card--contada {
    background-color: var(--tw-bg-secondary);
    opacity: 0.72;
}

/* La ocupación · el número es el dato y la barra es para el vistazo. */
.st-card-ocupacion {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.st-card-ocupacion-num {
    font-size: 34px;
    line-height: 1;
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
}

.st-card-ocupacion-de {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* De qué programa es lo que lleva · fichas, no renglones: son dos o tres y lo
   que se compara entre cajas es cuáles, no cuántas de cada una. */
.st-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.st-chip-min {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: var(--tw-radius-pill);
    background-color: var(--tw-bg-tertiary);
    font-size: var(--st-text-sm);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La leyenda del plano · una línea, arriba de la retícula. */
.st-leyenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-leyenda > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.st-leyenda i.punto {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    display: inline-block;
}

/* La ficha de abrir · va entre las cajas y no se lee como una. */
.st-card--nueva {
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-height: 148px;
    border-style: dashed;
    background-color: transparent;
    text-align: center;
    cursor: pointer;
}

.st-card--nueva > i {
    font-size: 24px;
    color: var(--tw-font-secondary);
}

.st-card--nueva:hover {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

/* El campo de un número dentro de un renglón · corto y centrado.

   `.st-scan` mide el ancho entero porque nació para el lector, donde el campo
   **es** la pantalla. En un renglón de lista con su botón al lado, eso empuja el
   dato a un tercio del ancho y deja un hueco de trescientos píxeles para dos
   dígitos. Aquí el tope va pegado al campo y el campo al botón. */
.st-scan--num {
    width: 6.5rem;
    min-height: 48px;
    text-align: center;
}

/* ── La barra del plano · buscar y leyenda en un renglón ──────────────────

   Tres bloques apilados delante del plano —buscador, leyenda, lector— eran tres
   franjas de ancho completo antes de que se viera una caja. Y el campo medía lo
   que mide un campo de escaneo, que es la altura de una pistola apuntando, no la
   de teclear tres letras. */
.st-barra {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
}

.st-buscar-corto {
    flex: 1 1 320px;
    max-width: 460px;
    min-height: var(--st-hit-bar);
    padding: 0 14px;
    font-size: var(--st-text-md);
    color: var(--tw-font-primary);
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
}

.st-buscar-corto:focus {
    outline: none;
    border-color: var(--tw-accent);
}

.st-buscar-corto::placeholder {
    color: var(--tw-font-extra-light);
}

/* El buscador con sugerencias · el desplegable cuelga del campo.
 *
 * Empezar busca el programa por su CNC (7-oct-2026, «debe tener dropdown de
 * sugerencia»): lo encontrado se abre debajo del campo, encima de lo que haya,
 * sin empujar la pantalla. Con las flechas se recorre y Enter elige. */
.st-buscador {
    position: relative;
}

/* El bloque que lleva un buscador con sugerencias no recorta: el desplegable
   tiene que poder salir por debajo de su borde. */
.st-block:has(.st-buscador) {
    overflow: visible;
}

.st-sugerencias {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 30;
    max-height: min(420px, 60vh);
    overflow-y: auto;
    background-color: var(--tw-bg-primary);
    border: 1px solid var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    box-shadow: var(--tw-shadow-strong);
}

.st-sugerencias[hidden] {
    display: none;
}

.st-sugerencias .st-list-item {
    flex-wrap: nowrap;
    min-height: 56px;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-sugerencias .st-list-item:last-child {
    border-bottom: 0;
}

.st-sugerencias .st-list-item.es-resaltada {
    background-color: var(--tw-bg-tertiary);
    box-shadow: inset 3px 0 0 var(--tw-accent);
}

.st-sugerencias-vacio {
    padding: 14px 16px;
    color: var(--tw-font-tertiary);
}

/* La lupa del buscador del CNC · dentro del campo, a la derecha (7-oct-2026).
 *
 * «Ponle en el buscador del folio un botón de lupa donde le muestres una hoja
 * de Lantek y le señales dónde viene el folio». Del alto del campo menos su
 * margen, para que no sea un botón suelto que compita con lo que se escribe. */
.st-buscador--ayuda .st-scan {
    padding-right: 68px;
}

.st-buscador-ayuda {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 48px;
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 26px;
    color: var(--tw-font-secondary);
    background-color: var(--tw-bg-secondary);
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-sm);
}

.st-buscador-ayuda:hover,
.st-buscador-ayuda:focus-visible {
    color: var(--tw-accent);
    border-color: var(--tw-accent);
}

/* Debajo del buscador, que la hoja también se escanea (8-oct, «aún no indicamos
   que pueden escanearla»): la pista a la izquierda y la cámara y la foto a la
   derecha; el visor, cuando se enciende, debajo y a lo ancho. */
.st-buscador-lector {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
    margin-top: 10px;
}

.st-buscador-pista {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--tw-font-secondary);
}

.st-buscador-pista .ti {
    font-size: 22px;
    color: var(--tw-font-primary);
}

.st-buscador-lector .st-scan-alt {
    margin: 0;
    padding: 0;
    border: 0;
}

.st-buscador-lector .st-scan-cam {
    flex-basis: 100%;
}

/* El folio del programa · lo primero del renglón de «Te surtieron».
   Es el número que trae la hoja: se lee antes que todo lo demás (7-oct, «al
   operador le interesa más el folio del nesteo»). */
.st-folio {
    font-size: var(--st-text-data);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.03em;
    line-height: 1.15;
}

/* La surtida tocada que espera su escaneo · marcada, y debajo qué falta. */
.st-list-item.es-por-confirmar {
    background-color: var(--tw-accent-tertiary);
    box-shadow: inset 3px 0 0 var(--tw-accent);
}

.st-por-confirmar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
    padding: 10px 16px 12px;
    border-bottom: 1px solid var(--tw-border-light);
    background-color: var(--tw-accent-tertiary);
}

/* «Ver los sobrantes» · plegado debajo de «Lámina que usa» (8-oct). Era un
   botón chico sin galón; desde el 9-oct-2026 es un `.st-fold--dentro` (ver
   `.st-fold`). */

/* ¿Dónde viene el CNC? · la cabecera de la hoja de Lantek, dibujada.
 *
 * Es papel: blanco y tinta negra en los dos temas, con las líneas de pelo y la
 * cursiva de la hoja impresa. Lo que se señala va en el color de acento con su
 * número, el mismo que la lista de abajo. */
.st-hoja-ejemplo {
    margin: 0 0 16px;
    padding: 14px;
    color: #111;
    background-color: #fff;
    border-radius: var(--tw-radius-sm);
    box-shadow: 0 0 0 1px var(--tw-border-medium);
    font-size: 13px;
    line-height: 1.25;
}

.st-hoja-ejemplo i {
    font-style: italic;
}

.st-hoja-ejemplo .he-cab {
    display: grid;
    grid-template-columns: 18% 1fr 19%;
    border: 0.75px solid #111;
}

.st-hoja-ejemplo .he-logo,
.st-hoja-ejemplo .he-der {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.st-hoja-ejemplo .he-logo {
    align-items: center;
    border-right: 0.75px solid #111;
}

/* La esquina del código, como la imprime `HojaDeCorteLamina.ejs` (8-oct: la hoja del piso es la del sistema). */
.st-hoja-ejemplo .he-qr {
    font-size: 46px;
    line-height: 1;
    color: #111;
}

.st-hoja-ejemplo .he-codigo {
    font-size: 10px;
    letter-spacing: 0.04em;
}

.st-hoja-ejemplo .he-escanealo {
    font-size: 9px;
    color: #555;
}

.st-hoja-ejemplo .he-centro {
    border-right: 0.75px solid #111;
}

.st-hoja-ejemplo .he-fila {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 26px;
    padding: 2px 8px;
    border-bottom: 0.75px solid #111;
}

.st-hoja-ejemplo .he-centro .he-fila:last-child,
.st-hoja-ejemplo .he-der .he-fila:last-child {
    border-bottom: 0;
}

.st-hoja-ejemplo .he-fila > span:first-child,
.st-hoja-ejemplo .he-fila > b:first-child {
    flex: 0 0 34%;
}

.st-hoja-ejemplo .he-ref {
    min-height: 34px;
    font-size: 15px;
}

/* Un valor, un renglón: como en la hoja, lo largo se corta y no empuja la casilla. */
.st-hoja-ejemplo .he-fila > i {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.st-hoja-ejemplo .he-ref > b:first-child {
    flex-basis: 22%;
}

.st-hoja-ejemplo .he-ref b {
    font-size: 20px;
}

.st-hoja-ejemplo .he-medida {
    margin-left: auto;
    padding: 1px 6px;
    font-size: 11px;
    border: 0.75px solid #111;
    border-bottom: 0;
}

.st-hoja-ejemplo .he-fecha {
    padding: 4px 8px;
    text-align: right;
}

/* Lo que se señala: el CNC con su anillo, y el número de cada cosa. */
.st-hoja-ejemplo .he-cnc {
    z-index: 1;
    font-size: 15px;
    font-weight: 600;
    box-shadow:
        0 0 0 3px var(--tw-accent),
        0 0 0 7px color-mix(in srgb, var(--tw-accent) 25%, transparent);
    border-radius: 2px;
}

.st-hoja-ejemplo .he-n,
.he-notas .he-n {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    font-size: 14px;
    font-style: normal;
    font-weight: 700;
    color: #fff;
    background-color: var(--tw-accent);
    border-radius: 50%;
}

.st-hoja-ejemplo .he-cnc .he-n {
    position: absolute;
    right: -13px;
    top: 50%;
    transform: translateY(-50%);
}

.st-hoja-ejemplo .he-logo .he-n {
    position: absolute;
    left: 6px;
    top: 6px;
}

/* El acomodo y la tabla, apagados: están para que se reconozca la hoja, no para leerse. */
.st-hoja-ejemplo .he-dibujo {
    height: 92px;
    margin: 8px 0;
    border: 0.75px solid #bbb;
    background-color: #fafafa;
    background-image:
        repeating-linear-gradient(90deg, transparent 0 46px, #c9c9c9 46px 47px),
        repeating-linear-gradient(0deg, transparent 0 22px, #c9c9c9 22px 23px);
}

.st-hoja-ejemplo .he-tabla {
    display: grid;
    grid-template-columns: 6% 30% 12% 12% 12% 12% 16%;
    border: 0.75px solid #bbb;
    color: #888;
    font-size: 12px;
}

.st-hoja-ejemplo .he-tabla span {
    padding: 4px 6px;
    border-right: 0.75px solid #ddd;
}

.he-notas {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 12px;
}

.he-notas li {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

/* El buscador de lo que se le puede meter a una caja · a lo ancho del panel,
   con aire hasta la lista. */
.st-buscar-disponible {
    display: block;
    width: 100%;
    max-width: none;
    margin: 12px 0 14px;
}

/* Entra sin que nadie haya comprobado la colada: la lámina no la tiene. En
   naranja, el mismo tono de «faltan por repartir»: no bloquea, pero se lee. */
.st-sin-colada {
    color: var(--tw-tag-orange-fg);
    font-size: var(--st-text-sm);
}

/* Lo que no entra, plegado · entre lo que cabe y el resto. Desde el 9-oct-2026
   es un renglón `.st-fold-head` a lo ancho, como todo lo que se pliega: el
   relleno lo pone él. */
.st-no-entran {
    border-top: 1px solid var(--tw-border-light);
}

/* La tira de lo que falta guardar · el segundo renglón de la barra.

   Con el rótulo a la izquierda y las fichas al lado: un título de ancho completo
   sobre una sola ficha era una franja entera de pantalla para doscientos
   píxeles de contenido. Con muchas láminas la tira se desplaza a lo ancho en vez
   de crecer hacia abajo, que es lo que empujaba el plano fuera de la vista. */
.st-tira {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 16px 14px;
}

.st-tira-rotulo {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
}

.st-tira .st-pend {
    flex: 1 1 auto;
    overflow-x: auto;
    padding-bottom: 2px;
}

.st-tira .st-pend-item {
    flex: 0 0 auto;
    padding: 8px 12px;
}

.st-pend-qty {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

/* ── Aire · las tarjetas no se pegan ──────────────────────────────────────

   Doce píxeles de hueco entre tarjetas de ciento sesenta de alto las deja
   leyéndose como una rejilla continua: el ojo no encuentra dónde acaba una caja
   y empieza la siguiente, que es justo lo que una tarjeta viene a resolver. Y el
   contenido dentro iba igual de junto —seis renglones a ocho píxeles— así que el
   número de piezas, la mezcla y la firma parecían el mismo párrafo.

   El margen lo pone el contenedor, como en el resto del sistema: ver
   `otv-aire-entre-tarjetas`. */
.st-cards {
    gap: 18px;
}

.st-card {
    gap: 12px;
    padding: 16px 18px;
}

/* La ocupación y la mezcla, separadas de lo de arriba y de lo de abajo: son los
   dos datos que se comparan entre cajas y necesitan quedar sueltos. */
.st-card-ocupacion {
    margin-top: 2px;
}

.st-card .st-chips {
    margin-top: 2px;
}

/* La firma de quién la dejó así va al pie y pegada al borde de abajo, no a la
   mitad: es la línea que se lee al final, cuando ya se decidió. */
.st-card > .st-card-senas:last-child {
    margin-top: auto;
    padding-top: 2px;
}

@media (max-width: 575.98px) {
    .st-cards {
        gap: 12px;
    }
}

/* Los dos estados que sólo ve el puesto de más adelante: la que le mandaron y
   todavía no cuenta, y la que ya contó y tiene en la mesa sin cerrar. */
.st-card--mandada {
    border-color: var(--tw-tag-blue-fg);
    background-color: var(--tw-tag-blue-bg);
}

.st-card--mesa {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

/* Y la cerrada que espera a que la recojan deja de ir teñida de azul: ese color
   es ahora el de «sin contar», que es trabajo esperando a alguien. Una caja
   cerrada y en su sitio no espera a nadie. */
.st-card--cerrada {
    border-color: var(--tw-border-medium);
    background-color: var(--tw-bg-primary);
}

/* ── El plano de cajas de Empaque · el mismo salón, otras mesas ───────────

   Salvador, 20 de septiembre de 2026: *«una manera más dinámica y gráfica de
   que propongan y visualicen cajas, algo estilo mesas de un restaurante»*. Es
   el plano de contenedores de arriba, con lo que cambia entre un puesto y el
   otro: aquí la caja no tiene capacidad —tiene **lo que declara**, y la barra
   mide cuánto de eso lleva escaneado— y sobre todo hay un envoltorio más, la
   tarima, que no se compara con sus cajas: las contiene.

   POR ESO LA TARIMA ES UNA ZONA Y NO UNA TARJETA. Dibujada como una tarjeta
   quedaba al lado de sus propias cajas, y saber cuáles eran suyas exigía leer
   un chip en cada una. Como zona la pertenencia se ve sin leer: lo que está
   dentro del recuadro, va dentro. Es la sala del plano de mesas. */
.st-zona {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-secondary);
}

/* Las zonas no se pegan entre ellas, igual que las tarjetas: el margen lo pone
   el contenedor. Ver `otv-aire-entre-tarjetas`. */
.st-zona + .st-zona,
.st-cards + .st-zona,
.st-zona + .st-cards {
    margin-top: 18px;
}

/* La cabecera es la tarima entera: código, estado, cuenta y su acción. Envuelve
   —el título es el que cede sitio— porque en la tablet la acción no se corta.
   Ver `otv-cabecera-de-subpanel-envuelve`. */
.st-zona-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.st-zona-cuenta {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
}

.st-zona-acciones {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-left: auto;
}

/* La tarima recién abierta no tiene cajas todavía y se dibuja igual, con su
   hueco: es lo que dice que se le van a escanear. */
.st-zona-vacia {
    padding: 18px 4px;
    text-align: center;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-zona--armada {
    border-color: var(--tw-tag-green-fg);
}

.st-zona--rechazada {
    border-color: var(--tw-tag-red-fg);
}

/* ── El arrastre de una caja a su tarima ─────────────────────────────────────
   Sólo con ratón: el arrastre del navegador no existe con el dedo, y el camino
   de la tablet es «Cambiar de tarima» en el «Más» de la caja. La tarjeta que
   viaja se apaga y la zona que va a recibirla se enciende entera; nada de
   mover el contenido, que a media pantalla parece que ya pasó algo. */
.st-card--arrastrando {
    opacity: 0.4;
}

.st-zona--recibe {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

/* Y mientras se arrastra, lo de dentro no se interpone: sin esto el `dragleave`
   salta al pasar por encima de cada tarjeta y la zona parpadea. */
.st-zona--recibe * {
    pointer-events: none;
}

/* La caja que se puede arrastrar lo dice al pasar por encima, y sólo con ratón:
   en la tablet un cursor que nadie ve no sobra, estorba. */
@media (hover: hover) and (pointer: fine) {
    .st-card[draggable='true'] {
        cursor: grab;
    }

    .st-card[draggable='true']:active {
        cursor: grabbing;
    }
}

/* «Sin tarima» no es un bulto: es el resto del salón. Sin fondo propio, para
   que las zonas de verdad sean las que se recortan contra la pantalla. */
.st-zona--suelta {
    background-color: transparent;
    border-style: dashed;
}

/* La zona que todavía no existe · «Nueva tarima». Punteada y en fila, como la
   ficha de abrir una caja, para que no se lea como una tarima más. */
.st-zona--nueva {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 88px;
    border-style: dashed;
    background-color: transparent;
    text-align: center;
    cursor: pointer;
}

.st-zona--nueva > i {
    font-size: 24px;
    color: var(--tw-font-secondary);
}

.st-zona--nueva:hover {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

/* Los cuatro estados teñidos de la caja de embarque · el tono va en el borde
   entero y el fondo, nunca en una barra al lado. Ver `otv-sin-bordes-ia`.

   «Por armar» no lleva ninguno: es lo normal, y teñir lo normal deja la
   pantalla sin fondo contra el que destacar lo que no lo es. */
.st-card--armandose {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-card--armada {
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

.st-card--rechazada {
    border-color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

/* Declarada y sin contenido: existe, no es de nadie todavía y no se toca. */
.st-card--vacia {
    background-color: var(--tw-bg-secondary);
    opacity: 0.72;
}

/* El chip de estado sobre una tarjeta teñida · LA píldora de la tarjeta.

   El chip y el tinte salen del mismo tono, así que puesto encima desaparecía:
   «Armada» sobre una tarjeta verde se leía como texto verde suelto, y la única
   píldora que quedaba a la vista era la de la prisa. Lo secundario ganándole a
   lo principal.

   Se le devuelve el fondo de la tarjeta **sin** teñir y el tono se queda donde
   se ve contra él: en la letra, que ya lo lleva, y en un aro del mismo color.
   `currentColor` es la letra del propio chip, así que los cuatro tonos salen de
   sus tokens sin repetirlos aquí. */
.st-card-estado {
    background-color: var(--tw-bg-primary);
    box-shadow: inset 0 0 0 1px currentColor;
}

/* Lo secundario de la tarjeta, arriba a la derecha y en plano: no compite con
   la tarjeta, que es la acción. */
.st-card-mas {
    margin-left: auto;
    min-height: 40px;
    padding: 0 10px;
    flex: 0 0 auto;
}

/* El código no se parte · un `BLT-2026-0017` cortado en dos renglones deja de
   leerse como un código y encima empuja la tarjeta media línea hacia abajo,
   así que dos tarjetas iguales dejan de estar a la misma altura. Lo que cede
   sitio es el botón de al lado, no el nombre. */
.st-card > .st-card-head > .st-card-code {
    white-space: nowrap;
}

/* Una ficha de contenido tampoco se sale de la tarjeta: el número de parte es
   largo y sin tope se lleva el ancho por delante. */
.st-card .st-chip-min {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Qué pasa al tocarla, al pie y pegado abajo: es la última línea que se lee,
   cuando ya se decidió. */
.st-card-go {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    margin-top: auto;
    padding-top: 2px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-primary);
}

/* La caja llena es una caja terminada, no una caja a punto de desbordarse: en
   Corte el tope en naranja avisa de que ya no cabe más, y aquí lo que dice es
   que ya está todo dentro. */
.st-card-cap-fill--ok {
    background-color: var(--tw-tag-green-fg);
}

/* La barra de avance de un renglón de lista —los embarques por preparar— no
   mide el ancho del renglón: es una seña al lado del folio, no una tabla. */
.st-list-item .st-card-cap {
    max-width: 260px;
}

/* El renglón de «lo que le puedes meter» · apilado.

   En la columna estrecha del detalle, el dato y sus controles lado a lado dejan
   el número de parte en un cuarto del ancho y parten el código de la lámina en
   tres líneas. Apilado se lee como una frase, y los controles quedan juntos
   abajo a la derecha, que es donde va la mano. */
.st-meter-row {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}

.st-meter-side {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

/* Con el veredicto a la izquierda del hueco: es la respuesta, y se lee antes de
   tocar el campo. */
.st-meter-side > .st-tag {
    margin-right: auto;
}

/* El renglón de meter, en tres pisos · qué es, cómo se reparte, qué se hace.

   Los tres campos iban en la misma línea que el veredicto y el botón, en una
   columna de 470 píxeles: el rótulo «No aparecen» se cortaba y el botón no
   casaba con los campos. Ahora el veredicto va con el título, que es de lo que
   habla, y el botón abajo con la frase de lo que queda por repartir. */
/* ── Lo que falta guardar, con la caja que le toca ─────────────────────────

   Cada lámina pendiente es un renglón que ya contesta: qué es, en qué caja va
   —o que hay que abrir una— y el botón que lo hace. En tres columnas para que la
   respuesta caiga siempre en la misma vertical y se lea bajando la vista, no
   buscándola en cada renglón. */
.st-sugerencia {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) auto;
    align-items: center;
    gap: 16px;
    cursor: pointer;
}

.st-sugerencia:hover {
    background-color: var(--tw-bg-tertiary);
}

/* La que llega de terminar un corte, o la que se tocó: el plano la está marcando. */
.st-sugerencia.is-active,
.st-sugerencia.is-active:hover {
    background-color: var(--tw-bg-secondary);
}

.st-sugerencia-respuesta {
    font-size: var(--st-text-md);
}

.st-sugerencia-respuesta .ti {
    color: var(--tw-font-secondary);
}

/* «Abre una caja nueva» no es un error: es la respuesta cuando ninguna sirve. Va
   en el tono de lo que hay que atender, no en rojo. */
.st-sugerencia-respuesta--nueva {
    color: var(--tw-tag-orange-fg);
}

@media (max-width: 991.98px) {
    .st-sugerencia {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .st-sugerencia-respuesta {
        grid-column: 1 / -1;
        grid-row: 2;
    }
}

/* El bulto de scrap en el historial · qué es a la izquierda, y a la derecha en
   qué va su etiqueta con el botón de pedirla otra vez cuando hace falta. */
.st-scrap-lado {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    max-width: 22rem;
    text-align: right;
}

/* La pastilla no se parte: dice el estado en dos o tres palabras, y lo que hay
   que hacer va debajo en su propia línea. Partida, el fondo redondo se rompía
   en tres renglones. */
.st-scrap-lado .st-tag {
    white-space: nowrap;
}

@media (max-width: 767.98px) {
    .st-list-item.st-scrap-bulto {
        flex-wrap: wrap;
    }

    .st-scrap-lado {
        align-items: flex-start;
        max-width: none;
        text-align: left;
    }
}

/* En una columna estrecha —la caja en grande de «Tus contenedores» de Empaque—
   el lado baja debajo del texto, como en el teléfono: a la derecha, «Reimprimir
   etiqueta» se partía en dos renglones. */
.st-list-item.st-scrap-bulto--estrecho {
    flex-wrap: wrap;
}

.st-scrap-bulto--estrecho .st-scrap-lado {
    align-items: flex-start;
    max-width: none;
    width: 100%;
    text-align: left;
}

.st-meter-cabeza {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.st-meter-cabeza > .st-tag {
    flex-shrink: 0;
}

/* Las tres salidas de lo que falta por guardar · a esta caja, de scrap o no
   aparecen, **a partes iguales y a lo ancho**. Cada campo lleva su rótulo
   encima: en este panel cada renglón es distinto —uno cabe, otro no entra— y no
   hay una cabecera común que los nombre. */
.st-meter-campos {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: end;
    gap: 12px;
}

/* Contar al recibir: buenas y de scrap, a partes iguales. */
.st-meter-campos--dos {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Y en la tablet horizontal, el número de parte a la izquierda de sus dos
   campos: con tres números de parte apilados, la caja no cabía sin bajar. */
@media (min-width: 992px) {
    .st-meter-row.st-conteo-renglon {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
        align-items: end;
        gap: 16px;
    }

    .st-conteo-renglon > .st-list-title {
        align-self: center;
    }

    /* Con varios números de parte las dos columnas se nombran una vez, arriba,
       y el rótulo de cada campo sobra. */
    .st-list--conteo .st-conteo-cabeza {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
        gap: 16px;
        padding: 0 16px 6px;
    }

    .st-list--conteo .st-conteo-renglon .st-meter-campo .st-field-label {
        display: none;
    }

    .st-list--conteo .st-meter-row.st-conteo-renglon {
        align-items: center;
    }
}

.st-conteo-cabeza {
    display: none;
}

/*
   La lámina se reparte entera (8-oct-2026): sus renglones en un bloque con su
   nombre arriba y un solo botón abajo. El bloque se separa del siguiente con la
   misma línea que los renglones; dentro, los renglones van sin línea propia
   arriba del primero.
*/
.st-meter-lamina {
    border-top: 1px solid var(--tw-border-light);
    padding-bottom: 12px;
}

.st-meter-lamina:first-child {
    border-top: 0;
}

.st-meter-lamina-cabeza {
    padding: 12px 16px 0;
}

.st-meter-lamina > .st-meter-pie {
    padding: 8px 16px 0;
}

.st-meter-pie {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: var(--st-hit);
}

.st-meter-pie .meter-cuadre {
    flex: 1 1 auto;
}

.st-meter-campo {
    display: flex;
    flex-direction: column;
    margin: 0;
}

.st-meter-campo .st-field-label {
    margin-bottom: 4px;
    white-space: nowrap;
}

.st-meter-campo .st-input,
.st-meter-campo .st-scan {
    width: 100%;
    min-height: 56px;
    text-align: center;
}

/* La caja que está aquí pero ya no es tuya · apartada para una salida, o ya en
   el proveedor. Punteada: sigue existiendo, no se le mete nada. */
.st-card--fuera {
    border-style: dashed;
    border-color: var(--tw-border-strong);
    background-color: var(--tw-bg-secondary);
}

/* ── Compras, vistas desde Almacén · consulta de órdenes y recepciones ────

   Tres pantallas de leer: la lista de órdenes a proveedor, su ficha y la
   bitácora de recepciones. Van con la escala de la estación —se consultan de
   pie, con la orden del chofer en la mano— y sin nada que escriba. */

/* La barra de una consulta: cómo se ve la lista y el buscador, en un renglón. */
.st-consulta-barra {
    display: flex;
    align-items: center;
    gap: 12px;
}

.st-consulta-barra .st-scan {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
}

.st-consulta-barra .st-block-count {
    flex-shrink: 0;
    min-width: 5ch;
    text-align: right;
}

@media (max-width: 767.98px) {
    .st-consulta-barra {
        flex-wrap: wrap;
    }

    .st-consulta-barra .st-seg {
        width: 100%;
    }

    .st-consulta-barra .st-seg-btn {
        flex: 1 1 0;
    }
}

/* Un control de tres posiciones. Plano, como el resto de la estación: la
   elegida se distingue por el fondo y el borde, no por una sombra. Alto de dedo
   con guante aunque vaya dentro de una barra. */
.st-seg {
    display: inline-flex;
    flex-shrink: 0;
    gap: 4px;
    padding: 4px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-secondary);
}

.st-seg-btn {
    min-height: 54px;
    padding: 0 18px;
    border: 1px solid transparent;
    border-radius: calc(var(--tw-radius-md) - 2px);
    background-color: transparent;
    color: var(--tw-font-secondary);
    font: inherit;
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    white-space: nowrap;
    cursor: pointer;
    transition:
        background-color var(--tw-transition),
        color var(--tw-transition);
}

.st-seg-btn:hover {
    color: var(--tw-font-primary);
}

.st-seg-btn[aria-pressed='true'] {
    background-color: var(--tw-bg-primary);
    border-color: var(--tw-border-strong);
    color: var(--tw-font-primary);
}

/* El mismo control a lo ancho, una opción por columna y su cifra debajo.
   Nació el 1 de octubre de 2026 para «¿De dónde sale cada componente?» al
   imprimir un ensamble: ahí se puede tocar más de una —si una procedencia no
   alcanza, otra cubre lo que falta—, así que la elegida se marca con el color
   de acción y no sólo con el borde. */
.st-seg--grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    width: 100%;
}

.st-seg--grid .st-seg-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 64px;
    padding: 8px 12px;
    white-space: normal;
    line-height: 1.2;
    text-align: center;
}

.st-seg--grid .st-seg-btn small {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-regular, 400);
    color: var(--tw-font-secondary);
}

.st-seg--grid .st-seg-btn[aria-pressed='true'] {
    background-color: var(--tw-accent-secondary);
    border-color: var(--tw-accent);
}

.st-seg--grid .st-seg-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* La cuenta de un reparto · cuánto pone cada procedencia, en una barra y en
   una frase. Nació con «¿De dónde salen las piezas?» (1 de octubre de 2026):
   con dos contenedores, existencia y sin registro a la vez, el operador tiene
   que ver de un vistazo cuánto sale de cada lado y si suma lo que imprime. Un
   color por procedencia, el mismo en la barra, en el punto de la frase y en el
   encabezado de su sección. */
.st-reparto {
    display: flex;
    height: 10px;
    border-radius: 999px;
    overflow: hidden;
    background-color: var(--tw-bg-tertiary);
}

.st-reparto > span {
    height: 100%;
}

.st-reparto > span + span {
    border-left: 2px solid var(--tw-bg-secondary);
}

.st-reparto-punto {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 999px;
    vertical-align: baseline;
}

.st-reparto--l {
    background-color: var(--tw-tag-blue-fg);
}

.st-reparto--s {
    background-color: var(--tw-tag-green-fg);
}

.st-reparto--d {
    background-color: var(--tw-tag-orange-fg);
}

/* La lista de una consulta es la pantalla entera, no un recuadro dentro de
   un paso: se le da el alto que queda bajo la barra. */
.st-list--alto {
    max-height: 62vh;
}

.st-list[aria-busy='true'] {
    opacity: 0.55;
    transition: opacity var(--tw-transition);
}

/* El avance de una orden en su renglón: cuántos renglones y la barra. */
.st-avance {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    min-width: 150px;
}

.st-avance-que {
    font-size: var(--st-text-sm);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.st-avance-barra {
    display: flex;
    align-items: center;
    white-space: nowrap;
}

/* El rótulo de la semana en la bitácora: un renglón de cabecera que no se
   pulsa, con el texto de un título de bloque. */
.st-semana {
    min-height: 40px;
    padding-top: 8px;
    padding-bottom: 8px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
    cursor: default;
}

/* Las cifras de arriba de la ficha. Cada una es rótulo, dato y una línea que
   dice de dónde sale; en la tablet horizontal caben cuatro en un renglón. */
.st-cifras {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
}

.st-cifra {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    padding: 14px 16px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
}

.st-cifra-rotulo {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tw-font-secondary);
}

.st-cifra-valor {
    display: flex;
    align-items: center;
    min-height: 26px;
}

.st-cifra-pie {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0 4px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* Lo retenido sí es un problema: el tono va en el borde entero y el fondo. */
.st-cifra--aviso {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

/* Una tabla de ficha no se recorta a media pantalla: la ficha es la que se
   desplaza, y el encabezado fijo se quedaría flotando sobre nada. */
.st-table-wrap--libre {
    max-height: none;
}

/* Los datos de una recepción, en rejilla sobre la tabla de sus renglones. */
.st-datos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 12px 20px;
    padding: 16px;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-dato-rotulo {
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-dato-valor {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-medium);
    overflow-wrap: anywhere;
}

.st-datos-pie {
    padding: 10px 16px;
    border-top: 1px solid var(--tw-border-light);
}

.st-notas {
    white-space: pre-line;
}

/* La cifra de una consulta del pie del inicio, pegada a su nombre. */
.st-lookup-count {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-secondary);
}

.st-lookup-count:not(:empty)::before {
    content: '·';
    margin-right: 6px;
    color: var(--tw-font-light);
}

/* El diálogo de leer una recepción, a lo ancho de la tablet.

   `modal-xl` sólo se ensancha desde 1200 px, y el iPad horizontal mide 1194:
   se quedaba en 720 y la tabla de renglones —seis columnas— se desplazaba de
   lado, con la etiqueta y el certificado fuera de la vista. */
@media (min-width: 768px) {
    /* Y todo `modal-xl` de estación, no sólo el que se acordó de la clase: el de
       Existencias se quedaba en 720 en la tablet (9-oct-2026). */
    .modal-xl,
    .st-modal-ancho {
        max-width: min(1080px, calc(100vw - 48px));
    }
}

/* En un teléfono, el control de tres posiciones y el lado derecho del renglón
   no caben con su holgura de tablet: «Todas» se salía del control y la etiqueta
   del plazo se cortaba contra el borde. Se reparte el ancho y el lado derecho
   baja a su propia línea. */
@media (max-width: 575.98px) {
    .st-consulta-barra .st-seg-btn {
        min-width: 0;
        padding: 0 8px;
    }

    .st-list--alto .st-pick-side {
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .st-list--alto .st-avance {
        min-width: 0;
        align-items: flex-start;
    }
}

/* ── La mesa de armado · el dibujo de una receta ──────────────────────────

   Armar ensambles era una lista plana: la receta iba en una frase —«PN ×2: 16 ·
   PN ×1: 10»— y para saber si alcanzaba había que hacer la división de cabeza,
   con las piezas en la mano y la caja en la mesa. Y lo que iba a sobrar, que es
   lo único que todavía se puede arreglar, salía al final o en un aviso de la
   esquina.

   Así que la receta se dibuja. Arriba el ensamble, con cuántos salen de lo que
   hay puesto; debajo un CARRIL por componente, y dentro del carril sus cajas
   como tarjetas que se tocan. Lo que se ve sin leer: cuántos salen, qué carril
   corta —teñido entero, borde y fondo, nunca una barra al lado— y qué caja está
   en la mesa.

   Todo lo de aquí lleva su propio prefijo y no toca una sola clase de las que ya
   había: `.st-card`, `.st-card-cap`, `.st-chips` y `.st-loadbar` son las mismas
   del plano de cajas y de la barra de Corte. */

/* ── La cabeza · qué se arma y cuántos salen ──────────────────────────────

   El ensamble va arriba y no en medio de sus componentes: se lee de arriba
   abajo —esto es lo que sale, y esto lo que lo alimenta— que es el orden en que
   se decide. En medio parecía un componente más. */
.st-arm-mesa-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 20px;
    padding: 10px 18px;
    border-bottom: 1px solid var(--tw-border-light);
}

/* La identidad cede el ancho al lector, y no al revés.

   Los tres respaldos del escáner —cámara, foto y teclado— miden lo que miden:
   si la columna del lector se queda corta bajan de línea y la banda crece
   cuarenta píxeles, que son los que le faltaban a la primera caja para caber
   en el iPad. Así que el lector pide más sitio de salida y crece el doble de
   deprisa; el número de parte se parte si hace falta, que no cuesta alto. */
.st-arm-mesa-quien {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 16px;
    flex: 1 1 260px;
    min-width: 0;
}

/* El número de parte cede el ancho y se parte antes que empujar el número
   grande a un renglón propio: dos renglones de código cuestan menos alto que
   una fila más en la banda. */
/* Un punto más pequeño que un título de pantalla, y por una razón de alto: a
   tamaño de título, el número de parte y el «5 se arman» no caben en el mismo
   renglón en el iPad y la banda crece una fila entera, que son las que le
   faltan a la primera caja para verse. */
.st-arm-mesa-pn {
    font-size: var(--st-text-lg);
    flex: 0 1 auto;
    min-width: 0;
    line-height: 1.2;
    overflow-wrap: anywhere;
}

/* Las señas bajan a su propio renglón para que el número de parte y el número
   grande compartan el primero: son los dos datos que se leen, y con las señas
   en medio el «5 se arman» caía suelto debajo de una frase. */
.st-arm-mesa-quien > .st-card-senas {
    flex: 1 0 100%;
    order: 3;
    min-width: 0;
}

/* Cuántos salen · el número grande, pegado al borde de su columna para que
   caiga siempre en la misma vertical y no baile con el largo del número de
   parte. */
.st-arm-mesa-salen {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex: 0 0 auto;
    margin-left: auto;
}

/* ── El lector · arriba, y diciendo qué falta ─────────────────────────────

   `.st-scan` mide el ancho entero porque nació para una pantalla que es el
   campo. Aquí el campo comparte renglón con la frase de lo que falta por
   escanear, que es la única instrucción de este paso y nace de lo que ya se
   eligió. */
.st-arm-lector {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px 16px;
    padding: 14px 18px;
}

/* Empaque · «¿Cuántos vas a armar?» y el botón del diálogo de procedencias, en
   el sitio del lector: aquí no se escanean cajas a la mesa, se elige de dónde
   sale cada componente (2 de octubre de 2026). */
.st-arm-mesa-head > .st-arm-plan {
    flex: 2 1 420px;
    max-width: 680px;
    margin-left: auto;
}

.st-arm-plan-fila {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}

.st-arm-cuantos {
    width: 110px;
    text-align: center;
    font-size: 20px;
    font-weight: 600;
}

/* Dentro de la banda de la cabeza no lleva relleno propio: lo pone la banda. */
.st-arm-mesa-head > .st-arm-lector {
    flex: 2 1 520px;
    max-width: 680px;
    margin-left: auto;
    padding: 0;
}

.st-arm-lector .st-scan {
    flex: 1 1 280px;
    max-width: 420px;
}

/* ── El lector, en una línea ──────────────────────────────────────────────

   El bloque del escáner nació para una pantalla que **es** el lector: disco de
   56 px, caja punteada de 112 de alto y los tres respaldos debajo. En la mesa
   eso son ciento sesenta píxeles antes de la primera caja, y la mesa son las
   cajas: a 1180×820 no se veía una entera sin desplazarse.

   Aquí el mismo bloque va tumbado —disco pequeño, caja de una línea y los tres
   respaldos a su derecha— sin tocar la regla compartida: todo cuelga del
   modificador, así que el lector de las demás pantallas no se entera. */
.st-arm-lector--linea .st-scan-step {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
}

/* La caja de espera se encoge hasta lo que mide su disco con dos palabras:
   lo que no puede bajar de línea son los tres respaldos, porque entonces el
   lector vuelve a medir ciento veinticinco píxeles. */
.st-arm-lector--linea .st-scan-wait {
    flex: 1 1 200px;
    max-width: 380px;
    min-height: 60px;
    padding: 8px 14px;
    gap: 12px;
}

.st-arm-lector--linea .st-scan-orb {
    width: 36px;
    height: 36px;
}

.st-arm-lector--linea .st-scan-orb i {
    font-size: 20px;
}

.st-arm-lector--linea .st-scan-wait-title {
    font-size: var(--st-text-md);
}

/* Los respaldos dejan de ir debajo y se ponen al lado, en una columna que se
   parte en dos filas si hace falta: dos filas de botón pequeño miden menos que
   una fila de botones debajo de la caja de espera, y dejan a ésta el ancho que
   necesita para decir lo que está leyendo en una sola línea. */
.st-arm-lector--linea .st-scan-alt {
    margin-top: 0;
    flex: 0 0 300px;
    gap: 4px;
}

.st-arm-lector--linea .st-scan-alt .st-btn {
    min-height: 36px;
    padding: 0 8px;
    font-size: var(--st-text-sm);
}

/* Y el campo tecleado, cuando se abre, ocupa la línea entera: es lo que se
   está haciendo, y al lado del disco no cabe. */
.st-arm-lector--linea .st-scan-manual {
    flex: 1 0 100%;
}

.st-arm-lector-que {
    flex: 1 1 200px;
    min-width: 0;
    font-size: var(--st-text-md);
    color: var(--tw-font-secondary);
}

/* ── Los carriles ─────────────────────────────────────────────────────── */

.st-arm-carriles {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 0 18px 14px;
}

.st-arm-carril {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-secondary);
}

/* El que corta · uno solo, teñido entero. Con dos marcados nadie sabe a cuál
   ir, y con una barra al lado no se ve a un metro. Ver `otv-sin-bordes-ia`. */
.st-arm-carril--corta {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

/* Y su píldora se vuelve maciza: la del mismo tono sobre el carril del mismo
   tono no se veía —era texto naranja suelto— y la píldora es el estado. */
.st-arm-carril--corta .st-arm-carril-head > .st-tag {
    background-color: var(--tw-tag-orange-fg);
    color: var(--tw-bg-primary);
}

/* La cabecera del carril envuelve y el que cede sitio es el nombre: el número
   de piezas en la mesa no se parte en dos renglones. */
.st-arm-carril-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 10px;
}

/* El nombre cede sitio y se parte si hace falta: un número de parte largo no
   se sale del carril ni se recorta con puntos suspensivos, porque lo que se
   recorta de un código es justo lo que lo distingue de otro. */
.st-arm-carril-head > .st-card-code {
    flex: 1 1 200px;
    min-width: 0;
    overflow-wrap: anywhere;
}

.st-arm-carril-lado {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-left: auto;
    flex: 0 0 auto;
}

/* El número del carril es el segundo de la pantalla, no el primero: el grande
   es cuántos ensambles salen. */
.st-arm-carril-lado .st-card-ocupacion-num {
    font-size: 26px;
}

/* Las cajas de un carril son más estrechas que las del plano: dentro de un
   carril caben cuatro en la tablet, y con seis bajan a un segundo renglón sin
   que el carril tenga que desplazarse por dentro —un desplazamiento dentro de
   otro se pierde con guante—. */
.st-arm-cajas {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 8px;
}

.st-arm-caja {
    text-align: left;
    color: inherit;
    cursor: pointer;
    gap: 4px;
    padding: 10px 12px;
}

/* Dos renglones y no cuatro: el código con lo que le queda arriba, y su estado
   con sus señas debajo. En cuatro la tarjeta medía ciento cincuenta píxeles y
   un carril entero no cabía en la pantalla de la tablet.

   El código va en su renglón y no al lado del número: la columna de una caja
   mide doscientos píxeles y en esos no caben los dos, así que el código se
   partía en tres líneas y la tarjeta crecía en vez de encoger. */
.st-arm-caja > .st-card-head > .st-card-code {
    flex: 1 0 100%;
}

.st-arm-caja-num {
    flex: 0 0 auto;
    font-size: 22px;
    line-height: 1.1;
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
}

.st-arm-caja-num > small {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-regular);
    color: var(--tw-font-secondary);
}

.st-arm-caja-linea {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
}

.st-arm-caja-linea > .st-chips {
    flex: 1 1 auto;
    justify-content: flex-end;
    margin-top: 0;
}

/* El motivo de por qué no se puede, anclado a la tarjeta que se tocó y no en un
   aviso de la esquina: el problema está aquí, y aquí es donde todavía se puede
   ir por la otra caja. Sin sitio reservado mientras no hay nada que decir. */
.st-arm-caja-por {
    display: none;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-tag-red-fg);
}

.st-arm-caja-por.is-on {
    display: block;
}

/* ── El código de una tarjeta no se sale ─────────────────────────────────

   El plano de cajas de embarque le prohíbe partirse —un `BLT-2026-0017` roto
   en dos deja de leerse como un código— y esa regla vale para un folio de doce
   caracteres. Aquí los códigos son números de parte del cliente, que son
   largos y no tienen tope: `UI-PN-ENSAMBLE-ESPERA` se salía del borde derecho
   de su tarjeta.

   Así que en estas tarjetas el código ocupa su propio renglón y se parte
   cuando no cabe de ninguna manera. No se recorta con puntos suspensivos: lo
   que se pierde al recortar un código es justo lo que lo distingue de otro. La
   altura no baila porque la retícula estira todas las tarjetas de la fila. */
.st-arm-cand > .st-card-head > .st-card-code,
.st-arm-enuso > .st-card-head > .st-card-code,
.st-arm-vaciada > .st-card-head > .st-card-code {
    flex: 1 0 100%;
}

.st-arm-cand > .st-card-head > .st-card-code,
.st-arm-caja > .st-card-head > .st-card-code,
.st-arm-enuso > .st-card-head > .st-card-code,
.st-arm-vaciada > .st-card-head > .st-card-code {
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}

.st-arm-medidor-head > .st-card-code {
    overflow-wrap: anywhere;
}

/* ── Las tarjetas de «¿qué vas a armar?» ─────────────────────────────────

   Una por ensamble, con el mismo reparto que una caja del plano: código
   arriba con su estado, la ocupación en número grande al centro con su barra, y
   la receta en fichas. La que no se puede armar se apaga y su porqué está en la
   tarjeta, que es lo que evita el viaje. */
.st-arm-cand {
    min-height: 200px;
}

/* ── Armar · la mesa gastándose ──────────────────────────────────────────

   El contador es el centro, y alrededor se ve bajar lo que queda: un medidor
   por componente con su barra, las cajas en uso, y el avance de la orden. */
.st-arm-tablero {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px 24px;
    padding: 12px 18px 0;
}

.st-arm-tablero > .st-counter {
    flex: 1 1 320px;
}

/* El avance de la orden · a la derecha del contador y con su propia barra: el
   contador dice lo de esta sesión y esto lo de la orden entera. */
.st-arm-avance {
    flex: 0 1 280px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.st-arm-avance-num {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.st-arm-medidores {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 12px;
}

.st-arm-medidor {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
}

/* El componente que se acabó · teñido entero, como el carril que corta: es la
   razón por la que el botón de armar está apagado. */
.st-arm-medidor--seco {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-arm-medidor-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 10px;
}

.st-arm-medidor-head > .st-card-code {
    flex: 1 1 auto;
    min-width: 0;
}

.st-arm-medidor .st-card-ocupacion-num {
    font-size: 26px;
}

/* Las dos salidas del pie, juntas y por orden de uso: primero terminar, y el
   botón de armar pegado al borde derecho, que es donde va el pulgar. */
.st-arm-go {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
}

/* «Armé uno» se toca cientos de veces por turno con guante: es el botón más
   grande de la estación y vive en la barra pegada, para que no dependa de
   cuánto haya que desplazarse. */
.st-arm-btn {
    min-height: 64px;
    min-width: 200px;
    font-size: var(--st-text-lg);
}

/* Las cajas en uso no son elegibles: son el acuse de con cuáles se está
   armando, así que no se levantan al pasar por encima. */
.st-arm-enuso {
    cursor: default;
}

/* ── Cerrar las cajas · las tres cifras del paso ─────────────────────────

   Llegaron, salieron en armados y quedan. En una línea de tres, porque lo que
   se compara es una con otra: si «quedan» no es cero, hay que decir por qué. */
/* La colada y el sobrante comparten renglón en el pie de la mesa: son dos
   señas cortas y en dos líneas el pie pegado crecía un tercio, que es alto que
   se le quita a las cajas. */
.st-block--panel > .st-loadbar {
    padding: 10px 16px;
}

.st-arm-mesa-pie {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 2px 16px;
}

.st-arm-mesa-pie > .st-loadbar-pending {
    margin-top: 0;
}

.st-arm-cifras {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 20px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

.st-arm-cifras b {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--tw-font-primary);
}

/* ── Listo · a dónde van ─────────────────────────────────────────────── */

.st-arm-final-que {
    margin-top: 10px;
    font-size: var(--st-text-md);
    color: var(--tw-font-secondary);
}

/* En el iPad en vertical y en el teléfono, el pie de armar se reparte el ancho
   en vez de amontonar los dos botones contra el borde. */
@media (max-width: 767.98px) {
    .st-arm-go {
        width: 100%;
    }

    .st-arm-go > .st-btn {
        flex: 1 1 0;
        min-width: 0;
    }

    .st-arm-mesa-salen,
    .st-arm-carril-lado {
        margin-left: 0;
    }
}

/* ══ LA TARIMA, DIBUJADA COMO UNA TARIMA · 22 de septiembre de 2026 ════════

   Salvador: *«las tarimas son pallets, ¿podrías ser más interactivo y dinámico
   para representar esto tanto en admin como en estación?»*.

   Una zona con borde y un rótulo que dice «Tarima» es una caja con letras
   dentro: el operador tiene delante un pallet de madera con cajas encima y en
   la pantalla veía una lista. Ahora la zona **se apoya en su tarima**: las
   cajas se dibujan arriba y debajo va la plataforma, con sus tres tablas y sus
   dos tacos. Es un dibujo de CSS, sin imágenes: pesa cero y se tiñe solo en
   los dos temas.

   La misma figura, con los mismos tonos, vive en la ficha del embarque
   (`.tw-pallet` en `twenty-theme.css`). Que el piso y la oficina miren el mismo
   dibujo es la mitad del valor: se habla por radio señalando «la de la
   izquierda». */

.st-tarima-base {
    /* Un pelo más angosta que la zona: el pallet no toca los bordes, lo que
       deja ver que la carga se apoya encima y no que la zona tiene un pie. */
    margin: 2px 6px 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* Las tres tablas de la plataforma. */
.st-tarima-tablas {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 3px;
}

.st-tarima-tablas > span {
    height: 11px;
    border-radius: 2px;
    /* Dos tonos del tema, no un gris plano: con uno solo la plataforma se lee
       como una barra de progreso a medio llenar. */
    background-image: linear-gradient(
        180deg,
        var(--tw-border-strong) 0%,
        var(--tw-border-strong) 60%,
        var(--tw-border-medium) 100%
    );
}

/* Los dos tacos, que es lo que la levanta del suelo. */
.st-tarima-tacos {
    display: flex;
    justify-content: space-between;
    padding: 0 10px;
}

.st-tarima-tacos > span {
    width: 24%;
    height: 8px;
    border-radius: 0 0 3px 3px;
    background-color: var(--tw-border-medium);
}

/* El taco del centro, en el pseudoelemento: una plataforma de dos patas parece
   una mesa. */
.st-tarima-tacos::before {
    content: '';
    width: 24%;
    height: 8px;
    border-radius: 0 0 3px 3px;
    background-color: var(--tw-border-medium);
}

/* Cargada: la plataforma se tiñe del verde del sistema cuando la tarima está
   armada, que es el mismo tono que su chip. El dibujo no inventa un estado
   nuevo, repite el que ya se dice con palabras. */
.st-zona--armada .st-tarima-tablas > span {
    background-image: none;
    background-color: var(--tw-tag-green-fg);
}

/* Y mientras se arrastra una caja encima, la plataforma se enciende: es la
   misma señal que `.st-zona--recibe` pone en el borde, dicha donde va a caer. */
.st-zona--recibe .st-tarima-tablas > span {
    background-image: none;
    background-color: var(--tw-accent);
}

/* La carga · las cajas apoyadas encima de la plataforma.

   Pegadas a ella —sin el aire de `.st-cards`— porque lo que se está diciendo
   es que están **encima**: un hueco de 12 px entre la última caja y la madera
   las deja flotando. */
.st-tarima-carga {
    display: grid;
    /* Cajas de ancho parejo y pegadas a la izquierda, como se apilan de verdad
       sobre la tarima: con `1fr` dos cajas se estiraban a media zona cada una y
       el hueco de la derecha desaparecía. Ese hueco es lo que queda libre en la
       plataforma, y se ve porque la madera sigue debajo. */
    grid-template-columns: repeat(auto-fill, minmax(228px, 264px));
    justify-content: start;
    gap: 8px;
    padding: 0 4px 6px;
}

/* La tarima vacía sigue enseñando su plataforma, con la instrucción encima: es
   lo que convierte el hueco en un sitio donde soltar algo. */
.st-tarima-vacia {
    padding: 10px;
    text-align: center;
    font-size: var(--st-text-sm);
    color: var(--tw-font-light);
}

/* ── EL AVISO GRANDE · 23 de septiembre de 2026 ────────────────────────────

   Salvador: *«hacer más visible doble escaneo de una pieza que ya se metió,
   que no sea un toast [...] me gustaría que todas las alertas de las
   estaciones sea mediante avisos grandes y no toasts»*.

   El toast de la esquina superior derecha es de un panel de escritorio: 14 px,
   cinco segundos y a dos brazos de distancia de donde el operador está
   mirando, que es el lector y la pieza que tiene en la mano. Escaneando
   seguido no se lee ninguno; el que avisa de que acaba de meter dos veces la
   misma pieza tampoco.

   Aquí son dos cosas distintas según lo que haya pasado, y la diferencia es
   deliberada:

     · **Lo que salió mal** —error y aviso— toma la pantalla entera y **no se
       va solo**. Hay que tocarlo. Es lo que para la mano antes del siguiente
       escaneo, que es justo lo que se pidió.
     · **Lo que salió bien** —hecho y dato— es una banda ancha arriba del
       trabajo, en grande, y se va sola en dos segundos y medio. Bloquear cada
       acierto obligaría a tocar la pantalla cuarenta veces para llenar una
       caja de cuarenta piezas, y eso lo que consigue es que el operador toque
       sin leer: cuando llegue el que importa, ya no lo mira.

   Se mide contra el iPad en horizontal, que es la terminal de Empaque. */

.st-aviso-fondo {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--st-gutter);
    /* Oscurece lo de detrás sin esconderlo: el operador tiene que reconocer
       en qué pantalla estaba para saber a qué vuelve al tocar. */
    background-color: rgb(0 0 0 / 55%);
}

.st-aviso-fondo[hidden] {
    display: none;
}

.st-aviso {
    display: flex;
    flex-direction: column;
    gap: 20px;
    width: min(680px, 100%);
    max-height: 100%;
    padding: 28px;
    border-radius: var(--tw-radius-md, 8px);
    border: 3px solid var(--tw-tag-red-fg);
    background-color: var(--tw-bg-primary);
    box-shadow: 0 24px 64px rgb(0 0 0 / 35%);
}

.st-aviso--warning {
    border-color: var(--tw-tag-orange-fg);
}

.st-aviso-cabeza {
    display: flex;
    align-items: center;
    gap: 18px;
}

/* El icono es del tamaño de la mano, no del texto: a un metro de la tablet es
   lo primero que se reconoce, antes de leer una palabra. */
.st-aviso-icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    flex-shrink: 0;
    border-radius: var(--tw-radius-sm);
    font-size: 44px;
    color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

.st-aviso--warning .st-aviso-icono {
    color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-aviso-titulo {
    font-size: var(--st-text-xl);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.15;
}

/* El mensaje del servidor, que es el que dice qué pasó y qué hacer. Va a 20 px
   y se desplaza si es largo: recortarlo dejaría fuera justo la mitad que
   explica qué hacer ahora. */
.st-aviso-texto {
    font-size: var(--st-text-lg);
    line-height: 1.35;
    overflow-y: auto;
    /* Un código de barras leído mal llega sin espacios y de sesenta
       caracteres: sin esto se sale de la tarjeta. */
    overflow-wrap: anywhere;
}

/* El pie pegado abajo y el botón a lo ancho, como en todo el puesto: se toca
   con guante y sin apuntar. */
.st-aviso-pie {
    margin-top: auto;
}

.st-aviso-pie .st-btn {
    width: 100%;
    min-height: var(--st-hit);
    font-size: var(--st-text-lg);
}

/* ── Y lo que salió bien · la banda que se va sola ─────────────────────── */

.st-bandas {
    position: fixed;
    /* El `top` lo pone `aviso.js` con el alto real de la cabecera: no es fijo
       —la franja de avisos permanentes aparece y desaparece sola— y con `0` la
       banda tapaba qué estación es y qué turno corre. */
    top: 0;
    left: 0;
    right: 0;
    z-index: 1900;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px var(--st-gutter);
    pointer-events: none;
}

.st-banda {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    border-radius: var(--tw-radius-sm);
    border: 2px solid var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
    color: var(--tw-font-primary);
    font-size: var(--st-text-lg);
    line-height: 1.25;
    box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
    /* Se puede tocar para quitarla antes de tiempo; el contenedor no estorba
       lo de debajo. */
    pointer-events: auto;
    overflow-wrap: anywhere;
}

.st-banda--info {
    border-color: var(--tw-tag-blue-fg);
    background-color: var(--tw-tag-blue-bg);
}

.st-banda-icono {
    font-size: 28px;
    flex-shrink: 0;
    color: var(--tw-tag-green-fg);
}

.st-banda--info .st-banda-icono {
    color: var(--tw-tag-blue-fg);
}

.st-banda--saliendo {
    opacity: 0;
    transition: opacity 0.25s ease;
}

/* En el teléfono la tarjeta ocupa todo y el icono baja de tamaño: el título
   necesita el ancho más que el dibujo. */
@media (max-width: 575.98px) {
    .st-aviso {
        padding: 18px;
        gap: 14px;
    }

    .st-aviso-icono {
        width: 52px;
        height: 52px;
        font-size: 32px;
    }
}

/* ── EL CAMIÓN Y LA TARIMA ABIERTA · 23 de septiembre de 2026 ──────────────

   Salvador, sobre EMB-2026-0010 —siete tarimas y 209 cajas, 22,700 px de
   plano en el iPad—: *«una vista generalizada y luego dar clic y que sea una
   transición como de abrir una tarima y comenzar a escanear»*.

   Arriba el camión: un mosaico por tarima, sin sus cajas. Al tocarlo crece
   hasta ser la pantalla (View Transitions: `#paso-tarima` y el mosaico tocado
   comparten nombre, y el navegador interpola uno en el otro). Dentro, cada
   caja es una casilla y no una tarjeta: 160 casillas caben en unos pocos
   renglones, 160 tarjetas eran 15,300 px. */

.st-mosaicos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.st-mosaico {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px 16px 10px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    cursor: pointer;
    transition:
        border-color var(--tw-transition),
        transform var(--tw-transition);
}

.st-mosaico:hover {
    border-color: var(--tw-border-strong, var(--tw-accent));
}

.st-mosaico:active {
    transform: scale(0.98);
}

.st-mosaico-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* La nota de la oficina es como la reconocen en el andén —«CAJAS MDF»—, así
   que va grande, justo debajo del código. */
.st-mosaico-nota {
    font-weight: 500;
    color: var(--tw-font-primary);
}

.st-mosaico-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* La base de madera, pegada al pie del mosaico: la carga va encima. */
.st-mosaico .st-tarima-base {
    margin-top: auto;
}

.st-mosaico--armada {
    border-color: var(--tw-tag-green-fg);
}

.st-mosaico--armada .st-tarima-tablas > span {
    background-image: none;
    background-color: var(--tw-tag-green-fg);
}

.st-mosaico--rechazada {
    border-color: var(--tw-tag-red-fg);
}

.st-mosaico.st-zona--recibe {
    border-color: var(--tw-accent);
}

.st-mosaicos + .st-zona {
    margin-top: 18px;
}

/* ── La tarima abierta: grupos por número de parte, una casilla por caja ─── */

.st-grupo-tarima {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px;
    border-top: 1px solid var(--tw-border-light, var(--tw-border-medium));
}

.st-grupo-tarima:first-child {
    border-top: 0;
}

.st-grupo-tarima-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.st-grupo-tarima-head .st-zona-cuenta {
    margin-left: auto;
}

.st-celdas {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* 32 px: lo más chico que el dedo acierta en el iPad sin tocar la de al lado. */
.st-celda {
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--tw-border-medium);
    border-radius: 6px;
    background-color: var(--tw-bg-secondary);
    cursor: pointer;
    transition:
        background-color 0.3s,
        transform 0.3s;
}

.st-celda--dentro {
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-fg);
}

.st-celda--armada {
    border: 2px solid var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

.st-celda--armandose {
    border-color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-celda--rechazada {
    border-color: var(--tw-tag-red-fg);
    background-color: var(--tw-tag-red-bg);
}

.st-celda--vacia {
    border-style: dashed;
    background-color: transparent;
    cursor: default;
}

/* La que acaba de entrar late una vez: es lo que dice «ésa» sin leer nada. */
.st-celda--recien {
    animation: st-celda-late 0.6s ease-out;
}

@keyframes st-celda-late {
    0% { transform: scale(1); }
    35% { transform: scale(1.45); }
    100% { transform: scale(1); }
}

.st-celda--muestra {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    vertical-align: -1px;
    cursor: default;
}

.st-leyenda--celdas {
    padding: 4px 16px 14px;
}

/* La transición · el mosaico tocado y la tarima abierta son el mismo objeto. */
#paso-tarima {
    view-transition-name: tarima-abierta;
}

::view-transition-group(tarima-abierta) {
    animation-duration: 380ms;
    animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 200ms;
}

@media (prefers-reduced-motion: reduce) {
    .st-celda--recien {
        animation: none;
    }
}

/* Lo que es el mosaico, dicho antes que su código: «Tarima». Sin esto el
   mosaico se leía como una caja más con muchas cajas dentro. */
.st-mosaico-tipo {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--st-text-sm);
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tw-font-secondary);
}

/* La pastilla que dice qué adhesivo se escanea lleva el icono del lector. */
.st-grupo-tarima-head .st-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* Los seriales de una partida en Verificar · cuáles faltan y cuáles ya pasaron.

   Van debajo del renglón que se pulsó y no en otra pantalla: se miran con la
   mesa delante, entre lectura y lectura. El consecutivo es lo que se busca en la
   etiqueta; el código entero va en el título. */
.st-serials {
    display: grid;
    gap: 12px;
    padding: 12px 16px 16px;
    border-bottom: 1px solid var(--tw-border-light);
    background: var(--tw-bg-secondary);
}

.st-serials-title {
    margin-bottom: 6px;
    font-weight: 600;
}

.st-serials-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.st-serial {
    font-variant-numeric: tabular-nums;
}

/* El desglose de etiquetas de una partida · las mismas cifras que el panel.
   Se llamaba `.st-desglose`, igual que el plegable de «Tus contenedores», y
   esta regla también le pegaba a ese `<details>`: lo volvía una fila flexible
   y su renglón dejaba de ir a lo ancho (9-oct-2026). */
.st-desglose-pastillas {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

/* Lo que el buscador de número de parte deja fuera (station/filtro-partes.js).
   Con !important porque los renglones traen su propio display (flex). */
.st-oculto {
    display: none !important;
}

/* ── «¿Cómo hago…?» · el glosario de preguntas (glosario/panel.js) ──────────

   Dos columnas en la tablet: la lista con su buscador a la izquierda y la
   respuesta a la derecha, cada una con su propio desplazamiento, para que al
   bajar por los pasos no se pierda la lista. En teléfono, una sola: la lista,
   y al tocar una pregunta la respuesta en su lugar con «Todas las preguntas».

   Lo que va entre «» en una respuesta es texto de pantalla y se resalta: es lo
   que la persona va a buscar con la vista en la tablet. */
.st-glosario {
    display: grid;
    grid-template-columns: minmax(280px, 2fr) minmax(0, 3fr);
    height: min(74dvh, 680px);
}

.st-glosario-lista {
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-right: 1px solid var(--tw-border-light);
}

.st-glosario-buscar {
    padding: 16px 16px 4px;
}

.st-glosario-buscar .st-scan {
    width: 100%;
}

.st-glosario-preguntas {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 0 16px 16px;
}

.st-glosario-grupo {
    margin: 16px 0 8px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-secondary);
}

.st-glosario-item,
.st-glosario-ysi {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    min-height: 52px;
    padding: 10px 14px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: var(--tw-font-primary);
    font-size: var(--st-text-md);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--tw-transition);
}

.st-glosario-item + .st-glosario-item,
.st-glosario-ysi + .st-glosario-ysi {
    margin-top: 6px;
}

.st-glosario-item:hover,
.st-glosario-ysi:hover {
    background-color: var(--tw-bg-tertiary);
}

.st-glosario-item[aria-current='true'] {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

.st-glosario-ysi .ti {
    color: var(--tw-font-light);
}

.st-glosario-vacio {
    padding: 24px 4px;
    color: var(--tw-font-secondary);
}

/* El capítulo en video, a la vista con su portada (9-oct-2026). */
.st-glosario-video {
    margin: 4px 0 16px;
}

.st-glosario-video video {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--tw-radius-lg);
    background: #000;
}

/* El buscador como asistente (9-oct-2026): las preguntas con video lo dicen
   en la lista, «Ver más parecidas» y la pista de abajo. */
.st-glosario-con-video {
    flex: 0 0 auto;
    color: var(--tw-accent);
}

.st-glosario-mas {
    margin-top: 8px;
}

.st-glosario-pista {
    padding: 12px 4px 0;
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary, var(--tw-font-secondary));
}

.st-glosario-respuesta {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
    padding: 20px 24px 0;
}

.st-glosario-inicio {
    display: grid;
    place-items: center;
    gap: 10px;
    margin: auto;
    max-width: 320px;
    color: var(--tw-font-secondary);
    text-align: center;
}

.st-glosario-inicio .ti {
    font-size: 40px;
    color: var(--tw-font-light);
}

/* Con el contenedor delante: `.modal .st-btn` (dos clases) le pondría su display. */
.st-glosario .st-glosario-volver {
    display: none;
    align-self: flex-start;
    margin-bottom: 12px;
}

.st-glosario-pregunta {
    margin: 0 0 8px;
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    line-height: 1.3;
}

.st-glosario-corta {
    margin: 0 0 8px;
    font-size: 1.125rem;
    line-height: 1.45;
}

.st-glosario-porque {
    margin: 0;
    color: var(--tw-font-secondary);
    line-height: 1.5;
}

.st-glosario-cita {
    font-weight: var(--tw-weight-semibold);
    color: var(--tw-font-primary);
}

.st-glosario-rotulo {
    margin: 22px 0 10px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-font-secondary);
}

.st-glosario-pasos {
    display: grid;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: paso;
}

.st-glosario-pasos li {
    display: grid;
    grid-template-columns: 28px 1fr;
    gap: 12px;
    align-items: start;
    line-height: 1.5;
}

.st-glosario-pasos li::before {
    counter-increment: paso;
    content: counter(paso);
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background-color: var(--tw-accent-secondary);
    color: var(--tw-accent);
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-semibold);
}

.st-glosario-mensaje {
    display: grid;
    gap: 2px;
    padding: 10px 0;
    border-top: 1px solid var(--tw-border-light);
}

.st-glosario-mensaje:last-child {
    border-bottom: 1px solid var(--tw-border-light);
}

.st-glosario-dice {
    font-weight: var(--tw-weight-medium);
}

.st-glosario-quiere {
    color: var(--tw-font-secondary);
}

/* El pie va pegado abajo, como el de los asistentes: «Practícalo» no se busca. */
.st-glosario-pie {
    position: sticky;
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 12px;
    margin-top: auto;
    padding: 16px 0 20px;
    background-color: var(--tw-bg-primary);
}

/* Sin pie, el último bloque no se queda pegado al borde de abajo. */
.st-glosario-respuesta > :last-child:not(.st-glosario-pie) {
    margin-bottom: 20px;
}

@media (max-width: 899.98px) {
    .st-glosario {
        grid-template-columns: 1fr;
        height: min(80dvh, 720px);
    }

    .st-glosario-lista {
        border-right: 0;
    }

    .st-glosario--respuesta .st-glosario-lista,
    .st-glosario:not(.st-glosario--respuesta) .st-glosario-respuesta {
        display: none;
    }

    .st-glosario .st-glosario-volver {
        display: inline-flex;
    }
}

@media (max-width: 767.98px) {
    .st-glosario {
        height: 100%;
    }
}

/* Transiciones y no cargas (5-oct-2026): al pasar de una pantalla a otra —y del 3D al 2D, que recarga— el navegador funde
   la anterior en la siguiente en vez de enseñar la página en blanco. Las dos páginas lo declaran; donde no se soporta no
   pasa nada. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
}

/* ── Las máquinas de Corte · el tablero y el diálogo de cambiarla (8-oct-2026) ─────────────────────────

   Salvador: «como se ve en la vista las máquinas con corte activo necesito algo intuitivo que lo vean y lo puedan
   cambiar». Una tarjeta por máquina del puesto (`maquinas-de-corte.js`): el nombre grande, si corta o está libre,
   qué nesteo y qué lámina, quién y desde cuándo, y su acción. La que corta se enciende entera —borde y fondo—, sin
   barra al lado. El punto sólo late mientras corta: es lo único que se mueve. */
.st-maquinas .st-cards {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 12px;
}

.st-maq {
    gap: 6px;
    padding: 14px 16px;
}

.st-maq--cortando {
    border-color: var(--tw-tag-green-fg);
    background-color: var(--tw-tag-green-bg);
}

.st-maq-cab {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.st-maq-nombre {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.st-maq-luz {
    flex: none;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background-color: var(--tw-tag-gray-fg);
    opacity: 0.45;
}

.st-maq--cortando .st-maq-luz {
    background-color: var(--tw-tag-green-fg);
    opacity: 1;
}

@media (prefers-reduced-motion: no-preference) {
    .st-maq--cortando .st-maq-luz {
        animation: st-maq-late 2.4s ease-in-out infinite;
    }
}

@keyframes st-maq-late {
    0%,
    100% {
        box-shadow: 0 0 0 0 color-mix(in srgb, var(--tw-tag-green-fg) 45%, transparent);
    }
    50% {
        box-shadow: 0 0 0 6px color-mix(in srgb, var(--tw-tag-green-fg) 0%, transparent);
    }
}

.st-maq-estado {
    flex: none;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    white-space: nowrap;
    color: var(--tw-tag-gray-fg);
    background-color: var(--tw-tag-gray-bg);
}

.st-maq-estado--cortando {
    color: var(--tw-tag-green-fg);
    background-color: var(--tw-bg-primary);
}

.st-maq-estado--ocupada {
    color: var(--tw-tag-orange-fg);
    background-color: var(--tw-tag-orange-bg);
}

.st-maq-estado--actual {
    color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

.st-maq-que {
    font-size: var(--st-text-md);
    line-height: 1.35;
}

.st-maq-quien {
    min-height: 1.3em;
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary);
}

.st-maq .st-card-foot {
    padding-top: 6px;
}

/* El diálogo · cada máquina es un renglón que se toca entero, con su estado a la derecha. La que no se puede elegir
   dice por qué y baja de tono; no desaparece: saber que la otra está ocupada es la respuesta. */
.st-maq-opciones {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.st-maq-opcion {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    min-height: var(--st-row);
    padding: 12px 16px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: var(--tw-font-primary);
    text-align: left;
    transition:
        border-color var(--tw-transition),
        background-color var(--tw-transition);
}

.st-maq-opcion:not(:disabled):hover,
.st-maq-opcion:not(:disabled):focus-visible {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
}

.st-maq-opcion:disabled {
    cursor: default;
    border-style: dashed;
    background-color: transparent;
}

.st-maq-opcion:disabled .st-maq-opcion-nombre,
.st-maq-opcion:disabled .st-maq-opcion-icono {
    color: var(--tw-font-tertiary);
}

.st-maq-opcion-icono {
    flex: none;
    font-size: 28px;
    color: var(--tw-font-secondary);
}

.st-maq-opcion-texto {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.st-maq-opcion-nombre {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
}

.st-maq-opcion-detalle {
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary);
}

.st-maq-elegida {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-semibold);
}

.st-maq-elegida .st-muted {
    font-size: var(--st-text-md);
    font-weight: var(--tw-weight-regular);
}

.st-maq-motivos {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 8px;
}

.st-maq-motivo.is-active {
    border-color: var(--tw-accent);
    background-color: var(--tw-accent-secondary);
    color: var(--tw-accent);
}

/* En Empezar · la máquina con su «Cambiar» al lado, y lo que cambió dicho debajo. */
.st-maq-fija {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
}

/* El rótulo del tablero, con su cuenta a la derecha y la línea fina del resto de los flujos. */
.st-maquinas-titulo {
    display: flex;
    align-items: center;
    gap: 10px;
}

.st-maquinas-titulo::after {
    content: '';
    order: 1;
    flex: 1 1 auto;
    height: 1px;
    background-color: var(--tw-border-light);
}

.st-maquinas-cuenta {
    order: 2;
    font-weight: var(--tw-weight-medium);
    text-transform: none;
    letter-spacing: 0;
}

/* La cabecera de la tarjeta se toca para ver la máquina entera: un botón sin aspecto de botón, con su flecha. */
button.st-maq-cab {
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.st-maq-ir {
    flex: none;
    color: var(--tw-font-tertiary);
}

/* Sin subrayado (no se subraya al pasar, en todo el sistema): la flecha toma el acento. */
button.st-maq-cab:hover .st-maq-ir,
button.st-maq-cab:focus-visible .st-maq-ir {
    color: var(--tw-accent);
}

/* El estado, dicho como la primera palabra de lo que hace la máquina: en su color, sin píldora. */
.st-maq-dice {
    font-weight: var(--tw-weight-semibold);
}

.st-maq-dice--cortando {
    color: var(--tw-tag-green-fg);
}

.st-maq-dice--libre {
    color: var(--tw-font-secondary);
}

/* Las sugerencias de «Teclear el código» (8-oct-2026) · cuelgan del campo del
   lector como las del buscador de Empezar (`.st-sugerencias`); el renglón del
   campo y Continuar es su ancla. */
.st-scan-manual-row.st-buscador {
    position: relative;
}

.st-sugerencias--lector {
    z-index: 40;
}

/* La máquina se elige siempre en Empezar (8-oct-2026) · la indicada por
   Ingeniería marcada en el color de acento, y la tocada con su borde. */
.st-maq-estado--indicada {
    color: var(--tw-accent);
    background-color: var(--tw-accent-tertiary);
}

.st-maq-opcion.is-elegida {
    border-color: var(--tw-accent);
    box-shadow: inset 0 0 0 1px var(--tw-accent);
    background-color: var(--tw-accent-tertiary);
}


/* ── «Enséñame cómo» · el mapa y el «Así se ve» dentro del globo (8-oct-2026) ──

   El mapa es la lista de pasos de la pantalla con el de ahora marcado. El
   ejemplo es un pedazo de pantalla dibujado por las mismas funciones que la
   pintan, dentro del globo y no en la página: va en un marco punteado con su
   rótulo «Ejemplo», apagado (`inert`) y a tamaño de globo. Ver
   `components/ensename.js`. */
.driver-popover.tw-guia-globo {
    max-width: min(400px, calc(100vw - 32px));
}

.tw-ensename-mapa {
    margin: 10px 0 0;
    padding-left: 22px;
    display: grid;
    gap: 4px;
}

.tw-ensename-mapa li[aria-current='step'] {
    color: var(--tw-font-primary);
    font-weight: var(--tw-weight-semibold);
}

.tw-ensename-aqui {
    margin-left: 4px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--tw-tag-blue-bg);
    color: var(--tw-tag-blue-fg);
    font-size: var(--tw-font-size-sm);
    font-weight: var(--tw-weight-medium);
}

.tw-ensename-ejemplo {
    position: relative;
    margin-top: 16px;
    padding: 14px 10px 10px;
    border: 1px dashed var(--tw-border-strong);
    border-radius: var(--tw-radius-md);
    background: var(--tw-bg-secondary);
    pointer-events: none;
}

/* Lo de dentro, a tres cuartos: cabe entero en el globo y se sigue leyendo. */
.tw-ensename-ejemplo-cuerpo {
    zoom: 0.78;
    max-height: 420px;
    overflow: hidden;
}

.tw-ensename-ejemplo-rotulo {
    position: absolute;
    top: -9px;
    left: 10px;
    padding: 0 6px;
    background: var(--tw-bg-primary);
    color: var(--tw-font-tertiary);
    font-size: 11px;
    line-height: 18px;
    font-weight: var(--tw-weight-medium);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Lo de la pantalla se encoge al globo: el renglón de lista y los botones a la mitad de su alto. */
.tw-ensename-ejemplo .st-list-item {
    min-height: 0;
    padding: 8px 10px;
}

.tw-ensename-ejemplo .st-btn {
    min-height: 32px;
    padding: 0 10px;
}

.tw-ensename-ejemplo .st-maq-opcion {
    min-height: 0;
}

/* ── La cabecera de la pantalla (8-oct-2026) ─────────────────────────────────

   Salvador: «en todas las estaciones cuida esto, demasiados botones
   amontonados». Los botones de la cabecera no se parten en dos renglones; si
   no caben, `cabecera-de-pagina.js` los lleva a «Más» (a la vista se quedan una
   acción, lo principal y la vuelta). «Enséñame cómo» va debajo del subtítulo,
   como enlace: es ayuda de lo que la pantalla dice, no una acción más. */
.st-page-head .st-btn {
    white-space: nowrap;
}

.st-page-head > :last-child:not(:first-child) {
    flex: 0 0 auto;
}

.st-menu-mas .st-mas-item {
    display: flex;
    width: 100%;
    justify-content: flex-start;
    gap: 10px;
    min-height: var(--st-hit-bar);
    padding: 8px 14px;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    color: var(--tw-font-primary);
    text-align: left;
    white-space: nowrap;
}

.st-menu-mas .st-mas-item:hover,
.st-menu-mas .st-mas-item:focus-visible {
    background: var(--tw-bg-tertiary);
}

.st-menu-mas .st-mas-item .st-btn-label {
    display: inline;
}

.st-ensename {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 36px;
    margin-top: 4px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--tw-accent);
    font: inherit;
    font-weight: var(--tw-weight-medium);
    cursor: pointer;
}

.st-ensename:hover {
    text-decoration: underline;
}

.st-ensename:focus-visible {
    outline: 2px solid var(--tw-accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Y la cabecera de arriba: sus botones tampoco se parten en dos renglones
   («Modo / 3D», «¿Cómo / hago…?» a 800 px). Entre el teléfono y la tablet del
   kiosco se quedan con su icono —llevan `title`—; desde 900 px, con su texto. */
.st-header .st-btn {
    white-space: nowrap;
}

@media (min-width: 576px) and (max-width: 899.98px) {
    .st-header .st-btn-label {
        display: none;
    }

    .st-header .st-btn {
        padding: 0 12px;
    }
}

/* La primera vez, en el mismo renglón de «Enséñame cómo»: una línea tenue y
   «Ya sé» (`ensename.js`). Sin caja ni botón propio: la acción es el enlace. */
.st-ensename-oferta {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-left: 10px;
    color: var(--tw-font-light);
    font-size: var(--st-text-sm);
}

.st-ensename-ya {
    padding: 0;
    border: 0;
    background: none;
    color: var(--tw-font-secondary);
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.st-ensename-ya:hover {
    color: var(--tw-font-primary);
}

/* ── Imprimir etiquetas · la ruta y lo que se escanea (8 de octubre de 2026) ──

   «De dónde» enseña los lugares en el orden en que se recorren, numerados, con
   lo que se hace en cada uno; «Escanear», las cajas que no están en la mesa.
   El color de cada procedencia va en el punto (`.st-reparto-punto`), nunca en
   un borde lateral: Salvador lo volvió a pedir ese día. */
.st-ruta {
    display: grid;
    gap: 10px;
}

.st-lugar {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr) auto;
    gap: 12px;
    align-items: start;
    padding: 12px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
}

.st-lugar--hecho {
    opacity: 0.6;
}

.st-lugar-num {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 999px;
    background-color: var(--tw-bg-tertiary);
    font-weight: var(--tw-weight-semibold);
}

.st-lugar-que {
    margin-top: 6px;
    color: var(--tw-font-primary);
}

.st-lugar .st-code {
    overflow-wrap: anywhere;
}

/* El número de terminadas que se toman de una caja que sigue en su proceso. */
.st-paso-numero .st-input {
    width: 96px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* El buscador de «¿Qué quieres imprimir?»: es la pregunta del paso, no un filtro de lista. */
.st-filter--grande {
    min-height: 56px;
    font-size: var(--st-text-lg);
}

/* Cuántas cajas van escaneadas. */
.st-avance-barra-larga {
    height: 10px;
    border-radius: 999px;
    overflow: hidden;
    background-color: var(--tw-bg-tertiary);
}

.st-avance-barra-larga > span {
    display: block;
    width: 0;
    height: 100%;
    background-color: var(--tw-tag-green-fg);
    transition: width var(--tw-transition);
}

/* Un enlace dentro de una frase: «¿No están ahí? Imprímelas sin trazabilidad». */
.st-enlace {
    padding: 0;
    border: 0;
    background: none;
    color: var(--tw-accent);
    font: inherit;
    cursor: pointer;
}


/* Lo de vez en cuando de «De dónde», en una línea de enlaces bajo la ruta. */
.st-ruta-enlaces {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 20px;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
}

/* ── El inicio de «Lo que sigue» (Empaque, 8-oct-2026) ─────────────────────

   Un campo para escanear o escribir lo que se tiene en la mano, los mosaicos
   del turno y, debajo, la lista de lo que espera —una cosa por renglón y una
   acción—; lo demás plegado en «Más». Ver `inicio` en stations.ts.

   La lista va debajo de las puertas desde el mismo día (Salvador: «lo único
   que no me gusta es que en todas las vistas pones lo que sigue por encima de
   las acciones principales»). */
.st-que-sigue {
    margin-bottom: 24px;
}

.st-que-sigue--abajo {
    margin: 24px 0 0;
}

.st-que-sigue--abajo .st-que-sigue-titulo {
    margin-top: 0;
}

/* ── «Aquí vale la pistola», en pequeño (8-oct-2026) ──────────────────────

   Un marco de lector con una línea que sube y baja, a la izquierda de todo
   buscador que acepta la pistola. Lo pone `bindScanner` con `campo: true`
   (`ponerIndicadorDeEscaneo`); el paso de escanear grande sigue siendo el de
   `armarPaso`. Es la única seña que se mueve en el campo: con el campo apagado
   se queda quieta y tenue, y con «reducir movimiento» la línea va fija. */
.st-campo-escaneo {
    position: relative;
    display: block;
    width: 100%;
}

.st-campo-escaneo > input {
    padding-left: 56px;
}

.st-escaneando {
    --st-escaneo-color: var(--tw-accent);
    --st-escaneo-esquina: 7px;
    --st-escaneo-trazo: 2px;

    position: absolute;
    top: 50%;
    left: 16px;
    width: 26px;
    height: 22px;
    transform: translateY(-50%);
    pointer-events: none;
    /* Las cuatro esquinas del marco, sin imagen: dos trazos por esquina. */
    background:
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) top left / var(--st-escaneo-esquina) var(--st-escaneo-trazo),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) top left / var(--st-escaneo-trazo) var(--st-escaneo-esquina),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) top right / var(--st-escaneo-esquina) var(--st-escaneo-trazo),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) top right / var(--st-escaneo-trazo) var(--st-escaneo-esquina),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) bottom left / var(--st-escaneo-esquina) var(--st-escaneo-trazo),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) bottom left / var(--st-escaneo-trazo) var(--st-escaneo-esquina),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) bottom right / var(--st-escaneo-esquina) var(--st-escaneo-trazo),
        linear-gradient(var(--st-escaneo-color), var(--st-escaneo-color)) bottom right / var(--st-escaneo-trazo) var(--st-escaneo-esquina);
    background-repeat: no-repeat;
}

/* Las barras del código, tenues, dentro del marco. */
.st-escaneando::before {
    content: '';
    position: absolute;
    inset: 6px 6px;
    background: repeating-linear-gradient(
        90deg,
        var(--tw-font-light) 0 1px,
        transparent 1px 3px,
        var(--tw-font-light) 3px 5px,
        transparent 5px 6px
    );
    opacity: 0.45;
}

/* La línea del lector. */
.st-escaneando::after {
    content: '';
    position: absolute;
    left: 3px;
    right: 3px;
    top: 3px;
    height: 2px;
    border-radius: 1px;
    background-color: var(--st-escaneo-color);
    animation: st-escaneando 1.4s ease-in-out infinite alternate;
}

@keyframes st-escaneando {
    from {
        transform: translateY(0);
    }
    to {
        transform: translateY(14px);
    }
}

.st-campo-escaneo:has(> input:disabled) .st-escaneando {
    opacity: 0.4;
}

.st-campo-escaneo:has(> input:disabled) .st-escaneando::after {
    animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
    .st-escaneando::after {
        animation: none;
        transform: translateY(7px);
    }
}

.st-que-sigue-titulo {
    margin-top: 20px;
}

.st-que-sigue .st-list {
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    overflow: hidden;
}

.st-sigue {
    --st-task-pad: 10px;
    justify-content: flex-start;
    min-height: 56px;
}

/* Las puertas del turno, compactas: la lista de abajo dice qué hay que
   hacer, así que el mosaico sólo nombra la puerta y su cifra. La descripción
   vuelve con «Ver las reglas». */
.st-turno--compacto .st-tiles--turno .st-tile {
    min-height: 0;
    padding: 14px 16px;
    gap: 8px;
}

.st-turno--compacto .st-tiles--turno .st-tile-title {
    font-size: var(--st-text-lg);
    padding-right: 24px;
}

.st-turno--compacto .st-tiles--turno .st-tile-desc {
    display: none;
}

html[data-reglas] .st-turno--compacto .st-tiles--turno .st-tile-desc {
    display: -webkit-box;
}

.st-turno--compacto .st-tiles--turno .st-tile-go {
    bottom: 16px;
}

.st-sigue-icono {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--tw-radius-sm);
    background-color: var(--tw-bg-tertiary);
    color: var(--tw-font-secondary);
    font-size: 20px;
}

.st-sigue-accion {
    font-weight: var(--tw-weight-semibold);
    color: var(--tw-accent);
    white-space: nowrap;
}

/* «Más»: lo que no es del turno. Plegado no gasta alto en la tablet. */
.st-inicio-mas {
    margin-top: 24px;
    border-bottom: 1px solid var(--tw-border-light);
}

.st-inicio-mas > summary {
    padding-left: 2px;
    padding-right: 2px;
}

.st-inicio-mas[open] > summary {
    margin-bottom: 12px;
}

/* Abierto, lo último que lleva —la tira de «Consulta» en Almacén y Empaque, los
   mosaicos en Procesos— se quedaba pegado a la raya de abajo: el pliegue pone la
   línea y no dejaba aire debajo de su contenido (9-oct-2026, «mira el borde
   inferior»). El mismo aire que la tira deja entre su raya de arriba y los
   botones. */
.st-inicio-mas[open] {
    padding-bottom: 14px;
}

@media (max-width: 575.98px) {
    .st-sigue-icono {
        display: none;
    }
}

/* ── Los contenedores que están en el puesto (11-oct-2026) ────────────────

   Salvador, con el inicio de Empaque: «no hay conciencia de los contenedores
   que tienen ahí en su estación de manera clara». Entre las puertas del turno
   y «Lo que sigue», una tarjeta chica por caja en un solo renglón que se
   desliza de lado: el alto no crece con las cajas, y en la tablet el inicio
   sigue cabiendo. Una sola píldora por tarjeta —lo que le pasa—; la prisa va
   en el número de parte. Ver `cajas-del-puesto.js`. */
.st-cajas-puesto {
    margin-top: 24px;
}

.st-cajas-puesto-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin: 0 2px 10px;
}

.st-cajas-puesto-head > .st-flow-title {
    margin: 0;
}

.st-cajas-puesto-cuenta {
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary);
    font-variant-numeric: tabular-nums;
}

.st-cajas-puesto-todos {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-medium);
    color: var(--tw-accent);
    text-decoration: none;
    white-space: nowrap;
}

.st-cajas-puesto-todos:hover {
    text-decoration: underline;
}

.st-cajas-puesto-lista {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 256px;
    gap: 10px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: thin;
    /* Aire para la sombra del foco y para que la barra no pise las tarjetas. */
    padding: 2px 2px 6px;
    margin: -2px -2px 0;
}

.st-caja-puesto {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
    padding: 10px 14px;
    border: 1px solid var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    background-color: var(--tw-bg-primary);
    color: var(--tw-font-primary);
    text-decoration: none;
    scroll-snap-align: start;
}

.st-caja-puesto:hover {
    border-color: var(--tw-border-strong);
    color: var(--tw-font-primary);
}

.st-caja-puesto:focus-visible {
    outline: 2px solid var(--tw-accent);
    outline-offset: 1px;
}

.st-caja-puesto-cab {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.st-caja-puesto-code {
    font-size: var(--st-text-lg);
    font-weight: var(--tw-weight-medium);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.st-caja-puesto-pza {
    margin-left: auto;
    font-size: var(--st-text-sm);
    color: var(--tw-font-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.st-caja-puesto-partes {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    font-size: var(--st-text-sm);
    white-space: nowrap;
    overflow: hidden;
}

.st-caja-puesto-partes > .st-code {
    overflow: hidden;
    text-overflow: ellipsis;
}

.st-caja-puesto-pie {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

/* La píldora es lo que se lee de lejos: si algo no cabe, se recorta la hora. */
.st-caja-puesto-pie > .st-tag {
    flex: 0 0 auto;
}

.st-caja-puesto-cuando {
    flex: 0 1 auto;
    min-width: 0;
    margin-left: auto;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary);
    white-space: nowrap;
}

/* Sin cajas, un renglón a lo ancho y no una tarjeta más del carril. */
.st-cajas-puesto-lista:has(> .st-cajas-puesto-vacio) {
    display: block;
}

.st-cajas-puesto-vacio {
    padding: 12px 14px;
    border: 1px dashed var(--tw-border-medium);
    border-radius: var(--tw-radius-md);
    font-size: var(--st-text-sm);
    color: var(--tw-font-tertiary);
}

/* En el puesto de proceso la rejilla de las puertas ya pone el aire. */
.st-puertas > .st-cajas-puesto {
    margin-top: 0;
}

.st-cajas-puesto-head > .st-flow-title {
    white-space: nowrap;
}

/* En el teléfono la cuenta no cabe junto al rótulo y al enlace: las tarjetas
   ya la dicen. */
@media (max-width: 575.98px) {
    .st-cajas-puesto-cuenta {
        display: none;
    }
}

/* ── «Pegar y verificar» sin esperar: la lista de lecturas (8-oct-2026) ─────

   Cada lectura entra al instante como «comprobando» y se pone en verde o en
   rojo cuando vuelve su tanda. Lo rechazado que nadie ha visto va arriba, en
   el recuadro rojo, hasta que se toca «Entendido». Ver «Leer sin esperar» en
   verify.js. */
.st-lecturas {
    display: grid;
    gap: 6px;
    margin-top: 12px;
}

.st-lecturas-rechazadas .st-lectura {
    margin-top: 8px;
    background-color: var(--tw-bg-primary);
}

.st-lectura {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border: 1px solid var(--tw-border-light);
    border-radius: var(--tw-radius-sm);
}

.st-lectura-texto {
    min-width: 0;
}

.st-lectura-texto .st-code {
    overflow-wrap: anywhere;
}

.st-lectura-icono {
    font-size: 22px;
    color: var(--tw-font-light);
}

.st-lectura--ok .st-lectura-icono {
    color: var(--tw-tag-green-fg);
}

.st-lectura--rechazada .st-lectura-icono {
    color: var(--tw-tag-red-fg);
}

.st-lectura--granel .st-lectura-icono {
    color: var(--tw-tag-orange-fg);
}

.st-lectura--quitada {
    opacity: 0.6;
}

.st-lectura--enviando .st-lectura-icono {
    animation: st-girando 0.9s linear infinite;
}

@keyframes st-girando {
    to {
        transform: rotate(360deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .st-lectura--enviando .st-lectura-icono {
        animation: none;
    }
}

/* La cifra del mosaico con lo que cuenta debajo: «16 / números de parte para hoy» (`cuentaDice`). */
.st-tile-mark .st-block-count:has(.st-cuenta-que) {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.1;
    text-align: right;
}

.st-cuenta-que {
    font-size: var(--st-text-sm);
    font-weight: var(--tw-weight-regular, 400);
    color: var(--tw-font-secondary);
}

.st-lectura--repetida .st-lectura-icono {
    color: var(--tw-font-secondary);
}

/* ── El distribuidor (8-oct-2026) ───────────────────────────────────────────

   Cada lugar con su cantidad y − / +, ya repartido; debajo, «48 de 50 · faltan
   2». Lo que no se puede tomar va apagado y dice por qué. Ver
   `station/distribuidor.js`. */
.st-reparto-lugar {
    grid-template-columns: 36px minmax(0, 1fr) auto;
}

.st-reparto-lugar--apagado {
    opacity: 0.55;
}

.st-reparto-lugar:not(.st-reparto-lugar--usado):not(.st-reparto-lugar--apagado) .st-list-title {
    color: var(--tw-font-secondary);
}

.st-reparto-paso {
    display: flex;
    align-items: center;
    gap: 6px;
}

.st-reparto-paso .st-input {
    width: 64px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-size: var(--st-text-lg);
}

.st-reparto-de {
    min-width: 64px;
    font-size: var(--st-text-sm);
}

.st-reparto-motivo {
    width: 100%;
}

.st-reparto-bloque + .st-reparto-bloque {
    margin-top: 20px;
    padding-top: 14px;
    border-top: 1px solid var(--tw-border-light);
}

.st-reparto-cabeza {
    margin-bottom: 8px;
    font-weight: var(--tw-weight-medium);
}

.st-reparto-total {
    margin-top: 12px;
}

.st-reparto-total-texto {
    margin-top: 6px;
    font-size: var(--st-text-md);
}

.st-reparto-total--listo .st-reparto-total-texto strong {
    color: var(--tw-tag-green-fg);
}

/* De otra orden: el punto en morado, como la pastilla de otra orden. */
.st-reparto--o {
    background-color: var(--tw-tag-purple-fg, #a78bfa);
}

@media (max-width: 575.98px) {
    .st-reparto-lugar {
        grid-template-columns: minmax(0, 1fr);
    }

    .st-reparto-lugar > .st-lugar-num {
        display: none;
    }

    .st-reparto-de {
        min-width: 0;
    }
}

/* ── El lector nunca espera, en todos los pasos de escaneo (8-oct-2026) ─────

   Debajo de cada paso de `bindScanner`: lo leído entra al instante y se pone en
   verde, ámbar o rojo según vuelve. Ver «El lector nunca espera» en station.js. */
.st-scan-lecturas:empty {
    display: none;
}

.st-scan-lecturas {
    margin-top: 12px;
}

.st-scan-lecturas .st-lecturas {
    margin-top: 8px;
}

.st-scan-lecturas .st-lecturas-rechazadas + .st-lecturas-rechazadas {
    margin-top: 8px;
}

.st-lectura--aviso .st-lectura-icono {
    color: var(--tw-tag-orange-fg);
}

.st-lectura--fila .st-lectura-icono {
    animation: none;
}

.st-scan-step[data-turno='off'] .st-scan-lecturas .st-lecturas {
    display: none;
}

/* El lector separado de la pregunta aunque entre los dos haya algo escondido
   (la barra de avance de «Escanear» sale sólo con dos cajas o más). Pegado, la
   pista quedaba encima del recuadro punteado (8-oct-2026, «cuidado con los
   amontonamientos de texto sobre el componente de escaneo»). */
:is(.st-step-ask, .st-step-hint) ~ .st-scan-step {
    margin-top: 16px;
}

/* ── − / + en las cantidades de los procesos (8-oct-2026) ────────────────────

   Salvador: «no debe haber repartición automática». Las cantidades de Corte,
   Tus contenedores, Partir, Baños, la salida y el retorno externos nacen en 0 y
   se dicen con − / +: es el `.st-reparto-paso` del distribuidor fuera de él,
   para un número suelto o los tres campos de un renglón (buenas, de scrap, no
   aparecen). Ver `station/process/pasos-de-cantidad.js`. */
.st-con-pasos .st-input {
    padding: 0 6px;
    -moz-appearance: textfield;
}

.st-con-pasos .st-input::-webkit-inner-spin-button,
.st-con-pasos .st-input::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* En los tres campos de un renglón el − / + llena su columna, y cabe en la
   columna angosta de «Tus contenedores» en la tablet. */
.st-meter-campo .st-con-pasos {
    display: grid;
    grid-template-columns: minmax(32px, 40px) minmax(30px, 1fr) minmax(32px, 40px);
    gap: 4px;
}

.st-meter-campo .st-con-pasos .st-btn--icon {
    width: 100%;
}

.st-meter-campo .st-con-pasos .st-input {
    width: 100%;
    min-width: 0;
    min-height: 48px;
}

/* La cuenta de debajo de cada renglón, pegada a sus campos. */
.meter-cuadre .st-reparto-total,
.cierre-cuadre .st-reparto-total,
[data-cuenta-salida] .st-reparto-total {
    margin-top: 4px;
}

/* «¿Qué salió?» en grande (8-oct-2026). Salvador, viendo el reparto de «Tus
   contenedores»: «esto se ve bien pero en el modal hazlo más grande». El diálogo
   ocupa casi toda la tablet y los tres campos de cada número de parte crecen:
   botones de 48, número de 24 px; a lo ancho caben con el «#» de la hoja. */
.st-modal-cierre {
    max-width: min(1080px, calc(100vw - 32px));
}

.st-modal-cierre .st-meter-campos {
    gap: 16px;
}

.st-modal-cierre .st-meter-campo .st-con-pasos {
    grid-template-columns: 48px minmax(48px, 1fr) 48px;
    gap: 6px;
}

.st-modal-cierre .st-meter-campo .st-con-pasos .st-btn--icon {
    height: 56px;
}

.st-modal-cierre .st-meter-campo .st-con-pasos .st-input {
    min-height: 56px;
    font-size: 24px;
}

.st-modal-cierre .st-meter-campo .st-field-label {
    font-size: var(--st-text-md);
}

/* «Tus contenedores» se apila también en el iPad horizontal (8-oct-2026).
   Salvador, viendo el reparto a lo ancho: «esto se ve bien». En dos columnas el
   reparto —a esta caja, de scrap, no aparecen— cabía en 5/12 de la tablet y los
   campos quedaban del ancho de sus botones; con «Una caja nueva» la columna de
   la izquierda iba casi vacía. Debajo de 1400 px va la caja arriba y lo que le
   puedes meter a lo ancho. */
@media (min-width: 992px) and (max-width: 1399.98px) {
    .st-cols--apila-en-tablet.st-cols--7-5 {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Los botones de acción no se esconden (8-oct-2026). Salvador: «solo ten
   cuidado que los botones de acción no se pierdan o escondan». El «Meter…» de
   cada lámina va pegado al pie de la pantalla mientras sus renglones se ven, y
   apilado no hay un segundo desplazamiento: la lista de lo que se mete crece
   con la página en vez de cortarse a 42vh con el botón dentro. */
.st-meter-lamina > .st-meter-pie {
    position: sticky;
    bottom: 0;
    z-index: 2;
    padding-bottom: 12px;
    background-color: var(--tw-bg-primary);
    box-shadow: 0 -8px 12px -8px rgba(0, 0, 0, 0.35);
}

.st-meter-lamina {
    padding-bottom: 0;
}

@media (max-width: 1399.98px) {
    .st-cols--apila-en-tablet #disponibles-lista {
        max-height: none;
        overflow: visible;
    }
}

/* Y en «¿Qué salió?» el pie no se va (8-oct-2026, «que los botones de acción no
   se pierdan»): con doce números de parte el diálogo pasaba del alto de la
   tablet y «Siguiente» quedaba abajo, fuera. Ahora se desplaza el cuerpo y la
   cabecera y el pie se quedan. El `<form>` envuelve cuerpo y pie, así que tiene
   que dejar pasar el alto. */
.st-modal-cierre.modal-dialog-scrollable .modal-content > form {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.st-modal-cierre.modal-dialog-scrollable .modal-content > form > .modal-body {
    overflow-y: auto;
}

/* Los tres destinos de una pieza, de un vistazo (8-oct-2026). Salvador:
   «puedes poner fondos de colores a los inputs para diferenciar los tres tipos,
   así sombreado». Verde lo que sigue su camino —buenas, a esta caja, suben—,
   rojo el scrap y ámbar lo que no aparece. Es el tinte de las etiquetas, que
   cambia solo con el tema; el número sigue en el color del texto. */
:is(input[data-good], input.meter-cantidad, input.conteo-parte, input.cierre-parte, input[data-declarado]) {
    background-color: var(--tw-tag-green-bg);
    border-color: color-mix(in srgb, var(--tw-tag-green-fg) 35%, transparent);
}

:is(input[data-rejected], input.meter-scrap, input.conteo-scrap, input.cierre-scrap, input[data-scrap-de]) {
    background-color: var(--tw-tag-red-bg);
    border-color: color-mix(in srgb, var(--tw-tag-red-fg) 35%, transparent);
}

:is(input[data-missing], input.meter-no-aparecen, input[data-faltan-de]) {
    background-color: var(--tw-tag-orange-bg);
    border-color: color-mix(in srgb, var(--tw-tag-orange-fg) 35%, transparent);
}

/* El rótulo lleva el mismo color, para que el campo y su nombre se lean juntos. */
.st-meter-campo:has(:is(input[data-good], input.meter-cantidad, input[data-declarado])) > .st-field-label {
    color: var(--tw-tag-green-fg);
}

.st-meter-campo:has(:is(input[data-rejected], input.meter-scrap, input[data-scrap-de])) > .st-field-label {
    color: var(--tw-tag-red-fg);
}

.st-meter-campo:has(:is(input[data-missing], input.meter-no-aparecen, input[data-faltan-de])) > .st-field-label {
    color: var(--tw-tag-orange-fg);
}
