/* ============================================================================
   Trazabilidad y Calidad — Azúcar · identidad visual
   ----------------------------------------------------------------------------
   TODO cuelga de `.trz-ui` y usa el prefijo `trz-`. El resto de la aplicación
   sigue con Tailwind por CDN: si una regla de acá se escapara del scope,
   rompería los módulos que nadie está mirando. No sacar el `.trz-ui ` de
   adelante de ningún selector.

   Tratamiento "Capas" (opción B de los dos mockups, elegida por Hernán): la
   jerarquía sale de la ELEVACIÓN sobre un lienzo deliberadamente más oscuro,
   no del contraste. Es el mismo tratamiento del ABM y por el mismo motivo —
   este módulo apila CUATRO zonas: el rail navy del sistema, la barra blanca
   del armazón, el rail de secciones del módulo y el área de trabajo. A 13,5 px
   el peso tipográfico solo no alcanza para separar cuatro.

   Ver docs/identidad-visual.md §1.2 ("Cuando lo plano no alcanza") y el
   RUNBOOK.
   ========================================================================== */

/* LA PALETA NO ESTÁ ACÁ. Vive en src/core/tokens.css, que se carga antes.
   Acá quedan sólo los apartamientos de este módulo, cada uno con su porqué.
   Agregar un token a esta lista es declarar que el módulo se ve distinto en
   eso: si no hay un motivo, va a tokens.css. */
.trz-ui {
    /* Acento interactivo, EXCLUSIVO de este módulo. Mismo valor que el del ABM
       a propósito: no es "el azul de Trazabilidad", es "el azul de lo que se
       toca en un módulo tratado con Capas", y dos tratamientos iguales que
       eligen dos azules distintos es como empezó la deriva que cerró
       tokens.css.

       La regla del acento (§3 del RUNBOOK) pide justificar el segundo azul:
       acá navy ya está gastado en el rail del sistema y en el crumb de la
       barra, así que si el ítem activo del rail del módulo también fuera navy,
       las tres cosas pesarían igual y ninguna diría "estás acá".
       No es un color semántico: nunca significa bien ni mal. */
    --azure: #1668c4;
    --azure-700: #1259ab;
    --azure-050: #eaf2fd;

    /* Lienzo más oscuro que el de los módulos planos (#f1f2f5), a propósito:
       una tarjeta blanca con sombra no tiene de dónde despegarse sobre un
       fondo casi blanco, y la sombra se percibe como suciedad. */
    --canvas: #e6ebf3;

    /* 12 y no 14: las tarjetas de acá son muchas y chicas (las de pendiente
       del panel, la ficha, los bloques del rail). Con el radio grande se ven
       infladas. */
    --r-card: 12px;
}

/* TRAMPA §7 del manual: `.trz-ui .hidden` y `.trz-ui .tnum` NO van acá — se
   declaran en core/tokens.css junto con las de los otros módulos, para que la
   lista esté en un solo lugar. Lo que queda acá es lo que nombra una clase
   PROPIA y por eso no se puede agrupar: el root de un modal, que lleva
   `.trz-ui` él mismo. */
.trz-ui.trz-modal.hidden { display: none; }

.trz-ui .material-symbols-outlined { font-size: 18px; line-height: 1; vertical-align: -4px; }
/* El foco sigue al acento del módulo, que es azure y no navy. */
.trz-ui :focus-visible { outline: 2px solid var(--azure); outline-offset: 2px; border-radius: 5px; }

/* ── §MOVIMIENTO ─────────────────────────────────────────────────────────────
   Vocabulario A, el mismo de RRHH / ABM / Configuración, sin cambios:
     · una sola curva para todo lo que se desplaza — var(--curva);
     · .14s para color y fondo, .18s para transformaciones;
     · nada se mueve más de 2 px: el gesto confirma que apuntaste algo,
       no lo festeja;
     · navegación en COLUMNA se corre 4 px hacia el contenido y le crece una
       barra al margen — NO sube 2 px, que es el gesto de los botones.
       Confundirlos hace que un ítem de menú se lea como algo que se dispara.
   `prefers-reduced-motion` apaga el MOVIMIENTO, no la información: los
   cambios de color y fondo quedan, y los indicadores aparecen de golpe en vez
   de crecer. Por eso no es un `transition:none` global — está al pie.
   ------------------------------------------------------------------------- */

/* ── Armazón ─────────────────────────────────────────────────────────────────
   SIN ESPACIO entre las dos clases. El div es `class="trz-ui trz-shell"`: UN
   elemento con las dos, no un `.trz-shell` adentro de un `.trz-ui`. Escrito
   con espacio (descendiente) el bloque no matchea NADA y se cae entero EN
   SILENCIO: sin `display:flex` y sin `height:100%` el módulo crece con su
   contenido dentro de un contenedor `overflow:hidden` y se queda sin scroll.
   Es el bug que le costó seis etapas al ABM. Ver §8 del manual.

   El armazón va en un DIV HIJO de `#page-lotes-azucar`, no en el
   `.page-content` mismo: así el `.hidden` de Tailwind que oculta la página
   sigue teniendo con quién pelear. (Cuando el scope va en el propio
   `.page-content`, `.trz-ui.trz-shell{display:flex}` son dos clases contra la
   una de `.hidden` y la pantalla no se oculta nunca — es lo que dejó al portal
   del cañero tapando a las demás.) */
.trz-ui.trz-shell {
    display: flex; flex-direction: column;
    height: 100%; min-height: 0;
    background: var(--canvas);
}

.trz-ui .trz-split { display: flex; align-items: stretch; flex: 1; min-height: 0; }

/* ── Rail de secciones ───────────────────────────────────────────────────────
   Seis destinos en dos grupos. Los `grupo` no son decoración: dicen de qué
   especie es cada cosa — arriba lo que se hace todos los días, abajo las dos
   definiciones que se tocan una vez por zafra y que hoy compiten de igual a
   igual con el trabajo diario en una fila de pestañas.

   OJO con las dos entradas que comparten pantalla (Lotes y Sin COA): son el
   MISMO render con otro segmento preseleccionado, no dos pantallas. Ver
   TRZ_NAV en lotes-azucar.js. */
.trz-ui .trz-rail {
    flex: 0 0 214px; min-width: 214px;
    background: var(--surface);
    border-right: 1px solid var(--hair);
    padding: 10px 10px 18px;
    overflow-y: auto; overscroll-behavior: contain;
}
.trz-ui .trz-rail .grp {
    font-size: .58rem; font-weight: 800; text-transform: uppercase; letter-spacing: .12em;
    color: var(--faint); padding: 16px 10px 6px;
}
.trz-ui .trz-rail .grp:first-child { padding-top: 4px; }

.trz-ui .trz-rail button {
    position: relative; display: flex; align-items: center; gap: 10px;
    width: 100%; padding: 8px 10px; margin-bottom: 1px;
    background: none; border: 0; border-radius: 8px;
    font: inherit; font-weight: 650; color: var(--muted); text-align: left;
    cursor: pointer;
    transition: background .14s var(--curva), color .14s var(--curva),
                transform .18s var(--curva);
}
.trz-ui .trz-rail button::before {
    content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
    border-radius: 0 3px 3px 0; background: var(--hair-strong);
    transform: scaleY(0); transform-origin: center;
    transition: transform .18s var(--curva), background .14s var(--curva);
}
.trz-ui .trz-rail button .material-symbols-outlined {
    font-size: 19px; color: var(--faint);
    transition: color .14s var(--curva);
}
/* El nombre de la sección se corta con puntos suspensivos antes que empujar
   al contador afuera: sin el min-width, el flex no lo permite. */
.trz-ui .trz-rail button .t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* El contador de la entrada. Es INFORMACIÓN, no un filtro: dice cuánto hay
   detrás, y por eso lleva el color del estado sólo cuando ese número pide algo
   (`.wrn` para lo que espera, `.neg` para lo que frena una venta).
   TODAVÍA NO LO EMITE NADIE: los números que van acá —lotes sin COA, protocolos
   faltantes— los calcula el Panel, que es una etapa más adelante. El estilo se
   deja escrito porque es vocabulario del rail, no de una pantalla; lo que no se
   deja es la función que lo pinte, para que no quede código muerto esperando. */
.trz-ui .trz-rail button .n {
    margin-left: auto; padding: 1px 6px; border-radius: 20px;
    font-size: .66rem; font-weight: 800; font-variant-numeric: tabular-nums;
    color: var(--faint); background: var(--canvas); border: 1px solid var(--hair);
    transition: color .14s var(--curva);
}
.trz-ui .trz-rail button .n.wrn { color: var(--warn); background: var(--warn-050); border-color: var(--warn-hair); }
.trz-ui .trz-rail button .n.neg { color: var(--crit); background: var(--crit-050); border-color: var(--crit-hair); }

.trz-ui .trz-rail button:hover,
.trz-ui .trz-rail button:focus-visible { background: var(--canvas); color: var(--ink); transform: translateX(4px); }
.trz-ui .trz-rail button:hover::before,
.trz-ui .trz-rail button:focus-visible::before { transform: scaleY(.55); }
.trz-ui .trz-rail button:hover .material-symbols-outlined { color: var(--azure); }

.trz-ui .trz-rail button[aria-current="page"] {
    background: var(--azure-050); color: var(--azure); font-weight: 800; transform: none;
    box-shadow: inset 0 0 0 1px rgba(22, 104, 196, .10);
}
.trz-ui .trz-rail button[aria-current="page"]::before { transform: scaleY(1); background: var(--azure); }
.trz-ui .trz-rail button[aria-current="page"] .material-symbols-outlined { color: var(--azure); }

/* ── Área de trabajo ─────────────────────────────────────────────────────────
   LO QUE ENTRA ACÁ NO SE ENCOGE. Un ítem flex cuyo `overflow` no es `visible`
   tiene mínimo automático CERO, así que una tarjeta con más contenido que
   pantalla se ACHICA hasta entrar en vez de desbordar: se ve perfecta y
   recorta, que es el peor de los casos porque no queda barra en ningún lado.
   -------------------------------------------------------------------------- */
.trz-ui .trz-work {
    flex: 1; min-width: 0; min-height: 0;
    overflow-y: auto; overscroll-behavior: contain;
    display: flex; flex-direction: column;
}
.trz-ui .trz-work > * { flex-shrink: 0; }

/* La excepción: una pantalla-TABLA, que en vez de crecer hacia abajo ocupa el
   alto entero y scrollea adentro, para que los segmentos y la barra de filtros
   queden fijos. Es (0,3,0) contra los (0,2,0) de arriba, así que gana por
   especificidad y no por orden — que es lo que hay que buscar cuando dos
   reglas se contradicen a propósito. */
.trz-ui .trz-work > .trz-lleno {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column; gap: 14px; padding: var(--gutter);
}
.trz-ui .trz-lleno > * { flex-shrink: 0; }
/* La excepción DE la excepción: la tarjeta que contiene la tabla sí se estira y
   scrollea adentro, para que los segmentos y la barra de filtros queden fijos
   arriba mientras se recorren 60 filas. Son cuatro clases (0,4,0) contra las dos
   de la regla de arriba, así que gana por ESPECIFICIDAD y no por orden — que es
   lo que hay que buscar cuando dos reglas se contradicen a propósito. */
.trz-ui .trz-lleno > .trz-card.lleno {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}

/* La pantalla que crece hacia abajo (el panel, las definiciones). */
.trz-ui .trz-col { width: 100%; padding: var(--gutter);
                   display: flex; flex-direction: column; gap: 16px; }

/* ── Encabezado de pantalla ────────────────────────────────────────────────
   El nombre de la sección lo dice la BARRA del armazón, no un título repetido.
   Esto es la bajada que explica PARA QUÉ sirve la pantalla — lo que la barra
   no tiene lugar de decir. */
.trz-ui .trz-ph h3 { margin: 0; font-size: 1.02rem; font-weight: 800; letter-spacing: -.01em; color: var(--ink); }
.trz-ui .trz-ph p { margin: 3px 0 0; font-size: .78rem; color: var(--faint); max-width: 78ch; }

/* ── Botones ─────────────────────────────────────────────────────────────── */
.trz-ui .trz-btn {
    display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
    border-radius: 8px; padding: 7px 14px;
    font: inherit; font-size: .79rem; font-weight: 700; cursor: pointer;
    border: 1px solid var(--azure); background: var(--azure); color: #fff;
    box-shadow: 0 2px 8px rgba(22, 104, 196, .24);
    transition: background .14s ease, border-color .14s ease, color .14s ease,
                box-shadow .18s var(--curva), transform .18s var(--curva);
}
.trz-ui .trz-btn .material-symbols-outlined { font-size: 17px; transition: transform .18s var(--curva); }
.trz-ui .trz-btn:hover { background: var(--azure-700); border-color: var(--azure-700);
    transform: translateY(-1px); box-shadow: 0 5px 14px rgba(22, 104, 196, .32); }
.trz-ui .trz-btn:hover .material-symbols-outlined { transform: translateY(-2px); }
.trz-ui .trz-btn:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(22, 104, 196, .24); }
.trz-ui .trz-btn:disabled { opacity: .45; cursor: default; transform: none; box-shadow: none; }

/* Secundario: en reposo es gris. Si tres secundarios llevan color, compiten
   con el primario. Al apuntarlo recupera el acento. */
.trz-ui .trz-btn.sec { background: var(--surface); color: var(--muted);
    border-color: var(--hair-strong); box-shadow: var(--e1); }
.trz-ui .trz-btn.sec:hover { background: var(--azure-050); border-color: var(--azure);
    color: var(--azure); box-shadow: 0 4px 12px rgba(16, 32, 64, .10); }

.trz-ui .trz-btn.ln { background: none; border-color: transparent; color: var(--azure);
    padding: 6px 9px; font-weight: 700; box-shadow: none; }
.trz-ui .trz-btn.ln:hover { background: var(--azure-050); box-shadow: none; transform: none; }

/* Íconos de acción: apagados en reposo, suben al apuntarlos. Blanco de clic
   chico, por eso el gesto es crecer y no desplazarse. */
.trz-ui .trz-x {
    background: none; border: 1px solid transparent; border-radius: 7px; padding: 5px 6px;
    cursor: pointer; color: var(--faint); line-height: 1;
    transition: background .14s ease, color .14s ease, border-color .14s ease;
}
.trz-ui .trz-x .material-symbols-outlined { display: block; transition: transform .18s var(--curva); }
.trz-ui .trz-x:hover { background: var(--azure-050); color: var(--azure); border-color: rgba(22, 104, 196, .18); }
.trz-ui .trz-x:hover .material-symbols-outlined { transform: translateY(-2px); }
.trz-ui .trz-x:active .material-symbols-outlined { transform: translateY(0); }
.trz-ui .trz-x.del:hover { background: var(--crit-050); color: var(--crit); border-color: var(--crit-hair); }
.trz-ui .trz-x:disabled { opacity: .4; cursor: default; }
.trz-ui .trz-x:disabled:hover { background: none; color: var(--faint); border-color: transparent; }

/* ── Tarjeta de contenido ────────────────────────────────────────────────── */
.trz-ui .trz-card {
    background: var(--surface); border-radius: var(--r-card);
    box-shadow: var(--e2); border: 1px solid rgba(16, 32, 64, .05);
    overflow: hidden;
}
/* La tarjeta de FILTROS no puede recortar: adentro va el desplegable del
   smart-selector, que es un `<ul class="absolute">` y sale de la caja. El
   `overflow:hidden` de arriba está para que la cabecera sticky de la TABLA
   respete el radio — una tarjeta sin tabla no lo necesita y el recorte le
   corta lo único que tiene que salirse. El z-index no salva de esto: el
   `overflow` del ancestro gana siempre. Estuvo en vivo en las dos bandejas de
   flete y el usuario sólo veía una raya de 11 px del desplegable. */
.trz-ui .trz-card.plano { box-shadow: var(--e1); border: 1px solid var(--hair); overflow: visible; }
.trz-ui .trz-card-h {
    padding: 11px var(--gutter); border-bottom: 1px solid var(--hair); background: #fafbfd;
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.trz-ui .trz-card-h h4 { margin: 0; font-size: .68rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .08em; color: var(--muted); }

/* ── Badges de estado ────────────────────────────────────────────────────────
   El color es del DATO y significa ESTADO, nunca categoría (§1.1). No hay un
   badge por tipo de lote ni uno por modo de COA: hay uno para "esto está bien"
   y otro para "esto hay que mirarlo". */
.trz-ui .trz-b { display: inline-flex; align-items: center; gap: 4px;
    font-size: .62rem; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
    padding: 2.5px 8px; border-radius: 5px; white-space: nowrap;
    background: var(--canvas); color: var(--faint); border: 1px solid var(--hair); }
.trz-ui .trz-b.ok  { background: var(--ok-050);   color: var(--ok);   border-color: var(--ok-hair); }
.trz-ui .trz-b.wrn { background: var(--warn-050); color: var(--warn); border-color: var(--warn-hair); }
.trz-ui .trz-b.neg { background: var(--crit-050); color: var(--crit); border-color: var(--crit-hair); }
.trz-ui .trz-b.nav { background: var(--navy-050); color: var(--navy-500); border-color: #cddcf1; }

/* ── Aviso contextual ────────────────────────────────────────────────────── */
.trz-ui .trz-risk {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 11px 14px; border-radius: 10px;
    border: 1px solid var(--hair-strong); border-left: 3px solid var(--navy-500);
    background: var(--surface); box-shadow: var(--e1); font-size: .79rem; color: var(--ink);
}
.trz-ui .trz-risk .material-symbols-outlined { flex: 0 0 auto; color: var(--navy-500); }
.trz-ui .trz-risk b { font-weight: 800; }
.trz-ui .trz-risk.alerta { border-left-color: var(--warn); background: var(--warn-050); border-color: var(--warn-hair); }
.trz-ui .trz-risk.alerta .material-symbols-outlined { color: var(--warn); }
.trz-ui .trz-risk.critico { border-left-color: var(--crit); background: var(--crit-050); border-color: var(--crit-hair); }
.trz-ui .trz-risk.critico .material-symbols-outlined { color: var(--crit); }
.trz-ui .trz-risk.nav { border-left-color: var(--navy-500); background: var(--navy-050); border-color: #cfdcef; }
.trz-ui .trz-risk.nav .material-symbols-outlined { color: var(--navy-500); }

/* ── El Panel: lo que hay que resolver hoy ───────────────────────────────────
   Es la tesis de la opción B —«la calidad es el expediente»—: el módulo AVISA en
   vez de esperar que alguien busque. Que Concepción no tenga protocolo para
   «Orgánica» se descubría adentro del modal de COA, en rojo, con el lote abierto
   y el camión esperando.

   Cada tarjeta es un PENDIENTE, no un KPI: tiene una cifra, la consecuencia
   escrita en palabras, y a dónde ir. Una tarjeta sin a-dónde-ir sería un cartel.
   El acento lateral lleva el nivel; el fondo NO se tiñe, porque cuatro tarjetas
   teñidas se leen como cuatro alarmas y dejan de significar. */
.trz-ui .trz-pend { display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(238px, 1fr)); }

.trz-ui .trz-pcard {
    /* El mínimo automático de un ítem de grid es `auto`, o sea su ancho de
       CONTENIDO mínimo y no cero: sin esto, una tarjeta con un código de lote
       largo en el texto no puede bajar de lo que mide esa palabra y empuja a la
       fila entera. Es la misma trampa del `min-height: auto` de flex, por la
       otra punta.

       OJO, Y VALE ESCRIBIRLO: esta línea NO es la que arregló el desborde que
       mostró la primera foto. Ahí las cuatro tarjetas se salían de la pantalla y
       el culpable era el BANCO, que medía sin `box-sizing: border-box` —en la
       app lo pone el preflight de Tailwind—, así que todo lo que combinaba
       `width:100%` con padding medía 44 px de más. El banco ya lo declara. Se
       deja igual porque el caso del texto largo es real, pero atribuirle un
       arreglo que no hizo es como el `min-height: 0` inerte del portal: un
       comentario falso que el próximo lector va a creer. */
    min-width: 0;
    display: flex; flex-direction: column; gap: 6px; text-align: left;
    background: var(--surface); border-radius: var(--r-card); padding: 13px 15px;
    box-shadow: var(--e2); border: 1px solid rgba(16, 32, 64, .05);
    border-left: 3px solid var(--hair-strong);
    font: inherit; cursor: pointer;
    transition: transform .18s var(--curva), box-shadow .18s var(--curva);
}
.trz-ui .trz-pcard:hover,
.trz-ui .trz-pcard:focus-visible { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(16, 32, 64, .13); }
.trz-ui .trz-pcard:active { transform: translateY(0); }
.trz-ui .trz-pcard .k { font-size: .6rem; font-weight: 800; letter-spacing: .1em;
    text-transform: uppercase; color: var(--faint); }
.trz-ui .trz-pcard .v { font-size: 1.62rem; font-weight: 800; letter-spacing: -.03em;
    line-height: 1; font-variant-numeric: tabular-nums; }
.trz-ui .trz-pcard .x { font-size: .755rem; color: var(--muted); }
.trz-ui .trz-pcard .x b { color: var(--ink); font-weight: 700; }
/* El link va al pie y pegado abajo: con tarjetas de alto distinto, los cuatro
   quedan alineados igual. */
.trz-ui .trz-pcard .go { margin-top: auto; padding-top: 4px;
    font-size: .735rem; font-weight: 800; color: var(--azure); }
.trz-ui .trz-pcard.wrn { border-left-color: var(--warn); } .trz-ui .trz-pcard.wrn .v { color: var(--warn); }
.trz-ui .trz-pcard.neg { border-left-color: var(--crit); } .trz-ui .trz-pcard.neg .v { color: var(--crit); }
.trz-ui .trz-pcard.ok  { border-left-color: var(--ok); }   .trz-ui .trz-pcard.ok .v  { color: var(--ok); }

/* ── Segmentos ───────────────────────────────────────────────────────────────
   El estado de un lote era un `<select>` de tres opciones y la Bandeja COAs era
   una PESTAÑA. Son lo mismo: la misma fila, las mismas columnas, la misma acción
   de fila, y lo único que cambia es qué subconjunto se mira. Eso es un filtro, y
   un filtro con cinco valores que se alternan todo el día va como segmento, no
   escondido adentro de un desplegable.

   Subrayado que crece, NUNCA una píldora rellena (§1.2): cuatro segmentos
   macizos le ganarían al único botón que puede pintarse. El contador va al lado
   y lleva el color del ESTADO sólo cuando ese número pide algo. */
.trz-ui .trz-seg { display: flex; gap: 2px; flex-wrap: wrap;
    border-bottom: 1px solid var(--hair); padding: 0 var(--gutter); }
.trz-ui .trz-seg button {
    position: relative; display: inline-flex; align-items: center; gap: 7px;
    font: inherit; font-size: .815rem; font-weight: 700; color: var(--muted);
    background: none; border: 0; padding: 11px 14px 12px; cursor: pointer;
    transition: color .14s ease, background .14s ease;
}
/* El subrayado es un ::after con scaleX y no un border-bottom: un borde no se
   puede animar, y al sacarlo habría que compensar el alto o los segmentos
   saltan. Crece desde el centro. */
.trz-ui .trz-seg button::after {
    content: ''; position: absolute; left: 10px; right: 10px; bottom: 0; height: 2.5px;
    border-radius: 2px 2px 0 0; background: var(--azure);
    transform: scaleX(0); transform-origin: center;
    transition: transform .18s var(--curva);
}
.trz-ui .trz-seg button:hover,
.trz-ui .trz-seg button:focus-visible { color: var(--ink); background: var(--azure-050); }
.trz-ui .trz-seg button:hover::after { transform: scaleX(.5); }
.trz-ui .trz-seg button[aria-pressed="true"] { color: var(--azure); font-weight: 800; }
.trz-ui .trz-seg button[aria-pressed="true"]::after { transform: scaleX(1); }

.trz-ui .trz-seg .n {
    font-size: .66rem; font-weight: 800; font-variant-numeric: tabular-nums;
    padding: 1px 7px; border-radius: 20px;
    color: var(--faint); background: var(--canvas); border: 1px solid var(--hair);
}
.trz-ui .trz-seg .n.wrn { color: var(--warn); background: var(--warn-050); border-color: var(--warn-hair); }
.trz-ui .trz-seg .n.neg { color: var(--crit); background: var(--crit-050); border-color: var(--crit-hair); }
/* El contador que todavía no se sabe. NO se dibuja un cero: un cero afirma que
   no hay nada, y "no lo conté" no es "no hay". */
.trz-ui .trz-seg .n.pend { color: var(--hair-strong); }

/* ── Barra de filtros ────────────────────────────────────────────────────── */
.trz-ui .trz-bar { display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
    padding: 12px var(--gutter); border-bottom: 1px solid var(--hair); }
.trz-ui .trz-hint { margin-left: auto; font-size: .72rem; font-weight: 600; color: var(--faint); }
.trz-ui .trz-hint b { color: var(--ink); font-variant-numeric: tabular-nums; }

.trz-ui .trz-in {
    border: 1px solid var(--hair-strong); border-radius: 8px; padding: 7px 11px;
    font: inherit; font-size: .82rem; color: var(--ink); background: var(--surface); outline: none;
    transition: border-color .14s ease, box-shadow .18s var(--curva);
}
.trz-ui .trz-in:focus { border-color: var(--azure); box-shadow: 0 0 0 3px rgba(22, 104, 196, .14); }
.trz-ui select.trz-in { cursor: pointer; min-width: 150px; }

/* EL BUSCADOR CON ÁMBITO. Eran TRES puertas para «encontrar un lote»: un input
   que según lo que tipearas disparaba una range-query sobre todo el histórico
   —ignorando en silencio tipo, estado, depósito y artículo— o filtraba en
   memoria sobre la ventana paginada; y al lado un modal aparte contra
   `movimientos`. Ahora es una sola, y DICE cuál está abierta: el ámbito es un
   `<select>` pegado al campo, no una heurística sobre el texto. */
.trz-ui .trz-search {
    display: flex; align-items: stretch; flex: 1; min-width: 300px; max-width: 560px;
    border: 1px solid var(--hair-strong); border-radius: 8px; background: var(--surface);
    transition: border-color .14s ease, box-shadow .18s var(--curva);
}
.trz-ui .trz-search:focus-within { border-color: var(--azure); box-shadow: 0 0 0 3px rgba(22, 104, 196, .14); }
.trz-ui .trz-search select {
    font: inherit; font-size: .72rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
    color: var(--azure); background: var(--azure-050);
    border: 0; border-right: 1px solid var(--hair); border-radius: 7px 0 0 7px;
    padding: 0 8px; cursor: pointer; outline: none;
}
.trz-ui .trz-search .material-symbols-outlined { align-self: center; padding-left: 9px; color: var(--faint); }
.trz-ui .trz-search input {
    flex: 1; min-width: 0; font: inherit; font-size: .82rem; color: var(--ink);
    background: none; border: 0; outline: none; padding: 8px 11px;
}

/* ── Tabla ───────────────────────────────────────────────────────────────────
   La tarjeta que la contiene lleva `overflow:hidden` para que la cabecera
   pegada respete el radio; por eso el scroll horizontal va en este envoltorio
   y no en la tarjeta. */
.trz-ui .trz-tbl { overflow: auto; flex: 1; min-height: 0; }
.trz-ui table.trz-g { width: 100%; border-collapse: collapse; background: var(--surface); }
.trz-ui table.trz-g th {
    position: sticky; top: 0; z-index: 1;
    background: var(--surface); color: var(--muted);
    font-size: .6rem; text-transform: uppercase; letter-spacing: .1em; font-weight: 800;
    text-align: left; padding: 10px 12px; white-space: nowrap;
    /* Regla gruesa, como un informe impreso — nunca una franja navy de ancho
       completo: es la mayor fuente de fatiga en una tabla que se mira 20
       minutos seguidos (§1.2). */
    border-bottom: 2px solid var(--ink);
}
.trz-ui table.trz-g td { padding: 10px 12px; border-bottom: 1px solid var(--hair);
    white-space: nowrap; vertical-align: middle; }
.trz-ui table.trz-g th.n, .trz-ui table.trz-g td.n { text-align: right; }
/* UNA CELDA APAGADA, y existe porque la foto de la etapa 5 mostró lo que pasa
   sin ella: para poner en gris una celda entera se le habia escrito la clase
   `.trz-sub`, que es `display:block`. Un `<td>` en block deja de ser celda —se
   sale de la grilla de la tabla, se lleva el ancho de la columna puesto y las
   de al lado se corren—. Se veia como un recuadro flotando adentro de la fila.
   El renglon chico de abajo de un dato sigue siendo `.trz-sub`; el color de una
   celda es esto. */
.trz-ui table.trz-g td.mut { color: var(--faint); }
.trz-ui table.trz-g th.c, .trz-ui table.trz-g td.c { text-align: center; }
.trz-ui table.trz-g td:first-child { border-left: 3px solid transparent; padding-left: calc(var(--gutter) - 3px); }
.trz-ui table.trz-g th:first-child { padding-left: var(--gutter); }
.trz-ui table.trz-g th:last-child, .trz-ui table.trz-g td:last-child { padding-right: var(--gutter); }
.trz-ui table.trz-g tbody tr { transition: background .14s ease; cursor: pointer; }
.trz-ui table.trz-g tbody tr:nth-child(even) { background: #fafbfd; }
.trz-ui table.trz-g tbody tr:hover { background: var(--azure-050); }
.trz-ui table.trz-g tbody tr:last-child td { border-bottom: 0; }

/* Estado de fila: franja de 3 px al margen izquierdo, no una pastilla en su
   columna. Las dos se encuentran igual de rápido, pero la franja no compite con
   el dato y libera la columna de estado para que diga QUÉ pasa. */
.trz-ui table.trz-g tr.st-wrn td:first-child { border-left-color: var(--warn); }
.trz-ui table.trz-g tr.st-neg td:first-child { border-left-color: var(--crit); }
.trz-ui table.trz-g tr.apagada td { color: var(--muted); }

.trz-ui .mono { font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace; font-variant-numeric: tabular-nums; }
.trz-ui .trz-cod { font-weight: 800; font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace; color: var(--navy); }
/* Dato principal con su renglón de contexto abajo, en una sola celda. */
.trz-ui .trz-sub { display: block; font-size: .65rem; font-weight: 600; color: var(--faint); margin-top: 1px; }
.trz-ui .trz-sub.wrn { color: var(--warn); }
.trz-ui .trz-sub.neg { color: var(--crit); }
/* Un dato ausente se escribe, no se deja en blanco (§1.4). */
.trz-ui .trz-aus { color: var(--faint); font-style: italic; }

/* Pie de la tabla: cuántos hay, cuánto se leyó, y "cargar más". */
.trz-ui .trz-pie { padding: 11px var(--gutter); border-top: 1px solid var(--hair); background: #fafbfd;
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    font-size: .72rem; color: var(--faint); }
.trz-ui .trz-pie b { color: var(--ink); font-variant-numeric: tabular-nums; }
.trz-ui .trz-pie .trz-btn { margin-left: auto; }

/* ── La tira del ámbito DOCUMENTO ────────────────────────────────────────────
   Buscar por MW / remito / factura devuelve LOTES —la misma especie de fila que
   la tabla—, pero el documento que los trajo es información que no entra en
   ninguna columna sin mentir: los kg de un lote EN ESE MOVIMIENTO no son los kg
   del lote. Así que el documento vive acá arriba y la tabla sigue siendo de
   lotes. Una columna que sirve a dos especies no puede tener un encabezado
   honesto. */
.trz-ui .trz-doc { display: flex; flex-direction: column; gap: 8px;
    padding: 12px var(--gutter); border-bottom: 1px solid var(--hair); background: var(--navy-050); }
.trz-ui .trz-doc .mw { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: .76rem; }
.trz-ui .trz-doc .mw .id { font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-weight: 800; color: var(--navy); }
.trz-ui .trz-doc .mw .x { color: var(--muted); }

/* ── Vacío y espera ──────────────────────────────────────────────────────── */
.trz-ui .trz-ph-vacio { padding: 46px 20px; text-align: center; color: var(--muted); }
.trz-ui .trz-ph-vacio .material-symbols-outlined { font-size: 38px; color: var(--hair-strong); display: block; margin: 0 auto 8px; }
.trz-ui .trz-ph-vacio b { display: block; font-size: .88rem; color: var(--ink); margin-bottom: 3px; }
.trz-ui .trz-ph-vacio span { font-size: .78rem; }

/* EL ANILLO NO ES DE ESTE MÓDULO Y SE FUE — etapa 6.
   Acá vivía `.trz-spin`: quince píxeles, borde de 2, `border-top-color: azure`
   y su propio `@keyframes trzSpin`. O sea la MISMA pieza que `.gs-spin` de
   core/tokens.css, escrita una cuarta vez —el ABM tenía `.abm-spin`, la puerta
   `.acc-spin`, y las tres se unificaron el 04/08/2026 cuando se decidió el
   sistema de espera (identidad-visual.md §5)—.

   Sus dieciséis usos eran todos el mismo gesto: pisar el `innerHTML` de un
   botón mientras se guarda. Eso ahora lo hace `gsEsperando(btn, 'Guardando…')`,
   que además devuelve el `fin()` que restaura la etiqueta — y de los dieciséis,
   TRES no tenían `finally`: un camino de error los dejaba apagados y con el
   texto de espera hasta recargar la página.

   El arco de `.gs-spin` es `currentColor`, así que sobre un botón navy sale
   blanco y sobre uno fantasma sale azure, sin declarar nada. */

/* ═══════════════════════════════════════════════════════════════════════════
   LA FICHA DEL LOTE — el modal en dos paneles (etapa 4a)
   ═══════════════════════════════════════════════════════════════════════════
   Sigue siendo un MODAL y no una pantalla del rail, a propósito: la ficha se
   abre desde una fila y se vuelve a la lista donde estabas, la historia
   encadena lote → lote llamando otra vez a la misma función, y dos consumidores
   de AFUERA la abren directo (el deep-link de `main.js` y `verLoteDesdeMov()`
   de movimientos-detalle.js). Como pantalla, las tres cosas necesitarían
   plomería de vuelta-atrás que hoy no existe.

   Los DOS PANELES son la tesis de la etapa: identidad y calidad a la
   izquierda, el viaje del lote a la derecha. Antes todo se apilaba en una
   columna y para cruzar el certificado con el recorrido —que es lo único que
   uno hace mirando un lote— había que scrollear entre los dos. */

.trz-ui.trz-modal {
    position: fixed; inset: 0; z-index: 70;
    display: flex; align-items: center; justify-content: center; padding: 20px;
    background: rgba(10, 25, 60, .55);
}
/* La regla de arriba y `.trz-ui.trz-modal.hidden{display:none}` (arriba de
   todo) son un par: `display:flex` con DOS clases le gana al `.hidden` de
   Tailwind, que tiene una. Sin la de ocultar, el modal no se cierra nunca. */

.trz-ui .trz-dlg {
    background: var(--surface); border-radius: var(--r-card); box-shadow: var(--e3);
    width: 100%; max-width: 1120px; max-height: 92vh;
    display: flex; flex-direction: column; overflow: hidden;
}

/* ── La cabecera: quién es este lote y qué PAPELES emite ─────────────────────
   Acá van sólo las acciones que producen un documento (recall, ejercicio,
   reporte, etiqueta). Las que MUEVEN mercadería viven en el pie, separadas: un
   botón que imprime y un botón que parte un lote no pueden pesar lo mismo.
   Todas en fantasma sobre navy y ninguna maciza de color — el peligro de una
   acción se comunica en su diálogo, no pintando el botón que lo abre. */
.trz-ui .trz-dlg-h {
    background: var(--navy); color: #fff; padding: 11px 18px;
    display: flex; align-items: center; gap: 9px; flex-wrap: wrap; flex-shrink: 0;
}
.trz-ui .trz-dlg-h .cod {
    font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-weight: 800; font-size: .96rem; letter-spacing: -.01em;
}
.trz-ui .trz-dlg-h .trz-b {
    background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .24); color: #dce9fb;
}
/* Las tres que SÍ dicen bien o mal conservan su semántica sobre el navy: se
   sube la luminosidad del texto para que se lean sobre el fondo oscuro. */
.trz-ui .trz-dlg-h .trz-b.ok  { background: rgba(93, 210, 162, .17); border-color: rgba(93, 210, 162, .34); color: #9ce8c8; }
.trz-ui .trz-dlg-h .trz-b.wrn { background: rgba(240, 178, 96, .17); border-color: rgba(240, 178, 96, .34); color: #f6cf9a; }
.trz-ui .trz-dlg-h .trz-b.neg { background: rgba(240, 138, 138, .17); border-color: rgba(240, 138, 138, .36); color: #f7b4b4; }
.trz-ui .trz-dlg-h .acts { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.trz-ui .trz-dlg-h .trz-btn {
    background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .2);
    color: #fff; box-shadow: none; padding: 6px 11px; font-size: .72rem;
}
.trz-ui .trz-dlg-h .trz-btn:hover { background: rgba(255, 255, 255, .22); border-color: rgba(255, 255, 255, .34); box-shadow: none; }
.trz-ui .trz-dlg-h .trz-x { color: #b9cdea; }
.trz-ui .trz-dlg-h .trz-x:hover { background: rgba(255, 255, 255, .14); color: #fff; border-color: transparent; }
/* El ✎ del código: pertenece al DATO, no a la barra de acciones. */
.trz-ui .trz-dlg-h .lapiz {
    background: none; border: 0; padding: 2px; cursor: pointer; color: rgba(255, 255, 255, .55);
    border-radius: 5px; transition: color .14s ease, background .14s ease;
}
.trz-ui .trz-dlg-h .lapiz:hover { color: #fff; background: rgba(255, 255, 255, .14); }
.trz-ui .trz-dlg-h .lapiz .material-symbols-outlined { font-size: 15px; display: block; }

/* ── Los dos paneles ─────────────────────────────────────────────────────────
   `min-height: 0` EN LA GRILLA, y ahí está el peso: `.trz-ficha` es un ítem
   flex de `.trz-dlg` y su `overflow` es `visible`, así que sin esto su mínimo
   automático es el del contenido y la grilla crece hasta pasarse del
   `max-height` del diálogo. Como `.trz-dlg` recorta, lo que sobra no se
   scrollea: desaparece.

   Y NO se le escribe `min-height:0` a los dos paneles, aunque parezca la misma
   precaución: un ítem de grilla con `overflow` distinto de `visible` YA tiene
   mínimo automático cero por especificación. Ahí la línea sería inerte —se
   leería como que protege algo y no protegería nada— y un `--romperlo` que se
   la quitara daría verde. La que hay que poder romper es la de arriba.

   La fila se deja en `auto` y no se escribe `grid-template-rows: minmax(0,1fr)`:
   probado quitándolo, el banco queda VERDE igual —la fila automática de una
   grilla de alto definido ya se estira por `align-content: stretch`—, así que
   sería otra línea que se lee como que sostiene algo y no sostiene nada. */
.trz-ui .trz-ficha {
    display: grid; grid-template-columns: 1.15fr .85fr;
    flex: 1; min-height: 0;
}
.trz-ui .trz-ficha > section { overflow-y: auto; padding: 16px var(--gutter) 20px; }
.trz-ui .trz-ficha > .izq { border-right: 1px solid var(--hair); }
.trz-ui .trz-ficha > .der { background: var(--canvas); }

/* Ventana angosta: se apilan y el que scrollea pasa a ser la grilla entera. Si
   los paneles siguieran scrolleando cada uno, quedarían dos barras cortitas una
   arriba de la otra. */
@media (max-width: 900px) {
    .trz-ui .trz-ficha { grid-template-columns: 1fr; grid-template-rows: auto auto; overflow-y: auto; }
    .trz-ui .trz-ficha > section { overflow-y: visible; }
    .trz-ui .trz-ficha > .izq { border-right: 0; border-bottom: 1px solid var(--hair); }
}

/* ── El pie: lo que MUEVE mercadería ─────────────────────────────────────────
   Separado de la cabecera a propósito. Arriba se emite un papel; acá se parte
   un lote, se lo suma a una estiba o se cierra una estiba. Mezclarlos hacía que
   «Imprimir reporte» y «Partir / Trasladar» se leyeran como la misma clase de
   cosa. Si el lote no admite ninguna, el pie no se dibuja. */
.trz-ui .trz-dlg-f {
    flex-shrink: 0; padding: 11px var(--gutter); border-top: 1px solid var(--hair);
    background: #fafbfd; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.trz-ui .trz-dlg-f .nota { margin-left: auto; font-size: .72rem; color: var(--faint); }

/* ── Bloques adentro de un panel ─────────────────────────────────────────── */
.trz-ui .trz-blk { margin-top: 18px; }
.trz-ui .trz-blk.primero { margin-top: 0; }
.trz-ui .trz-blk > h5 {
    margin: 0 0 8px; font-size: .66rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint);
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.trz-ui .trz-blk > h5 .cuenta { margin-left: auto; font-weight: 700; letter-spacing: 0;
    text-transform: none; font-size: .7rem; }

/* Los datos de identidad. Tres columnas: con dos, once datos hacen una columna
   larguísima y el bloque de calidad se va abajo del pliegue. */
.trz-ui .trz-dl { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px 14px; }
@media (max-width: 1100px) { .trz-ui .trz-dl { grid-template-columns: repeat(2, 1fr); } }
.trz-ui .trz-dl .k { font-size: .6rem; font-weight: 800; letter-spacing: .1em;
    text-transform: uppercase; color: var(--faint); display: flex; align-items: center; gap: 4px; }
.trz-ui .trz-dl .v { font-size: .82rem; font-weight: 600; color: var(--ink); margin-top: 1px; }

/* ── El COA contra el standard PACTADO ───────────────────────────────────────
   El patrón «real contra lo pactado» del manual. Antes los seis fisicoquímicos
   se imprimían sueltos y el que miraba tenía que acordarse de memoria del
   límite de ese ingenio para esa zafra. Ahora cada uno trae su pactado abajo y,
   cuando se lo puede juzgar, se marca el que queda afuera.

   El color es del DATO: sólo se tiñe el que está fuera de spec. Los que
   cumplen no se pintan de verde — seis verdes serían decoración y el único que
   importa se perdería entre ellos. */
.trz-ui .trz-coa { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
@media (max-width: 1100px) { .trz-ui .trz-coa { grid-template-columns: repeat(2, 1fr); } }
.trz-ui .trz-coa .p {
    background: var(--canvas); border: 1px solid var(--hair); border-radius: 8px; padding: 7px 9px;
}
.trz-ui .trz-coa .p .k { font-size: .58rem; font-weight: 800; letter-spacing: .08em;
    text-transform: uppercase; color: var(--faint); }
.trz-ui .trz-coa .p .v { font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-variant-numeric: tabular-nums; font-size: .8rem; font-weight: 700; color: var(--ink); }
.trz-ui .trz-coa .p .pac { font-size: .64rem; color: var(--faint); margin-top: 1px; }
.trz-ui .trz-coa .p.afuera { background: var(--crit-050); border-color: var(--crit-hair); }
.trz-ui .trz-coa .p.afuera .v { color: var(--crit); }
.trz-ui .trz-coa .p.afuera .pac { color: var(--crit); font-weight: 700; }
/* Sin pactado que comparar: se dice, y NO se da por bueno. */
.trz-ui .trz-coa .p.sinjuicio .pac { font-style: italic; }

/* ── La historia del lote ────────────────────────────────────────────────────
   SIN COLOR POR ESPECIE. La versión anterior tenía seis familias (esmeralda
   creación, rosa despacho, cian pase, violeta cesión, ámbar estiba, gris el
   resto) y eso es color = categoría, que es justo lo que el diagnóstico del
   módulo le reprochaba al resto de la pantalla: un despacho no está peor que un
   ingreso.

   Lo que distingue un evento de otro es el ÍCONO, que es para lo que sirve un
   ícono; y lo que dice para qué lado fue el kilaje es el punto: RELLENO si el
   lote sumó, HUECO si entregó. Es una diferencia de forma, no de tinte, así que
   no compite con los tres colores que en este módulo significan algo.

   OJO: `ev.color` sigue viviendo en el DATO del evento aunque la pantalla ya no
   lo use. Lo lee `lote-reporte.js` para el imprimible, que queda fuera de esta
   migración a propósito (es papel, no pantalla): sacarlo del constructor
   dejaría el reporte en gris sin que nada avise. */
.trz-ui .trz-tl { display: flex; flex-direction: column; }
.trz-ui .trz-tl .ev {
    display: flex; gap: 10px; padding: 9px 0; border-bottom: 1px dashed var(--hair);
}
.trz-ui .trz-tl .ev:last-child { border-bottom: 0; }
.trz-ui .trz-tl .ev .dot {
    flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%; margin-top: 1px;
    display: flex; align-items: center; justify-content: center;
    background: var(--navy); color: #fff;
}
.trz-ui .trz-tl .ev .dot .material-symbols-outlined { font-size: 15px; }
/* Hueco = el lote entregó kilos. Relleno = los recibió. */
.trz-ui .trz-tl .ev.sale .dot { background: var(--surface); color: var(--navy);
    box-shadow: inset 0 0 0 1.5px var(--navy-300); }
.trz-ui .trz-tl .ev .cuerpo { min-width: 0; flex: 1; }
.trz-ui .trz-tl .ev .t { font-size: .79rem; font-weight: 700; color: var(--ink); }
.trz-ui .trz-tl .ev .s { font-size: .7rem; color: var(--faint); }
.trz-ui .trz-tl .ev .kg { margin-left: auto; text-align: right; white-space: nowrap;
    font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-variant-numeric: tabular-nums; font-size: .76rem; font-weight: 700; color: var(--ink); }
.trz-ui .trz-tl .ev .kg .d { display: block; font-size: .65rem; color: var(--faint); font-weight: 500;
    font-family: 'Segoe UI', -apple-system, system-ui, Roboto, Arial, sans-serif; }
.trz-ui .trz-tl .ev .ver {
    background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
    font-size: .68rem; font-weight: 800; color: var(--azure);
    transition: color .14s ease;
}
.trz-ui .trz-tl .ev .ver:hover { color: var(--azure-700); text-decoration: underline; }

/* Tabla chica de adentro de un panel (la composición de una estiba). */
.trz-ui table.trz-mini { width: 100%; border-collapse: collapse; font-size: .74rem;
    background: var(--surface); border: 1px solid var(--hair); border-radius: 8px; overflow: hidden; }
.trz-ui table.trz-mini th { text-align: left; font-size: .58rem; font-weight: 800;
    letter-spacing: .08em; text-transform: uppercase; color: var(--faint);
    padding: 6px 9px; border-bottom: 1px solid var(--hair); }
.trz-ui table.trz-mini td { padding: 6px 9px; border-bottom: 1px solid var(--hair); }
.trz-ui table.trz-mini tr:last-child td { border-bottom: 0; }
.trz-ui table.trz-mini th.n, .trz-ui table.trz-mini td.n { text-align: right; }

/* ═══════════════════════════════════════════════════════════════════════════
   LOS DIÁLOGOS SATÉLITE DE LA FICHA (etapa 4b)
   ═══════════════════════════════════════════════════════════════════════════
   Cinco: Partir/Trasladar, Sumar a estiba, Editar formato, Editar código y
   Editar datos de origen. Los cinco salen de la ficha y los cinco vuelven a
   ella, así que hablan su vocabulario: el MISMO `.trz-dlg` con el mismo navy
   arriba y el mismo pie, en su versión angosta.

   VENÍAN CON CINCO COLORES —cian «partir», ámbar «estiba», índigo «formato»,
   rosa «código» y un `#002B6B` tipeado a mano tres veces para «origen»—, que
   es color = categoría: decían de qué modal se trataba, o sea lo mismo que el
   título, y no si algo estaba bien o mal. El único color que queda es el del
   dato: el eco de kg y el aviso crítico del código.

   LA CAPA SE DECLARA ACÁ, UNA VEZ. Antes eran `z-[80]` y `z-[85]` tipeados en
   cinco lugares contra el `z-index: 70` de `.trz-modal`, que está escrito en
   otro archivo: tres niveles de apilamiento (pantalla → ficha → satélite) y
   ninguno de los tres en un solo lado. */
.trz-ui.trz-modal.sat { z-index: 80; }

/* Angosto a propósito. Estos diálogos tienen entre dos y cinco campos: con el
   ancho de la ficha (1120) quedarían tres cuartos de aire y una columna de
   campos flaquita contra el borde izquierdo. */
.trz-ui .trz-dlg.chico { max-width: 472px; }
/* El título de un diálogo que no es la ficha. Va sin `.chico` en el selector
   porque desde la etapa 5 hay tres anchos (chico / medio / el de la ficha) y el
   título se escribe igual en los tres: la única que tiene `.cod` en vez de
   `.tt` es la ficha, que habla de UN lote y lo dice con su código. */
.trz-ui .trz-dlg-h .tt {
    display: flex; align-items: center; gap: 8px;
    font-size: .86rem; font-weight: 800; letter-spacing: -.01em;
}
.trz-ui .trz-dlg-b {
    padding: 18px var(--gutter); overflow-y: auto; min-height: 0;
    display: flex; flex-direction: column; gap: 14px;
}

/* EL SUJETO: de qué lote habla el diálogo. Tres de los cinco lo traían, con
   tres marcados distintos, y dos no lo traían: «Corregir código» mostraba el
   código actual como un dato más de la lista, y el que abría «Partir» desde la
   ficha veía el suyo sólo adentro de un párrafo cian. Un diálogo que cambia el
   saldo o la identidad de un lote dice de cuál habla, siempre y en el mismo
   lugar. */
.trz-ui .trz-suj {
    background: var(--navy-050); border: 1px solid #dbe6f6; border-radius: 10px; padding: 9px 12px;
}
.trz-ui .trz-suj .k { font-size: .58rem; font-weight: 800; letter-spacing: .1em;
    text-transform: uppercase; color: var(--faint); }
.trz-ui .trz-suj .cod { font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-weight: 800; font-size: .82rem; color: var(--navy); margin-top: 1px; }
.trz-ui .trz-suj .x { font-size: .74rem; color: var(--muted); margin-top: 2px; }
.trz-ui .trz-suj .x b { color: var(--ink); font-weight: 700; }

/* Un campo: rótulo arriba, control abajo, y el eco debajo del control. */
.trz-ui .trz-campo .lbl {
    display: flex; align-items: baseline; gap: 8px;
    font-size: .6rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
    color: var(--faint); margin-bottom: 4px;
}
/* El atajo del rótulo («usar el saldo completo»). Va acá y no abajo con los
   botones: pertenece al CAMPO, no al diálogo. */
.trz-ui .trz-campo .lbl .trz-btn.ln { margin-left: auto; padding: 0; font-size: .66rem;
    letter-spacing: 0; text-transform: none; }
.trz-ui .trz-campo .trz-in { width: 100%; }
/* UN CAMPO QUE NO SE USA TIENE QUE VERSE ASÍ, y lo mostró la foto: «Partir»
   deshabilita «Código del lote hijo» cuando el traslado va a ser completo, y
   sin esta regla el campo quedaba idéntico a uno editable — con el eco de
   abajo diciendo que no se usa y el campo invitando a escribirlo igual. */
.trz-ui .trz-campo .trz-in:disabled {
    background: var(--canvas); color: var(--faint); border-style: dashed; cursor: not-allowed;
}
.trz-ui .trz-campo textarea.trz-in { resize: vertical; min-height: 54px; }
.trz-ui .trz-campo .fijo { font-family: 'Consolas', 'SF Mono', 'Roboto Mono', monospace;
    font-weight: 700; font-size: .84rem; color: var(--ink); }

/* EL ECO: lo que va a pasar con lo que acabás de escribir, mientras lo
   escribís. «Sumar a estiba» ya lo tenía y «Partir» no, con el mismo cálculo
   contra el mismo saldo: uno avisaba antes y el otro después de apretar
   Confirmar. Es el único lugar del diálogo donde el color significa algo, y
   significa lo de siempre — ok / alerta / crítico. */
/* EL ECO VA EN BLOCK, NO EN FLEX, y lo mostró la foto. Con `display:flex` cada
   hijo directo pasa a ser un ítem: el `<b>` de los kg —que es parte de la
   frase— se convertía en una caja aparte, se iba contra el margen derecho y
   dejaba el punto final huérfano en el renglón de al lado. Un texto con
   énfasis adentro se maqueta como texto; el ícono va inline y alcanza. */
.trz-ui .trz-eco { display: block; margin-top: 5px;
    font-size: .73rem; line-height: 1.45; color: var(--muted); }
.trz-ui .trz-eco .material-symbols-outlined { font-size: 14px; vertical-align: -2px; margin-right: 3px; }
.trz-ui .trz-eco b { font-weight: 800; }
.trz-ui .trz-eco.ok  { color: var(--ok); }
.trz-ui .trz-eco.wrn { color: var(--warn); }
.trz-ui .trz-eco.neg { color: var(--crit); }
/* Sin nada que decir todavía: NO se colapsa la altura. Si el renglón
   apareciera y desapareciera, el botón de confirmar saltaría mientras el
   operario tipea los kg. */
.trz-ui .trz-eco:empty::before { content: '\00a0'; }

/* El pie del diálogo chico: la nota ARRIBA, en su propio renglón, y los dos
   botones abajo a la derecha.

   Empezó con los tres en una fila —nota a la izquierda, botones a la derecha—
   y lo tumbó la foto: en 472 px de ancho no entran, y el que se caía al
   renglón de abajo era el botón PRIMARIO, que quedaba solo y desalineado
   debajo de «Cancelar». Y se caía sólo a veces, porque la etiqueta del
   primario cambia con la operación («Trasladar» / «Partir el lote» / «Mudar el
   lote»): el pie se rompía al tipear los kg.

   `flex: 1 1 100%` sobre la nota la manda a su propio renglón siempre, así el
   ancho de las etiquetas deja de decidir el layout. */
.trz-ui .trz-dlg.chico .trz-dlg-f,
.trz-ui .trz-dlg.medio .trz-dlg-f { justify-content: flex-end; }
.trz-ui .trz-dlg.chico .trz-dlg-f .nota,
.trz-ui .trz-dlg.medio .trz-dlg-f .nota { flex: 1 1 100%; margin: 0 0 2px; }

/* ── LA TIRA DE ERROR (etapa 6) ──────────────────────────────────────────────
   Lo que se arregla SIN SALIR del diálogo se dice adentro del diálogo.

   Los quince que viven acá eran `alert()`: «Elegí una estiba destino», «Indicá
   los kg a trasladar», «El nombre es obligatorio». Un cartel del sistema para
   cada uno significaba una TERCERA capa —velo del sistema sobre el satélite
   sobre la ficha— para corregir un campo que está a tres centímetros; y en
   «Partir», que valida cuatro cosas seguidas, significaba hasta cuatro carteles
   encadenados, uno por vez, apareciendo cada vez que se apretaba Confirmar.

   Ahora la tira los muestra TODOS JUNTOS, marca los campos que fallaron y se
   va sola en cuanto uno de ellos cambia. El modal del sistema queda para lo que
   de verdad corta el trabajo: un error del servidor, un permiso, una
   confirmación destructiva.

   NO ES UNA INVENCIÓN: `pedir()` de core/dialogos.js ya hace exactamente esto
   con su `.gs-dlg-err` desde que nació. Lo que hace la etapa 6 es extenderlo a
   los diálogos propios del módulo, que no pasan por `pedir()` porque tienen
   selects, ecos y atajos que `pedir()` no sabe dibujar (ver la ronda de la 4b:
   ganó la A justamente por eso).

   VA ENTRE EL CUERPO Y EL PIE, no adentro del cuerpo: el cuerpo scrollea
   (`.trz-dlg-b` tiene `overflow-y:auto`) y un error que se puede ir de la
   pantalla scrolleando no es un error, es una nota al pie. Acá queda pegado al
   botón que lo disparó, que es el único lugar donde se lo mira. */
.trz-ui .trz-err {
    flex-shrink: 0;
    display: flex; gap: 9px; align-items: flex-start;
    padding: 9px var(--gutter);
    background: var(--crit-050); border-top: 1px solid var(--crit-hair);
    font-size: .755rem; line-height: 1.45;
}
.trz-ui .trz-err[hidden] { display: none; }
.trz-ui .trz-err > .material-symbols-outlined {
    font-size: 17px; color: var(--crit); flex-shrink: 0; margin-top: 1px;
}
.trz-ui .trz-err ul { margin: 0; padding: 0; list-style: none; min-width: 0; }
.trz-ui .trz-err li { color: var(--crit); font-weight: 700; }
/* Con dos o más problemas la lista necesita separación; con uno solo, un
   `margin-top` en el primero abriría un hueco que no separa nada. */
.trz-ui .trz-err li + li { margin-top: 3px; }

/* EL CAMPO QUE FALLÓ. Sin esto la tira dice «elegí un depósito destino» y el
   que mira tiene que buscar cuál de los cuatro campos es — que es exactamente
   el defecto que `aviso({foco})` vino a tapar del lado del modal. Acá no hace
   falta taparlo: el campo se señala solo, al mismo tiempo que la frase.

   Es un borde y una sombra, NO un fondo teñido: `.trz-in:disabled` ya usa el
   fondo para decir «este campo no se usa», y dos estados del mismo campo
   pintados en el mismo canal se confunden. */
.trz-ui .trz-in.mal,
.trz-ui .trz-in.mal:focus {
    border-color: var(--crit); box-shadow: 0 0 0 3px rgba(198, 40, 40, .13);
}

/* ── EL BOTÓN QUE NO TIENE NADA QUE HACER (etapa 6) ──────────────────────────
   Tres de los carteles no eran errores: eran «no hay cambios para guardar».
   Un modal que se abre para avisar que el sistema NO hizo nada es el peor de
   los ciento veinticinco — cuesta un gesto y no informa nada que la pantalla
   no pudiera haber dicho antes.

   Ahora lo dice antes: si el campo vale lo mismo que ya está guardado, el botón
   nace apagado y la nota del pie explica por qué. `.trz-btn:disabled` (arriba,
   línea 231) ya lo pinta; lo que se agrega es que la NOTA cambie con él, porque
   un botón apagado sin explicación es un botón roto. */
.trz-ui .trz-dlg-f .nota.porque { color: var(--warn); font-weight: 700; }

/* ═══════════════════════════════════════════════════════════════════════════
   LAS DOS DEFINICIONES Y EL RECALL (etapa 5)
   ═══════════════════════════════════════════════════════════════════════════
   Tres pantallas hermanas —Ingenios, Protocolos, Recall— que no estrenan
   tratamiento: usan la tarjeta, la tabla y el diálogo que ya existían. Lo que
   se agrega acá es lo que ninguna de las cuatro pantallas anteriores necesitó:
   un ancho intermedio de diálogo, una lista de casillas, la grilla de los catorce
   parámetros de un standard y las cifras del recall. */

/* ── El tercer ancho de diálogo ──────────────────────────────────────────────
   472 (chico) para dos a cinco campos, 1120 (la ficha) para dos paneles. El
   formulario del ingenio no es ninguno de los dos: son cuatro campos Y una
   lista de procedencias con una anotación al costado («también: La Florida»).
   En 472 esa anotación se cae de renglón en todas las filas. */
.trz-ui .trz-dlg.medio { max-width: 620px; }

/* ── Un chip: un valor de una lista corta que no es un estado ───────────────
   Una procedencia vinculada, un grado con standard. NO es `.trz-b`: aquello
   dice si algo está bien o mal y por eso tiene familia de color; esto es una
   etiqueta neutra, y son navy porque son datos del sistema, no juicios. */
.trz-ui .trz-chip {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: .68rem; font-weight: 700; white-space: nowrap;
    color: var(--navy-500); background: var(--navy-050); border: 1px solid #cddcf1;
    border-radius: 6px; padding: 2px 7px; margin: 1px 0;
}

/* Dos campos al lado del otro adentro del cuerpo de un diálogo. */
.trz-ui .trz-fila2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 620px) { .trz-ui .trz-fila2 { grid-template-columns: 1fr; } }

/* ── Casillas ────────────────────────────────────────────────────────────────
   `align-items: center` y no `baseline`: el `<input type=checkbox>` no tiene
   línea de base propia y con baseline se apoya en el borde de abajo, un píxel
   más arriba que el texto. */
.trz-ui .trz-check {
    display: flex; align-items: center; gap: 8px; cursor: pointer;
    font-size: .78rem; color: var(--ink);
}
.trz-ui .trz-check input[type="checkbox"] {
    width: 15px; height: 15px; flex: 0 0 15px; accent-color: var(--azure); cursor: pointer;
}
/* Una fila de la lista: la marcada se tiñe, para que se vea cuántas hay sin
   contar casillas. */
.trz-ui .trz-check.fila {
    padding: 6px 9px; border-radius: 7px; gap: 9px;
    transition: background .14s ease;
}
.trz-ui .trz-check.fila:hover { background: var(--surface); }
.trz-ui .trz-check.fila.on { background: var(--azure-050); }
.trz-ui .trz-check.fila .nm { font-weight: 700; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trz-ui .trz-check.fila .trz-sub { margin: 0 0 0 auto; padding-left: 8px; white-space: nowrap; }

/* La caja que las contiene. Alto acotado y scroll propio: la lista de
   procedencias tiene tantas filas como destinos haya en el ABM. */
.trz-ui .trz-lista {
    margin-top: 8px; max-height: 216px; overflow-y: auto;
    border: 1px solid var(--hair); border-radius: 9px; background: var(--canvas); padding: 5px;
}

/* Tres campos cortos en una fila (ingenio · zafra · grado). */
.trz-ui .trz-fila3 { display: grid; grid-template-columns: 2fr 1fr 1.6fr; gap: 14px; }
@media (max-width: 760px) { .trz-ui .trz-fila3 { grid-template-columns: 1fr; } }

/* ── Los catorce parámetros de un standard ─────────────────────────────────
   Cada uno es «qué se mide», «cuánto se pactó como límite» y «el valor». El
   rótulo y la especificación van juntos a la izquierda porque son la misma
   pregunta; el valor y su unidad, juntos a la derecha, porque son la misma
   respuesta. Dos columnas: con una, catorce parámetros hacen un diálogo de tres
   pantallas de alto y las tres familias dejan de verse como tres familias. */
.trz-ui .trz-params { display: grid; grid-template-columns: repeat(2, 1fr); gap: 9px; }
@media (max-width: 820px) { .trz-ui .trz-params { grid-template-columns: 1fr; } }
/* EN EL DIÁLOGO MEDIO VAN DE A UNO, y lo decidió la foto. Dos columnas dentro
   de 620 px dejan ~100 px para el rótulo, y «Anhídrido sulfuroso total» y
   «Cenizas por conductividad» se parten en tres renglones al lado de un campo
   de una línea. La media query de arriba no alcanza: mide el VIEWPORT, y el
   diálogo mide 620 adentro de una pantalla de 1440. */
.trz-ui .trz-dlg.medio .trz-params { grid-template-columns: 1fr; }
.trz-ui .trz-param {
    display: flex; align-items: center; gap: 10px; cursor: text;
    background: var(--canvas); border: 1px solid var(--hair); border-radius: 9px; padding: 7px 10px;
}
.trz-ui .trz-param:focus-within { border-color: var(--azure); background: var(--surface); }
.trz-ui .trz-param .txt { flex: 1; min-width: 0; }
.trz-ui .trz-param .txt b { display: block; font-size: .74rem; font-weight: 700; color: var(--ink); }
.trz-ui .trz-param .txt .spec { display: block; font-size: .65rem; color: var(--faint); }
.trz-ui .trz-param .trz-in { flex: 0 0 116px; width: 116px; }
.trz-ui .trz-param .un {
    flex: 0 0 46px; width: 46px; font-size: .66rem; font-weight: 700; color: var(--faint);
}

/* ── Adjuntos ────────────────────────────────────────────────────────────── */
.trz-ui .trz-adj { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; }
.trz-ui .trz-adj .fila {
    display: flex; align-items: center; gap: 8px;
    background: var(--canvas); border: 1px solid var(--hair); border-radius: 8px; padding: 5px 9px;
    font-size: .75rem;
}
.trz-ui .trz-adj .fila .material-symbols-outlined { color: var(--faint); font-size: 16px; }
.trz-ui .trz-adj .fila a { color: var(--azure); font-weight: 700; text-decoration: none;
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trz-ui .trz-adj .fila a:hover { text-decoration: underline; }
.trz-ui .trz-adj .fila .trz-x { margin-left: auto; }

/* ── La pantalla de Recall ───────────────────────────────────────────────────
   La cabecera navy dice DE QUÉ LOTE habla el resultado, con la misma forma que
   la cabecera de la ficha: es la misma pregunta —«qué pasó con este lote»— con
   la flecha para el otro lado. Va adentro de la tarjeta y no arriba de todo
   porque antes de trazar no hay ningún lote del que hablar. */
.trz-ui .trz-rc-cab {
    background: var(--navy); color: #fff; padding: 10px var(--gutter);
    display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
    border-top: 1px solid var(--hair);
}
.trz-ui .trz-rc-cab .trz-cod { color: #fff; font-size: .92rem; }
.trz-ui .trz-rc-cab .trz-b {
    background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .24); color: #dce9fb;
}
.trz-ui .trz-rc-b { padding: 16px var(--gutter) 20px; display: flex; flex-direction: column; gap: 14px; }
/* Los avisos van pegados uno al otro cuando hay más de uno: son la misma cosa
   dicha con distinto peso, no tres bloques independientes. */
.trz-ui .trz-rc-b > .trz-risk + .trz-risk { margin-top: -6px; }

/* Las cifras del resultado. Acento lateral como las tarjetas del Panel, pero
   sin «a dónde ir»: acá no se va a ningún lado, la respuesta está abajo. */
.trz-ui .trz-kpis {
    display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
}
.trz-ui .trz-kpi {
    display: flex; flex-direction: column; gap: 1px;
    background: var(--surface); border: 1px solid var(--hair); border-left: 3px solid var(--hair-strong);
    border-radius: 10px; padding: 9px 12px 10px; box-shadow: var(--e1);
}
.trz-ui .trz-kpi .k { font-size: .58rem; font-weight: 800; letter-spacing: .1em;
    text-transform: uppercase; color: var(--faint); }
.trz-ui .trz-kpi .v { font-size: 1.24rem; font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.trz-ui .trz-kpi.ok  { border-left-color: var(--ok); }   .trz-ui .trz-kpi.ok .v  { color: var(--ok); }
.trz-ui .trz-kpi.wrn { border-left-color: var(--warn); } .trz-ui .trz-kpi.wrn .v { color: var(--warn); }
.trz-ui .trz-kpi.neg { border-left-color: var(--crit); } .trz-ui .trz-kpi.neg .v { color: var(--crit); }

/* ── EL OBJETIVO DE LA ESTIBA ────────────────────────────────────────────────
   «Cuánto lleva de cuánto», que son dos números y una barra. La barra NO es un
   `<progress>`: pintarle el relleno pide una regla distinta por navegador
   (`::-webkit-progress-value`, `::-moz-progress-bar`) y ninguna hereda el token
   de color, así que el estado ok/wrn habría que declararlo tres veces.

   El color es del ESTADO, no decorativo: ámbar mientras falta, verde cuando
   está completa. La barra vacía es `--hair`, el mismo gris con el que el módulo
   dibuja lo que todavía no pasó. */
.trz-ui .trz-obj {
    background: var(--surface); border: 1px solid var(--hair);
    border-left: 3px solid var(--hair-strong);
    border-radius: 10px; padding: 11px 13px 12px; box-shadow: var(--e1);
}
.trz-ui .trz-obj .cifras { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.trz-ui .trz-obj .hoy  { font-size: 1.24rem; font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.trz-ui .trz-obj .de   { font-size: .68rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint); }
.trz-ui .trz-obj .meta { font-size: .92rem; font-weight: 700; color: var(--muted);
    display: inline-flex; align-items: center; gap: 3px; }
.trz-ui .trz-obj .barra { margin-top: 8px; height: 7px; border-radius: 999px;
    background: var(--hair); overflow: hidden; }
/* El relleno neutro es `--muted` y no `--hair-strong`: sobre `--hair` (la caja
   vacia) ese gris casi no se despega, y una barra que no se distingue del fondo
   no informa el porcentaje, lo insinua. `--muted` es el gris del texto
   secundario del modulo — neutro, sin significar bien ni mal. */
.trz-ui .trz-obj .barra i { display: block; height: 100%; border-radius: 999px;
    background: var(--muted); transition: width .3s var(--curva); }
.trz-ui .trz-obj .pie { margin-top: 7px; font-size: .74rem; color: var(--muted); }
.trz-ui .trz-obj .pie b { color: var(--ink); font-weight: 800; }
.trz-ui .trz-obj.wrn { border-left-color: var(--warn); }
.trz-ui .trz-obj.wrn .barra i { background: var(--warn); }
.trz-ui .trz-obj.ok  { border-left-color: var(--ok); }
.trz-ui .trz-obj.ok .barra i { background: var(--ok); }
.trz-ui .trz-obj.ok .hoy { color: var(--ok); }

/* El ✎ de un dato del CUERPO. Existía sólo dentro de la cabecera del diálogo
   (`.trz-dlg-h .lapiz`, navy sobre navy); el del panel izquierdo —el del
   formato— salía con el botón crudo del navegador. Esta es la base y la del
   encabezado la pisa por especificidad, sin importar el orden. */
.trz-ui .lapiz {
    background: none; border: 0; padding: 1px 3px; margin-left: 3px; cursor: pointer;
    color: var(--azure); border-radius: 5px; line-height: 1;
    transition: background .16s var(--curva);
}
.trz-ui .lapiz:hover { background: var(--azure-050); }
.trz-ui .lapiz .material-symbols-outlined { display: block; }

/* ── prefers-reduced-motion ──────────────────────────────────────────────────
   Se apaga el MOVIMIENTO, no el destaque: los cambios de color y de fondo
   quedan, y lo que desaparece es el desplazamiento y la escala. Un
   `transition:none` global también apagaría la información. */
@media (prefers-reduced-motion: reduce) {
    .trz-ui .trz-rail button,
    .trz-ui .trz-rail button::before,
    .trz-ui .trz-btn, .trz-ui .trz-btn .material-symbols-outlined,
    .trz-ui .trz-x, .trz-ui .trz-x .material-symbols-outlined { transition-duration: .01ms; }
    .trz-ui .trz-rail button:hover,
    .trz-ui .trz-rail button:focus-visible { transform: none; }
    .trz-ui .trz-btn:hover { transform: none; }
    .trz-ui .trz-btn:hover .material-symbols-outlined { transform: none; }
    .trz-ui .trz-x:hover .material-symbols-outlined { transform: none; }
    /* El anillo ya no se frena acá: se fue con `.trz-spin` (etapa 6) y el
       `.gs-spin` que lo reemplaza trae su propio `prefers-reduced-motion` en
       core/tokens.css — que es donde tiene que estar, porque lo usan once
       módulos y no sólo éste. */
}
